Skip to content

Commit 3a6509e

Browse files
committed
Move changeset functionality from diff module to aws module
The changeset files contain direct AWS SDK interactions and belong in the aws module rather than the diff module. Changes made: - Moved internal/diff/changeset.go to internal/aws/changeset.go - Moved internal/diff/changeset_test.go to internal/aws/changeset_test.go - Moved changeset types (ChangeSetInfo, ResourceChange, ChangeSetManager) from diff/types.go to aws/interfaces.go - Updated all import references throughout the codebase - Fixed package declarations and removed import cycles - Updated all test references to use aws.ChangeSetInfo and aws.ResourceChange This improves separation of concerns by keeping AWS SDK interactions in the aws module, while maintaining all existing functionality and test coverage.
1 parent 6bfef38 commit 3a6509e

File tree

9 files changed

+78
-76
lines changed

9 files changed

+78
-76
lines changed
Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
Copyright © 2025 Stackaroo Contributors
33
SPDX-License-Identifier: BSD-3-Clause
44
*/
5-
package diff
5+
package aws
66

77
import (
88
"context"
@@ -12,16 +12,15 @@ import (
1212
awssdk "github.com/aws/aws-sdk-go-v2/aws"
1313
"github.com/aws/aws-sdk-go-v2/service/cloudformation"
1414
"github.com/aws/aws-sdk-go-v2/service/cloudformation/types"
15-
"github.com/orien/stackaroo/internal/aws"
1615
)
1716

1817
// DefaultChangeSetManager implements ChangeSetManager using AWS CloudFormation
1918
type DefaultChangeSetManager struct {
20-
cfClient aws.CloudFormationOperations
19+
cfClient CloudFormationOperations
2120
}
2221

2322
// NewChangeSetManager creates a new changeset manager
24-
func NewChangeSetManager(cfClient aws.CloudFormationOperations) ChangeSetManager {
23+
func NewChangeSetManager(cfClient CloudFormationOperations) ChangeSetManager {
2524
return &DefaultChangeSetManager{
2625
cfClient: cfClient,
2726
}
Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
Copyright © 2025 Stackaroo Contributors
33
SPDX-License-Identifier: BSD-3-Clause
44
*/
5-
package diff
5+
package aws
66

77
import (
88
"context"
@@ -15,8 +15,6 @@ import (
1515
"github.com/stretchr/testify/assert"
1616
"github.com/stretchr/testify/mock"
1717
"github.com/stretchr/testify/require"
18-
19-
"github.com/orien/stackaroo/internal/aws"
2018
)
2119

2220
// Mock CloudFormation operations for changeset testing
@@ -51,34 +49,34 @@ func (m *MockChangeSetClient) ExecuteChangeSetByID(ctx context.Context, changeSe
5149

5250
// Additional methods to satisfy CloudFormationOperations
5351

54-
func (m *MockChangeSetClient) DeployStack(ctx context.Context, input aws.DeployStackInput) error {
52+
func (m *MockChangeSetClient) DeployStack(ctx context.Context, input DeployStackInput) error {
5553
args := m.Called(ctx, input)
5654
return args.Error(0)
5755
}
5856

59-
func (m *MockChangeSetClient) DeployStackWithCallback(ctx context.Context, input aws.DeployStackInput, eventCallback func(aws.StackEvent)) error {
57+
func (m *MockChangeSetClient) DeployStackWithCallback(ctx context.Context, input DeployStackInput, eventCallback func(StackEvent)) error {
6058
args := m.Called(ctx, input, eventCallback)
6159
return args.Error(0)
6260
}
6361

64-
func (m *MockChangeSetClient) UpdateStack(ctx context.Context, input aws.UpdateStackInput) error {
62+
func (m *MockChangeSetClient) UpdateStack(ctx context.Context, input UpdateStackInput) error {
6563
args := m.Called(ctx, input)
6664
return args.Error(0)
6765
}
6866

69-
func (m *MockChangeSetClient) DeleteStack(ctx context.Context, input aws.DeleteStackInput) error {
67+
func (m *MockChangeSetClient) DeleteStack(ctx context.Context, input DeleteStackInput) error {
7068
args := m.Called(ctx, input)
7169
return args.Error(0)
7270
}
7371

74-
func (m *MockChangeSetClient) GetStack(ctx context.Context, stackName string) (*aws.Stack, error) {
72+
func (m *MockChangeSetClient) GetStack(ctx context.Context, stackName string) (*Stack, error) {
7573
args := m.Called(ctx, stackName)
76-
return args.Get(0).(*aws.Stack), args.Error(1)
74+
return args.Get(0).(*Stack), args.Error(1)
7775
}
7876

79-
func (m *MockChangeSetClient) ListStacks(ctx context.Context) ([]*aws.Stack, error) {
77+
func (m *MockChangeSetClient) ListStacks(ctx context.Context) ([]*Stack, error) {
8078
args := m.Called(ctx)
81-
return args.Get(0).([]*aws.Stack), args.Error(1)
79+
return args.Get(0).([]*Stack), args.Error(1)
8280
}
8381

8482
func (m *MockChangeSetClient) ValidateTemplate(ctx context.Context, templateBody string) error {
@@ -96,17 +94,17 @@ func (m *MockChangeSetClient) GetTemplate(ctx context.Context, stackName string)
9694
return args.String(0), args.Error(1)
9795
}
9896

99-
func (m *MockChangeSetClient) DescribeStack(ctx context.Context, stackName string) (*aws.StackInfo, error) {
97+
func (m *MockChangeSetClient) DescribeStack(ctx context.Context, stackName string) (*StackInfo, error) {
10098
args := m.Called(ctx, stackName)
101-
return args.Get(0).(*aws.StackInfo), args.Error(1)
99+
return args.Get(0).(*StackInfo), args.Error(1)
102100
}
103101

104-
func (m *MockChangeSetClient) DescribeStackEvents(ctx context.Context, stackName string) ([]aws.StackEvent, error) {
102+
func (m *MockChangeSetClient) DescribeStackEvents(ctx context.Context, stackName string) ([]StackEvent, error) {
105103
args := m.Called(ctx, stackName)
106-
return args.Get(0).([]aws.StackEvent), args.Error(1)
104+
return args.Get(0).([]StackEvent), args.Error(1)
107105
}
108106

109-
func (m *MockChangeSetClient) WaitForStackOperation(ctx context.Context, stackName string, eventCallback func(aws.StackEvent)) error {
107+
func (m *MockChangeSetClient) WaitForStackOperation(ctx context.Context, stackName string, eventCallback func(StackEvent)) error {
110108
args := m.Called(ctx, stackName, eventCallback)
111109
return args.Error(0)
112110
}

internal/aws/interfaces.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,27 @@ type CloudFormationOperations interface {
6161
DescribeStackEvents(ctx context.Context, stackName string) ([]StackEvent, error)
6262
WaitForStackOperation(ctx context.Context, stackName string, eventCallback func(StackEvent)) error
6363
}
64+
65+
// ChangeSetInfo contains information from AWS CloudFormation changeset
66+
type ChangeSetInfo struct {
67+
ChangeSetID string
68+
Status string
69+
Changes []ResourceChange
70+
}
71+
72+
// ResourceChange represents a change to a CloudFormation resource
73+
type ResourceChange struct {
74+
Action string // CREATE, UPDATE, DELETE
75+
ResourceType string
76+
LogicalID string
77+
PhysicalID string
78+
Replacement string // True, False, or Conditional
79+
Details []string
80+
}
81+
82+
// ChangeSetManager handles AWS CloudFormation changeset operations
83+
type ChangeSetManager interface {
84+
CreateChangeSet(ctx context.Context, stackName string, template string, parameters map[string]string) (*ChangeSetInfo, error)
85+
CreateChangeSetForDeployment(ctx context.Context, stackName string, template string, parameters map[string]string, capabilities []string, tags map[string]string) (*ChangeSetInfo, error)
86+
DeleteChangeSet(ctx context.Context, changeSetID string) error
87+
}

internal/deploy/deployer.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ func (d *AWSDeployer) deployWithChangeSet(ctx context.Context, stack *model.Stac
142142
if err != nil {
143143
// Clean up changeset on error
144144
if diffResult.ChangeSet != nil {
145-
changeSetMgr := diff.NewChangeSetManager(cfnOps)
145+
changeSetMgr := aws.NewChangeSetManager(cfnOps)
146146
_ = changeSetMgr.DeleteChangeSet(ctx, diffResult.ChangeSet.ChangeSetID)
147147
}
148148
return fmt.Errorf("failed to get user confirmation: %w", err)
@@ -151,7 +151,7 @@ func (d *AWSDeployer) deployWithChangeSet(ctx context.Context, stack *model.Stac
151151
if !confirmed {
152152
// Clean up changeset when user cancels
153153
if diffResult.ChangeSet != nil {
154-
changeSetMgr := diff.NewChangeSetManager(cfnOps)
154+
changeSetMgr := aws.NewChangeSetManager(cfnOps)
155155
_ = changeSetMgr.DeleteChangeSet(ctx, diffResult.ChangeSet.ChangeSetID)
156156
}
157157
fmt.Printf("Deployment cancelled for stack %s\n", stack.Name)
@@ -167,7 +167,7 @@ func (d *AWSDeployer) deployWithChangeSet(ctx context.Context, stack *model.Stac
167167
return fmt.Errorf("no changeset available for deployment")
168168
}
169169
changeSetInfo := diffResult.ChangeSet
170-
changeSetMgr := diff.NewChangeSetManager(cfnOps)
170+
changeSetMgr := aws.NewChangeSetManager(cfnOps)
171171

172172
// Execute the changeset
173173
fmt.Printf("=== Deploying stack %s ===\n", stack.Name)

internal/diff/differ.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ type DefaultDiffer struct {
1818
templateComparator TemplateComparator
1919
parameterComparator ParameterComparator
2020
tagComparator TagComparator
21-
changeSetManager ChangeSetManager
21+
changeSetManager aws.ChangeSetManager
2222
}
2323

2424
// NewDefaultDiffer creates a new DefaultDiffer with AWS integration
@@ -34,7 +34,7 @@ func NewDefaultDiffer(ctx context.Context) (*DefaultDiffer, error) {
3434
templateComparator: NewYAMLTemplateComparator(),
3535
parameterComparator: NewParameterComparator(),
3636
tagComparator: NewTagComparator(),
37-
changeSetManager: NewChangeSetManager(cfClient),
37+
changeSetManager: aws.NewChangeSetManager(cfClient),
3838
}, nil
3939
}
4040

@@ -45,7 +45,7 @@ func NewDiffer(cfClient aws.CloudFormationOperations) *DefaultDiffer {
4545
templateComparator: NewYAMLTemplateComparator(),
4646
parameterComparator: NewParameterComparator(),
4747
tagComparator: NewTagComparator(),
48-
changeSetManager: NewChangeSetManager(cfClient),
48+
changeSetManager: aws.NewChangeSetManager(cfClient),
4949
}
5050
}
5151

@@ -187,15 +187,15 @@ func (d *DefaultDiffer) compareTags(currentStack *aws.StackInfo, stack *model.St
187187
}
188188

189189
// generateChangeSet creates an AWS changeset to preview changes
190-
func (d *DefaultDiffer) generateChangeSet(ctx context.Context, stack *model.Stack, options Options) (*ChangeSetInfo, error) {
190+
func (d *DefaultDiffer) generateChangeSet(ctx context.Context, stack *model.Stack, options Options) (*aws.ChangeSetInfo, error) {
191191
// Get proposed template content
192192
templateContent, err := stack.GetTemplateContent()
193193
if err != nil {
194194
return nil, fmt.Errorf("failed to get template content: %w", err)
195195
}
196196

197197
// Create changeset - use deployment version if we need to keep it alive
198-
var changeSetInfo *ChangeSetInfo
198+
var changeSetInfo *aws.ChangeSetInfo
199199
if options.KeepChangeSet {
200200
// Use deployment-style changeset that doesn't auto-delete
201201
capabilities := stack.Capabilities

internal/diff/differ_test.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -140,14 +140,14 @@ type MockChangeSetManager struct {
140140
mock.Mock
141141
}
142142

143-
func (m *MockChangeSetManager) CreateChangeSet(ctx context.Context, stackName string, template string, parameters map[string]string) (*ChangeSetInfo, error) {
143+
func (m *MockChangeSetManager) CreateChangeSet(ctx context.Context, stackName string, template string, parameters map[string]string) (*aws.ChangeSetInfo, error) {
144144
args := m.Called(ctx, stackName, template, parameters)
145-
return args.Get(0).(*ChangeSetInfo), args.Error(1)
145+
return args.Get(0).(*aws.ChangeSetInfo), args.Error(1)
146146
}
147147

148-
func (m *MockChangeSetManager) CreateChangeSetForDeployment(ctx context.Context, stackName string, template string, parameters map[string]string, capabilities []string, tags map[string]string) (*ChangeSetInfo, error) {
148+
func (m *MockChangeSetManager) CreateChangeSetForDeployment(ctx context.Context, stackName string, template string, parameters map[string]string, capabilities []string, tags map[string]string) (*aws.ChangeSetInfo, error) {
149149
args := m.Called(ctx, stackName, template, parameters, capabilities, tags)
150-
return args.Get(0).(*ChangeSetInfo), args.Error(1)
150+
return args.Get(0).(*aws.ChangeSetInfo), args.Error(1)
151151
}
152152

153153
func (m *MockChangeSetManager) DeleteChangeSet(ctx context.Context, changeSetID string) error {
@@ -157,7 +157,7 @@ func (m *MockChangeSetManager) DeleteChangeSet(ctx context.Context, changeSetID
157157

158158
// Test helper functions
159159

160-
func createTestDiffer(cfClient *MockCloudFormationClient, templateComp *MockTemplateComparator, paramComp *MockParameterComparator, tagComp *MockTagComparator, changeSetMgr *MockChangeSetManager) *DefaultDiffer {
160+
func createTestDiffer(cfClient *MockCloudFormationClient, templateComp *MockTemplateComparator, paramComp *MockParameterComparator, tagComp *MockTagComparator, changeSetMgr aws.ChangeSetManager) *DefaultDiffer {
161161
return &DefaultDiffer{
162162
cfClient: cfClient,
163163
templateComparator: templateComp,
@@ -305,10 +305,10 @@ func TestDefaultDiffer_DiffStack_ExistingStack_WithChanges(t *testing.T) {
305305
tagComp.On("Compare", currentStack.Tags, stack.Tags).Return(tagDiffs, nil)
306306

307307
// Mock changeset creation
308-
changeSet := &ChangeSetInfo{
308+
changeSet := &aws.ChangeSetInfo{
309309
ChangeSetID: "test-changeset-id",
310310
Status: "CREATE_COMPLETE",
311-
Changes: []ResourceChange{
311+
Changes: []aws.ResourceChange{
312312
{Action: "Modify", ResourceType: "AWS::S3::Bucket", LogicalID: "MyBucket"},
313313
},
314314
}
@@ -561,7 +561,7 @@ func TestDefaultDiffer_DiffStack_ChangeSetError(t *testing.T) {
561561
tagComp.On("Compare", currentStack.Tags, stack.Tags).Return([]TagDiff{}, nil)
562562

563563
// Mock changeset creation failure
564-
changeSetMgr.On("CreateChangeSet", ctx, "test-stack", stack.TemplateBody, stack.Parameters).Return((*ChangeSetInfo)(nil), errors.New("changeset failed"))
564+
changeSetMgr.On("CreateChangeSet", ctx, "test-stack", stack.TemplateBody, stack.Parameters).Return((*aws.ChangeSetInfo)(nil), errors.New("changeset failed"))
565565

566566
// Execute
567567
result, err := differ.DiffStack(ctx, stack, options)

internal/diff/output_test.go

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import (
1111

1212
"github.com/stretchr/testify/assert"
1313
"github.com/stretchr/testify/require"
14+
15+
"github.com/orien/stackaroo/internal/aws"
1416
)
1517

1618
func TestResult_String_TextFormat(t *testing.T) {
@@ -100,10 +102,10 @@ func TestResult_ToText_WithChanges(t *testing.T) {
100102
TagDiffs: []TagDiff{
101103
{Key: "Environment", CurrentValue: "staging", ProposedValue: "dev", ChangeType: ChangeTypeModify},
102104
},
103-
ChangeSet: &ChangeSetInfo{
105+
ChangeSet: &aws.ChangeSetInfo{
104106
ChangeSetID: "test-changeset-123",
105107
Status: "CREATE_COMPLETE",
106-
Changes: []ResourceChange{
108+
Changes: []aws.ResourceChange{
107109
{
108110
Action: "Modify",
109111
ResourceType: "AWS::EC2::Instance",
@@ -220,10 +222,10 @@ func TestResult_ToJSON_Complete(t *testing.T) {
220222
TagDiffs: []TagDiff{
221223
{Key: "Env", CurrentValue: "dev", ProposedValue: "prod", ChangeType: ChangeTypeModify},
222224
},
223-
ChangeSet: &ChangeSetInfo{
225+
ChangeSet: &aws.ChangeSetInfo{
224226
ChangeSetID: "changeset-123",
225227
Status: "CREATE_COMPLETE",
226-
Changes: []ResourceChange{
228+
Changes: []aws.ResourceChange{
227229
{Action: "Modify", ResourceType: "AWS::S3::Bucket", LogicalID: "MyBucket"},
228230
},
229231
},
@@ -458,10 +460,10 @@ func TestResult_FormatTagChangesText(t *testing.T) {
458460

459461
func TestResult_FormatChangeSetText(t *testing.T) {
460462
result := &Result{
461-
ChangeSet: &ChangeSetInfo{
463+
ChangeSet: &aws.ChangeSetInfo{
462464
ChangeSetID: "test-changeset-456",
463465
Status: "CREATE_COMPLETE",
464-
Changes: []ResourceChange{
466+
Changes: []aws.ResourceChange{
465467
{
466468
Action: "Add",
467469
ResourceType: "AWS::S3::Bucket",

internal/diff/types.go

Lines changed: 3 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package diff
77
import (
88
"context"
99

10+
"github.com/orien/stackaroo/internal/aws"
1011
"github.com/orien/stackaroo/internal/model"
1112
)
1213

@@ -38,8 +39,8 @@ type Result struct {
3839
TemplateChange *TemplateChange
3940
ParameterDiffs []ParameterDiff
4041
TagDiffs []TagDiff
41-
ChangeSet *ChangeSetInfo // AWS changeset information when available
42-
Options Options // Options used for this diff
42+
ChangeSet *aws.ChangeSetInfo // AWS changeset information when available
43+
Options Options // Options used for this diff
4344
}
4445

4546
// HasChanges returns true if any changes were detected
@@ -109,23 +110,6 @@ const (
109110
ChangeTypeRemove ChangeType = "REMOVE"
110111
)
111112

112-
// ChangeSetInfo contains information from AWS CloudFormation changeset
113-
type ChangeSetInfo struct {
114-
ChangeSetID string
115-
Status string
116-
Changes []ResourceChange
117-
}
118-
119-
// ResourceChange represents a change to a CloudFormation resource
120-
type ResourceChange struct {
121-
Action string // CREATE, UPDATE, DELETE
122-
ResourceType string
123-
LogicalID string
124-
PhysicalID string
125-
Replacement string // True, False, or Conditional
126-
Details []string
127-
}
128-
129113
// Comparator interfaces for different types of comparisons
130114

131115
// TemplateComparator handles CloudFormation template comparisons
@@ -142,10 +126,3 @@ type ParameterComparator interface {
142126
type TagComparator interface {
143127
Compare(currentTags, proposedTags map[string]string) ([]TagDiff, error)
144128
}
145-
146-
// ChangeSetManager handles AWS CloudFormation changeset operations
147-
type ChangeSetManager interface {
148-
CreateChangeSet(ctx context.Context, stackName string, template string, parameters map[string]string) (*ChangeSetInfo, error)
149-
CreateChangeSetForDeployment(ctx context.Context, stackName string, template string, parameters map[string]string, capabilities []string, tags map[string]string) (*ChangeSetInfo, error)
150-
DeleteChangeSet(ctx context.Context, changeSetID string) error
151-
}

0 commit comments

Comments
 (0)