capistrano-soa 0.0.6

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/README.md ADDED
@@ -0,0 +1,31 @@
1
+ # Capistrano SOA
2
+ - An extension for Capistrano supporting SOA Services Deployment
3
+
4
+ Capistrano SOA let you management services group in SOA architecuture with multi-stage support.
5
+
6
+ ## Usage
7
+
8
+ project/
9
+ |- config/
10
+ |- deploy.rb
11
+ |- deploy/
12
+ |- sub_project_a/
13
+ | |- service_a/
14
+ | | |- development.rb
15
+ | | |- production.rb
16
+ | |- service_b
17
+ | |- development.rb
18
+ | |- production.rb
19
+ |- sub_project_b/
20
+ |- service_c/
21
+ | |- development.rb
22
+ | |- production.rb
23
+ |- service_d
24
+ |- development.rb
25
+ |- production.rb
26
+
27
+ cap production sub_project_a:service_a deploy
28
+
29
+ cap sub_project_a:service_a:production deploy
30
+
31
+ cap production sub_project_a:service_a sub_project_a:service_b deploy
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "capistrano/version"
4
+
5
+ Gem::Specification.new do |s|
6
+
7
+ s.name = "capistrano-soa"
8
+ s.version = "0.0.6"
9
+ s.platform = Gem::Platform::RUBY
10
+ s.authors = ["Ben Wu"]
11
+ s.email = ["wucheokman@gmail.com"]
12
+ s.homepage = "http://github.com/capistrano/capistrano-soa"
13
+ s.summary = %q{An extension for Capistrano supporting SOA Services Deployment}
14
+ s.description = %q{Capistrano SOA let you management services group in SOA architecuture with multi-stage support.}
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
+ s.require_paths = ["lib"]
19
+ s.extra_rdoc_files = [
20
+ "README.md"
21
+ ]
22
+ end
@@ -0,0 +1,372 @@
1
+ require 'capistrano'
2
+ require 'fileutils'
3
+ require 'colored'
4
+
5
+ module Capistrano::Ext
6
+ module SOA
7
+ def get_config_files(config_root)
8
+ config_files = Dir["#{config_root}/**/*.rb"]
9
+ config_files.reject! do |config_file|
10
+ config_dir = config_file.gsub(/\.rb$/, '/')
11
+ config_files.any? { |file| file[0, config_dir.size] == config_dir }
12
+ end
13
+ config_files
14
+ end
15
+
16
+ def collect_stages(config_files)
17
+ config_files.map {|f| File.basename(f, ".rb")}.uniq
18
+ end
19
+
20
+ def get_config_names(config_files, config_root)
21
+ config_names = config_files.map do |config_file|
22
+ config_file.sub("#{config_root}/", '').sub(/\.rb$/, '').gsub('/', ':')
23
+ end
24
+ end
25
+
26
+ def get_services_name(config_names)
27
+ services_name = []
28
+ config_names.each do |config_name|
29
+ services_name << extract_service_name(config_name)
30
+ end
31
+ services_name
32
+ end
33
+
34
+ def extract_service_name(config_name)
35
+ segments = config_name.split(':')
36
+ segments[0, segments.size - 1].join(':')
37
+ end
38
+
39
+ def get_service_name(config_name, services)
40
+ if services.include?(config_name)
41
+ config_name
42
+ else
43
+ segments = config_name.split(':')
44
+ if segments.size > 1
45
+ possible_service_name = (segments[0, segments.size - 1].join(':'))
46
+ else
47
+ possible_service_name = segments[0]
48
+ end
49
+ if services.include?(possible_service_name)
50
+ possible_service_name
51
+ elsif possible_service_name == "world"
52
+ services.dup
53
+ else
54
+ nil
55
+ end
56
+ end
57
+ end
58
+
59
+ def get_stage_name(config_name, stages)
60
+ possible_stage_name = config_name.split(':').last
61
+ stages.include?(possible_stage_name) ? possible_stage_name : nil
62
+ end
63
+
64
+ #
65
+ # One Environment with different applications deployment
66
+ # cap integration prj0:subprj0:app0 prj1:subprj0:app1 deploy
67
+ # cap prj0:subprj0:app0:integration prj0:subprj0:app0:integration deploy
68
+ #
69
+ # One environment with one application
70
+ # cap prj0:subprj0:app0:integration deploy
71
+ #
72
+ # Different Environments with different applications deployment
73
+ # cap prj0:subprj0:app0:integration prj0:subprj0:app0:staging deploy
74
+ #
75
+
76
+ def parse_args(args, stages, services)
77
+ args = args.dup
78
+ selected_services = []
79
+ task = nil
80
+ selected_stage = nil
81
+
82
+ selected_stage = if stages.include?(args.first)
83
+ args.shift
84
+ elsif !get_stage_name(args.first, stages).nil?
85
+ arg = args.shift
86
+ selected_services << get_service_name(arg, services)
87
+ get_stage_name(arg, stages)
88
+ else
89
+ nil
90
+ end
91
+ args.each do |a|
92
+ if selected_stage.nil? && !get_stage_name(a, stages).nil?
93
+ selected_stage = get_stage_name(a, stages)
94
+ _service = get_service_name(a, services)
95
+ selected_services << _service unless selected_services.include?(_service)
96
+ elsif !get_service_name(a, services).nil?
97
+ _service = get_service_name(a, services)
98
+ selected_services << _service unless selected_services.include?(_service)
99
+ else
100
+ task = a
101
+ break
102
+ end
103
+ end
104
+ [selected_stage, selected_services.flatten.uniq, task]
105
+ end
106
+
107
+ def build_task(stage, services, this_task)
108
+
109
+ if services.size > 1
110
+ segments = this_task.split(':')
111
+ if segments.size > 1
112
+ namespace_names = segments[0, segments.size-1]
113
+ task_name = segments.last
114
+ else
115
+ namespace_names = [segments[0]]
116
+ task_name = "default"
117
+ end
118
+
119
+ block = lambda do |parent|
120
+ alias_task "_#{task_name}".to_sym, task_name.to_sym
121
+
122
+ task(task_name) do
123
+ services.each do |service|
124
+ system("cap #{stage} #{service} #{this_task}")
125
+ end
126
+ end
127
+ end
128
+
129
+ block = namespace_names.reverse.inject(block) do |child, name|
130
+ lambda do |parent|
131
+ parent.namespace(name, &child)
132
+ end
133
+ end
134
+ block.call(top)
135
+ end
136
+ end
137
+
138
+ def self.load_into(configuration)
139
+ configuration.extend self
140
+
141
+ configuration.load do
142
+ config_root = File.expand_path(fetch(:config_root, "config/deploy"))
143
+
144
+ #config_files = Dir["#{config_root}/**/*.rb"]
145
+ config_files = get_config_files(config_root)
146
+
147
+ set :stages, collect_stages(config_files) unless exists?(:stages)
148
+
149
+ # build configuration names list
150
+ config_names = get_config_names(config_files,config_root)
151
+
152
+ config_names.each do |config_name|
153
+ config_name.split(':').each do |segment|
154
+ if all_methods.any? { |m| m == segment }
155
+ raise ArgumentError, "Config task #{config_name} name overrides #{segment.inspect} (method|task|namespace)"
156
+ end
157
+ end
158
+ end
159
+
160
+ stages.each do |s|
161
+ desc "Set the target stage to `#{s}'."
162
+
163
+ task(s.to_sym) do
164
+ top.set :stage, s.to_sym
165
+ end
166
+ end
167
+
168
+ # create configuration task for each configuration name
169
+ config_names.each do |config_name|
170
+ segments = config_name.split(':')
171
+ namespace_names = segments[0, segments.size - 1]
172
+ task_name = segments.last
173
+
174
+ # create configuration task block.
175
+ # NOTE: Capistrano 'namespace' DSL invokes instance_eval that
176
+ # that pass evaluable object as argument to block.
177
+ block = lambda do |parent|
178
+ task(:default) do
179
+ default_segment = segments[0, segments.size - 1]
180
+ default_segment << fetch(:stage)
181
+ default_segment.size.times do |i|
182
+ path = ([config_root] + default_segment[0..i]).join('/') + '.rb'
183
+ top.load(:file => path) if File.exists?(path)
184
+ end
185
+ end
186
+
187
+ desc "Load #{config_name} configuration"
188
+ task(task_name) do
189
+ # set configuration name as :config_name variable
190
+ top.set :config_name, config_name
191
+
192
+ #set :stage, task_name.to_sym
193
+ # recursively load configurations
194
+ segments.size.times do |i|
195
+ path = ([config_root] + segments[0..i]).join('/') + '.rb'
196
+ top.load(:file => path) if File.exists?(path)
197
+ end
198
+ end
199
+ end
200
+
201
+ # wrap task block into namespace blocks
202
+ #
203
+ # namespace_names = [nsN, ..., ns2, ns1]
204
+ #
205
+ # block = block0 = lambda do |parent|
206
+ # desc "DESC"
207
+ # task(:task_name) { TASK }
208
+ # end
209
+ # block = block1 = lambda { |parent| parent.namespace(:ns1, &block0) }
210
+ # block = block2 = lambda { |parent| parent.namespace(:ns2, &block1) }
211
+ # ...
212
+ # block = blockN = lambda { |parent| parent.namespace(:nsN, &blockN-1) }
213
+ #
214
+ block = namespace_names.reverse.inject(block) do |child, name|
215
+ lambda do |parent|
216
+ parent.namespace(name, &child)
217
+ end
218
+ end
219
+
220
+ # create namespaced configuration task
221
+ #
222
+ # block = lambda do
223
+ # namespace :nsN do
224
+ # ...
225
+ # namespace :ns2 do
226
+ # namespace :ns1 do
227
+ # desc "DESC"
228
+ # task(:task_name) { TASK }
229
+ # end
230
+ # end
231
+ # ...
232
+ # end
233
+ # end
234
+ block.call(top)
235
+ end
236
+
237
+ STDOUT.sync
238
+ before "deploy:update_code" do
239
+ print "Updating Code........ "
240
+ start_spinner()
241
+ end
242
+
243
+ after "deploy:update_code" do
244
+ stop_spinner()
245
+ puts "Done.".green
246
+ end
247
+
248
+ before "deploy:cleanup" do
249
+ print "Cleaning Up.......... "
250
+ start_spinner()
251
+ end
252
+
253
+ after "deploy:restart" do
254
+ stop_spinner()
255
+ puts "Done.".green
256
+ end
257
+
258
+ before "deploy:restart" do
259
+ print "Restarting .......... "
260
+ start_spinner()
261
+ end
262
+
263
+ after "deploy:cleanup" do
264
+ stop_spinner()
265
+ puts "Done.".green
266
+ end
267
+ # spinner stuff
268
+ @spinner_running = false
269
+ @chars = ['|', '/', '-', '\\']
270
+ @spinner = Thread.new do
271
+ loop do
272
+ unless @spinner_running
273
+ Thread.stop
274
+ end
275
+ print @chars[0]
276
+ sleep(0.1)
277
+ print "\b"
278
+ @chars.push @chars.shift
279
+ end
280
+ end
281
+
282
+ def start_spinner
283
+ @spinner_running = true
284
+ @spinner.wakeup
285
+ end
286
+
287
+ # stops the spinner and backspaces over last displayed character
288
+ def stop_spinner
289
+ @spinner_running = false
290
+ print "\b"
291
+ end
292
+
293
+ on :load do
294
+ services_name = get_services_name(config_names)
295
+
296
+ selected_stage, selected_services, selected_task = parse_args(ARGV, stages, services_name)
297
+
298
+ set :stage, selected_stage
299
+ set :services, selected_services
300
+ build_task(selected_stage, selected_services, selected_task)
301
+
302
+ if stages.include?(stage)
303
+ # Execute the specified stage so that recipes required in stage can contribute to task list
304
+ tsk = stage
305
+ tsk = "#{services.first}:#{tsk}" if services.first
306
+ find_and_execute_task(tsk)# if ARGV.any?{ |option| option =~ /-T|--tasks|-e|--explain/ }
307
+ else
308
+ # Execute the default stage so that recipes required in stage can contribute tasks
309
+ if exists?(:default_stage)
310
+ tsk = default_stage
311
+ tsk = "#{services.first}:#{tsk}" if services.first
312
+ find_and_execute_task(tsk)
313
+ end
314
+ end
315
+ end
316
+
317
+ namespace :soa do
318
+ desc "[internal] Ensure that a stage has been selected."
319
+ task :ensure do
320
+ if !exists?(:stage)
321
+ if exists?(:default_stage)
322
+ logger.important "Defaulting to `#{default_stage}'"
323
+ find_and_execute_task("#{ARGV.first}:#{default_stage}")
324
+ else
325
+ abort "No stage specified. Please specify one of: #{stages.join(', ')} (e.g. `cap #{stages.first} #{ARGV.last}')"
326
+ end
327
+ end
328
+ end
329
+ end
330
+
331
+ set(:config_names, config_names)
332
+
333
+ on :start, "soa:ensure"
334
+
335
+ def service_list_from(services)
336
+ services = services.split(',') if String == services
337
+ services.reject {|s| !services_name.include?(s)}
338
+ end
339
+
340
+ def find_soa_stages(stage)
341
+ unless ENV["SRVS"].nil?
342
+ services = services_list_from(ENV["SRVS"])
343
+ else
344
+ services = services_name
345
+ end
346
+ end
347
+
348
+ task(:world) do
349
+ end
350
+
351
+ # namespace :world do
352
+ # stages.each do |stage|
353
+ # namespace stage.to_sym do
354
+ # task :deploy do
355
+ # end
356
+ # end
357
+ # end
358
+ # end
359
+ end
360
+
361
+ end
362
+
363
+ end
364
+ end
365
+
366
+ unless Capistrano::Configuration.respond_to?(:instance)
367
+ abort "capistrano/ext/soa require Capistrano 2"
368
+ end
369
+
370
+ if Capistrano::Configuration.instance
371
+ Capistrano::Ext::SOA.load_into(Capistrano::Configuration.instance)
372
+ end
File without changes
@@ -0,0 +1,46 @@
1
+ require 'capistrano'
2
+ module Capistrano
3
+ module Fakerecipe
4
+ def self.load_into(configuration)
5
+ configuration.load do
6
+ before "fake:before_this_execute_thing", "fake:thing"
7
+ before "fake:before_this_also_execute_thing", "fake:thing"
8
+ after "fake:after_this_execute_thing", "fake:thing"
9
+ after "fake:after_this_also_execute_thing", "fake:thing"
10
+ namespace :fake do
11
+ namespace :inner_fake do
12
+ task :inner_thing do
13
+ run ('do inner some stuff')
14
+ end
15
+ end
16
+ desc "thing and run fake manifests"
17
+ task :thing do
18
+ set :bar, "baz"
19
+ run('do some stuff')
20
+ upload("foo", "/tmp/foo")
21
+ get('/tmp/baz', 'baz')
22
+ put('fake content', '/tmp/put')
23
+ end
24
+ desc "More fake tasks!"
25
+ task :before_this_execute_thing do
26
+ #
27
+ end
28
+ desc "You get the picture..."
29
+ task :before_this_also_execute_thing do
30
+ #
31
+ end
32
+ task :after_this_execute_thing do
33
+ #
34
+ end
35
+ task :after_this_also_execute_thing do
36
+ #
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ if Capistrano::Configuration.instance
45
+ Capistrano::FakeRecipe.load_into(Capistrano::Configuration.instance)
46
+ end
data/spec/soa_spec.rb ADDED
@@ -0,0 +1,150 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
2
+ require File.expand_path('../recipes/fake_recipe', __FILE__)
3
+ describe Capistrano::Ext::SOA, "loaded into a configuration" do
4
+ before do
5
+ @configuration = Capistrano::Configuration.new
6
+
7
+ @configuration.extend(Capistrano::Spec::ConfigurationExtension)
8
+ config_root = "/opt/deploy"
9
+
10
+ File.stub!(:expand_path) {config_root}
11
+ @project_dir = ["a/b/production.rb", "a/b/staging.rb", "a/b.rb", "a/c/staging.rb"]
12
+
13
+ Dir.stub!(:[]) {@project_dir.map {|dir| "#{config_root}/#{dir}"}}
14
+ @configuration.extend(Capistrano::Fakerecipe)
15
+ Capistrano::Fakerecipe.load_into(@configuration)
16
+ Capistrano::Ext::SOA.load_into(@configuration)
17
+ @stages = ["production", "staging"]
18
+ @services = ["a:b", "a:c"]
19
+ end
20
+
21
+ it "should define correct tasks" do
22
+ @configuration.find_task('a:b:production').should_not == nil
23
+ @configuration.find_task('a:b:staging').should_not == nil
24
+ @configuration.find_task('a:c:staging').should_not == nil
25
+ @configuration.find_task('a:c:production').should == nil
26
+ @configuration.find_task('soa:ensure').should_not == nil
27
+ end
28
+
29
+ it "should use default stage if not stage define" do
30
+ @configuration.set :default_stage, 'staging'
31
+ @configuration.find_task('a:c').should_not == nil
32
+ @configuration.find_task('world:staging:deploy')
33
+ end
34
+
35
+ it "should parse with stage only args" do
36
+ args = ["staging"]
37
+ selected_stage, selected_services, task = @configuration.parse_args(args, @stages, @services)
38
+ selected_services.should be_empty
39
+ selected_stage.should == "staging"
40
+ task.should == nil
41
+ end
42
+
43
+ it "should parse single stage with one or more services" do
44
+ args = ["staging", "a:b", "a:b:production"]
45
+ selected_stage, selected_services, task = @configuration.parse_args(args, @stages, @services)
46
+ selected_services.should == ["a:b"]
47
+ selected_stage.should == "staging"
48
+ task.should == nil
49
+ end
50
+
51
+ it "should parse single stage with one or more services" do
52
+ args = ["a:b", "a:c"]
53
+ selected_stage, selected_services, task = @configuration.parse_args(args, @stages, @services)
54
+ selected_services.should == ["a:b", "a:c"]
55
+ selected_stage.should == nil
56
+ task.should == nil
57
+ end
58
+
59
+ it "should parse single stage with one or more services" do
60
+ args = ["a:b:integration", "a:c"]
61
+ selected_stage, selected_services, task = @configuration.parse_args(args, @stages, @services)
62
+ selected_services.should == ["a:b", "a:c"]
63
+ selected_stage.should == nil
64
+ task.should == nil
65
+ end
66
+
67
+ it "should parse single stage with one or more services" do
68
+ args = ["staging", "a:b", "a:c:production"]
69
+ selected_stage, selected_services, task = @configuration.parse_args(args, @stages, @services)
70
+ selected_services.should == ["a:b", "a:c"]
71
+ selected_stage.should == "staging"
72
+ task.should == nil
73
+ end
74
+
75
+ it "should parse single stage with one or more services" do
76
+ args = ["a:b:staging", "a:c:production"]
77
+ selected_stage, selected_services, task = @configuration.parse_args(args, @stages, @services)
78
+ selected_services.should == ["a:b", "a:c"]
79
+ selected_stage.should == "staging"
80
+ task.should == nil
81
+ end
82
+
83
+ it "should parse single stage with one or more services" do
84
+ args = ["a:b", "a:c:production"]
85
+ selected_stage, selected_services, task = @configuration.parse_args(args, @stages, @services)
86
+ selected_services.should == ["a:b", "a:c"]
87
+ selected_stage.should == "production"
88
+ task.should == nil
89
+ end
90
+
91
+ it "should parse single stage with one or more services" do
92
+ args = ["staging","a:b", "deploy:start"]
93
+ selected_stage, selected_services, task = @configuration.parse_args(args, @stages, @services)
94
+ selected_services.should == ["a:b"]
95
+ selected_stage.should == "staging"
96
+ task.should == "deploy:start"
97
+ end
98
+
99
+ it "should parse single stage with one or more services" do
100
+ args = ["staging","a:b", "deploy:start", "a:d"]
101
+ selected_stage, selected_services, task = @configuration.parse_args(args, @stages, @services)
102
+ selected_services.should == ["a:b"]
103
+ selected_stage.should == "staging"
104
+ task.should == "deploy:start"
105
+ end
106
+
107
+ it "should parse single stage with one or more services" do
108
+ args = ["staging","a:b", "a:d", "deploy:start"]
109
+ selected_stage, selected_services, task = @configuration.parse_args(args, @stages, @services)
110
+ selected_services.should == ["a:b"]
111
+ selected_stage.should == "staging"
112
+ task.should == "a:d"
113
+ end
114
+
115
+ it "should parse single stage with one or more services" do
116
+ args = ["staging","world", "deploy:start"]
117
+ selected_stage, selected_services, task = @configuration.parse_args(args, @stages, @services)
118
+ selected_services.should == ["a:b", "a:c"]
119
+ selected_stage.should == "staging"
120
+ task.should == "deploy:start"
121
+ end
122
+
123
+ it "should parse single stage with one or more services" do
124
+ args = ["world:staging", "deploy:start"]
125
+ selected_stage, selected_services, task = @configuration.parse_args(args, @stages, @services)
126
+ selected_services.should == ["a:b", "a:c"]
127
+ selected_stage.should == "staging"
128
+ task.should == "deploy:start"
129
+ end
130
+
131
+ it "should run one stage and service on load" do
132
+ args = ["staging"]
133
+ ARGV = args
134
+ @configuration.trigger(:load)
135
+ @configuration.fetch(:stage).should == "staging"
136
+ @configuration.fetch(:services).should == []
137
+ end
138
+
139
+ it "should build a task for services" do
140
+ @configuration.stub!(:services).and_return(["a:b", "a:c"])
141
+
142
+ @configuration.build_task("staging", ["a:b", "a:c"],"fake:thing")
143
+
144
+ @configuration.find_task("fake:_thing").should_not == nil
145
+ @configuration.find_task("fake:thing").should_not == nil
146
+
147
+ @configuration.find_and_execute_task("fake:thing")
148
+ @configuration.fetch(:bar).should == "baz"
149
+ end
150
+ end
@@ -0,0 +1,21 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+
4
+
5
+ require 'rspec'
6
+ require 'capistrano'
7
+ require 'capistrano-spec'
8
+ require 'rspec'
9
+ require 'rspec/autorun'
10
+
11
+
12
+
13
+
14
+ # Add capistrano-spec matchers and helpers to RSpec
15
+ RSpec.configure do |config|
16
+ config.include Capistrano::Spec::Matchers
17
+ config.include Capistrano::Spec::Helpers
18
+ end
19
+
20
+ # Require your lib here
21
+ require 'capistrano/ext/soa'
metadata ADDED
@@ -0,0 +1,57 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: capistrano-soa
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.6
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Ben Wu
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-09-06 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: Capistrano SOA let you management services group in SOA architecuture
15
+ with multi-stage support.
16
+ email:
17
+ - wucheokman@gmail.com
18
+ executables: []
19
+ extensions: []
20
+ extra_rdoc_files:
21
+ - README.md
22
+ files:
23
+ - README.md
24
+ - capistrano-soa.gemspec
25
+ - lib/capistrano/ext/soa.rb
26
+ - lib/capistrano/version.rb
27
+ - spec/recipes/fake_recipe.rb
28
+ - spec/soa_spec.rb
29
+ - spec/spec_helper.rb
30
+ homepage: http://github.com/capistrano/capistrano-soa
31
+ licenses: []
32
+ post_install_message:
33
+ rdoc_options: []
34
+ require_paths:
35
+ - lib
36
+ required_ruby_version: !ruby/object:Gem::Requirement
37
+ none: false
38
+ requirements:
39
+ - - ! '>='
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ required_rubygems_version: !ruby/object:Gem::Requirement
43
+ none: false
44
+ requirements:
45
+ - - ! '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ requirements: []
49
+ rubyforge_project:
50
+ rubygems_version: 1.8.25
51
+ signing_key:
52
+ specification_version: 3
53
+ summary: An extension for Capistrano supporting SOA Services Deployment
54
+ test_files:
55
+ - spec/recipes/fake_recipe.rb
56
+ - spec/soa_spec.rb
57
+ - spec/spec_helper.rb