Skip to content

Commit

Permalink
Merge pull request #90 from zadowsmash/add-no-fail-on-change-set-option
Browse files Browse the repository at this point in the history
add the ability to not fail on empty change set
  • Loading branch information
amcinnes authored Nov 25, 2020
2 parents 33e910f + 0c64d9e commit 6ec87da
Show file tree
Hide file tree
Showing 7 changed files with 91 additions and 11 deletions.
4 changes: 4 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# CHANGES

## 1.7.0 (2020-11-25)

* Feature: --no-fail-on-empty-change-set

## 1.6.0 (2020-11-19)

* Feature: Support --service-role-arn on "change-set create"
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,8 @@ The change-set name defaults to "pending", but can be overridden using `--name`.

The `change-set create` subcommand, like the `up` command, supports `--service-role-arn` to specify a service role.

It is impossible to create a change set with no changes. By default, stackup will only return successfully if a change set was actually created, and will otherwise fail. If the `--no-fail-on-empty-change-set` option is provided, stackup will return successfully if a change set was created _or_ if no change set was created because no changes were needed.

## Programmatic usage

Get a handle to a `Stack` object as follows:
Expand Down
9 changes: 7 additions & 2 deletions lib/stackup/change_set.rb
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ def create(options = {})
options[:change_set_name] = name
options[:change_set_type] = stack.exists? ? "UPDATE" : "CREATE"
force = options.delete(:force)
allow_empty_change_set = options.delete(:allow_empty_change_set)
options[:template_body] = MultiJson.dump(options.delete(:template)) if options[:template]
# optionally override template_body with the original template to preserve formatting (& comments in YAML)
template_orig = options.delete(:template_orig)
Expand All @@ -73,8 +74,12 @@ def create(options = {})
when /COMPLETE/
return current.status
when "FAILED"
logger.error(current.status_reason)
raise StackUpdateError, "change-set creation failed" if status == "FAILED"
if allow_empty_change_set and current.status_reason == "The submitted information didn't contain changes. Submit different information to create a change set."
return current.status_reason
else
logger.error(current.status_reason)
raise StackUpdateError, "change-set creation failed" if status == "FAILED"
end
end
sleep(wait_poll_interval)
end
Expand Down
4 changes: 4 additions & 0 deletions lib/stackup/main_command.rb
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,9 @@ def pad(s, width)
option ["--force"], :flag,
"replace existing change-set of the same name"

option ["--no-fail-on-empty-change-set"], :flag, "don't fail on empty change-set",
:attribute_name => :allow_empty_change_set

include HasParameters

option "--tags", "FILE", "stack tags file",
Expand Down Expand Up @@ -314,6 +317,7 @@ def execute
options[:role_arn] = service_role_arn if service_role_arn
options[:use_previous_template] = use_previous_template?
options[:force] = force?
options[:allow_empty_change_set] = allow_empty_change_set?
options[:capabilities] = capability_list
options[:preserve] = preserve_template_formatting?
report_change do
Expand Down
2 changes: 1 addition & 1 deletion lib/stackup/version.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module Stackup

VERSION = "1.6.0".freeze
VERSION = "1.7.0".freeze

end
49 changes: 41 additions & 8 deletions spec/stackup/main_command_spec.rb
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
require "stackup/main_command"

describe Stackup::MainCommand do
context "change-set create --service-role-arn"
it "invokes stack.change_set.create with role arn passed through" do
mock_stackup = double()
mock_stack = double()
mock_change_set = double()
allow_any_instance_of(Stackup::MainCommand).to receive(:Stackup).and_return(mock_stackup)
allow(mock_stackup).to receive(:stack).and_return(mock_stack)
allow(mock_stack).to receive(:change_set).and_return(mock_change_set)

let(:mock_change_set) { double() }

before(:example) do
mock_stackup = double()
mock_stack = double()
allow_any_instance_of(Stackup::MainCommand).to receive(:Stackup).and_return(mock_stackup)
allow(mock_stackup).to receive(:stack).and_return(mock_stack)
allow(mock_stack).to receive(:change_set).and_return(mock_change_set)
end

context "change-set create --service-role-arn" do
it "invokes stack.change_set.create with role arn passed through" do
expected_args = {
role_arn: "arn:aws:iam::000000000000:role/example"
}
Expand All @@ -20,4 +24,33 @@
"--template", "examples/template.yml",
"--service-role-arn", "arn:aws:iam::000000000000:role/example"])
end
end

context "change-set create" do
it "invokes stack.change_set.create with allow_empty_change_set nil" do
expected_args = {
allow_empty_change_set: nil
}
expect(mock_change_set).to receive(:create).with(hash_including(expected_args))

Stackup::MainCommand.run("stackup", [
"STACK-NAME", "change-set", "create",
"--template", "examples/template.yml"])
end
end

context "change-set create --no-fail-on-empty-change-set" do
it "invokes stack.change_set.create with allow_empty_change_set true" do
expected_args = {
allow_empty_change_set: true
}
expect(mock_change_set).to receive(:create).with(hash_including(expected_args))

Stackup::MainCommand.run("stackup", [
"STACK-NAME", "change-set", "create",
"--template", "examples/template.yml",
"--no-fail-on-empty-change-set"])
end
end

end
32 changes: 32 additions & 0 deletions spec/stackup/stack_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,38 @@ def create_change_set

end

context "when allow_empty_change_set is nil and there are no changes" do
it "raises an exception" do
cf_client.stub_responses(:describe_change_set, [{
status: "FAILED",
status_reason: "The submitted information didn't contain changes. Submit different information to create a change set."
}])
expect { create_change_set }.to raise_error(Stackup::StackUpdateError)
end
end

context "when allow_empty_change_set is true and there are no changes" do
it "does not raise an exception" do
cf_client.stub_responses(:describe_change_set, [{
status: "FAILED",
status_reason: "The submitted information didn't contain changes. Submit different information to create a change set."
}])
options[:allow_empty_change_set] = true
expect { create_change_set }.not_to raise_error
end
end

context "when allow_empty_change_set is true and there is some other failure" do
it "raises an exception" do
cf_client.stub_responses(:describe_change_set, [{
status: "FAILED",
status_reason: "some other failure message"
}])
options[:allow_empty_change_set] = true
expect { create_change_set }.to raise_error(Stackup::StackUpdateError)
end
end

end

describe "#change_set#execute" do
Expand Down

0 comments on commit 6ec87da

Please sign in to comment.