Skip to content

Commit a02986e

Browse files
authored
Stack: clean (#3871)
* Add terragrunt stack clean * action simplification * Add test for cleaning directories * Add stack clean documentation * Fixed lint issues * Docs update
1 parent 9c1482c commit a02986e

File tree

4 files changed

+69
-13
lines changed

4 files changed

+69
-13
lines changed

cli/commands/stack/action.go

+32-6
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package stack
22

33
import (
44
"context"
5+
"os"
56
"path/filepath"
67

78
runall "github.com/gruntwork-io/terragrunt/cli/commands/run-all"
@@ -21,17 +22,17 @@ const (
2122

2223
// RunGenerate runs the stack command.
2324
func RunGenerate(ctx context.Context, opts *options.TerragruntOptions) error {
24-
if !opts.Experiments.Evaluate(experiment.Stacks) {
25-
return cli.NewExitError(errors.New("stacks experiment is not enabled use --experiment stacks to enable it"), cli.ExitCodeGeneralError)
25+
if err := checkStackExperiment(opts); err != nil {
26+
return err
2627
}
2728

2829
return generateStack(ctx, opts)
2930
}
3031

3132
// Run execute stack command.
3233
func Run(ctx context.Context, opts *options.TerragruntOptions) error {
33-
if !opts.Experiments.Evaluate(experiment.Stacks) {
34-
return cli.NewExitError(errors.New("stacks experiment is not enabled use --experiment stacks to enable it"), cli.ExitCodeGeneralError)
34+
if err := checkStackExperiment(opts); err != nil {
35+
return err
3536
}
3637

3738
if err := RunGenerate(ctx, opts); err != nil {
@@ -45,8 +46,8 @@ func Run(ctx context.Context, opts *options.TerragruntOptions) error {
4546

4647
// RunOutput stack output.
4748
func RunOutput(ctx context.Context, opts *options.TerragruntOptions, index string) error {
48-
if !opts.Experiments.Evaluate(experiment.Stacks) {
49-
return cli.NewExitError(errors.New("stacks experiment is not enabled use --experiment stacks to enable it"), cli.ExitCodeGeneralError)
49+
if err := checkStackExperiment(opts); err != nil {
50+
return err
5051
}
5152

5253
// collect outputs
@@ -77,3 +78,28 @@ func RunOutput(ctx context.Context, opts *options.TerragruntOptions, index strin
7778

7879
return nil
7980
}
81+
82+
// RunClean cleans the stack directory
83+
func RunClean(_ context.Context, opts *options.TerragruntOptions) error {
84+
if err := checkStackExperiment(opts); err != nil {
85+
return err
86+
}
87+
88+
baseDir := filepath.Join(opts.WorkingDir, stackDir)
89+
opts.Logger.Debugf("Cleaning stack directory: %s", baseDir)
90+
err := os.RemoveAll(baseDir)
91+
92+
if err != nil {
93+
return errors.Errorf("failed to clean stack directory: %s %w", baseDir, err)
94+
}
95+
96+
return nil
97+
}
98+
99+
func checkStackExperiment(opts *options.TerragruntOptions) error {
100+
if !opts.Experiments.Evaluate(experiment.Stacks) {
101+
return cli.NewExitError(errors.New("stacks experiment is not enabled use --experiment stacks to enable it"), cli.ExitCodeGeneralError)
102+
}
103+
104+
return nil
105+
}

cli/commands/stack/command.go

+14-6
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,10 @@ const (
1414
JSONFormatFlagName = "json"
1515
RawFormatFlagName = "raw"
1616

17-
generate = "generate"
18-
run = "run"
19-
output = "output"
17+
generateCommandName = "generate"
18+
runCommandName = "run"
19+
outputCommandName = "output"
20+
cleanCommandName = "clean"
2021

2122
rawOutputFormat = "raw"
2223
jsonOutputFormat = "json"
@@ -61,22 +62,22 @@ func NewCommand(opts *options.TerragruntOptions) *cli.Command {
6162
Flags: NewFlags(opts, nil).Sort(),
6263
Subcommands: cli.Commands{
6364
&cli.Command{
64-
Name: generate,
65+
Name: generateCommandName,
6566
Usage: "Generate a stack from a terragrunt.stack.hcl file",
6667
Action: func(ctx *cli.Context) error {
6768
return RunGenerate(ctx.Context, opts.OptionsFromContext(ctx))
6869

6970
},
7071
},
7172
&cli.Command{
72-
Name: run,
73+
Name: runCommandName,
7374
Usage: "Run a command on the stack generated from the current directory",
7475
Action: func(ctx *cli.Context) error {
7576
return Run(ctx.Context, opts.OptionsFromContext(ctx))
7677
},
7778
},
7879
&cli.Command{
79-
Name: output,
80+
Name: outputCommandName,
8081
Usage: "Run fetch stack output",
8182
Action: func(ctx *cli.Context) error {
8283
index := ""
@@ -86,6 +87,13 @@ func NewCommand(opts *options.TerragruntOptions) *cli.Command {
8687
return RunOutput(ctx.Context, opts.OptionsFromContext(ctx), index)
8788
},
8889
},
90+
&cli.Command{
91+
Name: cleanCommandName,
92+
Usage: "Clean the stack generated from the current directory",
93+
Action: func(ctx *cli.Context) error {
94+
return RunClean(ctx.Context, opts.OptionsFromContext(ctx))
95+
},
96+
},
8997
},
9098
Action: cli.ShowCommandHelp,
9199
}

docs/_docs/04_reference/02-cli-options.md

+6-1
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,7 @@ Before executing the specified command, the `terragrunt stack run *` command wil
366366
the `.terragrunt-stack` directory using the `terragrunt.stack.hcl` configuration file.
367367
This ensures that all units are up-to-date before running the requested operation.
368368

369-
#### output
369+
#### stack output
370370

371371
The `terragrunt stack output` command allows users to retrieve and interact with outputs from multiple units within a Terragrunt stack.
372372
This feature simplifies handling infrastructure outputs by consolidating them into a single view.
@@ -494,6 +494,11 @@ $ terragrunt stack output --format raw project1_app2.data
494494
app2
495495
```
496496

497+
#### stack clean
498+
499+
Running `terragrunt stack clean` removes the `.terragrunt-stack` directory, which is generated by the `terragrunt stack generate`
500+
or `terragrunt stack run` commands. This can be useful when you need to remove generated configurations or troubleshoot issues.
501+
497502
### info
498503

499504
Emits limited terragrunt information to stdout in JSON format.

test/integration_stacks_test.go

+17
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,23 @@ func TestStacksApplyRemote(t *testing.T) {
159159
validateStackDir(t, path)
160160
}
161161

162+
func TestStacksApplyClean(t *testing.T) {
163+
t.Parallel()
164+
165+
helpers.CleanupTerraformFolder(t, testFixtureStacksInputs)
166+
tmpEnvPath := helpers.CopyEnvironment(t, testFixtureStacksInputs)
167+
rootPath := util.JoinPath(tmpEnvPath, testFixtureStacksInputs)
168+
169+
helpers.RunTerragrunt(t, "terragrunt stack run apply --experiment stacks --terragrunt-non-interactive --terragrunt-working-dir "+rootPath)
170+
path := util.JoinPath(rootPath, ".terragrunt-stack")
171+
// check that path exists
172+
assert.DirExists(t, path)
173+
174+
helpers.RunTerragrunt(t, "terragrunt stack clean --experiment stacks --terragrunt-working-dir "+rootPath)
175+
// check that path don't exist
176+
assert.NoDirExists(t, path)
177+
}
178+
162179
func TestStacksDestroy(t *testing.T) {
163180
t.Parallel()
164181

0 commit comments

Comments
 (0)