Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion test/integration_dag_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,22 @@ func TestIncludeExternalInDagGraphCmd(t *testing.T) {
workDir, err := filepath.EvalSymlinks(workDir)
require.NoError(t, err)

cmd := "terragrunt dag graph --queue-include-external --working-dir " + workDir
cmd := "terragrunt dag graph --working-dir " + workDir

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

func TestIncludeExternalInDagGraphCmdWithList(t *testing.T) {
t.Parallel()

helpers.CleanupTerraformFolder(t, testFixtureGraphDAG)
workDir := filepath.Join(testFixtureGraphDAG, "region-1")
workDir, err := filepath.EvalSymlinks(workDir)
require.NoError(t, err)

cmd := "terragrunt list --format=dot --dependencies --working-dir " + workDir

stdout, _, err := helpers.RunTerragruntCommandWithOutput(t, cmd)
require.NoError(t, err)
Expand Down
41 changes: 41 additions & 0 deletions test/integration_download_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -737,6 +737,47 @@ func TestTerragruntExternalDependencies(t *testing.T) {
}
}

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)
}
}
Comment on lines +740 to +779
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).


func TestPreventDestroy(t *testing.T) {
t.Parallel()

Expand Down
41 changes: 41 additions & 0 deletions test/integration_include_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,47 @@ func TestTerragruntWorksWithIncludeLocals(t *testing.T) {
})
}
}
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))
})
}
}
Comment on lines +68 to +108
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.


func TestTerragruntRunAllModulesThatIncludeRestrictsSet(t *testing.T) {
t.Parallel()
Expand Down
5 changes: 4 additions & 1 deletion test/integration_runner_pool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,10 @@ func TestRunnerPoolStackConfigIgnored(t *testing.T) {
helpers.CleanupTerraformFolder(t, tmpEnvPath)
testPath := util.JoinPath(tmpEnvPath, testFixtureMixedConfig)

_, stderr, err := helpers.RunTerragruntCommandWithOutput(t, "terragrunt run --queue-include-external --all --non-interactive --working-dir "+testPath+" -- apply")
_, stderr, err := helpers.RunTerragruntCommandWithOutput(
t,
"terragrunt run --all --non-interactive --working-dir "+testPath+" -- apply",
)
require.NoError(t, err)
require.NotContains(t, stderr, "Error: Unsupported block type")
require.NotContains(t, stderr, "Blocks of type \"unit\" are not expected here")
Expand Down