-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
chore: Bumping boilerplate #4805
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
f2eace4
3afaa76
d958a59
7f7ef5a
9cc83c3
4cc7841
043a551
a00e899
2a68a75
c198a1a
d49da22
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,6 +10,7 @@ import ( | |
| "strings" | ||
|
|
||
| "github.com/gruntwork-io/terragrunt/cli/commands/hcl/format" | ||
| "github.com/gruntwork-io/terragrunt/cli/flags/shared" | ||
| "github.com/gruntwork-io/terragrunt/config" | ||
| "github.com/gruntwork-io/terragrunt/pkg/log" | ||
| "github.com/gruntwork-io/terragrunt/shell" | ||
|
|
@@ -106,7 +107,31 @@ const ( | |
| rootFileName = "RootFileName" | ||
| ) | ||
|
|
||
| // NewBoilerplateOptions creates a new BoilerplateOptions struct | ||
| func NewBoilerplateOptions( | ||
| templateFolder, | ||
| outputFolder string, | ||
| vars map[string]any, | ||
| terragruntOpts *options.TerragruntOptions, | ||
| ) *boilerplate_options.BoilerplateOptions { | ||
| return &boilerplate_options.BoilerplateOptions{ | ||
| TemplateFolder: templateFolder, | ||
| OutputFolder: outputFolder, | ||
| OnMissingKey: boilerplate_options.DefaultMissingKeyAction, | ||
| OnMissingConfig: boilerplate_options.DefaultMissingConfigAction, | ||
| Vars: vars, | ||
| ShellCommandAnswers: map[string]bool{}, | ||
| NoShell: terragruntOpts.NoShell, | ||
| NoHooks: terragruntOpts.NoHooks, | ||
| NonInteractive: terragruntOpts.NonInteractive, | ||
| DisableDependencyPrompt: terragruntOpts.NoDependencyPrompt, | ||
| } | ||
| } | ||
|
|
||
| func Run(ctx context.Context, l log.Logger, opts *options.TerragruntOptions, moduleURL, templateURL string) error { | ||
| // Apply catalog configuration settings, with CLI flags taking precedence | ||
| applyCatalogConfigToScaffold(ctx, l, opts) | ||
|
|
||
| // download remote repo to local | ||
| var dirsToClean []string | ||
| // clean all temp dirs | ||
|
|
@@ -186,27 +211,25 @@ func Run(ctx context.Context, l log.Logger, opts *options.TerragruntOptions, mod | |
| if _, found := vars[enableRootInclude]; !found { | ||
| vars[enableRootInclude] = !opts.ScaffoldNoIncludeRoot | ||
| } else { | ||
| l.Warnf("The %s variable is already set in the var flag(s). The --%s flag will be ignored.", enableRootInclude, NoIncludeRootFlagName) | ||
| l.Warnf( | ||
| "The %s variable is already set in the var flag(s). The --%s flag will be ignored.", | ||
| enableRootInclude, | ||
| shared.NoIncludeRootFlagName, | ||
| ) | ||
| } | ||
|
|
||
| if _, found := vars[rootFileName]; !found { | ||
| vars[rootFileName] = opts.ScaffoldRootFileName | ||
| } else { | ||
| l.Warnf("The %s variable is already set in the var flag(s). The --%s flag will be ignored.", rootFileName, NoIncludeRootFlagName) | ||
| l.Warnf( | ||
| "The %s variable is already set in the var flag(s). The --%s flag will be ignored.", | ||
| rootFileName, | ||
| shared.NoIncludeRootFlagName, | ||
| ) | ||
| } | ||
|
|
||
| l.Infof("Running boilerplate generation to %s", outputDir) | ||
| boilerplateOpts := &boilerplate_options.BoilerplateOptions{ | ||
| OutputFolder: outputDir, | ||
| OnMissingKey: boilerplate_options.DefaultMissingKeyAction, | ||
| OnMissingConfig: boilerplate_options.DefaultMissingConfigAction, | ||
| Vars: vars, | ||
| DisableShell: true, | ||
| DisableHooks: true, | ||
| NonInteractive: opts.NonInteractive, | ||
| DisableDependencyPrompt: opts.NoDependencyPrompt, | ||
| TemplateFolder: boilerplateDir, | ||
| } | ||
| boilerplateOpts := NewBoilerplateOptions(boilerplateDir, outputDir, vars, opts) | ||
|
|
||
| emptyDep := variables.Dependency{} | ||
| if err := templates.ProcessTemplate(boilerplateOpts, boilerplateOpts, emptyDep); err != nil { | ||
|
|
@@ -224,22 +247,72 @@ func Run(ctx context.Context, l log.Logger, opts *options.TerragruntOptions, mod | |
| return nil | ||
| } | ||
|
|
||
| // applyCatalogConfigToScaffold applies catalog configuration settings to scaffold options. | ||
| // CLI flags take precedence over config file settings. | ||
| func applyCatalogConfigToScaffold(ctx context.Context, l log.Logger, opts *options.TerragruntOptions) { | ||
| catalogCfg, err := config.ReadCatalogConfig(ctx, l, opts) | ||
| if err != nil { | ||
| // Don't fail if catalog config can't be read - it's optional | ||
| l.Debugf("Could not read catalog config for scaffold: %v", err) | ||
| return | ||
| } | ||
|
|
||
| if catalogCfg == nil { | ||
| return | ||
| } | ||
|
|
||
| // Apply config settings only if CLI flags weren't explicitly set | ||
| // Since both NoShell and NoHooks default to false, we apply the config value | ||
| // only if it's true (enabling the restriction) | ||
| if catalogCfg.NoShell != nil && *catalogCfg.NoShell && !opts.NoShell { | ||
| l.Debugf("Applying catalog config: no_shell = true") | ||
|
|
||
| opts.NoShell = true | ||
| } | ||
|
|
||
| if catalogCfg.NoHooks != nil && *catalogCfg.NoHooks && !opts.NoHooks { | ||
| l.Debugf("Applying catalog config: no_hooks = true") | ||
|
|
||
| opts.NoHooks = true | ||
| } | ||
| } | ||
|
Comment on lines
+250
to
+278
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chainPrecedence bug: CLI “false” cannot override catalog “true”. applyCatalogConfigToScaffold can’t distinguish default false from an explicitly passed Suggested approach:
Diff (scaffold.go): -func applyCatalogConfigToScaffold(ctx context.Context, l log.Logger, opts *options.TerragruntOptions) {
+func applyCatalogConfigToScaffold(ctx context.Context, l log.Logger, opts *options.TerragruntOptions) {
catalogCfg, err := config.ReadCatalogConfig(ctx, l, opts)
if err != nil {
l.Debugf("Could not read catalog config for scaffold: %v", err)
return
}
if catalogCfg == nil {
return
}
- if catalogCfg.NoShell != nil && *catalogCfg.NoShell && !opts.NoShell {
+ // Only apply when CLI did not set the flag explicitly.
+ if catalogCfg.NoShell != nil && *catalogCfg.NoShell && !opts.NoShellFlagSet {
l.Debugf("Applying catalog config: no_shell = true")
opts.NoShell = true
}
- if catalogCfg.NoHooks != nil && *catalogCfg.NoHooks && !opts.NoHooks {
+ if catalogCfg.NoHooks != nil && *catalogCfg.NoHooks && !opts.NoHooksFlagSet {
l.Debugf("Applying catalog config: no_hooks = true")
opts.NoHooks = true
}
}And in options.TerragruntOptions (separate file): type TerragruntOptions struct {
// existing...
NoShell bool
NoHooks bool
+ // Set by flag parsing layer to preserve CLI-precedence semantics
+ NoShellFlagSet bool
+ NoHooksFlagSet bool
}Update flag parsing to set these booleans when the corresponding CLI flags are present. Run to locate flags to update: 🏁 Script executed: #!/usr/bin/env bash
rg -nP --type=go -C3 '\bNoShell\b|\bNoHooks\b|no-?shell|no-?hooks' cli/ --hiddenLength of output: 20069 Length of output: 20 🏁 Script executed: #!/bin/bash
# Show snippet of TerragruntOptions struct
fd -e go -x grep -A 30 'type TerragruntOptions struct' {} \;Length of output: 1468 Length of output: 12716 🏁 Script executed: #!/bin/bash
# Check cli package and flag parsing details
rg -nP --type=go 'import.*cli' cli/flags/shared/shared.go -A 5 -B 2Length of output: 0 🏁 Script executed: #!/bin/bash
# Look at complete flag parsing context for NoShell and NoHooks
rg -nP --type=go -B 10 -A 5 'Destination:.*NoShell|Destination:.*NoHooks' cli/flags/shared/shared.goLength of output: 795 💡 Result: Use the flag/Context IsSet check instead of the boolean value.
Minimal example (urfave/cli/v3): References:
Sources: 🏁 Script executed: #!/bin/bash
# Find where flags are used/applied, look for OnAction or Action callbacks
rg -nP --type=go 'OnAction|Action.*func|flag.*action' cli/ -A 3 -B 3 | head -100Length of output: 6426 🏁 Script executed: #!/bin/bash
# Look for where applyCatalogConfigToScaffold is called
rg -nP --type=go 'applyCatalogConfigToScaffold' cli/Length of output: 353 🏁 Script executed: #!/bin/bash
# View the call site of applyCatalogConfigToScaffold
sed -n '120,145p' cli/commands/scaffold/scaffold.goLength of output: 940 🏁 Script executed: #!/bin/bash
# Check scaffold command Action callback signature
sed -n '74,95p' cli/commands/scaffold/cli.goLength of output: 502 Precedence bug confirmed: CLI "false" cannot override catalog "true". The review comment correctly identifies the issue. The The architecture prevents using urfave/cli's Required changes:
🤖 Prompt for AI Agents |
||
|
|
||
| // generateDefaultTemplate - write default template to provided dir | ||
| func generateDefaultTemplate(boilerplateDir string) (string, error) { | ||
| const ownerWriteGlobalReadPerms = 0644 | ||
| if err := os.WriteFile(util.JoinPath(boilerplateDir, config.DefaultTerragruntConfigPath), []byte(DefaultTerragruntTemplate), ownerWriteGlobalReadPerms); err != nil { | ||
| if err := os.WriteFile( | ||
| util.JoinPath( | ||
| boilerplateDir, | ||
| config.DefaultTerragruntConfigPath, | ||
| ), | ||
| []byte(DefaultTerragruntTemplate), | ||
| ownerWriteGlobalReadPerms, | ||
| ); err != nil { | ||
| return "", errors.New(err) | ||
| } | ||
|
|
||
| if err := os.WriteFile(util.JoinPath(boilerplateDir, "boilerplate.yml"), []byte(DefaultBoilerplateConfig), ownerWriteGlobalReadPerms); err != nil { | ||
| if err := os.WriteFile( | ||
| util.JoinPath( | ||
| boilerplateDir, | ||
| "boilerplate.yml", | ||
| ), | ||
| []byte(DefaultBoilerplateConfig), | ||
| ownerWriteGlobalReadPerms, | ||
| ); err != nil { | ||
| return "", errors.New(err) | ||
| } | ||
|
|
||
| return boilerplateDir, nil | ||
| } | ||
|
|
||
| // downloadTemplate - parse URL, download files, and handle subfolders | ||
| func downloadTemplate(ctx context.Context, l log.Logger, opts *options.TerragruntOptions, templateURL string, tempDir string) (string, error) { | ||
| func downloadTemplate( | ||
| ctx context.Context, | ||
| l log.Logger, | ||
| opts *options.TerragruntOptions, | ||
| templateURL, | ||
| tempDir string, | ||
| ) (string, error) { | ||
| parsedTemplateURL, err := tf.ToSourceURL(templateURL, tempDir) | ||
| if err != nil { | ||
| return "", errors.New(err) | ||
|
|
@@ -278,15 +351,25 @@ func downloadTemplate(ctx context.Context, l log.Logger, opts *options.Terragrun | |
| templateDir = filepath.Join(templateDir, subFolder) | ||
| // Verify that subfolder exists | ||
| if _, err := os.Stat(templateDir); os.IsNotExist(err) { | ||
| return "", errors.Errorf("subfolder \"//%s\" not found in downloaded template from %s", subFolder, templateURL) | ||
| return "", errors.Errorf( | ||
| "subfolder \"//%s\" not found in downloaded template from %s", | ||
| subFolder, | ||
| templateURL, | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| return templateDir, nil | ||
| } | ||
|
|
||
| // prepareBoilerplateFiles - prepare boilerplate files from provided template, tf module, or (custom) default template | ||
| func prepareBoilerplateFiles(ctx context.Context, l log.Logger, opts *options.TerragruntOptions, templateURL string, tempDir string) (string, error) { | ||
| func prepareBoilerplateFiles( | ||
| ctx context.Context, | ||
| l log.Logger, | ||
| opts *options.TerragruntOptions, | ||
| templateURL, | ||
| tempDir string, | ||
| ) (string, error) { | ||
| boilerplateDir := util.JoinPath(tempDir, util.DefaultBoilerplateDir) | ||
|
|
||
| // process template url if it was passed. This overrides the .boilerplate folder in the OpenTofu/Terraform module | ||
|
|
@@ -335,7 +418,11 @@ func prepareBoilerplateFiles(ctx context.Context, l log.Logger, opts *options.Te | |
| } | ||
|
|
||
| // parseVariables - parse variables from tf files. | ||
| func parseVariables(l log.Logger, opts *options.TerragruntOptions, moduleDir string) ([]*config.ParsedVariable, []*config.ParsedVariable, error) { | ||
| func parseVariables( | ||
| l log.Logger, | ||
| opts *options.TerragruntOptions, | ||
| moduleDir string, | ||
| ) ([]*config.ParsedVariable, []*config.ParsedVariable, error) { | ||
| inputs, err := config.ParseVariables(l, opts, moduleDir) | ||
| if err != nil { | ||
| return nil, nil, errors.New(err) | ||
|
|
@@ -359,7 +446,13 @@ func parseVariables(l log.Logger, opts *options.TerragruntOptions, moduleDir str | |
| } | ||
|
|
||
| // parseModuleURL - parse module url and rewrite it if required | ||
| func parseModuleURL(ctx context.Context, l log.Logger, opts *options.TerragruntOptions, vars map[string]any, moduleURL string) (string, error) { | ||
| func parseModuleURL( | ||
| ctx context.Context, | ||
| l log.Logger, | ||
| opts *options.TerragruntOptions, | ||
| vars map[string]any, | ||
| moduleURL string, | ||
| ) (string, error) { | ||
| parsedModuleURL, err := tf.ToSourceURL(moduleURL, opts.WorkingDir) | ||
| if err != nil { | ||
| return "", errors.New(err) | ||
|
|
@@ -385,7 +478,12 @@ func parseModuleURL(ctx context.Context, l log.Logger, opts *options.TerragruntO | |
|
|
||
| // rewriteModuleURL rewrites module url to git ssh if required | ||
| // github.com/gruntwork-io/terragrunt.git//test/fixtures/inputs => git::https://github.com/gruntwork-io/terragrunt.git//test/fixtures/inputs | ||
| func rewriteModuleURL(l log.Logger, opts *options.TerragruntOptions, vars map[string]any, moduleURL string) (*url.URL, error) { | ||
| func rewriteModuleURL( | ||
| l log.Logger, | ||
| opts *options.TerragruntOptions, | ||
| vars map[string]any, | ||
| moduleURL string, | ||
| ) (*url.URL, error) { | ||
| var updatedModuleURL = moduleURL | ||
|
|
||
| sourceURLType := sourceURLTypeHTTPS | ||
|
|
@@ -428,7 +526,12 @@ func rewriteModuleURL(l log.Logger, opts *options.TerragruntOptions, vars map[st | |
|
|
||
| // rewriteTemplateURL rewrites template url with reference to tag | ||
| // github.com/denis256/terragrunt-tests.git//scaffold/base-template => github.com/denis256/terragrunt-tests.git//scaffold/base-template?ref=v0.53.8 | ||
| func rewriteTemplateURL(ctx context.Context, l log.Logger, opts *options.TerragruntOptions, parsedTemplateURL *url.URL) (*url.URL, error) { | ||
| func rewriteTemplateURL( | ||
| ctx context.Context, | ||
| l log.Logger, | ||
| opts *options.TerragruntOptions, | ||
| parsedTemplateURL *url.URL, | ||
| ) (*url.URL, error) { | ||
| var ( | ||
| updatedTemplateURL = parsedTemplateURL | ||
| templateParams = updatedTemplateURL.Query() | ||
|
|
@@ -459,7 +562,13 @@ func rewriteTemplateURL(ctx context.Context, l log.Logger, opts *options.Terragr | |
| } | ||
|
|
||
| // addRefToModuleURL adds ref to module url if is passed through variables or find it from git tags | ||
| func addRefToModuleURL(ctx context.Context, l log.Logger, opts *options.TerragruntOptions, parsedModuleURL *url.URL, vars map[string]any) (*url.URL, error) { | ||
| func addRefToModuleURL( | ||
| ctx context.Context, | ||
| l log.Logger, | ||
| opts *options.TerragruntOptions, | ||
| parsedModuleURL *url.URL, | ||
| vars map[string]any, | ||
| ) (*url.URL, error) { | ||
| var moduleURL = parsedModuleURL | ||
| // append ref to source url, if is passed through variables or find it from git tags | ||
| params := moduleURL.Query() | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wrong flag name in warning for RootFileName.
The warning for RootFileName uses
shared.NoIncludeRootFlagName. It should reference the root-file-name flag. Replace with the correct constant.If a dedicated constant doesn’t exist yet, add one alongside
NoIncludeRootFlagName.🤖 Prompt for AI Agents