cf-deploy 0.1.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.
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Made by Made Ltd
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,251 @@
1
+ # Rake tasks for deploying to CloudFoundry v6+
2
+
3
+ This gem provides the functionality you need to deploy your rails application to
4
+ a [CloudFoundry][CloudFoundry] provider like [Pivotal][Pivotal].
5
+
6
+ With `cf-deploy` you can:
7
+
8
+ * Define your CloudFoundry connection details in your Rakefile or using
9
+ environment variables
10
+ * Implement blue/green deployment
11
+ * Hook into your existing rake tasks for preparing deploys/syncing assets
12
+
13
+ ## Basics
14
+
15
+ The functionality comes in the shape of generated rake tasks. You require this
16
+ gem in your `Rakefile` and call the `.rake_tasks!` setup method.
17
+
18
+ ``` ruby
19
+ require 'cf-deploy'
20
+ CF::Deploy.rake_tasks!
21
+ ```
22
+
23
+ By default tasks will be created for each manifest in your `manifests/` folder.
24
+ If you have a `staging.yml` and `production.yml` you can now run the following
25
+ commands:
26
+
27
+ ``` sh
28
+ bundle exec rake cf:deploy:staging
29
+ bundle exec rake cf:deploy:production
30
+ ```
31
+
32
+ This however mimics the commands `cf push -f manifests/staging.yml` and
33
+ `cf push -f manifests/production.yml`. Not really anything helpful or new.
34
+ Things start to get more exciting when you define your environments in your
35
+ `Rakefile` along with their task dependencies just like normal rake task syntax.
36
+
37
+ ``` ruby
38
+ require 'cf-deploy'
39
+
40
+ CF::Deploy.rake_tasks! do
41
+ environment :staging => 'assets:precompile'
42
+ environment :production => [:clean, 'assets:precompile']
43
+ end
44
+ ```
45
+
46
+ Now when running `cf:deploy:staging` and `cf:deploy:production` the prerequisite
47
+ tasks will be run first.
48
+
49
+ The next thing to talk about is route mapping. You can define a route in a an
50
+ environment block like so:
51
+
52
+ ``` ruby
53
+ require 'cf-deploy'
54
+
55
+ CF::Deploy.rake_tasks! do
56
+ environment :staging => 'assets:precompile' do
57
+ route 'example.com', 'staging'
58
+ end
59
+
60
+ environment :production => [:clean, 'assets:precompile'] do
61
+ route 'example.com'
62
+ route 'example.com', 'admin'
63
+ end
64
+ end
65
+ ```
66
+
67
+ Any time you deploy an environment with one or more routes defined the routes
68
+ will be mapped to all applications in the environment's manifest.
69
+
70
+ And then things get super interesting when you start talking blue/green.
71
+
72
+ ## What is blue/green deployment?
73
+
74
+ Simply put, blue/green deployment allows you to deploy a new version of your
75
+ app, test it on a private URL and then direct your traffic to the new version
76
+ when you are ready.
77
+
78
+ You have two applications for one environment, say production. One version is
79
+ called green, the other is blue. The first time you deploy your app you either
80
+ go to blue or green. Thereafter, any changes you want to deploy you send to the
81
+ color that doesn't have your production domain pointed at it. You test it on
82
+ a private URL and then when you're happy you flip your domain to point at that.
83
+ If something then goes wrong you can then flip your domain back to the last
84
+ working version.
85
+
86
+ This gem provides rake tasks for you to deploy using this methodology as well
87
+ as the standard single app deployment process on a CloudFoundry provider.
88
+
89
+ For example you might have a straight forward deployment for staging but use
90
+ the blue/green strategy for production. Here is what your Rakefile might look
91
+ like:
92
+
93
+ ``` ruby
94
+ require 'cf-deploy'
95
+
96
+ CF::Deploy.rake_tasks! do
97
+ environment :staging => 'assets:precompile'
98
+
99
+ environment :production => 'assets:precompile' do
100
+ route 'example-app.io'
101
+ end
102
+ end
103
+ ```
104
+
105
+ You should also have `manifests/production_blue.yml` and
106
+ `manifests/production_green.yml` defined.
107
+
108
+ When you run `cf:deploy:production` for the first time (assuming neither
109
+ `production_blue.yml` or `production_green.yml` are deployed) your blue app will
110
+ be deployed and route setup.
111
+
112
+ Running `cf:deploy:production` thereafter will deploy which ever version isn't
113
+ currently deployed. Your route(s) will not be mapped automatically this time.
114
+ Nows your chance to checkout your new deployment using an alternate route. When
115
+ you're happy and want to map your route across run:
116
+
117
+ ``` sh
118
+ bundle exec rake cf:deploy:production:flip
119
+ ```
120
+
121
+ ## Installation
122
+
123
+ You need the `cf` command installed already. Grab the latest release from
124
+ the [CloudFoundry CLI][cli] repo on github.
125
+
126
+ You then need to install this gem in your project's `Gemfile`:
127
+
128
+ ``` ruby
129
+ gem 'cf-deploy', '0.1.0'
130
+ ```
131
+
132
+ ### Defining CloudFoundry details in your Rakefile
133
+
134
+ You can configure some or all of your CloudFoundry details when calling
135
+ `CF::Deploy.rake_tasks!`.
136
+
137
+ ``` ruby
138
+ require 'cf-deploy'
139
+
140
+ CF::Deploy.rake_tasks! do
141
+ api 'api.run.pivotal.io'
142
+ username 'example@example.com'
143
+ password 'SOMETHING'
144
+ organisation 'Made'
145
+ space 'development'
146
+
147
+ environment :staging => 'assets:precompile'
148
+
149
+ environment :production => 'assets:precompile' do
150
+ route 'example-app.io'
151
+ end
152
+ end
153
+ ```
154
+
155
+ All are optional. If you do not provide any you will be prompted when running
156
+ the rake tasks.
157
+
158
+ ### Defining CloudFoundry details using ENV variables
159
+
160
+ Instead of defining your CloudFoundry login details in your Rakefile and
161
+ committing them to your code repository you can instead provide them using
162
+ ENV variables on your command line:
163
+
164
+ ``` sh
165
+ export CF_API=api.run.pivotal.io
166
+ export CF_USERNAME=example@example.com
167
+ export CF_PASSWORD=SOMETHING
168
+ export CF_ORG=Made
169
+ export CF_SPACE=development
170
+ ```
171
+
172
+ Now you can run any of the `cf-deploy` rake tasks providing you have called
173
+ `CF::Deploy.rake_tasks!` in your `Rakefile`.
174
+
175
+ ## Commands
176
+
177
+ ### Deploying an environment
178
+
179
+ If you defined a staging environment in your Rakefile the following task will
180
+ have been created:
181
+
182
+ ```
183
+ bundle exec rake cf:deploy:staging
184
+ ```
185
+
186
+ Run this to deploy out your staging environment.
187
+
188
+ Any environment you define will have a task created named `cf:deploy:#{env}`.
189
+
190
+ ### Deploy the next blue/green environment
191
+
192
+ If you have defined CloudFoundry manifest files matching `manifests/*_blue.yml`
193
+ and `manifests/*_green.yml` you will be able to call `rake cf:deploy:*` without
194
+ the `_blue` or `_green`. For example with `production_blue.yml` and
195
+ `production_green.yml` you can call the following:
196
+
197
+ ```
198
+ bundle exec rake cf:deploy:production
199
+ ```
200
+
201
+ Running the deploy task for an env with blue and green manifests will trigger a
202
+ lookup to see which env is currently deployed. The task will then start
203
+ deploying the other production color, so if green is currently deployed then
204
+ blue will be deployed. If neither is currently deployed, blue will be deployed
205
+ first.
206
+
207
+ Once deployed your routing will still be pointing to the *previous deployment*.
208
+ If you run the same task again, the same environment will be deployed. That is
209
+ if green was deployed, and then you run the task, blue will be deployed, if you
210
+ run the task again, blue will be deployed again. This is because we work out
211
+ the current deployment based on where your routes are pointing and since the
212
+ deploy command for blue green environments doesn't map routes the current
213
+ deployment will not change.
214
+
215
+ #### First time proviso
216
+
217
+ This isn't the case for a first time deploy. The first time you deploy your
218
+ blue environment will be deployed and any defined routes will be mapped to all
219
+ apps defined in your blue manifest.
220
+
221
+ ### Switch routes over to new environment
222
+
223
+ In order to flip your routes from blue to green or vice-versa you need to run
224
+ the following task.
225
+
226
+ ```
227
+ bundle exec rake cf:deploy:production:flip
228
+ ```
229
+
230
+ This will go ahead and map routes to whatever color the routes aren't mapped to
231
+ and then unmap the other color. At this point your new production will be
232
+ deployed and live.
233
+
234
+ ## Credits
235
+
236
+ [![made](https://s3-eu-west-1.amazonaws.com/made-assets/googleapps/google-apps.png)][made]
237
+
238
+ Developed and maintained by [Made][made]. Key contributions:
239
+
240
+ * [Luke Morton](https://github.com/DrPheltRight)
241
+
242
+ ## License
243
+
244
+ Copyright © 2014 Made by Made Ltd. It is free software, and may be
245
+ redistributed under the terms specified in the [MIT-LICENSE][license] file.
246
+
247
+ [CloudFoundry]: http://www.cloudfoundry.org/
248
+ [Pivotal]: https://run.pivotal.io/
249
+ [cli]: https://github.com/cloudfoundry/cli/releases
250
+ [made]: http://www.madetech.co.uk?ref=github&repo=ydtd_frontend
251
+ [license]: https://github.com/madebymade/cf-deploy/blob/master/LICENSE
data/lib/cf-deploy.rb ADDED
@@ -0,0 +1 @@
1
+ require 'cf/deploy'
data/lib/cf/deploy.rb ADDED
@@ -0,0 +1,70 @@
1
+ require 'cf/deploy/version'
2
+ require 'cf/deploy/config'
3
+ require 'cf/deploy/env_config'
4
+ require 'cf/deploy/commands'
5
+ require 'rake'
6
+
7
+ module CF
8
+ class Deploy
9
+ class << self
10
+ def rake_tasks!(&block)
11
+ new(Config.new(&block)).tasks
12
+ end
13
+ end
14
+
15
+ include Commands
16
+
17
+ attr_accessor :config
18
+
19
+ def initialize(config)
20
+ @config = config
21
+ end
22
+
23
+ def tasks
24
+ [define_login_task].concat(deploy_tasks)
25
+ end
26
+
27
+ def deploy_tasks
28
+ config[:environments].map { |env| define_deploy_task(env) }
29
+ end
30
+
31
+ def define_login_task
32
+ return Rake::Task['cf:login'] if Rake::Task.task_defined?('cf:login')
33
+
34
+ Rake::Task.define_task('cf:login') do
35
+ login(config)
36
+ end
37
+ end
38
+
39
+ def define_deploy_task(env)
40
+ blue_green_task(env) if env[:deployments].size > 1
41
+
42
+ env[:deployments].each do |deployment|
43
+ Rake::Task.define_task(deployment[:task_name] => env[:deps]) do
44
+ push(deployment[:manifest])
45
+
46
+ env[:routes].each do |route|
47
+ deployment[:app_names].each do |app_name|
48
+ map_route(route, app_name)
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+
55
+ def first_domain(env)
56
+ env[:routes].first.values_at(:host, :domain).compact.join('.')
57
+ end
58
+
59
+ def next_production(env)
60
+ current_production(first_domain(env)) != 'blue' ? 'blue' : 'green'
61
+ end
62
+
63
+ def blue_green_task(env)
64
+ Rake::Task.define_task(env[:task_name] => env[:deps]) do
65
+ task_name = EnvConfig.task_name("#{env[:name]}_#{next_production(env)}")
66
+ Rake::Task[task_name].invoke
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,33 @@
1
+ module CF
2
+ class Deploy
3
+ module Commands
4
+ def login(config)
5
+ login_cmd = ['cf login']
6
+
7
+ login_cmd << Config::VALID_CF_KEYS
8
+ .reject { |key| config[key].nil? }
9
+ .map { |key| "-#{key.to_s[0]} #{config[key]}" }
10
+
11
+ Kernel.system(login_cmd.flatten.join(' '))
12
+ end
13
+
14
+ def push(manifest)
15
+ Kernel.system("cf push -f #{manifest}")
16
+ end
17
+
18
+ def map_route(route, app_name)
19
+ map_cmd = "cf map-route #{app_name} #{route[:domain]}"
20
+ map_cmd = "#{map_cmd} -n #{route[:hostname]}" unless route[:hostname].nil?
21
+ Kernel.system(map_cmd)
22
+ end
23
+
24
+ def current_production(domain)
25
+ io = IO.popen("cf routes | grep #{domain}")
26
+ matches = /(blue|green)/.match(io.read)
27
+ io.close
28
+ return if matches.nil?
29
+ matches[1].strip
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,81 @@
1
+ module CF
2
+ class Deploy
3
+ class Config < Hash
4
+ VALID_CF_KEYS = [:api, :username, :password, :organisation, :space]
5
+
6
+ attr_reader :environments_to_be_loaded
7
+
8
+ def initialize(&block)
9
+ @environments_to_be_loaded = []
10
+
11
+ merge!(:manifest_glob => 'manifests/*',
12
+ :api => nil,
13
+ :username => nil,
14
+ :password => nil,
15
+ :organisation => nil,
16
+ :space => nil)
17
+
18
+ instance_eval(&block) if block_given?
19
+
20
+ self[:environments] = environments(manifests_by_env)
21
+ end
22
+
23
+ def [](key)
24
+ from_env(key) || super
25
+ end
26
+
27
+ def from_env(key)
28
+ ENV["CF_#{key.upcase}"] if VALID_CF_KEYS.include?(key)
29
+ end
30
+
31
+ def manifests_by_env
32
+ Dir[self[:manifest_glob]].reduce({}) do |envs, manifest|
33
+ if manifest =~ /_blue.yml$/
34
+ env = File.basename(manifest, '_blue.yml').to_sym
35
+ elsif manifest =~ /_green.yml$/
36
+ env = File.basename(manifest, '_green.yml').to_sym
37
+ else
38
+ env = File.basename(manifest, '.yml').to_sym
39
+ end
40
+
41
+ envs[env] ||= []
42
+ envs[env] << manifest
43
+ envs
44
+ end
45
+ end
46
+
47
+ def environments(manifests_by_env)
48
+ environments = []
49
+
50
+ environments_to_be_loaded.each do |(env, block)|
51
+ if env.is_a?(Hash)
52
+ name, deps = env.first
53
+ deps = (['cf:login'] << deps).flatten
54
+ else
55
+ name = env
56
+ deps = ['cf:login']
57
+ end
58
+
59
+ manifests = manifests_by_env.delete(name) || []
60
+ environments << EnvConfig.new(name, deps, manifests, &block)
61
+ end
62
+
63
+ manifests_by_env.each do |(name, manifests)|
64
+ environments << EnvConfig.new(name, ['cf:login'], manifests)
65
+ end
66
+
67
+ environments
68
+ end
69
+
70
+ # Config setter methods
71
+ #
72
+ def manifest_glob(glob) self[:manifest_glob] = glob end
73
+ def api(api) self[:api] = api end
74
+ def username(username) self[:username] = username end
75
+ def password(password) self[:password] = password end
76
+ def organisation(organisation) self[:organisation] = organisation end
77
+ def space(space) self[:space] = space end
78
+ def environment(env, &block) @environments_to_be_loaded << [env, block] end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,57 @@
1
+ require 'yaml'
2
+
3
+ module CF
4
+ class Deploy
5
+ class EnvConfig < Hash
6
+ def self.task_name(name)
7
+ "cf:deploy:#{name}"
8
+ end
9
+
10
+ def initialize(name, deps, manifests, &block)
11
+ merge!(:name => name,
12
+ :task_name => EnvConfig.task_name(name),
13
+ :deps => deps,
14
+ :routes => [],
15
+ :manifests => manifests)
16
+
17
+ instance_eval(&block) if block_given?
18
+
19
+ self[:deployments] = deployments
20
+ end
21
+
22
+ def deployments
23
+ self[:manifests].map { |manifest| deployment_for_manifest(manifest) }
24
+ end
25
+
26
+ def deployment_for_manifest(manifest)
27
+ if self[:manifests].size > 1
28
+ task_name = EnvConfig.task_name(File.basename(manifest, '.yml').to_sym)
29
+ else
30
+ task_name = self[:task_name]
31
+ end
32
+
33
+ {:task_name => task_name,
34
+ :manifest => manifest,
35
+ :app_names => app_names_for_manifest(manifest)}
36
+ end
37
+
38
+ def app_names_for_manifest(manifest)
39
+ YAML.load_file(manifest)['applications'].map { |a| a['name'] }
40
+ end
41
+
42
+ # Environment config setter methods
43
+ #
44
+ def manifest(manifest)
45
+ self[:manifests] << manifest
46
+ end
47
+
48
+ def manifests(manifests)
49
+ self[:manifests].concat(manifests)
50
+ end
51
+
52
+ def route(domain, hostname = nil)
53
+ self[:routes] << {:domain => domain, :hostname => hostname}
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,5 @@
1
+ module CF
2
+ class Deploy
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,60 @@
1
+ require 'spec_helper'
2
+ require 'cf-deploy'
3
+ require 'rake'
4
+
5
+ describe CF::Deploy do
6
+ before :each do
7
+ Rake::Task.clear
8
+ end
9
+
10
+ context 'Blue/green deployment task' do
11
+ let :rake_tasks! do
12
+ Dir.chdir('spec/') do
13
+ described_class.rake_tasks! do
14
+ environment :production do
15
+ route 'example.com'
16
+ route 'example.com', '2'
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ it 'should exist if *_blue.yml and *_green.yml manifests exist' do
23
+ rake_tasks!
24
+ expect(Rake::Task['cf:deploy:production']).to be_a(Rake::Task)
25
+ end
26
+
27
+ it 'should deploy blue if not currently deployed' do
28
+ rake_tasks!
29
+ expect(Kernel).to receive(:system).with('cf login').ordered
30
+ expect(IO).to receive(:popen).with('cf routes | grep example.com') { double(:read => '', :close => nil) }
31
+ expect(Kernel).to receive(:system).with('cf push -f manifests/production_blue.yml').ordered
32
+ expect(Kernel).to receive(:system).with('cf map-route production-blue-app example.com').ordered
33
+ expect(Kernel).to receive(:system).with('cf map-route production-blue-app example.com -n 2').ordered
34
+ Rake::Task['cf:deploy:production'].invoke
35
+ end
36
+
37
+ it 'should deploy blue if green currently deployed' do
38
+ rake_tasks!
39
+ expect(Kernel).to receive(:system).with('cf login').ordered
40
+ expect(IO).to receive(:popen).with('cf routes | grep example.com') { double(:read => 'production-green-app', :close => nil) }
41
+ expect(Kernel).to receive(:system).with('cf push -f manifests/production_blue.yml').ordered
42
+ expect(Kernel).to receive(:system).with('cf map-route production-blue-app example.com').ordered
43
+ expect(Kernel).to receive(:system).with('cf map-route production-blue-app example.com -n 2').ordered
44
+ Rake::Task['cf:deploy:production'].invoke
45
+ end
46
+
47
+ it 'should deploy green if blue currently deployed' do
48
+ rake_tasks!
49
+ expect(Kernel).to receive(:system).with('cf login').ordered
50
+ expect(IO).to receive(:popen).with('cf routes | grep example.com') { double(:read => 'production-blue-app', :close => nil) }
51
+ expect(Kernel).to receive(:system).with('cf push -f manifests/production_green.yml').ordered
52
+ expect(Kernel).to receive(:system).with('cf map-route production-green-app example.com').ordered
53
+ expect(Kernel).to receive(:system).with('cf map-route production-green-app example.com -n 2').ordered
54
+ Rake::Task['cf:deploy:production'].invoke
55
+ end
56
+
57
+ xit 'should throw exception if no routes defined for blue/green task' do
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,91 @@
1
+ require 'spec_helper'
2
+ require 'cf-deploy'
3
+ require 'rake'
4
+
5
+ describe CF::Deploy do
6
+ before :each do
7
+ Rake::Task.clear
8
+ end
9
+
10
+ context 'Rake::Task[cf:deploy:XX]' do
11
+ it 'should run a manifest' do
12
+ Dir.chdir('spec/') do
13
+ described_class.rake_tasks!
14
+ end
15
+
16
+ expect(Kernel).to receive(:system).with('cf login').ordered
17
+ expect(Kernel).to receive(:system).with('cf push -f manifests/staging.yml').ordered
18
+ Rake::Task['cf:deploy:staging'].invoke
19
+ end
20
+
21
+ it 'should setup a route if defined after pushing manifest' do
22
+ Dir.chdir('spec/') do
23
+ described_class.rake_tasks! do
24
+ environment :test do
25
+ route 'testexample.com'
26
+ end
27
+ end
28
+ end
29
+
30
+ expect(Kernel).to receive(:system).with('cf login').ordered
31
+ expect(Kernel).to receive(:system).with('cf push -f manifests/test.yml').ordered
32
+ expect(Kernel).to receive(:system).with('cf map-route test-app testexample.com').ordered
33
+ Rake::Task['cf:deploy:test'].invoke
34
+ end
35
+
36
+ it 'should setup a route with a hostname if defined' do
37
+ Dir.chdir('spec/') do
38
+ described_class.rake_tasks! do
39
+ environment :test do
40
+ route 'example.com', 'test'
41
+ end
42
+ end
43
+ end
44
+
45
+ expect(Kernel).to receive(:system).with('cf login').ordered
46
+ expect(Kernel).to receive(:system).with('cf push -f manifests/test.yml').ordered
47
+ expect(Kernel).to receive(:system).with('cf map-route test-app example.com -n test')
48
+ Rake::Task['cf:deploy:test'].invoke
49
+ end
50
+
51
+ it 'should setup multiple routes if defined' do
52
+ Dir.chdir('spec/') do
53
+ described_class.rake_tasks! do
54
+ environment :test do
55
+ route 'example.com'
56
+ route 'example.com', '2'
57
+ end
58
+ end
59
+ end
60
+
61
+ expect(Kernel).to receive(:system).with('cf login').ordered
62
+ expect(Kernel).to receive(:system).with('cf push -f manifests/test.yml').ordered
63
+ expect(Kernel).to receive(:system).with('cf map-route test-app example.com').ordered
64
+ expect(Kernel).to receive(:system).with('cf map-route test-app example.com -n 2').ordered
65
+ Rake::Task['cf:deploy:test'].invoke
66
+ end
67
+
68
+ xit 'should not map routes if push fails' do
69
+ end
70
+
71
+ xit 'should throw decent error if manifest does not exist' do
72
+ end
73
+
74
+ xit 'should throw decent error if manifest invalid' do
75
+ end
76
+
77
+ it 'should allow individual manifest to be specified' do
78
+ Dir.chdir('spec/') do
79
+ CF::Deploy.rake_tasks! do
80
+ environment :custom_manifest do
81
+ manifest 'manifests/staging.yml'
82
+ end
83
+ end
84
+ end
85
+
86
+ expect(Kernel).to receive(:system).with('cf login').ordered
87
+ expect(Kernel).to receive(:system).with('cf push -f manifests/staging.yml').ordered
88
+ Rake::Task['cf:deploy:custom_manifest'].invoke
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,72 @@
1
+ require 'spec_helper'
2
+ require 'cf-deploy'
3
+ require 'rake'
4
+
5
+ describe CF::Deploy do
6
+ before :each do
7
+ Rake::Task.clear
8
+ end
9
+
10
+ context 'Rake::Task[cf:login]' do
11
+ it 'should run `cf login` without arguments if none provided' do
12
+ described_class.rake_tasks!
13
+ expect(Kernel).to receive(:system).with('cf login')
14
+ Rake::Task['cf:login'].invoke
15
+ end
16
+
17
+ it 'should include defined details' do
18
+ described_class.rake_tasks! do
19
+ api 'api.run.pivotal.io'
20
+ end
21
+
22
+ expect(Kernel).to receive(:system).with('cf login -a api.run.pivotal.io')
23
+ Rake::Task['cf:login'].invoke
24
+ end
25
+
26
+ it 'should include all defined details' do
27
+ described_class.rake_tasks! do
28
+ api 'api'
29
+ username 'test'
30
+ password 'pass'
31
+ organisation 'org'
32
+ space 'space'
33
+ end
34
+
35
+ expect(Kernel).to receive(:system).with('cf login -a api -u test -p pass -o org -s space')
36
+ Rake::Task['cf:login'].invoke
37
+ end
38
+
39
+ it 'should include all details provided in ENV' do
40
+ {'CF_API' => 'api',
41
+ 'CF_USERNAME' => 'test',
42
+ 'CF_PASSWORD' => 'pass',
43
+ 'CF_ORGANISATION' => 'org',
44
+ 'CF_SPACE' => 'space'}.each do |(k, v)|
45
+ expect(ENV).to receive(:[]).with(k).and_return(v).at_least(:once)
46
+ end
47
+
48
+ expect(Kernel).to receive(:system).with('cf login -a api -u test -p pass -o org -s space')
49
+ described_class.rake_tasks!
50
+ Rake::Task['cf:login'].invoke
51
+ end
52
+
53
+ it 'should mix and match ENV and defined details with ENV having precedence' do
54
+ {'CF_API' => nil,
55
+ 'CF_USERNAME' => 'test',
56
+ 'CF_PASSWORD' => 'pass',
57
+ 'CF_ORGANISATION' => 'org',
58
+ 'CF_SPACE' => nil}.each do |(k, v)|
59
+ expect(ENV).to receive(:[]).with(k).and_return(v).at_least(:once)
60
+ end
61
+
62
+ expect(Kernel).to receive(:system).with('cf login -a api -u test -p pass -o org')
63
+
64
+ described_class.rake_tasks! do
65
+ api 'api'
66
+ organisation 'will be overridden by ENV[CF_ORGANISATION]'
67
+ end
68
+
69
+ Rake::Task['cf:login'].invoke
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,61 @@
1
+ require 'spec_helper'
2
+ require 'cf-deploy'
3
+ require 'rake'
4
+
5
+ describe CF::Deploy do
6
+ before :each do
7
+ Rake::Task.clear
8
+ end
9
+
10
+ context '.rake_tasks!' do
11
+ it 'should install task for each manifest' do
12
+ Dir.chdir('spec/') do
13
+ described_class.rake_tasks!
14
+ end
15
+
16
+ expect(Rake::Task['cf:deploy:staging']).to be_a(Rake::Task)
17
+ expect(Rake::Task['cf:deploy:test']).to be_a(Rake::Task)
18
+ end
19
+
20
+ it 'should install login task' do
21
+ Dir.chdir('spec/') do
22
+ described_class.rake_tasks!
23
+ end
24
+
25
+ expect(Rake::Task['cf:login']).to be_a(Rake::Task)
26
+ end
27
+
28
+ it 'should install a login task as a prerequisite for deploy tasks' do
29
+ Dir.chdir('spec/') do
30
+ described_class.rake_tasks!
31
+ end
32
+
33
+ expect(Rake::Task['cf:deploy:staging'].prerequisite_tasks[0]).to be(Rake::Task['cf:login'])
34
+ end
35
+
36
+ it 'should install tasks with prerequisites' do
37
+ expected_task_1 = Rake::Task.define_task('asset:precompile')
38
+ expected_task_2 = Rake::Task.define_task(:clean)
39
+
40
+ Dir.chdir('spec/') do
41
+ described_class.rake_tasks! do
42
+ environment :staging => 'asset:precompile'
43
+ environment :test => ['asset:precompile', :clean]
44
+ end
45
+ end
46
+
47
+ expect(Rake::Task['cf:deploy:staging'].prerequisite_tasks[1]).to be(expected_task_1)
48
+ expect(Rake::Task['cf:deploy:test'].prerequisite_tasks[2]).to be(expected_task_2)
49
+ end
50
+
51
+ it 'should have a configurable manifest glob options' do
52
+ Dir.chdir('spec/') do
53
+ described_class.rake_tasks! do
54
+ manifest_glob 'manifests/staging.yml'
55
+ end
56
+ end
57
+
58
+ expect(Rake::Task.tasks.count).to eq(2)
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,9 @@
1
+ require 'simplecov'
2
+ require 'coveralls'
3
+
4
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
5
+ SimpleCov::Formatter::HTMLFormatter,
6
+ Coveralls::SimpleCov::Formatter
7
+ ]
8
+
9
+ SimpleCov.start
metadata ADDED
@@ -0,0 +1,145 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cf-deploy
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Luke Morton
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-07-21 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: bundler
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: '1.5'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: '1.5'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rspec
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: 3.0.0
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 3.0.0
62
+ - !ruby/object:Gem::Dependency
63
+ name: simplecov
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: 0.7.1
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: 0.7.1
78
+ - !ruby/object:Gem::Dependency
79
+ name: coveralls
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ~>
84
+ - !ruby/object:Gem::Version
85
+ version: 0.7.0
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ~>
92
+ - !ruby/object:Gem::Version
93
+ version: 0.7.0
94
+ description:
95
+ email:
96
+ - luke@madebymade.co.uk
97
+ executables: []
98
+ extensions: []
99
+ extra_rdoc_files: []
100
+ files:
101
+ - lib/cf/deploy/commands.rb
102
+ - lib/cf/deploy/config.rb
103
+ - lib/cf/deploy/env_config.rb
104
+ - lib/cf/deploy/version.rb
105
+ - lib/cf/deploy.rb
106
+ - lib/cf-deploy.rb
107
+ - spec/blue_green_task_spec.rb
108
+ - spec/deploy_task_spec.rb
109
+ - spec/login_task_spec.rb
110
+ - spec/rake_tasks_spec.rb
111
+ - spec/spec_helper.rb
112
+ - LICENSE
113
+ - README.md
114
+ homepage: https://github.com/madebymade/cf-deploy
115
+ licenses:
116
+ - MIT
117
+ post_install_message:
118
+ rdoc_options: []
119
+ require_paths:
120
+ - lib
121
+ required_ruby_version: !ruby/object:Gem::Requirement
122
+ none: false
123
+ requirements:
124
+ - - ! '>='
125
+ - !ruby/object:Gem::Version
126
+ version: '0'
127
+ segments:
128
+ - 0
129
+ hash: 3630708785980553311
130
+ required_rubygems_version: !ruby/object:Gem::Requirement
131
+ none: false
132
+ requirements:
133
+ - - ! '>='
134
+ - !ruby/object:Gem::Version
135
+ version: '0'
136
+ segments:
137
+ - 0
138
+ hash: 3630708785980553311
139
+ requirements: []
140
+ rubyforge_project:
141
+ rubygems_version: 1.8.23
142
+ signing_key:
143
+ specification_version: 3
144
+ summary: Rake tasks for deploying to CloudFoundry v6+
145
+ test_files: []