stackup 1.4.5 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -15,7 +15,7 @@ module Stackup
15
15
 
16
16
  def s3?
17
17
  uri.scheme == "https" &&
18
- uri.host =~ /(^|\.)s3(-\w+-\w+-\d)?\.amazonaws\.com$/
18
+ uri.host =~ /(^|\.)s3((\.|-)\w+-\w+-\d)?\.amazonaws\.com$/
19
19
  end
20
20
 
21
21
  def body
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "aws-sdk-cloudformation"
2
4
  require "logger"
3
5
  require "multi_json"
@@ -16,10 +18,10 @@ module Stackup
16
18
  DEFAULT_WAIT_POLL_INTERVAL = 5 # seconds
17
19
 
18
20
  def initialize(name, client = {}, options = {})
19
- client = Aws::CloudFormation::Client.new(client) if client.is_a?(Hash)
20
- @name = name
21
+ client = Aws::CloudFormation::Client.new(client) if client.is_a?(Hash)
22
+ @name = name
21
23
  @cf_client = client
22
- @wait = true
24
+ @wait = true
23
25
  options.each do |key, value|
24
26
  public_send("#{key}=", value)
25
27
  end
@@ -117,6 +119,9 @@ module Stackup
117
119
  if (template_data = options.delete(:template))
118
120
  options[:template_body] = MultiJson.dump(template_data)
119
121
  end
122
+ # optionally override template_body with the original template to preserve formatting (& comments in YAML)
123
+ template_orig = options.delete(:template_orig)
124
+ options[:template_body] = template_orig if options.delete(:preserve)
120
125
  if (parameters = options[:parameters])
121
126
  options[:parameters] = Parameters.new(parameters).to_a
122
127
  end
@@ -282,7 +287,7 @@ module Stackup
282
287
  end
283
288
 
284
289
  def create(options)
285
- options = options.dup
290
+ options = options.dup
286
291
  options[:stack_name] = name
287
292
  options.delete(:stack_policy_during_update_body)
288
293
  options.delete(:stack_policy_during_update_url)
@@ -312,7 +317,7 @@ module Stackup
312
317
  def event_handler
313
318
  @event_handler ||= lambda do |e|
314
319
  fields = [e.logical_resource_id, e.resource_status, e.resource_status_reason]
315
- time = e.timestamp.localtime.strftime("%H:%M:%S")
320
+ time = e.timestamp.localtime.strftime("%H:%M:%S")
316
321
  logger.info("[#{time}] #{fields.compact.join(' - ')}")
317
322
  end
318
323
  end
@@ -369,7 +374,13 @@ module Stackup
369
374
  { :key => key, :value => value.to_s }
370
375
  end
371
376
  else
372
- tags
377
+ tags.map do |tag|
378
+ if tag.key?("Key")
379
+ { :key => tag["Key"], :value => tag["Value"].to_s }
380
+ else
381
+ { :key => tag[:key], :value => tag[:value].to_s }
382
+ end
383
+ end
373
384
  end
374
385
  end
375
386
 
@@ -384,8 +395,8 @@ module Stackup
384
395
  handling_cf_errors do
385
396
  {}.tap do |result|
386
397
  cf_stack.public_send(collection_name).each do |item|
387
- key = item.public_send(key_name)
388
- value = item.public_send(value_name)
398
+ key = item.public_send(key_name)
399
+ value = item.public_send(value_name)
389
400
  result[key] = value
390
401
  end
391
402
  end
@@ -1,5 +1,5 @@
1
1
  module Stackup
2
2
 
3
- VERSION = "1.4.5".freeze
3
+ VERSION = "1.7.0".freeze
4
4
 
5
5
  end
@@ -0,0 +1,56 @@
1
+ require "stackup/main_command"
2
+
3
+ describe Stackup::MainCommand do
4
+
5
+ let(:mock_change_set) { double() }
6
+
7
+ before(:example) do
8
+ mock_stackup = double()
9
+ mock_stack = double()
10
+ allow_any_instance_of(Stackup::MainCommand).to receive(:Stackup).and_return(mock_stackup)
11
+ allow(mock_stackup).to receive(:stack).and_return(mock_stack)
12
+ allow(mock_stack).to receive(:change_set).and_return(mock_change_set)
13
+ end
14
+
15
+ context "change-set create --service-role-arn" do
16
+ it "invokes stack.change_set.create with role arn passed through" do
17
+ expected_args = {
18
+ role_arn: "arn:aws:iam::000000000000:role/example"
19
+ }
20
+ expect(mock_change_set).to receive(:create).with(hash_including(expected_args))
21
+
22
+ Stackup::MainCommand.run("stackup", [
23
+ "STACK-NAME", "change-set", "create",
24
+ "--template", "examples/template.yml",
25
+ "--service-role-arn", "arn:aws:iam::000000000000:role/example"])
26
+ end
27
+ end
28
+
29
+ context "change-set create" do
30
+ it "invokes stack.change_set.create with allow_empty_change_set nil" do
31
+ expected_args = {
32
+ allow_empty_change_set: nil
33
+ }
34
+ expect(mock_change_set).to receive(:create).with(hash_including(expected_args))
35
+
36
+ Stackup::MainCommand.run("stackup", [
37
+ "STACK-NAME", "change-set", "create",
38
+ "--template", "examples/template.yml"])
39
+ end
40
+ end
41
+
42
+ context "change-set create --no-fail-on-empty-change-set" do
43
+ it "invokes stack.change_set.create with allow_empty_change_set true" do
44
+ expected_args = {
45
+ allow_empty_change_set: true
46
+ }
47
+ expect(mock_change_set).to receive(:create).with(hash_including(expected_args))
48
+
49
+ Stackup::MainCommand.run("stackup", [
50
+ "STACK-NAME", "change-set", "create",
51
+ "--template", "examples/template.yml",
52
+ "--no-fail-on-empty-change-set"])
53
+ end
54
+ end
55
+
56
+ end
@@ -1,8 +1,8 @@
1
- require 'spec_helper'
2
- require 'stackup/rake_tasks'
1
+ require "spec_helper"
2
+ require "stackup/rake_tasks"
3
3
 
4
4
  RSpec.describe Stackup::RakeTasks do
5
- it 'can be required' do
5
+ it "can be required" do
6
6
  expect(described_class).to be_truthy
7
7
  end
8
8
  end
@@ -124,6 +124,16 @@ describe Stackup::Source do
124
124
 
125
125
  end
126
126
 
127
+ context "with dot separated bucket and region" do
128
+
129
+ let(:s3_url) { "https://bucket.s3.us-east-1.amazonaws.com/cfn/template.yml" }
130
+
131
+ it "is S3" do
132
+ expect(subject).to be_s3
133
+ end
134
+
135
+ end
136
+
127
137
  end
128
138
 
129
139
  end
@@ -260,6 +260,26 @@ describe Stackup::Stack do
260
260
 
261
261
  end
262
262
 
263
+ context "with :tags in SDK form as they arrive from file" do
264
+
265
+ before do
266
+ options[:tags] = [
267
+ { "Key" => "foo", "Value" => "bar" }
268
+ ]
269
+ end
270
+
271
+ it "converts them to an Array, that uses symbols as keys" do
272
+ expected_tags = [
273
+ { :key => "foo", :value => "bar" }
274
+ ]
275
+ create_or_update
276
+ expect(cf_client).to have_received(:create_stack) do |options|
277
+ expect(options[:tags]).to eq(expected_tags)
278
+ end
279
+ end
280
+
281
+ end
282
+
263
283
  context "with :tags in SDK form" do
264
284
 
265
285
  before do
@@ -322,6 +342,23 @@ describe Stackup::Stack do
322
342
  .with(hash_including(expected_args))
323
343
  end
324
344
 
345
+ it "passes options through to :create_change_set" do
346
+ options = {
347
+ :template_body => template,
348
+ :role_arn => "service role arn"
349
+ }
350
+ expected_args = {
351
+ :stack_name => stack_name,
352
+ :change_set_name => change_set_name,
353
+ :change_set_type => "CREATE",
354
+ :template_body => template,
355
+ :role_arn => "service role arn"
356
+ }
357
+ stack.change_set(change_set_name).create(options)
358
+ expect(cf_client).to have_received(:create_change_set)
359
+ .with(hash_including(expected_args))
360
+ end
361
+
325
362
  context "with :template as data" do
326
363
 
327
364
  let(:options) do
@@ -392,6 +429,38 @@ describe Stackup::Stack do
392
429
 
393
430
  end
394
431
 
432
+ context "when allow_empty_change_set is nil and there are no changes" do
433
+ it "raises an exception" do
434
+ cf_client.stub_responses(:describe_change_set, [{
435
+ status: "FAILED",
436
+ status_reason: "The submitted information didn't contain changes. Submit different information to create a change set."
437
+ }])
438
+ expect { create_change_set }.to raise_error(Stackup::StackUpdateError)
439
+ end
440
+ end
441
+
442
+ context "when allow_empty_change_set is true and there are no changes" do
443
+ it "does not raise an exception" do
444
+ cf_client.stub_responses(:describe_change_set, [{
445
+ status: "FAILED",
446
+ status_reason: "The submitted information didn't contain changes. Submit different information to create a change set."
447
+ }])
448
+ options[:allow_empty_change_set] = true
449
+ expect { create_change_set }.not_to raise_error
450
+ end
451
+ end
452
+
453
+ context "when allow_empty_change_set is true and there is some other failure" do
454
+ it "raises an exception" do
455
+ cf_client.stub_responses(:describe_change_set, [{
456
+ status: "FAILED",
457
+ status_reason: "some other failure message"
458
+ }])
459
+ options[:allow_empty_change_set] = true
460
+ expect { create_change_set }.to raise_error(Stackup::StackUpdateError)
461
+ end
462
+ end
463
+
395
464
  end
396
465
 
397
466
  describe "#change_set#execute" do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stackup
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.5
4
+ version: 1.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Williams
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2019-10-03 00:00:00.000000000 Z
12
+ date: 2020-11-25 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: aws-sdk-cloudformation
@@ -99,6 +99,7 @@ files:
99
99
  - lib/stackup/differ.rb
100
100
  - lib/stackup/error_handling.rb
101
101
  - lib/stackup/errors.rb
102
+ - lib/stackup/main_command.rb
102
103
  - lib/stackup/parameters.rb
103
104
  - lib/stackup/rake_tasks.rb
104
105
  - lib/stackup/service.rb
@@ -109,6 +110,7 @@ files:
109
110
  - lib/stackup/version.rb
110
111
  - lib/stackup/yaml.rb
111
112
  - spec/spec_helper.rb
113
+ - spec/stackup/main_command_spec.rb
112
114
  - spec/stackup/parameters_spec.rb
113
115
  - spec/stackup/rake_tasks_spec.rb
114
116
  - spec/stackup/source_spec.rb
@@ -141,6 +143,7 @@ specification_version: 4
141
143
  summary: Manage CloudFormation stacks
142
144
  test_files:
143
145
  - spec/spec_helper.rb
146
+ - spec/stackup/main_command_spec.rb
144
147
  - spec/stackup/parameters_spec.rb
145
148
  - spec/stackup/rake_tasks_spec.rb
146
149
  - spec/stackup/source_spec.rb