cloudfoundry_blue_green_deploy 0.0.1
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 +7 -0
- data/.gitignore +22 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +184 -0
- data/Rakefile +2 -0
- data/cloudfoundry_blue_green_deploy.gemspec +25 -0
- data/lib/cloudfoundry_blue_green_deploy.rb +8 -0
- data/lib/cloudfoundry_blue_green_deploy/app.rb +10 -0
- data/lib/cloudfoundry_blue_green_deploy/blue_green_deploy.rb +144 -0
- data/lib/cloudfoundry_blue_green_deploy/blue_green_deploy_config.rb +108 -0
- data/lib/cloudfoundry_blue_green_deploy/blue_green_deploy_error.rb +3 -0
- data/lib/cloudfoundry_blue_green_deploy/cloudfoundry.rb +90 -0
- data/lib/cloudfoundry_blue_green_deploy/command_line.rb +15 -0
- data/lib/cloudfoundry_blue_green_deploy/railtie.rb +11 -0
- data/lib/cloudfoundry_blue_green_deploy/route.rb +10 -0
- data/lib/cloudfoundry_blue_green_deploy/tasks/cf.rake +28 -0
- data/lib/cloudfoundry_blue_green_deploy/version.rb +3 -0
- data/spec/blue_green_deploy_config_spec.rb +140 -0
- data/spec/blue_green_deploy_spec.rb +287 -0
- data/spec/cloudfoundry_fake.rb +105 -0
- data/spec/cloudfoundry_spec.rb +161 -0
- data/spec/command_line_spec.rb +21 -0
- data/spec/manifest.yml +51 -0
- data/spec/route_spec.rb +13 -0
- data/spec/spec_helper.rb +7 -0
- metadata +134 -0
@@ -0,0 +1,105 @@
|
|
1
|
+
module CloudfoundryBlueGreenDeploy
|
2
|
+
class CloudfoundryFake
|
3
|
+
def self.init_route_table(domain, web_app_name, hot_url, current_hot_color)
|
4
|
+
@@web_app_name = web_app_name
|
5
|
+
@@current_hot_color = current_hot_color
|
6
|
+
@@hot_url = hot_url
|
7
|
+
@@cf_route_table = [
|
8
|
+
Route.new("#{web_app_name}-blue", domain, "#{web_app_name}-blue"),
|
9
|
+
Route.new("#{web_app_name}-green", domain, "#{web_app_name}-green"),
|
10
|
+
Route.new(hot_url, domain, "#{web_app_name}-#{current_hot_color}")
|
11
|
+
]
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.clear_route_table
|
15
|
+
@@cf_route_table = []
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.init_app_list_with_workers_for(app_name)
|
19
|
+
@@cf_app_list = [
|
20
|
+
App.new(name: "#{app_name}-worker-green", state: 'stopped'),
|
21
|
+
App.new(name: "#{app_name}-worker-blue", state: 'stopped')
|
22
|
+
]
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.init_app_list_from_names(app_names)
|
26
|
+
@@cf_app_list = []
|
27
|
+
app_names.each do |app|
|
28
|
+
['blue', 'green'].each do |color|
|
29
|
+
@@cf_app_list << App.new(name: "#{app}-#{color}", state: 'stopped')
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.mark_app_as_started(full_worker_app_name)
|
35
|
+
@@cf_app_list.find { |app| app.name == full_worker_app_name }.state = 'started'
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.mark_workers_as_started(worker_app_names, target_color)
|
39
|
+
@@cf_app_list.each do |app|
|
40
|
+
worker_app_names.each do |worker_name|
|
41
|
+
if app.name == "#{worker_name}-#{target_color}"
|
42
|
+
app.state = 'started'
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.init_app_list(apps)
|
49
|
+
@@cf_app_list = apps
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.clear_app_list
|
53
|
+
@@cf_app_list = []
|
54
|
+
end
|
55
|
+
|
56
|
+
# App List Helpers
|
57
|
+
|
58
|
+
def self.replace_app(new_app)
|
59
|
+
app_index = @@cf_app_list.find_index { |existing_app| existing_app.name == new_app.name }
|
60
|
+
@@cf_app_list[app_index] = new_app
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.apps
|
64
|
+
@@cf_app_list
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
def self.started_apps
|
69
|
+
@@cf_app_list.select { |app| app.state == 'started' }
|
70
|
+
end
|
71
|
+
|
72
|
+
# Route Table Helpers
|
73
|
+
def self.find_route(host)
|
74
|
+
@@cf_route_table.find { |route| route.host == host }
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.add_route(route)
|
78
|
+
@@cf_route_table << route
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.remove_route(host)
|
82
|
+
@@cf_route_table.delete_if { |route| route.host == host }
|
83
|
+
end
|
84
|
+
|
85
|
+
# Cloudfoundry fakes
|
86
|
+
def self.push(app)
|
87
|
+
end
|
88
|
+
|
89
|
+
def self.stop(app)
|
90
|
+
end
|
91
|
+
|
92
|
+
def self.routes
|
93
|
+
@@cf_route_table
|
94
|
+
end
|
95
|
+
|
96
|
+
def self.unmap_route(app, domain, host)
|
97
|
+
@@cf_route_table.delete_if { |route| route.app == "#{@@web_app_name}-#{@@current_hot_color}" && route.host == @@hot_url }
|
98
|
+
end
|
99
|
+
|
100
|
+
def self.map_route(app, domain, host)
|
101
|
+
@@cf_route_table.delete_if { |route| route.host == host }
|
102
|
+
@@cf_route_table.push(Route.new(host, domain, app))
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,161 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module CloudfoundryBlueGreenDeploy
|
4
|
+
describe Cloudfoundry do
|
5
|
+
describe '#push' do
|
6
|
+
subject { Cloudfoundry.push(app) }
|
7
|
+
let(:app) { 'app_name-blue' }
|
8
|
+
|
9
|
+
it 'invokes the Cloudfoundry CLI command "push"' do
|
10
|
+
expect(CommandLine).to receive(:system).with("cf push #{app}").and_return(true)
|
11
|
+
subject
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'when the Cloudfoundry push fails' do
|
15
|
+
before do
|
16
|
+
allow(CommandLine).to receive(:system).and_return(false)
|
17
|
+
end
|
18
|
+
it 'throws a CloudfoundryCliError' do
|
19
|
+
expect{ subject }.to raise_error(CloudfoundryCliError)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '#stop' do
|
25
|
+
subject { Cloudfoundry.stop(app) }
|
26
|
+
let(:app) { 'app_name-blue' }
|
27
|
+
|
28
|
+
it 'invokes the Cloudfoundry CLI command "stop"' do
|
29
|
+
expect(CommandLine).to receive(:system).with("cf stop #{app}").and_return(true)
|
30
|
+
subject
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'when the Cloudfoundry push fails' do
|
34
|
+
before do
|
35
|
+
allow(CommandLine).to receive(:system).and_return(false)
|
36
|
+
end
|
37
|
+
it 'throws a CloudfoundryCliError' do
|
38
|
+
expect{ subject }.to raise_error(CloudfoundryCliError)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe '#apps' do
|
44
|
+
subject { Cloudfoundry.apps }
|
45
|
+
before do
|
46
|
+
allow(CommandLine).to receive(:backtick).with('cf apps').and_return(cli_apps_output)
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'there is a list of apps defined in the current organization' do
|
50
|
+
let(:cli_apps_output) {
|
51
|
+
<<-CLI
|
52
|
+
Getting apps in org LA-Ping-Pong-Ding-Dongs / space carrot-soup as pivot-pong-developers@googlegroups.com...
|
53
|
+
OK
|
54
|
+
|
55
|
+
name requested state instances memory disk urls
|
56
|
+
carrot-soup-blue stopped 0/1 1G 1G carrot-soup-blue.cfapps.io
|
57
|
+
carrot-soup-green started 1/1 1G 1G la-pong.cfapps.io, carrot-soup-green.cfapps.io
|
58
|
+
red started 1/1 1G 1G relish.cfapps.io
|
59
|
+
CLI
|
60
|
+
}
|
61
|
+
|
62
|
+
it 'parses the CLI "apps" output into a collection of App objects, one for each app' do
|
63
|
+
expect(subject).to be_kind_of(Array)
|
64
|
+
expect(subject.length).to eq 3
|
65
|
+
expect(subject[0].name).to eq 'carrot-soup-blue'
|
66
|
+
expect(subject[0].state).to eq 'stopped'
|
67
|
+
expect(subject[1].name).to eq 'carrot-soup-green'
|
68
|
+
expect(subject[1].state).to eq 'started'
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
describe '#routes' do
|
75
|
+
subject { Cloudfoundry.routes }
|
76
|
+
before do
|
77
|
+
allow(CommandLine).to receive(:backtick).with('cf routes').and_return(cli_routes_output)
|
78
|
+
end
|
79
|
+
|
80
|
+
context 'there is a route defined in the current organization' do
|
81
|
+
let(:cli_routes_output) {
|
82
|
+
<<-CLI
|
83
|
+
Getting routes as pivot-pong-developers@googlegroups.com ...
|
84
|
+
|
85
|
+
host domain apps
|
86
|
+
pivot-pong-blue cfapps.io pivot-pong-staging-blue
|
87
|
+
pivot-pong-green cfapps.io pivot-pong-staging-green
|
88
|
+
la-pong cfapps.io pivot-pong-staging-green
|
89
|
+
CLI
|
90
|
+
}
|
91
|
+
|
92
|
+
|
93
|
+
it 'parses the CLI "routes" output into a collection of Route objects, one for each route' do
|
94
|
+
expect(subject).to be_kind_of(Array)
|
95
|
+
expect(subject.length).to eq 3
|
96
|
+
expect(subject[0].host).to eq 'pivot-pong-blue'
|
97
|
+
expect(subject[0].domain).to eq 'cfapps.io'
|
98
|
+
expect(subject[0].app).to eq 'pivot-pong-staging-blue'
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
context '"cf routes" fails with an error' do
|
103
|
+
let(:cli_routes_output) {
|
104
|
+
<<-CLI
|
105
|
+
Getting routes as pivot-pong-developers@googlegroups.com ...
|
106
|
+
|
107
|
+
FAILED
|
108
|
+
Failed fetching routes.
|
109
|
+
CLI
|
110
|
+
}
|
111
|
+
it 'throws a CloudfoundryCliError' do
|
112
|
+
expect{ subject }.to raise_error(CloudfoundryCliError)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
describe '#map_route' do
|
118
|
+
let(:app) { 'the-app' }
|
119
|
+
let(:domain) { 'the-domain' }
|
120
|
+
let(:host) { 'the-host' }
|
121
|
+
|
122
|
+
subject { Cloudfoundry.map_route(app, domain, host) }
|
123
|
+
|
124
|
+
it 'invokes the Cloudfoundry CLI command "map-route" with the proper set of parameters' do
|
125
|
+
expect(CommandLine).to receive(:system).with("cf map-route #{app} #{domain} -n #{host}").and_return(true)
|
126
|
+
subject
|
127
|
+
end
|
128
|
+
|
129
|
+
context 'when the Cloudfoundry map-route fails' do
|
130
|
+
before do
|
131
|
+
allow(CommandLine).to receive(:system).and_return(false)
|
132
|
+
end
|
133
|
+
it 'throws a CloudfoundryCliError' do
|
134
|
+
expect{ subject }.to raise_error(CloudfoundryCliError)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
describe '#unmap_route' do
|
140
|
+
let(:app) { 'the-app' }
|
141
|
+
let(:domain) { 'the-domain' }
|
142
|
+
let(:host) { 'the-host' }
|
143
|
+
|
144
|
+
subject { Cloudfoundry.unmap_route(app, domain, host) }
|
145
|
+
|
146
|
+
it 'invokes the Cloudfoundry CLI command "unmap-route" with the proper set of parameters' do
|
147
|
+
expect(CommandLine).to receive(:system).with("cf unmap-route #{app} #{domain} -n #{host}").and_return(true)
|
148
|
+
subject
|
149
|
+
end
|
150
|
+
|
151
|
+
context 'when the Cloudfoundry unmap-route fails' do
|
152
|
+
before do
|
153
|
+
allow(CommandLine).to receive(:system).and_return(false)
|
154
|
+
end
|
155
|
+
it 'throws a CloudfoundryCliError' do
|
156
|
+
expect{ subject }.to raise_error(CloudfoundryCliError)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module CloudfoundryBlueGreenDeploy
|
4
|
+
describe CommandLine do
|
5
|
+
describe 'backtick' do
|
6
|
+
it 'runs the supplied command and returns the stdout string' do
|
7
|
+
expect(CommandLine.backtick('echo "sports"')).to eq "sports\n"
|
8
|
+
end
|
9
|
+
it 'ensures that cf output omits ANSI color sequences' do
|
10
|
+
expect(CommandLine.backtick('echo $CF_COLOR')).to eq "false\n"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe 'system' do
|
15
|
+
it 'runs the supplied command using Kernel.system' do
|
16
|
+
expect(Kernel).to receive(:system)
|
17
|
+
CommandLine.system('echo "sports"')
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/spec/manifest.yml
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
---
|
2
|
+
applications:
|
3
|
+
|
4
|
+
- name: the-web-app-worker-green
|
5
|
+
host: the-web-app-worker-green
|
6
|
+
size: 1GB
|
7
|
+
command: bundle exec rake cf:on_first_instance db:migrate && bundle exec rails s -p $PORT -e $RAILS_ENV
|
8
|
+
services:
|
9
|
+
- creme-fraiche
|
10
|
+
|
11
|
+
- name: hard-worker-green
|
12
|
+
host: hard-worker-green
|
13
|
+
size: 1GB
|
14
|
+
command: bundle exec rake cf:on_first_instance db:migrate && bundle exec rails s -p $PORT -e $RAILS_ENV
|
15
|
+
services:
|
16
|
+
- creme-fraiche
|
17
|
+
|
18
|
+
- name: the-web-app-green
|
19
|
+
host: the-web-url-green
|
20
|
+
domain: cfapps.io
|
21
|
+
size: 1GB
|
22
|
+
command: bundle exec rake cf:on_first_instance db:migrate && bundle exec rails s -p $PORT -e $RAILS_ENV
|
23
|
+
services:
|
24
|
+
- oyster-cracker
|
25
|
+
|
26
|
+
- name: the-web-app-blue
|
27
|
+
host: the-web-url-blue
|
28
|
+
domain: cfapps.io
|
29
|
+
size: 1GB
|
30
|
+
command: bundle exec rake cf:on_first_instance db:migrate && bundle exec rails s -p $PORT -e $RAILS_ENV
|
31
|
+
services:
|
32
|
+
- oyster-cracker
|
33
|
+
|
34
|
+
- name: the-web-app-worker-blue
|
35
|
+
host: the-web-app-worker-blue
|
36
|
+
size: 1GB
|
37
|
+
command: bundle exec rake cf:on_first_instance db:migrate && bundle exec rails s -p $PORT -e $RAILS_ENV
|
38
|
+
services:
|
39
|
+
- creme-fraiche
|
40
|
+
|
41
|
+
- name: hard-worker-blue
|
42
|
+
host: hard-worker-blue
|
43
|
+
size: 1GB
|
44
|
+
command: bundle exec rake cf:on_first_instance db:migrate && bundle exec rails s -p $PORT -e $RAILS_ENV
|
45
|
+
services:
|
46
|
+
- creme-fraiche
|
47
|
+
|
48
|
+
- name: the-web-app-shutter
|
49
|
+
host: the-web-url-shutter
|
50
|
+
domain: cfapps.io
|
51
|
+
command: bundle exec rackup config.ru -p $PORT -E $RACK_ENV
|
data/spec/route_spec.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module CloudfoundryBlueGreenDeploy
|
4
|
+
describe Route do
|
5
|
+
describe '.initialize' do
|
6
|
+
context 'when supplied an empty "app"' do
|
7
|
+
it 'reports "app" as nil' do
|
8
|
+
expect(Route.new('blah', 'blah', '').app).to be_nil
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,134 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cloudfoundry_blue_green_deploy
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- John Ryan and Mariana Lenetis
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-05-09 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.6'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.6'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: awesome_print
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
description: Blue-green deployment tool for Cloud Foundry. Please see readme.
|
70
|
+
email:
|
71
|
+
- jryan@pivotallabs.com
|
72
|
+
- mlenetis@pivotallabs.com
|
73
|
+
executables: []
|
74
|
+
extensions: []
|
75
|
+
extra_rdoc_files: []
|
76
|
+
files:
|
77
|
+
- ".gitignore"
|
78
|
+
- Gemfile
|
79
|
+
- LICENSE.txt
|
80
|
+
- README.md
|
81
|
+
- Rakefile
|
82
|
+
- cloudfoundry_blue_green_deploy.gemspec
|
83
|
+
- lib/cloudfoundry_blue_green_deploy.rb
|
84
|
+
- lib/cloudfoundry_blue_green_deploy/app.rb
|
85
|
+
- lib/cloudfoundry_blue_green_deploy/blue_green_deploy.rb
|
86
|
+
- lib/cloudfoundry_blue_green_deploy/blue_green_deploy_config.rb
|
87
|
+
- lib/cloudfoundry_blue_green_deploy/blue_green_deploy_error.rb
|
88
|
+
- lib/cloudfoundry_blue_green_deploy/cloudfoundry.rb
|
89
|
+
- lib/cloudfoundry_blue_green_deploy/command_line.rb
|
90
|
+
- lib/cloudfoundry_blue_green_deploy/railtie.rb
|
91
|
+
- lib/cloudfoundry_blue_green_deploy/route.rb
|
92
|
+
- lib/cloudfoundry_blue_green_deploy/tasks/cf.rake
|
93
|
+
- lib/cloudfoundry_blue_green_deploy/version.rb
|
94
|
+
- spec/blue_green_deploy_config_spec.rb
|
95
|
+
- spec/blue_green_deploy_spec.rb
|
96
|
+
- spec/cloudfoundry_fake.rb
|
97
|
+
- spec/cloudfoundry_spec.rb
|
98
|
+
- spec/command_line_spec.rb
|
99
|
+
- spec/manifest.yml
|
100
|
+
- spec/route_spec.rb
|
101
|
+
- spec/spec_helper.rb
|
102
|
+
homepage: ''
|
103
|
+
licenses:
|
104
|
+
- MIT
|
105
|
+
metadata: {}
|
106
|
+
post_install_message:
|
107
|
+
rdoc_options: []
|
108
|
+
require_paths:
|
109
|
+
- lib
|
110
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
111
|
+
requirements:
|
112
|
+
- - ">="
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
version: '0'
|
115
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
116
|
+
requirements:
|
117
|
+
- - ">="
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
version: '0'
|
120
|
+
requirements: []
|
121
|
+
rubyforge_project:
|
122
|
+
rubygems_version: 2.2.0
|
123
|
+
signing_key:
|
124
|
+
specification_version: 4
|
125
|
+
summary: Blue-green deployment tool for Cloud Foundry.
|
126
|
+
test_files:
|
127
|
+
- spec/blue_green_deploy_config_spec.rb
|
128
|
+
- spec/blue_green_deploy_spec.rb
|
129
|
+
- spec/cloudfoundry_fake.rb
|
130
|
+
- spec/cloudfoundry_spec.rb
|
131
|
+
- spec/command_line_spec.rb
|
132
|
+
- spec/manifest.yml
|
133
|
+
- spec/route_spec.rb
|
134
|
+
- spec/spec_helper.rb
|