From 96c19f86d31324ca8542df253c96b7e3b1c16920 Mon Sep 17 00:00:00 2001 From: kzcat Date: Thu, 18 Dec 2025 08:46:05 +0900 Subject: [PATCH] Support Early Validation --- internal/aws/cfn/cfn.go | 50 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/internal/aws/cfn/cfn.go b/internal/aws/cfn/cfn.go index 8d359647..98dac6da 100644 --- a/internal/aws/cfn/cfn.go +++ b/internal/aws/cfn/cfn.go @@ -282,6 +282,35 @@ func GetStackEvents(stackName string) ([]types.StackEvent, error) { return events, nil } + +// GetChangeSetEvents returns all events associated with the named changeset +func GetChangeSetEvents(changeSetId string) ([]types.OperationEvent, error) { + events := make([]types.OperationEvent, 0) + + var token *string + + for { + res, err := getClient().DescribeEvents(context.Background(), &cloudformation.DescribeEventsInput{ + NextToken: token, + ChangeSetName: &changeSetId, + }) + + if err != nil { + return events, err + } + + events = append(events, res.OperationEvents...) + + if res.NextToken == nil { + break + } + + token = res.NextToken + } + + return events, nil +} + type ChangeSetContext struct { Template *cft.Template Params []types.Parameter @@ -378,6 +407,27 @@ func CreateChangeSet(ctx *ChangeSetContext) (string, error) { config.Debugf("ChangeSet status: %s", status) if status == "FAILED" { + // Get validation errors if available + if res.ChangeSetId != nil { + events, eventsErr := GetChangeSetEvents(*res.ChangeSetId) + if eventsErr == nil { + var validationErrors []string + for _, event := range events { + if event.EventType == types.EventTypeValidationError { + validationErrors = append(validationErrors, fmt.Sprintf("Resource: %s (%s), Validation: %s, Reason: %s", + ptr.ToString(event.LogicalResourceId), + ptr.ToString(event.ResourceType), + ptr.ToString(event.ValidationName), + ptr.ToString(event.ValidationStatusReason))) + } + } + if len(validationErrors) > 0 { + return changeSetName, fmt.Errorf("changeset creation failed with validation errors:\n - %s", strings.Join(validationErrors, "\n - ")) + } + } else { + config.Debugf("could not get changeset events: %v", eventsErr) + } + } return changeSetName, errors.New(ptr.ToString(res.StatusReason)) }