stacks: send progress events on failed provider configurations

This commit is contained in:
Daniel Schmidt 2026-01-05 17:05:51 +01:00
parent 59b84c820e
commit f9e6396d7b
No known key found for this signature in database
GPG key ID: 377C3A4D62FBBBE2
6 changed files with 106 additions and 0 deletions

View file

@ -0,0 +1,5 @@
kind: BUG FIXES
body: 'stacks: send progress events if the plan fails for better UI integration'
time: 2026-01-05T17:06:48.252069+01:00
custom:
Issue: "38039"

View file

@ -810,6 +810,69 @@ func TestStackChangeProgress(t *testing.T) {
},
},
},
"invalid": {
source: "git::https://example.com/invalid.git",
store: stacks_testing_provider.NewResourceStoreBuilder().
AddResource("resource", cty.ObjectVal(map[string]cty.Value{
"id": cty.StringVal("resource"),
"value": cty.NullVal(cty.String),
})).
Build(),
state: []stackstate.AppliedChange{
&stackstate.AppliedChangeComponentInstance{
ComponentAddr: mustAbsComponent(t, "component.self"),
ComponentInstanceAddr: mustAbsComponentInstance(t, "component.self"),
},
&stackstate.AppliedChangeResourceInstanceObject{
ResourceInstanceObjectAddr: mustAbsResourceInstanceObject(t, "component.self.testing_resource.resource"),
NewStateSrc: &states.ResourceInstanceObjectSrc{
AttrsJSON: mustMarshalJSONAttrs(map[string]interface{}{
"id": "resource",
"value": nil,
}),
Status: states.ObjectReady,
},
ProviderConfigAddr: mustDefaultRootProvider("testing"),
Schema: stacks_testing_provider.TestingResourceSchema,
},
},
want: []*stacks.StackChangeProgress{
{
Event: &stacks.StackChangeProgress_ResourceInstanceStatus_{
ResourceInstanceStatus: &stacks.StackChangeProgress_ResourceInstanceStatus{
Addr: &stacks.ResourceInstanceObjectInStackAddr{
ComponentInstanceAddr: "component.self",
ResourceInstanceAddr: "testing_resource.resource",
},
Status: stacks.StackChangeProgress_ResourceInstanceStatus_ERRORED,
},
},
},
{
Event: &stacks.StackChangeProgress_ComponentInstanceStatus_{
ComponentInstanceStatus: &stacks.StackChangeProgress_ComponentInstanceStatus{
Addr: &stacks.ComponentInstanceInStackAddr{
ComponentAddr: "component.self",
ComponentInstanceAddr: "component.self",
},
Status: stacks.StackChangeProgress_ComponentInstanceStatus_ERRORED,
},
},
},
},
diagnostics: []*terraform1.Diagnostic{
{
Severity: terraform1.Diagnostic_ERROR,
Summary: "invalid configuration",
Detail: "configure_error attribute was set",
},
{
Severity: terraform1.Diagnostic_ERROR,
Summary: "Provider configuration is invalid",
Detail: "Cannot decode the prior state for this resource instance because its provider configuration is invalid.",
},
},
},
}
for name, tc := range tcs {

View file

@ -0,0 +1,10 @@
terraform {
required_providers {
testing = {
source = "hashicorp/testing"
version = "0.1.0"
}
}
}
resource "testing_resource" "resource" {}

View file

@ -0,0 +1,21 @@
required_providers {
testing = {
source = "hashicorp/testing"
version = "0.1.0"
}
}
provider "testing" "default" {
config {
// This provider is going to fail to configure.
configure_error = "invalid configuration"
}
}
component "self" {
source = "./"
providers = {
testing = provider.testing.default
}
}

View file

@ -30,6 +30,11 @@
"source": "git::https://example.com/removed.git",
"local": "removed",
"meta": {}
},
{
"source": "git::https://example.com/invalid.git",
"local": "invalid",
"meta": {}
}
]
}

View file

@ -351,6 +351,8 @@ func (c *ComponentInstance) CheckModuleTreePlan(ctx context.Context) (*plans.Pla
ReportComponentInstance(ctx, plan, h, seq, c)
if plan.Complete {
hookMore(ctx, seq, h.EndComponentInstancePlan, c.Addr())
} else if plan.Errored {
hookMore(ctx, seq, h.ErrorComponentInstancePlan, c.Addr())
} else {
hookMore(ctx, seq, h.DeferComponentInstancePlan, c.Addr())
}