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-02-19 15:59:15 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/terragrunt (Old) and /work/SRC/openSUSE:Factory/.terragrunt.new.25061 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "terragrunt" Wed Feb 19 15:59:15 2025 rev:193 rq:1246856 version:0.73.8 Changes: -------- --- /work/SRC/openSUSE:Factory/terragrunt/terragrunt.changes 2025-02-16 22:51:13.794799623 +0100 +++ /work/SRC/openSUSE:Factory/.terragrunt.new.25061/terragrunt.changes 2025-02-19 16:00:08.588068491 +0100 @@ -1,0 +2,18 @@ +Wed Feb 19 05:55:32 UTC 2025 - opensuse_buildserv...@ojkastl.de + +- Update to version 0.73.8: + * Added --output-folder flag to scaffold (#3805) + * build(deps): bump google.golang.org/api from 0.220.0 to 0.221.0 + (#3893) + +------------------------------------------------------------------- +Wed Feb 19 05:49:57 UTC 2025 - opensuse_buildserv...@ojkastl.de + +- Update to version 0.73.7: + * Stack unit path validation (#3897) + * feat: Clean up TF commands help (#3895) + * build(deps): bump ruby/setup-ruby from 1.215.0 to 1.221.0 + (#3894) + * refactor: replace `golang.org/x/exp` with stdlib (#3881) + +------------------------------------------------------------------- Old: ---- terragrunt-0.73.6.obscpio New: ---- terragrunt-0.73.8.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ terragrunt.spec ++++++ --- /var/tmp/diff_new_pack.K6DUBc/_old 2025-02-19 16:00:09.488106149 +0100 +++ /var/tmp/diff_new_pack.K6DUBc/_new 2025-02-19 16:00:09.492106316 +0100 @@ -17,7 +17,7 @@ Name: terragrunt -Version: 0.73.6 +Version: 0.73.8 Release: 0 Summary: Thin wrapper for Terraform for working with multiple Terraform modules License: MIT ++++++ _service ++++++ --- /var/tmp/diff_new_pack.K6DUBc/_old 2025-02-19 16:00:09.540108324 +0100 +++ /var/tmp/diff_new_pack.K6DUBc/_new 2025-02-19 16:00:09.544108492 +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.6</param> + <param name="revision">v0.73.8</param> <param name="versionformat">@PARENT_TAG@</param> <param name="versionrewrite-pattern">v(.*)</param> <param name="changesgenerate">enable</param> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.K6DUBc/_old 2025-02-19 16:00:09.564109329 +0100 +++ /var/tmp/diff_new_pack.K6DUBc/_new 2025-02-19 16:00:09.564109329 +0100 @@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/gruntwork-io/terragrunt</param> - <param name="changesrevision">cdba05b19fe93a2db56a74468c8786a1a201f395</param></service></servicedata> + <param name="changesrevision">0b550a37186a01e257f9402241a92f769e7b35bc</param></service></servicedata> (No newline at EOF) ++++++ terragrunt-0.73.6.obscpio -> terragrunt-0.73.8.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.6/.github/workflows/pages.yml new/terragrunt-0.73.8/.github/workflows/pages.yml --- old/terragrunt-0.73.6/.github/workflows/pages.yml 2025-02-15 19:09:48.000000000 +0100 +++ new/terragrunt-0.73.8/.github/workflows/pages.yml 2025-02-18 20:16:20.000000000 +0100 @@ -28,7 +28,7 @@ - name: Checkout uses: actions/checkout@v4 - name: Setup Ruby - uses: ruby/setup-ruby@2654679fe7f7c29875c669398a8ec0791b8a64a1 # v1.215.0 + uses: ruby/setup-ruby@32110d4e311bd8996b2a82bf2a43b714ccc91777 # v1.221.0 with: ruby-version: '3.3' bundler-cache: true diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.6/cli/app.go new/terragrunt-0.73.8/cli/app.go --- old/terragrunt-0.73.6/cli/app.go 2025-02-15 19:09:48.000000000 +0100 +++ new/terragrunt-0.73.8/cli/app.go 2025-02-18 20:16:20.000000000 +0100 @@ -6,9 +6,8 @@ "fmt" "os" "path/filepath" - "strings" - "slices" + "strings" "github.com/gruntwork-io/terragrunt/engine" "github.com/gruntwork-io/terragrunt/internal/os/exec" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.6/cli/app_test.go new/terragrunt-0.73.8/cli/app_test.go --- old/terragrunt-0.73.6/cli/app_test.go 2025-02-15 19:09:48.000000000 +0100 +++ new/terragrunt-0.73.8/cli/app_test.go 2025-02-18 20:16:20.000000000 +0100 @@ -5,7 +5,6 @@ "fmt" "os" "path/filepath" - "regexp" "testing" "github.com/gruntwork-io/terragrunt/cli" @@ -456,15 +455,13 @@ func TestTerraformHelp(t *testing.T) { t.Parallel() - wrappedBinary := options.DefaultWrappedPath - testCases := []struct { args []string expected string }{ - {[]string{"terragrunt", tf.CommandNamePlan, "--help"}, "Usage: " + wrappedBinary + " .* plan"}, - {[]string{"terragrunt", tf.CommandNameApply, "-help"}, "Usage: " + wrappedBinary + " .* apply"}, - {[]string{"terragrunt", tf.CommandNameApply, "-h"}, "Usage: " + wrappedBinary + " .* apply"}, + {[]string{"terragrunt", tf.CommandNamePlan, "--help"}, "(?s)Usage: terragrunt \\[global options\\] plan.*-detailed-exitcode"}, + {[]string{"terragrunt", tf.CommandNameApply, "-help"}, "(?s)Usage: terragrunt \\[global options\\] apply.*-destroy"}, + {[]string{"terragrunt", tf.CommandNameApply, "-h"}, "(?s)Usage: terragrunt \\[global options\\] apply.*-destroy"}, } for _, testCase := range testCases { @@ -474,10 +471,7 @@ err := app.Run(testCase.args) require.NoError(t, err) - expectedRegex, err := regexp.Compile(testCase.expected) - require.NoError(t, err) - - assert.Regexp(t, expectedRegex, output.String()) + assert.Regexp(t, testCase.expected, output.String()) } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.6/cli/commands/commands.go new/terragrunt-0.73.8/cli/commands/commands.go --- old/terragrunt-0.73.6/cli/commands/commands.go 2025-02-15 19:09:48.000000000 +0100 +++ new/terragrunt-0.73.8/cli/commands/commands.go 2025-02-18 20:16:20.000000000 +0100 @@ -29,7 +29,7 @@ // Command category names. const ( - // MainCommandsCategoryName represents primary Terragrunt operations like run, run-all. + // MainCommandsCategoryName represents primary Terragrunt operations like run, exec. MainCommandsCategoryName = "Main commands" // CatalogCommandsCategoryName represents commands for managing Terragrunt catalogs. CatalogCommandsCategoryName = "Catalog commands" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.6/cli/commands/help/command.go new/terragrunt-0.73.8/cli/commands/help/command.go --- old/terragrunt-0.73.6/cli/commands/help/command.go 2025-02-15 19:09:48.000000000 +0100 +++ new/terragrunt-0.73.8/cli/commands/help/command.go 2025-02-18 20:16:20.000000000 +0100 @@ -38,7 +38,7 @@ } } - if args.CommandName() == "" { + if cmdName := args.CommandName(); cmdName == "" || cmds.Get(cmdName) == nil { return cli.ShowAppHelp(ctx) } @@ -58,7 +58,7 @@ } if ctx.Command != nil { - return cli.NewExitError(cli.ShowCommandHelp(ctx), cli.ExitCodeGeneralError) + return cli.ShowCommandHelp(ctx) } return cli.NewExitError(errors.New(cli.InvalidCommandNameError(args.First())), cli.ExitCodeGeneralError) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.6/cli/commands/run/command.go new/terragrunt-0.73.8/cli/commands/run/command.go --- old/terragrunt-0.73.6/cli/commands/run/command.go 2025-02-15 19:09:48.000000000 +0100 +++ new/terragrunt-0.73.8/cli/commands/run/command.go 2025-02-18 20:16:20.000000000 +0100 @@ -67,15 +67,6 @@ return subcommands } -// ShowTFHelp prints TF help for the given `ctx.Command` command. -func ShowTFHelp(opts *options.TerragruntOptions) cli.HelpFunc { - return func(ctx *cli.Context) error { - terraformHelpCmd := append([]string{tf.FlagNameHelpLong, ctx.Command.Name}, ctx.Args()...) - - return tf.RunCommand(ctx, opts, terraformHelpCmd...) - } -} - func Action(opts *options.TerragruntOptions) cli.ActionFunc { return func(ctx *cli.Context) error { if opts.TerraformCommand == tf.CommandNameDestroy { @@ -95,9 +86,13 @@ return nil } - if strings.HasSuffix(opts.TerraformPath, options.TerraformDefaultPath) { + if isTerraformPath(opts) { return WrongTerraformCommand(opts.TerraformCommand) } return WrongTofuCommand(opts.TerraformCommand) } + +func isTerraformPath(opts *options.TerragruntOptions) bool { + return strings.HasSuffix(opts.TerraformPath, options.TerraformDefaultPath) +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.6/cli/commands/run/creds/getter.go new/terragrunt-0.73.8/cli/commands/run/creds/getter.go --- old/terragrunt-0.73.6/cli/commands/run/creds/getter.go 2025-02-15 19:09:48.000000000 +0100 +++ new/terragrunt-0.73.8/cli/commands/run/creds/getter.go 2025-02-18 20:16:20.000000000 +0100 @@ -3,10 +3,10 @@ import ( "context" + "maps" "github.com/gruntwork-io/terragrunt/cli/commands/run/creds/providers" "github.com/gruntwork-io/terragrunt/options" - "golang.org/x/exp/maps" ) type Getter struct { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.6/cli/commands/run/creds/providers/externalcmd/provider.go new/terragrunt-0.73.8/cli/commands/run/creds/providers/externalcmd/provider.go --- old/terragrunt-0.73.6/cli/commands/run/creds/providers/externalcmd/provider.go 2025-02-15 19:09:48.000000000 +0100 +++ new/terragrunt-0.73.8/cli/commands/run/creds/providers/externalcmd/provider.go 2025-02-18 20:16:20.000000000 +0100 @@ -5,6 +5,7 @@ "context" "encoding/json" "fmt" + "maps" "strings" "github.com/gruntwork-io/terragrunt/cli/commands/run/creds/providers" @@ -12,7 +13,6 @@ "github.com/gruntwork-io/terragrunt/internal/errors" "github.com/gruntwork-io/terragrunt/options" "github.com/gruntwork-io/terragrunt/shell" - "golang.org/x/exp/maps" ) // Provider runs external command that returns a json string with credentials. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.6/cli/commands/run/flags.go new/terragrunt-0.73.8/cli/commands/run/flags.go --- old/terragrunt-0.73.6/cli/commands/run/flags.go 2025-02-15 19:09:48.000000000 +0100 +++ new/terragrunt-0.73.8/cli/commands/run/flags.go 2025-02-18 20:16:20.000000000 +0100 @@ -165,13 +165,7 @@ }, flags.WithDeprecatedNames(terragruntPrefix.FlagNames(DeprecatedConfigFlagName), terragruntPrefixControl)), - flags.NewFlag(&cli.GenericFlag[string]{ - Name: TFPathFlagName, - EnvVars: tgPrefix.EnvVars(TFPathFlagName), - Destination: &opts.TerraformPath, - Usage: "Path to the OpenTofu/Terraform binary. Default is tofu (on PATH).", - }, - flags.WithDeprecatedNames(terragruntPrefix.FlagNames(DeprecatedTfpathFlagName), terragruntPrefixControl)), + NewTFPathFlag(opts, prefix), flags.NewFlag(&cli.BoolFlag{ Name: NoAutoInitFlagName, @@ -547,3 +541,18 @@ return flags.Sort() } + +// NewTFPathFlag creates a flag for specifying the OpenTofu/Terraform binary path. +func NewTFPathFlag(opts *options.TerragruntOptions, prefix flags.Prefix) *flags.Flag { + tgPrefix := prefix.Prepend(flags.TgPrefix) + terragruntPrefix := prefix.Prepend(flags.TerragruntPrefix) + terragruntPrefixControl := flags.StrictControlsByGlobalFlags(opts.StrictControls) + + return flags.NewFlag(&cli.GenericFlag[string]{ + Name: TFPathFlagName, + EnvVars: tgPrefix.EnvVars(TFPathFlagName), + Destination: &opts.TerraformPath, + Usage: "Path to the OpenTofu/Terraform binary. Default is tofu (on PATH).", + }, + flags.WithDeprecatedNames(terragruntPrefix.FlagNames(DeprecatedTfpathFlagName), terragruntPrefixControl)) +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.6/cli/commands/run/help.go new/terragrunt-0.73.8/cli/commands/run/help.go --- old/terragrunt-0.73.6/cli/commands/run/help.go 1970-01-01 01:00:00.000000000 +0100 +++ new/terragrunt-0.73.8/cli/commands/run/help.go 2025-02-18 20:16:20.000000000 +0100 @@ -0,0 +1,81 @@ +package run + +import ( + "fmt" + "io" + "strings" + + "github.com/gruntwork-io/terragrunt/internal/cli" + "github.com/gruntwork-io/terragrunt/internal/errors" + "github.com/gruntwork-io/terragrunt/options" + "github.com/gruntwork-io/terragrunt/tf" + "github.com/gruntwork-io/terragrunt/util" +) + +// TFCommandHelpTemplate is the TF command CLI help template. +const TFCommandHelpTemplate = `Usage: {{ if .Command.UsageText }}{{ wrap .Command.UsageText 3 }}{{ else }}{{ range $parent := parentCommands . }}{{ $parent.HelpName }} {{ end }}[global options] {{ .Command.HelpName }} [options]{{ if eq .Command.Name "` + tf.CommandNameApply + `" }} [PLAN]{{ end }}{{ end }}{{ $description := .Command.Usage }}{{ if .Command.Description }}{{ $description = .Command.Description }}{{ end }}{{ if $description }} + + {{ wrap $description 3 }}{{ end }}{{ if ne .Parent.Command.Name "` + CommandName + `" }} + + This is a shortcut for the command ` + "`terragrunt " + CommandName + "`" + `.{{ end }} + + It wraps the ` + "`{{ tfCommand }}`" + ` command of the binary defined by ` + "`tf-path`" + `. + +{{ if isTerraformPath }}Terraform{{ else }}OpenTofu{{ end }} ` + "`{{ tfCommand }}`" + ` help:{{ $tfHelp := runTFHelp }}{{ if $tfHelp }} + +{{ $tfHelp }}{{ end }} +` + +// ShowTFHelp prints TF help for the given `ctx.Command` command. +func ShowTFHelp(opts *options.TerragruntOptions) cli.HelpFunc { + return func(ctx *cli.Context) error { + if err := NewTFPathFlag(opts, nil).Parse(ctx.Args()); err != nil { + return err + } + + cli.HelpPrinterCustom(ctx, TFCommandHelpTemplate, map[string]any{ + "isTerraformPath": func() bool { + return isTerraformPath(opts) + }, + "runTFHelp": func() string { + return runTFHelp(ctx, opts) + }, + "tfCommand": func() string { + return ctx.Command.Name + }, + }) + + return nil + } +} + +func runTFHelp(ctx *cli.Context, opts *options.TerragruntOptions) string { + opts = opts.Clone() + opts.Writer = io.Discard + + terraformHelpCmd := []string{tf.FlagNameHelpLong, ctx.Command.Name} + + out, err := tf.RunCommandWithOutput(ctx, opts, terraformHelpCmd...) + if err != nil { + var processError util.ProcessExecutionError + if ok := errors.As(err, &processError); ok { + err = processError.Err + } + + return fmt.Sprintf("Failed to execute \"%s %s\": %s", opts.TerraformPath, strings.Join(terraformHelpCmd, " "), err.Error()) + } + + result := out.Stdout.String() + lines := strings.Split(result, "\n") + + // Trim first empty lines or that has prefix "Usage:". + for i := 0; i < len(lines); i++ { + if strings.TrimSpace(lines[i]) == "" || strings.HasPrefix(lines[i], "Usage:") { + continue + } + + return strings.Join(lines[i:], "\n") + } + + return result +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.6/cli/commands/scaffold/action.go new/terragrunt-0.73.8/cli/commands/scaffold/action.go --- old/terragrunt-0.73.6/cli/commands/scaffold/action.go 2025-02-15 19:09:48.000000000 +0100 +++ new/terragrunt-0.73.8/cli/commands/scaffold/action.go 2025-02-18 20:16:20.000000000 +0100 @@ -116,6 +116,11 @@ } }() + outputDir := opts.ScaffoldOutputFolder + if outputDir == "" { + outputDir = opts.WorkingDir + } + // scaffold only in empty directories if empty, err := util.IsDirectoryEmpty(opts.WorkingDir); !empty || err != nil { if err != nil { @@ -149,7 +154,7 @@ return errors.New(err) } - opts.Logger.Infof("Scaffolding a new Terragrunt module %s to %s", moduleURL, opts.WorkingDir) + opts.Logger.Infof("Scaffolding a new Terragrunt module %s to %s", moduleURL, outputDir) if _, err := getter.GetAny(ctx, tempDir, moduleURL); err != nil { return errors.New(err) @@ -188,9 +193,9 @@ opts.Logger.Warnf("The %s variable is already set in the var flag(s). The --%s flag will be ignored.", rootFileName, NoIncludeRootFlagName) } - opts.Logger.Infof("Running boilerplate generation to %s", opts.WorkingDir) + opts.Logger.Infof("Running boilerplate generation to %s", outputDir) boilerplateOpts := &boilerplate_options.BoilerplateOptions{ - OutputFolder: opts.WorkingDir, + OutputFolder: outputDir, OnMissingKey: boilerplate_options.DefaultMissingKeyAction, OnMissingConfig: boilerplate_options.DefaultMissingConfigAction, Vars: vars, @@ -205,7 +210,7 @@ return errors.New(err) } - opts.Logger.Infof("Running fmt on generated code %s", opts.WorkingDir) + opts.Logger.Infof("Running fmt on generated code %s", outputDir) if err := hclfmt.Run(opts); err != nil { return errors.New(err) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.6/cli/commands/scaffold/command.go new/terragrunt-0.73.8/cli/commands/scaffold/command.go --- old/terragrunt-0.73.6/cli/commands/scaffold/command.go 2025-02-15 19:09:48.000000000 +0100 +++ new/terragrunt-0.73.8/cli/commands/scaffold/command.go 2025-02-18 20:16:20.000000000 +0100 @@ -17,6 +17,7 @@ RootFileNameFlagName = "root-file-name" NoIncludeRootFlagName = "no-include-root" + OutputFolderFlagName = "output-folder" VarFlagName = "var" VarFileFlagName = "var-file" ) @@ -54,6 +55,12 @@ Usage: "Do not include root unit in scaffolding done by catalog.", }), + flags.NewFlag(&cli.GenericFlag[string]{ + Name: OutputFolderFlagName, + Destination: &opts.ScaffoldOutputFolder, + Usage: "Output folder for scaffold output.", + }), + flags.NewFlag(&cli.SliceFlag[string]{ Name: VarFlagName, EnvVars: tgPrefix.EnvVars(VarFlagName), diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.6/cli/flags/flag.go new/terragrunt-0.73.8/cli/flags/flag.go --- old/terragrunt-0.73.6/cli/flags/flag.go 2025-02-15 19:09:48.000000000 +0100 +++ new/terragrunt-0.73.8/cli/flags/flag.go 2025-02-18 20:16:20.000000000 +0100 @@ -4,6 +4,8 @@ import ( "context" "flag" + "io" + "strings" "github.com/gruntwork-io/terragrunt/internal/cli" ) @@ -111,9 +113,31 @@ return newFlag.Flag.RunAction(ctx) } -// ParseEnvVars parses env vars values specified in the flag. +// Parse parses the given `args` for the flag value and env vars values specified in the flag. // The value will be assigned to the `Destination` field. // The value can also be retrieved using `flag.Value().Get()`. -func (newFlag *Flag) ParseEnvVars() error { - return newFlag.Apply(new(flag.FlagSet)) +func (newFlag *Flag) Parse(args cli.Args) error { + flagSet := flag.NewFlagSet("", flag.ContinueOnError) + flagSet.SetOutput(io.Discard) + + if err := newFlag.Apply(flagSet); err != nil { + return err + } + + const maxFlagsParse = 1000 // Maximum flags parse + + for range maxFlagsParse { + err := flagSet.Parse(args) + if err == nil { + break + } + + if errStr := err.Error(); !strings.HasPrefix(errStr, cli.ErrFlagUndefined) { + break + } + + args = flagSet.Args() + } + + return nil } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.6/cli/flags/flag_opts.go new/terragrunt-0.73.8/cli/flags/flag_opts.go --- old/terragrunt-0.73.6/cli/flags/flag_opts.go 2025-02-15 19:09:48.000000000 +0100 +++ new/terragrunt-0.73.8/cli/flags/flag_opts.go 2025-02-18 20:16:20.000000000 +0100 @@ -2,7 +2,6 @@ import ( "fmt" - "slices" "github.com/gruntwork-io/terragrunt/internal/cli" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.6/cli/help.go new/terragrunt-0.73.8/cli/help.go --- old/terragrunt-0.73.6/cli/help.go 2025-02-15 19:09:48.000000000 +0100 +++ new/terragrunt-0.73.8/cli/help.go 2025-02-18 20:16:20.000000000 +0100 @@ -19,25 +19,25 @@ ` // CommandHelpTemplate is the command CLI help template. -const CommandHelpTemplate = `Usage: {{if .Command.UsageText}}{{wrap .Command.UsageText 3}}{{else}}{{range $parent := parentCommands . }}{{$parent.HelpName}} {{end}}{{.Command.HelpName}}{{if .Command.VisibleSubcommands}} <command>{{end}}{{if .Command.VisibleFlags}} [options]{{end}}{{end}}{{$description := .Command.Usage}}{{if .Command.Description}}{{$description = .Command.Description}}{{end}}{{if $description}} +const CommandHelpTemplate = `Usage: {{ if .Command.UsageText }}{{ wrap .Command.UsageText 3 }}{{ else }}{{ range $parent := parentCommands . }}{{ $parent.HelpName }} {{ end }}{{ .Command.HelpName }}{{ if .Command.VisibleSubcommands }} <command>{{ end }}{{ if .Command.VisibleFlags }} [options]{{ end }}{{ end }}{{ $description := .Command.Usage }}{{ if .Command.Description }}{{ $description = .Command.Description }}{{ end }}{{ if $description }} - {{wrap $description 3}}{{end}}{{if .Command.Examples}} + {{ wrap $description 3 }}{{ end }}{{ if .Command.Examples }} Examples: - {{$s := join .Command.Examples "\n\n"}}{{wrap $s 3}}{{end}}{{if .Command.VisibleSubcommands}} + {{ $s := join .Command.Examples "\n\n" }}{{ wrap $s 3 }}{{ end }}{{ if .Command.VisibleSubcommands }} -Subcommands:{{ $cv := offsetCommands .Command.VisibleSubcommands 5}}{{range .Command.VisibleSubcommands}} - {{$s := .HelpName}}{{$s}}{{ $sp := subtract $cv (offset $s 3) }}{{ indent $sp ""}} {{wrap .Usage $cv}}{{end}}{{end}}{{if .Command.VisibleFlags}} +Subcommands:{{ $cv := offsetCommands .Command.VisibleSubcommands 5 }}{{ range .Command.VisibleSubcommands }} + {{ $s := .HelpName }}{{ $s }}{{ $sp := subtract $cv (offset $s 3) }}{{ indent $sp ""}} {{ wrap .Usage $cv }}{{ end }}{{ end }}{{ if .Command.VisibleFlags }} Options: - {{range $index, $option := .Command.VisibleFlags}}{{if $index}} - {{end}}{{wrap $option.String 6}}{{end}}{{end}}{{if .App.VisibleFlags}} + {{ range $index, $option := .Command.VisibleFlags }}{{ if $index }} + {{ end }}{{ wrap $option.String 6 }}{{ end }}{{ end }}{{ if .App.VisibleFlags }} Global Options: - {{range $index, $option := .App.VisibleFlags}}{{if $index}} - {{end}}{{wrap $option.String 6}}{{end}}{{end}} + {{ range $index, $option := .App.VisibleFlags }}{{ if $index }} + {{ end }}{{ wrap $option.String 6 }}{{ end }}{{ end }} ` -const AppVersionTemplate = `{{.App.Name}} version {{.App.Version}} +const AppVersionTemplate = `{{ .App.Name }} version {{ .App.Version }} ` diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.6/config/stack.go new/terragrunt-0.73.8/config/stack.go --- old/terragrunt-0.73.6/config/stack.go 2025-02-15 19:09:48.000000000 +0100 +++ new/terragrunt-0.73.8/config/stack.go 2025-02-18 20:16:20.000000000 +0100 @@ -4,6 +4,7 @@ "context" "fmt" "path/filepath" + "strings" "github.com/zclconf/go-cty/cty" @@ -79,9 +80,64 @@ return nil, errors.New(err) } + if err := ValidateStackConfig(config); err != nil { + return nil, errors.New(err) + } + return config, nil } +// ValidateStackConfig validates a StackConfigFile instance according to the rules: +// - Unit name, source, and path shouldn't be empty +// - Unit names should be unique +// - Units shouldn't have duplicate paths +func ValidateStackConfig(config *StackConfigFile) error { + if len(config.Units) == 0 { + return errors.New("stack config must contain at least one unit") + } + + validationErrors := &errors.MultiError{} + + names := make(map[string]bool) + paths := make(map[string]bool) + + for i, unit := range config.Units { + name := strings.TrimSpace(unit.Name) + path := strings.TrimSpace(unit.Path) + + if name == "" { + validationErrors = validationErrors.Append(errors.Errorf("unit at index %d has empty name", i)) + } + + if strings.TrimSpace(unit.Source) == "" { + validationErrors = validationErrors.Append(errors.Errorf("unit '%s' has empty source", unit.Name)) + } + + if path == "" { + validationErrors = validationErrors.Append(errors.Errorf("unit '%s' has empty path", unit.Name)) + } + + if names[name] { + validationErrors = validationErrors.Append(errors.Errorf("duplicate unit name found: '%s'", unit.Name)) + } + + if name != "" { + // save non-empty names for reuse + names[name] = true + } + + if paths[path] { + validationErrors = validationErrors.Append(errors.Errorf("duplicate unit path found: '%s'", unit.Path)) + } + + if path != "" { + paths[path] = true + } + } + + return validationErrors.ErrorOrNil() +} + func processLocals(parser *ParsingContext, opts *options.TerragruntOptions, file *hclparse.File) error { localsBlock, err := file.Blocks(MetadataLocals, false) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.6/config/stack_test.go new/terragrunt-0.73.8/config/stack_test.go --- old/terragrunt-0.73.6/config/stack_test.go 1970-01-01 01:00:00.000000000 +0100 +++ new/terragrunt-0.73.8/config/stack_test.go 2025-02-18 20:16:20.000000000 +0100 @@ -0,0 +1,170 @@ +package config_test + +import ( + "testing" + + "github.com/gruntwork-io/terragrunt/config" + + "github.com/stretchr/testify/assert" +) + +func TestValidateStackConfig(t *testing.T) { + t.Parallel() + tests := []struct { + name string + config *config.StackConfigFile + wantErr string + }{ + { + name: "valid config", + config: &config.StackConfigFile{ + Units: []*config.Unit{ + { + Name: "unit1", + Source: "source1", + Path: "path1", + }, + { + Name: "unit2", + Source: "source2", + Path: "path2", + }, + }, + }, + wantErr: "", + }, + { + name: "empty config", + config: &config.StackConfigFile{ + Units: []*config.Unit{}, + }, + wantErr: "stack config must contain at least one unit", + }, + { + name: "empty unit name", + config: &config.StackConfigFile{ + Units: []*config.Unit{ + { + Name: "", + Source: "source1", + Path: "path1", + }, + }, + }, + wantErr: "unit at index 0 has empty name", + }, + { + name: "whitespace unit name", + config: &config.StackConfigFile{ + Units: []*config.Unit{ + { + Name: " ", + Source: "source1", + Path: "path1", + }, + }, + }, + wantErr: "unit at index 0 has empty name", + }, + { + name: "empty unit source", + config: &config.StackConfigFile{ + Units: []*config.Unit{ + { + Name: "unit1", + Source: "", + Path: "path1", + }, + }, + }, + wantErr: "unit 'unit1' has empty source", + }, + { + name: "whitespace unit source", + config: &config.StackConfigFile{ + Units: []*config.Unit{ + { + Name: "unit1", + Source: " ", + Path: "path1", + }, + }, + }, + wantErr: "unit 'unit1' has empty source", + }, + { + name: "empty unit path", + config: &config.StackConfigFile{ + Units: []*config.Unit{ + { + Name: "unit1", + Source: "source1", + Path: "", + }, + }, + }, + wantErr: "unit 'unit1' has empty path", + }, + { + name: "whitespace unit path", + config: &config.StackConfigFile{ + Units: []*config.Unit{ + { + Name: "unit1", + Source: "source1", + Path: " ", + }, + }, + }, + wantErr: "unit 'unit1' has empty path", + }, + { + name: "duplicate unit names", + config: &config.StackConfigFile{ + Units: []*config.Unit{ + { + Name: "unit1", + Source: "source1", + Path: "path1", + }, + { + Name: "unit1", + Source: "source2", + Path: "path2", + }, + }, + }, + wantErr: "duplicate unit name found: 'unit1'", + }, + { + name: "duplicate unit paths", + config: &config.StackConfigFile{ + Units: []*config.Unit{ + { + Name: "unit1", + Source: "source1", + Path: "path1", + }, + { + Name: "unit2", + Source: "source2", + Path: "path1", + }, + }, + }, + wantErr: "duplicate unit path found: 'path1'", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + err := config.ValidateStackConfig(tt.config) + if tt.wantErr != "" { + assert.Contains(t, err.Error(), tt.wantErr) + } else { + assert.NoError(t, err) + } + }) + } +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.6/docs/_docs/02_features/05-catalog.md new/terragrunt-0.73.8/docs/_docs/02_features/05-catalog.md --- old/terragrunt-0.73.6/docs/_docs/02_features/05-catalog.md 2025-02-15 19:09:48.000000000 +0100 +++ new/terragrunt-0.73.8/docs/_docs/02_features/05-catalog.md 2025-02-18 20:16:20.000000000 +0100 @@ -16,7 +16,7 @@ Example: ```bash -terragrunt catalog <repo-url> [--no-include-root] [--root-file-name] +terragrunt catalog <repo-url> [--no-include-root] [--root-file-name] [--output-folder] ``` [{: width="50%" }](https://terragrunt.gruntwork.io/assets/img/screenshots/catalog-screenshot.png) @@ -52,3 +52,4 @@ - `--no-include-root` - Do not include the root configuration file in any generated `terragrunt.hcl` during scaffolding. - `--root-file-name` - The name of the root configuration file to include in any generated `terragrunt.hcl` during scaffolding. This value also controls the name of the root configuration file to search for when trying to determine Catalog urls. +- `--output-folder` - Location for generated `terragrunt.hcl`. If flag is not provided current working directory is selected. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.6/docs/_docs/04_reference/05-strict-mode.md new/terragrunt-0.73.8/docs/_docs/04_reference/05-strict-mode.md --- old/terragrunt-0.73.6/docs/_docs/04_reference/05-strict-mode.md 2025-02-15 19:09:48.000000000 +0100 +++ new/terragrunt-0.73.8/docs/_docs/04_reference/05-strict-mode.md 2025-02-18 20:16:20.000000000 +0100 @@ -214,7 +214,7 @@ ### deprecated-commands -Throw an error when using the deprecated commandes. +Throw an error when using the deprecated commands. **Controls**: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.6/go.mod new/terragrunt-0.73.8/go.mod --- old/terragrunt-0.73.6/go.mod 2025-02-15 19:09:48.000000000 +0100 +++ new/terragrunt-0.73.8/go.mod 2025-02-18 20:16:20.000000000 +0100 @@ -4,80 +4,60 @@ require ( cloud.google.com/go/storage v1.50.0 - github.com/aws/aws-sdk-go v1.55.6 - github.com/creack/pty v1.1.24 - github.com/fatih/structs v1.1.0 - github.com/go-errors/errors v1.5.1 - github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 - github.com/gruntwork-io/terratest v0.47.2 - github.com/hashicorp/go-cleanhttp v0.5.2 - github.com/hashicorp/go-getter v1.7.8 - github.com/hashicorp/go-multierror v1.1.1 - github.com/hashicorp/go-safetemp v1.0.0 - github.com/hashicorp/go-version v1.7.0 - github.com/hashicorp/hcl/v2 v2.23.0 - - // Many functions of terraform was converted to internal to avoid use as a library after v0.15.3. This means that we - // can't use terraform as a library after v0.15.3, so we pull that in here. - github.com/hashicorp/terraform v0.15.3 - github.com/hashicorp/terraform-config-inspect v0.0.0-20210318070130-9a80970d6b34 - github.com/mattn/go-zglob v0.0.6 - github.com/mitchellh/go-homedir v1.1.0 - github.com/mitchellh/mapstructure v1.5.0 - github.com/sirupsen/logrus v1.9.3 - github.com/stretchr/testify v1.10.0 - github.com/zclconf/go-cty v1.16.2 - golang.org/x/crypto v0.32.0 // indirect - golang.org/x/oauth2 v0.26.0 - golang.org/x/sync v0.11.0 - golang.org/x/sys v0.30.0 - google.golang.org/api v0.220.0 -) - -require ( - cloud.google.com/go v0.118.2 // indirect - github.com/hashicorp/go-retryablehttp v0.7.7 // indirect - github.com/hashicorp/hcl v1.0.1-vault-7 // indirect - github.com/hashicorp/vault/api v1.15.0 // indirect - github.com/klauspost/compress v1.17.11 // indirect - github.com/mitchellh/go-wordwrap v1.0.1 - github.com/pquerna/otp v1.4.0 // indirect - github.com/terraform-linters/tflint v0.55.0 - github.com/ulikunitz/xz v0.5.12 // indirect - golang.org/x/time v0.10.0 // indirect - google.golang.org/genproto v0.0.0-20250204164813-702378808489 // indirect -) - -require ( dario.cat/mergo v1.0.1 github.com/NYTimes/gziphandler v1.1.1 github.com/ProtonMail/go-crypto v1.1.5 + github.com/aws/aws-sdk-go v1.55.6 github.com/aws/aws-sdk-go-v2 v1.36.1 github.com/charmbracelet/bubbles v0.20.0 github.com/charmbracelet/bubbletea v1.3.3 github.com/charmbracelet/glamour v0.8.0 github.com/charmbracelet/lipgloss v1.0.0 + github.com/creack/pty v1.1.24 + github.com/fatih/structs v1.1.0 github.com/getsops/sops/v3 v3.9.4 github.com/gitsight/go-vcsurl v1.0.1 + github.com/go-errors/errors v1.5.1 github.com/gofrs/flock v0.12.1 + github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 github.com/google/uuid v1.6.0 github.com/gruntwork-io/boilerplate v0.6.0 github.com/gruntwork-io/go-commons v0.17.2 github.com/gruntwork-io/terragrunt-engine-go v0.0.8 + github.com/gruntwork-io/terratest v0.47.2 + github.com/hashicorp/go-cleanhttp v0.5.2 + github.com/hashicorp/go-getter v1.7.8 github.com/hashicorp/go-getter/v2 v2.2.3 github.com/hashicorp/go-hclog v1.6.3 + github.com/hashicorp/go-multierror v1.1.1 github.com/hashicorp/go-plugin v1.6.3 + github.com/hashicorp/go-safetemp v1.0.0 + github.com/hashicorp/go-version v1.7.0 + github.com/hashicorp/hcl/v2 v2.23.0 + + // Many functions of terraform was converted to internal to avoid use as a library after v0.15.3. This means that we + // can't use terraform as a library after v0.15.3, so we pull that in here. + github.com/hashicorp/terraform v0.15.3 + github.com/hashicorp/terraform-config-inspect v0.0.0-20210318070130-9a80970d6b34 github.com/hashicorp/terraform-svchost v0.1.1 github.com/huandu/go-clone v1.7.2 github.com/labstack/echo/v4 v4.13.3 github.com/mattn/go-isatty v0.0.20 + github.com/mattn/go-zglob v0.0.6 github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db + github.com/mitchellh/go-homedir v1.1.0 + github.com/mitchellh/go-wordwrap v1.0.1 + github.com/mitchellh/mapstructure v1.5.0 github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c github.com/pkg/errors v0.9.1 github.com/posener/complete v1.2.3 github.com/puzpuzpuz/xsync/v3 v3.5.0 + github.com/sirupsen/logrus v1.9.3 + github.com/stretchr/testify v1.10.0 + github.com/terraform-linters/tflint v0.55.0 github.com/urfave/cli/v2 v2.27.5 + github.com/zclconf/go-cty v1.16.2 go.opentelemetry.io/otel v1.34.0 go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.34.0 go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.34.0 @@ -89,10 +69,13 @@ go.opentelemetry.io/otel/sdk v1.34.0 go.opentelemetry.io/otel/sdk/metric v1.34.0 go.opentelemetry.io/otel/trace v1.34.0 - golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 golang.org/x/mod v0.23.0 + golang.org/x/oauth2 v0.26.0 + golang.org/x/sync v0.11.0 + golang.org/x/sys v0.30.0 golang.org/x/term v0.29.0 golang.org/x/text v0.22.0 + google.golang.org/api v0.221.0 google.golang.org/grpc v1.70.0 google.golang.org/protobuf v1.36.5 gopkg.in/ini.v1 v1.67.0 @@ -103,6 +86,7 @@ atomicgo.dev/keyboard v0.2.9 // indirect atomicgo.dev/schedule v0.1.0 // indirect cel.dev/expr v0.19.1 // indirect + cloud.google.com/go v0.118.2 // indirect cloud.google.com/go/auth v0.14.1 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.7 // indirect cloud.google.com/go/compute/metadata v0.6.0 // indirect @@ -196,13 +180,16 @@ github.com/goware/prefixer v0.0.0-20160118172347-395022866408 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-retryablehttp v0.7.7 // indirect github.com/hashicorp/go-rootcerts v1.0.2 // indirect github.com/hashicorp/go-secure-stdlib/parseutil v0.1.9 // indirect github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect github.com/hashicorp/go-sockaddr v1.0.7 // indirect github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/hcl v1.0.1-vault-7 // indirect github.com/hashicorp/logutils v1.0.0 // indirect github.com/hashicorp/terraform-registry-address v0.2.4 // indirect + github.com/hashicorp/vault/api v1.15.0 // indirect github.com/hashicorp/yamux v0.1.2 // indirect github.com/huandu/xstrings v1.5.0 // indirect github.com/inancgumus/screen v0.0.0-20190314163918-06e984b86ed3 // indirect @@ -210,6 +197,7 @@ github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jstemmer/go-junit-report v1.0.0 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect + github.com/klauspost/compress v1.17.11 // indirect github.com/kylelemons/godebug v1.1.0 // indirect github.com/labstack/gommon v0.4.2 // indirect github.com/lib/pq v1.10.9 // indirect @@ -231,6 +219,7 @@ github.com/owenrumney/go-sarif v1.1.1 // indirect github.com/planetscale/vtprotobuf v0.6.1-0.20241121165744-79df5c4772f2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/pquerna/otp v1.4.0 // indirect github.com/pterm/pterm v0.12.80 // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect @@ -244,6 +233,7 @@ github.com/stretchr/objx v0.5.2 // indirect github.com/terraform-linters/tflint-plugin-sdk v0.22.0 // indirect github.com/terraform-linters/tflint-ruleset-terraform v0.10.0 // indirect + github.com/ulikunitz/xz v0.5.12 // indirect github.com/urfave/cli v1.22.16 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect @@ -260,10 +250,14 @@ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0 // indirect go.opentelemetry.io/proto/otlp v1.5.0 // indirect - golang.org/x/net v0.34.0 // indirect + golang.org/x/crypto v0.33.0 // indirect + golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 // indirect + golang.org/x/net v0.35.0 // indirect + golang.org/x/time v0.10.0 // indirect golang.org/x/tools v0.29.0 // indirect + google.golang.org/genproto v0.0.0-20250204164813-702378808489 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250204164813-702378808489 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250204164813-702378808489 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250207221924-e9438ea467c6 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect sigs.k8s.io/yaml v1.4.0 // indirect diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.6/go.sum new/terragrunt-0.73.8/go.sum --- old/terragrunt-0.73.6/go.sum 2025-02-15 19:09:48.000000000 +0100 +++ new/terragrunt-0.73.8/go.sum 2025-02-18 20:16:20.000000000 +0100 @@ -1762,8 +1762,9 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= -golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= +golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus= +golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1900,8 +1901,9 @@ golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= -golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= +golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= +golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -2256,8 +2258,8 @@ google.golang.org/api v0.110.0/go.mod h1:7FC4Vvx1Mooxh8C5HWjzZHcavuS2f6pmJpZx60ca7iI= google.golang.org/api v0.111.0/go.mod h1:qtFHvU9mhgTJegR31csQ+rwxyUTHOKFqCKWp1J0fdw0= google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg= -google.golang.org/api v0.220.0 h1:3oMI4gdBgB72WFVwE1nerDD8W3HUOS4kypK6rRLbGns= -google.golang.org/api v0.220.0/go.mod h1:26ZAlY6aN/8WgpCzjPNy18QpYaz7Zgg1h0qe1GkZEmY= +google.golang.org/api v0.221.0 h1:qzaJfLhDsbMeFee8zBRdt/Nc+xmOuafD/dbdgGfutOU= +google.golang.org/api v0.221.0/go.mod h1:7sOU2+TL4TxUTdbi0gWgAIg7tH5qBXxoyhtL+9x3biQ= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -2402,8 +2404,8 @@ google.golang.org/genproto v0.0.0-20250204164813-702378808489/go.mod h1:wkQ2Aj/xvshAUDtO/JHvu9y+AaN9cqs28QuSVSHtZSY= google.golang.org/genproto/googleapis/api v0.0.0-20250204164813-702378808489 h1:fCuMM4fowGzigT89NCIsW57Pk9k2D12MMi2ODn+Nk+o= google.golang.org/genproto/googleapis/api v0.0.0-20250204164813-702378808489/go.mod h1:iYONQfRdizDB8JJBybql13nArx91jcUk7zCXEsOofM4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250204164813-702378808489 h1:5bKytslY8ViY0Cj/ewmRtrWHW64bNF03cAatUUFCdFI= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250204164813-702378808489/go.mod h1:8BS3B93F/U1juMFq9+EDk+qOT5CO1R9IzXxG3PTqiRk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250207221924-e9438ea467c6 h1:2duwAxN2+k0xLNpjnHTXoMUgnv6VPSp5fiqTuwSxjmI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250207221924-e9438ea467c6/go.mod h1:8BS3B93F/U1juMFq9+EDk+qOT5CO1R9IzXxG3PTqiRk= google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.6/internal/cli/bool_flag_test.go new/terragrunt-0.73.8/internal/cli/bool_flag_test.go --- old/terragrunt-0.73.6/internal/cli/bool_flag_test.go 2025-02-15 19:09:48.000000000 +0100 +++ new/terragrunt-0.73.8/internal/cli/bool_flag_test.go 2025-02-18 20:16:20.000000000 +0100 @@ -4,6 +4,7 @@ libflag "flag" "fmt" "io" + "maps" "strconv" "testing" @@ -11,7 +12,6 @@ "github.com/gruntwork-io/terragrunt/internal/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "golang.org/x/exp/maps" ) func TestBoolFlagApply(t *testing.T) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.6/internal/cli/command.go new/terragrunt-0.73.8/internal/cli/command.go --- old/terragrunt-0.73.6/internal/cli/command.go 2025-02-15 19:09:48.000000000 +0100 +++ new/terragrunt-0.73.8/internal/cli/command.go 2025-02-18 20:16:20.000000000 +0100 @@ -6,7 +6,7 @@ "strings" ) -const errFlagUndefined = "flag provided but not defined:" +const ErrFlagUndefined = "flag provided but not defined:" type Command struct { // Name is the command name. @@ -211,7 +211,9 @@ return undefArgs, nil } - for { + const maxFlagsParse = 1000 // Maximum flags parse + + for range maxFlagsParse { // check if the error is due to an undefArgs flag var undefArg string @@ -220,9 +222,9 @@ break } - if errStr := err.Error(); strings.HasPrefix(errStr, errFlagUndefined) { + if errStr := err.Error(); strings.HasPrefix(errStr, ErrFlagUndefined) { err = UndefinedFlagError(errStr) - undefArg = strings.Trim(strings.TrimPrefix(errStr, errFlagUndefined), " -") + undefArg = strings.Trim(strings.TrimPrefix(errStr, ErrFlagUndefined), " -") } else { break } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.6/internal/cli/help.go new/terragrunt-0.73.8/internal/cli/help.go --- old/terragrunt-0.73.6/internal/cli/help.go 2025-02-15 19:09:48.000000000 +0100 +++ new/terragrunt-0.73.8/internal/cli/help.go 2025-02-18 20:16:20.000000000 +0100 @@ -1,9 +1,10 @@ package cli import ( + "slices" "strings" - "slices" + "maps" "github.com/gruntwork-io/terragrunt/internal/errors" "github.com/urfave/cli/v2" @@ -45,8 +46,16 @@ // ShowCommandHelp prints command help for the given `ctx`. func ShowCommandHelp(ctx *Context) error { + if ctx.Command.HelpName == "" { + ctx.Command.HelpName = ctx.Command.Name + } + if ctx.Command.CustomHelp != nil { - return ctx.Command.CustomHelp(ctx) + if err := ctx.Command.CustomHelp(ctx); err != nil { + return err + } + + return NewExitError(nil, ExitCodeSuccess) } tpl := ctx.Command.CustomHelpTemplate @@ -58,16 +67,22 @@ return errors.Errorf("command help template not defined") } - if ctx.Command.HelpName == "" { - ctx.Command.HelpName = ctx.Command.Name - } + HelpPrinterCustom(ctx, tpl, nil) - cli.HelpPrinterCustom(ctx.App.Writer, tpl, ctx, map[string]any{ + return NewExitError(nil, ExitCodeSuccess) +} + +func HelpPrinterCustom(ctx *Context, tpl string, customFuncs map[string]any) { + var funcs = map[string]any{ "parentCommands": parentCommands, "offsetCommands": offsetCommands, - }) + } - return NewExitError(nil, ExitCodeSuccess) + if customFuncs != nil { + maps.Copy(funcs, customFuncs) + } + + cli.HelpPrinterCustom(ctx.App.Writer, tpl, ctx, funcs) } func ShowVersion(ctx *Context) error { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.6/internal/errors/multierror.go new/terragrunt-0.73.8/internal/errors/multierror.go --- old/terragrunt-0.73.6/internal/errors/multierror.go 2025-02-15 19:09:48.000000000 +0100 +++ new/terragrunt-0.73.8/internal/errors/multierror.go 2025-02-18 20:16:20.000000000 +0100 @@ -40,7 +40,7 @@ } // Append is a helper function that will append more errors -// onto an Multierror in order to create a larger errs-error. +// onto a Multierror in order to create a larger errs-error. func (errs *MultiError) Append(appendErrs ...error) *MultiError { if errs == nil { errs = &MultiError{inner: new(multierror.Error)} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.6/internal/strict/category.go new/terragrunt-0.73.8/internal/strict/category.go --- old/terragrunt-0.73.6/internal/strict/category.go 2025-02-15 19:09:48.000000000 +0100 +++ new/terragrunt-0.73.8/internal/strict/category.go 2025-02-18 20:16:20.000000000 +0100 @@ -1,9 +1,8 @@ package strict import ( - "sort" - "slices" + "sort" ) // Categories is multiple of DeprecatedFlag Category. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.6/internal/strict/control.go new/terragrunt-0.73.8/internal/strict/control.go --- old/terragrunt-0.73.6/internal/strict/control.go 2025-02-15 19:09:48.000000000 +0100 +++ new/terragrunt-0.73.8/internal/strict/control.go 2025-02-18 20:16:20.000000000 +0100 @@ -2,11 +2,10 @@ import ( "context" + "slices" "sort" "strings" - "slices" - "github.com/gruntwork-io/terragrunt/pkg/log" ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.6/internal/strict/controls/deprecated_env_var.go new/terragrunt-0.73.8/internal/strict/controls/deprecated_env_var.go --- old/terragrunt-0.73.6/internal/strict/controls/deprecated_env_var.go 2025-02-15 19:09:48.000000000 +0100 +++ new/terragrunt-0.73.8/internal/strict/controls/deprecated_env_var.go 2025-02-18 20:16:20.000000000 +0100 @@ -2,7 +2,6 @@ import ( "context" - "slices" "github.com/gruntwork-io/terragrunt/internal/cli" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.6/internal/strict/controls/deprecated_flag_name.go new/terragrunt-0.73.8/internal/strict/controls/deprecated_flag_name.go --- old/terragrunt-0.73.6/internal/strict/controls/deprecated_flag_name.go 2025-02-15 19:09:48.000000000 +0100 +++ new/terragrunt-0.73.8/internal/strict/controls/deprecated_flag_name.go 2025-02-18 20:16:20.000000000 +0100 @@ -2,7 +2,6 @@ import ( "context" - "slices" "github.com/gruntwork-io/terragrunt/internal/cli" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.6/main.go new/terragrunt-0.73.8/main.go --- old/terragrunt-0.73.6/main.go 2025-02-15 19:09:48.000000000 +0100 +++ new/terragrunt-0.73.8/main.go 2025-02-18 20:16:20.000000000 +0100 @@ -21,7 +21,7 @@ opts := options.NewTerragruntOptions() // Immediately parse the `TG_LOG_LEVEL` environment variable, e.g. to set the TRACE level. - if err := global.NewLogLevelFlag(opts, nil).ParseEnvVars(); err != nil { + if err := global.NewLogLevelFlag(opts, nil).Parse(os.Args); err != nil { opts.Logger.Error(err.Error()) os.Exit(1) } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.6/options/options.go new/terragrunt-0.73.8/options/options.go --- old/terragrunt-0.73.6/options/options.go 2025-02-15 19:09:48.000000000 +0100 +++ new/terragrunt-0.73.8/options/options.go 2025-02-18 20:16:20.000000000 +0100 @@ -313,6 +313,9 @@ // Name of the root Terragrunt configuration file, if used. ScaffoldRootFileName string + // Path to folder of scaffold output + ScaffoldOutputFolder string + // Root directory for graph command. GraphRoot string diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.6/pkg/log/format/format.go new/terragrunt-0.73.8/pkg/log/format/format.go --- old/terragrunt-0.73.6/pkg/log/format/format.go 2025-02-15 19:09:48.000000000 +0100 +++ new/terragrunt-0.73.8/pkg/log/format/format.go 2025-02-18 20:16:20.000000000 +0100 @@ -3,12 +3,13 @@ import ( "fmt" + "maps" + "slices" "strings" "github.com/gruntwork-io/terragrunt/internal/errors" . "github.com/gruntwork-io/terragrunt/pkg/log/format/options" //nolint:stylecheck,revive . "github.com/gruntwork-io/terragrunt/pkg/log/format/placeholders" //nolint:stylecheck,revive - "golang.org/x/exp/maps" ) const ( @@ -148,5 +149,5 @@ } } - return nil, errors.Errorf("available values: %s", strings.Join(maps.Keys(presets), ",")) + return nil, errors.Errorf("available values: %s", strings.Join(slices.Collect(maps.Keys(presets)), ",")) } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.6/pkg/log/format/options/color.go new/terragrunt-0.73.8/pkg/log/format/options/color.go --- old/terragrunt-0.73.6/pkg/log/format/options/color.go 2025-02-15 19:09:48.000000000 +0100 +++ new/terragrunt-0.73.8/pkg/log/format/options/color.go 2025-02-18 20:16:20.000000000 +0100 @@ -1,6 +1,8 @@ package options import ( + "maps" + "slices" "strconv" "strings" "sync" @@ -9,7 +11,6 @@ "github.com/gruntwork-io/terragrunt/pkg/log" "github.com/mgutz/ansi" "github.com/puzpuzpuz/xsync/v3" - "golang.org/x/exp/maps" ) // ColorOptionName is the option name. @@ -107,7 +108,7 @@ } if err := val.MapValue.Parse(str); err != nil { - return errors.Errorf("available values: 0..255,%s", strings.Join(maps.Values(val.list), ",")) + return errors.Errorf("available values: 0..255,%s", strings.Join(slices.Collect(maps.Values(val.list)), ",")) } return nil diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.6/pkg/log/format/options/common.go new/terragrunt-0.73.8/pkg/log/format/options/common.go --- old/terragrunt-0.73.6/pkg/log/format/options/common.go 2025-02-15 19:09:48.000000000 +0100 +++ new/terragrunt-0.73.8/pkg/log/format/options/common.go 2025-02-18 20:16:20.000000000 +0100 @@ -2,12 +2,12 @@ import ( "fmt" - "sort" + "maps" + "slices" "strconv" "strings" "github.com/gruntwork-io/terragrunt/internal/errors" - "golang.org/x/exp/maps" ) type CommonOption[T comparable] struct { @@ -111,8 +111,7 @@ } } - list := maps.Values(val.list) - sort.Strings(list) + list := slices.Sorted(maps.Values(val.list)) return errors.Errorf("available values: %s", strings.Join(list, ",")) } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.6/pkg/log/format/options/time_format.go new/terragrunt-0.73.8/pkg/log/format/options/time_format.go --- old/terragrunt-0.73.6/pkg/log/format/options/time_format.go 2025-02-15 19:09:48.000000000 +0100 +++ new/terragrunt-0.73.8/pkg/log/format/options/time_format.go 2025-02-18 20:16:20.000000000 +0100 @@ -1,11 +1,10 @@ package options import ( - "sort" + "maps" + "slices" "strings" "time" - - "golang.org/x/exp/maps" ) // TimeFormatOptionName is the option name. @@ -83,11 +82,9 @@ func (val TimeFormatValue) SortedKeys() []string { keys := maps.Keys(val.list) - sort.Slice(keys, func(i, j int) bool { - return val.list[keys[i]] < val.list[keys[j]] + return slices.SortedFunc(keys, func(a, b string) int { + return strings.Compare(val.list[a], val.list[b]) }) - - return keys } func (val TimeFormatValue) Set(v string) *TimeFormatValue { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.6/test/fixtures/stacks/errors/empty-path/terragrunt.stack.hcl new/terragrunt-0.73.8/test/fixtures/stacks/errors/empty-path/terragrunt.stack.hcl --- old/terragrunt-0.73.6/test/fixtures/stacks/errors/empty-path/terragrunt.stack.hcl 1970-01-01 01:00:00.000000000 +0100 +++ new/terragrunt-0.73.8/test/fixtures/stacks/errors/empty-path/terragrunt.stack.hcl 2025-02-18 20:16:20.000000000 +0100 @@ -0,0 +1,20 @@ +# This fixture tests the validation of unit paths in stack configurations. +# It includes units with empty paths (app1, app2) and a valid path (app3) +# to verify the validation logic. + +unit "app1_empty_path" { + source = "units/app" + path = "" +} + +unit "app2_empty_path" { + source = "units/app" + path = "" +} + +unit "app3_not_empty_path" { + source = "units/app" + path = "app3" +} + + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.6/test/fixtures/stacks/errors/locals-error/terragrunt.stack.hcl new/terragrunt-0.73.8/test/fixtures/stacks/errors/locals-error/terragrunt.stack.hcl --- old/terragrunt-0.73.6/test/fixtures/stacks/errors/locals-error/terragrunt.stack.hcl 1970-01-01 01:00:00.000000000 +0100 +++ new/terragrunt-0.73.8/test/fixtures/stacks/errors/locals-error/terragrunt.stack.hcl 2025-02-18 20:16:20.000000000 +0100 @@ -0,0 +1,7 @@ +locals { + chicken = "units/chicken" +} + +locals { + chick = "units/chick" +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.6/test/fixtures/stacks/locals-error/terragrunt.stack.hcl new/terragrunt-0.73.8/test/fixtures/stacks/locals-error/terragrunt.stack.hcl --- old/terragrunt-0.73.6/test/fixtures/stacks/locals-error/terragrunt.stack.hcl 2025-02-15 19:09:48.000000000 +0100 +++ new/terragrunt-0.73.8/test/fixtures/stacks/locals-error/terragrunt.stack.hcl 1970-01-01 01:00:00.000000000 +0100 @@ -1,7 +0,0 @@ -locals { - chicken = "units/chicken" -} - -locals { - chick = "units/chick" -} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.6/test/integration_scaffold_test.go new/terragrunt-0.73.8/test/integration_scaffold_test.go --- old/terragrunt-0.73.6/test/integration_scaffold_test.go 2025-02-15 19:09:48.000000000 +0100 +++ new/terragrunt-0.73.8/test/integration_scaffold_test.go 2025-02-18 20:16:20.000000000 +0100 @@ -189,3 +189,15 @@ _, _, err = helpers.RunTerragruntCommandWithOutput(t, "terragrunt hclvalidate --terragrunt-non-interactive --terragrunt-working-dir "+tmpEnvPath) require.NoError(t, err) } + +func TestScaffoldOutputFolderFlag(t *testing.T) { + t.Parallel() + + tmpEnvPath := t.TempDir() + + outputFolder := tmpEnvPath + "/foo/bar" + _, stderr, err := helpers.RunTerragruntCommandWithOutput(t, fmt.Sprintf("terragrunt --terragrunt-non-interactive --terragrunt-working-dir %s scaffold %s --output-folder %s", tmpEnvPath, testScaffoldModuleURL, outputFolder)) + require.NoError(t, err) + assert.Contains(t, stderr, "Scaffolding completed") + assert.FileExists(t, outputFolder+"/terragrunt.hcl") +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.6/test/integration_stacks_test.go new/terragrunt-0.73.8/test/integration_stacks_test.go --- old/terragrunt-0.73.6/test/integration_stacks_test.go 2025-02-15 19:09:48.000000000 +0100 +++ new/terragrunt-0.73.8/test/integration_stacks_test.go 2025-02-18 20:16:20.000000000 +0100 @@ -19,11 +19,12 @@ const ( testFixtureStacksBasic = "fixtures/stacks/basic" testFixtureStacksLocals = "fixtures/stacks/locals" - testFixtureStacksLocalsError = "fixtures/stacks/locals-error" + testFixtureStacksLocalsError = "fixtures/stacks/errors/locals-error" testFixtureStacksRemote = "fixtures/stacks/remote" testFixtureStacksInputs = "fixtures/stacks/inputs" testFixtureStacksOutputs = "fixtures/stacks/outputs" testFixtureStacksUnitValues = "fixtures/stacks/unit-values" + testFixtureStacksEmptyPath = "fixtures/stacks/errors/empty-path" ) func TestStacksGenerateBasic(t *testing.T) { @@ -383,6 +384,23 @@ assert.Contains(t, result, "app2") } +func TestStacksEmptyPathError(t *testing.T) { + t.Parallel() + + helpers.CleanupTerraformFolder(t, testFixtureStacksEmptyPath) + tmpEnvPath := helpers.CopyEnvironment(t, testFixtureStacksEmptyPath) + rootPath := util.JoinPath(tmpEnvPath, testFixtureStacksEmptyPath) + + _, _, err := helpers.RunTerragruntCommandWithOutput(t, "terragrunt stack generate --experiment stacks --terragrunt-working-dir "+rootPath) + require.Error(t, err) + + message := err.Error() + // check for app1 and app2 empty path error + assert.Contains(t, message, "unit 'app1_empty_path' has empty path") + assert.Contains(t, message, "unit 'app2_empty_path' has empty path") + assert.NotContains(t, message, "unit 'app3_not_empty_path' has empty path") +} + // check if the stack directory is created and contains files. func validateStackDir(t *testing.T, path string) { t.Helper() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.73.6/tf/getproviders/lock.go new/terragrunt-0.73.8/tf/getproviders/lock.go --- old/terragrunt-0.73.6/tf/getproviders/lock.go 2025-02-15 19:09:48.000000000 +0100 +++ new/terragrunt-0.73.8/tf/getproviders/lock.go 2025-02-18 20:16:20.000000000 +0100 @@ -8,12 +8,11 @@ "encoding/json" "os" "path/filepath" + "slices" "sort" "strings" "unicode" - "slices" - "github.com/gruntwork-io/terragrunt/internal/errors" "github.com/gruntwork-io/terragrunt/tf" "github.com/gruntwork-io/terragrunt/util" ++++++ terragrunt.obsinfo ++++++ --- /var/tmp/diff_new_pack.K6DUBc/_old 2025-02-19 16:00:10.984168744 +0100 +++ /var/tmp/diff_new_pack.K6DUBc/_new 2025-02-19 16:00:10.988168911 +0100 @@ -1,5 +1,5 @@ name: terragrunt -version: 0.73.6 -mtime: 1739642988 -commit: cdba05b19fe93a2db56a74468c8786a1a201f395 +version: 0.73.8 +mtime: 1739906180 +commit: 0b550a37186a01e257f9402241a92f769e7b35bc ++++++ vendor.tar.gz ++++++ /work/SRC/openSUSE:Factory/terragrunt/vendor.tar.gz /work/SRC/openSUSE:Factory/.terragrunt.new.25061/vendor.tar.gz differ: char 13, line 1