capistrano-soa 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
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