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-10-08 12:18:05 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/terragrunt (Old) and /work/SRC/openSUSE:Factory/.terragrunt.new.28202 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "terragrunt" Sun Oct 8 12:18:05 2023 rev:71 rq:1116083 version:0.52.0 Changes: -------- --- /work/SRC/openSUSE:Factory/terragrunt/terragrunt.changes 2023-10-05 20:04:35.777841263 +0200 +++ /work/SRC/openSUSE:Factory/.terragrunt.new.28202/terragrunt.changes 2023-10-08 12:21:13.032410781 +0200 @@ -1,0 +2,6 @@ +Fri Oct 06 13:17:52 UTC 2023 - ka...@b1-systems.de + +- Update to version 0.52.0: + * Add OpenTofu support (#2745) + +------------------------------------------------------------------- Old: ---- terragrunt-0.51.9.obscpio New: ---- terragrunt-0.52.0.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ terragrunt.spec ++++++ --- /var/tmp/diff_new_pack.wXXvA2/_old 2023-10-08 12:21:14.428460974 +0200 +++ /var/tmp/diff_new_pack.wXXvA2/_new 2023-10-08 12:21:14.428460974 +0200 @@ -19,7 +19,7 @@ %define __arch_install_post export NO_BRP_STRIP_DEBUG=true Name: terragrunt -Version: 0.51.9 +Version: 0.52.0 Release: 0 Summary: Thin wrapper for Terraform for working with multiple Terraform modules License: MIT ++++++ _service ++++++ --- /var/tmp/diff_new_pack.wXXvA2/_old 2023-10-08 12:21:14.472462556 +0200 +++ /var/tmp/diff_new_pack.wXXvA2/_new 2023-10-08 12:21:14.476462701 +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.51.9</param> + <param name="revision">v0.52.0</param> <param name="versionformat">@PARENT_TAG@</param> <param name="changesgenerate">enable</param> <param name="versionrewrite-pattern">v(.*)</param> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.wXXvA2/_old 2023-10-08 12:21:14.496463419 +0200 +++ /var/tmp/diff_new_pack.wXXvA2/_new 2023-10-08 12:21:14.500463564 +0200 @@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/gruntwork-io/terragrunt</param> - <param name="changesrevision">1a80dba8786bdca1e157530c153066e5cfdd4a52</param></service></servicedata> + <param name="changesrevision">70907d01effc98ac67b36cce37703336ca15a96f</param></service></servicedata> (No newline at EOF) ++++++ terragrunt-0.51.9.obscpio -> terragrunt-0.52.0.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.51.9/.circleci/config.yml new/terragrunt-0.52.0/.circleci/config.yml --- old/terragrunt-0.51.9/.circleci/config.yml 2023-10-04 20:33:53.000000000 +0200 +++ new/terragrunt-0.52.0/.circleci/config.yml 2023-10-06 09:09:15.000000000 +0200 @@ -13,6 +13,32 @@ docker: - image: 087285199408.dkr.ecr.us-east-1.amazonaws.com/circle-ci-test-image-base:go1.21-tf1.5-tg39.1-pck1.8-ci50.7 +install_tofu: &install_tofu + name: Install OpenTofu + command: | + pushd . + cd /tmp + curl -L "https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha1/tofu_1.6.0-alpha1_linux_amd64.zip" -o tofu.zip + unzip -o tofu.zip + sudo install -m 0755 tofu /usr/local/bin/tofu + rm -rf tofu + rm -rf tofu.zip + popd + tofu --version + +install_tflint: &install_tflint + name: Install Tflint + command: | + pushd . + cd /tmp + curl -L "https://github.com/terraform-linters/tflint/releases/download/v0.47.0/tflint_linux_amd64.zip" -o tflint.zip + unzip -o tflint.zip + sudo install -m 0755 tflint /usr/local/bin/tflint + rm -rf tflint + rm -rf tflint.zip + popd + tflint --version + version: 2.1 jobs: test_windows: @@ -30,11 +56,15 @@ shell: powershell.exe command: ./_ci/install-terraform.ps1 - run: + name: Install Opentofu + shell: powershell.exe + command: ./_ci/install-opentofu.ps1 + - run: name: Install TFLint shell: powershell.exe command: ./_ci/install-tflint.ps1 - run: - name: Run go tests + name: Run go terraform tests shell: powershell.exe no_output_timeout: 45m command: | @@ -42,6 +72,17 @@ # means of reproducing Terragrunt issues that only occur on that platform go test -v ./... -run TestWindowsTerragruntSourceMapDebug -timeout 45m go test -v ./... -run TestWindowsTflintIsInvoked -timeout 45m + - run: + name: Run go tofu tests + shell: powershell.exe + no_output_timeout: 45m + environment: + TERRAGRUNT_TFPATH: tofu + command: | + # We're running this test only on Windows currently to provide a convenient + # means of reproducing Terragrunt issues that only occur on that platform + go test -v ./... -run TestWindowsTerragruntSourceMapDebug -timeout 45m + go test -v ./... -run TestWindowsTflintIsInvoked -timeout 45m # We're running unit tests separately from integration tests - with no parallelization. # With heavy parallelization coupled with re-use of test fixtures we've witnessed slight # instability with the tests. The unit tests are fast to execute, so there is negligible @@ -74,24 +115,44 @@ path: logs - store_test_results: path: logs - integration_test: + + integration_test_terraform: resource_class: large <<: *defaults steps: - checkout - run: gruntwork-install --binary-name 'terratest_log_parser' --repo 'https://github.com/gruntwork-io/terratest' --tag 'v0.30.0' - # install tflint + - run: + <<: *install_tflint + + # Make GCP Service Account creds available as a file + - run: echo $GCLOUD_SERVICE_KEY > ${HOME}/gcloud-service-key.json + - run: echo 'export GOOGLE_APPLICATION_CREDENTIALS=${HOME}/gcloud-service-key.json' >> $BASH_ENV + # Import test / dev key for SOPS - run: command: | - pushd . - cd /tmp - curl -L "https://github.com/terraform-linters/tflint/releases/download/v0.47.0/tflint_linux_amd64.zip" -o tflint.zip - unzip -o tflint.zip - sudo install -m 0755 tflint /usr/local/bin/tflint - rm -rf tflint - rm -rf tflint.zip - popd - tflint --version + gpg --import --no-tty --batch --yes ./test/fixture-sops/test_pgp_key.asc + mkdir -p logs + run-go-tests --packages "$(go list ./... | grep /test | tr '\n' ' ')" | tee logs/integration.log + no_output_timeout: 30m + - run: + command: terratest_log_parser --testlog logs/integration.log --outputdir logs + when: always + - store_artifacts: + path: logs + - store_test_results: + path: logs + + integration_test_tofu: + resource_class: large + <<: *defaults + steps: + - checkout + - run: gruntwork-install --binary-name 'terratest_log_parser' --repo 'https://github.com/gruntwork-io/terratest' --tag 'v0.30.0' + - run: + <<: *install_tofu + - run: + <<: *install_tflint # Make GCP Service Account creds available as a file - run: echo $GCLOUD_SERVICE_KEY > ${HOME}/gcloud-service-key.json - run: echo 'export GOOGLE_APPLICATION_CREDENTIALS=${HOME}/gcloud-service-key.json' >> $BASH_ENV @@ -99,15 +160,44 @@ - run: command: | gpg --import --no-tty --batch --yes ./test/fixture-sops/test_pgp_key.asc + # remove terraform + sudo rm -f $(which terraform) mkdir -p logs run-go-tests --packages "$(go list ./... | grep /test | tr '\n' ' ')" | tee logs/integration.log no_output_timeout: 30m + environment: + # use tofu as wrapper + TERRAGRUNT_TFPATH: tofu - run: command: terratest_log_parser --testlog logs/integration.log --outputdir logs when: always + - store_artifacts: + path: logs + - store_test_results: + path: logs + + integration_test_tflint: + resource_class: large + <<: *defaults + steps: + - checkout + - run: gruntwork-install --binary-name 'terratest_log_parser' --repo 'https://github.com/gruntwork-io/terratest' --tag 'v0.30.0' + - run: + <<: *install_tofu + - run: + <<: *install_tflint + # Make GCP Service Account creds available as a file + - run: echo $GCLOUD_SERVICE_KEY > ${HOME}/gcloud-service-key.json + - run: echo 'export GOOGLE_APPLICATION_CREDENTIALS=${HOME}/gcloud-service-key.json' >> $BASH_ENV + # Import test / dev key for SOPS + - run: + command: | + gpg --import --no-tty --batch --yes ./test/fixture-sops/test_pgp_key.asc + no_output_timeout: 30m # Run TFLint tests separately as tflint during execution change working directory. - run: command: | + mkdir -p logs run-go-tests --packages "-tags tflint -run TestTflint ./test" | tee logs/integration.log no_output_timeout: 30m - run: @@ -117,6 +207,7 @@ path: logs - store_test_results: path: logs + build: resource_class: large <<: *defaults @@ -184,7 +275,25 @@ - GITHUB__PAT__gruntwork-ci - GCP__automated-tests - GITHUB__PAT__gruntwork-ci - - integration_test: + - integration_test_terraform: + filters: + tags: + only: /^v.*/ + context: + - AWS__PHXDEVOPS__circle-ci-test + - GITHUB__PAT__gruntwork-ci + - GCP__automated-tests + - GITHUB__PAT__gruntwork-ci + - integration_test_tofu: + filters: + tags: + only: /^v.*/ + context: + - AWS__PHXDEVOPS__circle-ci-test + - GITHUB__PAT__gruntwork-ci + - GCP__automated-tests + - GITHUB__PAT__gruntwork-ci + - integration_test_tflint: filters: tags: only: /^v.*/ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.51.9/_ci/install-opentofu.ps1 new/terragrunt-0.52.0/_ci/install-opentofu.ps1 --- old/terragrunt-0.51.9/_ci/install-opentofu.ps1 1970-01-01 01:00:00.000000000 +0100 +++ new/terragrunt-0.52.0/_ci/install-opentofu.ps1 2023-10-06 09:09:15.000000000 +0200 @@ -0,0 +1,29 @@ +OpenTofuInstallPath = "C:\Program Files\tofu\tofu.exe" +$OpenTofuTmpPath = "C:\OpenTofutmp" +$OpenTofuTmpBinaryPath = "C:\OpenTofutmp\tofu.exe" +$OpenTofuPath = "C:\Program Files\tofu" +# Remove any old OpenTofu installation, if present +if (Test-Path -Path $OpenTofuInstallPath) +{ + Remove-Item $OpenTofuInstallPath -Recurse +} +# Download OpenTofu and unpack it +$OpenTofuURI = "https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha1/tofu_1.6.0-alpha1_windows_amd64.zip" +$output = "tofu_1.6.0-alpha1_windows_amd64.zip" +$ProgressPreference = "SilentlyContinue" +Invoke-WebRequest -Uri $OpenTofuURI -OutFile $output +New-Item -ItemType "directory" -Path $OpenTofuTmpPath +# Unpack OpenTofu to temp directory +Expand-Archive -LiteralPath $output -DestinationPath $OpenTofuTmpPath +# Make new OpenTofu directory to hold binary +New-Item -ItemType "directory" -Path $OpenTofuPath +Move-Item $OpenTofuTmpBinaryPath $OpenTofuPath +# Add new OpenTofu path to system +$OldPath = [System.Environment]::GetEnvironmentVariable('PATH', "Machine") +$NewPath = "$OldPath;$OpenTofuPath" +[Environment]::SetEnvironmentVariable("PATH", "$NewPath", "Machine") +# Load System and User PATHs into latest $env:Path, which has the effect of "refreshing" the latest path +# in the current PowerShell session +$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") +# Verify installation +tofu version diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.51.9/cli/commands/terraform/action.go new/terragrunt-0.52.0/cli/commands/terraform/action.go --- old/terragrunt-0.51.9/cli/commands/terraform/action.go 2023-10-04 20:33:53.000000000 +0200 +++ new/terragrunt-0.52.0/cli/commands/terraform/action.go 2023-10-06 09:09:15.000000000 +0200 @@ -407,7 +407,7 @@ terragruntOptions.Logger.Infof("Encountered an error eligible for retrying. Sleeping %v before retrying.\n", terragruntOptions.RetrySleepIntervalSec) time.Sleep(terragruntOptions.RetrySleepIntervalSec) } else { - terragruntOptions.Logger.Errorf("Terraform invocation failed in %s", terragruntOptions.WorkingDir) + terragruntOptions.Logger.Errorf("%s invocation failed in %s", terragruntOptions.TerraformImplementation, terragruntOptions.WorkingDir) return tferr } } else { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.51.9/cli/commands/terraform/download_source.go new/terragrunt-0.52.0/cli/commands/terraform/download_source.go --- old/terragrunt-0.51.9/cli/commands/terraform/download_source.go 2023-10-04 20:33:53.000000000 +0200 +++ new/terragrunt-0.52.0/cli/commands/terraform/download_source.go 2023-10-06 09:09:15.000000000 +0200 @@ -78,7 +78,7 @@ if err := validateWorkingDir(terraformSource); err != nil { return err } - terragruntOptions.Logger.Debugf("Terraform files in %s are up to date. Will not download again.", terraformSource.WorkingDir) + terragruntOptions.Logger.Debugf("%s files in %s are up to date. Will not download again.", terragruntOptions.TerraformImplementation, terraformSource.WorkingDir) return nil } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.51.9/cli/commands/terraform/version_check.go new/terragrunt-0.52.0/cli/commands/terraform/version_check.go --- old/terragrunt-0.51.9/cli/commands/terraform/version_check.go 2023-10-04 20:33:53.000000000 +0200 +++ new/terragrunt-0.52.0/cli/commands/terraform/version_check.go 2023-10-06 09:09:15.000000000 +0200 @@ -22,7 +22,7 @@ // - Terraform v0.13.0-beta2 // - Terraform v0.12.27 // We only make sure the "v#.#.#" part is present in the output. -var TerraformVersionRegex = regexp.MustCompile(`Terraform (v?\d+\.\d+\.\d+).*`) +var TerraformVersionRegex = regexp.MustCompile(`^(.*?)\s(v?\d+\.\d+\.\d+).*`) // Check the version constraints of both terragrunt and terraform. Note that as a side effect this will set the // following settings on terragruntOptions: @@ -42,7 +42,7 @@ // Change the terraform binary path before checking the version // if the path is not changed from default and set in the config. - if terragruntOptions.TerraformPath == options.TerraformDefaultPath && partialTerragruntConfig.TerraformBinary != "" { + if terragruntOptions.TerraformPath == options.DefaultWrappedPath && partialTerragruntConfig.TerraformBinary != "" { terragruntOptions.TerraformPath = partialTerragruntConfig.TerraformBinary } if err := PopulateTerraformVersion(terragruntOptions); err != nil { @@ -92,8 +92,20 @@ return err } + tfImplementation, err := parseTerraformImplementationType(output.Stdout) + if err != nil { + return err + } + terragruntOptions.TerraformVersion = terraformVersion - terragruntOptions.Logger.Debugf("Terraform version: %s", terraformVersion) + terragruntOptions.TerraformImplementation = tfImplementation + + if tfImplementation == options.UnknownImpl { + terragruntOptions.TerraformImplementation = options.TerraformImpl + terragruntOptions.Logger.Warnf("Failed to identify Terraform implementation, fallback to terraform version: %s", terraformVersion) + } else { + terragruntOptions.Logger.Debugf("%s version: %s", tfImplementation, terraformVersion) + } return nil } @@ -141,11 +153,29 @@ func parseTerraformVersion(versionCommandOutput string) (*version.Version, error) { matches := TerraformVersionRegex.FindStringSubmatch(versionCommandOutput) - if len(matches) != 2 { + if len(matches) != 3 { return nil, errors.WithStackTrace(InvalidTerraformVersionSyntax(versionCommandOutput)) } - return version.NewVersion(matches[1]) + return version.NewVersion(matches[2]) +} + +// parseTerraformImplementationType - Parse terraform implementation from --version command output +func parseTerraformImplementationType(versionCommandOutput string) (options.TerraformImplementationType, error) { + matches := TerraformVersionRegex.FindStringSubmatch(versionCommandOutput) + + if len(matches) != 3 { + return options.UnknownImpl, errors.WithStackTrace(InvalidTerraformVersionSyntax(versionCommandOutput)) + } + rawType := strings.ToLower(matches[1]) + switch rawType { + case "terraform": + return options.TerraformImpl, nil + case "opentofu": + return options.OpenTofuImpl, nil + default: + return options.UnknownImpl, nil + } } // Custom error types diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.51.9/docs/_docs/01_getting-started/supported-terraform-versions.md new/terragrunt-0.52.0/docs/_docs/01_getting-started/supported-terraform-versions.md --- old/terragrunt-0.51.9/docs/_docs/01_getting-started/supported-terraform-versions.md 2023-10-04 20:33:53.000000000 +0200 +++ new/terragrunt-0.52.0/docs/_docs/01_getting-started/supported-terraform-versions.md 1970-01-01 01:00:00.000000000 +0100 @@ -1,38 +0,0 @@ ---- -layout: collection-browser-doc -title: Terraform Version Compatibility Table -category: getting-started -excerpt: Learn which Terraform versions are compatible with which versions of Terragrunt. -tags: ["install"] -order: 102 -nav_title: Documentation -nav_title_link: /docs/ ---- - -## Supported Terraform Versions - -The officially supported versions are: - -| Terraform Version | Terragrunt Version | -|-------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------| -| 1.5.x | >= [0.48.0](https://github.com/gruntwork-io/terragrunt/releases/tag/v0.48.0) | -| 1.4.x | >= [0.45.0](https://github.com/gruntwork-io/terragrunt/releases/tag/v0.45.0) | -| 1.3.x | >= [0.40.0](https://github.com/gruntwork-io/terragrunt/releases/tag/v0.40.0) | -| 1.2.x | >= [0.38.0](https://github.com/gruntwork-io/terragrunt/releases/tag/v0.38.0) | -| 1.1.x | >= [0.36.0](https://github.com/gruntwork-io/terragrunt/releases/tag/v0.36.0) | -| 1.0.x | >= [0.31.0](https://github.com/gruntwork-io/terragrunt/releases/tag/v0.31.0) | -| 0.15.x | >= [0.29.0](https://github.com/gruntwork-io/terragrunt/releases/tag/v0.29.0) | -| 0.14.x | >= [0.27.0](https://github.com/gruntwork-io/terragrunt/releases/tag/v0.27.0) | -| 0.13.x | >= [0.25.0](https://github.com/gruntwork-io/terragrunt/releases/tag/v0.25.0) | -| 0.12.x | [0.19.0](https://github.com/gruntwork-io/terragrunt/releases/tag/v0.19.0) - [0.24.4](https://github.com/gruntwork-io/terragrunt/releases/tag/v0.24.4) | -| 0.11.x | [0.14.0](https://github.com/gruntwork-io/terragrunt/releases/tag/v0.14.0) - [0.18.7](https://github.com/gruntwork-io/terragrunt/releases/tag/v0.18.7) | - - -However, note that these are the versions that are officially tested in the CI process. In practice, the version -compatibility is more relaxed than documented above. For example, we've found that Terraform 0.13 works with any version -above 0.19.0, and we've also found that terraform 0.11 works with any version above 0.19.18 as well. - -If you wish to use Terragrunt against an untested Terraform version, you can use the -[terraform_version_constraint](https://terragrunt.gruntwork.io/docs/reference/config-blocks-and-attributes/#terraform_version_constraint) -(introduced in Terragrunt [v0.19.18](https://github.com/gruntwork-io/terragrunt/releases/tag/v0.19.18)) attribute to -relax the version constraint. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.51.9/docs/_docs/01_getting-started/supported-versions.md new/terragrunt-0.52.0/docs/_docs/01_getting-started/supported-versions.md --- old/terragrunt-0.51.9/docs/_docs/01_getting-started/supported-versions.md 1970-01-01 01:00:00.000000000 +0100 +++ new/terragrunt-0.52.0/docs/_docs/01_getting-started/supported-versions.md 2023-10-06 09:09:15.000000000 +0200 @@ -0,0 +1,45 @@ +--- +layout: collection-browser-doc +title: Terraform and OpenTofu Version Compatibility Table +category: getting-started +excerpt: Learn which Terraform and OpenTofu versions are compatible with which versions of Terragrunt. +tags: ["install"] +order: 102 +nav_title: Documentation +nav_title_link: /docs/ +--- + +## Supported OpenTofu Versions + +The officially supported versions are: + +| OpenTofu Version | Terragrunt Version | +|------------------|------------------------------------------------------------------------------| +| 1.6.x | >= [0.52.0](https://github.com/gruntwork-io/terragrunt/releases/tag/v0.52.0) | + +## Supported Terraform Versions + +The officially supported versions are: + +| Terraform Version | Terragrunt Version | +|-------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------| +| 1.5.x | >= [0.48.0](https://github.com/gruntwork-io/terragrunt/releases/tag/v0.48.0) | +| 1.4.x | >= [0.45.0](https://github.com/gruntwork-io/terragrunt/releases/tag/v0.45.0) | +| 1.3.x | >= [0.40.0](https://github.com/gruntwork-io/terragrunt/releases/tag/v0.40.0) | +| 1.2.x | >= [0.38.0](https://github.com/gruntwork-io/terragrunt/releases/tag/v0.38.0) | +| 1.1.x | >= [0.36.0](https://github.com/gruntwork-io/terragrunt/releases/tag/v0.36.0) | +| 1.0.x | >= [0.31.0](https://github.com/gruntwork-io/terragrunt/releases/tag/v0.31.0) | +| 0.15.x | >= [0.29.0](https://github.com/gruntwork-io/terragrunt/releases/tag/v0.29.0) | +| 0.14.x | >= [0.27.0](https://github.com/gruntwork-io/terragrunt/releases/tag/v0.27.0) | +| 0.13.x | >= [0.25.0](https://github.com/gruntwork-io/terragrunt/releases/tag/v0.25.0) | +| 0.12.x | [0.19.0](https://github.com/gruntwork-io/terragrunt/releases/tag/v0.19.0) - [0.24.4](https://github.com/gruntwork-io/terragrunt/releases/tag/v0.24.4) | +| 0.11.x | [0.14.0](https://github.com/gruntwork-io/terragrunt/releases/tag/v0.14.0) - [0.18.7](https://github.com/gruntwork-io/terragrunt/releases/tag/v0.18.7) | + +However, note that these are the versions that are officially tested in the CI process. In practice, the version +compatibility is more relaxed than documented above. For example, we've found that Terraform 0.13 works with any version +above 0.19.0, and we've also found that terraform 0.11 works with any version above 0.19.18 as well. + +If you wish to use Terragrunt against an untested Terraform version, you can use the +[terraform_version_constraint](https://terragrunt.gruntwork.io/docs/reference/config-blocks-and-attributes/#terraform_version_constraint) +(introduced in Terragrunt [v0.19.18](https://github.com/gruntwork-io/terragrunt/releases/tag/v0.19.18)) attribute to +relax the version constraint. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.51.9/options/options.go new/terragrunt-0.52.0/options/options.go --- old/terragrunt-0.51.9/options/options.go 2023-10-04 20:33:53.000000000 +0200 +++ new/terragrunt-0.52.0/options/options.go 2023-10-06 09:09:15.000000000 +0200 @@ -27,6 +27,9 @@ // no limits on parallelism by default (limited by GOPROCS) DefaultParallelism = math.MaxInt32 + // TofuDefaultPath command to run tofu + TofuDefaultPath = "tofu" + // TerraformDefaultPath just takes terraform from the path TerraformDefaultPath = "terraform" @@ -40,8 +43,18 @@ const ContextKey ctxKey = iota +var DefaultWrappedPath = identifyDefaultWrappedExecutable() + type ctxKey byte +type TerraformImplementationType string + +const ( + TerraformImpl TerraformImplementationType = "terraform" + OpenTofuImpl TerraformImplementationType = "tofu" + UnknownImpl TerraformImplementationType = "unknown" +) + // TerragruntOptions represents options that configure the behavior of the Terragrunt program type TerragruntOptions struct { // Location of the Terragrunt config file @@ -70,6 +83,9 @@ // if you run `apply-all` (which is a terragrunt command), this variable will be set to `apply`. OriginalTerraformCommand string + // Terraform implementation tool (e.g. terraform, tofu) that terragrunt is wrapping + TerraformImplementation TerraformImplementationType + // Version of terraform (obtained by running 'terraform version') TerraformVersion *version.Version @@ -265,7 +281,7 @@ // Create a new TerragruntOptions object with reasonable defaults for real usage func NewTerragruntOptions() *TerragruntOptions { return &TerragruntOptions{ - TerraformPath: TerraformDefaultPath, + TerraformPath: DefaultWrappedPath, OriginalTerraformCommand: "", TerraformCommand: "", AutoInit: true, @@ -301,6 +317,7 @@ OutputPrefix: "", IncludeModulePrefix: false, JSONOut: DefaultJSONOutName, + TerraformImplementation: UnknownImpl, RunTerragrunt: func(opts *TerragruntOptions) error { return errors.WithStackTrace(RunTerragruntCommandNotSet) }, @@ -425,6 +442,7 @@ IncludeModulePrefix: opts.IncludeModulePrefix, FailIfBucketCreationRequired: opts.FailIfBucketCreationRequired, DisableBucketUpdate: opts.DisableBucketUpdate, + TerraformImplementation: opts.TerraformImplementation, } } @@ -502,6 +520,15 @@ return util.JoinPath(opts.WorkingDir, tfDataDir) } +// identifyDefaultWrappedExecutable - return default path used for wrapped executable +func identifyDefaultWrappedExecutable() string { + if util.IsCommandExecutable(TerraformDefaultPath, "-version") { + return TerraformDefaultPath + } + // fallback to Tofu if terraform is not available + return TofuDefaultPath +} + // Custom error types var RunTerragruntCommandNotSet = fmt.Errorf("The RunTerragrunt option has not been set on this TerragruntOptions object") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.51.9/test/fixture-download/custom-lock-file/.terraform.lock.hcl new/terragrunt-0.52.0/test/fixture-download/custom-lock-file/.terraform.lock.hcl --- old/terragrunt-0.51.9/test/fixture-download/custom-lock-file/.terraform.lock.hcl 2023-10-04 20:33:53.000000000 +0200 +++ new/terragrunt-0.52.0/test/fixture-download/custom-lock-file/.terraform.lock.hcl 2023-10-06 09:09:15.000000000 +0200 @@ -1,20 +1,20 @@ -# This file is maintained automatically by "terraform init". +# This file is maintained automatically by "tofu init". # Manual edits may be lost in future updates. -provider "registry.terraform.io/hashicorp/aws" { - version = "3.0.0" +provider "registry.opentofu.org/hashicorp/aws" { + version = "5.19.0" + constraints = "5.19.0" hashes = [ - "h1:ULKfwySvQ4pDhy027ryRhLxDhg640wsojYc+7NHMFBU=", - "h1:UyKRcHE2W3io32hVQD7s9Ovb9LSyTIvhAAPS9RX5vtg=", - "zh:25294510ae9c250502f2e37ac32b01017439735f098f82a1728772427626a2fd", - "zh:3b723e7772d47bd8cc11bea6e5d3e0b5e1df8398c0e7aaf510e3a8a54e0f1874", - "zh:4b7b73b86f4a0705d5d2a7f1d3ad3279706bdb3957a48f4a389c36918fba838e", - "zh:9e26cdc3be97e3001c253c0ca28c5c8ff2d5476373ca1beb849f3f3957ce7f1a", - "zh:9e73cf1304bf57968d3048d70c0b766d41497430a2a9a7a718a196f3a385106a", - "zh:a30b5b66facfbb2b02814e4cd33ca9899f9ade5bbf478f78c41d2fe789f0582a", - "zh:b06fb5da094db41cb5e430c95c988b73f32695e9f90f25499e926842dbd21b21", - "zh:c5a4ff607e9e9edee3fcd6d6666241fb532adf88ea1fe24f2aa1eb36845b3ca3", - "zh:df568a69087831c1780fac4395630a2cfb3cdf67b7dffbfe16bd78c64770bb75", - "zh:fce1b69dd673aace19508640b0b9b7eb1ef7e746d76cb846b49e7d52e0f5fb7e", + "h1:xoQFH3TCqCvdaBuqxChcPaooKWOuz3mHI3VKdgxnxEk=", + "zh:0c1887bd8efd1da9458ad6d8c59f33de21041d06db3a1d3fa8eae53404051943", + "zh:1c3604f15481eff8ccbbeb31b47acf11454a391c1247c7b23d4e3636f1ce4547", + "zh:3363e23fe87cb7b0fbbb5e6fc4ef58d2aff05ef5fdf17605e5fbd7e4ee91a312", + "zh:3cba361ff181877cb261762a8225a42c5d1053503cb53796b6277bfedeb1baf9", + "zh:7a9d7dfaa5878ab51c45d8b5b6bec74a42e12d755753efaee6b2075875d3afd0", + "zh:b160fd637ebf3ffb8ee3f4f17e8d51f50e176e26f7889464fd019d20dd045159", + "zh:b32b9da9dba98e5be8b9b110c5306e99f49e6608eb434e93211db5bc3a78412e", + "zh:b5b60196dd0ce47111fbe2792670a0aca4d8814d15c291d23f1cb29224fbd9a7", + "zh:bd349062b14435a8d8924b37208e51caa197617b7a5f2c26e488007c7c6f3298", + "zh:f574b9f4652b3d4209fe41f360868e2a90aebebff5f9000f94c507b520490f74", ] } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.51.9/test/fixture-download/custom-lock-file-module/main.tf new/terragrunt-0.52.0/test/fixture-download/custom-lock-file-module/main.tf --- old/terragrunt-0.51.9/test/fixture-download/custom-lock-file-module/main.tf 2023-10-04 20:33:53.000000000 +0200 +++ new/terragrunt-0.52.0/test/fixture-download/custom-lock-file-module/main.tf 2023-10-06 09:09:15.000000000 +0200 @@ -4,6 +4,15 @@ # when we run 'init'. If the lock file copying works as expected in the custom-lock-file test, then we'll end up # with an older version of the provider. If there is a bug, Terraform will end up downloading the latest version of # the provider, as we're not pinning the version in the Terraform code (only in the lock file). +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "5.19.0" + } + } +} + provider "aws" { region = "eu-west-1" } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.51.9/test/fixture-no-submodules/terragrunt.hcl new/terragrunt-0.52.0/test/fixture-no-submodules/terragrunt.hcl --- old/terragrunt-0.51.9/test/fixture-no-submodules/terragrunt.hcl 2023-10-04 20:33:53.000000000 +0200 +++ new/terragrunt-0.52.0/test/fixture-no-submodules/terragrunt.hcl 2023-10-06 09:09:15.000000000 +0200 @@ -1,3 +1,3 @@ terraform { - source = "git::g...@github.com:terraform-google-modules/terraform-google-folders.git?ref=v3.0.0" + source = "git::g...@github.com:terraform-google-modules/terraform-google-folders.git?ref=v4.0.0" } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.51.9/test/fixture-render-json-metadata/attributes/terragrunt.hcl new/terragrunt-0.52.0/test/fixture-render-json-metadata/attributes/terragrunt.hcl --- old/terragrunt-0.51.9/test/fixture-render-json-metadata/attributes/terragrunt.hcl 2023-10-04 20:33:53.000000000 +0200 +++ new/terragrunt-0.52.0/test/fixture-render-json-metadata/attributes/terragrunt.hcl 2023-10-06 09:09:15.000000000 +0200 @@ -15,7 +15,7 @@ iam_role = "arn:aws:iam::ACCOUNT_ID:role/ROLE_NAME" iam_assume_role_duration = 666 -terraform_binary = "terraform" +terraform_binary = get_env("TERRAGRUNT_TFPATH", "terraform") terraform_version_constraint = ">= 0.11" retryable_errors = [ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.51.9/test/integration_download_test.go new/terragrunt-0.52.0/test/integration_download_test.go --- old/terragrunt-0.51.9/test/integration_download_test.go 2023-10-04 20:33:53.000000000 +0200 +++ new/terragrunt-0.52.0/test/integration_download_test.go 2023-10-06 09:09:15.000000000 +0200 @@ -222,7 +222,7 @@ // In our lock file, we intentionally have hashes for an older version of the AWS provider. If the lock file // copying works, then Terraform will stick with this older version. If there is a bug, Terraform will end up // installing a newer version (since the version is not pinned in the .tf code, only in the lock file). - assert.Contains(t, string(readFile), `version = "3.0.0"`) + assert.Contains(t, string(readFile), `version = "5.19.0"`) } func TestExcludeDirs(t *testing.T) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.51.9/test/integration_test.go new/terragrunt-0.52.0/test/integration_test.go --- old/terragrunt-0.51.9/test/integration_test.go 2023-10-04 20:33:53.000000000 +0200 +++ new/terragrunt-0.52.0/test/integration_test.go 2023-10-06 09:09:15.000000000 +0200 @@ -174,6 +174,7 @@ TEST_FIXTURE_DISABLED_MODULE = "fixture-disabled/" TEST_FIXTURE_EMPTY_STATE = "fixture-empty-state/" TERRAFORM_BINARY = "terraform" + TOFU_BINARY = "tofu" TERRAFORM_FOLDER = ".terraform" TERRAFORM_STATE = "terraform.tfstate" TERRAFORM_STATE_BACKUP = "terraform.tfstate.backup" @@ -1337,22 +1338,22 @@ }{ { []string{"version"}, - "terraform version", + wrappedBinary() + " version", nil, }, { []string{"version", "foo"}, - "terraform version foo", + wrappedBinary() + " version foo", nil, }, { []string{"version", "foo", "bar", "baz"}, - "terraform version foo bar baz", + wrappedBinary() + " version foo bar baz", nil, }, { []string{"version", "foo", "bar", "baz", "foobar"}, - "terraform version foo bar baz foobar", + wrappedBinary() + " version foo bar baz foobar", nil, }, { @@ -1362,7 +1363,7 @@ }, { []string{"paln", "--terragrunt-disable-command-validation"}, - "Terraform invocation failed", // error caused by running terraform with the wrong command + wrappedBinary() + " invocation failed", // error caused by running terraform with the wrong command nil, }, } @@ -1397,19 +1398,19 @@ }{ { []string{"force-unlock"}, - "terraform force-unlock", + wrappedBinary() + " force-unlock", }, { []string{"force-unlock", "foo"}, - "terraform force-unlock foo", + wrappedBinary() + " force-unlock foo", }, { []string{"force-unlock", "foo", "bar", "baz"}, - "terraform force-unlock foo bar baz", + wrappedBinary() + " force-unlock foo bar baz", }, { []string{"force-unlock", "foo", "bar", "baz", "foobar"}, - "terraform force-unlock foo bar baz foobar", + wrappedBinary() + " force-unlock foo bar baz foobar", }, } @@ -1925,11 +1926,11 @@ logBufferContentsLineByLine(t, showStdout, "show stdout") var dat terragruntinfo.TerragruntInfoGroup - err_unmarshal := json.Unmarshal(showStdout.Bytes(), &dat) - assert.Nil(t, err_unmarshal) + errUnmarshal := json.Unmarshal(showStdout.Bytes(), &dat) + assert.Nil(t, errUnmarshal) assert.Equal(t, dat.DownloadDir, fmt.Sprintf("%s/%s", rootPath, TERRAGRUNT_CACHE)) - assert.Equal(t, dat.TerraformBinary, TERRAFORM_BINARY) + assert.Equal(t, dat.TerraformBinary, wrappedBinary()) assert.Equal(t, dat.IamRole, "") } @@ -1967,7 +1968,7 @@ // module has been destroyed. func TestDependencyOutputOptimization(t *testing.T) { expectOutputLogs := []string{ - `Running command: terraform init -get=false prefix=\[.*fixture-get-output/nested-optimization/dep\]`, + `Running command: ` + wrappedBinary() + ` init -get=false prefix=\[.*fixture-get-output/nested-optimization/dep\]`, } dependencyOutputOptimizationTest(t, "nested-optimization", true, expectOutputLogs) } @@ -1981,7 +1982,7 @@ func TestDependencyOutputOptimizationNoGenerate(t *testing.T) { expectOutputLogs := []string{ - `Running command: terraform init -get=false prefix=\[.*fixture-get-output/nested-optimization-nogen/dep\]`, + `Running command: ` + wrappedBinary() + ` init -get=false prefix=\[.*fixture-get-output/nested-optimization-nogen/dep\]`, } dependencyOutputOptimizationTest(t, "nested-optimization-nogen", true, expectOutputLogs) } @@ -3975,7 +3976,7 @@ output := stderr.String() assert.Error(t, err) - assert.Contains(t, output, "Terraform invocation failed in fixture-broken-dependency/dependency") + assert.Contains(t, output, wrappedBinary()+" invocation failed in fixture-broken-dependency/dependency") } func cleanupTerraformFolder(t *testing.T, templatesPath string) { @@ -4882,7 +4883,7 @@ err := runTerragruntCommand(t, fmt.Sprintf("terragrunt plan --terragrunt-non-interactive --terragrunt-working-dir %s", testPath), &stdout, &stderr) require.NoError(t, err) // providers initialization during first plan - assert.Equal(t, 1, strings.Count(stdout.String(), "Terraform has been successfully initialized!")) + assert.Equal(t, 1, strings.Count(stdout.String(), "has been successfully initialized!")) stdout = bytes.Buffer{} stderr = bytes.Buffer{} @@ -4891,7 +4892,7 @@ require.NoError(t, err) // no initialization expected for second plan run // https://github.com/gruntwork-io/terragrunt/issues/1921 - assert.Equal(t, 0, strings.Count(stdout.String(), "Terraform has been successfully initialized!")) + assert.Equal(t, 0, strings.Count(stdout.String(), "has been successfully initialized!")) } func TestAutoInitWhenSourceIsChanged(t *testing.T) { @@ -4915,7 +4916,7 @@ err = runTerragruntCommand(t, fmt.Sprintf("terragrunt plan --terragrunt-non-interactive --terragrunt-working-dir %s", testPath), &stdout, &stderr) require.NoError(t, err) // providers initialization during first plan - assert.Equal(t, 1, strings.Count(stdout.String(), "Terraform has been successfully initialized!")) + assert.Equal(t, 1, strings.Count(stdout.String(), "has been successfully initialized!")) updatedHcl = strings.Replace(contents, "__TAG_VALUE__", "v0.35.2", -1) require.NoError(t, os.WriteFile(terragruntHcl, []byte(updatedHcl), 0444)) @@ -4926,7 +4927,7 @@ err = runTerragruntCommand(t, fmt.Sprintf("terragrunt plan --terragrunt-non-interactive --terragrunt-working-dir %s", testPath), &stdout, &stderr) require.NoError(t, err) // auto initialization when source is changed - assert.Equal(t, 1, strings.Count(stdout.String(), "Terraform has been successfully initialized!")) + assert.Equal(t, 1, strings.Count(stdout.String(), "has been successfully initialized!")) } func TestNoColor(t *testing.T) { @@ -4942,7 +4943,7 @@ err := runTerragruntCommand(t, fmt.Sprintf("terragrunt plan -no-color --terragrunt-working-dir %s", testPath), &stdout, &stderr) require.NoError(t, err) // providers initialization during first plan - assert.Equal(t, 1, strings.Count(stdout.String(), "Terraform has been successfully initialized!")) + assert.Equal(t, 1, strings.Count(stdout.String(), "has been successfully initialized!")) assert.NotContains(t, stdout.String(), "[") } @@ -5037,7 +5038,7 @@ var terraformBinary = renderedJson[config.MetadataTerraformBinary] expectedTerraformBinary := map[string]interface{}{ "metadata": expectedMetadata, - "value": "terraform", + "value": wrappedBinary(), } assert.True(t, reflect.DeepEqual(expectedTerraformBinary, terraformBinary)) @@ -5830,8 +5831,8 @@ ) // verify that init was invoked - assert.Contains(t, stdout.String(), "Terraform has been successfully initialized!") - assert.Contains(t, stderr.String(), "Running command: terraform init") + assert.Contains(t, stdout.String(), "has been successfully initialized!") + assert.Contains(t, stderr.String(), "Running command: "+wrappedBinary()+" init") stdout = bytes.Buffer{} stderr = bytes.Buffer{} @@ -5842,8 +5843,8 @@ ) // verify that init wasn't invoked second time since cache directories are ignored - assert.NotContains(t, stdout.String(), "Terraform has been successfully initialized!") - assert.NotContains(t, stderr.String(), "Running command: terraform init") + assert.NotContains(t, stdout.String(), "has been successfully initialized!") + assert.NotContains(t, stderr.String(), "Running command: "+wrappedBinary()+" init") // verify that after adding new file, init is executed tfFile := util.JoinPath(tmpEnvPath, TEST_FIXTURE_INIT_CACHE, "app", "project.tf") @@ -5860,8 +5861,8 @@ ) // verify that init was invoked - assert.Contains(t, stdout.String(), "Terraform has been successfully initialized!") - assert.Contains(t, stderr.String(), "Running command: terraform init") + assert.Contains(t, stdout.String(), "has been successfully initialized!") + assert.Contains(t, stderr.String(), "Running command: "+wrappedBinary()+" init") } func TestRenderJsonWithInputsNotExistingOutput(t *testing.T) { @@ -6148,7 +6149,7 @@ jsonOut := filepath.Join(tmpDir, "terragrunt_rendered.json") runTerragrunt(t, fmt.Sprintf("terragrunt render-json --terragrunt-non-interactive --terragrunt-log-level debug --terragrunt-working-dir %s --terragrunt-json-out %s", tmpDir, jsonOut)) - jsonBytes, err := ioutil.ReadFile(jsonOut) + jsonBytes, err := os.ReadFile(jsonOut) require.NoError(t, err) var renderedJson = map[string]interface{}{} @@ -6170,7 +6171,7 @@ 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) + jsonBytes, err := os.ReadFile(jsonOut) require.NoError(t, err) var renderedJson = map[string]map[string]interface{}{} @@ -6189,3 +6190,12 @@ require.Truef(t, hasPlatform, "Expected output %s to be defined", key) require.Equalf(t, output.Value, value, "Expected output %s to be %t", key, value) } + +// wrappedBinary - return which binary will be wrapped by Terragrunt, useful in CICD to run same tests against tofu and terraform +func wrappedBinary() string { + value, found := os.LookupEnv("TERRAGRUNT_TFPATH") + if !found { + return TERRAFORM_BINARY + } + return value +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.51.9/util/shell.go new/terragrunt-0.52.0/util/shell.go --- old/terragrunt-0.51.9/util/shell.go 1970-01-01 01:00:00.000000000 +0100 +++ new/terragrunt-0.52.0/util/shell.go 2023-10-06 09:09:15.000000000 +0200 @@ -0,0 +1,19 @@ +package util + +import "os/exec" + +// IsCommandExecutable - returns true if a command can be executed without errors. +func IsCommandExecutable(command string, args ...string) bool { + cmd := exec.Command(command, args...) + cmd.Stdin = nil + cmd.Stdout = nil + cmd.Stderr = nil + + if err := cmd.Run(); err != nil { + if exitErr, ok := err.(*exec.ExitError); ok { + return exitErr.ExitCode() == 0 + } + return false + } + return true +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.51.9/util/shell_test.go new/terragrunt-0.52.0/util/shell_test.go --- old/terragrunt-0.51.9/util/shell_test.go 1970-01-01 01:00:00.000000000 +0100 +++ new/terragrunt-0.52.0/util/shell_test.go 2023-10-06 09:09:15.000000000 +0200 @@ -0,0 +1,19 @@ +package util + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestExistingCommand(t *testing.T) { + t.Parallel() + + assert.True(t, IsCommandExecutable("pwd")) +} + +func TestNotExistingCommand(t *testing.T) { + t.Parallel() + + assert.False(t, IsCommandExecutable("not-existing-command", "--version")) +} ++++++ terragrunt.obsinfo ++++++ --- /var/tmp/diff_new_pack.wXXvA2/_old 2023-10-08 12:21:15.284491752 +0200 +++ /var/tmp/diff_new_pack.wXXvA2/_new 2023-10-08 12:21:15.288491896 +0200 @@ -1,5 +1,5 @@ name: terragrunt -version: 0.51.9 -mtime: 1696444433 -commit: 1a80dba8786bdca1e157530c153066e5cfdd4a52 +version: 0.52.0 +mtime: 1696576155 +commit: 70907d01effc98ac67b36cce37703336ca15a96f ++++++ vendor.tar.gz ++++++ /work/SRC/openSUSE:Factory/terragrunt/vendor.tar.gz /work/SRC/openSUSE:Factory/.terragrunt.new.28202/vendor.tar.gz differ: char 5, line 1