diff --git a/internal/stacks/stackruntime/apply_test.go b/internal/stacks/stackruntime/apply_test.go index 6d3687fd75..b402862f88 100644 --- a/internal/stacks/stackruntime/apply_test.go +++ b/internal/stacks/stackruntime/apply_test.go @@ -3148,7 +3148,6 @@ func TestApply_RemovedBlocks(t *testing.T) { // TODO: Add tests for and implement the following cases: // - Removed and component blocks that target the same instance. - // - Edge cases around missing providers and type mismatches. // - Validate what happens when a removed block foreach evaluates to // unknown. // - Add a test for a removed block in an embedded stack. diff --git a/internal/stacks/stackruntime/internal/stackeval/stack_config.go b/internal/stacks/stackruntime/internal/stackeval/stack_config.go index 6158d4035b..eba0c154ea 100644 --- a/internal/stacks/stackruntime/internal/stackeval/stack_config.go +++ b/internal/stacks/stackruntime/internal/stackeval/stack_config.go @@ -449,11 +449,11 @@ func (s *StackConfig) Removed(ctx context.Context, addr stackaddrs.Component) *R // Removeds returns a map of the objects representing all of the // removed calls declared inside this stack configuration. func (s *StackConfig) Removeds(ctx context.Context) map[stackaddrs.Component]*RemovedConfig { - if len(s.config.Stack.Components) == 0 { + if len(s.config.Stack.Removed) == 0 { return nil } ret := make(map[stackaddrs.Component]*RemovedConfig, len(s.config.Stack.Removed)) - for name := range s.config.Stack.Components { + for name := range s.config.Stack.Removed { addr := stackaddrs.Component{Name: name} ret[addr] = s.Removed(ctx, addr) } diff --git a/internal/stacks/stackruntime/internal/stackeval/walk_static.go b/internal/stacks/stackruntime/internal/stackeval/walk_static.go index 19419f7572..082cdc5cce 100644 --- a/internal/stacks/stackruntime/internal/stackeval/walk_static.go +++ b/internal/stacks/stackruntime/internal/stackeval/walk_static.go @@ -64,6 +64,10 @@ func walkStaticObjectsInStackConfig[Output any]( visit(ctx, walk, obj) } + for _, obj := range stackConfig.Removeds(ctx) { + visit(ctx, walk, obj) + } + for _, obj := range stackConfig.StackCalls(ctx) { visit(ctx, walk, obj) } diff --git a/internal/stacks/stackruntime/testdata/mainbundle/test/with-single-input/invalid-provider-type/invalid-provider-type.tfstack.hcl b/internal/stacks/stackruntime/testdata/mainbundle/test/with-single-input/invalid-provider-type/invalid-provider-type.tfstack.hcl index 2e4a61b182..17593aabfd 100644 --- a/internal/stacks/stackruntime/testdata/mainbundle/test/with-single-input/invalid-provider-type/invalid-provider-type.tfstack.hcl +++ b/internal/stacks/stackruntime/testdata/mainbundle/test/with-single-input/invalid-provider-type/invalid-provider-type.tfstack.hcl @@ -26,3 +26,14 @@ component "self" { input = var.input } } + +removed { + from = component.removed + + source = "../" + + providers = { + // Everything looks okay here, but the provider types are actually wrong. + testing = provider.testing.default + } +} diff --git a/internal/stacks/stackruntime/testdata/mainbundle/test/with-single-input/missing-provider/missing-provider.tfstack.hcl b/internal/stacks/stackruntime/testdata/mainbundle/test/with-single-input/missing-provider/missing-provider.tfstack.hcl index f05795622e..8eadab5021 100644 --- a/internal/stacks/stackruntime/testdata/mainbundle/test/with-single-input/missing-provider/missing-provider.tfstack.hcl +++ b/internal/stacks/stackruntime/testdata/mainbundle/test/with-single-input/missing-provider/missing-provider.tfstack.hcl @@ -21,3 +21,12 @@ component "self" { input = var.input } } + +removed { + from = component.removed + + source = "../" + + # We do actually require a provider here, Validate() should warn us. + providers = {} +} diff --git a/internal/stacks/stackruntime/testdata/mainbundle/test/with-single-input/undeclared-provider/undeclared-provider.tfstack.hcl b/internal/stacks/stackruntime/testdata/mainbundle/test/with-single-input/undeclared-provider/undeclared-provider.tfstack.hcl index fa29629b95..44503088ad 100644 --- a/internal/stacks/stackruntime/testdata/mainbundle/test/with-single-input/undeclared-provider/undeclared-provider.tfstack.hcl +++ b/internal/stacks/stackruntime/testdata/mainbundle/test/with-single-input/undeclared-provider/undeclared-provider.tfstack.hcl @@ -14,3 +14,14 @@ component "self" { input = var.input } } + +removed { + from = component.removed + + source = "../" + + providers = { + # We haven't provided a definition for this anywhere. + testing = provider.testing.default + } +} diff --git a/internal/stacks/stackruntime/validate_test.go b/internal/stacks/stackruntime/validate_test.go index 31a3830bad..173ad14251 100644 --- a/internal/stacks/stackruntime/validate_test.go +++ b/internal/stacks/stackruntime/validate_test.go @@ -119,12 +119,32 @@ var ( End: hcl.Pos{Line: 10, Column: 39, Byte: 187}, }, }) + diags = diags.Append(&hcl.Diagnostic{ + Severity: hcl.DiagError, + Summary: "Reference to undeclared provider configuration", + Detail: "There is no provider \"testing\" \"default\" block declared in this stack.", + Subject: &hcl.Range{ + Filename: mainBundleSourceAddrStr("with-single-input/undeclared-provider/undeclared-provider.tfstack.hcl"), + Start: hcl.Pos{Line: 25, Column: 15, Byte: 379}, + End: hcl.Pos{Line: 25, Column: 39, Byte: 403}, + }, + }) return diags }, }, filepath.Join("with-single-input", "missing-provider"): { diags: func() tfdiags.Diagnostics { var diags tfdiags.Diagnostics + diags = diags.Append(&hcl.Diagnostic{ + Severity: hcl.DiagError, + Summary: "Missing required provider configuration", + Detail: "The root module for component.removed requires a provider configuration named \"testing\" for provider \"hashicorp/testing\", which is not assigned in the block's \"providers\" argument.", + Subject: &hcl.Range{ + Filename: mainBundleSourceAddrStr("with-single-input/missing-provider/missing-provider.tfstack.hcl"), + Start: hcl.Pos{Line: 25, Column: 1, Byte: 337}, + End: hcl.Pos{Line: 25, Column: 8, Byte: 344}, + }, + }) diags = diags.Append(&hcl.Diagnostic{ Severity: hcl.DiagError, Summary: "Missing required provider configuration", @@ -151,6 +171,16 @@ var ( End: hcl.Pos{Line: 22, Column: 39, Byte: 402}, }, }) + diags = diags.Append(&hcl.Diagnostic{ + Severity: hcl.DiagError, + Summary: "Invalid provider configuration", + Detail: "The provider configuration slot \"testing\" requires a configuration for provider \"registry.terraform.io/hashicorp/testing\", not for provider \"terraform.io/builtin/testing\".", + Subject: &hcl.Range{ + Filename: mainBundleSourceAddrStr("with-single-input/invalid-provider-type/invalid-provider-type.tfstack.hcl"), + Start: hcl.Pos{Line: 37, Column: 15, Byte: 614}, + End: hcl.Pos{Line: 37, Column: 39, Byte: 638}, + }, + }) return diags }, },