Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package terragrunt for openSUSE:Factory checked in at 2023-05-18 15:19:32 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/terragrunt (Old) and /work/SRC/openSUSE:Factory/.terragrunt.new.1533 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "terragrunt" Thu May 18 15:19:32 2023 rev:45 rq:1087699 version:0.45.13 Changes: -------- --- /work/SRC/openSUSE:Factory/terragrunt/terragrunt.changes 2023-05-11 12:34:15.150929042 +0200 +++ /work/SRC/openSUSE:Factory/.terragrunt.new.1533/terragrunt.changes 2023-05-18 15:19:39.881979001 +0200 @@ -1,0 +2,17 @@ +Wed May 17 17:42:37 UTC 2023 - ka...@b1-systems.de + +- Update to version 0.45.13: + * feat: add `timecmp` config function (#2571) + +------------------------------------------------------------------- +Wed May 17 17:38:30 UTC 2023 - ka...@b1-systems.de + +- Update to version 0.45.12: + * Handle provider lock file when fetching dependency outputs + (#2568) + * Update aws-auth.md (#2563) + * Add missing IAM Permissions s3:PutBucketOwnershipControls to + docs this is required now with TG versions starting from + v0.45.4 (#2562) + +------------------------------------------------------------------- Old: ---- terragrunt-0.45.11.obscpio New: ---- terragrunt-0.45.13.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ terragrunt.spec ++++++ --- /var/tmp/diff_new_pack.XMjAYy/_old 2023-05-18 15:19:41.757990504 +0200 +++ /var/tmp/diff_new_pack.XMjAYy/_new 2023-05-18 15:19:41.765990553 +0200 @@ -19,7 +19,7 @@ %define __arch_install_post export NO_BRP_STRIP_DEBUG=true Name: terragrunt -Version: 0.45.11 +Version: 0.45.13 Release: 0 Summary: Thin wrapper for Terraform for working with multiple Terraform modules License: MIT ++++++ _service ++++++ --- /var/tmp/diff_new_pack.XMjAYy/_old 2023-05-18 15:19:41.833990970 +0200 +++ /var/tmp/diff_new_pack.XMjAYy/_new 2023-05-18 15:19:41.837990994 +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.45.11</param> + <param name="revision">v0.45.13</param> <param name="versionformat">@PARENT_TAG@</param> <param name="changesgenerate">enable</param> <param name="versionrewrite-pattern">v(.*)</param> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.XMjAYy/_old 2023-05-18 15:19:41.865991166 +0200 +++ /var/tmp/diff_new_pack.XMjAYy/_new 2023-05-18 15:19:41.869991191 +0200 @@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/gruntwork-io/terragrunt</param> - <param name="changesrevision">fcfb391b5be91c67e9c0fb66ce41a4cc507c6c53</param></service></servicedata> + <param name="changesrevision">9015f781c2ffae79d8bace26e45ca20b86b99bbb</param></service></servicedata> (No newline at EOF) ++++++ terragrunt-0.45.11.obscpio -> terragrunt-0.45.13.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.45.11/cli/cli_app.go new/terragrunt-0.45.13/cli/cli_app.go --- old/terragrunt-0.45.11/cli/cli_app.go 2023-05-10 20:59:43.000000000 +0200 +++ new/terragrunt-0.45.13/cli/cli_app.go 2023-05-17 18:49:48.000000000 +0200 @@ -15,7 +15,6 @@ "github.com/gruntwork-io/gruntwork-cli/collections" "github.com/hashicorp/go-multierror" "github.com/mattn/go-zglob" - "github.com/sirupsen/logrus" "github.com/urfave/cli" "github.com/gruntwork-io/terragrunt/aws_helper" @@ -845,7 +844,7 @@ // case, we are using the user's working dir here, rather than just looking at the parent dir of the // terragrunt.hcl. However, the default value for the user's working dir, set in options.go, IS just the // parent dir of terragrunt.hcl, so these will likely always be the same. - lockFileError = copyLockFile(terragruntOptions.WorkingDir, originalTerragruntOptions.WorkingDir, terragruntOptions.Logger) + lockFileError = util.CopyLockFile(terragruntOptions.WorkingDir, originalTerragruntOptions.WorkingDir, terragruntOptions.Logger) } return multierror.Append(runTerraformError, lockFileError).ErrorOrNil() @@ -903,20 +902,6 @@ return false } -// Terraform 0.14 now generates a lock file when you run `terraform init`. -// If any such file exists, this function will copy the lock file to the destination folder -func copyLockFile(sourceFolder string, destinationFolder string, logger *logrus.Entry) error { - sourceLockFilePath := util.JoinPath(sourceFolder, util.TerraformLockFile) - destinationLockFilePath := util.JoinPath(destinationFolder, util.TerraformLockFile) - - if util.FileExists(sourceLockFilePath) { - logger.Debugf("Copying lock file from %s to %s", sourceLockFilePath, destinationFolder) - return util.CopyFile(sourceLockFilePath, destinationLockFilePath) - } - - return nil -} - // Run the given action function surrounded by hooks. That is, run the before hooks first, then, if there were no // errors, run the action, and finally, run the after hooks. Return any errors hit from the hooks or action. func runActionWithHooks(description string, terragruntOptions *options.TerragruntOptions, terragruntConfig *config.TerragruntConfig, action func() error) error { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.45.11/config/config_helpers.go new/terragrunt-0.45.13/config/config_helpers.go --- old/terragrunt-0.45.11/config/config_helpers.go 2023-05-10 20:59:43.000000000 +0200 +++ new/terragrunt-0.45.13/config/config_helpers.go 2023-05-17 18:49:48.000000000 +0200 @@ -147,6 +147,7 @@ terraformCompatibilityFunctions := map[string]function.Function{ "startswith": wrapStringSliceToBoolAsFuncImpl(startsWith, extensions.TrackInclude, terragruntOptions), "endswith": wrapStringSliceToBoolAsFuncImpl(endsWith, extensions.TrackInclude, terragruntOptions), + "timecmp": wrapStringSliceToNumberAsFuncImpl(timeCmp, extensions.TrackInclude, terragruntOptions), } functions := map[string]function.Function{} @@ -602,7 +603,6 @@ // source param in module's terragrunt.hcl: git::g...@github.com:acme/infrastructure-modules.git//networking/vpc?ref=v0.0.1 // // This method will return: /source/infrastructure-modules//networking/vpc -// func GetTerragruntSourceForModule(sourcePath string, modulePath string, moduleTerragruntConfig *TerragruntConfig) (string, error) { if sourcePath == "" || moduleTerragruntConfig.Terraform == nil || moduleTerragruntConfig.Terraform.Source == nil || *moduleTerragruntConfig.Terraform.Source == "" { return "", nil @@ -652,14 +652,12 @@ return matches[1], nil } -// // A cache of the results of a decrypt operation via sops. Each decryption // operation can take several seconds, so this cache speeds up terragrunt executions // where the same sops files are referenced multiple times. // // The cache keys are the canonical paths to the encrypted files, and the values are the // plain-text result of the decrypt operation. -// var sopsCache = NewStringCache() // decrypts and returns sops encrypted utf-8 yaml or json data as a string @@ -726,11 +724,11 @@ } // Return the selected include block based on a label passed in as a function param. Note that the assumption is that: -// - If the Original attribute is set, we are in the parent context so return that. -// - If there are no include blocks, no param is required and nil is returned. -// - If there is only one include block, no param is required and that is automatically returned. -// - If there is more than one include block, 1 param is required to use as the label name to lookup the include block -// to use. +// - If the Original attribute is set, we are in the parent context so return that. +// - If there are no include blocks, no param is required and nil is returned. +// - If there is only one include block, no param is required and that is automatically returned. +// - If there is more than one include block, 1 param is required to use as the label name to lookup the include block +// to use. func getSelectedIncludeBlock(trackInclude TrackInclude, params []string) (*IncludeConfig, error) { importMap := trackInclude.CurrentMap @@ -791,6 +789,32 @@ return false, nil } +// timeCmp implements Terraform's `timecmp` function that compares two timestamps. +func timeCmp(args []string, trackInclude *TrackInclude, terragruntOptions *options.TerragruntOptions) (int64, error) { + if len(args) != 2 { + return 0, errors.WithStackTrace(fmt.Errorf("function can take only two parameters: timestamp_a and timestamp_b")) + } + + tsA, err := util.ParseTimestamp(args[0]) + if err != nil { + return 0, errors.WithStackTrace(fmt.Errorf("could not parse first parameter %q: %w", args[0], err)) + } + tsB, err := util.ParseTimestamp(args[1]) + if err != nil { + return 0, errors.WithStackTrace(fmt.Errorf("could not parse second parameter %q: %w", args[1], err)) + } + + switch { + case tsA.Equal(tsB): + return 0, nil + case tsA.Before(tsB): + return -1, nil + default: + // By elimination, tsA must be after tsB. + return 1, nil + } +} + // Custom error types type WrongNumberOfParams struct { Func string diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.45.11/config/config_helpers_test.go new/terragrunt-0.45.13/config/config_helpers_test.go --- old/terragrunt-0.45.11/config/config_helpers_test.go 2023-05-10 20:59:43.000000000 +0200 +++ new/terragrunt-0.45.13/config/config_helpers_test.go 2023-05-17 18:49:48.000000000 +0200 @@ -1055,6 +1055,43 @@ } } +func TestTimeCmp(t *testing.T) { + t.Parallel() + + testCases := []struct { + config *options.TerragruntOptions + args []string + value int64 + err string + }{ + {terragruntOptionsForTest(t, ""), []string{"2017-11-22T00:00:00Z", "2017-11-22T00:00:00Z"}, 0, ""}, + {terragruntOptionsForTest(t, ""), []string{"2017-11-22T00:00:00Z", "2017-11-22T01:00:00+01:00"}, 0, ""}, + {terragruntOptionsForTest(t, ""), []string{"2017-11-22T00:00:01Z", "2017-11-22T01:00:00+01:00"}, 1, ""}, + {terragruntOptionsForTest(t, ""), []string{"2017-11-22T01:00:00Z", "2017-11-22T00:59:00-01:00"}, -1, ""}, + {terragruntOptionsForTest(t, ""), []string{"2017-11-22T01:00:00+01:00", "2017-11-22T01:00:00-01:00"}, -1, ""}, + {terragruntOptionsForTest(t, ""), []string{"2017-11-22T01:00:00-01:00", "2017-11-22T01:00:00+01:00"}, 1, ""}, + {terragruntOptionsForTest(t, ""), []string{"2017-11-22T00:00:00Z", "bloop"}, 0, `could not parse second parameter "bloop": not a valid RFC3339 timestamp: cannot use "bloop" as year`}, + {terragruntOptionsForTest(t, ""), []string{"2017-11-22 00:00:00Z", "2017-11-22T00:00:00Z"}, 0, `could not parse first parameter "2017-11-22 00:00:00Z": not a valid RFC3339 timestamp: missing required time introducer 'T'`}, + } + + for _, testCase := range testCases { + testCase := testCase + + t.Run(fmt.Sprintf("TimeCmp(%#v, %#v)", testCase.args[0], testCase.args[1]), func(t *testing.T) { + t.Parallel() + + actual, err := timeCmp(testCase.args, nil, testCase.config) + if testCase.err != "" { + assert.EqualError(t, err, testCase.err) + } else { + assert.NoError(t, err) + } + + assert.Equal(t, testCase.value, actual) + }) + } +} + func mockConfigWithSource(sourceUrl string) *TerragruntConfig { cfg := TerragruntConfig{IsPartial: true} cfg.Terraform = &TerraformConfig{Source: &sourceUrl} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.45.11/config/cty_helpers.go new/terragrunt-0.45.13/config/cty_helpers.go --- old/terragrunt-0.45.11/config/cty_helpers.go 2023-05-10 20:59:43.000000000 +0200 +++ new/terragrunt-0.45.13/config/cty_helpers.go 2023-05-17 18:49:48.000000000 +0200 @@ -38,6 +38,28 @@ }) } +func wrapStringSliceToNumberAsFuncImpl( + toWrap func(params []string, trackInclude *TrackInclude, terragruntOptions *options.TerragruntOptions) (int64, error), + trackInclude *TrackInclude, + terragruntOptions *options.TerragruntOptions, +) function.Function { + return function.New(&function.Spec{ + VarParam: &function.Parameter{Type: cty.String}, + Type: function.StaticReturnType(cty.Number), + Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { + params, err := ctySliceToStringSlice(args) + if err != nil { + return cty.StringVal(""), err + } + out, err := toWrap(params, trackInclude, terragruntOptions) + if err != nil { + return cty.NumberIntVal(0), err + } + return cty.NumberIntVal(out), nil + }, + }) +} + func wrapStringSliceToBoolAsFuncImpl( toWrap func(params []string, trackInclude *TrackInclude, terragruntOptions *options.TerragruntOptions) (bool, error), trackInclude *TrackInclude, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.45.11/config/dependency.go new/terragrunt-0.45.13/config/dependency.go --- old/terragrunt-0.45.11/config/dependency.go 2023-05-10 20:59:43.000000000 +0200 +++ new/terragrunt-0.45.13/config/dependency.go 2023-05-17 18:49:48.000000000 +0200 @@ -654,6 +654,7 @@ // To do this, this function will: // - Create a temporary folder // - Generate the backend.tf file with the backend configuration from the remote_state block +// - Copy the provider lock file, if there is one in the dependency's working directory // - Run terraform init and terraform output // - Clean up folder once json file is generated // NOTE: terragruntOptions should be in the context of the targetConfig already. @@ -713,6 +714,12 @@ } terragruntOptions.Logger.Debugf("Generated remote state configuration in working dir %s", tempWorkDir) + // Check for a provider lock file and copy it to the working dir if it exists. + terragruntDir := filepath.Dir(terragruntOptions.TerragruntConfigPath) + if err := util.CopyLockFile(terragruntDir, tempWorkDir, terragruntOptions.Logger); err != nil { + return nil, err + } + // The working directory is now set up to interact with the state, so pull it down to get the json output. // First run init to setup the backend configuration so that we can run output. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.45.11/docs/_docs/02_features/aws-auth.md new/terragrunt-0.45.13/docs/_docs/02_features/aws-auth.md --- old/terragrunt-0.45.11/docs/_docs/02_features/aws-auth.md 2023-05-10 20:59:43.000000000 +0200 +++ new/terragrunt-0.45.13/docs/_docs/02_features/aws-auth.md 2023-05-17 18:49:48.000000000 +0200 @@ -76,7 +76,8 @@ "s3:GetEncryptionConfiguration", "s3:GetBucketPolicy", "s3:GetBucketPublicAccessBlock", - "s3:PutLifecycleConfiguration" + "s3:PutLifecycleConfiguration", + "s3:PutBucketOwnershipControls" ], "Resource": "arn:aws:s3:::BUCKET_NAME" }, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.45.11/test/fixture-timecmp/main.tf new/terragrunt-0.45.13/test/fixture-timecmp/main.tf --- old/terragrunt-0.45.11/test/fixture-timecmp/main.tf 1970-01-01 01:00:00.000000000 +0100 +++ new/terragrunt-0.45.13/test/fixture-timecmp/main.tf 2023-05-17 18:49:48.000000000 +0200 @@ -0,0 +1,47 @@ +variable "timecmp1" { + type = number +} + +variable "timecmp2" { + type = number +} + +variable "timecmp3" { + type = number +} + +variable "timecmp4" { + type = number +} + +variable "timecmp5" { + type = number +} + +variable "timecmp6" { + type = number +} + +output "timecmp1" { + value = var.timecmp1 +} + +output "timecmp2" { + value = var.timecmp2 +} + +output "timecmp3" { + value = var.timecmp3 +} + +output "timecmp4" { + value = var.timecmp4 +} + +output "timecmp5" { + value = var.timecmp5 +} + +output "timecmp6" { + value = var.timecmp6 +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.45.11/test/fixture-timecmp/terragrunt.hcl new/terragrunt-0.45.13/test/fixture-timecmp/terragrunt.hcl --- old/terragrunt-0.45.11/test/fixture-timecmp/terragrunt.hcl 1970-01-01 01:00:00.000000000 +0100 +++ new/terragrunt-0.45.13/test/fixture-timecmp/terragrunt.hcl 2023-05-17 18:49:48.000000000 +0200 @@ -0,0 +1,8 @@ +inputs = { + timecmp1 = timecmp("2017-11-22T00:00:00Z", "2017-11-22T00:00:00Z") + timecmp2 = timecmp("2017-11-22T00:00:00Z", "2017-11-22T01:00:00+01:00") + timecmp3 = timecmp("2017-11-22T00:00:01Z", "2017-11-22T01:00:00+01:00") + timecmp4 = timecmp("2017-11-22T01:00:00Z", "2017-11-22T00:59:00-01:00") + timecmp5 = timecmp("2017-11-22T01:00:00+01:00", "2017-11-22T01:00:00-01:00") + timecmp6 = timecmp("2017-11-22T01:00:00-01:00", "2017-11-22T01:00:00+01:00") +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.45.11/test/fixture-timecmp-errors/invalid-timestamp/main.tf new/terragrunt-0.45.13/test/fixture-timecmp-errors/invalid-timestamp/main.tf --- old/terragrunt-0.45.11/test/fixture-timecmp-errors/invalid-timestamp/main.tf 1970-01-01 01:00:00.000000000 +0100 +++ new/terragrunt-0.45.13/test/fixture-timecmp-errors/invalid-timestamp/main.tf 2023-05-17 18:49:48.000000000 +0200 @@ -0,0 +1,7 @@ +variable "timecmp1" { + type = number +} + +output "timecmp1" { + value = var.timecmp1 +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.45.11/test/fixture-timecmp-errors/invalid-timestamp/terragrunt.hcl new/terragrunt-0.45.13/test/fixture-timecmp-errors/invalid-timestamp/terragrunt.hcl --- old/terragrunt-0.45.11/test/fixture-timecmp-errors/invalid-timestamp/terragrunt.hcl 1970-01-01 01:00:00.000000000 +0100 +++ new/terragrunt-0.45.13/test/fixture-timecmp-errors/invalid-timestamp/terragrunt.hcl 2023-05-17 18:49:48.000000000 +0200 @@ -0,0 +1,3 @@ +inputs = { + timecmp1 = timecmp("2017-11-22 00:00:00Z", "2017-11-22T01:00:00+01:00") +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.45.11/test/integration_test.go new/terragrunt-0.45.13/test/integration_test.go --- old/terragrunt-0.45.11/test/integration_test.go 2023-05-10 20:59:43.000000000 +0200 +++ new/terragrunt-0.45.13/test/integration_test.go 2023-05-17 18:49:48.000000000 +0200 @@ -134,6 +134,8 @@ TEST_FIXTURE_RENDER_JSON_METADATA = "fixture-render-json-metadata" TEST_FIXTURE_RENDER_JSON_MOCK_OUTPUTS = "fixture-render-json-mock-outputs" TEST_FIXTURE_STARTSWITH = "fixture-startswith" + TEST_FIXTURE_TIMECMP = "fixture-timecmp" + TEST_FIXTURE_TIMECMP_INVALID_TIMESTAMP = "fixture-timecmp-errors/invalid-timestamp" TEST_FIXTURE_ENDSWITH = "fixture-endswith" TEST_FIXTURE_TFLINT_NO_ISSUES_FOUND = "fixture-tflint/no-issues-found" TEST_FIXTURE_TFLINT_ISSUES_FOUND = "fixture-tflint/issues-found" @@ -5169,15 +5171,62 @@ require.NoError(t, json.Unmarshal([]byte(stdout.String()), &outputs)) - validateBoolOutput(t, outputs, "startswith1", true) - validateBoolOutput(t, outputs, "startswith2", false) - validateBoolOutput(t, outputs, "startswith3", true) - validateBoolOutput(t, outputs, "startswith4", false) - validateBoolOutput(t, outputs, "startswith5", true) - validateBoolOutput(t, outputs, "startswith6", false) - validateBoolOutput(t, outputs, "startswith7", true) - validateBoolOutput(t, outputs, "startswith8", false) - validateBoolOutput(t, outputs, "startswith9", false) + validateOutput(t, outputs, "startswith1", true) + validateOutput(t, outputs, "startswith2", false) + validateOutput(t, outputs, "startswith3", true) + validateOutput(t, outputs, "startswith4", false) + validateOutput(t, outputs, "startswith5", true) + validateOutput(t, outputs, "startswith6", false) + validateOutput(t, outputs, "startswith7", true) + validateOutput(t, outputs, "startswith8", false) + validateOutput(t, outputs, "startswith9", false) +} + +func TestTimeCmp(t *testing.T) { + t.Parallel() + + cleanupTerraformFolder(t, TEST_FIXTURE_TIMECMP) + tmpEnvPath := copyEnvironment(t, TEST_FIXTURE_TIMECMP) + rootPath := util.JoinPath(tmpEnvPath, TEST_FIXTURE_TIMECMP) + + runTerragrunt(t, fmt.Sprintf("terragrunt apply-all --terragrunt-non-interactive --terragrunt-working-dir %s", rootPath)) + + // verify expected outputs are not empty + stdout := bytes.Buffer{} + stderr := bytes.Buffer{} + + require.NoError( + t, + runTerragruntCommand(t, fmt.Sprintf("terragrunt output -no-color -json --terragrunt-non-interactive --terragrunt-working-dir %s", rootPath), &stdout, &stderr), + ) + + outputs := map[string]TerraformOutput{} + + require.NoError(t, json.Unmarshal([]byte(stdout.String()), &outputs)) + + validateOutput(t, outputs, "timecmp1", float64(0)) + validateOutput(t, outputs, "timecmp2", float64(0)) + validateOutput(t, outputs, "timecmp3", float64(1)) + validateOutput(t, outputs, "timecmp4", float64(-1)) + validateOutput(t, outputs, "timecmp5", float64(-1)) + validateOutput(t, outputs, "timecmp6", float64(1)) +} + +func TestTimeCmpInvalidTimestamp(t *testing.T) { + t.Parallel() + + cleanupTerraformFolder(t, TEST_FIXTURE_TIMECMP_INVALID_TIMESTAMP) + tmpEnvPath := copyEnvironment(t, TEST_FIXTURE_TIMECMP_INVALID_TIMESTAMP) + rootPath := util.JoinPath(tmpEnvPath, TEST_FIXTURE_TIMECMP_INVALID_TIMESTAMP) + + // verify expected outputs are not empty + stdout := bytes.Buffer{} + stderr := bytes.Buffer{} + + err := runTerragruntCommand(t, fmt.Sprintf("terragrunt apply --terragrunt-non-interactive --terragrunt-working-dir %s", rootPath), &stdout, &stderr) + + expectedError := `not a valid RFC3339 timestamp: missing required time introducer 'T'` + require.ErrorContains(t, err, expectedError) } func TestEndsWith(t *testing.T) { @@ -5202,15 +5251,15 @@ require.NoError(t, json.Unmarshal([]byte(stdout.String()), &outputs)) - validateBoolOutput(t, outputs, "endswith1", true) - validateBoolOutput(t, outputs, "endswith2", false) - validateBoolOutput(t, outputs, "endswith3", true) - validateBoolOutput(t, outputs, "endswith4", false) - validateBoolOutput(t, outputs, "endswith5", true) - validateBoolOutput(t, outputs, "endswith6", false) - validateBoolOutput(t, outputs, "endswith7", true) - validateBoolOutput(t, outputs, "endswith8", false) - validateBoolOutput(t, outputs, "endswith9", false) + validateOutput(t, outputs, "endswith1", true) + validateOutput(t, outputs, "endswith2", false) + validateOutput(t, outputs, "endswith3", true) + validateOutput(t, outputs, "endswith4", false) + validateOutput(t, outputs, "endswith5", true) + validateOutput(t, outputs, "endswith6", false) + validateOutput(t, outputs, "endswith7", true) + validateOutput(t, outputs, "endswith8", false) + validateOutput(t, outputs, "endswith9", false) } func TestMockOutputsMergeWithState(t *testing.T) { @@ -5319,7 +5368,7 @@ assert.Contains(t, explanation, "Check your credentials and permissions") } -func validateBoolOutput(t *testing.T, outputs map[string]TerraformOutput, key string, value bool) { +func validateOutput(t *testing.T, outputs map[string]TerraformOutput, key string, value interface{}) { t.Helper() output, hasPlatform := outputs[key] require.Truef(t, hasPlatform, "Expected output %s to be defined", key) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.45.11/util/datetime.go new/terragrunt-0.45.13/util/datetime.go --- old/terragrunt-0.45.11/util/datetime.go 1970-01-01 01:00:00.000000000 +0100 +++ new/terragrunt-0.45.13/util/datetime.go 2023-05-17 18:49:48.000000000 +0200 @@ -0,0 +1,67 @@ +package util + +import ( + "fmt" + "time" +) + +func ParseTimestamp(ts string) (time.Time, error) { + t, err := time.Parse(time.RFC3339, ts) + if err != nil { + switch err := err.(type) { + case *time.ParseError: + // If err is a time.ParseError then its string representation is not + // appropriate since it relies on details of Go's strange date format + // representation, which a caller of our functions is not expected + // to be familiar with. + // + // Therefore we do some light transformation to get a more suitable + // error that should make more sense to our callers. These are + // still not awesome error messages, but at least they refer to + // the timestamp portions by name rather than by Go's example + // values. + if err.LayoutElem == "" && err.ValueElem == "" && err.Message != "" { + // For some reason err.Message is populated with a ": " prefix + // by the time package. + return time.Time{}, fmt.Errorf("not a valid RFC3339 timestamp%s", err.Message) + } + var what string + switch err.LayoutElem { + case "2006": + what = "year" + case "01": + what = "month" + case "02": + what = "day of month" + case "15": + what = "hour" + case "04": + what = "minute" + case "05": + what = "second" + case "Z07:00": + what = "UTC offset" + case "T": + return time.Time{}, fmt.Errorf("not a valid RFC3339 timestamp: missing required time introducer 'T'") + case ":", "-": + if err.ValueElem == "" { + return time.Time{}, fmt.Errorf("not a valid RFC3339 timestamp: end of string where %q is expected", err.LayoutElem) + } else { + return time.Time{}, fmt.Errorf("not a valid RFC3339 timestamp: found %q where %q is expected", err.ValueElem, err.LayoutElem) + } + default: + // Should never get here, because time.RFC3339 includes only the + // above portions, but since that might change in future we'll + // be robust here. + what = "timestamp segment" + } + if err.ValueElem == "" { + return time.Time{}, fmt.Errorf("not a valid RFC3339 timestamp: end of string before %s", what) + } else { + return time.Time{}, fmt.Errorf("not a valid RFC3339 timestamp: cannot use %q as %s", err.ValueElem, what) + } + } + return time.Time{}, err + } + return t, nil +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.45.11/util/datetime_test.go new/terragrunt-0.45.13/util/datetime_test.go --- old/terragrunt-0.45.11/util/datetime_test.go 1970-01-01 01:00:00.000000000 +0100 +++ new/terragrunt-0.45.13/util/datetime_test.go 2023-05-17 18:49:48.000000000 +0200 @@ -0,0 +1,41 @@ +package util + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func TestParseTimestamp(t *testing.T) { + t.Parallel() + + testCases := []struct { + arg string + value time.Time + err string + }{ + {"2017-11-22T00:00:00Z", time.Date(2017, time.Month(11), 22, 0, 0, 0, 0, time.UTC), ""}, + {"2017-11-22T01:00:00+01:00", time.Date(2017, time.Month(11), 22, 1, 0, 0, 0, time.FixedZone("", 3600)), ""}, + {"bloop", time.Time{}, `not a valid RFC3339 timestamp: cannot use "bloop" as year`}, + {"2017-11-22 00:00:00Z", time.Time{}, `not a valid RFC3339 timestamp: missing required time introducer 'T'`}, + } + + for _, testCase := range testCases { + testCase := testCase + + t.Run(fmt.Sprintf("ParseTimestamp(%#v)", testCase.arg), func(t *testing.T) { + t.Parallel() + + actual, err := ParseTimestamp(testCase.arg) + if testCase.err != "" { + assert.EqualError(t, err, testCase.err) + } else { + assert.NoError(t, err) + } + + assert.Equal(t, testCase.value, actual) + }) + } +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.45.11/util/file.go new/terragrunt-0.45.13/util/file.go --- old/terragrunt-0.45.11/util/file.go 2023-05-10 20:59:43.000000000 +0200 +++ new/terragrunt-0.45.13/util/file.go 2023-05-17 18:49:48.000000000 +0200 @@ -14,6 +14,7 @@ "github.com/gruntwork-io/terragrunt/errors" "github.com/mattn/go-zglob" homedir "github.com/mitchellh/go-homedir" + "github.com/sirupsen/logrus" ) const TerraformLockFile = ".terraform.lock.hcl" @@ -511,3 +512,17 @@ func (err PathIsNotFile) Error() string { return fmt.Sprintf("%s is not a file", err.path) } + +// Terraform 0.14 now generates a lock file when you run `terraform init`. +// If any such file exists, this function will copy the lock file to the destination folder +func CopyLockFile(sourceFolder string, destinationFolder string, logger *logrus.Entry) error { + sourceLockFilePath := JoinPath(sourceFolder, TerraformLockFile) + destinationLockFilePath := JoinPath(destinationFolder, TerraformLockFile) + + if FileExists(sourceLockFilePath) { + logger.Debugf("Copying lock file from %s to %s", sourceLockFilePath, destinationFolder) + return CopyFile(sourceLockFilePath, destinationLockFilePath) + } + + return nil +} ++++++ terragrunt.obsinfo ++++++ --- /var/tmp/diff_new_pack.XMjAYy/_old 2023-05-18 15:19:42.645995950 +0200 +++ /var/tmp/diff_new_pack.XMjAYy/_new 2023-05-18 15:19:42.645995950 +0200 @@ -1,5 +1,5 @@ name: terragrunt -version: 0.45.11 -mtime: 1683745183 -commit: fcfb391b5be91c67e9c0fb66ce41a4cc507c6c53 +version: 0.45.13 +mtime: 1684342188 +commit: 9015f781c2ffae79d8bace26e45ca20b86b99bbb ++++++ 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