From 081fce5d89dedcd17f39326e94003686d2e7a70a Mon Sep 17 00:00:00 2001 From: Denis O Date: Tue, 16 Jul 2024 21:22:45 +0100 Subject: [PATCH] Add handling of multi line variables description (#3269) * Fix for scaffold execution * Template update * Multiline description handling and tests --- cli/commands/scaffold/action.go | 14 ++ .../scaffold-module/variables.tf | 5 +- test/integration_scaffold_test.go | 147 ++++++++++-------- 3 files changed, 97 insertions(+), 69 deletions(-) diff --git a/cli/commands/scaffold/action.go b/cli/commands/scaffold/action.go index 495c774d7..45929cd00 100644 --- a/cli/commands/scaffold/action.go +++ b/cli/commands/scaffold/action.go @@ -61,7 +61,14 @@ inputs = { # Required input variables # -------------------------------------------------------------------------------------------------------------------- {{ range .requiredVariables }} + {{- if eq 1 (regexSplit "\n" .Description -1 | len ) }} # Description: {{ .Description }} + {{- else }} + # Description: + {{- range $line := regexSplit "\n" .Description -1 }} + # {{ $line | indent 2 }} + {{- end }} + {{- end }} # Type: {{ .Type }} {{ .Name }} = {{ .DefaultValuePlaceholder }} # TODO: fill in value {{ end }} @@ -71,7 +78,14 @@ inputs = { # Uncomment the ones you wish to set # -------------------------------------------------------------------------------------------------------------------- {{ range .optionalVariables }} + {{- if eq 1 (regexSplit "\n" .Description -1 | len ) }} # Description: {{ .Description }} + {{- else }} + # Description: + {{- range $line := regexSplit "\n" .Description -1 }} + # {{ $line | indent 2 }} + {{- end }} + {{- end }} # Type: {{ .Type }} # {{ .Name }} = {{ .DefaultValue }} {{ end }} diff --git a/test/fixture-scaffold/scaffold-module/variables.tf b/test/fixture-scaffold/scaffold-module/variables.tf index 21e0b2647..5ef05eae6 100644 --- a/test/fixture-scaffold/scaffold-module/variables.tf +++ b/test/fixture-scaffold/scaffold-module/variables.tf @@ -22,7 +22,10 @@ variable "enabled" { variable "open_port" { type = number - description = "Port to open" + description = <<-EOF + Port to be opened in the security group + Can be a single port or a range + EOF } variable "enable_backups" { diff --git a/test/integration_scaffold_test.go b/test/integration_scaffold_test.go index f7c27a439..1461cd87d 100644 --- a/test/integration_scaffold_test.go +++ b/test/integration_scaffold_test.go @@ -1,168 +1,144 @@ package test import ( - "bytes" "fmt" "os" "path/filepath" "testing" + "github.com/stretchr/testify/assert" + "github.com/gruntwork-io/terragrunt/util" "github.com/stretchr/testify/require" ) const ( - TEST_SCAFOLD_MODULE = "https://github.com/gruntwork-io/terragrunt.git//test/fixture-scaffold/scaffold-module" - TEST_SCAFOLD_MODULE_GIT = "git@github.com:gruntwork-io/terragrunt.git//test/fixture-scaffold/scaffold-module" - TEST_SCAFOLD_MODULE_SHORT = "github.com/gruntwork-io/terragrunt.git//test/fixture-inputs" - TEST_SCAFOLD_TEMPLATE_MODULE = "git@github.com:gruntwork-io/terragrunt.git//test/fixture-scaffold/module-with-template" - TEST_SCAFOLD_EXTERNAL_TEMPLATE_MODULE = "git@github.com:gruntwork-io/terragrunt.git//test/fixture-scaffold/external-template" + TEST_SCAFFOLD_MODULE = "https://github.com/gruntwork-io/terragrunt.git//test/fixture-scaffold/scaffold-module" + TEST_SCAFFOLD_MODULE_GIT = "git@github.com:gruntwork-io/terragrunt.git//test/fixture-scaffold/scaffold-module" + TEST_SCAFFOLD_MODULE_SHORT = "github.com/gruntwork-io/terragrunt.git//test/fixture-inputs" + TEST_SCAFFOLD_TEMPLATE_MODULE = "git@github.com:gruntwork-io/terragrunt.git//test/fixture-scaffold/module-with-template" + TEST_SCAFFOLD_EXTERNAL_TEMPLATE_MODULE = "git@github.com:gruntwork-io/terragrunt.git//test/fixture-scaffold/external-template" + TEST_SCAFFOLD_LOCAL_MODULE = "fixture-scaffold/scaffold-module" + TEST_SCAFFOLD_3RD_PARTY_MODULE = "git::https://github.com/Azure/terraform-azurerm-avm-res-compute-virtualmachine.git//.?ref=v0.15.0" ) -func TestTerragruntScaffoldModule(t *testing.T) { +func TestScaffoldModule(t *testing.T) { t.Parallel() tmpEnvPath, err := os.MkdirTemp("", "terragrunt-scaffold-test") require.NoError(t, err) - stdout := bytes.Buffer{} - stderr := bytes.Buffer{} - - err = runTerragruntCommand(t, fmt.Sprintf("terragrunt --terragrunt-non-interactive --terragrunt-working-dir %s scaffold %s", tmpEnvPath, TEST_SCAFOLD_MODULE), &stdout, &stderr) + _, stderr, err := runTerragruntCommandWithOutput(t, fmt.Sprintf("terragrunt --terragrunt-non-interactive --terragrunt-working-dir %s scaffold %s", tmpEnvPath, TEST_SCAFFOLD_MODULE)) require.NoError(t, err) - require.Contains(t, stderr.String(), "Scaffolding completed") + require.Contains(t, stderr, "Scaffolding completed") require.FileExists(t, fmt.Sprintf("%s/terragrunt.hcl", tmpEnvPath)) } -func TestTerragruntScaffoldModuleShortUrl(t *testing.T) { +func TestScaffoldModuleShortUrl(t *testing.T) { t.Parallel() tmpEnvPath, err := os.MkdirTemp("", "terragrunt-scaffold-test") require.NoError(t, err) - stdout := bytes.Buffer{} - stderr := bytes.Buffer{} - - err = runTerragruntCommand(t, fmt.Sprintf("terragrunt --terragrunt-non-interactive --terragrunt-working-dir %s scaffold %s", tmpEnvPath, TEST_SCAFOLD_MODULE_SHORT), &stdout, &stderr) + _, stderr, err := runTerragruntCommandWithOutput(t, fmt.Sprintf("terragrunt --terragrunt-non-interactive --terragrunt-working-dir %s scaffold %s", tmpEnvPath, TEST_SCAFFOLD_MODULE_SHORT)) require.NoError(t, err) - require.Contains(t, stderr.String(), "Scaffolding completed") + require.Contains(t, stderr, "Scaffolding completed") // check that find_in_parent_folders is generated in terragrunt.hcl content, err := util.ReadFileAsString(fmt.Sprintf("%s/terragrunt.hcl", tmpEnvPath)) require.NoError(t, err) require.Contains(t, content, "find_in_parent_folders") } -func TestTerragruntScaffoldModuleShortUrlNoRootInclude(t *testing.T) { +func TestScaffoldModuleShortUrlNoRootInclude(t *testing.T) { t.Parallel() tmpEnvPath, err := os.MkdirTemp("", "terragrunt-scaffold-test") require.NoError(t, err) - stdout := bytes.Buffer{} - stderr := bytes.Buffer{} - - err = runTerragruntCommand(t, fmt.Sprintf("terragrunt --terragrunt-non-interactive --terragrunt-working-dir %s scaffold %s --var=EnableRootInclude=false", tmpEnvPath, TEST_SCAFOLD_MODULE_SHORT), &stdout, &stderr) + _, stderr, err := runTerragruntCommandWithOutput(t, fmt.Sprintf("terragrunt --terragrunt-non-interactive --terragrunt-working-dir %s scaffold %s --var=EnableRootInclude=false", tmpEnvPath, TEST_SCAFFOLD_MODULE_SHORT)) require.NoError(t, err) - require.Contains(t, stderr.String(), "Scaffolding completed") + require.Contains(t, stderr, "Scaffolding completed") // check that find_in_parent_folders is NOT generated in terragrunt.hcl content, err := util.ReadFileAsString(fmt.Sprintf("%s/terragrunt.hcl", tmpEnvPath)) require.NoError(t, err) require.NotContains(t, content, "find_in_parent_folders") } -func TestTerragruntScaffoldModuleDifferentRevision(t *testing.T) { +func TestScaffoldModuleDifferentRevision(t *testing.T) { t.Parallel() tmpEnvPath, err := os.MkdirTemp("", "terragrunt-scaffold-test") require.NoError(t, err) - stdout := bytes.Buffer{} - stderr := bytes.Buffer{} - - err = runTerragruntCommand(t, fmt.Sprintf("terragrunt --terragrunt-non-interactive --terragrunt-working-dir %s scaffold %s --var=Ref=v0.53.1", tmpEnvPath, TEST_SCAFOLD_MODULE_SHORT), &stdout, &stderr) + _, stderr, err := runTerragruntCommandWithOutput(t, fmt.Sprintf("terragrunt --terragrunt-non-interactive --terragrunt-working-dir %s scaffold %s --var=Ref=v0.53.1", tmpEnvPath, TEST_SCAFFOLD_MODULE_SHORT)) require.NoError(t, err) - require.Contains(t, stderr.String(), "git::https://github.com/gruntwork-io/terragrunt.git//test/fixture-inputs?ref=v0.53.1") - require.Contains(t, stderr.String(), "Scaffolding completed") + require.Contains(t, stderr, "git::https://github.com/gruntwork-io/terragrunt.git//test/fixture-inputs?ref=v0.53.1") + require.Contains(t, stderr, "Scaffolding completed") } -func TestTerragruntScaffoldModuleDifferentRevisionAndSsh(t *testing.T) { +func TestScaffoldModuleDifferentRevisionAndSsh(t *testing.T) { t.Parallel() tmpEnvPath, err := os.MkdirTemp("", "terragrunt-scaffold-test") require.NoError(t, err) - stdout := bytes.Buffer{} - stderr := bytes.Buffer{} - - err = runTerragruntCommand(t, fmt.Sprintf("terragrunt --terragrunt-non-interactive --terragrunt-working-dir %s scaffold %s --var=Ref=v0.53.1 --var=SourceUrlType=git-ssh", tmpEnvPath, TEST_SCAFOLD_MODULE_SHORT), &stdout, &stderr) + _, stderr, err := runTerragruntCommandWithOutput(t, fmt.Sprintf("terragrunt --terragrunt-non-interactive --terragrunt-working-dir %s scaffold %s --var=Ref=v0.53.1 --var=SourceUrlType=git-ssh", tmpEnvPath, TEST_SCAFFOLD_MODULE_SHORT)) require.NoError(t, err) - require.Contains(t, stderr.String(), "git::ssh://git@github.com/gruntwork-io/terragrunt.git//test/fixture-inputs?ref=v0.53.1") - require.Contains(t, stderr.String(), "Scaffolding completed") + require.Contains(t, stderr, "git::ssh://git@github.com/gruntwork-io/terragrunt.git//test/fixture-inputs?ref=v0.53.1") + require.Contains(t, stderr, "Scaffolding completed") } -func TestTerragruntScaffoldModuleSsh(t *testing.T) { +func TestScaffoldModuleSsh(t *testing.T) { t.Parallel() tmpEnvPath, err := os.MkdirTemp("", "terragrunt-scaffold-test") require.NoError(t, err) - stdout := bytes.Buffer{} - stderr := bytes.Buffer{} - - err = runTerragruntCommand(t, fmt.Sprintf("terragrunt --terragrunt-non-interactive --terragrunt-working-dir %s scaffold %s", tmpEnvPath, TEST_SCAFOLD_MODULE_GIT), &stdout, &stderr) + _, stderr, err := runTerragruntCommandWithOutput(t, fmt.Sprintf("terragrunt --terragrunt-non-interactive --terragrunt-working-dir %s scaffold %s", tmpEnvPath, TEST_SCAFFOLD_MODULE_GIT)) require.NoError(t, err) - require.Contains(t, stderr.String(), "Scaffolding completed") + require.Contains(t, stderr, "Scaffolding completed") } -func TestTerragruntScaffoldModuleTemplate(t *testing.T) { +func TestScaffoldModuleTemplate(t *testing.T) { t.Parallel() tmpEnvPath, err := os.MkdirTemp("", "terragrunt-scaffold-test") require.NoError(t, err) - stdout := bytes.Buffer{} - stderr := bytes.Buffer{} - - err = runTerragruntCommand(t, fmt.Sprintf("terragrunt --terragrunt-non-interactive --terragrunt-working-dir %s scaffold %s", tmpEnvPath, TEST_SCAFOLD_TEMPLATE_MODULE), &stdout, &stderr) + _, stderr, err := runTerragruntCommandWithOutput(t, fmt.Sprintf("terragrunt --terragrunt-non-interactive --terragrunt-working-dir %s scaffold %s", tmpEnvPath, TEST_SCAFFOLD_TEMPLATE_MODULE)) require.NoError(t, err) - require.Contains(t, stderr.String(), "Scaffolding completed") + require.Contains(t, stderr, "Scaffolding completed") // check that exists file from .boilerplate dir require.FileExists(t, fmt.Sprintf("%s/template-file.txt", tmpEnvPath)) } -func TestTerragruntScaffoldModuleExternalTemplate(t *testing.T) { +func TestScaffoldModuleExternalTemplate(t *testing.T) { t.Parallel() tmpEnvPath, err := os.MkdirTemp("", "terragrunt-scaffold-test") require.NoError(t, err) - stdout := bytes.Buffer{} - stderr := bytes.Buffer{} - - err = runTerragruntCommand(t, fmt.Sprintf("terragrunt --terragrunt-non-interactive --terragrunt-working-dir %s scaffold %s %s", tmpEnvPath, TEST_SCAFOLD_MODULE_GIT, TEST_SCAFOLD_EXTERNAL_TEMPLATE_MODULE), &stdout, &stderr) + _, stderr, err := runTerragruntCommandWithOutput(t, fmt.Sprintf("terragrunt --terragrunt-non-interactive --terragrunt-working-dir %s scaffold %s %s", tmpEnvPath, TEST_SCAFFOLD_MODULE_GIT, TEST_SCAFFOLD_EXTERNAL_TEMPLATE_MODULE)) require.NoError(t, err) - require.Contains(t, stderr.String(), "Scaffolding completed") + require.Contains(t, stderr, "Scaffolding completed") // check that exists file from external template require.FileExists(t, fmt.Sprintf("%s/external-template.txt", tmpEnvPath)) } -func TestTerragruntScaffoldErrorNoModuleUrl(t *testing.T) { +func TestScaffoldErrorNoModuleUrl(t *testing.T) { t.Parallel() tmpEnvPath, err := os.MkdirTemp("", "terragrunt-scaffold-test") require.NoError(t, err) - stdout := bytes.Buffer{} - stderr := bytes.Buffer{} - - err = runTerragruntCommand(t, fmt.Sprintf("terragrunt --terragrunt-non-interactive --terragrunt-working-dir %s scaffold", tmpEnvPath), &stdout, &stderr) + _, _, err = runTerragruntCommandWithOutput(t, fmt.Sprintf("terragrunt --terragrunt-non-interactive --terragrunt-working-dir %s scaffold", tmpEnvPath)) require.Error(t, err) require.Contains(t, err.Error(), "No module URL passed") } -func TestTerragruntScaffoldModuleVarFile(t *testing.T) { +func TestScaffoldModuleVarFile(t *testing.T) { t.Parallel() // generate var file with specific version, without root include and use GIT/SSH to clone module. varFileContent := ` @@ -177,14 +153,49 @@ SourceUrlType: "git-ssh" tmpEnvPath, err := os.MkdirTemp("", "terragrunt-scaffold-test") require.NoError(t, err) - stdout := bytes.Buffer{} - stderr := bytes.Buffer{} - - err = runTerragruntCommand(t, fmt.Sprintf("terragrunt --terragrunt-non-interactive --terragrunt-working-dir %s scaffold %s --var-file=%s", tmpEnvPath, TEST_SCAFOLD_MODULE_SHORT, varFile), &stdout, &stderr) + _, stderr, err := runTerragruntCommandWithOutput(t, fmt.Sprintf("terragrunt --terragrunt-non-interactive --terragrunt-working-dir %s scaffold %s --var-file=%s", tmpEnvPath, TEST_SCAFFOLD_MODULE_SHORT, varFile)) require.NoError(t, err) - require.Contains(t, stderr.String(), "git::ssh://git@github.com/gruntwork-io/terragrunt.git//test/fixture-inputs?ref=v0.53.1") - require.Contains(t, stderr.String(), "Scaffolding completed") + require.Contains(t, stderr, "git::ssh://git@github.com/gruntwork-io/terragrunt.git//test/fixture-inputs?ref=v0.53.1") + require.Contains(t, stderr, "Scaffolding completed") content, err := util.ReadFileAsString(fmt.Sprintf("%s/terragrunt.hcl", tmpEnvPath)) require.NoError(t, err) require.NotContains(t, content, "find_in_parent_folders") } + +func TestScaffoldLocalModule(t *testing.T) { + t.Parallel() + + tmpEnvPath, err := os.MkdirTemp("", "terragrunt-scaffold-test") + require.NoError(t, err) + + workingDir, err := os.Getwd() + require.NoError(t, err) + + _, stderr, err := runTerragruntCommandWithOutput(t, fmt.Sprintf("terragrunt --terragrunt-non-interactive --terragrunt-working-dir %s scaffold %s", tmpEnvPath, fmt.Sprintf("%s//%s", workingDir, TEST_SCAFFOLD_LOCAL_MODULE))) + require.NoError(t, err) + require.Contains(t, stderr, "Scaffolding completed") + require.FileExists(t, fmt.Sprintf("%s/terragrunt.hcl", tmpEnvPath)) +} + +func TestScaffold3rdPartyModule(t *testing.T) { + t.Parallel() + + tmpRoot, err := os.MkdirTemp("", "terragrunt-scaffold-test") + require.NoError(t, err) + tmpEnvPath := filepath.Join(tmpRoot, "app") + err = os.MkdirAll(tmpEnvPath, 0755) + assert.NoError(t, err) + + // create "root" terragrunt.hcl + err = os.WriteFile(filepath.Join(tmpRoot, "terragrunt.hcl"), []byte(""), 0644) + assert.NoError(t, err) + + _, stderr, err := runTerragruntCommandWithOutput(t, fmt.Sprintf("terragrunt --terragrunt-non-interactive --terragrunt-working-dir %s scaffold %s", tmpEnvPath, TEST_SCAFFOLD_3RD_PARTY_MODULE)) + require.NoError(t, err) + require.Contains(t, stderr, "Scaffolding completed") + require.FileExists(t, fmt.Sprintf("%s/terragrunt.hcl", tmpEnvPath)) + + // validate the generated files + _, _, err = runTerragruntCommandWithOutput(t, fmt.Sprintf("terragrunt --terragrunt-non-interactive --terragrunt-working-dir %s hclvalidate", tmpEnvPath)) + require.NoError(t, err) +}