taketo 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -78,11 +78,37 @@ Destination resolving works intelligently. Given the following config:
78
78
 
79
79
  ```taketo my_project:staging``` will ssh to s1 with host = 1.2.3.4
80
80
  ```taketo my_project2``` will ssh to s2 with host = 2.3.4.5
81
- ```taketo mps2``` will ssh to s2 with host = 3.4.5.6 - note the use of global alias
81
+ ```taketo mps1``` will ssh to ps1 with host = 3.4.5.6 - note the use of global alias
82
82
 
83
83
  Note that default destination can be specified via ```default_destination``` config option
84
84
 
85
-
85
+ You can use shared server configs to reduce duplication:
86
+
87
+ ```ruby
88
+ shared_server_config :my_staging do
89
+ command :console do
90
+ execute "rails c"
91
+ desc "Launch rails console"
92
+ end
93
+ end
94
+
95
+ project :my_project do
96
+ environment :staging do
97
+ server :s1 do
98
+ host "1.2.3.4"
99
+ include_shared_server_config(:my_staging)
100
+ end
101
+
102
+ server :s2 do
103
+ host :s2 do
104
+ include_shared_server_config(:my_staging)
105
+ end
106
+ end
107
+ end
108
+ ```
109
+
110
+ This will give you ```console``` commands available both on s1 and s2
111
+
86
112
  To-Do:
87
113
  ------
88
114
 
@@ -92,6 +118,10 @@ To-Do:
92
118
  The Changelog:
93
119
  --------------
94
120
 
121
+ ### v0.0.6 (26.07.2012) ###
122
+ * Add identity_file server config option
123
+ * Add shared server config support
124
+
95
125
  ### v0.0.5 (24.07.2012) ###
96
126
  * Add --directory option, which enables specifying directory on remote server upon launch
97
127
  * Add global_alias config option for servers
data/Rakefile CHANGED
@@ -15,7 +15,14 @@ require 'rspec/core/rake_task'
15
15
  require 'cucumber'
16
16
  require 'cucumber/rake/task'
17
17
 
18
- RSpec::Core::RakeTask.new
18
+ RSpec::Core::RakeTask.new do |t|
19
+ t.pattern = 'spec/lib/**/*_spec.rb'
20
+ end
21
+
22
+ RSpec::Core::RakeTask.new do |t|
23
+ t.pattern = 'spec/integration/**/*_spec.rb'
24
+ t.name = :integration_spec
25
+ end
19
26
 
20
27
  Cucumber::Rake::Task.new(:features) do |t|
21
28
  t.cucumber_opts = "features --tags ~@wip --format pretty -x"
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.5
1
+ 0.0.6
data/bin/taketo CHANGED
@@ -31,7 +31,7 @@ def parse_options
31
31
 
32
32
  OptionParser.new do |opts|
33
33
  opts.banner = "Usage: taketo [destination] [options]"
34
- opts.version = VERSION
34
+ opts.version = ::Taketo::VERSION
35
35
  opts.separator ""
36
36
  opts.separator "Common options:"
37
37
 
@@ -0,0 +1,90 @@
1
+ Feature: taketo config
2
+ In order to get rid of routineous ssh command calls
3
+ As a user
4
+ I want to be able configure taketo
5
+
6
+ Scenario: Shared server configs
7
+ When I have the following config in "/tmp/taketo_test_cfg.rb"
8
+ """
9
+ shared_server_config :shared_config_example do
10
+ port 9999 #can contain any server config options
11
+ end
12
+
13
+ project :slots do
14
+ environment :staging do
15
+ server(:s1) { host "1.2.3.4"; include_shared_server_config(:shared_config_example) }
16
+ end
17
+ end
18
+ """
19
+ And I successfully run `taketo slots:staging:s1 --config=/tmp/taketo_test_cfg.rb --dry-run`
20
+ Then the output should contain
21
+ """
22
+ ssh -t -p 9999 1.2.3.4 "RAILS_ENV=staging bash"
23
+ """
24
+
25
+ Scenario: Set environment variables
26
+ When I have the following config in "/tmp/taketo_test_cfg.rb"
27
+ """
28
+ project :slots do
29
+ environment :staging do
30
+ server do
31
+ host "1.2.3.4"
32
+ location "/var/apps/slots"
33
+ env :FOO => "the value"
34
+ end
35
+ end
36
+ end
37
+ """
38
+ And I successfully run `taketo --config=/tmp/taketo_test_cfg.rb --dry-run`
39
+ Then the output should contain
40
+ """
41
+ RAILS_ENV=staging
42
+ """
43
+ And the output should contain
44
+ """
45
+ FOO=the\ value
46
+ """
47
+
48
+ Scenario: Reopen config scopes
49
+ When I have the following config in "/tmp/taketo_test_cfg.rb"
50
+ """
51
+ project :slots do
52
+ environment :staging do
53
+ server do
54
+ host "1.2.3.4"
55
+ end
56
+ end
57
+ end
58
+
59
+ project :slots do
60
+ environment :staging do
61
+ server do
62
+ env :FOO => "bar"
63
+ end
64
+ end
65
+ end
66
+ """
67
+ And I successfully run `taketo --config=/tmp/taketo_test_cfg.rb slots:staging --dry-run`
68
+ Then the output should match /ssh -t 1\.2\.3\.4 "(RAILS_ENV=staging FOO=bar|FOO=bar RAILS_ENV=staging) bash"/
69
+
70
+ Scenario: Unique server alias
71
+ When I have the following config in "/tmp/taketo_test_cfg.rb"
72
+ """
73
+ project :slots do
74
+ environment :staging do
75
+ server :s1 do
76
+ host "1.2.3.4"
77
+ end
78
+ server :s2 do
79
+ global_alias :ss2
80
+ host "2.3.4.5"
81
+ end
82
+ end
83
+ end
84
+ """
85
+ And I successfully run `taketo ss2 --config=/tmp/taketo_test_cfg.rb --dry-run`
86
+ Then the output should contain
87
+ """
88
+ ssh -t 2.3.4.5 "RAILS_ENV=staging bash"
89
+ """
90
+
@@ -46,51 +46,6 @@ Feature:
46
46
  ssh -t 1.2.3.4 "cd /var/apps/slots; RAILS_ENV=staging bash"
47
47
  """
48
48
 
49
- Scenario: Set environment variables
50
- When I have the following config in "/tmp/taketo_test_cfg.rb"
51
- """
52
- project :slots do
53
- environment :staging do
54
- server do
55
- host "1.2.3.4"
56
- location "/var/apps/slots"
57
- env :FOO => "the value"
58
- end
59
- end
60
- end
61
- """
62
- And I successfully run `taketo --config=/tmp/taketo_test_cfg.rb --dry-run`
63
- Then the output should contain
64
- """
65
- RAILS_ENV=staging
66
- """
67
- And the output should contain
68
- """
69
- FOO=the\ value
70
- """
71
-
72
- Scenario: Reopen config scopes
73
- When I have the following config in "/tmp/taketo_test_cfg.rb"
74
- """
75
- project :slots do
76
- environment :staging do
77
- server do
78
- host "1.2.3.4"
79
- end
80
- end
81
- end
82
-
83
- project :slots do
84
- environment :staging do
85
- server do
86
- env :FOO => "bar"
87
- end
88
- end
89
- end
90
- """
91
- And I successfully run `taketo --config=/tmp/taketo_test_cfg.rb slots:staging --dry-run`
92
- Then the output should match /ssh -t 1\.2\.3\.4 "(RAILS_ENV=staging FOO=bar|FOO=bar RAILS_ENV=staging) bash"/
93
-
94
49
  Scenario: Default destination
95
50
  When I have the following config in "/tmp/taketo_test_cfg.rb"
96
51
  """
@@ -111,23 +66,21 @@ Feature:
111
66
  ssh -t 2.3.4.5 "RAILS_ENV=staging bash"
112
67
  """
113
68
 
114
- Scenario: Unique server alias
69
+ Scenario: SSH key file
115
70
  When I have the following config in "/tmp/taketo_test_cfg.rb"
116
71
  """
117
72
  project :slots do
118
73
  environment :staging do
119
- server :s1 do
120
- host "1.2.3.4"
121
- end
122
- server :s2 do
123
- global_alias :ss2
74
+ server do
75
+ identity_file "/home/gor/.ssh/foo bar"
124
76
  host "2.3.4.5"
125
77
  end
126
78
  end
127
79
  end
128
80
  """
129
- And I successfully run `taketo ss2 --config=/tmp/taketo_test_cfg.rb --dry-run`
81
+ And I successfully run `taketo --config=/tmp/taketo_test_cfg.rb --dry-run`
130
82
  Then the output should contain
131
83
  """
132
- ssh -t 2.3.4.5 "RAILS_ENV=staging bash"
84
+ ssh -t -i /home/gor/.ssh/foo\ bar 2.3.4.5 "RAILS_ENV=staging bash"
133
85
  """
86
+
@@ -13,7 +13,7 @@ module Taketo
13
13
  end
14
14
 
15
15
  def render(rendered_command)
16
- %Q[ssh -t #{port} #{username}#{host} "#{rendered_command}"].squeeze(" ")
16
+ %Q[ssh -t #{port} #{identity_file} #{username}#{host} "#{rendered_command}"].squeeze(" ")
17
17
  end
18
18
 
19
19
  def host
@@ -30,6 +30,10 @@ module Taketo
30
30
  def username
31
31
  %Q[#{shellescape @server.username}@] if @server.username
32
32
  end
33
+
34
+ def identity_file
35
+ %Q[-i #{shellescape @server.identity_file}] if @server.identity_file
36
+ end
33
37
  end
34
38
  end
35
39
  end
@@ -7,7 +7,7 @@ module Taketo
7
7
  module Constructs
8
8
  class Server < BaseConstruct
9
9
  attr_reader :environment_variables
10
- attr_accessor :host, :port, :username, :default_location, :environment, :global_alias
10
+ attr_accessor :host, :port, :username, :default_location, :environment, :global_alias, :identity_file
11
11
 
12
12
  has_nodes :commands, :command
13
13
 
data/lib/taketo/dsl.rb CHANGED
@@ -2,7 +2,8 @@ require 'taketo/constructs_factory'
2
2
 
3
3
  module Taketo
4
4
  class DSL
5
- class ScopeError < StandardError; end
5
+ class ScopeError < StandardError; end
6
+ class ConfigError < StandardError; end
6
7
 
7
8
  class << self
8
9
  def define_scope(scope, parent_scope, options = {})
@@ -19,23 +20,25 @@ module Taketo
19
20
  end
20
21
  end
21
22
 
22
- def define_attribute(name, parent_scope, &block)
23
- define_method name do |attribute|
23
+ def define_method_in_scope(name, parent_scope, &block)
24
+ define_method name do |*args, &blk|
24
25
  unless current_scope?(parent_scope)
25
26
  raise ScopeError,
26
27
  "#{name} can't be defined in #{current_scope} scope"
27
28
  end
28
- instance_exec(attribute, &block)
29
+ args.push blk if blk
30
+ instance_exec(*args, &block)
29
31
  end
30
32
  end
31
33
  end
32
34
 
33
- attr_reader :current_scope_object, :config
35
+ attr_reader :current_scope_object, :config, :shared_server_configs
34
36
 
35
37
  def initialize(factory = Taketo::ConstructsFactory.new)
36
38
  @factory = factory
37
39
  @scope = [:config]
38
40
  @config = @current_scope_object = factory.create_config
41
+ @shared_server_configs = Hash.new { |h, k| raise ConfigError, "Shared server config '#{k}' is not defined!"}
39
42
  end
40
43
 
41
44
  def configure(filename = nil, &block)
@@ -56,15 +59,24 @@ module Taketo
56
59
  define_scope :server, :environment, :default_name => :default
57
60
  define_scope :command, :server
58
61
 
59
- define_attribute(:default_destination, :config) { |destination| current_scope_object.default_destination = destination }
60
- define_attribute(:host, :server) { |hostname| current_scope_object.host = hostname }
61
- define_attribute(:port, :server) { |port_number| current_scope_object.port = port_number }
62
- define_attribute(:user, :server) { |username| current_scope_object.username = username }
63
- define_attribute(:location, :server) { |path| current_scope_object.default_location = path }
64
- define_attribute(:global_alias,:server) { |alias_name| current_scope_object.global_alias = alias_name }
65
- define_attribute(:env, :server) { |env| current_scope_object.env(env) }
66
- define_attribute(:execute, :command) { |command| current_scope_object.command = command }
67
- define_attribute(:desc, :command) { |description| current_scope_object.description = description }
62
+ define_method_in_scope(:default_destination, :config) { |destination| current_scope_object.default_destination = destination }
63
+ define_method_in_scope(:host, :server) { |hostname| current_scope_object.host = hostname }
64
+ define_method_in_scope(:port, :server) { |port_number| current_scope_object.port = port_number }
65
+ define_method_in_scope(:user, :server) { |username| current_scope_object.username = username }
66
+ define_method_in_scope(:location, :server) { |path| current_scope_object.default_location = path }
67
+ define_method_in_scope(:global_alias,:server) { |alias_name| current_scope_object.global_alias = alias_name }
68
+ define_method_in_scope(:env, :server) { |env| current_scope_object.env(env) }
69
+ define_method_in_scope(:identity_file, :server) { |identity_file| current_scope_object.identity_file = identity_file }
70
+ define_method_in_scope(:execute, :command) { |command| current_scope_object.command = command }
71
+ define_method_in_scope(:desc, :command) { |description| current_scope_object.description = description }
72
+
73
+ define_method_in_scope(:shared_server_config, :config) do |name, blk|
74
+ @shared_server_configs.store(name.to_sym, blk)
75
+ end
76
+
77
+ define_method_in_scope(:include_shared_server_config, :server) do |name, *args|
78
+ instance_exec(*args, &shared_server_configs[name])
79
+ end
68
80
 
69
81
  private
70
82
 
@@ -7,7 +7,7 @@ module Taketo
7
7
  include Enumerable
8
8
  extend Forwardable
9
9
 
10
- def_delegators :@nodes, :each, :length, :size, :empty?
10
+ def_delegators :@nodes, :each, :length, :size, :empty?, :first, :last
11
11
 
12
12
  def initialize(nodes = [])
13
13
  @nodes = nodes
data/lib/taketo.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  module Taketo
2
2
  version_file = File.expand_path('../VERSION', File.dirname(__FILE__))
3
- VERSION = File.read(version_file).freeze unless defined? VERSION
3
+ VERSION = File.read(version_file).freeze
4
4
  end
5
5
 
6
6
  require 'taketo/support'
@@ -5,6 +5,13 @@ describe "Taketo DSL" do
5
5
  it "should parse config and instantiate objects" do
6
6
  factory = Taketo::ConstructsFactory.new
7
7
  config = Taketo::DSL.new(factory).configure do
8
+ shared_server_config(:commands) do
9
+ command :console do
10
+ execute "rails c"
11
+ desc "Rails console"
12
+ end
13
+ end
14
+
8
15
  project :slots do
9
16
  environment :staging do
10
17
  server do
@@ -12,9 +19,7 @@ describe "Taketo DSL" do
12
19
  user "deployer"
13
20
  location "/var/app"
14
21
  env :FOO => "bar"
15
- command :console do
16
- execute "rails c"
17
- end
22
+ include_shared_server_config :commands
18
23
  end
19
24
  end
20
25
 
@@ -26,6 +31,7 @@ describe "Taketo DSL" do
26
31
  server server_name do
27
32
  host host_name
28
33
  location "/var/app"
34
+ include_shared_server_config :commands
29
35
  end
30
36
  end
31
37
  end
@@ -46,11 +52,15 @@ describe "Taketo DSL" do
46
52
  staging_server.username.should == "deployer"
47
53
  staging_server.default_location.should == "/var/app"
48
54
  staging_server.environment_variables.should == { :RAILS_ENV => "staging", :FOO => "bar" }
49
- staging_server.commands.length.should == 1
50
- staging_server.commands[:console].command.should == "rails c"
51
55
 
52
56
  production = project.environments[:production]
53
57
  production.servers.length.should == 2
58
+ production_server_1, production_server_2 = production.servers.first, production.servers.last
59
+
60
+ [staging_server, production_server_1, production_server_2].each do |s|
61
+ s.commands.length.should == 1
62
+ s.commands[:console].command.should == "rails c"
63
+ end
54
64
  end
55
65
  end
56
66
 
@@ -11,6 +11,7 @@ describe "SSH Command" do
11
11
  :port => 22,
12
12
  :username => "deployer",
13
13
  :default_location => "/var/app",
14
+ :identity_file => "/home/gor/.ssh/qqq",
14
15
  :environment => environment,
15
16
  :environment_variables => {})
16
17
  end
@@ -19,12 +20,13 @@ describe "SSH Command" do
19
20
  let(:ssh_command) { SSHCommand.new(server) }
20
21
 
21
22
  it "should compose command based on provided server object" do
22
- ssh_command.render("foobar").should == %q[ssh -t -p 22 deployer@1.2.3.4 "foobar"]
23
+ ssh_command.render("foobar").should == %q[ssh -t -p 22 -i /home/gor/.ssh/qqq deployer@1.2.3.4 "foobar"]
23
24
  end
24
25
 
25
26
  it "should ignore absent parts" do
26
27
  server.stub(:port => nil)
27
28
  server.stub(:username => nil)
29
+ server.stub(:identity_file => nil)
28
30
  ssh_command.render("foobar").should == %q[ssh -t 1.2.3.4 "foobar"]
29
31
  end
30
32
 
@@ -16,6 +16,7 @@ describe "Server" do
16
16
  it { should have_accessor(:username) }
17
17
  it { should have_accessor(:default_location) }
18
18
  it { should have_accessor(:global_alias) }
19
+ it { should have_accessor(:identity_file) }
19
20
 
20
21
  describe "#environment=" do
21
22
  let(:environment) { environment = stub(:Environment, :name => :the_environment) }
@@ -48,7 +48,7 @@ describe "DSL" do
48
48
  end # end
49
49
  end
50
50
 
51
- shared_examples "an attribute" do |attribute_name, parent_scope_name, parent_scope_method, example_value|
51
+ shared_examples "a scoped method" do |attribute_name, parent_scope_name, parent_scope_method, example_value|
52
52
  parent_scope = scopes[parent_scope_name]
53
53
 
54
54
  it { should be_appropriate_construct(attribute_name, example_value).under(parent_scope) }
@@ -66,7 +66,41 @@ describe "DSL" do
66
66
  end
67
67
 
68
68
  describe "#default_destination" do
69
- it_behaves_like "an attribute", :default_destination, :config, :default_destination=, "foo:bar:baz"
69
+ it_behaves_like "a scoped method", :default_destination, :config, :default_destination=, "foo:bar:baz"
70
+ end
71
+
72
+ describe "Shared server config" do
73
+ specify "#shared_server_config should store a block" do
74
+ dsl(scopes[:config], factory.create(:config)) do |c|
75
+ cfg = proc { any_method_call_here }
76
+ c.shared_server_config(:foo, &cfg)
77
+ c.shared_server_configs[:foo].should == cfg
78
+ end
79
+ end
80
+
81
+ describe "#include_shared_server_config" do
82
+ it "should execute the block on dsl object in server scope" do
83
+ dsl(scopes[:server], factory.create(:server)) do |c|
84
+ c.stub(:shared_server_configs => { :foo => proc { any_method_call_here } })
85
+ c.should_receive(:any_method_call_here)
86
+ c.include_shared_server_config(:foo)
87
+ end
88
+ end
89
+
90
+ it "should accept arguments" do
91
+ dsl(scopes[:server], factory.create(:server)) do |c|
92
+ c.stub(:shared_server_configs => { :foo => proc { |qux| any_method_call_here(qux) } })
93
+ c.should_receive(:any_method_call_here).with(321)
94
+ c.include_shared_server_config(:foo, 321)
95
+ end
96
+ end
97
+
98
+ it "should raise ConfigError if non-existent config included" do
99
+ dsl(scopes[:server], factory.create(:server)) do |c|
100
+ expect { c.include_shared_server_config(:foo) }.to raise_error(Taketo::DSL::ConfigError, "Shared server config 'foo' is not defined!")
101
+ end
102
+ end
103
+ end
70
104
  end
71
105
 
72
106
  describe "#project" do
@@ -88,38 +122,42 @@ describe "DSL" do
88
122
  end
89
123
 
90
124
  describe "#host" do
91
- it_behaves_like "an attribute", :host, :server, :host=, "127.0.0.2"
125
+ it_behaves_like "a scoped method", :host, :server, :host=, "127.0.0.2"
92
126
  end
93
127
 
94
128
  describe "#port" do
95
- it_behaves_like "an attribute", :port, :server, :port=, 4096
129
+ it_behaves_like "a scoped method", :port, :server, :port=, 4096
96
130
  end
97
131
 
98
132
  describe "#user" do
99
- it_behaves_like "an attribute", :user, :server, :username=, "deployer"
133
+ it_behaves_like "a scoped method", :user, :server, :username=, "deployer"
100
134
  end
101
135
 
102
136
  describe "#location" do
103
- it_behaves_like "an attribute", :location, :server, :default_location=, "/var/app/"
137
+ it_behaves_like "a scoped method", :location, :server, :default_location=, "/var/app/"
104
138
  end
105
139
 
106
140
  describe "#env" do
107
- it_behaves_like "an attribute", :env, :server, :env, { :FOO => "bar" }
141
+ it_behaves_like "a scoped method", :env, :server, :env, { :FOO => "bar" }
108
142
  end
109
143
 
110
144
  describe "#global_alias" do
111
- it_behaves_like "an attribute", :global_alias, :server, :global_alias=, "foobared"
145
+ it_behaves_like "a scoped method", :global_alias, :server, :global_alias=, "foobared"
146
+ end
147
+
148
+ describe "#identity_file" do
149
+ it_behaves_like "a scoped method", :identity_file, :server, :identity_file=, "/home/gor/.ssh/qqq"
112
150
  end
113
151
 
114
152
  describe "#command" do
115
153
  it_behaves_like "a scope", :command, :server
116
154
 
117
155
  describe "#execute" do
118
- it_behaves_like "an attribute", :execute, :command, :command=, "rails c"
156
+ it_behaves_like "a scoped method", :execute, :command, :command=, "rails c"
119
157
  end
120
158
 
121
159
  describe "#desc" do
122
- it_behaves_like "an attribute", :desc, :command, :description=, "Run rails console"
160
+ it_behaves_like "a scoped method", :desc, :command, :description=, "Run rails console"
123
161
  end
124
162
  end
125
163
  end
@@ -18,6 +18,8 @@ describe "NamedNodesCollection" do
18
18
  collection.map(&:name).should == [:foo, :bar]
19
19
  collection.length.should == 2
20
20
  collection.size.should == 2
21
+ collection.first.should == node1
22
+ collection.last.should == node2
21
23
  end
22
24
 
23
25
  it "should raise error if element not found" do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: taketo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.6
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-07-24 00:00:00.000000000 Z
12
+ date: 2012-07-26 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
@@ -124,6 +124,7 @@ files:
124
124
  - spec/support/matchers/enclose_scope_matcher.rb
125
125
  - spec/support/matchers/have_accessor_matcher.rb
126
126
  - features/commands.feature
127
+ - features/config.feature
127
128
  - features/config_validation.feature
128
129
  - features/connect_to_server.feature
129
130
  - features/error_handling.feature