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]
 ```
 
 [![screenshot](/assets/img/screenshots/catalog-screenshot.png){: 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

Reply via email to