Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package terragrunt for openSUSE:Factory checked in at 2025-03-05 13:47:58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/terragrunt (Old) and /work/SRC/openSUSE:Factory/.terragrunt.new.19136 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "terragrunt" Wed Mar 5 13:47:58 2025 rev:199 rq:1250371 version:0.75.0 Changes: -------- --- /work/SRC/openSUSE:Factory/terragrunt/terragrunt.changes 2025-03-01 19:17:53.736438263 +0100 +++ /work/SRC/openSUSE:Factory/.terragrunt.new.19136/terragrunt.changes 2025-03-05 13:48:00.687378353 +0100 @@ -1,0 +2,20 @@ +Wed Mar 05 10:24:55 UTC 2025 - opensuse_buildserv...@ojkastl.de + +- Update to version 0.75.0: + Terraform 1.11 support: We are now testing Terragrunt against + Terraform 1.11 and is confirmed to be working. + NOTE: Although this release is marked as backward incompatible, + it is functionally compatible as nothing has been changed in + Terragrunt internals. The minor version release is useful to mark + the change in Terraform version that is being tested. + * Add support for Terraform 1.11 (#3958) + * fix: Using `run -- graph` command (#3959) + +------------------------------------------------------------------- +Wed Mar 05 10:11:07 UTC 2025 - opensuse_buildserv...@ojkastl.de + +- Update to version 0.74.0: + * Terraform 1.10 (#3605) + * feat: Implementation of `--all` `--graph` flags (#3944) + +------------------------------------------------------------------- Old: ---- terragrunt-0.73.16.obscpio New: ---- terragrunt-0.75.0.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ terragrunt.spec ++++++ --- /var/tmp/diff_new_pack.iFFUZ7/_old 2025-03-05 13:48:02.691462205 +0100 +++ /var/tmp/diff_new_pack.iFFUZ7/_new 2025-03-05 13:48:02.691462205 +0100 @@ -17,7 +17,7 @@ Name: terragrunt -Version: 0.73.16 +Version: 0.75.0 Release: 0 Summary: Thin wrapper for Terraform for working with multiple Terraform modules License: MIT ++++++ _service ++++++ --- /var/tmp/diff_new_pack.iFFUZ7/_old 2025-03-05 13:48:02.775465720 +0100 +++ /var/tmp/diff_new_pack.iFFUZ7/_new 2025-03-05 13:48:02.779465887 +0100 @@ -3,7 +3,7 @@ <param name="url">https://github.com/gruntwork-io/terragrunt</param> <param name="scm">git</param> <param name="exclude">.git</param> - <param name="revision">v0.73.16</param> + <param name="revision">v0.75.0</param> <param name="versionformat">@PARENT_TAG@</param> <param name="versionrewrite-pattern">v(.*)</param> <param name="changesgenerate">enable</param> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.iFFUZ7/_old 2025-03-05 13:48:02.807467059 +0100 +++ /var/tmp/diff_new_pack.iFFUZ7/_new 2025-03-05 13:48:02.811467226 +0100 @@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/gruntwork-io/terragrunt</param> - <param name="changesrevision">2ede06c52c35d03467c40fd5d668a49ac82ea5da</param></service></servicedata> + <param name="changesrevision">f83766b7449b60a9c6b0bc17db997cf0139d12a7</param></service></servicedata> (No newline at EOF) ++++++ terragrunt-0.73.16.obscpio -> terragrunt-0.75.0.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.16/.circleci/config.yml new/terragrunt-0.75.0/.circleci/config.yml --- old/terragrunt-0.73.16/.circleci/config.yml 2025-02-28 19:14:10.000000000 +0100 +++ new/terragrunt-0.75.0/.circleci/config.yml 2025-03-03 15:42:15.000000000 +0100 @@ -9,7 +9,7 @@ GRUNTWORK_INSTALLER_VERSION: v0.0.39 MODULE_CI_VERSION: v0.57.0 OPENTOFU_VERSION: "1.9.0" - TERRAFORM_VERSION: "1.9.7" + TERRAFORM_VERSION: "1.11.0" TFLINT_VERSION: "0.47.0" TOFU_ENGINE_VERSION: "v0.0.11" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.16/cli/app.go new/terragrunt-0.75.0/cli/app.go --- old/terragrunt-0.73.16/cli/app.go 2025-02-28 19:14:10.000000000 +0100 +++ new/terragrunt-0.75.0/cli/app.go 2025-03-03 15:42:15.000000000 +0100 @@ -37,6 +37,10 @@ "github.com/gruntwork-io/terragrunt/pkg/log/format/placeholders" ) +const ( + AppName = "terragrunt" +) + func init() { cli.AppVersionTemplate = AppVersionTemplate cli.AppHelpTemplate = AppHelpTemplate @@ -53,7 +57,7 @@ terragruntCommands := commands.New(opts) app := cli.NewApp() - app.Name = "terragrunt" + app.Name = AppName app.Usage = "Terragrunt is a flexible orchestration tool that allows Infrastructure as Code written in OpenTofu/Terraform to scale.\nFor documentation, see https://terragrunt.gruntwork.io/." app.Author = "Gruntwork <www.gruntwork.io>" app.Version = version.GetVersion() @@ -241,8 +245,12 @@ args := cliCtx.Args().WithoutBuiltinCmdSep().Normalize(cli.SingleDashFlag) cmdName := cliCtx.Command.Name - switch cmdName { - case runCmd.CommandName, runall.CommandName, graph.CommandName: + switch { + case cmdName == runCmd.CommandName: + fallthrough + case cmdName == runall.CommandName: + fallthrough + case cmdName == graph.CommandName && cliCtx.Parent().Command.IsRoot: cmdName = args.CommandName() default: args = append([]string{cmdName}, args...) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.16/cli/commands/aws-provider-patch/command.go new/terragrunt-0.75.0/cli/commands/aws-provider-patch/command.go --- old/terragrunt-0.73.16/cli/commands/aws-provider-patch/command.go 2025-02-28 19:14:10.000000000 +0100 +++ new/terragrunt-0.75.0/cli/commands/aws-provider-patch/command.go 2025-03-03 15:42:15.000000000 +0100 @@ -30,6 +30,8 @@ package awsproviderpatch import ( + "github.com/gruntwork-io/terragrunt/cli/commands/common/graph" + "github.com/gruntwork-io/terragrunt/cli/commands/common/runall" "github.com/gruntwork-io/terragrunt/cli/commands/run" "github.com/gruntwork-io/terragrunt/cli/flags" "github.com/gruntwork-io/terragrunt/internal/cli" @@ -61,11 +63,16 @@ } func NewCommand(opts *options.TerragruntOptions) *cli.Command { - return &cli.Command{ + cmd := &cli.Command{ Name: CommandName, Usage: "Overwrite settings on nested AWS providers to work around a Terraform bug (issue #13018).", Hidden: true, Flags: append(run.NewFlags(opts, nil), NewFlags(opts, nil)...).Sort(), Action: func(ctx *cli.Context) error { return Run(ctx, opts.OptionsFromContext(ctx)) }, } + + cmd = runall.WrapCommand(opts, cmd) + cmd = graph.WrapCommand(opts, cmd) + + return cmd } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.16/cli/commands/common/errors.go new/terragrunt-0.75.0/cli/commands/common/errors.go --- old/terragrunt-0.73.16/cli/commands/common/errors.go 1970-01-01 01:00:00.000000000 +0100 +++ new/terragrunt-0.75.0/cli/commands/common/errors.go 2025-03-03 15:42:15.000000000 +0100 @@ -0,0 +1,10 @@ +// Package common provides common code that are used by many commands. +package common + +var _ error = new(AllGraphFlagsError) + +type AllGraphFlagsError byte + +func (err *AllGraphFlagsError) Error() string { + return "Using the `--all` and `--graph` flags simultaneously is not supported." +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.16/cli/commands/common/graph/action.go new/terragrunt-0.75.0/cli/commands/common/graph/action.go --- old/terragrunt-0.73.16/cli/commands/common/graph/action.go 1970-01-01 01:00:00.000000000 +0100 +++ new/terragrunt-0.75.0/cli/commands/common/graph/action.go 2025-03-03 15:42:15.000000000 +0100 @@ -0,0 +1,67 @@ +package graph + +import ( + "context" + "errors" + + "github.com/gruntwork-io/terragrunt/cli/commands/common/runall" + "github.com/gruntwork-io/terragrunt/config" + "github.com/gruntwork-io/terragrunt/util" + + "github.com/gruntwork-io/terragrunt/configstack" + "github.com/gruntwork-io/terragrunt/options" + "github.com/gruntwork-io/terragrunt/shell" +) + +func Run(ctx context.Context, opts *options.TerragruntOptions) error { + cfg, err := config.ReadTerragruntConfig(ctx, opts, config.DefaultParserOptions(opts)) + if err != nil { + return err + } + + if cfg == nil { + return errors.New("terragrunt was not able to render the config as json because it received no config. This is almost certainly a bug in Terragrunt. Please open an issue on github.com/gruntwork-io/terragrunt with this message and the contents of your terragrunt.hcl") + } + // consider root for graph identification passed destroy-graph-root argument + rootDir := opts.GraphRoot + + // if destroy-graph-root is empty, use git to find top level dir. + // may cause issues if in the same repo exist unrelated modules which will generate errors when scanning. + if rootDir == "" { + gitRoot, err := shell.GitTopLevelDir(ctx, opts, opts.WorkingDir) + if err != nil { + return err + } + + rootDir = gitRoot + } + + rootOptions, err := opts.CloneWithConfigPath(rootDir) + if err != nil { + return err + } + + rootOptions.WorkingDir = rootDir + + stack, err := configstack.FindStackInSubfolders(ctx, rootOptions) + if err != nil { + return err + } + + dependentModules := stack.ListStackDependentModules() + + workDir := opts.WorkingDir + modulesToInclude := dependentModules[workDir] + // workdir to list too + modulesToInclude = append(modulesToInclude, workDir) + + // include from stack only elements from modulesToInclude + for _, module := range stack.Modules { + module.FlagExcluded = true + if util.ListContainsElement(modulesToInclude, module.Path) { + module.FlagExcluded = false + } + } + + return runall.RunAllOnStack(ctx, opts, stack) +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.16/cli/commands/common/graph/command.go new/terragrunt-0.75.0/cli/commands/common/graph/command.go --- old/terragrunt-0.73.16/cli/commands/common/graph/command.go 1970-01-01 01:00:00.000000000 +0100 +++ new/terragrunt-0.75.0/cli/commands/common/graph/command.go 2025-03-03 15:42:15.000000000 +0100 @@ -0,0 +1,70 @@ +// Package graph provides the `graph` feature for Terragrunt. +package graph + +import ( + "context" + + "github.com/gruntwork-io/terragrunt/cli/commands/common" + "github.com/gruntwork-io/terragrunt/cli/flags" + "github.com/gruntwork-io/terragrunt/internal/cli" + "github.com/gruntwork-io/terragrunt/internal/errors" + "github.com/gruntwork-io/terragrunt/options" +) + +const ( + GraphFlagName = "graph" + GraphRootFlagName = "graph-root" + + DeprecatedGraphRootFlagName = "graph-root" +) + +func NewFlags(opts *options.TerragruntOptions, commandName string, prefix flags.Prefix) cli.Flags { + tgPrefix := prefix.Prepend(flags.TgPrefix) + terragruntPrefix := flags.Prefix{flags.TerragruntPrefix} + terragruntPrefixControl := flags.StrictControlsByCommand(opts.StrictControls, commandName) + + return cli.Flags{ + flags.NewFlag(&cli.BoolFlag{ + Name: GraphFlagName, + EnvVars: tgPrefix.EnvVars(GraphFlagName), + Destination: &opts.Graph, + Usage: "Run the specified OpenTofu/Terraform command following the Directed Acyclic Graph (DAG) of dependencies.", + Action: func(_ *cli.Context, _ bool) error { + if opts.RunAll { + return errors.New(new(common.AllGraphFlagsError)) + } + + return nil + }, + }), + + flags.NewFlag(&cli.GenericFlag[string]{ + Name: GraphRootFlagName, + EnvVars: tgPrefix.EnvVars(GraphRootFlagName), + Destination: &opts.GraphRoot, + Usage: "Root directory from where to build graph dependencies.", + }, + flags.WithDeprecatedName(terragruntPrefix.FlagName(DeprecatedGraphRootFlagName), terragruntPrefixControl)), + } +} + +// WrapCommand appends flags to the given `cmd` and wraps its action. +func WrapCommand(opts *options.TerragruntOptions, cmd *cli.Command) *cli.Command { + cmd = cmd.WrapAction(func(cliCtx *cli.Context, action cli.ActionFunc) error { + if !opts.Graph { + return action(cliCtx) + } + + opts.RunTerragrunt = func(ctx context.Context, opts *options.TerragruntOptions) error { + cliCtx := cliCtx.WithValue(options.ContextKey, opts) + return action(cliCtx) + } + + return Run(cliCtx, opts.OptionsFromContext(cliCtx)) + }) + + flags := append(cmd.Flags, NewFlags(opts, cmd.Name, nil)...) + cmd.Flags = flags.Sort() + + return cmd +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.16/cli/commands/common/runall/action.go new/terragrunt-0.75.0/cli/commands/common/runall/action.go --- old/terragrunt-0.73.16/cli/commands/common/runall/action.go 1970-01-01 01:00:00.000000000 +0100 +++ new/terragrunt-0.75.0/cli/commands/common/runall/action.go 2025-03-03 15:42:15.000000000 +0100 @@ -0,0 +1,88 @@ +package runall + +import ( + "context" + + "github.com/gruntwork-io/terragrunt/configstack" + "github.com/gruntwork-io/terragrunt/internal/errors" + "github.com/gruntwork-io/terragrunt/options" + "github.com/gruntwork-io/terragrunt/shell" + "github.com/gruntwork-io/terragrunt/telemetry" + "github.com/gruntwork-io/terragrunt/tf" +) + +// Known terraform commands that are explicitly not supported in run-all due to the nature of the command. This is +// tracked as a map that maps the terraform command to the reasoning behind disallowing the command in run-all. +var runAllDisabledCommands = map[string]string{ + tf.CommandNameImport: "terraform import should only be run against a single state representation to avoid injecting the wrong object in the wrong state representation.", + tf.CommandNameTaint: "terraform taint should only be run against a single state representation to avoid using the wrong state address.", + tf.CommandNameUntaint: "terraform untaint should only be run against a single state representation to avoid using the wrong state address.", + tf.CommandNameConsole: "terraform console requires stdin, which is shared across all instances of run-all when multiple modules run concurrently.", + tf.CommandNameForceUnlock: "lock IDs are unique per state representation and thus should not be run with run-all.", + + // MAINTAINER'S NOTE: There are a few other commands that might not make sense, but we deliberately allow it for + // certain use cases that are documented here: + // - state : Supporting `state` with run-all could be useful for a mass pull and push operation, which can + // be done en masse with the use of relative pathing. + // - login / logout : Supporting `login` with run-all could be useful when used in conjunction with mise and + // multi-terraform version setups, where multiple terraform versions need to be configured. + // - version : Supporting `version` with run-all could be useful for sanity checking a multi-version setup. +} + +func Run(ctx context.Context, opts *options.TerragruntOptions) error { + if opts.TerraformCommand == "" { + return errors.New(MissingCommand{}) + } + + reason, isDisabled := runAllDisabledCommands[opts.TerraformCommand] + if isDisabled { + return RunAllDisabledErr{ + command: opts.TerraformCommand, + reason: reason, + } + } + + stack, err := configstack.FindStackInSubfolders(ctx, opts) + if err != nil { + return err + } + + return RunAllOnStack(ctx, opts, stack) +} + +func RunAllOnStack(ctx context.Context, opts *options.TerragruntOptions, stack *configstack.Stack) error { + opts.Logger.Debugf("%s", stack.String()) + + if err := stack.LogModuleDeployOrder(opts.Logger, opts.TerraformCommand); err != nil { + return err + } + + var prompt string + + switch opts.TerraformCommand { + case tf.CommandNameApply: + prompt = "Are you sure you want to run 'terragrunt apply' in each folder of the stack described above?" + case tf.CommandNameDestroy: + prompt = "WARNING: Are you sure you want to run `terragrunt destroy` in each folder of the stack described above? There is no undo!" + case tf.CommandNameState: + prompt = "Are you sure you want to manipulate the state with `terragrunt state` in each folder of the stack described above? Note that absolute paths are shared, while relative paths will be relative to each working directory." + } + + if prompt != "" { + shouldRunAll, err := shell.PromptUserForYesNo(ctx, prompt, opts) + if err != nil { + return err + } + + if !shouldRunAll { + return nil + } + } + + return telemetry.Telemetry(ctx, opts, "run_all_on_stack", map[string]interface{}{ + "terraform_command": opts.TerraformCommand, + "working_dir": opts.WorkingDir, + }, func(childCtx context.Context) error { + return stack.Run(ctx, opts) + }) +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.16/cli/commands/common/runall/action_test.go new/terragrunt-0.75.0/cli/commands/common/runall/action_test.go --- old/terragrunt-0.73.16/cli/commands/common/runall/action_test.go 1970-01-01 01:00:00.000000000 +0100 +++ new/terragrunt-0.75.0/cli/commands/common/runall/action_test.go 2025-03-03 15:42:15.000000000 +0100 @@ -0,0 +1,30 @@ +package runall_test + +import ( + "context" + "errors" + "fmt" + "testing" + + "github.com/gruntwork-io/terragrunt/cli/commands/common/runall" + "github.com/gruntwork-io/terragrunt/options" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestMissingRunAllArguments(t *testing.T) { + t.Parallel() + + tgOptions, err := options.NewTerragruntOptionsForTest("") + require.NoError(t, err) + + tgOptions.TerraformCommand = "" + + err = runall.Run(context.Background(), tgOptions) + require.Error(t, err) + + var missingCommand runall.MissingCommand + ok := errors.As(err, &missingCommand) + fmt.Println(err, errors.Unwrap(err)) + assert.True(t, ok) +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.16/cli/commands/common/runall/command.go new/terragrunt-0.75.0/cli/commands/common/runall/command.go --- old/terragrunt-0.73.16/cli/commands/common/runall/command.go 1970-01-01 01:00:00.000000000 +0100 +++ new/terragrunt-0.75.0/cli/commands/common/runall/command.go 2025-03-03 15:42:15.000000000 +0100 @@ -0,0 +1,81 @@ +// Package runall provides the feature that runs a terraform command +// against a 'stack' by running the specified command in each subfolder. +package runall + +import ( + "context" + + "github.com/gruntwork-io/terragrunt/cli/commands/common" + "github.com/gruntwork-io/terragrunt/cli/flags" + "github.com/gruntwork-io/terragrunt/internal/cli" + "github.com/gruntwork-io/terragrunt/internal/errors" + "github.com/gruntwork-io/terragrunt/options" +) + +const ( + AllFlagName = "all" + OutDirFlagName = "out-dir" + JSONOutDirFlagName = "json-out-dir" + + DeprecatedOutDirFlagName = "out-dir" + DeprecatedJSONOutDirFlagName = "json-out-dir" +) + +func NewFlags(opts *options.TerragruntOptions, commandName string, prefix flags.Prefix) cli.Flags { + tgPrefix := prefix.Prepend(flags.TgPrefix) + terragruntPrefix := flags.Prefix{flags.TerragruntPrefix} + terragruntPrefixControl := flags.StrictControlsByCommand(opts.StrictControls, commandName) + + return cli.Flags{ + flags.NewFlag(&cli.BoolFlag{ + Name: AllFlagName, + EnvVars: tgPrefix.EnvVars(AllFlagName), + Destination: &opts.RunAll, + Usage: `Run the specified OpenTofu/Terraform command on the stack of units in the current directory.`, + Action: func(_ *cli.Context, _ bool) error { + if opts.Graph { + return errors.New(new(common.AllGraphFlagsError)) + } + + return nil + }, + }), + + flags.NewFlag(&cli.GenericFlag[string]{ + Name: OutDirFlagName, + EnvVars: tgPrefix.EnvVars(OutDirFlagName), + Destination: &opts.OutputFolder, + Usage: "Directory to store plan files.", + }, + flags.WithDeprecatedNames(terragruntPrefix.FlagNames(DeprecatedOutDirFlagName), terragruntPrefixControl)), + + flags.NewFlag(&cli.GenericFlag[string]{ + Name: JSONOutDirFlagName, + EnvVars: tgPrefix.EnvVars(JSONOutDirFlagName), + Destination: &opts.JSONOutputFolder, + Usage: "Directory to store json plan files.", + }, + flags.WithDeprecatedNames(terragruntPrefix.FlagNames(DeprecatedJSONOutDirFlagName), terragruntPrefixControl)), + } +} + +// WrapCommand appends flags to the given `cmd` and wraps its action. +func WrapCommand(opts *options.TerragruntOptions, cmd *cli.Command) *cli.Command { + cmd = cmd.WrapAction(func(cliCtx *cli.Context, action cli.ActionFunc) error { + if !opts.RunAll { + return action(cliCtx) + } + + opts.RunTerragrunt = func(ctx context.Context, opts *options.TerragruntOptions) error { + cliCtx := cliCtx.WithValue(options.ContextKey, opts) + return action(cliCtx) + } + + return Run(cliCtx, opts.OptionsFromContext(cliCtx)) + }) + + flags := append(cmd.Flags, NewFlags(opts, cmd.Name, nil)...) + cmd.Flags = flags.Sort() + + return cmd +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.16/cli/commands/common/runall/errors.go new/terragrunt-0.75.0/cli/commands/common/runall/errors.go --- old/terragrunt-0.73.16/cli/commands/common/runall/errors.go 1970-01-01 01:00:00.000000000 +0100 +++ new/terragrunt-0.75.0/cli/commands/common/runall/errors.go 2025-03-03 15:42:15.000000000 +0100 @@ -0,0 +1,18 @@ +package runall + +import "fmt" + +type RunAllDisabledErr struct { + command string + reason string +} + +func (err RunAllDisabledErr) Error() string { + return fmt.Sprintf("%s with run-all is disabled: %s", err.command, err.reason) +} + +type MissingCommand struct{} + +func (err MissingCommand) Error() string { + return "Missing run-all command argument (Example: terragrunt run-all plan)" +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.16/cli/commands/graph/action.go new/terragrunt-0.75.0/cli/commands/graph/action.go --- old/terragrunt-0.73.16/cli/commands/graph/action.go 2025-02-28 19:14:10.000000000 +0100 +++ new/terragrunt-0.75.0/cli/commands/graph/action.go 1970-01-01 01:00:00.000000000 +0100 @@ -1,70 +0,0 @@ -package graph - -import ( - "context" - "errors" - - runall "github.com/gruntwork-io/terragrunt/cli/commands/run-all" - - "github.com/gruntwork-io/terragrunt/cli/commands/run" - "github.com/gruntwork-io/terragrunt/config" - "github.com/gruntwork-io/terragrunt/util" - - "github.com/gruntwork-io/terragrunt/configstack" - "github.com/gruntwork-io/terragrunt/options" - "github.com/gruntwork-io/terragrunt/shell" -) - -func Run(ctx context.Context, opts *options.TerragruntOptions) error { - target := run.NewTarget(run.TargetPointParseConfig, graph) - - return run.RunWithTarget(ctx, opts, target) -} - -func graph(ctx context.Context, opts *options.TerragruntOptions, cfg *config.TerragruntConfig) error { - if cfg == nil { - return errors.New("terragrunt was not able to render the config as json because it received no config. This is almost certainly a bug in Terragrunt. Please open an issue on github.com/gruntwork-io/terragrunt with this message and the contents of your terragrunt.hcl") - } - // consider root for graph identification passed destroy-graph-root argument - rootDir := opts.GraphRoot - - // if destroy-graph-root is empty, use git to find top level dir. - // may cause issues if in the same repo exist unrelated modules which will generate errors when scanning. - if rootDir == "" { - gitRoot, err := shell.GitTopLevelDir(ctx, opts, opts.WorkingDir) - if err != nil { - return err - } - - rootDir = gitRoot - } - - rootOptions, err := opts.CloneWithConfigPath(rootDir) - if err != nil { - return err - } - - rootOptions.WorkingDir = rootDir - - stack, err := configstack.FindStackInSubfolders(ctx, rootOptions) - if err != nil { - return err - } - - dependentModules := stack.ListStackDependentModules() - - workDir := opts.WorkingDir - modulesToInclude := dependentModules[workDir] - // workdir to list too - modulesToInclude = append(modulesToInclude, workDir) - - // include from stack only elements from modulesToInclude - for _, module := range stack.Modules { - module.FlagExcluded = true - if util.ListContainsElement(modulesToInclude, module.Path) { - module.FlagExcluded = false - } - } - - return runall.RunAllOnStack(ctx, opts, stack) -} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.16/cli/commands/graph/command.go new/terragrunt-0.75.0/cli/commands/graph/command.go --- old/terragrunt-0.73.16/cli/commands/graph/command.go 2025-02-28 19:14:10.000000000 +0100 +++ new/terragrunt-0.75.0/cli/commands/graph/command.go 2025-03-03 15:42:15.000000000 +0100 @@ -6,47 +6,30 @@ "sort" awsproviderpatch "github.com/gruntwork-io/terragrunt/cli/commands/aws-provider-patch" + "github.com/gruntwork-io/terragrunt/cli/commands/common/graph" graphdependencies "github.com/gruntwork-io/terragrunt/cli/commands/graph-dependencies" "github.com/gruntwork-io/terragrunt/cli/commands/hclfmt" renderjson "github.com/gruntwork-io/terragrunt/cli/commands/render-json" "github.com/gruntwork-io/terragrunt/cli/commands/run" terragruntinfo "github.com/gruntwork-io/terragrunt/cli/commands/terragrunt-info" validateinputs "github.com/gruntwork-io/terragrunt/cli/commands/validate-inputs" - "github.com/gruntwork-io/terragrunt/cli/flags" "github.com/gruntwork-io/terragrunt/internal/cli" "github.com/gruntwork-io/terragrunt/options" ) const ( CommandName = "graph" - - GraphRootFlagName = "graph-root" - - DeprecatedGraphRootFlagName = "graph-root" ) -func NewFlags(opts *options.TerragruntOptions, prefix flags.Prefix) cli.Flags { - tgPrefix := prefix.Prepend(flags.TgPrefix) - terragruntPrefix := flags.Prefix{flags.TerragruntPrefix} - terragruntPrefixControl := flags.StrictControlsByCommand(opts.StrictControls, CommandName) - - return cli.Flags{ - flags.NewFlag(&cli.GenericFlag[string]{ - Name: GraphRootFlagName, - EnvVars: tgPrefix.EnvVars(GraphRootFlagName), - Destination: &opts.GraphRoot, - Usage: "Root directory from where to build graph dependencies.", - }, - flags.WithDeprecatedName(terragruntPrefix.FlagName(DeprecatedGraphRootFlagName), terragruntPrefixControl)), - } -} - func NewCommand(opts *options.TerragruntOptions) *cli.Command { + flags := graph.NewFlags(opts, CommandName, nil).Filter(graph.GraphRootFlagName) + flags = append(flags, run.NewFlags(opts, nil)...) + return &cli.Command{ Name: CommandName, Usage: "Execute commands on the full graph of dependent modules for the current module, ensuring correct execution order.", ErrorOnUndefinedFlag: true, - Flags: append(run.NewFlags(opts, nil), NewFlags(opts, nil)...).Sort(), + Flags: flags.Sort(), Subcommands: subCommands(opts).SkipRunning(), Action: action(opts), } @@ -64,7 +47,7 @@ return run.Run(ctx, opts) } - return Run(cliCtx.Context, opts.OptionsFromContext(cliCtx)) + return graph.Run(cliCtx.Context, opts.OptionsFromContext(cliCtx)) } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.16/cli/commands/graph-dependencies/command.go new/terragrunt-0.75.0/cli/commands/graph-dependencies/command.go --- old/terragrunt-0.73.16/cli/commands/graph-dependencies/command.go 2025-02-28 19:14:10.000000000 +0100 +++ new/terragrunt-0.75.0/cli/commands/graph-dependencies/command.go 2025-03-03 15:42:15.000000000 +0100 @@ -2,6 +2,8 @@ package graphdependencies import ( + "github.com/gruntwork-io/terragrunt/cli/commands/common/graph" + "github.com/gruntwork-io/terragrunt/cli/commands/common/runall" "github.com/gruntwork-io/terragrunt/cli/commands/run" "github.com/gruntwork-io/terragrunt/internal/cli" "github.com/gruntwork-io/terragrunt/options" @@ -12,10 +14,15 @@ ) func NewCommand(opts *options.TerragruntOptions) *cli.Command { - return &cli.Command{ + cmd := &cli.Command{ Name: CommandName, Flags: run.NewFlags(opts, nil), Usage: "Prints the terragrunt dependency graph to stdout.", Action: func(ctx *cli.Context) error { return Run(ctx, opts.OptionsFromContext(ctx)) }, } + + cmd = runall.WrapCommand(opts, cmd) + cmd = graph.WrapCommand(opts, cmd) + + return cmd } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.16/cli/commands/hclfmt/command.go new/terragrunt-0.75.0/cli/commands/hclfmt/command.go --- old/terragrunt-0.73.16/cli/commands/hclfmt/command.go 2025-02-28 19:14:10.000000000 +0100 +++ new/terragrunt-0.75.0/cli/commands/hclfmt/command.go 2025-03-03 15:42:15.000000000 +0100 @@ -2,6 +2,8 @@ package hclfmt import ( + "github.com/gruntwork-io/terragrunt/cli/commands/common/graph" + "github.com/gruntwork-io/terragrunt/cli/commands/common/runall" "github.com/gruntwork-io/terragrunt/cli/flags" "github.com/gruntwork-io/terragrunt/internal/cli" "github.com/gruntwork-io/terragrunt/options" @@ -74,11 +76,16 @@ func NewCommand(opts *options.TerragruntOptions) *cli.Command { prefix := flags.Prefix{CommandName} - return &cli.Command{ + cmd := &cli.Command{ Name: CommandName, Usage: "Recursively find hcl files and rewrite them into a canonical format.", Flags: NewFlags(opts, prefix).Sort(), ErrorOnUndefinedFlag: true, Action: func(ctx *cli.Context) error { return Run(opts.OptionsFromContext(ctx)) }, } + + cmd = runall.WrapCommand(opts, cmd) + cmd = graph.WrapCommand(opts, cmd) + + return cmd } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.16/cli/commands/render-json/command.go new/terragrunt-0.75.0/cli/commands/render-json/command.go --- old/terragrunt-0.73.16/cli/commands/render-json/command.go 2025-02-28 19:14:10.000000000 +0100 +++ new/terragrunt-0.75.0/cli/commands/render-json/command.go 2025-03-03 15:42:15.000000000 +0100 @@ -2,6 +2,8 @@ package renderjson import ( + "github.com/gruntwork-io/terragrunt/cli/commands/common/graph" + "github.com/gruntwork-io/terragrunt/cli/commands/common/runall" "github.com/gruntwork-io/terragrunt/cli/commands/run" "github.com/gruntwork-io/terragrunt/cli/flags" "github.com/gruntwork-io/terragrunt/internal/cli" @@ -53,11 +55,16 @@ func NewCommand(opts *options.TerragruntOptions) *cli.Command { prefix := flags.Prefix{CommandName} - return &cli.Command{ + cmd := &cli.Command{ Name: CommandName, Usage: "Render the final terragrunt config, with all variables, includes, and functions resolved, as json.", Description: "This is useful for enforcing policies using static analysis tools like Open Policy Agent, or for debugging your terragrunt config.", Flags: append(run.NewFlags(opts, nil), NewFlags(opts, prefix)...).Sort(), Action: func(ctx *cli.Context) error { return Run(ctx, opts.OptionsFromContext(ctx)) }, } + + cmd = runall.WrapCommand(opts, cmd) + cmd = graph.WrapCommand(opts, cmd) + + return cmd } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.16/cli/commands/run/command.go new/terragrunt-0.75.0/cli/commands/run/command.go --- old/terragrunt-0.73.16/cli/commands/run/command.go 2025-02-28 19:14:10.000000000 +0100 +++ new/terragrunt-0.75.0/cli/commands/run/command.go 2025-03-03 15:42:15.000000000 +0100 @@ -5,6 +5,8 @@ "strings" "github.com/gruntwork-io/go-commons/collections" + "github.com/gruntwork-io/terragrunt/cli/commands/common/graph" + "github.com/gruntwork-io/terragrunt/cli/commands/common/runall" "github.com/gruntwork-io/terragrunt/internal/cli" "github.com/gruntwork-io/terragrunt/internal/errors" "github.com/gruntwork-io/terragrunt/internal/experiment" @@ -17,7 +19,7 @@ ) func NewCommand(opts *options.TerragruntOptions) *cli.Command { - return &cli.Command{ + cmd := &cli.Command{ Name: CommandName, Usage: "Run an OpenTofu/Terraform command.", UsageText: "terragrunt run [options] -- <tofu/terraform command>", @@ -32,11 +34,14 @@ Flags: NewFlags(opts, nil), ErrorOnUndefinedFlag: true, Subcommands: NewSubcommands(opts), - Action: func(ctx *cli.Context) error { + Before: func(ctx *cli.Context) error { if !opts.Experiments.Evaluate(experiment.CLIRedesign) { return cli.NewExitError(errors.Errorf("requires that the %[1]s experiment is enabled. e.g. --experiment %[1]s", experiment.CLIRedesign), cli.ExitCodeGeneralError) } + return nil + }, + Action: func(ctx *cli.Context) error { if len(ctx.Args()) == 0 { return cli.ShowCommandHelp(ctx) } @@ -44,6 +49,11 @@ return Action(opts)(ctx) }, } + + cmd = runall.WrapCommand(opts, cmd) + cmd = graph.WrapCommand(opts, cmd) + + return cmd } func NewSubcommands(opts *options.TerragruntOptions) cli.Commands { @@ -52,7 +62,7 @@ for i, name := range tf.CommandNames { usage, visible := tf.CommandUsages[name] - subcommands[i] = &cli.Command{ + subcommand := &cli.Command{ Name: name, Usage: usage, Hidden: !visible, @@ -62,6 +72,7 @@ return Action(opts)(ctx) }, } + subcommands[i] = subcommand } return subcommands diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.16/cli/commands/run/flags.go new/terragrunt-0.75.0/cli/commands/run/flags.go --- old/terragrunt-0.73.16/cli/commands/run/flags.go 2025-02-28 19:14:10.000000000 +0100 +++ new/terragrunt-0.75.0/cli/commands/run/flags.go 2025-03-03 15:42:15.000000000 +0100 @@ -6,15 +6,12 @@ "github.com/gruntwork-io/terragrunt/cli/flags" "github.com/gruntwork-io/terragrunt/internal/cli" - "github.com/gruntwork-io/terragrunt/internal/errors" "github.com/gruntwork-io/terragrunt/internal/strict/controls" "github.com/gruntwork-io/terragrunt/options" "github.com/gruntwork-io/terragrunt/util" ) const ( - AllFlagName = "all" - GraphFlagName = "graph" ConfigFlagName = "config" NoAutoInitFlagName = "no-auto-init" NoAutoRetryFlagName = "no-auto-retry" @@ -137,24 +134,6 @@ legacyLogsControl := flags.StrictControlsByCommand(opts.StrictControls, CommandName, controls.LegacyLogs) flags := cli.Flags{ - flags.NewFlag(&cli.BoolFlag{ - Name: AllFlagName, - EnvVars: tgPrefix.EnvVars(AllFlagName), - Usage: `Run the specified OpenTofu/Terraform command on the stack of units in the current directory.`, - Action: func(_ *cli.Context, _ bool) error { - return errors.Errorf("`--%s` flag is under development", AllFlagName) - }, - }), - - flags.NewFlag(&cli.BoolFlag{ - Name: GraphFlagName, - EnvVars: tgPrefix.EnvVars(GraphFlagName), - Usage: "Run the specified OpenTofu/Terraform command following the Directed Acyclic Graph (DAG) of dependencies.", - Action: func(_ *cli.Context, _ bool) error { - return errors.Errorf("`--%s` flag is under development", GraphFlagName) - }, - }), - // Backward compatibility with `terragrunt-` prefix flags. flags.NewFlag(&cli.GenericFlag[string]{ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.16/cli/commands/run-all/action.go new/terragrunt-0.75.0/cli/commands/run-all/action.go --- old/terragrunt-0.73.16/cli/commands/run-all/action.go 2025-02-28 19:14:10.000000000 +0100 +++ new/terragrunt-0.75.0/cli/commands/run-all/action.go 1970-01-01 01:00:00.000000000 +0100 @@ -1,88 +0,0 @@ -package runall - -import ( - "context" - - "github.com/gruntwork-io/terragrunt/configstack" - "github.com/gruntwork-io/terragrunt/internal/errors" - "github.com/gruntwork-io/terragrunt/options" - "github.com/gruntwork-io/terragrunt/shell" - "github.com/gruntwork-io/terragrunt/telemetry" - "github.com/gruntwork-io/terragrunt/tf" -) - -// Known terraform commands that are explicitly not supported in run-all due to the nature of the command. This is -// tracked as a map that maps the terraform command to the reasoning behind disallowing the command in run-all. -var runAllDisabledCommands = map[string]string{ - tf.CommandNameImport: "terraform import should only be run against a single state representation to avoid injecting the wrong object in the wrong state representation.", - tf.CommandNameTaint: "terraform taint should only be run against a single state representation to avoid using the wrong state address.", - tf.CommandNameUntaint: "terraform untaint should only be run against a single state representation to avoid using the wrong state address.", - tf.CommandNameConsole: "terraform console requires stdin, which is shared across all instances of run-all when multiple modules run concurrently.", - tf.CommandNameForceUnlock: "lock IDs are unique per state representation and thus should not be run with run-all.", - - // MAINTAINER'S NOTE: There are a few other commands that might not make sense, but we deliberately allow it for - // certain use cases that are documented here: - // - state : Supporting `state` with run-all could be useful for a mass pull and push operation, which can - // be done en masse with the use of relative pathing. - // - login / logout : Supporting `login` with run-all could be useful when used in conjunction with mise and - // multi-terraform version setups, where multiple terraform versions need to be configured. - // - version : Supporting `version` with run-all could be useful for sanity checking a multi-version setup. -} - -func Run(ctx context.Context, opts *options.TerragruntOptions) error { - if opts.TerraformCommand == "" { - return errors.New(MissingCommand{}) - } - - reason, isDisabled := runAllDisabledCommands[opts.TerraformCommand] - if isDisabled { - return RunAllDisabledErr{ - command: opts.TerraformCommand, - reason: reason, - } - } - - stack, err := configstack.FindStackInSubfolders(ctx, opts) - if err != nil { - return err - } - - return RunAllOnStack(ctx, opts, stack) -} - -func RunAllOnStack(ctx context.Context, opts *options.TerragruntOptions, stack *configstack.Stack) error { - opts.Logger.Debugf("%s", stack.String()) - - if err := stack.LogModuleDeployOrder(opts.Logger, opts.TerraformCommand); err != nil { - return err - } - - var prompt string - - switch opts.TerraformCommand { - case tf.CommandNameApply: - prompt = "Are you sure you want to run 'terragrunt apply' in each folder of the stack described above?" - case tf.CommandNameDestroy: - prompt = "WARNING: Are you sure you want to run `terragrunt destroy` in each folder of the stack described above? There is no undo!" - case tf.CommandNameState: - prompt = "Are you sure you want to manipulate the state with `terragrunt state` in each folder of the stack described above? Note that absolute paths are shared, while relative paths will be relative to each working directory." - } - - if prompt != "" { - shouldRunAll, err := shell.PromptUserForYesNo(ctx, prompt, opts) - if err != nil { - return err - } - - if !shouldRunAll { - return nil - } - } - - return telemetry.Telemetry(ctx, opts, "run_all_on_stack", map[string]interface{}{ - "terraform_command": opts.TerraformCommand, - "working_dir": opts.WorkingDir, - }, func(childCtx context.Context) error { - return stack.Run(ctx, opts) - }) -} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.16/cli/commands/run-all/action_test.go new/terragrunt-0.75.0/cli/commands/run-all/action_test.go --- old/terragrunt-0.73.16/cli/commands/run-all/action_test.go 2025-02-28 19:14:10.000000000 +0100 +++ new/terragrunt-0.75.0/cli/commands/run-all/action_test.go 1970-01-01 01:00:00.000000000 +0100 @@ -1,30 +0,0 @@ -package runall_test - -import ( - "context" - "errors" - "fmt" - "testing" - - runall "github.com/gruntwork-io/terragrunt/cli/commands/run-all" - "github.com/gruntwork-io/terragrunt/options" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestMissingRunAllArguments(t *testing.T) { - t.Parallel() - - tgOptions, err := options.NewTerragruntOptionsForTest("") - require.NoError(t, err) - - tgOptions.TerraformCommand = "" - - err = runall.Run(context.Background(), tgOptions) - require.Error(t, err) - - var missingCommand runall.MissingCommand - ok := errors.As(err, &missingCommand) - fmt.Println(err, errors.Unwrap(err)) - assert.True(t, ok) -} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.16/cli/commands/run-all/command.go new/terragrunt-0.75.0/cli/commands/run-all/command.go --- old/terragrunt-0.73.16/cli/commands/run-all/command.go 2025-02-28 19:14:10.000000000 +0100 +++ new/terragrunt-0.75.0/cli/commands/run-all/command.go 2025-03-03 15:42:15.000000000 +0100 @@ -6,59 +6,32 @@ "sort" awsproviderpatch "github.com/gruntwork-io/terragrunt/cli/commands/aws-provider-patch" + "github.com/gruntwork-io/terragrunt/cli/commands/common/runall" graphdependencies "github.com/gruntwork-io/terragrunt/cli/commands/graph-dependencies" "github.com/gruntwork-io/terragrunt/cli/commands/hclfmt" renderjson "github.com/gruntwork-io/terragrunt/cli/commands/render-json" "github.com/gruntwork-io/terragrunt/cli/commands/run" terragruntinfo "github.com/gruntwork-io/terragrunt/cli/commands/terragrunt-info" validateinputs "github.com/gruntwork-io/terragrunt/cli/commands/validate-inputs" - "github.com/gruntwork-io/terragrunt/cli/flags" "github.com/gruntwork-io/terragrunt/internal/cli" "github.com/gruntwork-io/terragrunt/options" ) const ( CommandName = "run-all" - - OutDirFlagName = "out-dir" - JSONOutDirFlagName = "json-out-dir" - - DeprecatedOutDirFlagName = "out-dir" - DeprecatedJSONOutDirFlagName = "json-out-dir" ) func NewCommand(opts *options.TerragruntOptions) *cli.Command { + flags := runall.NewFlags(opts, CommandName, nil).Filter(runall.OutDirFlagName, runall.JSONOutDirFlagName) + flags = append(flags, run.NewFlags(opts, nil)...) + return &cli.Command{ Name: CommandName, Usage: "Run a terraform command against a 'stack' by running the specified command in each subfolder.", Description: "The command will recursively find terragrunt modules in the current directory tree and run the terraform command in dependency order (unless the command is destroy, in which case the command is run in reverse dependency order).", Subcommands: subCommands(opts).SkipRunning(), Action: action(opts), - Flags: append(run.NewFlags(opts, nil), NewFlags(opts, nil)...).Sort(), - } -} - -func NewFlags(opts *options.TerragruntOptions, prefix flags.Prefix) cli.Flags { - tgPrefix := prefix.Prepend(flags.TgPrefix) - terragruntPrefix := flags.Prefix{flags.TerragruntPrefix} - terragruntPrefixControl := flags.StrictControlsByCommand(opts.StrictControls, CommandName) - - return cli.Flags{ - flags.NewFlag(&cli.GenericFlag[string]{ - Name: OutDirFlagName, - EnvVars: tgPrefix.EnvVars(OutDirFlagName), - Destination: &opts.OutputFolder, - Usage: "Directory to store plan files.", - }, - flags.WithDeprecatedNames(terragruntPrefix.FlagNames(DeprecatedOutDirFlagName), terragruntPrefixControl)), - - flags.NewFlag(&cli.GenericFlag[string]{ - Name: JSONOutDirFlagName, - EnvVars: tgPrefix.EnvVars(JSONOutDirFlagName), - Destination: &opts.JSONOutputFolder, - Usage: "Directory to store json plan files.", - }, - flags.WithDeprecatedNames(terragruntPrefix.FlagNames(DeprecatedJSONOutDirFlagName), terragruntPrefixControl)), + Flags: flags.Sort(), } } @@ -73,7 +46,7 @@ return run.Run(ctx, opts) } - return Run(cliCtx.Context, opts.OptionsFromContext(cliCtx)) + return runall.Run(cliCtx.Context, opts.OptionsFromContext(cliCtx)) } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.16/cli/commands/run-all/errors.go new/terragrunt-0.75.0/cli/commands/run-all/errors.go --- old/terragrunt-0.73.16/cli/commands/run-all/errors.go 2025-02-28 19:14:10.000000000 +0100 +++ new/terragrunt-0.75.0/cli/commands/run-all/errors.go 1970-01-01 01:00:00.000000000 +0100 @@ -1,18 +0,0 @@ -package runall - -import "fmt" - -type RunAllDisabledErr struct { - command string - reason string -} - -func (err RunAllDisabledErr) Error() string { - return fmt.Sprintf("%s with run-all is disabled: %s", err.command, err.reason) -} - -type MissingCommand struct{} - -func (err MissingCommand) Error() string { - return "Missing run-all command argument (Example: terragrunt run-all plan)" -} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.16/cli/commands/stack/action.go new/terragrunt-0.75.0/cli/commands/stack/action.go --- old/terragrunt-0.73.16/cli/commands/stack/action.go 2025-02-28 19:14:10.000000000 +0100 +++ new/terragrunt-0.75.0/cli/commands/stack/action.go 2025-03-03 15:42:15.000000000 +0100 @@ -5,9 +5,9 @@ "os" "path/filepath" + "github.com/gruntwork-io/terragrunt/cli/commands/common/runall" "github.com/gruntwork-io/terragrunt/config" - runall "github.com/gruntwork-io/terragrunt/cli/commands/run-all" "github.com/gruntwork-io/terragrunt/internal/cli" "github.com/gruntwork-io/terragrunt/internal/experiment" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.16/cli/commands/terragrunt-info/command.go new/terragrunt-0.75.0/cli/commands/terragrunt-info/command.go --- old/terragrunt-0.73.16/cli/commands/terragrunt-info/command.go 2025-02-28 19:14:10.000000000 +0100 +++ new/terragrunt-0.75.0/cli/commands/terragrunt-info/command.go 2025-03-03 15:42:15.000000000 +0100 @@ -2,6 +2,8 @@ package terragruntinfo import ( + "github.com/gruntwork-io/terragrunt/cli/commands/common/graph" + "github.com/gruntwork-io/terragrunt/cli/commands/common/runall" "github.com/gruntwork-io/terragrunt/cli/commands/run" "github.com/gruntwork-io/terragrunt/internal/cli" "github.com/gruntwork-io/terragrunt/options" @@ -12,10 +14,15 @@ ) func NewCommand(opts *options.TerragruntOptions) *cli.Command { - return &cli.Command{ + cmd := &cli.Command{ Name: CommandName, Flags: run.NewFlags(opts, nil), Usage: "Emits limited terragrunt state on stdout and exits.", Action: func(ctx *cli.Context) error { return Run(ctx, opts.OptionsFromContext(ctx)) }, } + + cmd = runall.WrapCommand(opts, cmd) + cmd = graph.WrapCommand(opts, cmd) + + return cmd } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.16/cli/commands/validate-inputs/command.go new/terragrunt-0.75.0/cli/commands/validate-inputs/command.go --- old/terragrunt-0.73.16/cli/commands/validate-inputs/command.go 2025-02-28 19:14:10.000000000 +0100 +++ new/terragrunt-0.75.0/cli/commands/validate-inputs/command.go 2025-03-03 15:42:15.000000000 +0100 @@ -3,6 +3,8 @@ package validateinputs import ( + "github.com/gruntwork-io/terragrunt/cli/commands/common/graph" + "github.com/gruntwork-io/terragrunt/cli/commands/common/runall" "github.com/gruntwork-io/terragrunt/cli/commands/run" "github.com/gruntwork-io/terragrunt/cli/flags" "github.com/gruntwork-io/terragrunt/internal/cli" @@ -34,10 +36,15 @@ } func NewCommand(opts *options.TerragruntOptions) *cli.Command { - return &cli.Command{ + cmd := &cli.Command{ Name: CommandName, Usage: "Checks if the terragrunt configured inputs align with the terraform defined variables.", Flags: append(run.NewFlags(opts, nil), NewFlags(opts, nil)...).Sort(), Action: func(ctx *cli.Context) error { return Run(ctx, opts.OptionsFromContext(ctx)) }, } + + cmd = runall.WrapCommand(opts, cmd) + cmd = graph.WrapCommand(opts, cmd) + + return cmd } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.16/docs/_docs/04_reference/06-experiments.md new/terragrunt-0.75.0/docs/_docs/04_reference/06-experiments.md --- old/terragrunt-0.73.16/docs/_docs/04_reference/06-experiments.md 2025-02-28 19:14:10.000000000 +0100 +++ new/terragrunt-0.75.0/docs/_docs/04_reference/06-experiments.md 2025-03-03 15:42:15.000000000 +0100 @@ -143,10 +143,10 @@ To transition `cli-redesign` features to a stable release, the following must be addressed: -- [ ] Add support for `run` command. +- [x] Add support for `run` command. - [x] Add support for basic usage of the `run` command (e.g., `terragrunt run plan`, `terragrunt run -- plan -no-color`). - - [ ] Add support for the `--all` flag. - - [ ] Add support for the `--graph` flag. + - [x] Add support for the `--all` flag. + - [x] Add support for the `--graph` flag. - [x] Add support for `exec` command. - [x] Rename legacy `--terragrunt-` prefixed flags so that they no longer need the prefix. - [ ] Add the `hcl` command, replacing commands like `hclfmt`, `hclvalidate` and `validate-inputs`. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.16/docs/_docs/04_reference/07-supported-versions.md new/terragrunt-0.75.0/docs/_docs/04_reference/07-supported-versions.md --- old/terragrunt-0.73.16/docs/_docs/04_reference/07-supported-versions.md 2025-02-28 19:14:10.000000000 +0100 +++ new/terragrunt-0.75.0/docs/_docs/04_reference/07-supported-versions.md 2025-03-03 15:42:15.000000000 +0100 @@ -28,6 +28,8 @@ | Terraform Version | Terragrunt Version | |-------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------| +| 1.11.x | >= [0.75.0](https://github.com/gruntwork-io/terragrunt/releases/tag/v0.75.0) | +| 1.10.x | >= [0.74.0](https://github.com/gruntwork-io/terragrunt/releases/tag/v0.74.0) | | 1.9.x | >= [0.60.0](https://github.com/gruntwork-io/terragrunt/releases/tag/v0.60.0) | | 1.8.x | >= [0.57.0](https://github.com/gruntwork-io/terragrunt/releases/tag/v0.57.0) | | 1.7.x | >= [0.56.0](https://github.com/gruntwork-io/terragrunt/releases/tag/v0.56.0) | diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.16/docs-starlight/src/content/docs/04-reference/04-experiments.md new/terragrunt-0.75.0/docs-starlight/src/content/docs/04-reference/04-experiments.md --- old/terragrunt-0.73.16/docs-starlight/src/content/docs/04-reference/04-experiments.md 2025-02-28 19:14:10.000000000 +0100 +++ new/terragrunt-0.75.0/docs-starlight/src/content/docs/04-reference/04-experiments.md 2025-03-03 15:42:15.000000000 +0100 @@ -143,10 +143,10 @@ To transition `cli-redesign` features to a stable release, the following must be addressed: -- [ ] Add support for `run` command. +- [x] Add support for `run` command. - [x] Add support for basic usage of the `run` command (e.g., `terragrunt run plan`, `terragrunt run -- plan -no-color`). - - [ ] Add support for the `--all` flag. - - [ ] Add support for the `--graph` flag. + - [x] Add support for the `--all` flag. + - [x] Add support for the `--graph` flag. - [x] Add support for `exec` command. - [x] Rename legacy `--terragrunt-` prefixed flags so that they no longer need the prefix. - [ ] Add the `hcl` command, replacing commands like `hclfmt`, `hclvalidate` and `validate-inputs`. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.16/options/options.go new/terragrunt-0.75.0/options/options.go --- old/terragrunt-0.73.16/options/options.go 2025-02-28 19:14:10.000000000 +0100 +++ new/terragrunt-0.75.0/options/options.go 2025-03-03 15:42:15.000000000 +0100 @@ -399,6 +399,12 @@ // StackOutputFormat format how the stack output is rendered. StackOutputFormat string + + // RunAll runs the provided OpenTofu/Terraform command against a stack. + RunAll bool + + // Graph runs the provided OpenTofu/Terraform against the graph of dependencies for the unit in the current working directory. + Graph bool } // TerragruntOptionsFunc is a functional option type used to pass options in certain integration tests diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.16/test/fixtures/ephemeral-inputs/main.tf new/terragrunt-0.75.0/test/fixtures/ephemeral-inputs/main.tf --- old/terragrunt-0.73.16/test/fixtures/ephemeral-inputs/main.tf 1970-01-01 01:00:00.000000000 +0100 +++ new/terragrunt-0.75.0/test/fixtures/ephemeral-inputs/main.tf 2025-03-03 15:42:15.000000000 +0100 @@ -0,0 +1,14 @@ +variable "test" { + type = string + default = "test_value" + ephemeral = true +} + +output "output" { + value = ephemeralasnull(var.test) +} + +resource "local_file" "file" { + content = "test" + filename = "${path.module}/test.txt" +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.16/test/fixtures/ephemeral-inputs/terragrunt.hcl new/terragrunt-0.75.0/test/fixtures/ephemeral-inputs/terragrunt.hcl --- old/terragrunt-0.73.16/test/fixtures/ephemeral-inputs/terragrunt.hcl 1970-01-01 01:00:00.000000000 +0100 +++ new/terragrunt-0.75.0/test/fixtures/ephemeral-inputs/terragrunt.hcl 2025-03-03 15:42:15.000000000 +0100 @@ -0,0 +1,4 @@ + +inputs = { + test = "test input 46521694" +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.16/test/helpers/package.go new/terragrunt-0.75.0/test/helpers/package.go --- old/terragrunt-0.73.16/test/helpers/package.go 2025-02-28 19:14:10.000000000 +0100 +++ new/terragrunt-0.75.0/test/helpers/package.go 2025-03-03 15:42:15.000000000 +0100 @@ -658,10 +658,35 @@ return run.WrongTerraformCommand(command) } +// IsTerraform checks if the wrapped binary currently in use is the Terraform binary. func IsTerraform() bool { return WrappedBinary() == TerraformBinary } +// IsTerraform110OrHigher checks if the installed Terraform binary is version 1.10.0 or higher. +func IsTerraform110OrHigher() bool { + const ( + requiredMajor = 1 + requiredMinor = 10 + ) + + if !IsTerraform() { + return false + } + + output, err := exec.Command(WrappedBinary(), "-version").Output() + if err != nil { + return false + } + + matches := regexp.MustCompile(`Terraform v(\d+)\.(\d+)\.`).FindStringSubmatch(string(output)) + + major, _ := strconv.Atoi(matches[1]) + minor, _ := strconv.Atoi(matches[2]) + + return major > requiredMajor || (major == requiredMajor && minor >= requiredMinor) +} + func FindFilesWithExtension(dir string, ext string) ([]string, error) { var files []string diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.16/test/integration_destroy_test.go new/terragrunt-0.75.0/test/integration_destroy_test.go --- old/terragrunt-0.73.16/test/integration_destroy_test.go 2025-02-28 19:14:10.000000000 +0100 +++ new/terragrunt-0.75.0/test/integration_destroy_test.go 2025-03-03 15:42:15.000000000 +0100 @@ -313,6 +313,9 @@ helpers.CleanupTerraformFolder(t, tmpEnvPath) testPath := util.JoinPath(tmpEnvPath, testFixtureOutDir) + dependencyPath := util.JoinPath(tmpEnvPath, testFixtureOutDir, "dependency") + helpers.RunTerragrunt(t, fmt.Sprintf("terragrunt apply -auto-approve --terragrunt-non-interactive --terragrunt-log-level trace --terragrunt-working-dir %s --terragrunt-out-dir %s", dependencyPath, tmpDir)) + // plan and apply _, _, err := helpers.RunTerragruntCommandWithOutput(t, fmt.Sprintf("terragrunt run-all plan --terragrunt-non-interactive --terragrunt-log-level trace --terragrunt-working-dir %s --terragrunt-out-dir %s", testPath, tmpDir)) require.NoError(t, err) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.16/test/integration_graph_test.go new/terragrunt-0.75.0/test/integration_graph_test.go --- old/terragrunt-0.73.16/test/integration_graph_test.go 2025-02-28 19:14:10.000000000 +0100 +++ new/terragrunt-0.75.0/test/integration_graph_test.go 2025-03-03 15:42:15.000000000 +0100 @@ -86,21 +86,25 @@ t.Parallel() testCases := []struct { + args string path string expectedModules []string notExpectedModules []string }{ { + args: "graph apply --terragrunt-non-interactive --terragrunt-working-dir %s --terragrunt-graph-root %s", path: "services/eks-service-3-v2", expectedModules: []string{"services/eks-service-3-v2", "services/eks-service-3-v3"}, notExpectedModules: []string{"lambda", "eks", "services/eks-service-3"}, }, { + args: "run --graph apply --experiment cli-redesign --terragrunt-non-interactive --terragrunt-working-dir %s --terragrunt-graph-root %s", path: "lambda", expectedModules: []string{"lambda", "services/lambda-service-1", "services/lambda-service-2"}, notExpectedModules: []string{"eks", "services/eks-service-1", "services/eks-service-2", "services/eks-service-3"}, }, { + args: "run apply --graph --experiment cli-redesign --non-interactive --working-dir %s --graph-root %s", path: "services/eks-service-5", expectedModules: []string{"services/eks-service-5"}, notExpectedModules: []string{"eks", "lambda", "services/eks-service-1", "services/eks-service-2", "services/eks-service-3"}, @@ -108,8 +112,6 @@ } for _, testCase := range testCases { - testCase := testCase - t.Run(testCase.path, func(t *testing.T) { t.Parallel() @@ -117,7 +119,7 @@ fixturePath := util.JoinPath(tmpEnvPath, testFixtureGraph) tmpModulePath := util.JoinPath(fixturePath, testCase.path) - stdout, stderr, err := helpers.RunTerragruntCommandWithOutput(t, fmt.Sprintf("terragrunt graph apply --terragrunt-non-interactive --terragrunt-working-dir %s --terragrunt-graph-root %s", tmpModulePath, tmpEnvPath)) + stdout, stderr, err := helpers.RunTerragruntCommandWithOutput(t, fmt.Sprintf("terragrunt "+testCase.args, tmpModulePath, tmpEnvPath)) require.NoError(t, err) output := fmt.Sprintf("%v\n%v\n", stdout, stderr) @@ -145,19 +147,32 @@ func TestTerragruntGraphNonTerraformCommandExecution(t *testing.T) { t.Parallel() - tmpEnvPath := prepareGraphFixture(t) - tmpModulePath := util.JoinPath(tmpEnvPath, testFixtureGraph, "eks") + testCases := []struct { + args string + }{ + {"graph render-json --terragrunt-non-interactive --terragrunt-working-dir %s --terragrunt-graph-root %s"}, + {"render-json --graph --terragrunt-non-interactive --terragrunt-working-dir %s --terragrunt-graph-root %s"}, + } - stdout := bytes.Buffer{} - stderr := bytes.Buffer{} + for _, testCase := range testCases { + t.Run("terragrunt args: "+testCase.args, func(t *testing.T) { + t.Parallel() - err := helpers.RunTerragruntCommand(t, fmt.Sprintf("terragrunt graph render-json --terragrunt-non-interactive --terragrunt-working-dir %s --terragrunt-graph-root %s", tmpModulePath, tmpEnvPath), &stdout, &stderr) - require.NoError(t, err) + tmpEnvPath := prepareGraphFixture(t) + tmpModulePath := util.JoinPath(tmpEnvPath, testFixtureGraph, "eks") - // check that terragrunt_rendered.json is created in mod1/mod2/mod3 - for _, module := range []string{"services/eks-service-1", "eks"} { - _, err = os.Stat(util.JoinPath(tmpEnvPath, testFixtureGraph, module, "terragrunt_rendered.json")) - require.NoError(t, err) + stdout := bytes.Buffer{} + stderr := bytes.Buffer{} + + err := helpers.RunTerragruntCommand(t, fmt.Sprintf("terragrunt "+testCase.args, tmpModulePath, tmpEnvPath), &stdout, &stderr) + require.NoError(t, err) + + // check that terragrunt_rendered.json is created in mod1/mod2/mod3 + for _, module := range []string{"services/eks-service-1", "eks"} { + _, err = os.Stat(util.JoinPath(tmpEnvPath, testFixtureGraph, module, "terragrunt_rendered.json")) + require.NoError(t, err) + } + }) } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.16/test/integration_test.go new/terragrunt-0.75.0/test/integration_test.go --- old/terragrunt-0.73.16/test/integration_test.go 2025-02-28 19:14:10.000000000 +0100 +++ new/terragrunt-0.75.0/test/integration_test.go 2025-03-03 15:42:15.000000000 +0100 @@ -14,8 +14,9 @@ "testing" "time" + "github.com/gruntwork-io/terragrunt/cli/commands/common" + "github.com/gruntwork-io/terragrunt/cli/commands/common/runall" "github.com/gruntwork-io/terragrunt/cli/commands/run" - runall "github.com/gruntwork-io/terragrunt/cli/commands/run-all" terragruntinfo "github.com/gruntwork-io/terragrunt/cli/commands/terragrunt-info" "github.com/gruntwork-io/terragrunt/cli/flags" "github.com/gruntwork-io/terragrunt/codegen" @@ -109,6 +110,7 @@ textFixtureDisjointSymlinks = "fixtures/stack/disjoint-symlinks" testFixtureLogStreaming = "fixtures/streaming" testFixtureCLIFlagHints = "fixtures/cli-flag-hints" + testFixtureEphemeralInputs = "fixtures/ephemeral-inputs" terraformFolder = ".terraform" @@ -527,12 +529,12 @@ tmpEnvPath := helpers.CopyEnvironment(t, testFixtureLogStdoutLevel) rootPath := util.JoinPath(tmpEnvPath, testFixtureLogStdoutLevel) - stdout, _, err := helpers.RunTerragruntCommandWithOutput(t, "terragrunt apply -auto-approve --terragrunt-log-level trace --terragrunt-non-interactive -no-color --terragrunt-no-color --terragrunt-log-format=pretty --terragrunt-working-dir "+rootPath) + stdout, _, err := helpers.RunTerragruntCommandWithOutput(t, "terragrunt apply -auto-approve --terragrunt-non-interactive -no-color --terragrunt-no-color --terragrunt-log-format=pretty --terragrunt-working-dir "+rootPath) require.NoError(t, err) assert.Contains(t, stdout, "STDOUT "+wrappedBinary()+": Changes to Outputs") - stdout, _, err = helpers.RunTerragruntCommandWithOutput(t, "terragrunt destroy -auto-approve --terragrunt-log-level trace --terragrunt-non-interactive -no-color --terragrunt-no-color --terragrunt-log-format=pretty --terragrunt-working-dir "+rootPath) + stdout, _, err = helpers.RunTerragruntCommandWithOutput(t, "terragrunt destroy -auto-approve --terragrunt-non-interactive -no-color --terragrunt-no-color --terragrunt-log-format=pretty --terragrunt-working-dir "+rootPath) require.NoError(t, err) assert.Contains(t, stdout, "STDOUT "+wrappedBinary()+": Changes to Outputs") @@ -1097,6 +1099,11 @@ nil, }, { + []string{"--", "graph"}, + "digraph", + nil, + }, + { []string{"--", "paln"}, //codespell:ignore "", expectedWrongCommandErr("paln"), //codespell:ignore @@ -1123,7 +1130,7 @@ output := stdout.String() errOutput := stderr.String() - assert.True(t, strings.Contains(errOutput, testCase.expected) || strings.Contains(output, testCase.expected)) + assert.Contains(t, output+errOutput, testCase.expected) } } @@ -3762,6 +3769,9 @@ tmpEnvPath := helpers.CopyEnvironment(t, testFixtureOutDir) helpers.CleanupTerraformFolder(t, tmpEnvPath) testPath := util.JoinPath(tmpEnvPath, testFixtureOutDir) + dependencyPath := util.JoinPath(tmpEnvPath, testFixtureOutDir, "dependency") + + helpers.RunTerragrunt(t, fmt.Sprintf("terragrunt apply -auto-approve --terragrunt-non-interactive --terragrunt-log-level trace --terragrunt-working-dir %s --terragrunt-out-dir %s", dependencyPath, tmpDir)) // run plan with output directory _, output, err := helpers.RunTerragruntCommandWithOutput(t, fmt.Sprintf("terragrunt run-all plan --terragrunt-non-interactive --terragrunt-log-level trace --terragrunt-working-dir %s --terragrunt-out-dir %s", testPath, tmpDir)) @@ -3788,6 +3798,9 @@ helpers.CleanupTerraformFolder(t, tmpEnvPath) testPath := util.JoinPath(tmpEnvPath, testFixtureOutDir) + dependencyPath := util.JoinPath(tmpEnvPath, testFixtureOutDir, "dependency") + helpers.RunTerragrunt(t, fmt.Sprintf("terragrunt apply -auto-approve --terragrunt-non-interactive --terragrunt-log-level trace --terragrunt-working-dir %s --terragrunt-out-dir %s", dependencyPath, testPath)) + // run plan with output directory _, _, err := helpers.RunTerragruntCommandWithOutput(t, fmt.Sprintf("terragrunt run-all plan --terragrunt-non-interactive --terragrunt-log-level trace --terragrunt-working-dir %s --terragrunt-out-dir %s", testPath, "test")) require.NoError(t, err) @@ -3806,28 +3819,52 @@ require.NoError(t, err) } +func TestUsingAllAndGraphFlagsSimultaneously(t *testing.T) { + t.Parallel() + + _, _, err := helpers.RunTerragruntCommandWithOutput(t, "terragrunt run --graph --all") + expectedErr := new(common.AllGraphFlagsError) + require.ErrorAs(t, err, &expectedErr) +} + func TestStorePlanFilesJsonRelativePath(t *testing.T) { t.Parallel() - tmpEnvPath := helpers.CopyEnvironment(t, testFixtureOutDir) - helpers.CleanupTerraformFolder(t, tmpEnvPath) - testPath := util.JoinPath(tmpEnvPath, testFixtureOutDir) + testCases := []struct { + args string + }{ + {"run-all plan --terragrunt-non-interactive --terragrunt-log-level trace --terragrunt-working-dir %s --terragrunt-out-dir test --terragrunt-json-out-dir json"}, + {"run --all plan --experiment cli-redesign --non-interactive --log-level trace --working-dir %s --out-dir test --json-out-dir json"}, + {"run plan --all --experiment cli-redesign --non-interactive --log-level trace --working-dir %s --out-dir test --json-out-dir json"}, + {"run --all --experiment cli-redesign --non-interactive --log-level trace --working-dir %s --out-dir test --json-out-dir json -- plan"}, + } - // run plan with output directory - _, _, err := helpers.RunTerragruntCommandWithOutput(t, fmt.Sprintf("terragrunt run-all plan --terragrunt-non-interactive --terragrunt-log-level trace --terragrunt-working-dir %s --terragrunt-out-dir test --terragrunt-json-out-dir json", testPath)) - require.NoError(t, err) + for _, testCase := range testCases { + t.Run("terragrunt args: "+testCase.args, func(t *testing.T) { + t.Parallel() - // verify that tfplan files are created in the tmpDir, 2 files - outDir := util.JoinPath(testPath, "test") - list, err := findFilesWithExtension(outDir, ".tfplan") - require.NoError(t, err) - assert.Len(t, list, 2) + tmpEnvPath := helpers.CopyEnvironment(t, testFixtureOutDir) + helpers.CleanupTerraformFolder(t, tmpEnvPath) + testPath := util.JoinPath(tmpEnvPath, testFixtureOutDir) - // verify that json files are create - jsonDir := util.JoinPath(testPath, "json") - listJSON, err := findFilesWithExtension(jsonDir, ".json") - require.NoError(t, err) - assert.Len(t, listJSON, 2) + // run plan with output directory + _, _, err := helpers.RunTerragruntCommandWithOutput(t, fmt.Sprintf("terragrunt "+testCase.args, testPath)) + require.NoError(t, err) + + // verify that tfplan files are created in the tmpDir, 2 files + outDir := util.JoinPath(testPath, "test") + list, err := findFilesWithExtension(outDir, ".tfplan") + require.NoError(t, err) + assert.Len(t, list, 2) + + // verify that json files are create + jsonDir := util.JoinPath(testPath, "json") + listJSON, err := findFilesWithExtension(jsonDir, ".json") + require.NoError(t, err) + assert.Len(t, listJSON, 2) + + }) + } } func TestPlanJsonFilesRunAll(t *testing.T) { @@ -3867,6 +3904,9 @@ helpers.CleanupTerraformFolder(t, tmpEnvPath) testPath := util.JoinPath(tmpEnvPath, testFixtureOutDir) + dependencyPath := util.JoinPath(tmpEnvPath, testFixtureOutDir, "dependency") + helpers.RunTerragrunt(t, fmt.Sprintf("terragrunt apply -auto-approve --terragrunt-non-interactive --terragrunt-log-level trace --terragrunt-working-dir %s --terragrunt-out-dir %s", dependencyPath, tmpDir)) + // run plan with output directory _, _, err := helpers.RunTerragruntCommandWithOutput(t, fmt.Sprintf("terragrunt run-all plan --terragrunt-non-interactive --terragrunt-log-level trace --terragrunt-working-dir %s --terragrunt-json-out-dir %s --terragrunt-out-dir %s", testPath, tmpDir, tmpDir)) require.NoError(t, err) @@ -3902,6 +3942,9 @@ helpers.CleanupTerraformFolder(t, tmpEnvPath) testPath := util.JoinPath(tmpEnvPath, testFixtureOutDir) + dependencyPath := util.JoinPath(tmpEnvPath, testFixtureOutDir, "dependency") + helpers.RunTerragrunt(t, fmt.Sprintf("terragrunt apply -auto-approve --terragrunt-non-interactive --terragrunt-log-level trace --terragrunt-working-dir %s --terragrunt-out-dir %s", dependencyPath, tmpDir)) + // run plan and apply _, _, err := helpers.RunTerragruntCommandWithOutput(t, fmt.Sprintf("terragrunt run-all plan --terragrunt-non-interactive --terragrunt-log-level trace --terragrunt-working-dir %s --terragrunt-out-dir %s", testPath, tmpDir)) require.NoError(t, err) @@ -4127,3 +4170,24 @@ assert.Contains(t, stdout, "Initializing the backend...") assert.NotContains(t, stdout, "STDO[0000] Initializing the backend...") } + +func TestTF110EphemeralVars(t *testing.T) { + t.Parallel() + if !helpers.IsTerraform110OrHigher() { + t.Skip("This test requires Terraform 1.10 or higher") + + return + } + + tmpEnvPath := helpers.CopyEnvironment(t, testFixtureEphemeralInputs) + helpers.CleanupTerraformFolder(t, tmpEnvPath) + testPath := util.JoinPath(tmpEnvPath, testFixtureEphemeralInputs) + + stdout, _, err := helpers.RunTerragruntCommandWithOutput(t, "terragrunt plan --terragrunt-non-interactive --terragrunt-working-dir "+testPath) + require.NoError(t, err) + assert.Contains(t, stdout, "Plan: 1 to add, 0 to change, 0 to destroy") + + stdout, _, err = helpers.RunTerragruntCommandWithOutput(t, "terragrunt apply --auto-approve --terragrunt-non-interactive --terragrunt-working-dir "+testPath) + require.NoError(t, err) + assert.Contains(t, stdout, "Apply complete! Resources: 1 added, 0 changed, 0 destroyed") +} ++++++ terragrunt.obsinfo ++++++ --- /var/tmp/diff_new_pack.iFFUZ7/_old 2025-03-05 13:48:04.151523294 +0100 +++ /var/tmp/diff_new_pack.iFFUZ7/_new 2025-03-05 13:48:04.163523797 +0100 @@ -1,5 +1,5 @@ name: terragrunt -version: 0.73.16 -mtime: 1740766450 -commit: 2ede06c52c35d03467c40fd5d668a49ac82ea5da +version: 0.75.0 +mtime: 1741012935 +commit: f83766b7449b60a9c6b0bc17db997cf0139d12a7 ++++++ vendor.tar.gz ++++++ /work/SRC/openSUSE:Factory/terragrunt/vendor.tar.gz /work/SRC/openSUSE:Factory/.terragrunt.new.19136/vendor.tar.gz differ: char 12, line 1