diff --git a/internal/provider/template_resource.go b/internal/provider/template_resource.go index f053773..3cab62f 100644 --- a/internal/provider/template_resource.go +++ b/internal/provider/template_resource.go @@ -1049,7 +1049,36 @@ func (d *versionsPlanModifier) PlanModifyList(ctx context.Context, req planmodif return } - resp.PlanValue, diag = types.ListValueFrom(ctx, req.PlanValue.ElementType(ctx), planVersions) + // Now patch the original plan elements with only the fields we changed + planElements := req.PlanValue.Elements() + newElements := make([]attr.Value, len(planElements)) + + for i, elem := range planElements { + obj, ok := elem.(types.Object) + if !ok { + resp.Diagnostics.AddError("Client Error", "Expected object element in versions list") + return + } + + attrs := obj.Attributes() + attrTypes := obj.AttributeTypes(ctx) + + // Overwrite only the fields the plan modifier manages + attrs["id"] = planVersions[i].ID + attrs["name"] = planVersions[i].Name + attrs["directory_hash"] = planVersions[i].DirectoryHash + + // tf_vars, provisioner_tags, directory, active, message — all untouched + + newObj, objDiag := types.ObjectValue(attrTypes, attrs) + if objDiag.HasError() { + resp.Diagnostics.Append(objDiag...) + return + } + newElements[i] = newObj + } + + resp.PlanValue, diag = types.ListValue(req.PlanValue.ElementType(ctx), newElements) if diag.HasError() { resp.Diagnostics.Append(diag...) } @@ -1517,7 +1546,7 @@ func (planVersions Versions) reconcileVersionIDs(lv LastVersionsByHash, configVe prevList := lv[planVersions[i].DirectoryHash.ValueString()] if len(prevList) > 0 && planVersions[i].ID.IsUnknown() { planVersions[i].ID = UUIDValue(prevList[0].ID) - if planVersions[i].Name.IsUnknown() { + if configVersions[i].Name.IsNull() { planVersions[i].Name = types.StringValue(prevList[0].Name) } lv[planVersions[i].DirectoryHash.ValueString()] = prevList[1:] diff --git a/internal/provider/template_resource_test.go b/internal/provider/template_resource_test.go index 971de6e..f1ba360 100644 --- a/internal/provider/template_resource_test.go +++ b/internal/provider/template_resource_test.go @@ -1388,6 +1388,8 @@ func TestReconcileVersionIDs(t *testing.T) { }, }, { + // Config name is null (auto-generated), plan name is unknown. + // Should backfill name from state since the user didn't set one. Name: "UnknownUsesStateInOrder", planVersions: []TemplateVersion{ { @@ -1408,7 +1410,7 @@ func TestReconcileVersionIDs(t *testing.T) { Name: types.StringValue("foo"), }, { - Name: types.StringValue("bar"), + Name: types.StringNull(), }, }, inputState: map[string][]PreviousTemplateVersion{ @@ -1440,6 +1442,62 @@ func TestReconcileVersionIDs(t *testing.T) { }, }, }, + { + // Config name is non-null (e.g. random_uuid.result), plan name is unknown + // because the upstream resource is being recreated. + // Should NOT backfill name — leave it unknown to resolve after apply. + Name: "UnknownNonNullConfigNameNotBackfilled", + planVersions: []TemplateVersion{ + { + Name: types.StringValue("foo"), + DirectoryHash: types.StringValue("aaa"), + ID: NewUUIDUnknown(), + TerraformVariables: []Variable{}, + }, + { + Name: types.StringUnknown(), + DirectoryHash: types.StringValue("aaa"), + ID: NewUUIDUnknown(), + TerraformVariables: []Variable{}, + }, + }, + configVersions: []TemplateVersion{ + { + Name: types.StringValue("foo"), + }, + { + Name: types.StringValue("bar"), + }, + }, + inputState: map[string][]PreviousTemplateVersion{ + "aaa": { + { + ID: aUUID, + Name: "qux", + TFVars: map[string]string{}, + }, + { + ID: bUUID, + Name: "baz", + TFVars: map[string]string{}, + }, + }, + }, + expectedVersions: []TemplateVersion{ + { + Name: types.StringValue("foo"), + DirectoryHash: types.StringValue("aaa"), + ID: UUIDValue(aUUID), + TerraformVariables: []Variable{}, + }, + { + Name: types.StringUnknown(), + DirectoryHash: types.StringValue("aaa"), + ID: UUIDValue(bUUID), + TerraformVariables: []Variable{}, + }, + }, + }, { Name: "NewVersionNewRandomName", planVersions: []TemplateVersion{