ensure we record diagnostics from nested modules

When loading nested modules, the child module diagnostics were dropped
in the recursive function. This mean that the config from the submodules
wasn't fully loaded, even though no errors were reported to the user.

This caused further problems if the plan was stored in a plan file, when
means only the partial configuration was stored for the subsequent apply
operation, which would result in unexplained "Resource node has no
configuration attached" errors later on.

Also due to the child module diagnostics being lost, any newly added
nested modules would be silently ignored until `init` was run again
manually.
This commit is contained in:
James Bardin 2019-07-16 18:58:40 -04:00
parent 9ebcbe1d60
commit 8111050c66
5 changed files with 59 additions and 0 deletions

View File

@ -76,6 +76,7 @@ func buildChildModules(parent *Config, walker ModuleWalker) (map[string]*Config,
} }
child.Children, modDiags = buildChildModules(child, walker) child.Children, modDiags = buildChildModules(child, walker)
diags = append(diags, modDiags...)
ret[call.Name] = child ret[call.Name] = child
} }

View File

@ -69,3 +69,48 @@ func TestBuildConfig(t *testing.T) {
t.Fatalf("child_a.child_c is same object as child_b.child_c; should not be") t.Fatalf("child_a.child_c is same object as child_b.child_c; should not be")
} }
} }
func TestBuildConfigDiags(t *testing.T) {
parser := NewParser(nil)
mod, diags := parser.LoadConfigDir("testdata/nested-errors")
assertNoDiagnostics(t, diags)
if mod == nil {
t.Fatal("got nil root module; want non-nil")
}
versionI := 0
cfg, diags := BuildConfig(mod, ModuleWalkerFunc(
func(req *ModuleRequest) (*Module, *version.Version, hcl.Diagnostics) {
// For the sake of this test we're going to just treat our
// SourceAddr as a path relative to our fixture directory.
// A "real" implementation of ModuleWalker should accept the
// various different source address syntaxes Terraform supports.
sourcePath := filepath.Join("testdata/nested-errors", req.SourceAddr)
mod, diags := parser.LoadConfigDir(sourcePath)
version, _ := version.NewVersion(fmt.Sprintf("1.0.%d", versionI))
versionI++
return mod, version, diags
},
))
wantDiag := `testdata/nested-errors/child_c/child_c.tf:5,1-8: ` +
`Unsupported block type; Blocks of type "invalid" are not expected here.`
assertExactDiagnostics(t, diags, []string{wantDiag})
// we should still have module structure loaded
var got []string
cfg.DeepEach(func(c *Config) {
got = append(got, fmt.Sprintf("%s %s", strings.Join(c.Path, "."), c.Version))
})
sort.Strings(got)
want := []string{
" <nil>",
"child_a 1.0.0",
"child_a.child_c 1.0.1",
}
if !reflect.DeepEqual(got, want) {
t.Fatalf("wrong result\ngot: %swant: %s", spew.Sdump(got), spew.Sdump(want))
}
}

View File

@ -0,0 +1,4 @@
module "child_c" {
source = "child_c"
}

View File

@ -0,0 +1,6 @@
output "hello" {
value = "hello"
}
invalid "block" "type " {
}

View File

@ -0,0 +1,3 @@
module "child_a" {
source = "child_a"
}