Skip to content

Commit cb0aadf

Browse files
authored
feat: state rm (#2880)
* feat: state rm * review feedback * fix conflict for pegomock generation code * adopt state command into allow-commands * fix conflicts * fix: state rm works on workspace * notify import/state rm discard plan file * fix lint * use repeat instead warning for re-plan * perl -pi -e 's!\* 🔁 plan file was discarded. to!🚮 A plan file was discarded. Re-plan would be required before applying.\n\n\* 🔁 To!g' server/**/* * follow main branch
1 parent 9e3d887 commit cb0aadf

File tree

81 files changed

+1793
-217
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

81 files changed

+1793
-217
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ require (
4343
github.com/xanzy/go-gitlab v0.78.0
4444
go.etcd.io/bbolt v1.3.6
4545
go.uber.org/zap v1.24.0
46+
golang.org/x/exp v0.0.0-20230113152452-c42ee1cf562e
4647
golang.org/x/term v0.4.0
4748
golang.org/x/text v0.6.0
4849
gopkg.in/yaml.v2 v2.4.0

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
508508
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
509509
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
510510
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
511+
golang.org/x/exp v0.0.0-20230113152452-c42ee1cf562e h1:uGuXqQsI2BAE8xNqSqNxhTdDdhlvpBvWFw/KBwtCtjI=
512+
golang.org/x/exp v0.0.0-20230113152452-c42ee1cf562e/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
511513
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
512514
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
513515
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=

runatlantis.io/docs/custom-workflows.md

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,11 @@ workflows:
5656
- init
5757
- import:
5858
extra_args: ["-var-file", "production.tfvars"]
59+
state_rm:
60+
steps:
61+
- init
62+
- state_rm:
63+
extra_args: ["-lock=false"]
5964
```
6065
Then in your repo-level `atlantis.yaml` file, you would reference the workflows:
6166
```yaml
@@ -374,13 +379,15 @@ projects:
374379
plan:
375380
apply:
376381
import:
382+
state_rm:
377383
```
378384

379-
| Key | Type | Default | Required | Description |
380-
|--------|-----------------|-------------------------|----------|----------------------------------|
381-
| plan | [Stage](#stage) | `steps: [init, plan]` | no | How to plan for this project. |
382-
| apply | [Stage](#stage) | `steps: [apply]` | no | How to apply for this project. |
383-
| import | [Stage](#stage) | `steps: [init, import]` | no | How to import for this project. |
385+
| Key | Type | Default | Required | Description |
386+
|----------|-----------------|---------------------------|----------|---------------------------------------|
387+
| plan | [Stage](#stage) | `steps: [init, plan]` | no | How to plan for this project. |
388+
| apply | [Stage](#stage) | `steps: [apply]` | no | How to apply for this project. |
389+
| import | [Stage](#stage) | `steps: [init, import]` | no | How to import for this project. |
390+
| state_rm | [Stage](#stage) | `steps: [init, state_rm]` | no | How to run state rm for this project. |
384391

385392
### Stage
386393
```yaml
@@ -403,10 +410,11 @@ Steps can be a single string for a built-in command.
403410
- plan
404411
- apply
405412
- import
413+
- state_rm
406414
```
407-
| Key | Type | Default | Required | Description |
408-
|------------------------|--------|---------|----------|------------------------------------------------------------------------------------------------------------------|
409-
| init/plan/apply/import | string | none | no | Use a built-in command without additional configuration. Only `init`, `plan`, `apply` and `import` are supported |
415+
| Key | Type | Default | Required | Description |
416+
|---------------------------------|--------|---------|----------|------------------------------------------------------------------------------------------------------------------------------|
417+
| init/plan/apply/import/state_rm | string | none | no | Use a built-in command without additional configuration. Only `init`, `plan`, `apply`, `import` and `state_rm` are supported |
410418

411419
#### Built-In Command With Extra Args
412420
A map from string to `extra_args` for a built-in command with extra arguments.
@@ -419,10 +427,12 @@ A map from string to `extra_args` for a built-in command with extra arguments.
419427
extra_args: [arg1, arg2]
420428
- import:
421429
extra_args: [arg1, arg2]
430+
- state_rm:
431+
extra_args: [arg1, arg2]
422432
```
423-
| Key | Type | Default | Required | Description |
424-
|------------------------|------------------------------------|---------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------|
425-
| init/plan/apply/import | map[`extra_args` -> array[string]] | none | no | Use a built-in command and append `extra_args`. Only `init`, `plan`, `apply` and `import` are supported as keys and only `extra_args` is supported as a value |
433+
| Key | Type | Default | Required | Description |
434+
|---------------------------------|------------------------------------|---------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
435+
| init/plan/apply/import/state_rm | map[`extra_args` -> array[string]] | none | no | Use a built-in command and append `extra_args`. Only `init`, `plan`, `apply`, `import` and `state_rm` are supported as keys and only `extra_args` is supported as a value |
426436

427437
#### Custom `run` Command
428438
Or a custom command

runatlantis.io/docs/server-configuration.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ Values are chosen in this order:
5757

5858
Notes:
5959
* Accepts a comma separated list, ex. `command1,command2`.
60-
* `version`, `plan`, `apply`, `unlock`, `approve_policies`, `import` and `all` are available.
60+
* `version`, `plan`, `apply`, `unlock`, `approve_policies`, `import`, `state` and `all` are available.
6161
* `all` is a special keyword that allows all commands. If pass `all` then all other commands will be ignored.
6262

6363
### `--allow-draft-prs`

runatlantis.io/docs/using-atlantis.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,51 @@ atlantis import -d dir 'aws_instance.example["foo"]' i-1234567890abcdef0 -- -var
169169
```
170170
If a flag is needed to be always appended, see [Custom Workflow Use Cases](custom-workflows.html#adding-extra-arguments-to-terraform-commands).
171171

172+
---
173+
## atlantis state rm
174+
```bash
175+
atlantis state [options] rm ADDRESS... -- [terraform state rm flags]
176+
```
177+
### Explanation
178+
Runs `terraform state rm` that matches the directory/project/workspace.
179+
This command discards the terraform plan result. After run state rm and before an apply, another `atlantis plan` must be run again.
180+
181+
To allow the `state` command requires [--allow-commands](/docs/server-configuration.html#allow-commands) configuration.
182+
183+
### Examples
184+
```bash
185+
# Runs state rm
186+
atlantis state rm ADDRESS1 ADDRESS2
187+
188+
# Runs state rm in the root directory of the repo with workspace `default`
189+
atlantis state -d . rm ADDRESS
190+
191+
# Runs state rm in the `project1` directory of the repo with workspace `default`
192+
atlantis state -d project1 rm ADDRESS
193+
194+
# Runs state rm in the root directory of the repo with workspace `staging`
195+
atlantis state -w staging rm ADDRESS
196+
```
197+
198+
::: tip
199+
* If run state rm to for_each resources, it requires a single quoted address.
200+
* ex. `atlantis state rm 'aws_instance.example["foo"]'`
201+
:::
202+
203+
### Options
204+
* `-d directory` Run state rm a resource for this directory, relative to root of repo. Use `.` for root.
205+
* `-p project` Run state rm a resource for this project. Refers to the name of the project configured in the repo's [`atlantis.yaml`](repo-level-atlantis-yaml.html) repo configuration file. This cannot be used at the same time as `-d` or `-w`.
206+
* `-w workspace` Run state rm a resource for a specific [Terraform workspace](https://developer.hashicorp.com/terraform/language/state/workspaces). Ignore this if Terraform workspaces are unused.
207+
208+
### Additional Terraform flags
209+
210+
If `terraform state rm` requires additional arguments, like `-lock=false'`
211+
append them to the end of the comment after `--`, e.g.
212+
```
213+
atlantis state -d dir rm 'aws_instance.example["foo"]' -- -lock=false
214+
```
215+
If a flag is needed to be always appended, see [Custom Workflow Use Cases](custom-workflows.html#adding-extra-arguments-to-terraform-commands).
216+
172217
---
173218
## atlantis unlock
174219
```bash

server/controllers/events/events_controller_e2e_test.go

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,71 @@ func TestGitHubWorkflow(t *testing.T) {
497497
{"exp-output-merge.txt"},
498498
},
499499
},
500+
{
501+
Description: "state rm single project",
502+
RepoDir: "state-rm-single-project",
503+
ModifiedFiles: []string{"main.tf"},
504+
ExpAutoplan: true,
505+
Comments: []string{
506+
"atlantis import random_id.simple AA",
507+
"atlantis import 'random_id.for_each[\"overridden\"]' BB -- -var var=overridden",
508+
"atlantis import random_id.count[0] BB",
509+
"atlantis plan -- -var var=overridden",
510+
"atlantis state rm 'random_id.for_each[\"overridden\"]' -- -lock=false",
511+
"atlantis state rm random_id.count[0] random_id.simple",
512+
"atlantis plan -- -var var=overridden",
513+
},
514+
ExpReplies: [][]string{
515+
{"exp-output-autoplan.txt"},
516+
{"exp-output-import-simple.txt"},
517+
{"exp-output-import-foreach.txt"},
518+
{"exp-output-import-count.txt"},
519+
{"exp-output-plan.txt"},
520+
{"exp-output-state-rm-foreach.txt"},
521+
{"exp-output-state-rm-multiple.txt"},
522+
{"exp-output-plan-again.txt"},
523+
{"exp-output-merged.txt"},
524+
},
525+
},
526+
{
527+
Description: "state rm workspace",
528+
RepoDir: "state-rm-workspace",
529+
Comments: []string{
530+
"atlantis import -p dir1-ops 'random_id.dummy1[0]' AA",
531+
"atlantis plan -p dir1-ops",
532+
"atlantis state rm -p dir1-ops 'random_id.dummy1[0]'",
533+
"atlantis plan -p dir1-ops",
534+
},
535+
ExpReplies: [][]string{
536+
{"exp-output-import-dummy1.txt"},
537+
{"exp-output-plan.txt"},
538+
{"exp-output-state-rm-dummy1.txt"},
539+
{"exp-output-plan-again.txt"},
540+
{"exp-output-merge.txt"},
541+
},
542+
},
543+
{
544+
Description: "state rm multiple project",
545+
RepoDir: "state-rm-multiple-project",
546+
ModifiedFiles: []string{"dir1/main.tf", "dir2/main.tf"},
547+
ExpAutoplan: true,
548+
Comments: []string{
549+
"atlantis import -d dir1 random_id.dummy AA",
550+
"atlantis import -d dir2 random_id.dummy BB",
551+
"atlantis plan",
552+
"atlantis state rm random_id.dummy",
553+
"atlantis plan",
554+
},
555+
ExpReplies: [][]string{
556+
{"exp-output-autoplan.txt"},
557+
{"exp-output-import-dummy1.txt"},
558+
{"exp-output-import-dummy2.txt"},
559+
{"exp-output-plan.txt"},
560+
{"exp-output-state-rm-multiple-projects.txt"},
561+
{"exp-output-plan-again.txt"},
562+
{"exp-output-merged.txt"},
563+
},
564+
},
500565
}
501566
for _, c := range cases {
502567
t.Run(c.Description, func(t *testing.T) {
@@ -1152,7 +1217,8 @@ func setupE2E(t *testing.T, repoDir string, opt setupOption) (events_controllers
11521217
ApplyStepRunner: &runtime.ApplyStepRunner{
11531218
TerraformExecutor: terraformClient,
11541219
},
1155-
ImportStepRunner: runtime.NewImportStepRunner(terraformClient, defaultTFVersion),
1220+
ImportStepRunner: runtime.NewImportStepRunner(terraformClient, defaultTFVersion),
1221+
StateRmStepRunner: runtime.NewStateRmStepRunner(terraformClient, defaultTFVersion),
11561222
RunStepRunner: &runtime.RunStepRunner{
11571223
TerraformExecutor: terraformClient,
11581224
DefaultTFVersion: defaultTFVersion,
@@ -1262,13 +1328,20 @@ func setupE2E(t *testing.T, repoDir string, opt setupOption) (events_controllers
12621328
projectCommandRunner,
12631329
)
12641330

1331+
stateCommandRunner := events.NewStateCommandRunner(
1332+
pullUpdater,
1333+
projectCommandBuilder,
1334+
projectCommandRunner,
1335+
)
1336+
12651337
commentCommandRunnerByCmd := map[command.Name]events.CommentCommandRunner{
12661338
command.Plan: planCommandRunner,
12671339
command.Apply: applyCommandRunner,
12681340
command.ApprovePolicies: approvePoliciesCommandRunner,
12691341
command.Unlock: unlockCommandRunner,
12701342
command.Version: versionCommandRunner,
12711343
command.Import: importCommandRunner,
1344+
command.State: stateCommandRunner,
12721345
}
12731346

12741347
commandRunner := &events.DefaultCommandRunner{

server/controllers/events/testdata/test-repos/import-multiple-project/exp-output-import-dummy1.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,7 @@ The resources that were imported are shown above. These resources are now in
1212
your Terraform state and will henceforth be managed by Terraform.
1313
```
1414

15+
:put_litter_in_its_place: A plan file was discarded. Re-plan would be required before applying.
16+
1517
* :repeat: To **plan** this project again, comment:
1618
* `atlantis plan -d dir1`

server/controllers/events/testdata/test-repos/import-single-project-var/exp-output-import-count.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,7 @@ The resources that were imported are shown above. These resources are now in
1212
your Terraform state and will henceforth be managed by Terraform.
1313
```
1414

15+
:put_litter_in_its_place: A plan file was discarded. Re-plan would be required before applying.
16+
1517
* :repeat: To **plan** this project again, comment:
1618
* `atlantis plan -d .`

server/controllers/events/testdata/test-repos/import-single-project-var/exp-output-import-foreach.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,7 @@ The resources that were imported are shown above. These resources are now in
1212
your Terraform state and will henceforth be managed by Terraform.
1313
```
1414

15+
:put_litter_in_its_place: A plan file was discarded. Re-plan would be required before applying.
16+
1517
* :repeat: To **plan** this project again, comment:
1618
* `atlantis plan -d .`

server/controllers/events/testdata/test-repos/import-single-project/exp-output-import-dummy1.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,7 @@ The resources that were imported are shown above. These resources are now in
1212
your Terraform state and will henceforth be managed by Terraform.
1313
```
1414

15+
:put_litter_in_its_place: A plan file was discarded. Re-plan would be required before applying.
16+
1517
* :repeat: To **plan** this project again, comment:
1618
* `atlantis plan -d .`

0 commit comments

Comments
 (0)