Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package terragrunt for openSUSE:Factory checked in at 2022-07-26 19:43:51 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/terragrunt (Old) and /work/SRC/openSUSE:Factory/.terragrunt.new.1533 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "terragrunt" Tue Jul 26 19:43:51 2022 rev:10 rq:990832 version:0.38.6 Changes: -------- --- /work/SRC/openSUSE:Factory/terragrunt/terragrunt.changes 2022-07-18 18:34:53.297839578 +0200 +++ /work/SRC/openSUSE:Factory/.terragrunt.new.1533/terragrunt.changes 2022-07-26 19:44:16.837138225 +0200 @@ -1,0 +2,7 @@ +Fri Jul 22 17:39:05 UTC 2022 - ka...@b1-systems.de + +- Update to version 0.38.6: + * Add metadata to render-json output (#2199) + * Remove unused appveyor (#2194) + +------------------------------------------------------------------- Old: ---- terragrunt-0.38.5.tar.gz New: ---- terragrunt-0.38.6.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ terragrunt.spec ++++++ --- /var/tmp/diff_new_pack.H8GLL0/_old 2022-07-26 19:44:17.956965183 +0200 +++ /var/tmp/diff_new_pack.H8GLL0/_new 2022-07-26 19:44:17.964963947 +0200 @@ -19,7 +19,7 @@ %define __arch_install_post export NO_BRP_STRIP_DEBUG=true Name: terragrunt -Version: 0.38.5 +Version: 0.38.6 Release: 0 Summary: Thin wrapper for Terraform for working with multiple Terraform modules License: MIT ++++++ _service ++++++ --- /var/tmp/diff_new_pack.H8GLL0/_old 2022-07-26 19:44:17.996959004 +0200 +++ /var/tmp/diff_new_pack.H8GLL0/_new 2022-07-26 19:44:17.996959004 +0200 @@ -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.38.5</param> + <param name="revision">v0.38.6</param> <param name="versionformat">@PARENT_TAG@</param> <param name="changesgenerate">enable</param> <param name="versionrewrite-pattern">v(.*)</param> @@ -16,7 +16,7 @@ <param name="compression">gz</param> </service> <service name="go_modules" mode="disabled"> - <param name="archive">terragrunt-0.38.5.tar.gz</param> + <param name="archive">terragrunt-0.38.6.tar.gz</param> </service> </services> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.H8GLL0/_old 2022-07-26 19:44:18.016955913 +0200 +++ /var/tmp/diff_new_pack.H8GLL0/_new 2022-07-26 19:44:18.020955295 +0200 @@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/gruntwork-io/terragrunt</param> - <param name="changesrevision">7b7e213d90be6460cb37f8b57c0f8c48401f431d</param></service></servicedata> + <param name="changesrevision">e6f53ed2d428944a30e03f32461d51393c68dd0f</param></service></servicedata> (No newline at EOF) ++++++ terragrunt-0.38.5.tar.gz -> terragrunt-0.38.6.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.38.5/appveyor.yml new/terragrunt-0.38.6/appveyor.yml --- old/terragrunt-0.38.5/appveyor.yml 2022-07-13 15:59:36.000000000 +0200 +++ new/terragrunt-0.38.6/appveyor.yml 1970-01-01 01:00:00.000000000 +0100 @@ -1,35 +0,0 @@ -version: 1.0.{build} -clone_folder: c:\gopath\src\github.com\%APPVEYOR_REPO_NAME% -init: - - go version - - go env - - pwsh: Invoke-RestMethod -Method Get -Uri "https://releases.hashicorp.com/terraform/$($env:TERRAFORMVERSION)/terraform_$($env:TERRAFORMVERSION)_windows_amd64.zip" -OutFile "c:/terraform_windows_amd64.zip" - - pwsh: Expand-Archive -Path "c:/terraform_windows_amd64.zip" -Destination "C:/Tools/terraform" - - mkdir "C:/Tools/logparser" - - pwsh: Invoke-WebRequest -Method Get -Uri "https://github.com/gruntwork-io/terratest/releases/download/$($env:LOGPARSERVERSION)/terratest_log_parser_windows_amd64.exe" -OutFile "C:/Tools/logparser/terratest_log_parser.exe" - - set PATH=%PATH%;C:\Tools\terraform\;C:\Tools\logparser\ -install: - - choco install dep -environment: - GOPATH: c:\gopath - GOTESTTIMEOUT: 45m - LOGPARSERVERSION: v0.13.8 - TERRAGRUNT_DOWNLOAD: C:\.terragrunt-cache - matrix: - - TERRAFORMVERSION: 0.11.13 -build_script: - - dep ensure -test_script: - - mkdir logs - - pwsh: go test -v -parallel 1 $(go list ./... | where-object { $_ -notlike "*/test" }) | Tee-Object -FilePath 'logs/unit.log' - - terratest_log_parser.exe --testlog logs/unit.log --outputdir ./logs/unit/ - - pwsh: go test -v $(go list ./... | where-object { $_ -like "*/test" }) | Tee-Object -FilePath 'logs/integration.log' - - terratest_log_parser.exe --testlog logs/integration.log --outputdir ./logs/integration/ -artifacts: - - path: logs - name: test_logs -deploy: off -on_finish: - - ps: $wc = New-Object 'System.Net.WebClient' - - ps: $wc.UploadFile("https://ci.appveyor.com/api/testresults/junit/$($env:APPVEYOR_JOB_ID)", (Resolve-Path ./logs/unit/report.xml)) - - ps: $wc.UploadFile("https://ci.appveyor.com/api/testresults/junit/$($env:APPVEYOR_JOB_ID)", (Resolve-Path ./logs/integration/report.xml)) \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.38.5/cli/args.go new/terragrunt-0.38.6/cli/args.go --- old/terragrunt-0.38.5/cli/args.go 2022-07-13 15:59:36.000000000 +0200 +++ new/terragrunt-0.38.6/cli/args.go 2022-07-22 19:19:40.000000000 +0200 @@ -222,6 +222,8 @@ opts.HclFile = filepath.ToSlash(terragruntHclFilePath) opts.AwsProviderPatchOverrides = awsProviderPatchOverrides opts.FetchDependencyOutputFromState = parseBooleanArg(args, optTerragruntFetchDependencyOutputFromState, os.Getenv("TERRAGRUNT_FETCH_DEPENDENCY_OUTPUT_FROM_STATE") == "true") + opts.RenderJsonWithMetadata = parseBooleanArg(args, optTerragruntOutputWithMetadata, false) + opts.JSONOut, err = parseStringArg(args, optTerragruntJSONOut, "terragrunt_rendered.json") if err != nil { return nil, err diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.38.5/cli/cli_app.go new/terragrunt-0.38.6/cli/cli_app.go --- old/terragrunt-0.38.5/cli/cli_app.go 2022-07-13 15:59:36.000000000 +0200 +++ new/terragrunt-0.38.6/cli/cli_app.go 2022-07-22 19:19:40.000000000 +0200 @@ -58,6 +58,7 @@ optTerragruntJSONOut = "terragrunt-json-out" optTerragruntModulesThatInclude = "terragrunt-modules-that-include" optTerragruntFetchDependencyOutputFromState = "terragrunt-fetch-dependency-output-from-state" + optTerragruntOutputWithMetadata = "with-metadata" ) var allTerragruntBooleanOpts = []string{ @@ -74,6 +75,7 @@ optTerragruntStrictInclude, optTerragruntDebug, optTerragruntFetchDependencyOutputFromState, + optTerragruntOutputWithMetadata, } var allTerragruntStringOpts = []string{ optTerragruntConfig, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.38.5/cli/render_json.go new/terragrunt-0.38.6/cli/render_json.go --- old/terragrunt-0.38.5/cli/render_json.go 2022-07-13 15:59:36.000000000 +0200 +++ new/terragrunt-0.38.6/cli/render_json.go 2022-07-22 19:19:40.000000000 +0200 @@ -25,9 +25,20 @@ return fmt.Errorf("Terragrunt was not able to render the config as json because it received no config. This is almost certainly a bug in Terragrunt. Please open an issue on github.com/gruntwork-io/terragrunt with this message and the contents of your terragrunt.hcl.") } - terragruntConfigCty, err := config.TerragruntConfigAsCty(terragruntConfig) - if err != nil { - return err + var terragruntConfigCty cty.Value + + if terragruntOptions.RenderJsonWithMetadata { + cty, err := config.TerragruntConfigAsCtyWithMetadata(terragruntConfig) + if err != nil { + return err + } + terragruntConfigCty = cty + } else { + cty, err := config.TerragruntConfigAsCty(terragruntConfig) + if err != nil { + return err + } + terragruntConfigCty = cty } jsonBytes, err := marshalCtyValueJSONWithoutType(terragruntConfigCty) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.38.5/config/config.go new/terragrunt-0.38.6/config/config.go --- old/terragrunt-0.38.5/config/config.go 2022-07-13 15:59:36.000000000 +0200 +++ new/terragrunt-0.38.6/config/config.go 2022-07-22 19:19:40.000000000 +0200 @@ -28,6 +28,30 @@ const DefaultTerragruntConfigPath = "terragrunt.hcl" const DefaultTerragruntJsonConfigPath = "terragrunt.hcl.json" +const foundInFile = "found_in_file" + +const ( + MetadataTerraform = "terraform" + MetadataTerraformBinary = "terraform_binary" + MetadataTerraformVersionConstraint = "terraform_version_constraint" + MetadataTerragruntVersionConstraint = "terragrunt_version_constraint" + MetadataRemoteState = "remote_state" + MetadataDependencies = "dependencies" + MetadataDependency = "dependency" + MetadataDownloadDir = "download_dir" + MetadataPreventDestroy = "prevent_destroy" + MetadataSkip = "skip" + MetadataIamRole = "iam_role" + MetadataIamAssumeRoleDuration = "iam_assume_role_duration" + MetadataIamAssumeRoleSessionName = "iam_assume_role_session_name" + MetadataInputs = "inputs" + MetadataLocals = "locals" + MetadataGenerateConfigs = "generate" + MetadataRetryableErrors = "retryable_errors" + MetadataRetryMaxAttempts = "retry_max_attempts" + MetadataRetrySleepIntervalSec = "retry_sleep_interval_sec" +) + // TerragruntConfig represents a parsed and expanded configuration // NOTE: if any attributes are added, make sure to update terragruntConfigAsCty in config_as_cty.go type TerragruntConfig struct { @@ -57,6 +81,9 @@ // Map of processed includes ProcessedIncludes map[string]IncludeConfig + + // Map to store fields metadata + FieldsMetadata map[string]map[string]interface{} } func (conf *TerragruntConfig) String() string { @@ -705,6 +732,7 @@ // original locals for the current config being handled, as that is the locals list that is in scope for this // config. mergedConfig.Locals = config.Locals + return mergedConfig, nil } return config, nil @@ -804,12 +832,14 @@ GenerateConfigs: map[string]codegen.GenerateConfig{}, } + defaultMetadata := map[string]interface{}{foundInFile: configPath} if terragruntConfigFromFile.RemoteState != nil { remoteState, err := terragruntConfigFromFile.RemoteState.toConfig() if err != nil { return nil, err } terragruntConfig.RemoteState = remoteState + terragruntConfig.SetFieldMetadata(MetadataRemoteState, defaultMetadata) } if terragruntConfigFromFile.RemoteStateAttr != nil { @@ -824,6 +854,7 @@ } terragruntConfig.RemoteState = remoteState + terragruntConfig.SetFieldMetadata(MetadataRemoteState, defaultMetadata) } if err := terragruntConfigFromFile.Terraform.ValidateHooks(); err != nil { @@ -831,58 +862,83 @@ } terragruntConfig.Terraform = terragruntConfigFromFile.Terraform + if terragruntConfig.Terraform != nil { // since Terraform is nil each time avoid saving metadata when it is nil + terragruntConfig.SetFieldMetadata(MetadataTerraform, defaultMetadata) + } + if err := validateDependencies(terragruntOptions, terragruntConfigFromFile.Dependencies); err != nil { return nil, err } terragruntConfig.Dependencies = terragruntConfigFromFile.Dependencies + if terragruntConfig.Dependencies != nil { + for _, item := range terragruntConfig.Dependencies.Paths { + terragruntConfig.SetFieldMetadataWithType(MetadataDependencies, item, defaultMetadata) + } + } + terragruntConfig.TerragruntDependencies = terragruntConfigFromFile.TerragruntDependencies + for _, dep := range terragruntConfig.TerragruntDependencies { + terragruntConfig.SetFieldMetadataWithType(MetadataDependency, dep.Name, defaultMetadata) + } if terragruntConfigFromFile.TerraformBinary != nil { terragruntConfig.TerraformBinary = *terragruntConfigFromFile.TerraformBinary + terragruntConfig.SetFieldMetadata(MetadataTerraformBinary, defaultMetadata) } if terragruntConfigFromFile.RetryableErrors != nil { terragruntConfig.RetryableErrors = terragruntConfigFromFile.RetryableErrors + terragruntConfig.SetFieldMetadata(MetadataRetryableErrors, defaultMetadata) } if terragruntConfigFromFile.RetryMaxAttempts != nil { terragruntConfig.RetryMaxAttempts = terragruntConfigFromFile.RetryMaxAttempts + terragruntConfig.SetFieldMetadata(MetadataRetryMaxAttempts, defaultMetadata) } if terragruntConfigFromFile.RetrySleepIntervalSec != nil { terragruntConfig.RetrySleepIntervalSec = terragruntConfigFromFile.RetrySleepIntervalSec + terragruntConfig.SetFieldMetadata(MetadataRetrySleepIntervalSec, defaultMetadata) } if terragruntConfigFromFile.DownloadDir != nil { terragruntConfig.DownloadDir = *terragruntConfigFromFile.DownloadDir + terragruntConfig.SetFieldMetadata(MetadataDownloadDir, defaultMetadata) } if terragruntConfigFromFile.TerraformVersionConstraint != nil { terragruntConfig.TerraformVersionConstraint = *terragruntConfigFromFile.TerraformVersionConstraint + terragruntConfig.SetFieldMetadata(MetadataTerraformVersionConstraint, defaultMetadata) } if terragruntConfigFromFile.TerragruntVersionConstraint != nil { terragruntConfig.TerragruntVersionConstraint = *terragruntConfigFromFile.TerragruntVersionConstraint + terragruntConfig.SetFieldMetadata(MetadataTerragruntVersionConstraint, defaultMetadata) } if terragruntConfigFromFile.PreventDestroy != nil { terragruntConfig.PreventDestroy = terragruntConfigFromFile.PreventDestroy + terragruntConfig.SetFieldMetadata(MetadataPreventDestroy, defaultMetadata) } if terragruntConfigFromFile.Skip != nil { terragruntConfig.Skip = *terragruntConfigFromFile.Skip + terragruntConfig.SetFieldMetadata(MetadataSkip, defaultMetadata) } if terragruntConfigFromFile.IamRole != nil { terragruntConfig.IamRole = *terragruntConfigFromFile.IamRole + terragruntConfig.SetFieldMetadata(MetadataIamRole, defaultMetadata) } if terragruntConfigFromFile.IamAssumeRoleDuration != nil { terragruntConfig.IamAssumeRoleDuration = terragruntConfigFromFile.IamAssumeRoleDuration + terragruntConfig.SetFieldMetadata(MetadataIamAssumeRoleDuration, defaultMetadata) } if terragruntConfigFromFile.IamAssumeRoleSessionName != nil { terragruntConfig.IamAssumeRoleSessionName = *terragruntConfigFromFile.IamAssumeRoleSessionName + terragruntConfig.SetFieldMetadata(MetadataIamAssumeRoleSessionName, defaultMetadata) } generateBlocks := []terragruntGenerateBlock{} @@ -928,6 +984,7 @@ genConfig.DisableSignature = *block.DisableSignature } terragruntConfig.GenerateConfigs[block.Name] = genConfig + terragruntConfig.SetFieldMetadataWithType(MetadataGenerateConfigs, block.Name, defaultMetadata) } if terragruntConfigFromFile.Inputs != nil { @@ -937,6 +994,7 @@ } terragruntConfig.Inputs = inputs + terragruntConfig.SetFieldMetadataMap(MetadataInputs, terragruntConfig.Inputs, defaultMetadata) } if contextExtensions.Locals != nil && *contextExtensions.Locals != cty.NilVal { @@ -945,6 +1003,7 @@ return nil, err } terragruntConfig.Locals = localsParsed + terragruntConfig.SetFieldMetadataMap(MetadataLocals, localsParsed, defaultMetadata) } return terragruntConfig, nil @@ -1015,6 +1074,62 @@ return false, nil } +// SetFieldMetadataWithType set metadata on the given field name grouped by type. +// Example usage - setting metadata on different dependencies, locals, inputs. +func (conf *TerragruntConfig) SetFieldMetadataWithType(fieldType, fieldName string, m map[string]interface{}) { + if conf.FieldsMetadata == nil { + conf.FieldsMetadata = map[string]map[string]interface{}{} + } + + field := fmt.Sprintf("%s-%s", fieldType, fieldName) + + metadata, found := conf.FieldsMetadata[field] + if !found { + metadata = make(map[string]interface{}) + } + for key, value := range m { + metadata[key] = value + } + conf.FieldsMetadata[field] = metadata +} + +// SetFieldMetadata set metadata on the given field name. +func (conf *TerragruntConfig) SetFieldMetadata(fieldName string, m map[string]interface{}) { + conf.SetFieldMetadataWithType(fieldName, fieldName, m) +} + +// SetFieldMetadataMap set metadata on fields from map keys. +// Example usage - setting metadata on all variables from inputs. +func (conf *TerragruntConfig) SetFieldMetadataMap(field string, data map[string]interface{}, metadata map[string]interface{}) { + for name, _ := range data { + conf.SetFieldMetadataWithType(field, name, metadata) + } +} + +// GetFieldMetadata return field metadata by field name. +func (conf *TerragruntConfig) GetFieldMetadata(fieldName string) (map[string]string, bool) { + return conf.GetMapFieldMetadata(fieldName, fieldName) +} + +// GetMapFieldMetadata return field metadata by field type and name. +func (conf *TerragruntConfig) GetMapFieldMetadata(fieldType, fieldName string) (map[string]string, bool) { + if conf.FieldsMetadata == nil { + return nil, false + } + field := fmt.Sprintf("%s-%s", fieldType, fieldName) + + value, found := conf.FieldsMetadata[field] + if !found { + return nil, false + } + var result = make(map[string]string) + for key, value := range value { + result[key] = fmt.Sprintf("%v", value) + } + + return result, found +} + // Custom error types type InvalidArgError string diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.38.5/config/config_as_cty.go new/terragrunt-0.38.6/config/config_as_cty.go --- old/terragrunt-0.38.5/config/config_as_cty.go 2022-07-13 15:59:36.000000000 +0200 +++ new/terragrunt-0.38.6/config/config_as_cty.go 2022-07-22 19:19:40.000000000 +0200 @@ -20,20 +20,20 @@ output := map[string]cty.Value{} // Convert attributes that are primitive types - output["terraform_binary"] = gostringToCty(config.TerraformBinary) - output["terraform_version_constraint"] = gostringToCty(config.TerraformVersionConstraint) - output["terragrunt_version_constraint"] = gostringToCty(config.TerragruntVersionConstraint) - output["download_dir"] = gostringToCty(config.DownloadDir) - output["iam_role"] = gostringToCty(config.IamRole) - output["skip"] = goboolToCty(config.Skip) - output["iam_assume_role_session_name"] = gostringToCty(config.IamAssumeRoleSessionName) + output[MetadataTerraformBinary] = gostringToCty(config.TerraformBinary) + output[MetadataTerraformVersionConstraint] = gostringToCty(config.TerraformVersionConstraint) + output[MetadataTerragruntVersionConstraint] = gostringToCty(config.TerragruntVersionConstraint) + output[MetadataDownloadDir] = gostringToCty(config.DownloadDir) + output[MetadataIamRole] = gostringToCty(config.IamRole) + output[MetadataSkip] = goboolToCty(config.Skip) + output[MetadataIamAssumeRoleSessionName] = gostringToCty(config.IamAssumeRoleSessionName) terraformConfigCty, err := terraformConfigAsCty(config.Terraform) if err != nil { return cty.NilVal, err } if terraformConfigCty != cty.NilVal { - output["terraform"] = terraformConfigCty + output[MetadataTerraform] = terraformConfigCty } remoteStateCty, err := remoteStateAsCty(config.RemoteState) @@ -41,7 +41,7 @@ return cty.NilVal, err } if remoteStateCty != cty.NilVal { - output["remote_state"] = remoteStateCty + output[MetadataRemoteState] = remoteStateCty } dependenciesCty, err := goTypeToCty(config.Dependencies) @@ -49,11 +49,11 @@ return cty.NilVal, err } if dependenciesCty != cty.NilVal { - output["dependencies"] = dependenciesCty + output[MetadataDependencies] = dependenciesCty } if config.PreventDestroy != nil { - output["prevent_destroy"] = goboolToCty(*config.PreventDestroy) + output[MetadataPreventDestroy] = goboolToCty(*config.PreventDestroy) } dependencyCty, err := dependencyBlocksAsCty(config.TerragruntDependencies) @@ -61,7 +61,7 @@ return cty.NilVal, err } if dependencyCty != cty.NilVal { - output["dependency"] = dependencyCty + output[MetadataDependency] = dependencyCty } generateCty, err := goTypeToCty(config.GenerateConfigs) @@ -69,7 +69,7 @@ return cty.NilVal, err } if generateCty != cty.NilVal { - output["generate"] = generateCty + output[MetadataGenerateConfigs] = generateCty } retryableCty, err := goTypeToCty(config.RetryableErrors) @@ -77,7 +77,7 @@ return cty.NilVal, err } if retryableCty != cty.NilVal { - output["retryable_errors"] = retryableCty + output[MetadataRetryableErrors] = retryableCty } iamAssumeRoleDurationCty, err := goTypeToCty(config.IamAssumeRoleDuration) @@ -86,7 +86,7 @@ } if iamAssumeRoleDurationCty != cty.NilVal { - output["iam_assume_role_duration"] = iamAssumeRoleDurationCty + output[MetadataIamAssumeRoleDuration] = iamAssumeRoleDurationCty } retryMaxAttemptsCty, err := goTypeToCty(config.RetryMaxAttempts) @@ -94,7 +94,7 @@ return cty.NilVal, err } if retryMaxAttemptsCty != cty.NilVal { - output["retry_max_attempts"] = retryMaxAttemptsCty + output[MetadataRetryMaxAttempts] = retryMaxAttemptsCty } retrySleepIntervalSecCty, err := goTypeToCty(config.RetrySleepIntervalSec) @@ -102,7 +102,7 @@ return cty.NilVal, err } if retrySleepIntervalSecCty != cty.NilVal { - output["retry_sleep_interval_sec"] = retrySleepIntervalSecCty + output[MetadataRetrySleepIntervalSec] = retrySleepIntervalSecCty } inputsCty, err := convertToCtyWithJson(config.Inputs) @@ -110,7 +110,7 @@ return cty.NilVal, err } if inputsCty != cty.NilVal { - output["inputs"] = inputsCty + output[MetadataInputs] = inputsCty } localsCty, err := convertToCtyWithJson(config.Locals) @@ -118,12 +118,241 @@ return cty.NilVal, err } if localsCty != cty.NilVal { - output["locals"] = localsCty + output[MetadataLocals] = localsCty } return convertValuesMapToCtyVal(output) } +func TerragruntConfigAsCtyWithMetadata(config *TerragruntConfig) (cty.Value, error) { + output := map[string]cty.Value{} + + // Convert attributes that are primitive types + if err := wrapWithMetadata(config, config.TerraformBinary, MetadataTerraformBinary, &output); err != nil { + return cty.NilVal, err + } + + if err := wrapWithMetadata(config, config.TerraformVersionConstraint, MetadataTerraformVersionConstraint, &output); err != nil { + return cty.NilVal, err + } + + if err := wrapWithMetadata(config, config.TerragruntVersionConstraint, MetadataTerragruntVersionConstraint, &output); err != nil { + return cty.NilVal, err + } + + if err := wrapWithMetadata(config, config.DownloadDir, MetadataDownloadDir, &output); err != nil { + return cty.NilVal, err + } + + if err := wrapWithMetadata(config, config.IamRole, MetadataIamRole, &output); err != nil { + return cty.NilVal, err + } + + if err := wrapWithMetadata(config, config.Skip, MetadataSkip, &output); err != nil { + return cty.NilVal, err + } + + if err := wrapWithMetadata(config, config.IamAssumeRoleSessionName, MetadataIamAssumeRoleSessionName, &output); err != nil { + return cty.NilVal, err + } + + if config.PreventDestroy != nil { + if err := wrapWithMetadata(config, *config.PreventDestroy, MetadataPreventDestroy, &output); err != nil { + return cty.NilVal, err + } + } + + if err := wrapWithMetadata(config, config.RetryableErrors, MetadataRetryableErrors, &output); err != nil { + return cty.NilVal, err + } + + if err := wrapWithMetadata(config, config.IamAssumeRoleDuration, MetadataIamAssumeRoleDuration, &output); err != nil { + return cty.NilVal, err + } + + if err := wrapWithMetadata(config, config.RetryMaxAttempts, MetadataRetryMaxAttempts, &output); err != nil { + return cty.NilVal, err + } + if err := wrapWithMetadata(config, config.RetrySleepIntervalSec, MetadataRetrySleepIntervalSec, &output); err != nil { + return cty.NilVal, err + } + + // Terraform + terraformConfigCty, err := terraformConfigAsCty(config.Terraform) + if err != nil { + return cty.NilVal, err + } + if terraformConfigCty != cty.NilVal { + if err := wrapWithMetadata(config, terraformConfigCty, MetadataTerraform, &output); err != nil { + return cty.NilVal, err + } + } + + // Remote state + remoteStateCty, err := remoteStateAsCty(config.RemoteState) + if err != nil { + return cty.NilVal, err + } + if remoteStateCty != cty.NilVal { + if err := wrapWithMetadata(config, remoteStateCty, MetadataRemoteState, &output); err != nil { + return cty.NilVal, err + } + } + + if err := wrapCtyMapWithMetadata(config, &config.Inputs, MetadataInputs, &output); err != nil { + return cty.NilVal, err + } + + if err := wrapCtyMapWithMetadata(config, &config.Locals, MetadataLocals, &output); err != nil { + return cty.NilVal, err + } + + // remder dependencies as list of maps with "value" and "metadata" + if config.Dependencies != nil { + var dependencyWithMetadata = make([]ValueWithMetadata, 0, len(config.Dependencies.Paths)) + for _, dependency := range config.Dependencies.Paths { + var content = ValueWithMetadata{} + content.Value = gostringToCty(dependency) + metadata, found := config.GetMapFieldMetadata(MetadataDependencies, dependency) + if found { + content.Metadata = metadata + } + dependencyWithMetadata = append(dependencyWithMetadata, content) + } + dependenciesCty, err := goTypeToCty(dependencyWithMetadata) + if err != nil { + return cty.NilVal, err + } + output[MetadataDependencies] = dependenciesCty + } + + if config.TerragruntDependencies != nil { + var dependenciesMap = map[string]cty.Value{} + for _, block := range config.TerragruntDependencies { + ctyValue, err := goTypeToCty(block) + if err != nil { + continue + } + if ctyValue == cty.NilVal { + continue + } + + var content = ValueWithMetadata{} + content.Value = ctyValue + metadata, found := config.GetMapFieldMetadata(MetadataDependency, block.Name) + if found { + content.Metadata = metadata + } + + value, err := goTypeToCty(content) + if err != nil { + continue + } + dependenciesMap[block.Name] = value + } + if len(dependenciesMap) > 0 { + dependenciesCty, err := convertValuesMapToCtyVal(dependenciesMap) + if err != nil { + return cty.NilVal, err + } + output[MetadataDependency] = dependenciesCty + } + } + + if config.GenerateConfigs != nil { + var generateConfigsWithMetadata = map[string]cty.Value{} + for key, value := range config.GenerateConfigs { + ctyValue, err := goTypeToCty(value) + if err != nil { + continue + } + if ctyValue == cty.NilVal { + continue + } + var content = ValueWithMetadata{} + content.Value = ctyValue + metadata, found := config.GetMapFieldMetadata(MetadataGenerateConfigs, key) + if found { + content.Metadata = metadata + } + + v, err := goTypeToCty(content) + if err != nil { + continue + } + generateConfigsWithMetadata[key] = v + } + if len(generateConfigsWithMetadata) > 0 { + dependenciesCty, err := convertValuesMapToCtyVal(generateConfigsWithMetadata) + if err != nil { + return cty.NilVal, err + } + output[MetadataGenerateConfigs] = dependenciesCty + } + } + + return convertValuesMapToCtyVal(output) +} + +func wrapCtyMapWithMetadata(config *TerragruntConfig, data *map[string]interface{}, fieldType string, output *map[string]cty.Value) error { + var valueWithMetadata = map[string]cty.Value{} + for key, value := range *data { + var content = ValueWithMetadata{} + ctyValue, err := convertToCtyWithJson(value) + if err != nil { + return err + } + content.Value = ctyValue + metadata, found := config.GetMapFieldMetadata(fieldType, key) + if found { + content.Metadata = metadata + } + v, err := goTypeToCty(content) + if err != nil { + continue + } + valueWithMetadata[key] = v + } + if len(valueWithMetadata) > 0 { + localsCty, err := convertValuesMapToCtyVal(valueWithMetadata) + if err != nil { + return err + } + (*output)[fieldType] = localsCty + } + return nil +} + +func wrapWithMetadata(config *TerragruntConfig, value interface{}, metadataName string, output *map[string]cty.Value) error { + if value == nil { + return nil + } + var valueWithMetadata = ValueWithMetadata{} + ctyValue, err := goTypeToCty(value) + if err != nil { + return err + } + valueWithMetadata.Value = ctyValue + metadata, found := config.GetFieldMetadata(metadataName) + if found { + valueWithMetadata.Metadata = metadata + } + ctyJson, err := goTypeToCty(valueWithMetadata) + if err != nil { + return err + } + if ctyJson != cty.NilVal { + (*output)[metadataName] = ctyJson + } + return nil +} + +// ValueWithMetadata stores value and metadata used in render-json with metadata. +type ValueWithMetadata struct { + Value cty.Value `json:"value" cty:"value"` + Metadata map[string]string `json:"metadata" cty:"metadata"` +} + // ctyTerraformConfig is an alternate representation of TerraformConfig that converts internal blocks into a map that // maps the name to the underlying struct, as opposed to a list representation. type ctyTerraformConfig struct { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.38.5/config/config_as_cty_test.go new/terragrunt-0.38.6/config/config_as_cty_test.go --- old/terragrunt-0.38.5/config/config_as_cty_test.go 2022-07-13 15:59:36.000000000 +0200 +++ new/terragrunt-0.38.6/config/config_as_cty_test.go 2022-07-22 19:19:40.000000000 +0200 @@ -213,6 +213,8 @@ return "", false case "ProcessedIncludes": return "", false + case "FieldsMetadata": + return "", false case "RetryableErrors": return "retryable_errors", true case "RetryMaxAttempts": diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.38.5/config/include.go new/terragrunt-0.38.6/config/include.go --- old/terragrunt-0.38.5/config/include.go 2022-07-13 15:59:36.000000000 +0200 +++ new/terragrunt-0.38.6/config/include.go 2022-07-22 19:19:40.000000000 +0200 @@ -332,6 +332,8 @@ if sourceConfig.Inputs != nil { targetConfig.Inputs = mergeInputs(sourceConfig.Inputs, targetConfig.Inputs) } + + copyFieldsMetadata(sourceConfig, targetConfig) } // DeepMerge performs a deep merge of the given sourceConfig into the targetConfig. Deep merge is defined as follows: @@ -478,6 +480,8 @@ for key, val := range sourceConfig.GenerateConfigs { targetConfig.GenerateConfigs[key] = val } + + copyFieldsMetadata(sourceConfig, targetConfig) return nil } @@ -839,6 +843,18 @@ return false } +// copyFieldsMetadata Copy fields metadata between TerragruntConfig instances. +func copyFieldsMetadata(sourceConfig *TerragruntConfig, targetConfig *TerragruntConfig) { + if sourceConfig.FieldsMetadata != nil { + if targetConfig.FieldsMetadata == nil { + targetConfig.FieldsMetadata = map[string]map[string]interface{}{} + } + for k, v := range sourceConfig.FieldsMetadata { + targetConfig.FieldsMetadata[k] = v + } + } +} + // Custom error types type MultipleBareIncludeBlocksErr struct{} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.38.5/docs/_docs/04_reference/cli-options.md new/terragrunt-0.38.6/docs/_docs/04_reference/cli-options.md --- old/terragrunt-0.38.5/docs/_docs/04_reference/cli-options.md 2022-07-13 15:59:36.000000000 +0200 +++ new/terragrunt-0.38.6/docs/_docs/04_reference/cli-options.md 2022-07-22 19:19:40.000000000 +0200 @@ -35,7 +35,7 @@ - [graph-dependencies](#graph-dependencies) - [hclfmt](#hclfmt) - [aws-provider-patch](#aws-provider-patch) - - [render-json](#render-json) + - [crender-json](#render-json) ### All Terraform built-in commands @@ -439,6 +439,30 @@ You can use the CLI option `--terragrunt-json-out` to configure where terragrunt renders out the json representation. +To generate json with metadata can be specified argument `--with-metadata` which will add metadata to the json output. + +Example: +``` +{ + "inputs": { + "aws_region": { + "metadata": { + "found_in_file": "/example/terragrunt.hcl" + }, + "value": "us-east-1" + } + }, + "locals": { + "aws_region": { + "metadata": { + "found_in_file": "/example/terragrunt.hcl" + }, + "value": "us-east-1" + } + } + // NOTE: other attributes are omitted for brevity +} +``` ## CLI options diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.38.5/options/options.go new/terragrunt-0.38.6/options/options.go --- old/terragrunt-0.38.5/options/options.go 2022-07-13 15:59:36.000000000 +0200 +++ new/terragrunt-0.38.6/options/options.go 2022-07-22 19:19:40.000000000 +0200 @@ -192,6 +192,9 @@ // This is an experimental feature, used to speed up dependency processing by getting the output from the state FetchDependencyOutputFromState bool + + // Include fields metadata in render-json + RenderJsonWithMetadata bool } // IAMOptions represents options that are used by Terragrunt to assume an IAM role. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.38.5/test/fixture-render-json-metadata/attributes/terragrunt.hcl new/terragrunt-0.38.6/test/fixture-render-json-metadata/attributes/terragrunt.hcl --- old/terragrunt-0.38.5/test/fixture-render-json-metadata/attributes/terragrunt.hcl 1970-01-01 01:00:00.000000000 +0100 +++ new/terragrunt-0.38.6/test/fixture-render-json-metadata/attributes/terragrunt.hcl 2022-07-22 19:19:40.000000000 +0200 @@ -0,0 +1,26 @@ +inputs = { + region = local.aws_region + name = "${local.aws_region}-bucket" +} + +locals { + aws_region = "us-east-1" +} + +download_dir = "/tmp" + +prevent_destroy = true +skip = true + +iam_role = "arn:aws:iam::ACCOUNT_ID:role/ROLE_NAME" +iam_assume_role_duration = 666 + +terraform_binary = "terraform" +terraform_version_constraint = ">= 0.11" + +retryable_errors = [ + "(?s).*Error installing provider.*tcp.*connection reset by peer.*", + "(?s).*ssh_exchange_identification.*Connection closed by remote host.*" +] +iam_assume_role_session_name = "qwe" + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.38.5/test/fixture-render-json-metadata/dependencies/app/include.hcl new/terragrunt-0.38.6/test/fixture-render-json-metadata/dependencies/app/include.hcl --- old/terragrunt-0.38.5/test/fixture-render-json-metadata/dependencies/app/include.hcl 1970-01-01 01:00:00.000000000 +0100 +++ new/terragrunt-0.38.6/test/fixture-render-json-metadata/dependencies/app/include.hcl 2022-07-22 19:19:40.000000000 +0200 @@ -0,0 +1,7 @@ +dependencies { + paths = ["../dependency2"] +} + +inputs = { + test_input = "test_value" +} \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.38.5/test/fixture-render-json-metadata/dependencies/app/terragrunt.hcl new/terragrunt-0.38.6/test/fixture-render-json-metadata/dependencies/app/terragrunt.hcl --- old/terragrunt-0.38.5/test/fixture-render-json-metadata/dependencies/app/terragrunt.hcl 1970-01-01 01:00:00.000000000 +0100 +++ new/terragrunt-0.38.6/test/fixture-render-json-metadata/dependencies/app/terragrunt.hcl 2022-07-22 19:19:40.000000000 +0200 @@ -0,0 +1,7 @@ +dependencies { + paths = ["../dependency1" ] +} + +include "include" { + path = "./include.hcl" +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.38.5/test/fixture-render-json-metadata/dependency/app/terragrunt.hcl new/terragrunt-0.38.6/test/fixture-render-json-metadata/dependency/app/terragrunt.hcl --- old/terragrunt-0.38.5/test/fixture-render-json-metadata/dependency/app/terragrunt.hcl 1970-01-01 01:00:00.000000000 +0100 +++ new/terragrunt-0.38.6/test/fixture-render-json-metadata/dependency/app/terragrunt.hcl 2022-07-22 19:19:40.000000000 +0200 @@ -0,0 +1,16 @@ + +dependency "dep" { + config_path = "../dependency" + + mock_outputs = { + test = "value" + } +} + +dependency "dep2" { + config_path = "../dependency2" + + mock_outputs = { + test2 = "value2" + } +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.38.5/test/fixture-render-json-metadata/dependency/dependency/terragrunt.hcl new/terragrunt-0.38.6/test/fixture-render-json-metadata/dependency/dependency/terragrunt.hcl --- old/terragrunt-0.38.5/test/fixture-render-json-metadata/dependency/dependency/terragrunt.hcl 1970-01-01 01:00:00.000000000 +0100 +++ new/terragrunt-0.38.6/test/fixture-render-json-metadata/dependency/dependency/terragrunt.hcl 2022-07-22 19:19:40.000000000 +0200 @@ -0,0 +1,4 @@ +locals { + + x = run_cmd("echo", "HCL file evaluation") +} \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.38.5/test/fixture-render-json-metadata/dependency/dependency2/terragrunt.hcl new/terragrunt-0.38.6/test/fixture-render-json-metadata/dependency/dependency2/terragrunt.hcl --- old/terragrunt-0.38.5/test/fixture-render-json-metadata/dependency/dependency2/terragrunt.hcl 1970-01-01 01:00:00.000000000 +0100 +++ new/terragrunt-0.38.6/test/fixture-render-json-metadata/dependency/dependency2/terragrunt.hcl 2022-07-22 19:19:40.000000000 +0200 @@ -0,0 +1,4 @@ +locals { + + x = run_cmd("echo", "HCL file evaluation") +} \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.38.5/test/fixture-render-json-metadata/includes/app/generate.hcl new/terragrunt-0.38.6/test/fixture-render-json-metadata/includes/app/generate.hcl --- old/terragrunt-0.38.5/test/fixture-render-json-metadata/includes/app/generate.hcl 1970-01-01 01:00:00.000000000 +0100 +++ new/terragrunt-0.38.6/test/fixture-render-json-metadata/includes/app/generate.hcl 2022-07-22 19:19:40.000000000 +0200 @@ -0,0 +1,7 @@ +generate "provider" { + path = "provider.tf" + if_exists = "overwrite" + contents = <<EOF +# test +EOF +} \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.38.5/test/fixture-render-json-metadata/includes/app/inputs.hcl new/terragrunt-0.38.6/test/fixture-render-json-metadata/includes/app/inputs.hcl --- old/terragrunt-0.38.5/test/fixture-render-json-metadata/includes/app/inputs.hcl 1970-01-01 01:00:00.000000000 +0100 +++ new/terragrunt-0.38.6/test/fixture-render-json-metadata/includes/app/inputs.hcl 2022-07-22 19:19:40.000000000 +0200 @@ -0,0 +1,3 @@ +inputs = { + qwe = "123" +} \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.38.5/test/fixture-render-json-metadata/includes/app/locals.hcl new/terragrunt-0.38.6/test/fixture-render-json-metadata/includes/app/locals.hcl --- old/terragrunt-0.38.5/test/fixture-render-json-metadata/includes/app/locals.hcl 1970-01-01 01:00:00.000000000 +0100 +++ new/terragrunt-0.38.6/test/fixture-render-json-metadata/includes/app/locals.hcl 2022-07-22 19:19:40.000000000 +0200 @@ -0,0 +1,8 @@ +locals { + a1 = "qwe" + content = "test" +} + +inputs = { + content = local.content +} \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.38.5/test/fixture-render-json-metadata/includes/app/main.tf new/terragrunt-0.38.6/test/fixture-render-json-metadata/includes/app/main.tf --- old/terragrunt-0.38.5/test/fixture-render-json-metadata/includes/app/main.tf 1970-01-01 01:00:00.000000000 +0100 +++ new/terragrunt-0.38.6/test/fixture-render-json-metadata/includes/app/main.tf 2022-07-22 19:19:40.000000000 +0200 @@ -0,0 +1,6 @@ +variable "content" {} + +resource "local_file" "file" { + content = "content: ${var.content}" + filename = "${path.module}/cluster_name.txt" +} \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.38.5/test/fixture-render-json-metadata/includes/app/terragrunt.hcl new/terragrunt-0.38.6/test/fixture-render-json-metadata/includes/app/terragrunt.hcl --- old/terragrunt-0.38.5/test/fixture-render-json-metadata/includes/app/terragrunt.hcl 1970-01-01 01:00:00.000000000 +0100 +++ new/terragrunt-0.38.6/test/fixture-render-json-metadata/includes/app/terragrunt.hcl 2022-07-22 19:19:40.000000000 +0200 @@ -0,0 +1,20 @@ +include "common" { + path = "../common/common.hcl" +} + +include "inputs" { + path = "./inputs.hcl" +} + +include "locals" { + path = "./locals.hcl" +} + +include "generate" { + path = "./generate.hcl" +} + +locals { + abc = "xyz" + +} \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.38.5/test/fixture-render-json-metadata/includes/common/common.hcl new/terragrunt-0.38.6/test/fixture-render-json-metadata/includes/common/common.hcl --- old/terragrunt-0.38.5/test/fixture-render-json-metadata/includes/common/common.hcl 1970-01-01 01:00:00.000000000 +0100 +++ new/terragrunt-0.38.6/test/fixture-render-json-metadata/includes/common/common.hcl 2022-07-22 19:19:40.000000000 +0200 @@ -0,0 +1,8 @@ +remote_state { + backend = "s3" + config = { + bucket = "mybucket" + key = "path/to/my/key" + region = "us-east-1" + } +} \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.38.5/test/fixture-render-json-metadata/terraform-remote-state/app/terragrunt.hcl new/terragrunt-0.38.6/test/fixture-render-json-metadata/terraform-remote-state/app/terragrunt.hcl --- old/terragrunt-0.38.5/test/fixture-render-json-metadata/terraform-remote-state/app/terragrunt.hcl 1970-01-01 01:00:00.000000000 +0100 +++ new/terragrunt-0.38.6/test/fixture-render-json-metadata/terraform-remote-state/app/terragrunt.hcl 2022-07-22 19:19:40.000000000 +0200 @@ -0,0 +1,7 @@ +include "terraform" { + path = "../common/terraform.hcl" +} + +include "remote_state" { + path = "../common/remote_state.hcl" +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.38.5/test/fixture-render-json-metadata/terraform-remote-state/common/remote_state.hcl new/terragrunt-0.38.6/test/fixture-render-json-metadata/terraform-remote-state/common/remote_state.hcl --- old/terragrunt-0.38.5/test/fixture-render-json-metadata/terraform-remote-state/common/remote_state.hcl 1970-01-01 01:00:00.000000000 +0100 +++ new/terragrunt-0.38.6/test/fixture-render-json-metadata/terraform-remote-state/common/remote_state.hcl 2022-07-22 19:19:40.000000000 +0200 @@ -0,0 +1,8 @@ +remote_state { + backend = "s3" + config = { + bucket = "mybucket" + key = "path/to/my/key" + region = "us-east-1" + } +} \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.38.5/test/fixture-render-json-metadata/terraform-remote-state/common/terraform.hcl new/terragrunt-0.38.6/test/fixture-render-json-metadata/terraform-remote-state/common/terraform.hcl --- old/terragrunt-0.38.5/test/fixture-render-json-metadata/terraform-remote-state/common/terraform.hcl 1970-01-01 01:00:00.000000000 +0100 +++ new/terragrunt-0.38.6/test/fixture-render-json-metadata/terraform-remote-state/common/terraform.hcl 2022-07-22 19:19:40.000000000 +0200 @@ -0,0 +1,4 @@ +terraform { + source = "../terraform" +} + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.38.5/test/integration_test.go new/terragrunt-0.38.6/test/integration_test.go --- old/terragrunt-0.38.5/test/integration_test.go 2022-07-13 15:59:36.000000000 +0200 +++ new/terragrunt-0.38.6/test/integration_test.go 2022-07-22 19:19:40.000000000 +0200 @@ -13,6 +13,7 @@ "os/exec" "path" "path/filepath" + "reflect" "regexp" "runtime" "sort" @@ -128,6 +129,7 @@ TEST_FIXTURE_DISJOINT = "fixture-stack/disjoint" TEST_FIXTURE_BROKEN_LOCALS = "fixture-broken-locals" TEST_FIXTURE_BROKEN_DEPENDENCY = "fixture-broken-dependency" + TEST_FIXTURE_RENDER_JSON_METADATA = "fixture-render-json-metadata" TERRAFORM_BINARY = "terraform" TERRAFORM_FOLDER = ".terraform" TERRAFORM_STATE = "terraform.tfstate" @@ -4543,3 +4545,408 @@ errout = string(stderr.Bytes()) assert.Equal(t, 1, strings.Count(errout, "Terraform has been successfully initialized!")) } + +func TestRenderJsonAttributesMetadata(t *testing.T) { + t.Parallel() + + tmpEnvPath := copyEnvironment(t, TEST_FIXTURE_RENDER_JSON_METADATA) + cleanupTerraformFolder(t, tmpEnvPath) + tmpDir := util.JoinPath(tmpEnvPath, TEST_FIXTURE_RENDER_JSON_METADATA, "attributes") + + terragruntHcl := util.JoinPath(tmpEnvPath, TEST_FIXTURE_RENDER_JSON_METADATA, "attributes", "terragrunt.hcl") + + var expectedMetadata = map[string]interface{}{ + "found_in_file": terragruntHcl, + } + + jsonOut := filepath.Join(tmpDir, "terragrunt_rendered.json") + + runTerragrunt(t, fmt.Sprintf("terragrunt render-json --with-metadata --terragrunt-non-interactive --terragrunt-log-level debug --terragrunt-working-dir %s --terragrunt-json-out %s", tmpDir, jsonOut)) + + jsonBytes, err := ioutil.ReadFile(jsonOut) + require.NoError(t, err) + + var renderedJson = map[string]interface{}{} + require.NoError(t, json.Unmarshal(jsonBytes, &renderedJson)) + + var inputs = renderedJson[config.MetadataInputs] + var expectedInputs = map[string]interface{}{ + "name": map[string]interface{}{ + "metadata": expectedMetadata, + "value": "us-east-1-bucket", + }, + "region": map[string]interface{}{ + "metadata": expectedMetadata, + "value": "us-east-1", + }, + } + assert.True(t, reflect.DeepEqual(expectedInputs, inputs)) + + var locals = renderedJson[config.MetadataLocals] + var expectedLocals = map[string]interface{}{ + "aws_region": map[string]interface{}{ + "metadata": expectedMetadata, + "value": "us-east-1", + }, + } + assert.True(t, reflect.DeepEqual(expectedLocals, locals)) + + var downloadDir = renderedJson[config.MetadataDownloadDir] + var expecteDownloadDir = map[string]interface{}{ + "metadata": expectedMetadata, + "value": "/tmp", + } + assert.True(t, reflect.DeepEqual(expecteDownloadDir, downloadDir)) + + var iamAssumeRoleDuration = renderedJson[config.MetadataIamAssumeRoleDuration] + expectedIamAssumeRoleDuration := map[string]interface{}{ + "metadata": expectedMetadata, + "value": float64(666), + } + assert.True(t, reflect.DeepEqual(expectedIamAssumeRoleDuration, iamAssumeRoleDuration)) + + var iamAssumeRoleName = renderedJson[config.MetadataIamAssumeRoleSessionName] + expectedIamAssumeRoleName := map[string]interface{}{ + "metadata": expectedMetadata, + "value": "qwe", + } + assert.True(t, reflect.DeepEqual(expectedIamAssumeRoleName, iamAssumeRoleName)) + + var iamRole = renderedJson[config.MetadataIamRole] + expectedIamRole := map[string]interface{}{ + "metadata": expectedMetadata, + "value": "arn:aws:iam::ACCOUNT_ID:role/ROLE_NAME", + } + assert.True(t, reflect.DeepEqual(expectedIamRole, iamRole)) + + var preventDestroy = renderedJson[config.MetadataPreventDestroy] + expectedPreventDestroy := map[string]interface{}{ + "metadata": expectedMetadata, + "value": true, + } + assert.True(t, reflect.DeepEqual(expectedPreventDestroy, preventDestroy)) + + var skip = renderedJson[config.MetadataSkip] + expectedSkip := map[string]interface{}{ + "metadata": expectedMetadata, + "value": true, + } + assert.True(t, reflect.DeepEqual(expectedSkip, skip)) + + var terraformBinary = renderedJson[config.MetadataTerraformBinary] + expectedTerraformBinary := map[string]interface{}{ + "metadata": expectedMetadata, + "value": "terraform", + } + assert.True(t, reflect.DeepEqual(expectedTerraformBinary, terraformBinary)) + + var terraformVersionConstraint = renderedJson[config.MetadataTerraformVersionConstraint] + expectedTerraformVersionConstraint := map[string]interface{}{ + "metadata": expectedMetadata, + "value": ">= 0.11", + } + assert.True(t, reflect.DeepEqual(expectedTerraformVersionConstraint, terraformVersionConstraint)) +} + +func TestRenderJsonMetadataDependencies(t *testing.T) { + t.Parallel() + + tmpEnvPath := copyEnvironment(t, TEST_FIXTURE_RENDER_JSON_METADATA) + cleanupTerraformFolder(t, tmpEnvPath) + tmpDir := util.JoinPath(tmpEnvPath, TEST_FIXTURE_RENDER_JSON_METADATA, "dependencies", "app") + + terragruntHcl := util.JoinPath(tmpEnvPath, TEST_FIXTURE_RENDER_JSON_METADATA, "dependencies", "app", "terragrunt.hcl") + includeHcl := util.JoinPath(tmpEnvPath, TEST_FIXTURE_RENDER_JSON_METADATA, "dependencies", "app", "include.hcl") + + var includeMetadata = map[string]interface{}{ + "found_in_file": includeHcl, + } + + var terragruntMetadata = map[string]interface{}{ + "found_in_file": terragruntHcl, + } + + jsonOut := filepath.Join(tmpDir, "terragrunt_rendered.json") + + runTerragrunt(t, fmt.Sprintf("terragrunt render-json --with-metadata --terragrunt-non-interactive --terragrunt-log-level debug --terragrunt-working-dir %s --terragrunt-json-out %s", tmpDir, jsonOut)) + + jsonBytes, err := ioutil.ReadFile(jsonOut) + require.NoError(t, err) + + var renderedJson = map[string]interface{}{} + require.NoError(t, json.Unmarshal(jsonBytes, &renderedJson)) + + var inputs = renderedJson[config.MetadataInputs] + var expectedInputs = map[string]interface{}{ + "test_input": map[string]interface{}{ + "metadata": includeMetadata, + "value": "test_value", + }, + } + assert.True(t, reflect.DeepEqual(expectedInputs, inputs)) + + var dependencies = renderedJson[config.MetadataDependencies] + var expectedDependencies = []interface{}{ + map[string]interface{}{ + "metadata": includeMetadata, + "value": "../dependency2", + }, + map[string]interface{}{ + "metadata": terragruntMetadata, + "value": "../dependency1", + }, + } + assert.True(t, reflect.DeepEqual(expectedDependencies, dependencies)) +} + +func TestRenderJsonMetadataIncludes(t *testing.T) { + t.Parallel() + + tmpEnvPath := copyEnvironment(t, TEST_FIXTURE_RENDER_JSON_METADATA) + cleanupTerraformFolder(t, tmpEnvPath) + tmpDir := util.JoinPath(tmpEnvPath, TEST_FIXTURE_RENDER_JSON_METADATA, "includes", "app") + + terragruntHcl := util.JoinPath(tmpEnvPath, TEST_FIXTURE_RENDER_JSON_METADATA, "includes", "app", "terragrunt.hcl") + localsHcl := util.JoinPath(tmpEnvPath, TEST_FIXTURE_RENDER_JSON_METADATA, "includes", "app", "locals.hcl") + inputHcl := util.JoinPath(tmpEnvPath, TEST_FIXTURE_RENDER_JSON_METADATA, "includes", "app", "inputs.hcl") + generateHcl := util.JoinPath(tmpEnvPath, TEST_FIXTURE_RENDER_JSON_METADATA, "includes", "app", "generate.hcl") + commonHcl := util.JoinPath(tmpEnvPath, TEST_FIXTURE_RENDER_JSON_METADATA, "includes", "common", "common.hcl") + + var terragruntMetadata = map[string]interface{}{ + "found_in_file": terragruntHcl, + } + var localsMetadata = map[string]interface{}{ + "found_in_file": localsHcl, + } + var inputMetadata = map[string]interface{}{ + "found_in_file": inputHcl, + } + var generateMetadata = map[string]interface{}{ + "found_in_file": generateHcl, + } + var commonMetadata = map[string]interface{}{ + "found_in_file": commonHcl, + } + + jsonOut := filepath.Join(tmpDir, "terragrunt_rendered.json") + + runTerragrunt(t, fmt.Sprintf("terragrunt render-json --with-metadata --terragrunt-non-interactive --terragrunt-log-level debug --terragrunt-working-dir %s --terragrunt-json-out %s", tmpDir, jsonOut)) + + jsonBytes, err := ioutil.ReadFile(jsonOut) + require.NoError(t, err) + + var renderedJson = map[string]interface{}{} + require.NoError(t, json.Unmarshal(jsonBytes, &renderedJson)) + + var inputs = renderedJson[config.MetadataInputs] + var expectedInputs = map[string]interface{}{ + "content": map[string]interface{}{ + "metadata": localsMetadata, + "value": "test", + }, + "qwe": map[string]interface{}{ + "metadata": inputMetadata, + "value": "123", + }, + } + assert.True(t, reflect.DeepEqual(expectedInputs, inputs)) + + var locals = renderedJson[config.MetadataLocals] + var expectedLocals = map[string]interface{}{ + "abc": map[string]interface{}{ + "metadata": terragruntMetadata, + "value": "xyz", + }, + } + assert.True(t, reflect.DeepEqual(expectedLocals, locals)) + + var generate = renderedJson[config.MetadataGenerateConfigs] + var expectedGenerate = map[string]interface{}{ + "provider": map[string]interface{}{ + "metadata": generateMetadata, + "value": map[string]interface{}{ + "comment_prefix": "# ", + "contents": "# test\n", + "disable_signature": false, + "if_exists": "overwrite", + "path": "provider.tf", + }, + }, + } + + // compare fields by serialization in json since map from "value" field is not deterministic + serializedGenerate, err := json.Marshal(generate) + assert.NoError(t, err) + + serializedExpectedGenerate, err := json.Marshal(expectedGenerate) + assert.NoError(t, err) + + assert.Equal(t, string(serializedExpectedGenerate), string(serializedGenerate)) + + var remoteState = renderedJson[config.MetadataRemoteState] + var expectedRemoteState = map[string]interface{}{ + "metadata": commonMetadata, + "value": map[string]interface{}{ + "backend": "s3", + "disable_dependency_optimization": false, + "disable_init": false, + "generate": nil, + "config": map[string]interface{}{ + "bucket": "mybucket", + "key": "path/to/my/key", + "region": "us-east-1", + }, + }, + } + + // compare fields by serialization in json since map from "value" field is not deterministic + serializedRemoteState, err := json.Marshal(remoteState) + assert.NoError(t, err) + + serializedExpectedRemoteState, err := json.Marshal(expectedRemoteState) + assert.NoError(t, err) + + assert.Equal(t, string(serializedExpectedRemoteState), string(serializedRemoteState)) +} + +func TestRenderJsonMetadataDepenency(t *testing.T) { + t.Parallel() + + tmpEnvPath := copyEnvironment(t, TEST_FIXTURE_RENDER_JSON_METADATA) + cleanupTerraformFolder(t, tmpEnvPath) + tmpDir := util.JoinPath(tmpEnvPath, TEST_FIXTURE_RENDER_JSON_METADATA, "dependency", "app") + + terragruntHcl := util.JoinPath(tmpEnvPath, TEST_FIXTURE_RENDER_JSON_METADATA, "dependency", "app", "terragrunt.hcl") + + var terragruntMetadata = map[string]interface{}{ + "found_in_file": terragruntHcl, + } + + jsonOut := filepath.Join(tmpDir, "terragrunt_rendered.json") + + runTerragrunt(t, fmt.Sprintf("terragrunt render-json --with-metadata --terragrunt-non-interactive --terragrunt-log-level debug --terragrunt-working-dir %s --terragrunt-json-out %s", tmpDir, jsonOut)) + + jsonBytes, err := ioutil.ReadFile(jsonOut) + require.NoError(t, err) + + var renderedJson = map[string]interface{}{} + require.NoError(t, json.Unmarshal(jsonBytes, &renderedJson)) + + var dependency = renderedJson[config.MetadataDependency] + + var expectedDependency = map[string]interface{}{ + "dep": map[string]interface{}{ + "metadata": terragruntMetadata, + "value": map[string]interface{}{ + "config_path": "../dependency", + "mock_outputs": map[string]interface{}{ + "test": "value", + }, + "mock_outputs_allowed_terraform_commands": nil, + "mock_outputs_merge_strategy_with_state": nil, + "mock_outputs_merge_with_state": nil, + "name": "dep", + "outputs": nil, + "skip": nil, + }, + }, + "dep2": map[string]interface{}{ + "metadata": terragruntMetadata, + "value": map[string]interface{}{ + "config_path": "../dependency2", + "mock_outputs": map[string]interface{}{ + "test2": "value2", + }, + "mock_outputs_allowed_terraform_commands": nil, + "mock_outputs_merge_strategy_with_state": nil, + "mock_outputs_merge_with_state": nil, + "name": "dep2", + "outputs": nil, + "skip": nil, + }, + }, + } + + // compare fields by serialization in json since map from "value" field is not deterministic + serializedDependency, err := json.Marshal(dependency) + assert.NoError(t, err) + + serializedExpectedDependency, err := json.Marshal(expectedDependency) + assert.NoError(t, err) + + assert.Equal(t, string(serializedExpectedDependency), string(serializedDependency)) +} + +func TestRenderJsonMetadataTerraform(t *testing.T) { + t.Parallel() + + tmpEnvPath := copyEnvironment(t, TEST_FIXTURE_RENDER_JSON_METADATA) + cleanupTerraformFolder(t, tmpEnvPath) + tmpDir := util.JoinPath(tmpEnvPath, TEST_FIXTURE_RENDER_JSON_METADATA, "terraform-remote-state", "app") + + commonHcl := util.JoinPath(tmpEnvPath, TEST_FIXTURE_RENDER_JSON_METADATA, "terraform-remote-state", "common", "terraform.hcl") + remoteStateHcl := util.JoinPath(tmpEnvPath, TEST_FIXTURE_RENDER_JSON_METADATA, "terraform-remote-state", "common", "remote_state.hcl") + var terragruntMetadata = map[string]interface{}{ + "found_in_file": commonHcl, + } + var remoteMetadata = map[string]interface{}{ + "found_in_file": remoteStateHcl, + } + + jsonOut := filepath.Join(tmpDir, "terragrunt_rendered.json") + + runTerragrunt(t, fmt.Sprintf("terragrunt render-json --with-metadata --terragrunt-non-interactive --terragrunt-log-level debug --terragrunt-working-dir %s --terragrunt-json-out %s", tmpDir, jsonOut)) + + jsonBytes, err := ioutil.ReadFile(jsonOut) + require.NoError(t, err) + + var renderedJson = map[string]interface{}{} + require.NoError(t, json.Unmarshal(jsonBytes, &renderedJson)) + + var terraform = renderedJson[config.MetadataTerraform] + var expectedTerraform = map[string]interface{}{ + "metadata": terragruntMetadata, + "value": map[string]interface{}{ + "after_hook": map[string]interface{}{}, + "before_hook": map[string]interface{}{}, + "error_hook": map[string]interface{}{}, + "extra_arguments": map[string]interface{}{}, + "include_in_copy": nil, + "source": "../terraform", + }, + } + + // compare fields by serialization in json since map from "value" field is not deterministic + serializedTerraform, err := json.Marshal(terraform) + assert.NoError(t, err) + + serializedExpectedTerraform, err := json.Marshal(expectedTerraform) + assert.NoError(t, err) + + assert.Equal(t, string(serializedExpectedTerraform), string(serializedTerraform)) + + var remoteState = renderedJson[config.MetadataRemoteState] + var expectedRemoteState = map[string]interface{}{ + "metadata": remoteMetadata, + "value": map[string]interface{}{ + "backend": "s3", + "config": map[string]interface{}{ + "bucket": "mybucket", + "key": "path/to/my/key", + "region": "us-east-1", + }, + "disable_dependency_optimization": false, + "disable_init": false, + "generate": nil, + }, + } + + // compare fields by serialization in json since map from "value" field is not deterministic + serializedRemoteState, err := json.Marshal(remoteState) + assert.NoError(t, err) + + serializedExpectedRemoteState, err := json.Marshal(expectedRemoteState) + assert.NoError(t, err) + + assert.Equal(t, string(serializedExpectedRemoteState), string(serializedRemoteState)) +} ++++++ vendor.tar.gz ++++++ /work/SRC/openSUSE:Factory/terragrunt/vendor.tar.gz /work/SRC/openSUSE:Factory/.terragrunt.new.1533/vendor.tar.gz differ: char 5, line 1