cfn-flow 0.0.1 → 0.0.3

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9b11eb9cc9a03afce395768b4e29f5b59764646f
4
- data.tar.gz: 18fa02cf2b9834e8ab4c870d23ecb548dfd7a064
3
+ metadata.gz: badcc4a2c292d0183d5af25a50c9fd8837c9d22f
4
+ data.tar.gz: e176fe7a536d22fda562e993d30f656aa142fa7d
5
5
  SHA512:
6
- metadata.gz: 81a7ce12e778b4b5beb6fd566143900ec6a9803b19f56a9b4b4700dd65d4128a792ec9f48be6a3741c329f24ad5a7c3023a2288c4a80014c836a86348910266a
7
- data.tar.gz: 01491f61b53acc8ece495146a7e8b9864f96dd897ec7fc4465ce97910d773ba88fd04da9952abd9db7a1314eeb3630ae533276b465b0b67866354163166b9365
6
+ metadata.gz: 488423d2988b714671702d0c27386aacdca6b63c890172f390d9300f28cd5334e99aa8279685b2a0dd2dc74d72c45096a23ed3fce136c645dbf1f3f698e02726
7
+ data.tar.gz: 7728d38cb7d74beaad45675d7df8d983f3d99763a1708164fa80244eb00f33d715cbb3cac096c1f864339260a4346b7bf9490820139ffe9c088f96f66d2563f7
data/README.md CHANGED
@@ -76,22 +76,25 @@ environment variables are overridden by command line arguments.
76
76
 
77
77
  ```
78
78
  # cfn-flow.yml in the root of your project
79
+ # You can specify an alternative path by setting the CFN_FLOW_CONFIG environment
80
+ # variable.
81
+ #
79
82
  # All options in this config can be overridden with command line arguments
80
83
  ---
81
84
  # S3 bucket where templates are uploaded. No default.
82
- # Override with CFN_FLOW_BUCKET
85
+ # Override with CFN_FLOW_BUCKET env var
83
86
  bucket: 'my-s3-bucket'
84
87
 
85
88
  # S3 path prefix. Default: none
86
- # Override with CFN_FLOW_TO
89
+ # Override with CFN_FLOW_TO env var
87
90
  to: my/project/prefix
88
91
 
89
92
  # Local path in which to recursively search for templates. Default: .
90
- # Override with CFN_FLOW_FROM
93
+ # Override with CFN_FLOW_FROM env var
91
94
  from: my/local/prefix
92
95
 
93
96
  # AWS Region
94
- # Override with AWS_REGION
97
+ # Override with AWS_REGION env var
95
98
  region: us-east-1 # AWS region
96
99
  ```
97
100
 
@@ -122,7 +125,7 @@ resources](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-pro
122
125
  "Type" : "AWS::CloudFormation::Stack",
123
126
  "Properties" : {
124
127
  "TemplateURL" : {
125
- "Fn::Join" : [ ":",r
128
+ "Fn::Join" : [ ":",
126
129
  [ "https://s3.amazonaws.com/my-bucket", {"Ref": "prefix"}, "my-template.json" ]
127
130
  ]
128
131
  }
@@ -130,4 +133,12 @@ resources](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-pro
130
133
  }
131
134
  ```
132
135
 
133
- While testing, set the `prefix` parameter to dev prefix like `dev/aaron`. When you're confident your changes work, release them with cfn-flow and change the `prefix` parameter to `release/1.0.0` for production.
136
+ While testing, set the `prefix` parameter to a dev prefix like `dev/aaron`. When you're confident your changes work, release them with cfn-flow and change the `prefix` parameter to `release/1.0.0` for production.
137
+
138
+ #### Continuous integration
139
+
140
+ #### Github commit status
141
+
142
+ #### Minimal AWS credentials
143
+
144
+ TODO: example IAM policy
data/Rakefile CHANGED
@@ -1,18 +1,9 @@
1
1
  require "rubygems"
2
2
  require "bundler/setup"
3
+ require "bundler/gem_tasks"
3
4
  require 'rake/testtask'
4
5
 
5
- namespace :test do
6
- Rake::TestTask.new(:units) do |t|
7
- t.pattern = "spec/*_spec.rb"
8
- end
9
-
10
- Rake::TestTask.new(:integration) do |t|
11
- t.pattern = "spec/integration/*_spec.rb"
12
- end
6
+ Rake::TestTask.new do |t|
7
+ t.pattern = "spec/*_spec.rb"
13
8
  end
14
-
15
- desc 'Run tests'
16
- task :test => %w[test:units test:integration]
17
-
18
9
  task :default => :test
@@ -1,3 +1,4 @@
1
1
  #!/usr/bin/env ruby
2
+
2
3
  require 'cfn-flow'
3
- CfnFlow.start
4
+ CfnFlow::CLI.start
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'rake' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('rake', 'rake')
@@ -3,141 +3,7 @@ require 'aws-sdk'
3
3
  require 'multi_json'
4
4
  require 'yaml'
5
5
 
6
- class CfnFlow < Thor
7
- class GitError < StandardError; end
8
-
9
- require 'cfn-flow/template'
10
- def self.shared_options
11
-
12
- method_option :bucket, type: :string, desc: 'S3 bucket for templates'
13
- method_option :to, type: :string, desc: 'S3 path prefix for templates'
14
- method_option :from, type: :string, desc: 'Local source directory for templates'
15
- method_option 'dev-name', type: :string, desc: 'Personal development prefix'
16
- method_option :region, type: :string, desc: 'AWS Region'
17
-
18
- method_option :verbose, type: :boolean, desc: 'Verbose output', default: false
19
- end
20
-
21
- no_commands do
22
- def load_config
23
- defaults = { 'from' => '.' }
24
- file_config = begin
25
- YAML.load_file('./cfn-flow.yml')
26
- rescue Errno::ENOENT
27
- {}
28
- end
29
- env_config = {
30
- 'bucket' => ENV['CFN_FLOW_BUCKET'],
31
- 'to' => ENV['CFN_FLOW_TO'],
32
- 'from' => ENV['CFN_FLOW_FROM'],
33
- 'dev-name' => ENV['CFN_FLOW_DEV_NAME'],
34
- 'region' => ENV['AWS_REGION']
35
- }.delete_if {|_,v| v.nil?}
36
-
37
- # Env vars override config file. Command args override env vars.
38
- self.options = defaults.merge(file_config).merge(env_config).merge(options)
39
-
40
- # Ensure region env var is set for AWS client
41
- ENV['AWS_REGION'] = options['region']
42
-
43
- # TODO: validate required options are present
44
- end
45
-
46
- shared_options
47
- def load_templates
48
- load_config
49
- glob = File.join(options['from'], '**/*.{yml,json,template}')
50
-
51
- @templates = Dir.glob(glob).map { |path|
52
- CfnFlow::Template.new(from: path, bucket: options['bucket'], prefix: prefix)
53
- }.select! {|t|
54
- verbose "Checking file #{t.from}... "
55
- if t.is_cfn_template?
56
- verbose "loaded"
57
- true
58
- else
59
- verbose "skipped."
60
- false
61
- end
62
- }
63
- end
64
- end
65
-
66
- desc :validate, 'Validates templates'
67
- shared_options
68
- def validate
69
- load_templates
70
- @templates.each do |t|
71
- begin
72
- verbose "Validating #{t.from}... "
73
- t.validate!
74
- verbose "valid."
75
- rescue Aws::CloudFormation::Errors::ValidationError
76
- say "Error validating #{t.from}. Message:"
77
- say $!.message
78
- end
79
- end
80
- end
81
-
82
- desc :upload, 'Validate & upload templates to the CFN_DEV_FLOW_NAME prefix'
83
- shared_options
84
- method_option :release, type: :string, desc: 'Upload & tag release'
85
- def upload
86
- tag_release if options['release']
87
-
88
- validate
89
- @templates.each do |t|
90
- verbose "Uploading #{t.from} to #{t.url}"
91
- t.upload!
92
- end
93
-
94
- push_release if options['release']
95
-
96
- end
97
- default_task :upload
98
-
99
- private
100
- def verbose(msg)
101
- say msg if options['verbose']
102
- end
103
-
104
- def prefix
105
- # Add the release or dev name to the prefix
106
- parts = []
107
- parts << options['prefix'] unless options['prefix'].empty?
108
- if options['release']
109
- parts += [ 'release', options['release'] ]
110
- else
111
- parts += [ 'dev', options['dev-name'] ]
112
- end
113
- File.join(*parts)
114
- end
115
-
116
- def tag_release
117
- # Check git status
118
- unless `git status -s`.empty?
119
- git_error "Git working directory is not clean. Please commit or reset changes in order to release."
120
- end
121
- unless $?.success?
122
- git_error "Error running `git status`"
123
- end
124
-
125
- say "Tagging release #{options['release']}"
126
- `git tag -a -m #{options['release']}, #{options['release']}`
127
- unless $?.success?
128
- git_error "Error tagging release."
129
- end
130
- end
131
-
132
- def push_tag
133
- `git push origin #{options['release']}`
134
- unless $?.success?
135
- git_error "Error pushing tag to origin."
136
- end
137
- end
138
-
139
- def git_error(message)
140
- say message, :red
141
- raise GitError.new(message)
142
- end
143
- end
6
+ module CfnFlow; end
7
+ require 'cfn-flow/template'
8
+ require 'cfn-flow/git'
9
+ require 'cfn-flow/cli'
@@ -0,0 +1,105 @@
1
+ class CfnFlow::CLI < Thor
2
+
3
+ def self.shared_options
4
+ method_option :bucket, type: :string, desc: 'S3 bucket for templates'
5
+ method_option :to, type: :string, desc: 'S3 path prefix for templates'
6
+ method_option :from, type: :string, desc: 'Local source directory for templates'
7
+ method_option 'dev-name', type: :string, desc: 'Personal development prefix'
8
+ method_option :region, type: :string, desc: 'AWS Region'
9
+ method_option :verbose, type: :boolean, desc: 'Verbose output', default: false
10
+ end
11
+
12
+ no_commands do
13
+ def load_config
14
+ defaults = { 'from' => '.' }
15
+ file_config = begin
16
+ YAML.load_file(ENV['CFN_FLOW_CONFIG'] || './cfn-flow.yml')
17
+ rescue Errno::ENOENT
18
+ {}
19
+ end
20
+ env_config = {
21
+ 'bucket' => ENV['CFN_FLOW_BUCKET'],
22
+ 'to' => ENV['CFN_FLOW_TO'],
23
+ 'from' => ENV['CFN_FLOW_FROM'],
24
+ 'dev-name' => ENV['CFN_FLOW_DEV_NAME'],
25
+ 'region' => ENV['AWS_REGION']
26
+ }.delete_if {|_,v| v.nil?}
27
+
28
+ # Env vars override config file. Command args override env vars.
29
+ self.options = defaults.merge(file_config).merge(env_config).merge(options)
30
+
31
+ # Ensure region env var is set for AWS client
32
+ ENV['AWS_REGION'] = options['region']
33
+
34
+ # TODO: validate required options are present
35
+ end
36
+
37
+ shared_options
38
+ def load_templates
39
+ load_config
40
+ glob = File.join(options['from'], '**/*.{yml,json,template}')
41
+
42
+ puts Dir.glob(glob.inspect)
43
+ @templates = Dir.glob(glob).map { |path|
44
+ CfnFlow::Template.new(from: path, bucket: options['bucket'], prefix: prefix)
45
+ }.select {|t|
46
+ verbose "Checking file #{t.from}... "
47
+ if t.is_cfn_template?
48
+ verbose "loaded"
49
+ true
50
+ else
51
+ verbose "skipped."
52
+ false
53
+ end
54
+ }
55
+ end
56
+ end
57
+
58
+ desc :validate, 'Validates templates'
59
+ shared_options
60
+ def validate
61
+ load_templates
62
+ @templates.each do |t|
63
+ begin
64
+ verbose "Validating #{t.from}... "
65
+ t.validate!
66
+ verbose "valid."
67
+ rescue Aws::CloudFormation::Errors::ValidationError
68
+ say "Error validating #{t.from}. Message:"
69
+ say $!.message
70
+ end
71
+ end
72
+ end
73
+
74
+ desc :upload, 'Validate & upload templates to the CFN_FLOW_DEV_NAME prefix'
75
+ shared_options
76
+ method_option :release, type: :string, lazy_default: CfnFlow::Git.sha, desc: 'Upload release'
77
+ def upload
78
+ check_git_status if options['release']
79
+
80
+ validate
81
+ @templates.each do |t|
82
+ verbose "Uploading #{t.from} to #{t.url}"
83
+ t.upload!
84
+ end
85
+
86
+ end
87
+ default_task :upload
88
+
89
+ private
90
+ def verbose(msg)
91
+ say msg if options['verbose']
92
+ end
93
+
94
+ def prefix
95
+ # Add the release or dev name to the prefix
96
+ parts = []
97
+ parts << options['prefix'] unless options['prefix'].empty?
98
+ if options['release']
99
+ parts += [ 'release', options['release'] ]
100
+ else
101
+ parts += [ 'dev', options['dev-name'] ]
102
+ end
103
+ File.join(*parts)
104
+ end
105
+ end
@@ -0,0 +1,24 @@
1
+ # Git helper module
2
+ class CfnFlow::Git
3
+ class << self
4
+
5
+ def sha
6
+ command = "git rev-parse --verify HEAD"
7
+ result = `#{command}`.chomp
8
+ unless $?.success?
9
+ raise Thor::Error.new("Error running `#{command}`")
10
+ end
11
+ result
12
+ end
13
+
14
+ def check_status
15
+ unless `git status -s`.empty?
16
+ raise Thor::Error.new("Git working directory is not clean. Please commit or reset changes in order to release.")
17
+ end
18
+ unless $?.success?
19
+ raise Thor::Error.new("Error running `git status`")
20
+ end
21
+ end
22
+
23
+ end
24
+ end
@@ -17,13 +17,15 @@ class CfnFlow::Template
17
17
  from_data.is_a?(Hash) && from_data.key?('Resources')
18
18
  end
19
19
 
20
+ # Returns a response object if valid, or raises an
21
+ # Aws::CloudFormation::Errors::ValidationError with an error message
20
22
  def validate!
21
23
  cfn.validate_template(template_body: to_json)
22
24
  end
23
25
 
24
26
  def key
25
- # Replace leading './' in from, rename *.yml to *.json
26
- File.join(prefix, from.sub(/\A\.\//, '').sub(/\.yml\Z/, '.json'))
27
+ # Replace leading './' in from
28
+ File.join(prefix, from.sub(/\A\.\//, ''))
27
29
  end
28
30
 
29
31
  def upload!
@@ -0,0 +1,56 @@
1
+ require_relative 'spec_helper'
2
+
3
+ describe 'CfnFlow::Template' do
4
+
5
+ let(:template) {
6
+ CfnFlow::Template.new(from: 'spec/data/sqs.template', prefix: 'p', bucket: 'b')
7
+ }
8
+
9
+ let(:yml_template) {
10
+ CfnFlow::Template.new(from: 'spec/data/sqs.yml', prefix: 'p', bucket: 'b')
11
+ }
12
+
13
+ let(:not_a_template) {
14
+ CfnFlow::Template.new(from: 'spec/data/cfn-flow.yml', prefix: 'p', bucket: 'b')
15
+ }
16
+
17
+ describe '#initialize' do
18
+ subject { CfnFlow::Template }
19
+
20
+ it('succeeds') do
21
+ subject.new(from: 'f', prefix: 'p', bucket: 'b').must_be_kind_of CfnFlow::Template
22
+ end
23
+
24
+ it('requires args') do
25
+ -> { subject.new }.must_raise(ArgumentError)
26
+ end
27
+ end
28
+
29
+ describe '#yaml?' do
30
+ it 'works' do
31
+ yml_template.yaml?.must_equal true
32
+ yml_template.json?.must_equal false
33
+ template.yaml?.must_equal false
34
+ template.json?.must_equal true
35
+ end
36
+ end
37
+
38
+ describe '#is_cfn_template?' do
39
+ it 'works' do
40
+ yml_template.is_cfn_template?.must_equal true
41
+ template.is_cfn_template?.must_equal true
42
+ not_a_template.is_cfn_template?.must_equal false
43
+ end
44
+ end
45
+
46
+ describe '#validate!' do
47
+ it 'can succeed' do
48
+ template.send(:cfn).stub_responses(:validate_template)
49
+ template.validate!
50
+ end
51
+ it 'can raise an error' do
52
+ template.send(:cfn).stub_responses(:validate_template, 'ValidationError')
53
+ -> { template.validate! }.must_raise Aws::CloudFormation::Errors::ValidationError
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,6 @@
1
+ ---
2
+ bucket: test-bucket
3
+ prefix: test-prefix
4
+ from: spec/data
5
+ to: test-to
6
+ region: us-east-1
File without changes
File without changes
@@ -0,0 +1,17 @@
1
+ require "rubygems"
2
+ require "bundler/setup"
3
+ require "minitest/autorun"
4
+ require "minitest/pride"
5
+
6
+ begin
7
+ require 'pry'
8
+ rescue LoadError
9
+ # NBD.
10
+ end
11
+
12
+ require "cfn-flow"
13
+
14
+ Aws.config[:stub_responses] = true
15
+ ENV['AWS_REGION'] = 'us-east-1'
16
+ ENV['AWS_ACCESS_KEY_ID'] = 'test-key'
17
+ ENV['AWS_SECRET_ACCESS_KEY'] = 'test-secret'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cfn-flow
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aaron Suggs
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-01-27 00:00:00.000000000 Z
11
+ date: 2015-02-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk
@@ -94,7 +94,7 @@ dependencies:
94
94
  - - ">="
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
- description: An opinionate worflow for AWS CloudFormation
97
+ description: An opinionated worflow for AWS CloudFormation
98
98
  email: aaron@ktheory.com
99
99
  executables:
100
100
  - cfn-flow
@@ -104,11 +104,16 @@ files:
104
104
  - README.md
105
105
  - Rakefile
106
106
  - bin/cfn-flow
107
+ - bin/rake
107
108
  - lib/cfn-flow.rb
109
+ - lib/cfn-flow/cli.rb
110
+ - lib/cfn-flow/git.rb
108
111
  - lib/cfn-flow/template.rb
109
- - lib/cfn-flow/version.rb
110
- - spec/sqs.template
111
- - spec/sqs.yml
112
+ - spec/cfn-flow_template_spec.rb
113
+ - spec/data/cfn-flow.yml
114
+ - spec/data/sqs.template
115
+ - spec/data/sqs.yml
116
+ - spec/spec_helper.rb
112
117
  homepage: http://github.com/kickstarter/cfn-flow
113
118
  licenses:
114
119
  - MIT
@@ -135,5 +140,8 @@ signing_key:
135
140
  specification_version: 4
136
141
  summary: A CLI for CloudFormation templates
137
142
  test_files:
138
- - spec/sqs.template
139
- - spec/sqs.yml
143
+ - spec/cfn-flow_template_spec.rb
144
+ - spec/data/cfn-flow.yml
145
+ - spec/data/sqs.template
146
+ - spec/data/sqs.yml
147
+ - spec/spec_helper.rb
@@ -1,3 +0,0 @@
1
- module CfnFlow
2
- VERSION = '0.0.1'
3
- end