engineyard-serverside-adapter 1.3.1.pre
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/Rakefile +9 -0
- data/engineyard-serverside-adapter.gemspec +25 -0
- data/lib/engineyard-serverside-adapter.rb +53 -0
- data/lib/engineyard-serverside-adapter/action.rb +94 -0
- data/lib/engineyard-serverside-adapter/arguments.rb +61 -0
- data/lib/engineyard-serverside-adapter/command.rb +66 -0
- data/lib/engineyard-serverside-adapter/deploy.rb +25 -0
- data/lib/engineyard-serverside-adapter/disable_maintenance_page.rb +19 -0
- data/lib/engineyard-serverside-adapter/enable_maintenance_page.rb +19 -0
- data/lib/engineyard-serverside-adapter/integrate.rb +21 -0
- data/lib/engineyard-serverside-adapter/rollback.rb +21 -0
- data/lib/engineyard-serverside-adapter/version.rb +7 -0
- data/spec/adapter_spec.rb +125 -0
- data/spec/arguments_spec.rb +28 -0
- data/spec/deploy_spec.rb +48 -0
- data/spec/disable_maintenance_page_spec.rb +26 -0
- data/spec/enable_maintenance_page_spec.rb +28 -0
- data/spec/integrate_spec.rb +32 -0
- data/spec/rollback_spec.rb +34 -0
- data/spec/spec.opts +3 -0
- data/spec/spec_helper.rb +182 -0
- metadata +156 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path("../lib/engineyard-serverside-adapter/version", __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = "engineyard-serverside-adapter"
|
6
|
+
s.version = EY::Serverside::Adapter::VERSION
|
7
|
+
s.platform = Gem::Platform::RUBY
|
8
|
+
s.authors = []
|
9
|
+
s.email = []
|
10
|
+
s.homepage = "http://github.com/engineyard/engineyard-serverside-adapter"
|
11
|
+
s.summary = "Adapter for speaking to engineyard-serverside"
|
12
|
+
s.description = "A separate adapter for speaking the CLI language of the engineyard-serverside gem."
|
13
|
+
|
14
|
+
s.required_rubygems_version = ">= 1.3.6"
|
15
|
+
s.rubyforge_project = "engineyard-serverside-adapter"
|
16
|
+
|
17
|
+
s.add_dependency "escape", "~> 0.0.4"
|
18
|
+
s.add_dependency "json_pure", "~> 1.4.6"
|
19
|
+
s.add_development_dependency "bundler", ">= 1.0.0"
|
20
|
+
s.add_development_dependency "rspec", "~> 1.3.0"
|
21
|
+
|
22
|
+
s.files = `git ls-files`.split("\n")
|
23
|
+
s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
|
24
|
+
s.require_path = 'lib'
|
25
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
3
|
+
module EY
|
4
|
+
module Serverside
|
5
|
+
class Adapter
|
6
|
+
autoload :Action, 'engineyard-serverside-adapter/action'
|
7
|
+
autoload :Arguments, 'engineyard-serverside-adapter/arguments'
|
8
|
+
autoload :Command, 'engineyard-serverside-adapter/command'
|
9
|
+
autoload :Deploy, 'engineyard-serverside-adapter/deploy'
|
10
|
+
autoload :DisableMaintenancePage, 'engineyard-serverside-adapter/disable_maintenance_page'
|
11
|
+
autoload :EnableMaintenancePage, 'engineyard-serverside-adapter/enable_maintenance_page'
|
12
|
+
autoload :Integrate, 'engineyard-serverside-adapter/integrate'
|
13
|
+
autoload :Rollback, 'engineyard-serverside-adapter/rollback'
|
14
|
+
autoload :VERSION, 'engineyard-serverside-adapter/version'
|
15
|
+
|
16
|
+
ENGINEYARD_SERVERSIDE_VERSION = ENV['ENGINEYARD_SERVERSIDE_VERSION'] || VERSION
|
17
|
+
|
18
|
+
def initialize(gem_bin_path = "")
|
19
|
+
@gem_bin_path = Pathname.new(gem_bin_path)
|
20
|
+
@arguments = Arguments.new
|
21
|
+
|
22
|
+
yield @arguments if block_given?
|
23
|
+
end
|
24
|
+
|
25
|
+
def deploy(&b)
|
26
|
+
Deploy.new(new_action_args, &b)
|
27
|
+
end
|
28
|
+
|
29
|
+
def disable_maintenance_page(&b)
|
30
|
+
DisableMaintenancePage.new(new_action_args, &b)
|
31
|
+
end
|
32
|
+
|
33
|
+
def enable_maintenance_page(&b)
|
34
|
+
EnableMaintenancePage.new(new_action_args, &b)
|
35
|
+
end
|
36
|
+
|
37
|
+
def integrate(&b)
|
38
|
+
Integrate.new(new_action_args, &b)
|
39
|
+
end
|
40
|
+
|
41
|
+
def rollback(&b)
|
42
|
+
Rollback.new(new_action_args, &b)
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def new_action_args
|
48
|
+
{:arguments => @arguments.dup, :gem_bin_path => @gem_bin_path}
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'escape'
|
2
|
+
require 'pathname'
|
3
|
+
|
4
|
+
module EY
|
5
|
+
module Serverside
|
6
|
+
class Adapter
|
7
|
+
class Action
|
8
|
+
|
9
|
+
def initialize(options = {}, &block)
|
10
|
+
@gem_bin_path = Pathname.new(options[:gem_bin_path] || "")
|
11
|
+
arguments = options[:arguments] || Arguments.new
|
12
|
+
block.call arguments if block
|
13
|
+
|
14
|
+
extract_state_from_arguments(arguments)
|
15
|
+
validate!
|
16
|
+
end
|
17
|
+
|
18
|
+
def call(&block)
|
19
|
+
block.call check_and_install_command.to_s
|
20
|
+
block.call action_command.to_s
|
21
|
+
end
|
22
|
+
|
23
|
+
def verbose
|
24
|
+
@state[:verbose]
|
25
|
+
end
|
26
|
+
|
27
|
+
class << self
|
28
|
+
attr_accessor :options
|
29
|
+
|
30
|
+
def option(name, type, extra={:required => false})
|
31
|
+
self.options ||= {}
|
32
|
+
options[name] = extra.merge({:type => type})
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def extract_state_from_arguments(arguments)
|
39
|
+
@state = self.class.options.inject({}) do |acc, (option_name, option_attrs)|
|
40
|
+
acc.merge(option_name => arguments.send(option_name))
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def check_and_install_command
|
45
|
+
"(#{check_command}) || (#{install_command})"
|
46
|
+
end
|
47
|
+
|
48
|
+
def check_command
|
49
|
+
escaped_engineyard_serverside_version = ENGINEYARD_SERVERSIDE_VERSION.gsub(/\./, '\.')
|
50
|
+
|
51
|
+
[
|
52
|
+
Escape.shell_command([gem_path, "list", "engineyard-serverside"]),
|
53
|
+
Escape.shell_command(["grep", "engineyard-serverside "]),
|
54
|
+
Escape.shell_command(["egrep", "-q", "#{escaped_engineyard_serverside_version}[,)]"]),
|
55
|
+
].join(" | ")
|
56
|
+
end
|
57
|
+
|
58
|
+
def install_command
|
59
|
+
# rubygems looks at *.gem in its current directory for
|
60
|
+
# installation candidates, so we have to make sure it
|
61
|
+
# runs from a directory with no gem files in it.
|
62
|
+
#
|
63
|
+
# rubygems help suggests that --remote will disable this
|
64
|
+
# behavior, but it doesn't.
|
65
|
+
install_command = "cd `mktemp -d` && #{gem_path} install engineyard-serverside --no-rdoc --no-ri -v #{ENGINEYARD_SERVERSIDE_VERSION}"
|
66
|
+
Escape.shell_command(['sudo', 'sh', '-c', install_command])
|
67
|
+
end
|
68
|
+
|
69
|
+
def gem_path
|
70
|
+
@gem_bin_path.join('gem').to_s
|
71
|
+
end
|
72
|
+
|
73
|
+
def action_command
|
74
|
+
cmd = Command.new(@gem_bin_path, *task)
|
75
|
+
@state.each do |option_name, value|
|
76
|
+
option_type = self.class.options[option_name][:type]
|
77
|
+
switch = "--" + option_name.to_s.gsub(/_/, '-')
|
78
|
+
cmd.send("#{option_type}_argument", switch, value)
|
79
|
+
end
|
80
|
+
cmd
|
81
|
+
end
|
82
|
+
|
83
|
+
def validate!
|
84
|
+
self.class.options.each do |option_name, option_attrs|
|
85
|
+
if option_attrs[:required] && !@state[option_name]
|
86
|
+
raise ArgumentError, "Required field '#{option_name}' not provided."
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module EY
|
2
|
+
module Serverside
|
3
|
+
class Adapter
|
4
|
+
class Arguments < Struct.new(:app, :config, :framework_env, :instances, :migrate, :ref, :repo, :stack, :verbose)
|
5
|
+
|
6
|
+
def app=(app)
|
7
|
+
enforce_nonempty!('app', app)
|
8
|
+
super
|
9
|
+
end
|
10
|
+
|
11
|
+
def framework_env=(framework_env)
|
12
|
+
enforce_nonempty!('framework_env', framework_env)
|
13
|
+
super
|
14
|
+
end
|
15
|
+
|
16
|
+
def instances=(instances)
|
17
|
+
unless instances.respond_to?(:each)
|
18
|
+
raise ArgumentError, "Value for 'instances' must look like an enumerable."
|
19
|
+
end
|
20
|
+
|
21
|
+
if instances.empty?
|
22
|
+
raise ArgumentError, "Value for 'instances' must not be empty."
|
23
|
+
end
|
24
|
+
|
25
|
+
instances.each do |instance|
|
26
|
+
unless instance.respond_to?(:[]) && instance[:hostname] && instance[:roles]
|
27
|
+
raise ArgumentError, "Malformed instance #{instance}; it must have both [:hostname] and [:roles]"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
super
|
32
|
+
end
|
33
|
+
|
34
|
+
def ref=(ref)
|
35
|
+
enforce_nonempty!('ref', ref)
|
36
|
+
super
|
37
|
+
end
|
38
|
+
|
39
|
+
def repo=(repo)
|
40
|
+
enforce_nonempty!('repo', repo)
|
41
|
+
super
|
42
|
+
end
|
43
|
+
|
44
|
+
def stack=(stack)
|
45
|
+
enforce_nonempty!('stack', stack)
|
46
|
+
super
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def enforce_nonempty!(name, value)
|
52
|
+
if value.to_s.empty?
|
53
|
+
raise ArgumentError, "Value for '#{name}' must be non-empty."
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'escape'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module EY
|
5
|
+
module Serverside
|
6
|
+
class Adapter
|
7
|
+
class Command
|
8
|
+
def initialize(bin_path, *task)
|
9
|
+
@task = task
|
10
|
+
@arguments = []
|
11
|
+
@binary = bin_path.join('engineyard-serverside').to_s
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_s
|
15
|
+
Escape.shell_command [@binary, "_#{ENGINEYARD_SERVERSIDE_VERSION}_"] + @task + @arguments.sort_by { |x| x.first }.flatten
|
16
|
+
end
|
17
|
+
|
18
|
+
def array_argument(switch, values)
|
19
|
+
compacted = values.compact.sort
|
20
|
+
if compacted.any?
|
21
|
+
@arguments << [switch, compacted]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def boolean_argument(switch, value)
|
26
|
+
if value
|
27
|
+
@arguments << [switch]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def hash_argument(switch, pairs)
|
32
|
+
if pairs.any? {|k,v| !v.nil?}
|
33
|
+
@arguments << [switch, pairs.reject { |k,v| v.nil? }.map { |pair| pair.join(':') }.sort]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def instances_argument(_, instances)
|
38
|
+
role_pairs = instances.inject({}) do |roles, instance|
|
39
|
+
roles.merge(instance[:hostname] => instance[:roles].join(','))
|
40
|
+
end
|
41
|
+
hash_argument('--instance-roles', role_pairs)
|
42
|
+
|
43
|
+
role_pairs = instances.inject({}) do |roles, instance|
|
44
|
+
roles.merge(instance[:hostname] => instance[:name])
|
45
|
+
end
|
46
|
+
hash_argument('--instance-names', role_pairs)
|
47
|
+
|
48
|
+
array_argument('--instances', instances.map{|i| i[:hostname]})
|
49
|
+
end
|
50
|
+
|
51
|
+
def json_argument(switch, value)
|
52
|
+
if value
|
53
|
+
string_argument(switch, value.to_json)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def string_argument(switch, value)
|
58
|
+
unless value.to_s.empty?
|
59
|
+
@arguments << [switch, value]
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module EY
|
2
|
+
module Serverside
|
3
|
+
class Adapter
|
4
|
+
class Deploy < Action
|
5
|
+
|
6
|
+
option :app, :string, :required => true
|
7
|
+
option :stack, :string, :required => true
|
8
|
+
option :instances, :instances, :required => true
|
9
|
+
option :config, :json
|
10
|
+
option :verbose, :boolean
|
11
|
+
option :framework_env, :string, :required => true
|
12
|
+
option :ref, :string, :required => true
|
13
|
+
option :repo, :string, :required => true
|
14
|
+
option :migrate, :string
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def task
|
19
|
+
['deploy']
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module EY
|
2
|
+
module Serverside
|
3
|
+
class Adapter
|
4
|
+
class DisableMaintenancePage < Action
|
5
|
+
|
6
|
+
option :app, :string, :required => true
|
7
|
+
option :instances, :instances, :required => true
|
8
|
+
option :verbose, :boolean
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def task
|
13
|
+
['deploy', 'disable_maintenance_page']
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module EY
|
2
|
+
module Serverside
|
3
|
+
class Adapter
|
4
|
+
class EnableMaintenancePage < Action
|
5
|
+
|
6
|
+
option :app, :string, :required => true
|
7
|
+
option :instances, :instances, :required => true
|
8
|
+
option :verbose, :boolean
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def task
|
13
|
+
['deploy', 'enable_maintenance_page']
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module EY
|
2
|
+
module Serverside
|
3
|
+
class Adapter
|
4
|
+
class Integrate < Action
|
5
|
+
|
6
|
+
option :app, :string, :required => true
|
7
|
+
option :stack, :string, :required => true
|
8
|
+
option :instances, :instances, :required => true
|
9
|
+
option :framework_env, :string, :required => true
|
10
|
+
option :verbose, :boolean
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def task
|
15
|
+
['integrate']
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module EY
|
2
|
+
module Serverside
|
3
|
+
class Adapter
|
4
|
+
class Rollback < Action
|
5
|
+
|
6
|
+
option :app, :string, :required => true
|
7
|
+
option :stack, :string, :required => true
|
8
|
+
option :instances, :instances, :required => true
|
9
|
+
option :config, :json
|
10
|
+
option :verbose, :boolean
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def task
|
15
|
+
['deploy', 'rollback']
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
shared_examples_for "a serverside action" do
|
4
|
+
before(:each) do
|
5
|
+
@adapter = described_class.new do |args|
|
6
|
+
args.app = 'app-from-adapter-new'
|
7
|
+
args.instances = [{:hostname => 'localhost', :roles => %w[a b c]}]
|
8
|
+
args.framework_env = 'production'
|
9
|
+
args.ref = 'master'
|
10
|
+
args.repo = 'git@github.com:engineyard/engineyard-serverside.git'
|
11
|
+
args.stack = 'nginx_unicorn'
|
12
|
+
args
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
it "gives you an Arguments already set up from when you instantiated the adapter" do
|
17
|
+
command = @adapter.send(@method) do |args|
|
18
|
+
args.app.should == 'app-from-adapter-new'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
it "applies both sets of changes" do
|
23
|
+
action = @adapter.send(@method) do |args|
|
24
|
+
args.verbose = true
|
25
|
+
end
|
26
|
+
|
27
|
+
command = last_command(action)
|
28
|
+
command.should include('--app app-from-adapter-new')
|
29
|
+
command.should include('--verbose')
|
30
|
+
end
|
31
|
+
|
32
|
+
it "does not let arguments changes propagate back up to the adapter" do
|
33
|
+
command1 = @adapter.send(@method) do |args|
|
34
|
+
args.app = 'sporkr'
|
35
|
+
end
|
36
|
+
|
37
|
+
@adapter.send(@method) do |args|
|
38
|
+
args.app.should == 'app-from-adapter-new'
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context "with no pathname specified" do
|
43
|
+
it "begins both commands with no path" do
|
44
|
+
action = @adapter.send(@method) do |args|
|
45
|
+
args.verbose = true
|
46
|
+
end
|
47
|
+
|
48
|
+
commands = all_commands(action)
|
49
|
+
commands.first.should =~ /^\(gem/
|
50
|
+
commands.last.should =~ /^engineyard-serverside/
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context "with a pathname specified" do
|
55
|
+
it "begins both commands with the given path" do
|
56
|
+
adapter = described_class.new("/usr/local/grin") do |args|
|
57
|
+
args.app = 'app-from-adapter-new'
|
58
|
+
args.instances = [{:hostname => 'localhost', :roles => %w[a b c]}]
|
59
|
+
args.framework_env = 'production'
|
60
|
+
args.ref = 'master'
|
61
|
+
args.repo = 'git@github.com:engineyard/engineyard-serverside.git'
|
62
|
+
args.stack = 'nginx_unicorn'
|
63
|
+
args
|
64
|
+
end
|
65
|
+
|
66
|
+
action = adapter.send(@method) do |args|
|
67
|
+
args.verbose = true
|
68
|
+
end
|
69
|
+
|
70
|
+
commands = all_commands(action)
|
71
|
+
commands.first.should =~ %r{^\(/usr/local/grin/gem}
|
72
|
+
commands.last.should =~ %r{^/usr/local/grin/engineyard-serverside}
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe EY::Serverside::Adapter do
|
78
|
+
context ".new" do
|
79
|
+
it "lets you access the arguments" do
|
80
|
+
adapter = described_class.new do |args|
|
81
|
+
args.app = 'myapp'
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
it "does not require a block" do
|
86
|
+
lambda { described_class.new }.should_not raise_error
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
[
|
91
|
+
:deploy,
|
92
|
+
:disable_maintenance_page,
|
93
|
+
:enable_maintenance_page,
|
94
|
+
:integrate,
|
95
|
+
:rollback,
|
96
|
+
].each do |method|
|
97
|
+
context "##{method}" do
|
98
|
+
before { @method = method }
|
99
|
+
it_should_behave_like "a serverside action"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
context "mapping of methods to action classes" do
|
104
|
+
before(:each) do
|
105
|
+
@adapter = described_class.new do |args|
|
106
|
+
args.app = 'app-from-adapter-new'
|
107
|
+
args.instances = [{:hostname => 'localhost', :roles => %w[a b c]}]
|
108
|
+
args.framework_env = 'production'
|
109
|
+
args.ref = 'master'
|
110
|
+
args.repo = 'git@github.com:engineyard/engineyard-serverside.git'
|
111
|
+
args.stack = 'nginx_unicorn'
|
112
|
+
args
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
it "gives you the right command" do
|
117
|
+
@adapter.enable_maintenance_page.should be_kind_of(EY::Serverside::Adapter::EnableMaintenancePage)
|
118
|
+
@adapter.disable_maintenance_page.should be_kind_of(EY::Serverside::Adapter::DisableMaintenancePage)
|
119
|
+
@adapter.deploy.should be_kind_of(EY::Serverside::Adapter::Deploy)
|
120
|
+
@adapter.integrate.should be_kind_of(EY::Serverside::Adapter::Integrate)
|
121
|
+
@adapter.rollback.should be_kind_of(EY::Serverside::Adapter::Rollback)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe EY::Serverside::Adapter::Arguments do
|
4
|
+
def raises_argument_error(&block)
|
5
|
+
lambda {
|
6
|
+
block.call(described_class.new)
|
7
|
+
}.should raise_error(ArgumentError)
|
8
|
+
end
|
9
|
+
|
10
|
+
it "raises an ArgumentError immediately when instances is empty" do
|
11
|
+
raises_argument_error do |arguments|
|
12
|
+
arguments.instances = []
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
it "raises an ArgumentError immediately when instances is something totally silly" do
|
17
|
+
raises_argument_error do |arguments|
|
18
|
+
arguments.instances = 42
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
it "raises an ArgumentError immediately when instances contains something totally silly" do
|
23
|
+
raises_argument_error do |arguments|
|
24
|
+
arguments.instances = [nil]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
data/spec/deploy_spec.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe EY::Serverside::Adapter::Deploy do
|
4
|
+
it_should_behave_like "it installs engineyard-serverside"
|
5
|
+
|
6
|
+
it_should_behave_like "it accepts app"
|
7
|
+
it_should_behave_like "it accepts framework_env"
|
8
|
+
it_should_behave_like "it accepts instances"
|
9
|
+
it_should_behave_like "it accepts migrate"
|
10
|
+
it_should_behave_like "it accepts ref"
|
11
|
+
it_should_behave_like "it accepts repo"
|
12
|
+
it_should_behave_like "it accepts stack"
|
13
|
+
it_should_behave_like "it accepts verbose"
|
14
|
+
|
15
|
+
it_should_require :app
|
16
|
+
it_should_require :instances
|
17
|
+
it_should_require :framework_env
|
18
|
+
it_should_require :ref
|
19
|
+
it_should_require :repo
|
20
|
+
it_should_require :stack
|
21
|
+
|
22
|
+
it_should_behave_like "it treats config as optional"
|
23
|
+
it_should_behave_like "it treats migrate as optional"
|
24
|
+
|
25
|
+
context "with valid arguments" do
|
26
|
+
let(:command) do
|
27
|
+
adapter = described_class.new do |arguments|
|
28
|
+
arguments.app = "rackapp"
|
29
|
+
arguments.framework_env = 'production'
|
30
|
+
arguments.config = {'a' => 1}
|
31
|
+
arguments.instances = [{:hostname => 'localhost', :roles => %w[han solo], :name => 'chewie'}]
|
32
|
+
arguments.migrate = 'rake db:migrate'
|
33
|
+
arguments.ref = 'master'
|
34
|
+
arguments.repo = 'git@github.com:engineyard/engineyard-serverside.git'
|
35
|
+
arguments.stack = "nginx_unicorn"
|
36
|
+
end
|
37
|
+
last_command(adapter)
|
38
|
+
end
|
39
|
+
|
40
|
+
it "puts the config in the command line as json" do
|
41
|
+
command.should =~ /--config '#{Regexp.quote '{"a":1}'}'/
|
42
|
+
end
|
43
|
+
|
44
|
+
it "invokes exactly the right command" do
|
45
|
+
command.should == "engineyard-serverside _#{EY::Serverside::Adapter::VERSION}_ deploy --app rackapp --config '{\"a\":1}' --framework-env production --instance-names localhost:chewie --instance-roles localhost:han,solo --instances localhost --migrate 'rake db:migrate' --ref master --repo git@github.com:engineyard/engineyard-serverside.git --stack nginx_unicorn"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe EY::Serverside::Adapter::DisableMaintenancePage do
|
4
|
+
it_should_behave_like "it installs engineyard-serverside"
|
5
|
+
|
6
|
+
it_should_behave_like "it accepts app"
|
7
|
+
it_should_behave_like "it accepts instances"
|
8
|
+
it_should_behave_like "it accepts verbose"
|
9
|
+
|
10
|
+
it_should_require :app
|
11
|
+
it_should_require :instances
|
12
|
+
|
13
|
+
context "with valid arguments" do
|
14
|
+
let(:command) do
|
15
|
+
adapter = described_class.new do |arguments|
|
16
|
+
arguments.app = "rackapp"
|
17
|
+
arguments.instances = [{:hostname => 'localhost', :roles => %w[han solo], :name => 'chewie'}]
|
18
|
+
end
|
19
|
+
last_command(adapter)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "invokes exactly the right command" do
|
23
|
+
command.should == "engineyard-serverside _#{EY::Serverside::Adapter::VERSION}_ deploy disable_maintenance_page --app rackapp --instance-names localhost:chewie --instance-roles localhost:han,solo --instances localhost"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe EY::Serverside::Adapter::EnableMaintenancePage do
|
4
|
+
it_should_behave_like "it installs engineyard-serverside"
|
5
|
+
|
6
|
+
it_should_behave_like "it accepts app"
|
7
|
+
it_should_behave_like "it accepts instances"
|
8
|
+
it_should_behave_like "it accepts verbose"
|
9
|
+
|
10
|
+
it_should_require :app
|
11
|
+
it_should_require :instances
|
12
|
+
|
13
|
+
context "with valid arguments" do
|
14
|
+
|
15
|
+
let(:command) do
|
16
|
+
adapter = described_class.new do |arguments|
|
17
|
+
arguments.app = "rackapp"
|
18
|
+
arguments.instances = [{:hostname => 'localhost', :roles => %w[han solo], :name => 'chewie'}]
|
19
|
+
end
|
20
|
+
last_command(adapter)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "invokes exactly the right command" do
|
24
|
+
command.should == "engineyard-serverside _#{EY::Serverside::Adapter::VERSION}_ deploy enable_maintenance_page --app rackapp --instance-names localhost:chewie --instance-roles localhost:han,solo --instances localhost"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe EY::Serverside::Adapter::Integrate do
|
4
|
+
it_should_behave_like "it installs engineyard-serverside"
|
5
|
+
|
6
|
+
it_should_behave_like "it accepts app"
|
7
|
+
it_should_behave_like "it accepts framework_env"
|
8
|
+
it_should_behave_like "it accepts instances"
|
9
|
+
it_should_behave_like "it accepts stack"
|
10
|
+
it_should_behave_like "it accepts verbose"
|
11
|
+
|
12
|
+
it_should_require :app
|
13
|
+
it_should_require :stack
|
14
|
+
it_should_require :instances
|
15
|
+
it_should_require :framework_env
|
16
|
+
|
17
|
+
context "with valid arguments" do
|
18
|
+
let(:command) do
|
19
|
+
adapter = described_class.new do |arguments|
|
20
|
+
arguments.app = "rackapp"
|
21
|
+
arguments.instances = [{:hostname => 'localhost', :roles => %w[han solo], :name => 'chewie'}]
|
22
|
+
arguments.stack = "nginx_unicorn"
|
23
|
+
arguments.framework_env = "production"
|
24
|
+
end
|
25
|
+
last_command(adapter)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "invokes exactly the right command" do
|
29
|
+
command.should == "engineyard-serverside _#{EY::Serverside::Adapter::VERSION}_ integrate --app rackapp --framework-env production --instance-names localhost:chewie --instance-roles localhost:han,solo --instances localhost --stack nginx_unicorn"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe EY::Serverside::Adapter::Rollback do
|
4
|
+
it_should_behave_like "it installs engineyard-serverside"
|
5
|
+
|
6
|
+
it_should_behave_like "it accepts app"
|
7
|
+
it_should_behave_like "it accepts instances"
|
8
|
+
it_should_behave_like "it accepts stack"
|
9
|
+
it_should_behave_like "it accepts verbose"
|
10
|
+
|
11
|
+
it_should_require :app
|
12
|
+
it_should_require :stack
|
13
|
+
it_should_require :instances
|
14
|
+
|
15
|
+
context "with valid arguments" do
|
16
|
+
let(:command) do
|
17
|
+
adapter = described_class.new do |arguments|
|
18
|
+
arguments.app = "rackapp"
|
19
|
+
arguments.instances = [{:hostname => 'localhost', :roles => %w[han solo], :name => 'chewie'}]
|
20
|
+
arguments.stack = "nginx_unicorn"
|
21
|
+
arguments.config = {'a' => 1}
|
22
|
+
end
|
23
|
+
last_command(adapter)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "puts the config in the command line as json" do
|
27
|
+
command.should =~ /--config '#{Regexp.quote '{"a":1}'}'/
|
28
|
+
end
|
29
|
+
|
30
|
+
it "invokes exactly the right command" do
|
31
|
+
command.should == "engineyard-serverside _#{EY::Serverside::Adapter::VERSION}_ deploy rollback --app rackapp --config '{\"a\":1}' --instance-names localhost:chewie --instance-roles localhost:han,solo --instances localhost --stack nginx_unicorn"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/spec/spec.opts
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,182 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
3
|
+
|
4
|
+
require 'engineyard-serverside-adapter'
|
5
|
+
require 'pp'
|
6
|
+
|
7
|
+
module ArgumentsHelpers
|
8
|
+
def valid_options
|
9
|
+
{
|
10
|
+
:app => 'rackapp',
|
11
|
+
:framework_env => 'production',
|
12
|
+
:instances => [{:hostname => 'localhost', :roles => %w[han solo], :name => 'chewie'}],
|
13
|
+
:ref => 'master',
|
14
|
+
:repo => 'git@github.com:engineyard/engineyard-serverside.git',
|
15
|
+
:stack => 'nginx_unicorn',
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
def valid_arguments() arguments_without() end # without nothing --> valid :)
|
20
|
+
|
21
|
+
def arguments_with(fields)
|
22
|
+
arguments = valid_arguments
|
23
|
+
fields.each do |field, value|
|
24
|
+
arguments.send("#{field}=", value)
|
25
|
+
end
|
26
|
+
arguments
|
27
|
+
end
|
28
|
+
|
29
|
+
def arguments_without(*fields)
|
30
|
+
arguments = EY::Serverside::Adapter::Arguments.new
|
31
|
+
valid_options.each do |field, value|
|
32
|
+
arguments.send("#{field}=", value) unless fields.include?(field)
|
33
|
+
end
|
34
|
+
arguments
|
35
|
+
end
|
36
|
+
|
37
|
+
def all_commands(adapter)
|
38
|
+
commands = []
|
39
|
+
adapter.call { |command| commands << command }
|
40
|
+
commands
|
41
|
+
end
|
42
|
+
|
43
|
+
def last_command(adapter)
|
44
|
+
all_commands(adapter).last
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
module RequiredFieldHelpers
|
49
|
+
def it_should_require(field)
|
50
|
+
context "field #{field}" do
|
51
|
+
it "is just fine when #{field} is there" do
|
52
|
+
lambda { described_class.new(:arguments => valid_arguments) }.should_not raise_error
|
53
|
+
end
|
54
|
+
|
55
|
+
it "raises an error if #{field} is missing" do
|
56
|
+
lambda { described_class.new(:arguments => arguments_without(field)) }.should raise_error(ArgumentError)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
Spec::Runner.configure do |config|
|
63
|
+
config.include ArgumentsHelpers
|
64
|
+
config.extend RequiredFieldHelpers
|
65
|
+
|
66
|
+
shared_examples_for "it installs engineyard-serverside" do
|
67
|
+
it "checks for and installs engineyard-serverside before invoking it" do
|
68
|
+
adapter = described_class.new(:arguments => valid_arguments)
|
69
|
+
|
70
|
+
all_commands(adapter).size.should == 2
|
71
|
+
installation_command = all_commands(adapter).first
|
72
|
+
|
73
|
+
# of course, the only way to be sure is to actually run it, but
|
74
|
+
# this gives us regression-proofing
|
75
|
+
version = EY::Serverside::Adapter::ENGINEYARD_SERVERSIDE_VERSION
|
76
|
+
escaped_version = version.gsub(/\./, '\\.')
|
77
|
+
installation_command.should == "(gem list engineyard-serverside | grep 'engineyard-serverside ' | egrep -q '#{escaped_version}[,)]') || (sudo sh -c 'cd `mktemp -d` && gem install engineyard-serverside --no-rdoc --no-ri -v #{version}')"
|
78
|
+
|
79
|
+
|
80
|
+
installation_command.should =~ /gem list engineyard-serverside/
|
81
|
+
installation_command.should =~ /egrep -q /
|
82
|
+
installation_command.should =~ /gem install engineyard-serverside.*-v #{Regexp.quote EY::Serverside::Adapter::VERSION}/
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
shared_examples_for "it accepts verbose" do
|
87
|
+
context "the --verbose arg" do
|
88
|
+
it "is present when you set verbose to true" do
|
89
|
+
adapter = described_class.new(:arguments => arguments_with(:verbose => true))
|
90
|
+
last_command(adapter).should =~ /--verbose/
|
91
|
+
end
|
92
|
+
|
93
|
+
it "is absent when you set verbose to false" do
|
94
|
+
adapter = described_class.new(:arguments => arguments_with(:verbose => false))
|
95
|
+
last_command(adapter).should_not =~ /--verbose/
|
96
|
+
end
|
97
|
+
|
98
|
+
it "is absent when you omit verbose" do
|
99
|
+
adapter = described_class.new(:arguments => valid_arguments)
|
100
|
+
last_command(adapter).should_not =~ /--verbose/
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
{
|
106
|
+
:app => '--app',
|
107
|
+
:stack => '--stack',
|
108
|
+
:framework_env => '--framework-env',
|
109
|
+
:ref => '--ref',
|
110
|
+
:repo => '--repo',
|
111
|
+
:migrate => '--migrate',
|
112
|
+
}.each do |arg, switch|
|
113
|
+
shared_examples_for "it accepts #{arg}" do
|
114
|
+
it "puts the #{switch} arg in the command line" do
|
115
|
+
adapter = described_class.new(:arguments => arguments_with(arg => 'word'))
|
116
|
+
last_command(adapter).should =~ /#{switch} word/
|
117
|
+
end
|
118
|
+
|
119
|
+
it "handles arguments that need to be escaped" do
|
120
|
+
adapter = described_class.new(:arguments => arguments_with(arg => 'two words'))
|
121
|
+
last_command(adapter).should =~ /#{switch} 'two words'/
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
shared_examples_for "it treats #{arg} as optional" do
|
126
|
+
it "omits #{switch} when you don't give it #{arg}" do
|
127
|
+
adapter = described_class.new(:arguments => arguments_without(arg))
|
128
|
+
last_command(adapter).should_not include(switch)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
shared_examples_for "it treats config as optional" do
|
135
|
+
it "omits --config when you don't give it config" do
|
136
|
+
adapter = described_class.new(:arguments => arguments_without(:config))
|
137
|
+
last_command(adapter).should_not include('--config')
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
shared_examples_for "it accepts instances" do
|
142
|
+
context "given an unnamed instance" do
|
143
|
+
it "puts the instance in the command line" do
|
144
|
+
adapter = described_class.new(:arguments => arguments_with(
|
145
|
+
:instances => [{:hostname => 'localhost', :roles => %w[han solo], :name => nil}]
|
146
|
+
))
|
147
|
+
command = last_command(adapter)
|
148
|
+
command.should =~ /--instances localhost/
|
149
|
+
command.should =~ /--instance-roles localhost:han,solo/
|
150
|
+
command.should_not =~ /--instance-names/
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
context "given a named instance" do
|
155
|
+
it "puts the instance in the command line" do
|
156
|
+
adapter = described_class.new(:arguments => arguments_with(
|
157
|
+
:instances => [{:hostname => 'localhost', :roles => %w[han solo], :name => 'chewie'}]
|
158
|
+
))
|
159
|
+
command = last_command(adapter)
|
160
|
+
command.should =~ /--instances localhost/
|
161
|
+
command.should =~ /--instance-roles localhost:han,solo/
|
162
|
+
command.should =~ /--instance-names localhost:chewie/
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
context "given multiple instances" do
|
167
|
+
it "puts the instance in the command line" do
|
168
|
+
adapter = described_class.new(:arguments => arguments_with({
|
169
|
+
:instances => [
|
170
|
+
{:hostname => 'localhost', :roles => %w[wookie], :name => 'chewie'},
|
171
|
+
{:hostname => 'crazy-ass-amazon-1243324321.domain', :roles => %w[bounty-hunter], :name => nil},
|
172
|
+
{:hostname => 'simpler.domain', :roles => %w[pilot scruffy-lookin-nerf-herder], :name => 'han'},
|
173
|
+
]
|
174
|
+
}))
|
175
|
+
command = last_command(adapter)
|
176
|
+
command.should =~ /--instances crazy-ass-amazon-1243324321.domain localhost simpler.domain/
|
177
|
+
command.should =~ /--instance-roles crazy-ass-amazon-1243324321.domain:bounty-hunter localhost:wookie simpler.domain:pilot,scruffy-lookin-nerf-herder/
|
178
|
+
command.should =~ /--instance-names localhost:chewie simpler.domain:han/
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
metadata
ADDED
@@ -0,0 +1,156 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: engineyard-serverside-adapter
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 961915976
|
5
|
+
prerelease: true
|
6
|
+
segments:
|
7
|
+
- 1
|
8
|
+
- 3
|
9
|
+
- 1
|
10
|
+
- pre
|
11
|
+
version: 1.3.1.pre
|
12
|
+
platform: ruby
|
13
|
+
authors: []
|
14
|
+
|
15
|
+
autorequire:
|
16
|
+
bindir: bin
|
17
|
+
cert_chain: []
|
18
|
+
|
19
|
+
date: 2010-09-15 00:00:00 -07:00
|
20
|
+
default_executable:
|
21
|
+
dependencies:
|
22
|
+
- !ruby/object:Gem::Dependency
|
23
|
+
name: escape
|
24
|
+
prerelease: false
|
25
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ~>
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
hash: 23
|
31
|
+
segments:
|
32
|
+
- 0
|
33
|
+
- 0
|
34
|
+
- 4
|
35
|
+
version: 0.0.4
|
36
|
+
type: :runtime
|
37
|
+
version_requirements: *id001
|
38
|
+
- !ruby/object:Gem::Dependency
|
39
|
+
name: json_pure
|
40
|
+
prerelease: false
|
41
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ~>
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
hash: 11
|
47
|
+
segments:
|
48
|
+
- 1
|
49
|
+
- 4
|
50
|
+
- 6
|
51
|
+
version: 1.4.6
|
52
|
+
type: :runtime
|
53
|
+
version_requirements: *id002
|
54
|
+
- !ruby/object:Gem::Dependency
|
55
|
+
name: bundler
|
56
|
+
prerelease: false
|
57
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
hash: 23
|
63
|
+
segments:
|
64
|
+
- 1
|
65
|
+
- 0
|
66
|
+
- 0
|
67
|
+
version: 1.0.0
|
68
|
+
type: :development
|
69
|
+
version_requirements: *id003
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: rspec
|
72
|
+
prerelease: false
|
73
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
74
|
+
none: false
|
75
|
+
requirements:
|
76
|
+
- - ~>
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
hash: 27
|
79
|
+
segments:
|
80
|
+
- 1
|
81
|
+
- 3
|
82
|
+
- 0
|
83
|
+
version: 1.3.0
|
84
|
+
type: :development
|
85
|
+
version_requirements: *id004
|
86
|
+
description: A separate adapter for speaking the CLI language of the engineyard-serverside gem.
|
87
|
+
email: []
|
88
|
+
|
89
|
+
executables: []
|
90
|
+
|
91
|
+
extensions: []
|
92
|
+
|
93
|
+
extra_rdoc_files: []
|
94
|
+
|
95
|
+
files:
|
96
|
+
- .gitignore
|
97
|
+
- Gemfile
|
98
|
+
- Rakefile
|
99
|
+
- engineyard-serverside-adapter.gemspec
|
100
|
+
- lib/engineyard-serverside-adapter.rb
|
101
|
+
- lib/engineyard-serverside-adapter/action.rb
|
102
|
+
- lib/engineyard-serverside-adapter/arguments.rb
|
103
|
+
- lib/engineyard-serverside-adapter/command.rb
|
104
|
+
- lib/engineyard-serverside-adapter/deploy.rb
|
105
|
+
- lib/engineyard-serverside-adapter/disable_maintenance_page.rb
|
106
|
+
- lib/engineyard-serverside-adapter/enable_maintenance_page.rb
|
107
|
+
- lib/engineyard-serverside-adapter/integrate.rb
|
108
|
+
- lib/engineyard-serverside-adapter/rollback.rb
|
109
|
+
- lib/engineyard-serverside-adapter/version.rb
|
110
|
+
- spec/adapter_spec.rb
|
111
|
+
- spec/arguments_spec.rb
|
112
|
+
- spec/deploy_spec.rb
|
113
|
+
- spec/disable_maintenance_page_spec.rb
|
114
|
+
- spec/enable_maintenance_page_spec.rb
|
115
|
+
- spec/integrate_spec.rb
|
116
|
+
- spec/rollback_spec.rb
|
117
|
+
- spec/spec.opts
|
118
|
+
- spec/spec_helper.rb
|
119
|
+
has_rdoc: true
|
120
|
+
homepage: http://github.com/engineyard/engineyard-serverside-adapter
|
121
|
+
licenses: []
|
122
|
+
|
123
|
+
post_install_message:
|
124
|
+
rdoc_options: []
|
125
|
+
|
126
|
+
require_paths:
|
127
|
+
- lib
|
128
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - ">="
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
hash: 3
|
134
|
+
segments:
|
135
|
+
- 0
|
136
|
+
version: "0"
|
137
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
138
|
+
none: false
|
139
|
+
requirements:
|
140
|
+
- - ">="
|
141
|
+
- !ruby/object:Gem::Version
|
142
|
+
hash: 23
|
143
|
+
segments:
|
144
|
+
- 1
|
145
|
+
- 3
|
146
|
+
- 6
|
147
|
+
version: 1.3.6
|
148
|
+
requirements: []
|
149
|
+
|
150
|
+
rubyforge_project: engineyard-serverside-adapter
|
151
|
+
rubygems_version: 1.3.7
|
152
|
+
signing_key:
|
153
|
+
specification_version: 3
|
154
|
+
summary: Adapter for speaking to engineyard-serverside
|
155
|
+
test_files: []
|
156
|
+
|