Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package terragrunt for openSUSE:Factory checked in at 2025-11-13 17:28:20 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/terragrunt (Old) and /work/SRC/openSUSE:Factory/.terragrunt.new.2061 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "terragrunt" Thu Nov 13 17:28:20 2025 rev:272 rq:1317535 version:0.93.8 Changes: -------- --- /work/SRC/openSUSE:Factory/terragrunt/terragrunt.changes 2025-11-11 19:20:30.197378576 +0100 +++ /work/SRC/openSUSE:Factory/.terragrunt.new.2061/terragrunt.changes 2025-11-13 17:30:10.310251118 +0100 @@ -1,0 +2,59 @@ +Thu Nov 13 08:18:46 UTC 2025 - Johannes Kastl <[email protected]> + +- Update to version 0.93.8: + * Process Improvements + - Terragrunt static executables + Release pipeline now publishes statically linked executables + * What's Changed + - chore: static executables building (#5093) + - chore: Re-enable units reading with filter test (#5077) + - chore: updated installation steps (#5091) + +------------------------------------------------------------------- +Thu Nov 13 08:07:02 UTC 2025 - Johannes Kastl <[email protected]> + +- Update to version 0.93.7: + * fix(discovery): add OriginalTerragruntConfigPath to parse + options and test its functionality (#5090) + * chore: release scripts simplification (#5085) + +------------------------------------------------------------------- +Thu Nov 13 07:00:12 UTC 2025 - Johannes Kastl <[email protected]> + +- Update to version 0.93.6: + * Process Improvements + - Terragrunt release automation moved to GitHub Actions + The release automation for Terragrunt has moved to GitHub + Actions. With this move, Terragrunt releases now support: + - Windows binary signing + - Additional packaging for artifacts (.zip and .tar.gz + release artifacts) + You can still download standalone executables from release + assets for backward compatibility. + * Experiments Updated + - The filter-flag experiment now supports the source= attribute + The --filter flag can now be used to filter units by their + usage of particular OpenTofu/Terraform modules in their + terraform source blocks (remember that you must use the + filter-flag experiment to try this). + + # Filter by exact source match + terragrunt find --filter 'source=github.com/acme/foo' + terragrunt find --filter 'source=gitlab.com/example/baz' + terragrunt find --filter 'source=./module' + + # Filter by source using glob patterns + terragrunt find --filter 'source=*github.com**acme/*' + terragrunt find --filter 'source=git::[email protected]:acme/**' + terragrunt find --filter 'source=**github.com**' + terragrunt find --filter 'source=gitlab.com/**' + + For more information, see the filter feature documentation. + https://terragrunt.gruntwork.io/docs/features/filter/#source-based-filtering + * What's Changed + - docs: Documenting `--filter` for `source=` attribute (#5076) + - feat: Adding `--filter` `source=` support (#5075) + - chore: Github action release improvements (#5066) + - chore: Switching to mise for go install in tidy check (#5082) + +------------------------------------------------------------------- Old: ---- terragrunt-0.93.5.obscpio New: ---- terragrunt-0.93.8.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ terragrunt.spec ++++++ --- /var/tmp/diff_new_pack.l2zYA8/_old 2025-11-13 17:30:12.062325590 +0100 +++ /var/tmp/diff_new_pack.l2zYA8/_new 2025-11-13 17:30:12.062325590 +0100 @@ -17,7 +17,7 @@ Name: terragrunt -Version: 0.93.5 +Version: 0.93.8 Release: 0 Summary: Thin wrapper for Terraform for working with multiple Terraform modules License: MIT ++++++ _service ++++++ --- /var/tmp/diff_new_pack.l2zYA8/_old 2025-11-13 17:30:12.158329656 +0100 +++ /var/tmp/diff_new_pack.l2zYA8/_new 2025-11-13 17:30:12.162329826 +0100 @@ -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.93.5</param> + <param name="revision">v0.93.8</param> <param name="versionformat">@PARENT_TAG@</param> <param name="versionrewrite-pattern">v(.*)</param> <param name="changesgenerate">enable</param> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.l2zYA8/_old 2025-11-13 17:30:12.186330842 +0100 +++ /var/tmp/diff_new_pack.l2zYA8/_new 2025-11-13 17:30:12.190331012 +0100 @@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/gruntwork-io/terragrunt</param> - <param name="changesrevision">be923a80e54d611aee07c9183be6b0020f7813dd</param></service></servicedata> + <param name="changesrevision">3019e3bd2aeb122b449303af27fe5659fab74d4c</param></service></servicedata> (No newline at EOF) ++++++ terragrunt-0.93.5.obscpio -> terragrunt-0.93.8.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.93.5/.circleci/config.yml new/terragrunt-0.93.8/.circleci/config.yml --- old/terragrunt-0.93.5/.circleci/config.yml 2025-11-10 21:41:38.000000000 +0100 +++ new/terragrunt-0.93.8/.circleci/config.yml 1970-01-01 01:00:00.000000000 +0100 @@ -1,153 +0,0 @@ -orbs: - go: circleci/[email protected] - -# The "sign binary" rubs in a MacOS environment, so it's necessary to download GW's binaries -env: &env - environment: - GRUNTWORK_INSTALLER_VERSION: v0.0.39 - MODULE_CI_VERSION: v0.57.0 - TERRAFORM_VERSION: "1.11.3" - TFLINT_VERSION: "0.47.0" - -defaults: &defaults - docker: - - image: 087285199408.dkr.ecr.us-east-1.amazonaws.com/circle-ci-test-image-base:go1.25.0-tf1.5-tg58.8-pck1.8-ci58.2 - -version: 2.1 -jobs: - build: - resource_class: xlarge - <<: *defaults - steps: - - checkout - - run: build-go-binaries --app-name terragrunt --dest-path bin --ld-flags "-s -w -X github.com/gruntwork-io/go-commons/version.Version=$CIRCLE_TAG -extldflags '-static'" - - persist_to_workspace: - root: . - paths: [bin] - - test_signing: - <<: *env - macos: - xcode: 16.4.0 - resource_class: m4pro.medium - steps: - - checkout - - attach_workspace: - at: . - - go/install: - version: "1.25.3" - - run: - name: Install sign-binary-helpers - command: | - curl -Ls https://raw.githubusercontent.com/gruntwork-io/gruntwork-installer/v0.0.40/bootstrap-gruntwork-installer.sh | bash /dev/stdin --version "${GRUNTWORK_INSTALLER_VERSION}" - gruntwork-install --module-name "gruntwork-module-circleci-helpers" --repo "https://github.com/gruntwork-io/terraform-aws-ci" --tag "${MODULE_CI_VERSION}" - gruntwork-install --module-name "sign-binary-helpers" --repo "https://github.com/gruntwork-io/terraform-aws-ci" --tag "${MODULE_CI_VERSION}" - - run: - name: Compile and sign the binaries - command: | - export AC_PASSWORD=${MACOS_AC_PASSWORD} - export AC_PROVIDER=${MACOS_AC_PROVIDER} - - sign-binary --os mac --install-macos-sign-dependencies .gon_amd64.hcl - sign-binary --os mac .gon_arm64.hcl - echo "Done signing the binary" - - # Replace the files in bin. These are the same file names generated from .gon_amd64.hcl and .gon_arm64.hcl - unzip terragrunt_darwin_amd64.zip - mv terragrunt_darwin_amd64 bin/ - - unzip terragrunt_darwin_arm64.zip - mv terragrunt_darwin_arm64 bin/ - - codesign -dv --verbose=4 ./bin/terragrunt_darwin_amd64 - codesign -dv --verbose=4 ./bin/terragrunt_darwin_arm64 - - deploy: - <<: *env - macos: - xcode: 16.4.0 - resource_class: m4pro.medium - steps: - - checkout - - attach_workspace: - at: . - - go/install: - version: "1.25.3" - - run: - name: Install sign-binary-helpers - command: | - curl -Ls https://raw.githubusercontent.com/gruntwork-io/gruntwork-installer/v0.0.40/bootstrap-gruntwork-installer.sh | bash /dev/stdin --version "${GRUNTWORK_INSTALLER_VERSION}" - gruntwork-install --module-name "gruntwork-module-circleci-helpers" --repo "https://github.com/gruntwork-io/terraform-aws-ci" --tag "${MODULE_CI_VERSION}" - gruntwork-install --module-name "sign-binary-helpers" --repo "https://github.com/gruntwork-io/terraform-aws-ci" --tag "${MODULE_CI_VERSION}" - - run: - name: Compile and sign the binaries - command: | - export AC_PASSWORD=${MACOS_AC_PASSWORD} - export AC_PROVIDER=${MACOS_AC_PROVIDER} - - sign-binary --os mac --install-macos-sign-dependencies .gon_amd64.hcl - sign-binary --os mac .gon_arm64.hcl - echo "Done signing the binary" - - # Replace the files in bin. These are the same file names generated from .gon_amd64.hcl and .gon_arm64.hcl - unzip terragrunt_darwin_amd64.zip - mv terragrunt_darwin_amd64 bin/ - - unzip terragrunt_darwin_arm64.zip - mv terragrunt_darwin_arm64 bin/ - - run: - name: Run SHA256SUM - command: | - brew install coreutils - cd bin && sha256sum * > SHA256SUMS - - run: upload-github-release-assets bin/* - - run: - name: Verify that assets attached to the release - command: | - ./_ci/verify-release-assets.sh - -workflows: - version: 2 - build-and-test: - jobs: - - build: - filters: - tags: - only: - - /^v.*/ - - /^alpha.*/ - - /^beta.*/ - context: - - AWS__PHXDEVOPS__circle-ci-test - - GCP__automated-tests - - GITHUB__PAT__gruntwork-ci - - test_signing: - requires: - - build - filters: - tags: - only: - - /^v.*/ - - /^alpha.*/ - - /^beta.*/ - context: - - AWS__PHXDEVOPS__circle-ci-test - - GCP__automated-tests - - GITHUB__PAT__gruntwork-ci - - APPLE__OSX__code-signing - - deploy: - requires: - - build - filters: - tags: - only: - - /^v.*/ - - /^alpha.*/ - - /^beta.*/ - branches: - ignore: /.*/ - context: - - AWS__PHXDEVOPS__circle-ci-test - - GCP__automated-tests - - GITHUB__PAT__gruntwork-ci - - APPLE__OSX__code-signing diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.93.5/Makefile new/terragrunt-0.93.8/Makefile --- old/terragrunt-0.93.5/Makefile 2025-11-10 21:41:38.000000000 +0100 +++ new/terragrunt-0.93.8/Makefile 2025-11-12 20:11:44.000000000 +0100 @@ -27,13 +27,13 @@ # This build target just for convenience for those building directly from -# source. See also: .circleci/config.yml +# source. See also: .github/workflows/build.yml build: terragrunt terragrunt: $(shell find . \( -type d -name 'vendor' -prune \) \ -o \( -type f -name '*.go' -print \) ) set -xe ;\ vtag_maybe_extra=$$(git describe --tags --abbrev=12 --dirty --broken) ;\ - go build -o $@ -ldflags "-s -w -X github.com/gruntwork-io/go-commons/version.Version=$${vtag_maybe_extra} -extldflags '-static'" . + CGO_ENABLED=0 go build -o $@ -ldflags "-s -w -X github.com/gruntwork-io/go-commons/version.Version=$${vtag_maybe_extra}" . clean: rm -f terragrunt diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.93.5/config/include.go new/terragrunt-0.93.8/config/include.go --- old/terragrunt-0.93.5/config/include.go 2025-11-10 21:41:38.000000000 +0100 +++ new/terragrunt-0.93.8/config/include.go 2025-11-12 20:11:44.000000000 +0100 @@ -136,6 +136,8 @@ logPrefix string ) + trackFileRead(ctx.FilesRead, includeConfig.Path) + if isPartial { parsedIncludeConfig, err = partialParseIncludedConfig(ctx, l, &includeConfig) logPrefix = "[Partial] " diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.93.5/docs-starlight/src/components/InstallTab.astro new/terragrunt-0.93.8/docs-starlight/src/components/InstallTab.astro --- old/terragrunt-0.93.5/docs-starlight/src/components/InstallTab.astro 2025-11-10 21:41:38.000000000 +0100 +++ new/terragrunt-0.93.8/docs-starlight/src/components/InstallTab.astro 2025-11-12 20:11:44.000000000 +0100 @@ -21,7 +21,7 @@ Invoke-WebRequest -Uri "$baseUrl/$binaryName" -OutFile $binaryName -UseBasicParsing Invoke-WebRequest -Uri "$baseUrl/SHA256SUMS" -OutFile "SHA256SUMS" -UseBasicParsing $actualChecksum = (Get-FileHash -Algorithm SHA256 $binaryName).Hash.ToLower() - $expectedChecksum = (Get-Content "SHA256SUMS" | Select-String -Pattern $binaryName).Line.Split()[0].ToLower() + $expectedChecksum = (Get-Content "SHA256SUMS" | ForEach-Object { $parts = $_ -split '\s+'; if ($parts[1] -eq $binaryName) { return $parts[0].ToLower() } } | Select-Object -First 1) if ($actualChecksum -ne $expectedChecksum) { Write-Error "Checksum verification failed" exit 1 @@ -53,19 +53,19 @@ BINARY_NAME="terragrunt_\${OS}_\${ARCH}" # Download the binary -curl -sL "https://github.com/gruntwork-io/terragrunt/releases/download/$VERSION/$BINARY_NAME" -o "$BINARY_NAME" +curl -sL "https://github.com/gruntwork-io/terragrunt/releases/download/\$VERSION/\$BINARY_NAME" -o "\$BINARY_NAME" # Generate the checksum -CHECKSUM="$(${os == 'linux' ? 'sha256sum' : 'shasum -a 256'} "$BINARY_NAME" | awk '{print $1}')" +CHECKSUM="\$(${os == 'linux' ? 'sha256sum' : 'shasum -a 256'} "\$BINARY_NAME" | awk '{print \$1}')" # Download the checksum file -curl -sL "https://github.com/gruntwork-io/terragrunt/releases/download/$VERSION/SHA256SUMS" -o SHA256SUMS +curl -sL "https://github.com/gruntwork-io/terragrunt/releases/download/\$VERSION/SHA256SUMS" -o SHA256SUMS -# Grab the expected checksum -EXPECTED_CHECKSUM="$(grep "$BINARY_NAME" <SHA256SUMS | awk '{print $1}')" +# Grab the expected checksum (exact match on filename) +EXPECTED_CHECKSUM="\$(awk -v binary="\$BINARY_NAME" '\$2 == binary {print \$1; exit}' SHA256SUMS)" # Compare the checksums -if [ "$CHECKSUM" == "$EXPECTED_CHECKSUM" ]; then +if [ "\$CHECKSUM" == "\$EXPECTED_CHECKSUM" ]; then echo "Checksums match!" else echo "Checksums do not match!" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.93.5/docs-starlight/src/content/docs/03-features/18-filter.mdx new/terragrunt-0.93.8/docs-starlight/src/content/docs/03-features/18-filter.mdx --- old/terragrunt-0.93.5/docs-starlight/src/content/docs/03-features/18-filter.mdx 2025-11-10 21:41:38.000000000 +0100 +++ new/terragrunt-0.93.8/docs-starlight/src/content/docs/03-features/18-filter.mdx 2025-11-12 20:11:44.000000000 +0100 @@ -172,6 +172,43 @@ - terragrunt.hcl </FileTree> +### Source-Based Filtering + +Match units and stacks by their Terraform source URL or path specified in the `terraform` block of `terragrunt.hcl` files. + +```bash +# Filter by exact source match +terragrunt find --filter 'source=github.com/acme/foo' +terragrunt find --filter 'source=gitlab.com/example/baz' +terragrunt find --filter 'source=./module' + +# Filter by source using glob patterns +terragrunt find --filter 'source=*github.com**acme/*' +terragrunt find --filter 'source=git::[email protected]:acme/**' +terragrunt find --filter 'source=**github.com**' +terragrunt find --filter 'source=gitlab.com/**' +``` + +<FileTree> +- . + - **github-acme-foo** \<-- Matched by source=github.com/acme/foo and source=*github.com**acme/* + - terragrunt.hcl (source: github.com/acme/foo) + - **github-acme-bar** \<-- Matched by source=*github.com**acme/* and source=git::[email protected]:acme/** + - terragrunt.hcl (source: git::[email protected]:acme/bar) + - **gitlab-example-baz** \<-- Matched by source=gitlab.com/example/baz and source=gitlab.com/** + - terragrunt.hcl (source: gitlab.com/example/baz) + - **local-module** \<-- Matched by source=./module + - terragrunt.hcl (source: ./module) + - module + - main.tf + - other-unit + - terragrunt.hcl (source: s3://bucket/module) +</FileTree> + +<Aside type="note"> +The `source=` filter matches against the Terraform source URL or path specified in the `terraform` block of `terragrunt.hcl` files in units. It supports glob patterns, allowing you to match multiple sources with patterns like `*github.com**` or `gitlab.com/**`. This is useful for filtering units that use specific module sources, such as all units using a particular GitHub organization's modules or all local modules. This attribute may be supported on stacks in the future. +</Aside> + ### Negation Exclude units and stacks using the `!` prefix. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.93.5/internal/component/component.go new/terragrunt-0.93.8/internal/component/component.go --- old/terragrunt-0.93.5/internal/component/component.go 2025-11-10 21:41:38.000000000 +0100 +++ new/terragrunt-0.93.8/internal/component/component.go 2025-11-12 20:11:44.000000000 +0100 @@ -28,6 +28,7 @@ SetExternal() Reading() []string SetReading(...string) + Sources() []string DiscoveryContext() *DiscoveryContext SetDiscoveryContext(*DiscoveryContext) AddDependency(Component) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.93.5/internal/component/stack.go new/terragrunt-0.93.8/internal/component/stack.go --- old/terragrunt-0.93.5/internal/component/stack.go 2025-11-10 21:41:38.000000000 +0100 +++ new/terragrunt-0.93.8/internal/component/stack.go 2025-11-12 20:11:44.000000000 +0100 @@ -87,6 +87,13 @@ s.reading = files } +// Sources returns the list of sources for this component. +// +// Stacks don't support leveraging sources right now, so we just return an empty list. +func (s *Stack) Sources() []string { + return []string{} +} + // DiscoveryContext returns the discovery context for this component. func (s *Stack) DiscoveryContext() *DiscoveryContext { return s.discoveryContext diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.93.5/internal/component/unit.go new/terragrunt-0.93.8/internal/component/unit.go --- old/terragrunt-0.93.5/internal/component/unit.go 2025-11-10 21:41:38.000000000 +0100 +++ new/terragrunt-0.93.8/internal/component/unit.go 2025-11-12 20:11:44.000000000 +0100 @@ -92,6 +92,15 @@ u.reading = files } +// Sources returns the list of sources for this component. +func (u *Unit) Sources() []string { + if u.cfg == nil || u.cfg.Terraform == nil || u.cfg.Terraform.Source == nil { + return []string{} + } + + return []string{*u.cfg.Terraform.Source} +} + // DiscoveryContext returns the discovery context for this component. func (u *Unit) DiscoveryContext() *DiscoveryContext { return u.discoveryContext diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.93.5/internal/discovery/discovery.go new/terragrunt-0.93.8/internal/discovery/discovery.go --- old/terragrunt-0.93.5/internal/discovery/discovery.go 2025-11-10 21:41:38.000000000 +0100 +++ new/terragrunt-0.93.8/internal/discovery/discovery.go 2025-11-12 20:11:44.000000000 +0100 @@ -484,6 +484,7 @@ parseOpts.SkipOutput = true parseOpts.TerragruntConfigPath = filepath.Join(parseOpts.WorkingDir, configFilename) + parseOpts.OriginalTerragruntConfigPath = parseOpts.TerragruntConfigPath parsingCtx := config.NewParsingContext(ctx, l, parseOpts).WithDecodeList( config.TerraformSource, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.93.5/internal/discovery/discovery_test.go new/terragrunt-0.93.8/internal/discovery/discovery_test.go --- old/terragrunt-0.93.5/internal/discovery/discovery_test.go 2025-11-10 21:41:38.000000000 +0100 +++ new/terragrunt-0.93.8/internal/discovery/discovery_test.go 2025-11-12 20:11:44.000000000 +0100 @@ -715,6 +715,48 @@ } } +func TestDiscoveryOriginalTerragruntConfigPath(t *testing.T) { + t.Parallel() + + tmpDir := t.TempDir() + unitDir := filepath.Join(tmpDir, "unit") + require.NoError(t, os.MkdirAll(unitDir, 0755)) + + // Create a config that uses get_original_terragrunt_dir() in the terraform source + // This function relies on OriginalTerragruntConfigPath being set correctly + configPath := filepath.Join(unitDir, "terragrunt.hcl") + require.NoError(t, os.WriteFile(configPath, []byte(` +terraform { + source = "${get_original_terragrunt_dir()}/module" +} +`), 0644)) + + opts := options.NewTerragruntOptions() + opts.WorkingDir = tmpDir + opts.RootWorkingDir = tmpDir + // Start with a different config path to simulate the scenario where opts is cloned + opts.TerragruntConfigPath = tmpDir + opts.OriginalTerragruntConfigPath = tmpDir + + l := logger.CreateLogger() + + // Create a unit component with the directory + unit := component.NewUnit(unitDir) + + err := discovery.Parse(unit, t.Context(), l, opts, false, nil) + require.NoError(t, err) + + // Verify that the config was parsed correctly + require.NotNil(t, unit.Config()) + require.NotNil(t, unit.Config().Terraform) + require.NotNil(t, unit.Config().Terraform.Source) + + // The key test: verify that get_original_terragrunt_dir() returned the correct directory + expectedSource := filepath.Join(unitDir, "module") + require.Equal(t, expectedSource, *unit.Config().Terraform.Source, + "terraform source should use the correct unit directory from get_original_terragrunt_dir()") +} + func TestDependentDiscovery_NewDependentDiscovery(t *testing.T) { t.Parallel() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.93.5/internal/filter/ast.go new/terragrunt-0.93.8/internal/filter/ast.go --- old/terragrunt-0.93.5/internal/filter/ast.go 2025-11-10 21:41:38.000000000 +0100 +++ new/terragrunt-0.93.8/internal/filter/ast.go 2025-11-12 20:11:44.000000000 +0100 @@ -103,7 +103,7 @@ // supportsGlob returns true if the attribute filter supports glob patterns. func (a *AttributeFilter) supportsGlob() bool { - return a.Key == AttributeReading || a.Key == AttributeName + return a.Key == AttributeReading || a.Key == AttributeName || a.Key == AttributeSource } func (a *AttributeFilter) expressionNode() {} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.93.5/internal/filter/evaluator.go new/terragrunt-0.93.8/internal/filter/evaluator.go --- old/terragrunt-0.93.5/internal/filter/evaluator.go 2025-11-10 21:41:38.000000000 +0100 +++ new/terragrunt-0.93.8/internal/filter/evaluator.go 2025-11-12 20:11:44.000000000 +0100 @@ -2,6 +2,7 @@ import ( "path/filepath" + "slices" "github.com/gruntwork-io/terragrunt/internal/component" "github.com/gruntwork-io/terragrunt/pkg/log" @@ -12,6 +13,7 @@ AttributeType = "type" AttributeExternal = "external" AttributeReading = "reading" + AttributeSource = "source" AttributeTypeValueUnit = string(component.UnitKind) AttributeTypeValueStack = string(component.StackKind) @@ -148,6 +150,17 @@ } } } + case AttributeSource: + g, err := filter.CompileGlob() + if err != nil { + return nil, NewEvaluationErrorWithCause("failed to compile glob pattern for source filter: "+filter.Value, err) + } + + for _, c := range components { + if slices.ContainsFunc(c.Sources(), g.Match) { + result = append(result, c) + } + } default: return nil, NewEvaluationError("unknown attribute key: " + filter.Key) } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.93.5/internal/filter/evaluator_test.go new/terragrunt-0.93.8/internal/filter/evaluator_test.go --- old/terragrunt-0.93.5/internal/filter/evaluator_test.go 2025-11-10 21:41:38.000000000 +0100 +++ new/terragrunt-0.93.8/internal/filter/evaluator_test.go 2025-11-12 20:11:44.000000000 +0100 @@ -3,9 +3,11 @@ import ( "testing" + "github.com/gruntwork-io/terragrunt/config" "github.com/gruntwork-io/terragrunt/internal/component" "github.com/gruntwork-io/terragrunt/internal/filter" "github.com/gruntwork-io/terragrunt/pkg/log" + "github.com/gruntwork-io/terragrunt/test/helpers" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -260,6 +262,67 @@ require.NoError(t, err) assert.ElementsMatch(t, tt.expected, result) }) + } +} + +func TestEvaluate_AttributeFilter_Source(t *testing.T) { + t.Parallel() + + components := []component.Component{ + component.NewUnit("./apps/app1").WithConfig( + &config.TerragruntConfig{ + Terraform: &config.TerraformConfig{ + Source: helpers.PointerTo("github.com/acme/foo"), + }, + }, + ), + component.NewUnit("./apps/app2").WithConfig( + &config.TerragruntConfig{ + Terraform: &config.TerraformConfig{ + Source: helpers.PointerTo("git::[email protected]:acme/bar?ref=v1.0.0"), + }, + }, + ), + } + + tests := []struct { + name string + filter *filter.AttributeFilter + expected []component.Component + }{ + { + name: "glob pattern with single wildcard - github.com/acme/*", + filter: &filter.AttributeFilter{Key: "source", Value: "github.com/acme/*"}, + expected: []component.Component{ + components[0], + }, + }, + { + name: "glob pattern with double wildcard - git::[email protected]:acme/**", + filter: &filter.AttributeFilter{Key: "source", Value: "git::[email protected]:acme/**"}, + expected: []component.Component{ + components[1], + }, + }, + { + name: "glob pattern with double wildcard - **github.com**", + filter: &filter.AttributeFilter{Key: "source", Value: "**github.com**"}, + expected: []component.Component{ + components[0], + components[1], + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + l := log.New() + result, err := filter.Evaluate(l, tt.filter, components) + require.NoError(t, err) + assert.ElementsMatch(t, tt.expected, result) + }) } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.93.5/test/fixtures/filter-source/github-acme-bar/main.tf new/terragrunt-0.93.8/test/fixtures/filter-source/github-acme-bar/main.tf --- old/terragrunt-0.93.5/test/fixtures/filter-source/github-acme-bar/main.tf 1970-01-01 01:00:00.000000000 +0100 +++ new/terragrunt-0.93.8/test/fixtures/filter-source/github-acme-bar/main.tf 2025-11-12 20:11:44.000000000 +0100 @@ -0,0 +1,2 @@ +# Empty module + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.93.5/test/fixtures/filter-source/github-acme-bar/terragrunt.hcl new/terragrunt-0.93.8/test/fixtures/filter-source/github-acme-bar/terragrunt.hcl --- old/terragrunt-0.93.5/test/fixtures/filter-source/github-acme-bar/terragrunt.hcl 1970-01-01 01:00:00.000000000 +0100 +++ new/terragrunt-0.93.8/test/fixtures/filter-source/github-acme-bar/terragrunt.hcl 2025-11-12 20:11:44.000000000 +0100 @@ -0,0 +1,4 @@ +terraform { + source = "git::[email protected]:acme/bar?ref=v1.0.0" +} + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.93.5/test/fixtures/filter-source/github-acme-foo/main.tf new/terragrunt-0.93.8/test/fixtures/filter-source/github-acme-foo/main.tf --- old/terragrunt-0.93.5/test/fixtures/filter-source/github-acme-foo/main.tf 1970-01-01 01:00:00.000000000 +0100 +++ new/terragrunt-0.93.8/test/fixtures/filter-source/github-acme-foo/main.tf 2025-11-12 20:11:44.000000000 +0100 @@ -0,0 +1,2 @@ +# Empty module + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.93.5/test/fixtures/filter-source/github-acme-foo/terragrunt.hcl new/terragrunt-0.93.8/test/fixtures/filter-source/github-acme-foo/terragrunt.hcl --- old/terragrunt-0.93.5/test/fixtures/filter-source/github-acme-foo/terragrunt.hcl 1970-01-01 01:00:00.000000000 +0100 +++ new/terragrunt-0.93.8/test/fixtures/filter-source/github-acme-foo/terragrunt.hcl 2025-11-12 20:11:44.000000000 +0100 @@ -0,0 +1,4 @@ +terraform { + source = "github.com/acme/foo" +} + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.93.5/test/fixtures/filter-source/gitlab-example-baz/main.tf new/terragrunt-0.93.8/test/fixtures/filter-source/gitlab-example-baz/main.tf --- old/terragrunt-0.93.5/test/fixtures/filter-source/gitlab-example-baz/main.tf 1970-01-01 01:00:00.000000000 +0100 +++ new/terragrunt-0.93.8/test/fixtures/filter-source/gitlab-example-baz/main.tf 2025-11-12 20:11:44.000000000 +0100 @@ -0,0 +1,2 @@ +# Empty module + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.93.5/test/fixtures/filter-source/gitlab-example-baz/terragrunt.hcl new/terragrunt-0.93.8/test/fixtures/filter-source/gitlab-example-baz/terragrunt.hcl --- old/terragrunt-0.93.5/test/fixtures/filter-source/gitlab-example-baz/terragrunt.hcl 1970-01-01 01:00:00.000000000 +0100 +++ new/terragrunt-0.93.8/test/fixtures/filter-source/gitlab-example-baz/terragrunt.hcl 2025-11-12 20:11:44.000000000 +0100 @@ -0,0 +1,4 @@ +terraform { + source = "gitlab.com/example/baz" +} + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.93.5/test/fixtures/filter-source/local-module/module/main.tf new/terragrunt-0.93.8/test/fixtures/filter-source/local-module/module/main.tf --- old/terragrunt-0.93.5/test/fixtures/filter-source/local-module/module/main.tf 1970-01-01 01:00:00.000000000 +0100 +++ new/terragrunt-0.93.8/test/fixtures/filter-source/local-module/module/main.tf 2025-11-12 20:11:44.000000000 +0100 @@ -0,0 +1,2 @@ +# Empty module + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.93.5/test/fixtures/filter-source/local-module/terragrunt.hcl new/terragrunt-0.93.8/test/fixtures/filter-source/local-module/terragrunt.hcl --- old/terragrunt-0.93.5/test/fixtures/filter-source/local-module/terragrunt.hcl 1970-01-01 01:00:00.000000000 +0100 +++ new/terragrunt-0.93.8/test/fixtures/filter-source/local-module/terragrunt.hcl 2025-11-12 20:11:44.000000000 +0100 @@ -0,0 +1,4 @@ +terraform { + source = "./module" +} + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.93.5/test/helpers/test_helpers.go new/terragrunt-0.93.8/test/helpers/test_helpers.go --- old/terragrunt-0.93.5/test/helpers/test_helpers.go 2025-11-10 21:41:38.000000000 +0100 +++ new/terragrunt-0.93.8/test/helpers/test_helpers.go 2025-11-12 20:11:44.000000000 +0100 @@ -98,6 +98,12 @@ require.NoError(t, err) } +// PointerTo returns a pointer to the given parameter. +// Useful for constructing pointers to primitive types in test tables, etc. +func PointerTo[T any](v T) *T { + return &v +} + type testLogger struct { t *testing.T prefix string diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.93.5/test/integration_docs_test.go new/terragrunt-0.93.8/test/integration_docs_test.go --- old/terragrunt-0.93.5/test/integration_docs_test.go 2025-11-10 21:41:38.000000000 +0100 +++ new/terragrunt-0.93.8/test/integration_docs_test.go 2025-11-12 20:11:44.000000000 +0100 @@ -315,6 +315,7 @@ generateIntersectionFixture(t, tmpDir) generateReadingFixture(t, tmpDir) generateGraphBasedFixture(t, tmpDir) + generateSourceBasedFixture(t, tmpDir) testCases := []struct { name string @@ -512,6 +513,50 @@ filterQuery: "service... | !^db...", expectedOutput: "cache\ndb\nservice\n", }, + + // Source-based filtering + { + name: "source-exact-match-github", + fixtureDir: "source-based", + filterQuery: "source=github.com/acme/foo", + expectedOutput: "github-acme-foo\n", + }, + { + name: "source-exact-match-gitlab", + fixtureDir: "source-based", + filterQuery: "source=gitlab.com/example/baz", + expectedOutput: "gitlab-example-baz\n", + }, + { + name: "source-exact-match-local", + fixtureDir: "source-based", + filterQuery: "source=./module", + expectedOutput: "local-module\n", + }, + { + name: "source-glob-github-org", + fixtureDir: "source-based", + filterQuery: "source=*github.com**acme/*", + expectedOutput: "github-acme-bar\ngithub-acme-foo\n", + }, + { + name: "source-glob-github-ssh", + fixtureDir: "source-based", + filterQuery: "source=git::[email protected]:acme/**", + expectedOutput: "github-acme-bar\n", + }, + { + name: "source-glob-all-github", + fixtureDir: "source-based", + filterQuery: "source=**github.com**", + expectedOutput: "github-acme-bar\ngithub-acme-foo\n", + }, + { + name: "source-glob-gitlab", + fixtureDir: "source-based", + filterQuery: "source=gitlab.com/**", + expectedOutput: "gitlab-example-baz\n", + }, } // Run all test cases @@ -833,6 +878,59 @@ require.NoError(t, os.WriteFile(filepath.Join(serviceDir, "main.tf"), []byte(""), 0644)) } +func generateSourceBasedFixture(t *testing.T, baseDir string) { + rootDir := filepath.Join(baseDir, "source-based", "root") + require.NoError(t, os.MkdirAll(rootDir, 0755)) + + // Create github-acme-foo with source github.com/acme/foo + githubAcmeFooDir := filepath.Join(rootDir, "github-acme-foo") + require.NoError(t, os.MkdirAll(githubAcmeFooDir, 0755)) + require.NoError(t, os.WriteFile(filepath.Join(githubAcmeFooDir, "terragrunt.hcl"), []byte(`terraform { + source = "github.com/acme/foo" +} +`), 0644)) + require.NoError(t, os.WriteFile(filepath.Join(githubAcmeFooDir, "main.tf"), []byte(""), 0644)) + + // Create github-acme-bar with source git::[email protected]:acme/bar + githubAcmeBarDir := filepath.Join(rootDir, "github-acme-bar") + require.NoError(t, os.MkdirAll(githubAcmeBarDir, 0755)) + require.NoError(t, os.WriteFile(filepath.Join(githubAcmeBarDir, "terragrunt.hcl"), []byte(`terraform { + source = "git::[email protected]:acme/bar" +} +`), 0644)) + require.NoError(t, os.WriteFile(filepath.Join(githubAcmeBarDir, "main.tf"), []byte(""), 0644)) + + // Create gitlab-example-baz with source gitlab.com/example/baz + gitlabExampleBazDir := filepath.Join(rootDir, "gitlab-example-baz") + require.NoError(t, os.MkdirAll(gitlabExampleBazDir, 0755)) + require.NoError(t, os.WriteFile(filepath.Join(gitlabExampleBazDir, "terragrunt.hcl"), []byte(`terraform { + source = "gitlab.com/example/baz" +} +`), 0644)) + require.NoError(t, os.WriteFile(filepath.Join(gitlabExampleBazDir, "main.tf"), []byte(""), 0644)) + + // Create local-module with source ./module + localModuleDir := filepath.Join(rootDir, "local-module") + require.NoError(t, os.MkdirAll(localModuleDir, 0755)) + require.NoError(t, os.WriteFile(filepath.Join(localModuleDir, "terragrunt.hcl"), []byte(`terraform { + source = "./module" +} +`), 0644)) + // Create the module directory with main.tf + moduleDir := filepath.Join(localModuleDir, "module") + require.NoError(t, os.MkdirAll(moduleDir, 0755)) + require.NoError(t, os.WriteFile(filepath.Join(moduleDir, "main.tf"), []byte(""), 0644)) + + // Create other-unit with source s3://bucket/module (for non-matching examples) + otherUnitDir := filepath.Join(rootDir, "other-unit") + require.NoError(t, os.MkdirAll(otherUnitDir, 0755)) + require.NoError(t, os.WriteFile(filepath.Join(otherUnitDir, "terragrunt.hcl"), []byte(`terraform { + source = "s3://bucket/module" +} +`), 0644)) + require.NoError(t, os.WriteFile(filepath.Join(otherUnitDir, "main.tf"), []byte(""), 0644)) +} + // Helper functions to create Terragrunt configuration files func createTerragruntUnit(t *testing.T, dir string) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.93.5/test/integration_filter_test.go new/terragrunt-0.93.8/test/integration_filter_test.go --- old/terragrunt-0.93.5/test/integration_filter_test.go 2025-11-10 21:41:38.000000000 +0100 +++ new/terragrunt-0.93.8/test/integration_filter_test.go 2025-11-12 20:11:44.000000000 +0100 @@ -11,9 +11,10 @@ ) const ( - testFixtureFilterBasic = "fixtures/find/basic" - testFixtureFilterDAG = "fixtures/find/dag" - testFixtureFilterList = "fixtures/list/basic" + testFixtureFilterBasic = "fixtures/find/basic" + testFixtureFilterDAG = "fixtures/find/dag" + testFixtureFilterList = "fixtures/list/basic" + testFixtureFilterSource = "fixtures/filter-source" ) func TestFilterFlagWithFind(t *testing.T) { @@ -618,4 +619,107 @@ } }) } +} + +func TestFilterFlagWithSource(t *testing.T) { + t.Parallel() + + // Skip if filter-flag experiment is not enabled + if !helpers.IsExperimentMode(t) { + t.Skip("Skipping filter flag tests - TG_EXPERIMENT_MODE not enabled") + } + + workingDir, err := filepath.Abs(testFixtureFilterSource) + require.NoError(t, err) + + testCases := []struct { + name string + filterQuery string + expectedOutput string + expectError bool + }{ + { + name: "filter by source - exact match github.com/acme/foo", + filterQuery: "source=github.com/acme/foo", + expectedOutput: "github-acme-foo\n", + expectError: false, + }, + { + name: "filter by source - glob pattern *github.com**acme/*", + filterQuery: "source=*github.com**acme/*", + expectedOutput: "github-acme-foo\ngithub-acme-bar\n", + expectError: false, + }, + { + name: "filter by source - glob pattern git::[email protected]:acme/**", + filterQuery: "source=git::[email protected]:acme/**", + expectedOutput: "github-acme-bar\n", + expectError: false, + }, + { + name: "filter by source - glob pattern **github.com**", + filterQuery: "source=**github.com**", + expectedOutput: "github-acme-foo\ngithub-acme-bar\n", + expectError: false, + }, + { + name: "filter by source - exact match gitlab.com/example/baz", + filterQuery: "source=gitlab.com/example/baz", + expectedOutput: "gitlab-example-baz\n", + expectError: false, + }, + { + name: "filter by source - glob pattern gitlab.com/**", + filterQuery: "source=gitlab.com/**", + expectedOutput: "gitlab-example-baz\n", + expectError: false, + }, + { + name: "filter by source - local module", + filterQuery: "source=./module", + expectedOutput: "local-module\n", + expectError: false, + }, + { + name: "filter by source - non-matching query", + filterQuery: "source=nonexistent", + expectedOutput: "", + expectError: false, + }, + { + name: "filter by source with negation - exclude github.com/acme/foo", + filterQuery: "!source=github.com/acme/foo", + expectedOutput: "github-acme-bar\ngitlab-example-baz\nlocal-module\n", + expectError: false, + }, + { + name: "filter by source with intersection - github.com/acme/* and path", + filterQuery: "source=github.com/acme/* | ./github-acme-foo", + expectedOutput: "github-acme-foo\n", + expectError: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + + helpers.CleanupTerraformFolder(t, workingDir) + + cmd := "terragrunt find --no-color --working-dir " + workingDir + " --filter '" + tc.filterQuery + "'" + stdout, stderr, err := helpers.RunTerragruntCommandWithOutput(t, cmd) + + if tc.expectError { + require.Error(t, err, "Expected error for filter query: %s", tc.filterQuery) + assert.NotEmpty(t, stderr, "Expected error message in stderr") + } else { + require.NoError(t, err, "Unexpected error for filter query: %s", tc.filterQuery) + assert.Empty(t, stderr, "Unexpected error message in stderr") + // Sort both outputs for comparison since order may vary + expectedLines := strings.Fields(tc.expectedOutput) + actualLines := strings.Fields(stdout) + assert.ElementsMatch(t, expectedLines, actualLines, "Output mismatch for filter query: %s", tc.filterQuery) + } + }) + } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.93.5/test/integration_include_test.go new/terragrunt-0.93.8/test/integration_include_test.go --- old/terragrunt-0.93.5/test/integration_include_test.go 2025-11-10 21:41:38.000000000 +0100 +++ new/terragrunt-0.93.8/test/integration_include_test.go 2025-11-12 20:11:44.000000000 +0100 @@ -73,25 +73,39 @@ modulePath := util.JoinPath(rootPath, includeRunAllFixturePath) helpers.CleanupTerraformFolder(t, modulePath) - stdout := bytes.Buffer{} - stderr := bytes.Buffer{} - err := helpers.RunTerragruntCommand( + stdout, _, err := helpers.RunTerragruntCommandWithOutput( t, fmt.Sprintf( "terragrunt run --all plan --non-interactive --log-level trace --tf-forward-stdout --working-dir %s --units-that-include alpha.hcl", modulePath, ), - &stdout, - &stderr, ) require.NoError(t, err) - helpers.LogBufferContentsLineByLine(t, stdout, "stdout") - helpers.LogBufferContentsLineByLine(t, stderr, "stderr") + assert.Contains(t, stdout, "alpha") + assert.NotContains(t, stdout, "beta") + assert.NotContains(t, stdout, "charlie") +} + +func TestTerragruntRunAllModulesThatIncludeRestrictsSetWithFilter(t *testing.T) { + t.Parallel() + + if !helpers.IsExperimentMode(t) { + t.Skip("Skipping test - filter flag experiment is not enabled") + } + + rootPath := helpers.CopyEnvironment(t, includeRunAllFixturePath) + modulePath := util.JoinPath(rootPath, includeRunAllFixturePath) + helpers.CleanupTerraformFolder(t, modulePath) + + stdout, _, err := helpers.RunTerragruntCommandWithOutput( + t, + "terragrunt run --all plan --non-interactive --log-level trace --working-dir "+modulePath+" --filter 'reading=alpha.hcl'", + ) + require.NoError(t, err) - planOutput := stdout.String() - assert.Contains(t, planOutput, "alpha") - assert.NotContains(t, planOutput, "beta") - assert.NotContains(t, planOutput, "charlie") + assert.Contains(t, stdout, "alpha") + assert.NotContains(t, stdout, "beta") + assert.NotContains(t, stdout, "charlie") } func TestTerragruntRunAllModulesWithPrefix(t *testing.T) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.93.5/test/integration_units_reading_test.go new/terragrunt-0.93.8/test/integration_units_reading_test.go --- old/terragrunt-0.93.5/test/integration_units_reading_test.go 2025-11-10 21:41:38.000000000 +0100 +++ new/terragrunt-0.93.8/test/integration_units_reading_test.go 2025-11-12 20:11:44.000000000 +0100 @@ -312,11 +312,6 @@ t.Run(tc.name, func(t *testing.T) { t.Parallel() - if tc.name != "reading_from_hcl_with_include_and_exclude" { - t.Skip("Skipping test " + tc.name + " - not supported yet") - return - } - tmpEnvPath := helpers.CopyEnvironment(t, testFixtureUnitsReading) rootPath := util.JoinPath(tmpEnvPath, testFixtureUnitsReading) rootPath, err := filepath.EvalSymlinks(rootPath) ++++++ terragrunt.obsinfo ++++++ --- /var/tmp/diff_new_pack.l2zYA8/_old 2025-11-13 17:30:18.374592990 +0100 +++ /var/tmp/diff_new_pack.l2zYA8/_new 2025-11-13 17:30:18.382593329 +0100 @@ -1,5 +1,5 @@ name: terragrunt -version: 0.93.5 -mtime: 1762807298 -commit: be923a80e54d611aee07c9183be6b0020f7813dd +version: 0.93.8 +mtime: 1762974704 +commit: 3019e3bd2aeb122b449303af27fe5659fab74d4c ++++++ vendor.tar.gz ++++++ /work/SRC/openSUSE:Factory/terragrunt/vendor.tar.gz /work/SRC/openSUSE:Factory/.terragrunt.new.2061/vendor.tar.gz differ: char 13, line 1
