Skip to content

Commit 7b593b8

Browse files
committed
chore: parse improvements
1 parent 5d8df91 commit 7b593b8

5 files changed

Lines changed: 90 additions & 14 deletions

File tree

internal/hclparse/fuzz_test.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import (
77
"github.com/gruntwork-io/terragrunt/internal/vfs"
88
"github.com/hashicorp/hcl/v2"
99
"github.com/hashicorp/hcl/v2/hclsyntax"
10-
"github.com/stretchr/testify/require"
1110
"github.com/zclconf/go-cty/cty"
1211
)
1312

@@ -182,8 +181,8 @@ dependency "b" { config_path = "../b" }`,
182181
fs := vfs.NewMemMapFS()
183182

184183
dir := "/fuzz/unit"
185-
require.NoError(t, fs.MkdirAll(dir, 0755))
186-
require.NoError(t, vfs.WriteFile(fs, dir+"/terragrunt.autoinclude.hcl", []byte(input), 0644))
184+
_ = fs.MkdirAll(dir, 0755)
185+
_ = vfs.WriteFile(fs, dir+"/terragrunt.autoinclude.hcl", []byte(input), 0644)
187186

188187
_, _ = hclparse.AutoIncludeDependencyPaths(fs, dir)
189188
})
@@ -229,7 +228,6 @@ func FuzzNestedStackPath(f *testing.F) {
229228
f.Add("infra", "deep", "vpc", "db")
230229
f.Add("network", "storage", "subnet", "bucket")
231230
f.Add("a", "b", "c", "d")
232-
f.Add("", "", "", "")
233231
f.Add("path", "name", "source", "autoinclude")
234232

235233
f.Fuzz(func(t *testing.T, stackName, nestedStackName, unitName, nestedUnitName string) {

internal/hclparse/panic_test.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package hclparse_test
22

33
import (
4+
"fmt"
45
"testing"
56

67
"github.com/gruntwork-io/terragrunt/internal/hclparse"
@@ -11,17 +12,15 @@ import (
1112

1213
// assertPanicsContaining asserts the given call panics with a message
1314
// containing the expected substring. Uses Contains so the descriptive
14-
// panic texts remain flexible to small wording edits.
15+
// panic texts remain flexible to small wording edits. fmt.Sprint handles
16+
// string, error, fmt.Stringer, and arbitrary panic values uniformly.
1517
func assertPanicsContaining(t *testing.T, want string, fn func()) {
1618
t.Helper()
1719

1820
defer func() {
1921
r := recover()
2022
require.NotNil(t, r, "expected panic containing %q, got no panic", want)
21-
22-
msg, ok := r.(string)
23-
require.True(t, ok, "panic value is not a string: %v", r)
24-
assert.Contains(t, msg, want)
23+
assert.Contains(t, fmt.Sprint(r), want)
2524
}()
2625

2726
fn()

internal/hclparse/parse.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,10 @@ func buildStackRefsWithAbsPath(fs vfs.FS, stackDir string, stackTargetDir string
416416
for _, s := range stacks {
417417
stackGenPath := filepath.Join(stackTargetDir, s.Path)
418418

419+
if s.NoStack != nil && *s.NoStack {
420+
stackGenPath = filepath.Join(filepath.Dir(stackTargetDir), s.Path)
421+
}
422+
419423
ref := ComponentRef{
420424
Name: s.Name,
421425
Path: stackGenPath,

internal/hclparse/parse_test.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,64 @@ unit "app" {
585585
assert.Equal(t, expectedPath, resolved.Dependencies[0].ConfigPath)
586586
}
587587

588+
// TestParseStackFile_TopLevelStackNoDotTerragruntStack verifies that a top-level
589+
// stack block with no_dot_terragrunt_stack = true resolves stack.<name>.path to
590+
// <stackDir>/<s.Path> (not <stackDir>/.terragrunt-stack/<s.Path>), matching the
591+
// behavior of resolveDestPath in pkg/config/stack.go.
592+
func TestParseStackFile_TopLevelStackNoDotTerragruntStack(t *testing.T) {
593+
t.Parallel()
594+
595+
fs := vfs.NewMemMapFS()
596+
597+
require.NoError(t, fs.MkdirAll("/project/catalog/stacks/networking", 0755))
598+
require.NoError(t, vfs.WriteFile(fs, "/project/catalog/stacks/networking/terragrunt.stack.hcl", []byte(`
599+
unit "vpc" {
600+
source = "../../units/vpc"
601+
path = "vpc"
602+
}
603+
`), 0644))
604+
605+
parentStackDir := "/project/live"
606+
607+
require.NoError(t, fs.MkdirAll(parentStackDir, 0755))
608+
609+
parentSrc := `
610+
stack "networking" {
611+
source = "../catalog/stacks/networking"
612+
path = "networking"
613+
no_dot_terragrunt_stack = true
614+
}
615+
616+
unit "app" {
617+
source = "../catalog/units/app"
618+
path = "app"
619+
620+
autoinclude {
621+
dependency "net" {
622+
config_path = stack.networking.path
623+
}
624+
}
625+
}
626+
`
627+
parentStackFile := filepath.Join(parentStackDir, "terragrunt.stack.hcl")
628+
require.NoError(t, vfs.WriteFile(fs, parentStackFile, []byte(parentSrc), 0644))
629+
630+
result, err := hclparse.ParseStackFile(fs, &hclparse.ParseStackFileInput{
631+
Src: []byte(parentSrc),
632+
Filename: parentStackFile,
633+
StackDir: parentStackDir,
634+
})
635+
require.NoError(t, err)
636+
637+
resolved, ok := result.AutoIncludes[hclparse.AutoIncludeKey("unit", "app")]
638+
require.True(t, ok)
639+
require.Len(t, resolved.Dependencies, 1)
640+
641+
// Must resolve directly under parentStackDir, bypassing .terragrunt-stack/.
642+
expectedPath := filepath.Join(parentStackDir, "networking")
643+
assert.Equal(t, expectedPath, resolved.Dependencies[0].ConfigPath)
644+
}
645+
588646
func TestParseStackFile_LocalsCycle(t *testing.T) {
589647
t.Parallel()
590648

test/integration_stack_dependencies_test.go

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ func TestStackDepsAutoIncludeGenerationAndDAG(t *testing.T) {
3838
helpers.CleanupTerraformFolder(t, testFixtureStackDepsAutoInclude)
3939
tmpEnvPath := helpers.CopyEnvironment(t, testFixtureStackDepsAutoInclude)
4040
liveDir := filepath.Join(tmpEnvPath, testFixtureStackDepsAutoInclude, "live")
41-
liveDir, _ = filepath.EvalSymlinks(liveDir)
41+
liveDir, err := filepath.EvalSymlinks(liveDir)
42+
require.NoError(t, err)
4243

4344
stackFile := filepath.Join(liveDir, "terragrunt.stack.hcl")
4445

@@ -154,7 +155,8 @@ func TestStackDepsDAGExpandsStackToUnits(t *testing.T) {
154155
helpers.CleanupTerraformFolder(t, testFixtureStackDepsStackRef)
155156
tmpEnvPath := helpers.CopyEnvironment(t, testFixtureStackDepsStackRef)
156157
liveDir := filepath.Join(tmpEnvPath, testFixtureStackDepsStackRef, "live")
157-
liveDir, _ = filepath.EvalSymlinks(liveDir)
158+
liveDir, err := filepath.EvalSymlinks(liveDir)
159+
require.NoError(t, err)
158160

159161
stackFile := filepath.Join(liveDir, "terragrunt.stack.hcl")
160162

@@ -274,6 +276,10 @@ func TestStackDepsE2EChain(t *testing.T) {
274276
assert.Equal(t, "unit-b received: from-c", string(contentB))
275277

276278
helpers.RunTerragrunt(t, "terragrunt run --all --non-interactive --experiment stack-dependencies --working-dir "+rootPath+" -- destroy -auto-approve")
279+
280+
// Destroy must remove the marker files produced by apply.
281+
assert.NoFileExists(t, markerA[0])
282+
assert.NoFileExists(t, markerB[0])
277283
}
278284

279285
// TestStackDepsE2ECrossStack tests stack generation with cross-stack dependencies:
@@ -327,7 +333,8 @@ func TestStackDepsDocExample_UnitInStack(t *testing.T) {
327333
helpers.CleanupTerraformFolder(t, testFixtureStackDepsUnitInStack)
328334
tmpEnvPath := helpers.CopyEnvironment(t, testFixtureStackDepsUnitInStack)
329335
liveDir := filepath.Join(tmpEnvPath, testFixtureStackDepsUnitInStack, "live")
330-
liveDir, _ = filepath.EvalSymlinks(liveDir)
336+
liveDir, err := filepath.EvalSymlinks(liveDir)
337+
require.NoError(t, err)
331338

332339
stackFile := filepath.Join(liveDir, "terragrunt.stack.hcl")
333340

@@ -373,7 +380,8 @@ func TestStackDepsDocExample_EntireStack(t *testing.T) {
373380
helpers.CleanupTerraformFolder(t, testFixtureStackDepsEntireStack)
374381
tmpEnvPath := helpers.CopyEnvironment(t, testFixtureStackDepsEntireStack)
375382
liveDir := filepath.Join(tmpEnvPath, testFixtureStackDepsEntireStack, "live")
376-
liveDir, _ = filepath.EvalSymlinks(liveDir)
383+
liveDir, err := filepath.EvalSymlinks(liveDir)
384+
require.NoError(t, err)
377385

378386
stackFile := filepath.Join(liveDir, "terragrunt.stack.hcl")
379387

@@ -428,7 +436,8 @@ func TestStackDepsDocExample_NestedStackPath(t *testing.T) {
428436
helpers.CleanupTerraformFolder(t, testFixtureStackDepsNestedStack)
429437
tmpEnvPath := helpers.CopyEnvironment(t, testFixtureStackDepsNestedStack)
430438
liveDir := filepath.Join(tmpEnvPath, testFixtureStackDepsNestedStack, "live")
431-
liveDir, _ = filepath.EvalSymlinks(liveDir)
439+
liveDir, err := filepath.EvalSymlinks(liveDir)
440+
require.NoError(t, err)
432441

433442
stackFile := filepath.Join(liveDir, "terragrunt.stack.hcl")
434443

@@ -507,6 +516,7 @@ func TestStackDepsFindJSON(t *testing.T) {
507516

508517
// Find the unit-w-inputs component and verify its dependency
509518
foundInputs := false
519+
foundOutputs := false
510520

511521
for _, c := range components {
512522
if c.Type != "unit" {
@@ -521,11 +531,14 @@ func TestStackDepsFindJSON(t *testing.T) {
521531
}
522532

523533
if strings.HasSuffix(c.Path, "unit-w-outputs") {
534+
foundOutputs = true
535+
524536
assert.Empty(t, c.Dependencies)
525537
}
526538
}
527539

528540
require.True(t, foundInputs, "unit-w-inputs should be in find output")
541+
require.True(t, foundOutputs, "unit-w-outputs should be in find output")
529542
}
530543

531544
// TestStackDepsFindDAG verifies that terragrunt find --dag lists units in
@@ -807,4 +820,8 @@ func TestStackDepsE2ETree(t *testing.T) {
807820
assert.Equal(t, "unit-a(from-b(from-d,from-e),from-c)", string(contentA))
808821

809822
helpers.RunTerragrunt(t, "terragrunt run --all --non-interactive --experiment stack-dependencies --working-dir "+rootPath+" -- destroy -auto-approve")
823+
824+
// Destroy must remove the marker files produced by apply.
825+
assert.NoFileExists(t, markerA[0])
826+
assert.NoFileExists(t, markerB[0])
810827
}

0 commit comments

Comments
 (0)