-
-
Notifications
You must be signed in to change notification settings - Fork 106
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix terraform clean bugs #870
base: main
Are you sure you want to change the base?
Changes from all commits
6832ddd
0c90df5
a2b820e
1649cd9
4a9bde6
755e5c6
13126b2
7e2f054
f4a81b3
8d1292b
1acd1d0
338d859
6735525
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -248,3 +248,103 @@ func verifyFileContains(t *testing.T, filePatterns map[string][]string) bool { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return success | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
func TestCLITerraformClean(t *testing.T) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Capture the starting working directory | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
startingDir, err := os.Getwd() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
t.Fatalf("Failed to get the current working directory: %v", err) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Initialize PathManager and update PATH | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
pathManager := NewPathManager() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
pathManager.Prepend("../build", "..") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
err = pathManager.Apply() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
t.Fatalf("Failed to apply updated PATH: %v", err) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
fmt.Printf("Updated PATH: %s\n", pathManager.GetPath()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
defer func() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Change back to the original working directory after the test | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if err := os.Chdir(startingDir); err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
t.Fatalf("Failed to change back to the starting directory: %v", err) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
workDir := "../examples/quick-start-simple" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
err = os.Chdir(workDir) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
t.Fatalf("Failed to change directory to %q: %v", workDir, err) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
binaryPath, err := exec.LookPath("atmos") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
t.Fatalf("Binary not found: %s. Current PATH: %s", "atmos", pathManager.GetPath()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
cmd := exec.Command(binaryPath, "terraform", "apply", "station", "-s", "dev") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
var stdout, stderr bytes.Buffer | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
cmd.Stdout = &stdout | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
cmd.Stderr = &stderr | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// ATMOS_COMPONENTS_TERRAFORM_APPLY_AUTO_APPROVE | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
envVars := os.Environ() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
envVars = append(envVars, "ATMOS_COMPONENTS_TERRAFORM_APPLY_AUTO_APPROVE=true") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
cmd.Env = envVars | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// run terraform apply station -s dev and terraform apply station -s prod | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
err = cmd.Run() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
t.Log(stdout.String()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
t.Fatalf("Failed to run terraform apply station -s dev: %v", stderr.String()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
cmd = exec.Command(binaryPath, "terraform", "apply", "station", "-s", "prod") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
envVars = append(envVars, "ATMOS_COMPONENTS_TERRAFORM_APPLY_AUTO_APPROVE=true") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
cmd.Env = envVars | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
err = cmd.Run() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
t.Log(stdout.String()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
t.Fatalf("Failed to run terraform apply station -s prod: %v", stderr.String()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// get command error sta | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// check if the state files and directories for the component and stack are exist | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
stateFiles := []string{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"./components/terraform/weather/.terraform", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"./components/terraform/weather/terraform.tfstate.d", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"./components/terraform/weather/.terraform.lock.hcl", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
for _, file := range stateFiles { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
fileAbs, err := filepath.Abs(file) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
t.Fatalf("Failed to resolve absolute path for %q: %v", file, err) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if _, err := os.Stat(fileAbs); errors.Is(err, os.ErrNotExist) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
t.Errorf("Reason: Expected file exist: %q", fileAbs) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+307
to
+323
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Improve state file verification logic. Several issues to address:
- // get command error sta
+ // check terraform state files existence
stateFiles := []string{
- "./components/terraform/weather/.terraform",
- "./components/terraform/weather/terraform.tfstate.d",
- "./components/terraform/weather/.terraform.lock.hcl",
+ filepath.Join("components", "terraform", "weather", ".terraform"),
+ filepath.Join("components", "terraform", "weather", "terraform.tfstate.d"),
+ filepath.Join("components", "terraform", "weather", ".terraform.lock.hcl"),
} 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// run atmos terraform clean | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
cmd = exec.Command(binaryPath, "terraform", "clean", "--force") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
err = cmd.Run() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
t.Log(stdout.String()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
t.Fatalf("Failed to run atmos terraform clean: %v", stderr.String()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// check if the state files and directories for the component and stack are deleted | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
for _, file := range stateFiles { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
fileAbs, err := filepath.Abs(file) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
t.Fatalf("Failed to resolve absolute path for %q: %v", file, err) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
_, err = os.Stat(fileAbs) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if errors.Is(err, os.ErrNotExist) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
continue | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
t.Errorf("Reason: error %q", fileAbs) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+324
to
+348
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Codebase verification Improve clean command test verification logic The review comment is correct. Looking at the implementation in
Suggested improvements:
🔗 Analysis chainFix clean command verification logic. The verification has several issues:
- return
+ t.Errorf("Expected file %q to be deleted, but it still exists", fileAbs)
+ failed = true
}
- return
+ if failed {
+ t.Fail()
+ } Also, consider adding verification of the command output to ensure it matches the expected behavior from the PR objectives. 🏁 Scripts executedThe following scripts were executed for the analysis: Script: #!/bin/bash
# Description: Verify the output of terraform clean command matches expected behavior
# Test: Check if the command output contains expected success message
cmd_output=$(atmos terraform clean --force 2>&1)
echo "$cmd_output" | grep -q "deleted" || echo "Command output doesn't indicate successful deletion"
Length of output: 382 Script: #!/bin/bash
# Let's check the implementation of the clean command to understand expected output
ast-grep --pattern 'func $_($$$ *cli.Context) error {
$$$
clean($$$)
$$$
}'
Length of output: 83 Script: #!/bin/bash
# Let's check the test file more thoroughly
rg -A 5 "terraform clean" tests/cli_test.go
Length of output: 448 Script: #!/bin/bash
# Check if there are any other tests for clean command
rg "TestClean" tests/
Length of output: 21 Script: #!/bin/bash
# Let's check the clean command implementation with a different pattern
ast-grep --pattern 'func clean($$$) {
$$$
}'
Length of output: 48 Script: #!/bin/bash
# Let's look for any clean-related functions
rg -B 2 -A 5 "func.*[Cc]lean" .
Length of output: 1790 Script: #!/bin/bash
# Check the test setup for stateFiles
rg -B 5 "stateFiles :=" tests/cli_test.go
Length of output: 270 |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -23,7 +23,7 @@ Execute the `terraform clean` command like this: | |||||
atmos terraform clean <component> -s <stack> [--skip-lock-file] [--everything] [--force] | ||||||
|
||||||
:::warning | ||||||
The `--everything` flag will delete all Terraform-related files including state files. The `--force` flag will bypass confirmation prompts. | ||||||
The `clean` default behavior and will delete all Terraform-related files including state files, with a confirmation prompt before proceeding. The `--force` flag will bypass confirmation prompts. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
Use these flags with extreme caution as they can lead to irreversible data loss. | ||||||
::: | ||||||
``` | ||||||
|
@@ -36,10 +36,9 @@ Run `atmos terraform clean --help` to see all the available options | |||||
|
||||||
```shell | ||||||
# Delete all Terraform-related files for all components (with confirmation) | ||||||
atmos terraform clean --everything | ||||||
|
||||||
atmos terraform clean | ||||||
# Force delete all Terraform-related files for all components (no confirmation) | ||||||
atmos terraform clean --everything --force | ||||||
atmos terraform clean --force | ||||||
atmos terraform clean top-level-component1 -s tenant1-ue2-dev | ||||||
atmos terraform clean infra/vpc -s tenant1-ue2-staging | ||||||
atmos terraform clean infra/vpc -s tenant1-ue2-staging --skip-lock-file | ||||||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -59,11 +59,11 @@ HCL-based domain-specific language and its interpreter. Atmos works with [OpenTo | |||||
|
||||||
- `atmos terraform clean` command deletes the `.terraform` folder, `.terraform.lock.hcl` lock file, and the previously generated `planfile` | ||||||
and `varfile` for the specified component and stack. Use the `--skip-lock-file` flag to skip deleting the `.terraform.lock.hcl` file. | ||||||
Use the `--everything` flag to delete all the local Terraform state files and directories (including `terraform.tfstate.d`) for all components and stacks. | ||||||
Use the `--force` flag to bypass the safety confirmation prompt and force the deletion (use with caution). | ||||||
It deletes all local Terraform state files and directories (including `terraform.tfstate.d/`) for all components and stacks. | ||||||
The `--force` flag bypasses the safety confirmation prompt and forces the deletion. Use with caution. | ||||||
|
||||||
:::warning | ||||||
The `--everything` flag performs destructive operations that can lead to permanent state loss. Always ensure you have remote state configured in your components before proceeding. | ||||||
The `clean` performs destructive operations that can lead to permanent state loss. Always ensure you have remote state configured in your components before proceeding. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
::: | ||||||
|
||||||
- `atmos terraform workspace` command first runs `terraform init -reconfigure`, then `terraform workspace select`, and if the workspace was not | ||||||
|
@@ -113,16 +113,16 @@ atmos terraform destroy test/test-component-override -s tenant1-ue2-dev --redire | |||||
atmos terraform init test/test-component-override-3 -s tenant1-ue2-dev | ||||||
|
||||||
# Clean all components (with confirmation) | ||||||
atmos terraform clean --everything | ||||||
atmos terraform clean | ||||||
|
||||||
# Clean a specific component | ||||||
atmos terraform clean vpc --everything | ||||||
atmos terraform clean vpc | ||||||
|
||||||
# Clean a specific component in a stack | ||||||
atmos terraform clean vpc --stack dev --everything | ||||||
atmos terraform clean vpc --stack dev | ||||||
|
||||||
# Clean without confirmation prompt | ||||||
atmos terraform clean --everything --force | ||||||
atmos terraform clean --force | ||||||
atmos terraform clean test/test-component-override-3 -s tenant1-ue2-dev | ||||||
|
||||||
atmos terraform workspace test/test-component-override-3 -s tenant1-ue2-dev | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Improve command execution and error handling.
The command execution pattern could be improved in several ways: