Skip to content

chore: Verify --queue-include-external isn't necessary when using the --filter flag#5216

Merged
yhakbar merged 1 commit intomainfrom
chore/verify-queue-include-external-is-unnecessary-with-filter
Dec 15, 2025
Merged

chore: Verify --queue-include-external isn't necessary when using the --filter flag#5216
yhakbar merged 1 commit intomainfrom
chore/verify-queue-include-external-is-unnecessary-with-filter

Conversation

@yhakbar
Copy link
Copy Markdown
Collaborator

@yhakbar yhakbar commented Dec 11, 2025

Description

Takes every test that uses --queue-include-external and ensures it's either not necessary or replacable with --filter '{./**}...'.

TODOs

Read the Gruntwork contribution guidelines.

  • I authored this code entirely myself
  • I am submitting code based on open source software (e.g. MIT, MPL-2.0, Apache)]
  • I am adding or upgrading a dependency or adapted code and confirm it has a compatible open source license
  • Update the docs.
  • Run the relevant tests successfully, including pre-commit checks.
  • Include release notes. If this PR is backward incompatible, include a migration guide.

Release Notes (draft)

Added / Removed / Updated [X].

Migration Guide

Summary by CodeRabbit

Tests

  • Added test coverage for filter functionality with external dependencies across multiple scenarios (DAG graphs, downloads, and includes)
  • Updated existing tests by removing deprecated command flags

✏️ Tip: You can customize this high-level summary in your review settings.

@vercel
Copy link
Copy Markdown

vercel bot commented Dec 11, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
terragrunt-docs Ready Ready Preview Comment Dec 12, 2025 6:19pm

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Dec 11, 2025

📝 Walkthrough

Walkthrough

Integration test updates across four test files: removal of the --queue-include-external flag from DAG graph and runner pool tests, and addition of three new test functions that validate --filter flag behavior with external dependencies, include-locals, and experiment mode gating.

Changes

Cohort / File(s) Summary
Flag removal from existing tests
test/integration_dag_test.go, test/integration_runner_pool_test.go
Removed --queue-include-external flag from DAG graph command tests and runner pool tests
New filter flag tests
test/integration_download_test.go, test/integration_include_test.go
Added TestTerragruntExternalDependenciesWithFilter and TestTerragruntWorksWithIncludeLocalsWithFilter to test --filter flag behavior with external dependencies and include-locals; include experiment mode gating
New DAG test for external dependencies
test/integration_dag_test.go
Added TestIncludeExternalInDagGraphCmdWithList to validate edge output in DAG graph with external dependencies included

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~15 minutes

  • Review focus areas:
    • Verify test setup/cleanup consistency with existing test patterns
    • Confirm experiment mode guards are correctly applied in new tests
    • Validate that --filter flag invocations and assertions match expected behavior
    • Ensure flag removals do not unintentionally alter test intent

Possibly related PRs

Suggested reviewers

  • denis256

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main purpose of the changeset: verifying whether --queue-include-external is necessary when using the --filter flag, which directly aligns with the test modifications throughout the PR.
Description check ✅ Passed The description provides a clear purpose and indicates TODOs are checked. However, the Release Notes section lacks substantive content (contains placeholder '[X]') and the Migration Guide is empty despite being marked as completed, which reduces clarity for downstream consumers.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch chore/verify-queue-include-external-is-unnecessary-with-filter

Comment @coderabbitai help to get the list of available commands and usage tips.

@yhakbar yhakbar force-pushed the chore/verify-queue-include-external-is-unnecessary-with-filter branch from 7488e4f to 0c6bc08 Compare December 12, 2025 17:49
@yhakbar yhakbar force-pushed the chore/verify-queue-include-external-is-unnecessary-with-filter branch from 0c6bc08 to b04fa2e Compare December 12, 2025 18:18
@yhakbar yhakbar marked this pull request as ready for review December 12, 2025 22:05
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
test/integration_dag_test.go (2)

36-41: Don’t discard stderr in graph test; it can hide regressions.

You’re currently ignoring stderr (stdout, _, err := ...). Consider asserting it’s empty (or at least does not contain level=error) to avoid passing tests with degraded output.

- stdout, _, err := helpers.RunTerragruntCommandWithOutput(t, cmd)
+ stdout, stderr, err := helpers.RunTerragruntCommandWithOutput(t, cmd)
  require.NoError(t, err)
+ assert.Empty(t, stderr)
  assert.Contains(t, stdout, "unit-a\" ->")

43-56: Same stderr visibility issue in new list-based test.

Given this is validating the replacement behavior for “include external” semantics, it’s worth asserting stderr is empty to avoid silently accepting warnings/errors.

- stdout, _, err := helpers.RunTerragruntCommandWithOutput(t, cmd)
+ stdout, stderr, err := helpers.RunTerragruntCommandWithOutput(t, cmd)
  require.NoError(t, err)
+ assert.Empty(t, stderr)
  assert.Contains(t, stdout, "unit-a\" ->")
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 480ef76 and b04fa2e.

📒 Files selected for processing (4)
  • test/integration_dag_test.go (1 hunks)
  • test/integration_download_test.go (1 hunks)
  • test/integration_include_test.go (1 hunks)
  • test/integration_runner_pool_test.go (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.go

⚙️ CodeRabbit configuration file

Review the Go code for quality and correctness. Make sure that the Go code follows best practices, is performant, and is easy to understand and maintain.

Files:

  • test/integration_download_test.go
  • test/integration_dag_test.go
  • test/integration_include_test.go
  • test/integration_runner_pool_test.go
🧠 Learnings (2)
📚 Learning: 2025-08-19T16:05:54.723Z
Learnt from: Resonance1584
Repo: gruntwork-io/terragrunt PR: 4683
File: go.mod:86-90
Timestamp: 2025-08-19T16:05:54.723Z
Learning: When analyzing Go module dependencies for removal, always check for both direct imports and API usage across all Go files in the repository, not just a quick search. The github.com/mattn/go-zglob library is used for filesystem walking and glob expansion in multiple Terragrunt files including util/file.go, format commands, and AWS provider patch functionality.

Applied to files:

  • test/integration_download_test.go
📚 Learning: 2025-11-03T04:40:01.000Z
Learnt from: ThisGuyCodes
Repo: gruntwork-io/terragrunt PR: 5041
File: test/fixtures/hclvalidate/valid/duplicate-attributes-in-required-providers/main.tf:2-7
Timestamp: 2025-11-03T04:40:01.000Z
Learning: In the terragrunt repository, test fixtures under test/fixtures/hclvalidate/valid/ are intentionally testing that INPUT validation succeeds even when Terraform code contains syntax errors or other issues unrelated to input validation (e.g., duplicate attributes, circular references, invalid locals). The "valid" designation means "valid for input validation purposes" not "syntactically valid Terraform/OpenTofu code".

Applied to files:

  • test/integration_runner_pool_test.go
🧬 Code graph analysis (4)
test/integration_download_test.go (3)
test/helpers/test_helpers.go (1)
  • IsExperimentMode (138-144)
test/helpers/package.go (4)
  • CleanupTerraformFolder (882-889)
  • CopyEnvironment (89-105)
  • RunTerragruntCommand (965-969)
  • LogBufferContentsLineByLine (985-993)
util/file.go (1)
  • JoinPath (626-628)
test/integration_dag_test.go (2)
test/helpers/package.go (2)
  • RunTerragruntCommandWithOutput (1007-1011)
  • CleanupTerraformFolder (882-889)
internal/errors/export.go (1)
  • Join (17-19)
test/integration_include_test.go (3)
test/helpers/test_helpers.go (1)
  • IsExperimentMode (138-144)
test/helpers/package.go (3)
  • CleanupTerraformFolder (882-889)
  • CopyEnvironment (89-105)
  • TerraformOutput (83-87)
util/file.go (1)
  • JoinPath (626-628)
test/integration_runner_pool_test.go (1)
test/helpers/package.go (1)
  • RunTerragruntCommandWithOutput (1007-1011)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: base_tests / Test (ubuntu)
  • GitHub Check: Pull Request has non-contributor approval
🔇 Additional comments (1)
test/integration_runner_pool_test.go (1)

105-108: Good change; consider also asserting stderr is otherwise clean (optional).

Removing --queue-include-external here matches the PR objective, and the existing require.NotContains checks keep the test focused. If you’ve seen intermittent warnings/noise, consider also assert.NotContains for other known bad substrings or assert.Empty when appropriate.

Comment on lines +740 to +779
func TestTerragruntExternalDependenciesWithFilter(t *testing.T) {
t.Parallel()

if !helpers.IsExperimentMode(t) {
t.Skip("Skipping filter flag tests - TG_EXPERIMENT_MODE not enabled")
}

modules := []string{
"module-a",
"module-b",
}

helpers.CleanupTerraformFolder(t, testFixtureExternalDependence)

for _, module := range modules {
helpers.CleanupTerraformFolder(t, util.JoinPath(testFixtureExternalDependence, module))
}

var (
applyAllStdout bytes.Buffer
applyAllStderr bytes.Buffer
)

rootPath := helpers.CopyEnvironment(t, testFixtureExternalDependence)
modulePath := util.JoinPath(rootPath, testFixtureExternalDependence, "module-b")

err := helpers.RunTerragruntCommand(t, "terragrunt run --all apply --non-interactive --filter '{./**}...' --tf-forward-stdout --working-dir "+modulePath, &applyAllStdout, &applyAllStderr)
helpers.LogBufferContentsLineByLine(t, applyAllStdout, "run --all apply stdout")
helpers.LogBufferContentsLineByLine(t, applyAllStderr, "run --all apply stderr")

applyAllStdoutString := applyAllStdout.String()

if err != nil {
t.Errorf("Did not expect to get error: %s", err.Error())
}

for _, module := range modules {
assert.Contains(t, applyAllStdoutString, "Hello World, "+module)
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# First, locate and examine the RunTerragruntCommand helper function
echo "=== Locating RunTerragruntCommand implementation ==="
fd "helpers\\.go|helpers\\.ts|helpers\\.py" test/ --type f | head -5

# Search for RunTerragruntCommand definition
echo -e "\n=== Searching for RunTerragruntCommand function ==="
rg -n "func RunTerragruntCommand\(" test/ -A 5 | head -40

Repository: gruntwork-io/terragrunt

Length of output: 995


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Look for the actual implementation of how commands are executed
echo "=== Searching for command execution patterns ==="
rg -n "exec\\.Command" test/helpers -A 3 | head -60

# Also check for any shell invocation patterns
echo -e "\n=== Checking for shell string parsing ==="
rg -n "strings\\.Fields|shellwords|sh -c|bash -c" test/helpers -B 2 -A 2 | head -40

Repository: gruntwork-io/terragrunt

Length of output: 4559


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find the helpers file more directly
echo "=== Finding helpers files ==="
find test -name "*helper*" -type f | head -10

# Check main test directory structure
echo -e "\n=== Files in test directory ==="
ls -la test/*.go | head -20

Repository: gruntwork-io/terragrunt

Length of output: 1977


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Search for RunTerragruntCommand in test files
echo "=== Searching for RunTerragruntCommand ==="
rg -n "func RunTerragruntCommand" . --type go -B 1 -A 10 | head -80

# Also check imports to find helpers location
echo -e "\n=== Finding helpers import in test file ==="
rg -n "helpers\.|import" test/integration_download_test.go | head -20

Repository: gruntwork-io/terragrunt

Length of output: 6014


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# List test directory
echo "=== Test directory structure ==="
ls -la test/ | grep -E "^-|^d"

# Check if there's a helpers subdirectory
echo -e "\n=== Check helpers directory ==="
if [ -d test/helpers ]; then
  ls -la test/helpers/ | head -20
fi

# Try to locate the helpers package
echo -e "\n=== Locating helpers files ==="
find test -name "*.go" -exec grep -l "func RunTerragruntCommand" {} \; | head -5

Repository: gruntwork-io/terragrunt

Length of output: 6175


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Search across all Go files for the function definition
echo "=== Searching for RunTerragruntCommand across all Go files ==="
find . -name "*.go" -exec grep -l "func RunTerragruntCommand" {} \; 2>/dev/null

# If found, get the implementation
echo -e "\n=== Getting RunTerragruntCommand implementation ==="
rg "func RunTerragruntCommand\(" --type go -A 15 2>/dev/null | head -100

Repository: gruntwork-io/terragrunt

Length of output: 2094


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check git to understand the repo structure
echo "=== Repository files related to helpers ==="
git ls-files | grep -i helper | head -20

# Look at the test file itself to understand imports
echo -e "\n=== Checking integration_download_test.go imports and structure ==="
head -50 test/integration_download_test.go

Repository: gruntwork-io/terragrunt

Length of output: 3592


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Get more of the test file to understand the helpers package
echo "=== First 100 lines of integration_download_test.go ==="
head -100 test/integration_download_test.go | cat -n

Repository: gruntwork-io/terragrunt

Length of output: 6093


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Search for where helpers is defined
echo "=== Searching for 'package helpers' ==="
rg "^package helpers" --type go

# Search for RunTerragruntCommand definition
echo -e "\n=== Searching for RunTerragruntCommand definition ==="
rg "func.*RunTerragruntCommand\(" --type go -A 5 | head -80

Repository: gruntwork-io/terragrunt

Length of output: 1303


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# List all go files in test directory
echo "=== Go files in test directory ==="
find test -maxdepth 1 -name "*.go" | sort

# Check if there's a helpers.go file
echo -e "\n=== Check for helpers.go ==="
ls -la test/helpers.go 2>/dev/null || echo "Not found at test/helpers.go"

# Search in all test*.go files
echo -e "\n=== Searching in all test files ==="
rg "RunTerragruntCommand" test/*.go | head -10

Repository: gruntwork-io/terragrunt

Length of output: 3584


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Get context around the test function to find the helpers package
echo "=== Context around test function (lines 700-750) ==="
sed -n '700,750p' test/integration_download_test.go | cat -n

# Search for imports in the test file
echo -e "\n=== All imports in integration_download_test.go ==="
rg "^import" -A 20 test/integration_download_test.go

Repository: gruntwork-io/terragrunt

Length of output: 2596


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Look for the actual helpers module/package
echo "=== Search for helpers package definition ==="
find . -path ./vendor -prune -o -name "*.go" -exec grep -l "helpers\\.RunTerragruntCommand\|func.*RunTerragruntCommand" {} \; 2>/dev/null | head -10

# Check what "helpers" refers to in the context
echo -e "\n=== Checking beginning of test file ==="
head -30 test/integration_download_test.go | cat -n

Repository: gruntwork-io/terragrunt

Length of output: 1948


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check test_helper.go or similar
echo "=== Looking for test helper files ==="
find test -name "*helper*" -o -name "*util*" | sort

# Get the full import section
echo -e "\n=== Complete imports section of integration_download_test.go ==="
sed -n '1,50p' test/integration_download_test.go | grep -A 30 "^import"

Repository: gruntwork-io/terragrunt

Length of output: 1862


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check the go.mod or directory structure
echo "=== Repository structure around test directory ==="
ls -la | grep -E "test|helper"

# Look at actual file locations
echo -e "\n=== Testing different paths ==="
test -f test_helper.go && echo "Found: test_helper.go" || echo "Not at test_helper.go"
test -f test/test_helper.go && echo "Found: test/test_helper.go" || echo "Not at test/test_helper.go"
test -d test_fixtures && echo "Found: test_fixtures directory" || echo "No test_fixtures"

# Just search all go files for the function
echo -e "\n=== All matches for RunTerragruntCommand ==="
rg "RunTerragruntCommand" . --type go | head -20

Repository: gruntwork-io/terragrunt

Length of output: 3876


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Search in terragrunt directory specifically
echo "=== Search entire repo for the function definition ==="
rg "func.*RunTerragruntCommand" . --type go -B 2 -A 15 | head -100

# Also check module name
echo -e "\n=== Check if it's a local package ==="
rg "^package main|^package test" test/*.go | head -5

Repository: gruntwork-io/terragrunt

Length of output: 5159


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check the actual test file content more carefully
echo "=== First 80 lines of test file with context ==="
head -80 test/integration_download_test.go

# Count total lines
echo -e "\n=== File info ==="
wc -l test/integration_download_test.go

Repository: gruntwork-io/terragrunt

Length of output: 4409


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check around line 740 context
echo "=== Context around the test (lines 730-770) ==="
sed -n '730,770p' test/integration_download_test.go | cat -n

# Find all function definitions in the file to understand structure
echo -e "\n=== All test functions in the file ==="
rg "^func Test" test/integration_download_test.go | head -20

Repository: gruntwork-io/terragrunt

Length of output: 2735


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Get the package declaration and imports
echo "=== Package and imports (first 50 lines) ==="
head -50 test/integration_download_test.go | cat -n

# Search for where helpers is used/defined
echo -e "\n=== Search for 'helpers' usage patterns ==="
rg "helpers\\." test/integration_download_test.go | head -10

Repository: gruntwork-io/terragrunt

Length of output: 4349


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Now search for the actual definition by checking if it's in a subpackage
echo "=== Check test subdirectories ==="
find test -maxdepth 2 -type f -name "*.go" | sort

# Look for helpers specifically
echo -e "\n=== Files with 'helpers' in path ==="
git ls-files | grep -i helper

# Direct search for function
echo -e "\n=== Direct grep for RunTerragruntCommand ==="
grep -r "func RunTerragruntCommand" . --include="*.go" 2>/dev/null | head -5

Repository: gruntwork-io/terragrunt

Length of output: 3952


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Get actual file content showing package and initial functions
echo "=== Full beginning section to understand setup ==="
head -100 test/integration_download_test.go

# Search for fixture definitions
echo -e "\n=== Search for testFixtureExternalDependence definition ==="
grep -n "testFixtureExternalDependence" test/integration_download_test.go | head -10

Repository: gruntwork-io/terragrunt

Length of output: 6099


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Get the exact lines from the review
echo "=== Exact lines 740-779 from the file ==="
sed -n '740,779p' test/integration_download_test.go | cat -n

Repository: gruntwork-io/terragrunt

Length of output: 1644


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check what's at line 740 and surrounding context
echo "=== Lines 735-785 with numbers ==="
sed -n '735,785p' test/integration_download_test.go | cat -n

Repository: gruntwork-io/terragrunt

Length of output: 2014


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Simple cat with head to see the structure
echo "=== First 30 lines ==="
head -30 test/integration_download_test.go

echo -e "\n=== Line count ==="
wc -l test/integration_download_test.go

# Check if file exists
echo -e "\n=== File check ==="
ls -lh test/integration_download_test.go

Repository: gruntwork-io/terragrunt

Length of output: 1462


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# List all files in test directory
echo "=== Files in test directory ==="
ls -1 test/*.go 2>/dev/null | head -20 || echo "No .go files in test/"

# Check subdirectories
echo -e "\n=== Subdirectories in test ==="
ls -1d test/*/ 2>/dev/null || echo "No subdirectories"

# Count total go files
echo -e "\n=== Total test-related go files ==="
find test -name "*.go" -type f 2>/dev/null | wc -l

Repository: gruntwork-io/terragrunt

Length of output: 869


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Search for the test function anywhere
echo "=== Searching for TestTerragruntExternalDependenciesWithFilter ==="
rg "TestTerragruntExternalDependenciesWithFilter" . --type go

# Count results
echo -e "\n=== Count ==="
rg "TestTerragruntExternalDependenciesWithFilter" . --type go | wc -l

Repository: gruntwork-io/terragrunt

Length of output: 252


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Search for testFixtureExternalDependence
echo "=== Search for testFixtureExternalDependence ==="
rg "testFixtureExternalDependence" . --type go -l

# Get context if found
echo -e "\n=== Full matches ==="
rg "testFixtureExternalDependence" . --type go | head -20

Repository: gruntwork-io/terragrunt

Length of output: 1632


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check for the fixture in test directories
echo "=== Searching for ExternalDependence in test fixtures ==="
find test -type d -name "*external*" -o -type d -name "*dependenc*"

# Also search for the string
echo -e "\n=== Search string in all files ==="
rg "ExternalDependenc" . --type go -l 2>/dev/null || echo "Not found"

Repository: gruntwork-io/terragrunt

Length of output: 3961


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# List all Go test files
echo "=== All Go test files ==="
find . -name "*_test.go" -type f | sort

# Count them
echo -e "\n=== Count ==="
find . -name "*_test.go" -type f | wc -l

Repository: gruntwork-io/terragrunt

Length of output: 7086


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Search for integration test file specifically
echo "=== Search for integration*test files ==="
find . -name "*integration*test*.go" -type f

# Try a broader search for download test
echo -e "\n=== Search for download test ==="
find . -name "*download*test*.go" -type f

Repository: gruntwork-io/terragrunt

Length of output: 2674


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check git ls-files for test files
echo "=== Test files in git ==="
git ls-files | grep -E "(test\.go|_test\.go)$" | head -30

echo -e "\n=== Files with 'integration' ==="
git ls-files | grep -i integration | head -20

Repository: gruntwork-io/terragrunt

Length of output: 2333


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Search for CopyEnvironment usage to understand test isolation pattern
echo "=== Search for helpers.CopyEnvironment usage ==="
rg "CopyEnvironment" . --type go -B 2 -A 2 | head -60

# Check how t.Parallel() is used with CleanupTerraformFolder
echo -e "\n=== Pattern: t.Parallel with CleanupTerraformFolder ==="
rg "t\.Parallel\(\)" . --type go -A 10 | rg -B 8 "CleanupTerraformFolder" | head -60

Repository: gruntwork-io/terragrunt

Length of output: 8078


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Search for similar test patterns with the fixture
echo "=== Tests using testFixtureExternalDependence or similar ==="
rg "Cleanup.*Folder.*t.*Parallel\|t\.Parallel.*Cleanup" . --type go -B 5 -A 10 | head -100

# Check other uses of CleanupTerraformFolder
echo -e "\n=== All CleanupTerraformFolder usage patterns ==="
rg "CleanupTerraformFolder" . --type go -B 3 -A 1 | head -80

Repository: gruntwork-io/terragrunt

Length of output: 127


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Look for how helpers package handles command execution
echo "=== Search for command execution in helpers ==="
rg "exec\.Command|sh -c|bash -c" . --type go -B 2 -A 5 | head -100

# Check strings.Fields for command splitting
echo -e "\n=== Command string splitting patterns ==="
rg "strings\.Fields|shellwords" . --type go -B 2 -A 3 | head -60

Repository: gruntwork-io/terragrunt

Length of output: 10461


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check the test framework setup - look for t.Parallel usage patterns
echo "=== Analysis of t.Parallel() patterns and cleanup ==="
rg "t\.Parallel\(\)" . --type go -c | head -20

# Check if other tests cleanup before or after CopyEnvironment
echo -e "\n=== Pattern: CopyEnvironment followed by Cleanup ==="
rg "CopyEnvironment.*\n.*Cleanup|Cleanup.*\n.*CopyEnvironment" . --type go -A 5 -B 5 | head -80

Repository: gruntwork-io/terragrunt

Length of output: 993


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Search for the test or similar tests
echo "=== Search for tests with 'Filter' in name ==="
rg "func Test.*Filter" . --type go -l

# Also search for tests that use --filter flag
echo -e "\n=== Tests using --filter flag ==="
rg "\-\-filter" . --type go -B 3 -A 3 | head -80

Repository: gruntwork-io/terragrunt

Length of output: 6195


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Look for shell quoting patterns with curly braces and dots
echo "=== Search for --filter with glob patterns ==="
rg "\-\-filter.*\{.*\*" . --type go -B 2 -A 2 | head -40

# Look for any filter usage
echo -e "\n=== All uses of filter flag ==="
rg "\-\-filter" . --type go | head -20

Repository: gruntwork-io/terragrunt

Length of output: 4327


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check for the "run --all" command pattern used in tests
echo "=== Tests using 'run --all' command ==="
rg "run \-\-all" . --type go -B 5 -A 5 | head -80

# Look for terragrunt run command patterns
echo -e "\n=== RunTerragruntCommand with 'run' subcommand ==="
rg "RunTerragrunt.*run " . --type go | head -20

Repository: gruntwork-io/terragrunt

Length of output: 9321


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Look at git log for recent changes to test files
echo "=== Recent test file changes ==="
git log --oneline --name-only --since="2 months ago" | grep "_test\.go" | head -20

# Check if there are uncommitted changes
echo -e "\n=== Check git status ==="
git status --short | grep test | head -20

Repository: gruntwork-io/terragrunt

Length of output: 797


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Core concern 1: Check if cleanup before and after CopyEnvironment is common pattern
echo "=== Pattern analysis: When is cleanup called relative to CopyEnvironment ==="
rg "CopyEnvironment" . --type go -B 10 -A 10 | grep -E "(Cleanup|CopyEnvironment)" | head -40

# Core concern 2: Check overall t.Parallel usage
echo -e "\n=== t.Parallel usage stats ==="
rg "t\.Parallel\(\)" . --type go | wc -l

# Check how require vs t.Errorf is used
echo -e "\n=== Error handling patterns in tests ==="
rg "require\.NoError|t\.Errorf" . --type go --stats | head -20

Repository: gruntwork-io/terragrunt

Length of output: 4266


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check require.NoError vs t.Errorf usage
echo "=== Count of require.NoError ==="
rg "require\.NoError" . --type go | wc -l

echo -e "\n=== Count of t.Errorf ==="
rg "t\.Errorf" . --type go | wc -l

# Check patterns in test files
echo -e "\n=== Common error handling in recent tests ==="
rg "require\.NoError|t\.Errorf|assert\." test/ --type go | head -30

Repository: gruntwork-io/terragrunt

Length of output: 3515


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Verify the learning about go-zglob since a learnings mentioned filtering/globbing
echo "=== Check for glob/filtering implementations ==="
rg "go-zglob|filepath.Glob|doublestar" . --type go | head -20

# Check command-line filtering in terragrunt
echo -e "\n=== Filtering/glob patterns in source ==="
rg "filter|glob" . --type go | grep -i "cli\|command\|flag" | head -20

Repository: gruntwork-io/terragrunt

Length of output: 3440


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Search for best practice: shared fixture cleanup and t.Parallel
echo "=== Pattern: fixture cleanup with t.Parallel in tests ==="
rg "t\.Parallel\(\)" . --type go -A 20 | rg "testFixture|fixture|Cleanup" | head -40

# Check if there are other tests with the same pattern mentioned in review
echo -e "\n=== Check for test fixture external dependence references ==="
rg "testFixtureExternal\|External.*[Dd]epend" . --type go | head -20

Repository: gruntwork-io/terragrunt

Length of output: 4118


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Final check: Look for the actual command pattern and how it's parsed
echo "=== How commands are typically split in helpers ==="
rg "RunTerragrunt.*Command" . --type go -A 3 | grep -E "(split|Field|arg|Command)" | head -40

# Check if the command string with filter is being tested elsewhere
echo -e "\n=== Commands with complex quoting in tests ==="
rg 'RunTerragrunt.*"[^"]*\{.*\}[^"]*"' . --type go | head -20

Repository: gruntwork-io/terragrunt

Length of output: 7264


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Verify best practice: The concern about t.Parallel and shared fixture mutation
echo "=== Documenting test isolation pattern issues ==="

# Count tests using t.Parallel
parallel_count=$(rg "t\.Parallel\(\)" . --type go | wc -l)
echo "Tests using t.Parallel: $parallel_count"

# Count cleanup patterns
cleanup_count=$(rg "Cleanup.*Folder|Cleanup.*Terraform" . --type go | wc -l)
echo "Tests with cleanup: $cleanup_count"

# Check the actual pattern: do tests cleanup shared fixtures?
echo -e "\n=== Tests that cleanup shared path fixtures ==="
rg "testFixture[A-Z][^ ]*\"" . --type go -B 5 | rg "t\.Parallel|Cleanup" | head -40

# Analysis of the concern
echo -e "\n=== Analyzing concern: When is fixture mutated? ==="
# The review argues cleaning the original (non-copied) fixture while t.Parallel runs
# But the code shows cleaning testFixtureExternalDependence THEN copying THEN running
# The concern is valid IF testFixtureExternalDependence is not in a temp location
rg "testFixtureExternalDependence\s*=" . --type go | head -10

Repository: gruntwork-io/terragrunt

Length of output: 604


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Verify the fixture definition and whether it's shared
echo "=== Locate fixture path definitions ==="
rg "const.*Fixture|var.*Fixture|fixture\s*=" . --type go | head -30

# Check CopyEnvironment implementation
echo -e "\n=== CopyEnvironment function ==="
rg "func.*CopyEnvironment" . --type go -A 10 | head -40

# Understand test isolation
echo -e "\n=== How CopyEnvironment handles fixtures ==="
rg "CopyEnvironment" . --type go -B 3 -A 15 | head -60

Repository: gruntwork-io/terragrunt

Length of output: 7667


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check the pattern: is t.Errorf vs require.NoError a significant difference?
echo "=== Error handling patterns and test continuation ==="

# Show examples of require.NoError
echo "Examples of require.NoError:"
rg "require\.NoError.*RunTerragrunt" . --type go -B 2 -A 2 | head -30

echo -e "\n=== Examples of t.Errorf after command execution ==="
rg "t\.Errorf.*err\." . --type go -B 3 -A 3 | head -30

# Check if tests continue after error in both patterns
echo -e "\n=== Assertion patterns after error checks ==="
rg "if err != nil|require\.NoError" . --type go -A 5 | grep -E "(assert|require|if)" | head -40

Repository: gruntwork-io/terragrunt

Length of output: 7247


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Apply the learning: check for similar test fixture issues
echo "=== Learning application: test fixture cleanup patterns ==="

# According to learning, test fixtures should be handled carefully
# Check how other tests manage this
rg "test.*fixture|fixture.*test" . --type go -l | wc -l

# Check for fixture copy pattern
echo -e "\n=== How other tests handle fixtures with Parallel ==="
rg "t\.Parallel" . --type go -A 30 | rg "CopyEnvironment|CleanupTerraform" -B 5 -A 5 | head -60

Repository: gruntwork-io/terragrunt

Length of output: 4407


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check how RunTerragruntCommand parses its command string argument
echo "=== Understanding command parsing in helpers ==="

# Find the implementation
rg "func.*RunTerragruntCommand" . --type go -A 20 | head -60

# Check if it uses exec.Command with split vs shell
echo -e "\n=== Command execution methods ==="
rg "exec\.Command\(\"" . --type go | head -20

# Check for strings.Fields usage (which would split on whitespace, breaking quotes)
echo -e "\n=== String field splitting patterns ==="
rg "strings\.Fields\(" . --type go -B 3 -A 3 | head -40

Repository: gruntwork-io/terragrunt

Length of output: 3381


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Final comprehensive check on the core concerns
echo "=== Verifying concern 1: shared fixture mutation with t.Parallel ==="

# Get examples of cleanup patterns with t.Parallel
rg "t\.Parallel" . --type go -A 50 | rg "Cleanup" -B 3 -A 3 | head -100

echo -e "\n=== Fixture path constants ==="
# Find const definitions for fixtures
rg "const\s+test.*=|const\s+\w*Fixture" . --type go | head -40

Repository: gruntwork-io/terragrunt

Length of output: 7184


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check if the comment references a new test being added
# The review says "now doubled by adding a second similar test"
echo "=== Search for similar tests that were added ==="
git log --oneline --all -20 -- "**/*download*test.go"

echo -e "\n=== Check for tests with similar names ==="
rg "TestTerragrunt.*With\|TestTerragrunt.*Filter" . --type go | head -20

Repository: gruntwork-io/terragrunt

Length of output: 359


Move fixture cleanup to copied environment to prevent race conditions; replace t.Errorf with require.NoError to fail fast.

The test cleans the repository fixture (testFixtureExternalDependence) before copying the environment. With t.Parallel(), this creates a race condition as other tests may access the same shared fixture path. Move cleanup operations after CopyEnvironment to operate only on the isolated copy. Additionally, replace t.Errorf with require.NoError to fail immediately on command errors instead of allowing subsequent assertions to run with invalid data.

 func TestTerragruntExternalDependenciesWithFilter(t *testing.T) {
 	t.Parallel()
 
 	if !helpers.IsExperimentMode(t) {
 		t.Skip("Skipping filter flag tests - TG_EXPERIMENT_MODE not enabled")
 	}
 
 	modules := []string{
 		"module-a",
 		"module-b",
 	}
 
-	helpers.CleanupTerraformFolder(t, testFixtureExternalDependence)
-
-	for _, module := range modules {
-		helpers.CleanupTerraformFolder(t, util.JoinPath(testFixtureExternalDependence, module))
-	}
-
 	var (
 		applyAllStdout bytes.Buffer
 		applyAllStderr bytes.Buffer
 	)
 
 	rootPath := helpers.CopyEnvironment(t, testFixtureExternalDependence)
-	modulePath := util.JoinPath(rootPath, testFixtureExternalDependence, "module-b")
+	fixtureRoot := util.JoinPath(rootPath, testFixtureExternalDependence)
+	helpers.CleanupTerraformFolder(t, fixtureRoot)
+	for _, module := range modules {
+		helpers.CleanupTerraformFolder(t, util.JoinPath(fixtureRoot, module))
+	}
+	modulePath := util.JoinPath(fixtureRoot, "module-b")
 
 	err := helpers.RunTerragruntCommand(t, "terragrunt run --all apply --non-interactive --filter '{./**}...' --tf-forward-stdout --working-dir "+modulePath, &applyAllStdout, &applyAllStderr)
 	helpers.LogBufferContentsLineByLine(t, applyAllStdout, "run --all apply stdout")
 	helpers.LogBufferContentsLineByLine(t, applyAllStderr, "run --all apply stderr")
+	require.NoError(t, err)
 
 	applyAllStdoutString := applyAllStdout.String()
-
-	if err != nil {
-		t.Errorf("Did not expect to get error: %s", err.Error())
-	}
 
 	for _, module := range modules {
 		assert.Contains(t, applyAllStdoutString, "Hello World, "+module)
 	}
 }
🤖 Prompt for AI Agents
In test/integration_download_test.go around lines 740 to 779, the fixture
cleanup runs on the shared repository path before copying the environment which
can race with other parallel tests, and the test uses t.Errorf to report the
command error instead of failing fast. Move the CleanupTerraformFolder calls to
after rootPath := helpers.CopyEnvironment(...) and update module cleanup loops
to reference util.JoinPath(rootPath, testFixtureExternalDependence, module) (so
cleanup targets the isolated copy), and replace the t.Errorf check with
require.NoError(t, err) to immediately fail the test on command failure (ensure
the require package is imported).

Comment on lines +68 to +108
func TestTerragruntWorksWithIncludeLocalsWithFilter(t *testing.T) {
t.Parallel()

if !helpers.IsExperimentMode(t) {
t.Skip("Skipping filter flag tests - TG_EXPERIMENT_MODE not enabled")
}

helpers.CleanupTerraformFolder(t, includeExposeFixturePath)
tmpEnvPath := helpers.CopyEnvironment(t, includeExposeFixturePath)
tmpEnvPath = util.JoinPath(tmpEnvPath, includeExposeFixturePath)

files, err := os.ReadDir(tmpEnvPath)
require.NoError(t, err)

testCases := []string{}

for _, finfo := range files {
if finfo.IsDir() {
testCases = append(testCases, finfo.Name())
}
}

for _, tc := range testCases {
t.Run(filepath.Base(tc), func(t *testing.T) {
t.Parallel()

childPath := filepath.Join(tmpEnvPath, tc, includeChildFixturePath)
helpers.CleanupTerraformFolder(t, childPath)
helpers.RunTerragrunt(t, "terragrunt run --all --filter '{./**}...' --non-interactive --log-level trace --working-dir "+childPath+" -- apply -auto-approve")

stdout := bytes.Buffer{}
stderr := bytes.Buffer{}
err := helpers.RunTerragruntCommand(t, "terragrunt output -no-color -json --non-interactive --log-level trace --working-dir "+childPath, &stdout, &stderr)
require.NoError(t, err)

outputs := map[string]helpers.TerraformOutput{}
require.NoError(t, json.Unmarshal(stdout.Bytes(), &outputs))
assert.Equal(t, "us-west-1-test", outputs["region"].Value.(string))
})
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find the RunTerragruntCommandWithOutputWithContext function
echo "=== Searching for RunTerragruntCommandWithOutputWithContext ==="
rg -n "func RunTerragruntCommandWithOutputWithContext\(" test/helpers -A 10

echo -e "\n=== Searching for shell command parsing patterns ==="
rg -n "shellwords|sh -c|bash -c|strings\.Fields|Split\(" test/helpers -B 2 -A 2

echo -e "\n=== Checking CleanupTerraformFolder implementation ==="
rg -n "func CleanupTerraformFolder" test/helpers -A 10

echo -e "\n=== Checking other similar test patterns in integration_include_test.go ==="
rg -n "helpers.CleanupTerraformFolder" test/integration_include_test.go -B 3 -A 3

Repository: gruntwork-io/terragrunt

Length of output: 5916


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Finding CopyEnvironment implementation ==="
rg -n "func CopyEnvironment" test/helpers -A 15

echo -e "\n=== Understanding what includeExposeFixturePath, tmpEnvPath point to ==="
rg -n "includeExposeFixturePath\|includeChildFixturePath" test/integration_include_test.go -B 2 -A 2 | head -40

echo -e "\n=== Check the fixture path definitions at top of file ==="
head -30 test/integration_include_test.go

Repository: gruntwork-io/terragrunt

Length of output: 1069


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== File header with fixture path definitions ==="
head -30 test/integration_include_test.go

echo -e "\n=== Full context of the test function ==="
sed -n '68,110p' test/integration_include_test.go

Repository: gruntwork-io/terragrunt

Length of output: 2427


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Checking for t.Parallel() calls in related tests ==="
rg -n "func Test.*IncludeLocals" test/integration_include_test.go -A 3

echo -e "\n=== Verifying the issue: both tests clean shared fixture while running in parallel ==="
echo "TestTerragruntWorksWithIncludeLocals:"
sed -n '31,36p' test/integration_include_test.go
echo ""
echo "TestTerragruntWorksWithIncludeLocalsWithFilter:"
sed -n '68,77p' test/integration_include_test.go

Repository: gruntwork-io/terragrunt

Length of output: 1234


Move cleanup from repo fixture to temp copy to avoid parallel test interference.

Both TestTerragruntWorksWithIncludeLocals and TestTerragruntWorksWithIncludeLocalsWithFilter run with t.Parallel() and clean the shared includeExposeFixturePath fixture. This creates a race condition where concurrent test execution could cause cross-test interference. Since each test receives its own isolated temp copy via t.TempDir(), clean tmpEnvPath instead.

-	helpers.CleanupTerraformFolder(t, includeExposeFixturePath)
 	tmpEnvPath := helpers.CopyEnvironment(t, includeExposeFixturePath)
 	tmpEnvPath = util.JoinPath(tmpEnvPath, includeExposeFixturePath)
+	helpers.CleanupTerraformFolder(t, tmpEnvPath)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func TestTerragruntWorksWithIncludeLocalsWithFilter(t *testing.T) {
t.Parallel()
if !helpers.IsExperimentMode(t) {
t.Skip("Skipping filter flag tests - TG_EXPERIMENT_MODE not enabled")
}
helpers.CleanupTerraformFolder(t, includeExposeFixturePath)
tmpEnvPath := helpers.CopyEnvironment(t, includeExposeFixturePath)
tmpEnvPath = util.JoinPath(tmpEnvPath, includeExposeFixturePath)
files, err := os.ReadDir(tmpEnvPath)
require.NoError(t, err)
testCases := []string{}
for _, finfo := range files {
if finfo.IsDir() {
testCases = append(testCases, finfo.Name())
}
}
for _, tc := range testCases {
t.Run(filepath.Base(tc), func(t *testing.T) {
t.Parallel()
childPath := filepath.Join(tmpEnvPath, tc, includeChildFixturePath)
helpers.CleanupTerraformFolder(t, childPath)
helpers.RunTerragrunt(t, "terragrunt run --all --filter '{./**}...' --non-interactive --log-level trace --working-dir "+childPath+" -- apply -auto-approve")
stdout := bytes.Buffer{}
stderr := bytes.Buffer{}
err := helpers.RunTerragruntCommand(t, "terragrunt output -no-color -json --non-interactive --log-level trace --working-dir "+childPath, &stdout, &stderr)
require.NoError(t, err)
outputs := map[string]helpers.TerraformOutput{}
require.NoError(t, json.Unmarshal(stdout.Bytes(), &outputs))
assert.Equal(t, "us-west-1-test", outputs["region"].Value.(string))
})
}
}
func TestTerragruntWorksWithIncludeLocalsWithFilter(t *testing.T) {
t.Parallel()
if !helpers.IsExperimentMode(t) {
t.Skip("Skipping filter flag tests - TG_EXPERIMENT_MODE not enabled")
}
tmpEnvPath := helpers.CopyEnvironment(t, includeExposeFixturePath)
tmpEnvPath = util.JoinPath(tmpEnvPath, includeExposeFixturePath)
helpers.CleanupTerraformFolder(t, tmpEnvPath)
files, err := os.ReadDir(tmpEnvPath)
require.NoError(t, err)
testCases := []string{}
for _, finfo := range files {
if finfo.IsDir() {
testCases = append(testCases, finfo.Name())
}
}
for _, tc := range testCases {
t.Run(filepath.Base(tc), func(t *testing.T) {
t.Parallel()
childPath := filepath.Join(tmpEnvPath, tc, includeChildFixturePath)
helpers.CleanupTerraformFolder(t, childPath)
helpers.RunTerragrunt(t, "terragrunt run --all --filter '{./**}...' --non-interactive --log-level trace --working-dir "+childPath+" -- apply -auto-approve")
stdout := bytes.Buffer{}
stderr := bytes.Buffer{}
err := helpers.RunTerragruntCommand(t, "terragrunt output -no-color -json --non-interactive --log-level trace --working-dir "+childPath, &stdout, &stderr)
require.NoError(t, err)
outputs := map[string]helpers.TerraformOutput{}
require.NoError(t, json.Unmarshal(stdout.Bytes(), &outputs))
assert.Equal(t, "us-west-1-test", outputs["region"].Value.(string))
})
}
}
🤖 Prompt for AI Agents
In test/integration_include_test.go around lines 68 to 108, the test currently
calls helpers.CleanupTerraformFolder(t, includeExposeFixturePath) which cleans
the shared repo fixture; instead, remove that call and call
helpers.CleanupTerraformFolder(t, tmpEnvPath) after creating tmpEnvPath (i.e.,
after helpers.CopyEnvironment and util.JoinPath) so each parallel test cleans
its own temp copy and avoids cross-test interference.

@yhakbar yhakbar merged commit 0be026a into main Dec 15, 2025
71 of 72 checks passed
@yhakbar yhakbar deleted the chore/verify-queue-include-external-is-unnecessary-with-filter branch December 15, 2025 19:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants