Skip to content

Commit 00a9825

Browse files
committed
Improve user feedback when CloudFormation reports no changes
When CloudFormation returns 'no changes' errors during apply, provide a clearer explanation that while the template may have differences (e.g., whitespace, comments, formatting), no actual resource changes are needed and the stack is already in the desired state. This addresses the confusing scenario where users see a template diff but CloudFormation reports: 'The submitted information didn't contain changes. Submit different information to create a change set.' Changes: - Add user_friendly_changeset_error method to detect common 'no changes' error messages and provide helpful context - Update both create and update stack flows to use the improved message - Add comprehensive tests covering various CloudFormation error messages
1 parent 51457b6 commit 00a9825

File tree

3 files changed

+53
-5
lines changed

3 files changed

+53
-5
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,14 @@ The format is based on [Keep a Changelog], and this project adheres to
1212

1313
### Changed
1414

15+
- Improve message when CloudFormation claims there are no changes to apply, even when a template diff is present. ([#398])
1516
- Display Tags diff (stack tags) in `stack_master diff` and `stack_master apply` commands. ([#397])
1617
- Resolve style issues identified by RuboCop. ([#396])
1718

1819
[Unreleased]: https://github.com/envato/stack_master/compare/v2.17.1...HEAD
1920
[#396]: https://github.com/envato/stack_master/pull/396
2021
[#397]: https://github.com/envato/stack_master/pull/397
22+
[#398]: https://github.com/envato/stack_master/pull/398
2123

2224
## [2.17.1] - 2025-12-19
2325

lib/stack_master/commands/apply.rb

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ def create_stack_by_change_set
8989
@change_set = ChangeSet.create(stack_options.merge(change_set_type: 'CREATE'))
9090
if @change_set.failed?
9191
ChangeSet.delete(@change_set.id)
92-
halt!(@change_set.status_reason)
92+
halt!(user_friendly_changeset_error(@change_set.status_reason))
9393
end
9494

9595
@change_set.display(StackMaster.stdout)
@@ -123,7 +123,7 @@ def update_stack
123123
@change_set = ChangeSet.create(stack_options)
124124
if @change_set.failed?
125125
ChangeSet.delete(@change_set.id)
126-
halt!(@change_set.status_reason)
126+
halt!(user_friendly_changeset_error(@change_set.status_reason))
127127
end
128128

129129
@change_set.display(StackMaster.stdout)
@@ -230,6 +230,21 @@ def set_stack_policy
230230
StackMaster.stdout.puts 'done.'
231231
end
232232

233+
def user_friendly_changeset_error(status_reason)
234+
# CloudFormation returns various messages when there are no changes to apply
235+
if status_reason =~ /didn'?t contain changes|no changes|no updates are to be performed/i
236+
<<~MESSAGE.chomp
237+
#{status_reason}
238+
239+
While there may be differences in the template file (e.g., whitespace, comments, or
240+
formatting), CloudFormation has determined that no actual resource changes are needed.
241+
The stack is already in the desired state.
242+
MESSAGE
243+
else
244+
status_reason
245+
end
246+
end
247+
233248
extend Forwardable
234249
def_delegators :@stack_definition, :stack_name, :region
235250
end

spec/stack_master/commands/apply_spec.rb

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,11 +127,42 @@ def apply
127127
before do
128128
allow(StackMaster::ChangeSet).to receive(:delete)
129129
allow(change_set).to receive(:failed?).and_return(true)
130-
allow(change_set).to receive(:status_reason).and_return('reason')
131130
end
132131

133-
it 'outputs the status reason' do
134-
expect { apply }.to output(/reason/).to_stdout
132+
context 'with a generic error' do
133+
before do
134+
allow(change_set).to receive(:status_reason).and_return('reason')
135+
end
136+
137+
it 'outputs the status reason' do
138+
expect { apply }.to output(/reason/).to_stdout
139+
end
140+
end
141+
142+
context 'with a "no changes" error from CloudFormation' do
143+
before do
144+
allow(change_set)
145+
.to receive(:status_reason)
146+
.and_return("The submitted information didn't contain changes. " \
147+
'Submit different information to create a change set.')
148+
end
149+
150+
it 'outputs a user-friendly explanation' do
151+
expect { apply }.to output(/The submitted information didn't contain changes/).to_stdout
152+
expect { apply }.to output(/no actual resource changes are needed/).to_stdout
153+
expect { apply }.to output(/stack is already in the desired state/).to_stdout
154+
end
155+
end
156+
157+
context 'with alternative "no changes" error message' do
158+
before do
159+
allow(change_set).to receive(:status_reason).and_return('No updates are to be performed.')
160+
end
161+
162+
it 'outputs a user-friendly explanation' do
163+
expect { apply }.to output(/No updates are to be performed/).to_stdout
164+
expect { apply }.to output(/no actual resource changes are needed/).to_stdout
165+
end
135166
end
136167
end
137168

0 commit comments

Comments
 (0)