taketo 0.0.4 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +6 -0
- data/VERSION +1 -1
- data/bin/taketo +7 -2
- data/features/commands.feature +14 -17
- data/features/connect_to_server.feature +21 -0
- data/features/error_handling.feature +28 -0
- data/lib/taketo/commands/ssh_command.rb +2 -2
- data/lib/taketo/config_printer.rb +1 -1
- data/lib/taketo/config_validator.rb +10 -0
- data/lib/taketo/constructs/base_construct.rb +53 -3
- data/lib/taketo/constructs/command.rb +5 -4
- data/lib/taketo/constructs/config.rb +4 -11
- data/lib/taketo/constructs/environment.rb +2 -11
- data/lib/taketo/constructs/project.rb +1 -14
- data/lib/taketo/constructs/server.rb +6 -13
- data/lib/taketo/destination_resolver.rb +47 -92
- data/lib/taketo/dsl.rb +1 -0
- data/spec/lib/taketo/commands/ssh_command_spec.rb +2 -3
- data/spec/lib/taketo/config_printer_spec.rb +3 -2
- data/spec/lib/taketo/config_validator_spec.rb +20 -0
- data/spec/lib/taketo/constructs/base_construct_spec.rb +39 -0
- data/spec/lib/taketo/constructs/command_spec.rb +16 -13
- data/spec/lib/taketo/constructs/config_spec.rb +6 -18
- data/spec/lib/taketo/constructs/environment_spec.rb +8 -20
- data/spec/lib/taketo/constructs/project_spec.rb +5 -17
- data/spec/lib/taketo/constructs/server_spec.rb +19 -47
- data/spec/lib/taketo/destination_resolver_spec.rb +67 -60
- data/spec/lib/taketo/dsl_spec.rb +4 -0
- data/spec/support/helpers/construct_spec_helper.rb +15 -0
- data/spec/support/matchers/have_accessor_matcher.rb +7 -0
- metadata +5 -2
data/README.md
CHANGED
@@ -61,6 +61,7 @@ Destination resolving works intelligently. Given the following config:
|
|
61
61
|
end
|
62
62
|
environment :production do
|
63
63
|
server :ps1 do
|
64
|
+
global_alias :mps1
|
64
65
|
host "3.4.5.6"
|
65
66
|
end
|
66
67
|
end
|
@@ -77,6 +78,7 @@ Destination resolving works intelligently. Given the following config:
|
|
77
78
|
|
78
79
|
```taketo my_project:staging``` will ssh to s1 with host = 1.2.3.4
|
79
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
|
80
82
|
|
81
83
|
Note that default destination can be specified via ```default_destination``` config option
|
82
84
|
|
@@ -90,6 +92,10 @@ To-Do:
|
|
90
92
|
The Changelog:
|
91
93
|
--------------
|
92
94
|
|
95
|
+
### v0.0.5 (24.07.2012) ###
|
96
|
+
* Add --directory option, which enables specifying directory on remote server upon launch
|
97
|
+
* Add global_alias config option for servers
|
98
|
+
|
93
99
|
### v0.0.4 (22.07.2012) ###
|
94
100
|
* Add --view option. Now you can view your config quickly: ```taketo my_project:environment:server --view``` or just ```taketo --view```
|
95
101
|
* Now commands can have description
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.5
|
data/bin/taketo
CHANGED
@@ -45,6 +45,11 @@ def parse_options
|
|
45
45
|
options[:command] = c
|
46
46
|
end
|
47
47
|
|
48
|
+
opts.on("-d DIRECTORY", "--directory", "Directory on destination server to cd to") do |d|
|
49
|
+
raise OptionParser::MissingArgument if String(d).strip.empty?
|
50
|
+
options[:directory] = d
|
51
|
+
end
|
52
|
+
|
48
53
|
opts.on("-v", "--view", "Show config contents and exit") do |v|
|
49
54
|
options[:view] = v
|
50
55
|
end
|
@@ -87,14 +92,14 @@ begin
|
|
87
92
|
destination_path = ARGV.shift.to_s
|
88
93
|
resolver = DestinationResolver.new(config, destination_path)
|
89
94
|
|
90
|
-
if options
|
95
|
+
if options.delete(:view)
|
91
96
|
node = resolver.get_node
|
92
97
|
puts ConfigPrinter.new.render(node).chomp
|
93
98
|
else
|
94
99
|
server = resolver.resolve
|
95
100
|
|
96
101
|
server_command = remote_command(server, options)
|
97
|
-
command_to_execute = Commands::SSHCommand.new(server).render(server_command)
|
102
|
+
command_to_execute = Commands::SSHCommand.new(server).render(server_command.render(server, options))
|
98
103
|
|
99
104
|
if options[:dry_run]
|
100
105
|
puts command_to_execute
|
data/features/commands.feature
CHANGED
@@ -4,7 +4,7 @@ Feature:
|
|
4
4
|
I want to have ability to create command shortcuts via config
|
5
5
|
or specify command directly
|
6
6
|
|
7
|
-
|
7
|
+
Background:
|
8
8
|
When I have the following config in "/tmp/taketo_test_cfg.rb"
|
9
9
|
"""
|
10
10
|
project :slots do
|
@@ -12,34 +12,31 @@ Feature:
|
|
12
12
|
server do
|
13
13
|
host "1.2.3.4"
|
14
14
|
location "/var/apps/slots"
|
15
|
+
command :console do
|
16
|
+
execute "rails c"
|
17
|
+
end
|
15
18
|
end
|
16
19
|
end
|
17
20
|
end
|
18
21
|
"""
|
19
|
-
|
22
|
+
|
23
|
+
Scenario: Run explicit command
|
24
|
+
When I successfully run `taketo --config=/tmp/taketo_test_cfg.rb --dry-run --command "TERM=xterm-256color bash"`
|
20
25
|
Then the output should contain
|
21
26
|
"""
|
22
27
|
ssh -t 1.2.3.4 "cd /var/apps/slots; RAILS_ENV=staging TERM=xterm-256color bash"
|
23
28
|
"""
|
24
29
|
|
25
30
|
Scenario: Run command defined in config
|
26
|
-
When I
|
27
|
-
"""
|
28
|
-
project :slots do
|
29
|
-
environment :staging do
|
30
|
-
server do
|
31
|
-
host "1.2.3.4"
|
32
|
-
location "/var/apps/slots"
|
33
|
-
command :console do
|
34
|
-
execute "rails c"
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
"""
|
40
|
-
And I successfully run `taketo --config=/tmp/taketo_test_cfg.rb --dry-run --command console slots:staging`
|
31
|
+
When I successfully run `taketo --config=/tmp/taketo_test_cfg.rb --dry-run --command console slots:staging`
|
41
32
|
Then the output should contain
|
42
33
|
"""
|
43
34
|
ssh -t 1.2.3.4 "cd /var/apps/slots; RAILS_ENV=staging rails c"
|
44
35
|
"""
|
45
36
|
|
37
|
+
Scenario: Override default location specified for server
|
38
|
+
When I successfully run `taketo --config=/tmp/taketo_test_cfg.rb --dry-run --directory /var/www slots:staging`
|
39
|
+
Then the output should contain
|
40
|
+
"""
|
41
|
+
ssh -t 1.2.3.4 "cd /var/www; RAILS_ENV=staging bash"
|
42
|
+
"""
|
@@ -110,3 +110,24 @@ Feature:
|
|
110
110
|
"""
|
111
111
|
ssh -t 2.3.4.5 "RAILS_ENV=staging bash"
|
112
112
|
"""
|
113
|
+
|
114
|
+
Scenario: Unique server alias
|
115
|
+
When I have the following config in "/tmp/taketo_test_cfg.rb"
|
116
|
+
"""
|
117
|
+
project :slots do
|
118
|
+
environment :staging do
|
119
|
+
server :s1 do
|
120
|
+
host "1.2.3.4"
|
121
|
+
end
|
122
|
+
server :s2 do
|
123
|
+
global_alias :ss2
|
124
|
+
host "2.3.4.5"
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
"""
|
129
|
+
And I successfully run `taketo ss2 --config=/tmp/taketo_test_cfg.rb --dry-run`
|
130
|
+
Then the output should contain
|
131
|
+
"""
|
132
|
+
ssh -t 2.3.4.5 "RAILS_ENV=staging bash"
|
133
|
+
"""
|
@@ -0,0 +1,28 @@
|
|
1
|
+
Feature:
|
2
|
+
To be able to troubleshoot my config issues quickly
|
3
|
+
As a user
|
4
|
+
I want to see meaningful errors when I accidentally specify bad location
|
5
|
+
|
6
|
+
Background:
|
7
|
+
When I have the following config in "/tmp/taketo_test_cfg.rb"
|
8
|
+
"""
|
9
|
+
default_destination "slots:staging:s2"
|
10
|
+
project :slots do
|
11
|
+
environment :staging do
|
12
|
+
server :s1 do
|
13
|
+
end
|
14
|
+
server :s2 do
|
15
|
+
host "2.3.4.5"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
"""
|
20
|
+
|
21
|
+
Scenario: Non-existent location
|
22
|
+
And I run `taketo slots:staging:qqq --config=/tmp/taketo_test_cfg.rb --dry-run`
|
23
|
+
Then the stderr should contain "server qqq not found for environment staging"
|
24
|
+
|
25
|
+
Scenario: Ambiguous location
|
26
|
+
And I run `taketo slots:staging --config=/tmp/taketo_test_cfg.rb --dry-run`
|
27
|
+
Then the stderr should contain "There are multiple servers for environment staging: s1, s2"
|
28
|
+
|
@@ -12,8 +12,8 @@ module Taketo
|
|
12
12
|
@environment = @server.environment
|
13
13
|
end
|
14
14
|
|
15
|
-
def render(
|
16
|
-
%Q[ssh -t #{port} #{username}#{host} "#{
|
15
|
+
def render(rendered_command)
|
16
|
+
%Q[ssh -t #{port} #{username}#{host} "#{rendered_command}"].squeeze(" ")
|
17
17
|
end
|
18
18
|
|
19
19
|
def host
|
@@ -10,6 +10,7 @@ module Taketo
|
|
10
10
|
ensure_projects_exist
|
11
11
|
ensure_environments_exist
|
12
12
|
ensure_servers_exist
|
13
|
+
ensure_global_server_aliases_unique
|
13
14
|
end
|
14
15
|
|
15
16
|
private
|
@@ -38,6 +39,15 @@ module Taketo
|
|
38
39
|
end
|
39
40
|
end
|
40
41
|
end
|
42
|
+
|
43
|
+
def ensure_global_server_aliases_unique
|
44
|
+
aliases = @config.projects.map { |p| p.environments.map { |e| e.servers.map(&:global_alias) } }.flatten
|
45
|
+
non_uniq_aliases = aliases.reject(&:nil?).group_by(&:to_sym).reject { |k, v| v.size == 1 }
|
46
|
+
unless non_uniq_aliases.empty?
|
47
|
+
raise ConfigError,
|
48
|
+
"There are duplicates among global server aliases: #{non_uniq_aliases.keys.join(", ")}"
|
49
|
+
end
|
50
|
+
end
|
41
51
|
end
|
42
52
|
end
|
43
53
|
|
@@ -1,22 +1,72 @@
|
|
1
1
|
require 'taketo/support'
|
2
2
|
|
3
3
|
module Taketo
|
4
|
+
class NodesNotDefinedError < StandardError; end
|
5
|
+
|
4
6
|
module Constructs
|
5
7
|
class BaseConstruct
|
6
8
|
attr_reader :name
|
7
9
|
|
10
|
+
##
|
11
|
+
# Adds nodes collections to the construct
|
12
|
+
#
|
13
|
+
# Example:
|
14
|
+
#
|
15
|
+
# class Bar < BaseConstruct
|
16
|
+
# has_nodes :foos, :foo
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# bar = Bar.new
|
20
|
+
# bar.foos # => foos collection
|
21
|
+
# bar.append_foo(foo) # adds node the collection
|
22
|
+
# bar.find_foo(:foo_name) # find foo in foos collection by name
|
23
|
+
#
|
24
|
+
def self.has_nodes(name_plural, name_singular)
|
25
|
+
self.node_types << name_plural
|
26
|
+
|
27
|
+
define_method "append_#{name_singular}" do |object|
|
28
|
+
nodes(name_plural) << object
|
29
|
+
end
|
30
|
+
|
31
|
+
define_method "find_#{name_singular}" do |name|
|
32
|
+
nodes(name_plural).find_by_name(name)
|
33
|
+
end
|
34
|
+
|
35
|
+
define_method name_plural do
|
36
|
+
nodes(name_plural)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.node_types
|
41
|
+
@node_types ||= []
|
42
|
+
end
|
43
|
+
|
8
44
|
def initialize(name)
|
9
45
|
@name = name
|
46
|
+
@nodes = {}
|
10
47
|
end
|
11
48
|
|
12
|
-
def find(
|
13
|
-
send("find_#{
|
49
|
+
def find(singular_node_name, name)
|
50
|
+
send("find_#{singular_node_name}", name) or
|
14
51
|
if block_given?
|
15
52
|
yield
|
16
53
|
else
|
17
|
-
raise KeyError, "#{
|
54
|
+
raise KeyError, "#{singular_node_name} #{name} not found for #{node_type} #{self.name}"
|
18
55
|
end
|
19
56
|
end
|
57
|
+
|
58
|
+
def nodes(name_plural)
|
59
|
+
unless self.class.node_types.include?(name_plural)
|
60
|
+
raise NodesNotDefinedError, "#{name_plural} not defined for #{node_type}"
|
61
|
+
end
|
62
|
+
@nodes[name_plural] ||= Taketo::Support::NamedNodesCollection.new
|
63
|
+
end
|
64
|
+
|
65
|
+
def node_type
|
66
|
+
demodulized = self.class.name.gsub(/.*::/, '')
|
67
|
+
demodulized.gsub(/([a-z])([A-Z])/, '\\1_\\2').downcase.to_sym
|
68
|
+
end
|
69
|
+
|
20
70
|
end
|
21
71
|
end
|
22
72
|
end
|
@@ -8,14 +8,15 @@ module Taketo
|
|
8
8
|
|
9
9
|
attr_accessor :command, :description
|
10
10
|
|
11
|
-
def render(server)
|
12
|
-
%Q[#{location(server)} #{environment_variables(server)} #{command}].strip.squeeze(" ")
|
11
|
+
def render(server, options = {})
|
12
|
+
%Q[#{location(server, options)} #{environment_variables(server)} #{command}].strip.squeeze(" ")
|
13
13
|
end
|
14
14
|
|
15
15
|
private
|
16
16
|
|
17
|
-
def location(server)
|
18
|
-
|
17
|
+
def location(server, options = {})
|
18
|
+
directory = options.fetch(:directory) { server.default_location }
|
19
|
+
%Q[cd #{shellescape directory};] if directory
|
19
20
|
end
|
20
21
|
|
21
22
|
def environment_variables(server)
|
@@ -4,19 +4,12 @@ require 'taketo/support'
|
|
4
4
|
module Taketo
|
5
5
|
module Constructs
|
6
6
|
class Config < BaseConstruct
|
7
|
-
|
8
|
-
attr_accessor :default_destination
|
9
|
-
|
10
|
-
def initialize
|
11
|
-
@projects = Taketo::Support::NamedNodesCollection.new
|
12
|
-
end
|
7
|
+
has_nodes :projects, :project
|
13
8
|
|
14
|
-
|
15
|
-
@projects << project
|
16
|
-
end
|
9
|
+
attr_accessor :default_destination
|
17
10
|
|
18
|
-
def
|
19
|
-
|
11
|
+
def initialize(*args)
|
12
|
+
super(nil)
|
20
13
|
end
|
21
14
|
end
|
22
15
|
end
|
@@ -4,20 +4,11 @@ require 'taketo/support'
|
|
4
4
|
module Taketo
|
5
5
|
module Constructs
|
6
6
|
class Environment < BaseConstruct
|
7
|
-
|
8
|
-
|
9
|
-
def initialize(name)
|
10
|
-
super
|
11
|
-
@servers = Taketo::Support::NamedNodesCollection.new
|
12
|
-
end
|
7
|
+
has_nodes :servers, :server
|
13
8
|
|
14
9
|
def append_server(server)
|
15
10
|
server.environment = self
|
16
|
-
|
17
|
-
end
|
18
|
-
|
19
|
-
def find_server(name)
|
20
|
-
@servers.find_by_name(name)
|
11
|
+
nodes(:servers) << server
|
21
12
|
end
|
22
13
|
end
|
23
14
|
end
|
@@ -4,20 +4,7 @@ require 'taketo/support'
|
|
4
4
|
module Taketo
|
5
5
|
module Constructs
|
6
6
|
class Project < BaseConstruct
|
7
|
-
|
8
|
-
|
9
|
-
def initialize(name)
|
10
|
-
super
|
11
|
-
@environments = Taketo::Support::NamedNodesCollection.new
|
12
|
-
end
|
13
|
-
|
14
|
-
def append_environment(environment)
|
15
|
-
@environments << environment
|
16
|
-
end
|
17
|
-
|
18
|
-
def find_environment(name)
|
19
|
-
@environments.find_by_name(name)
|
20
|
-
end
|
7
|
+
has_nodes :environments, :environment
|
21
8
|
end
|
22
9
|
end
|
23
10
|
end
|
@@ -2,31 +2,24 @@ require 'taketo/constructs/base_construct'
|
|
2
2
|
require 'taketo/support'
|
3
3
|
|
4
4
|
module Taketo
|
5
|
+
class CommandNotFoundError < StandardError; end
|
6
|
+
|
5
7
|
module Constructs
|
6
8
|
class Server < BaseConstruct
|
7
|
-
|
8
|
-
|
9
|
-
attr_reader :environment_variables, :commands
|
10
|
-
attr_accessor :host, :port, :username, :default_location, :environment
|
9
|
+
attr_reader :environment_variables
|
10
|
+
attr_accessor :host, :port, :username, :default_location, :environment, :global_alias
|
11
11
|
|
12
|
+
has_nodes :commands, :command
|
13
|
+
|
12
14
|
def initialize(name)
|
13
15
|
super
|
14
16
|
@environment_variables = {}
|
15
|
-
@commands = Taketo::Support::NamedNodesCollection.new
|
16
17
|
end
|
17
18
|
|
18
19
|
def env(env_variables)
|
19
20
|
@environment_variables.merge!(env_variables)
|
20
21
|
end
|
21
22
|
|
22
|
-
def append_command(command)
|
23
|
-
@commands << command
|
24
|
-
end
|
25
|
-
|
26
|
-
def find_command(name)
|
27
|
-
@commands.find_by_name(name)
|
28
|
-
end
|
29
|
-
|
30
23
|
def environment=(environment)
|
31
24
|
env(:RAILS_ENV => environment.name.to_s)
|
32
25
|
@environment = environment
|
@@ -1,126 +1,81 @@
|
|
1
1
|
module Taketo
|
2
|
-
class ConfigError < StandardError; end
|
3
2
|
class AmbiguousDestinationError < StandardError; end
|
4
3
|
class NonExistentDestinationError < StandardError; end
|
5
4
|
|
6
5
|
class DestinationResolver
|
7
|
-
|
8
|
-
|
9
|
-
set_destination(path)
|
10
|
-
end
|
6
|
+
class Path
|
7
|
+
PATH = [[:project, :projects], [:environment, :environments], [:server, :servers]].freeze
|
11
8
|
|
12
|
-
|
13
|
-
case @path.size
|
14
|
-
when 3 then resolve_by_three_segments
|
15
|
-
when 2 then resolve_by_two_segments
|
16
|
-
when 1 then resolve_by_one_segment
|
17
|
-
when 0 then resolve_with_no_segments
|
18
|
-
end
|
19
|
-
end
|
9
|
+
class PathNode < Struct.new(:name, :singular, :plural); end
|
20
10
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
when 2 then get_project_and_environment(*@path).last
|
25
|
-
when 1 then get_project(*@path)
|
26
|
-
when 0 then @config
|
11
|
+
def initialize(names)
|
12
|
+
names = names.split(":").map(&:to_sym)
|
13
|
+
@path = PATH.each_with_index.map { |n, i| PathNode.new(names[i], *n) }
|
27
14
|
end
|
28
|
-
end
|
29
|
-
|
30
|
-
private
|
31
15
|
|
32
|
-
|
33
|
-
|
34
|
-
@path = String(path).split(":").map(&:to_sym)
|
35
|
-
end
|
36
|
-
|
37
|
-
def resolve_by_three_segments
|
38
|
-
get_server(*@path)
|
39
|
-
end
|
40
|
-
|
41
|
-
def resolve_by_two_segments
|
42
|
-
project, environment = get_project_and_environment(*@path)
|
43
|
-
get_only_server_for_project_and_environment(project, environment)
|
44
|
-
end
|
45
|
-
|
46
|
-
def resolve_by_one_segment
|
47
|
-
project = get_project(*@path)
|
48
|
-
get_only_server_for_project(project)
|
49
|
-
end
|
50
|
-
|
51
|
-
def resolve_with_no_segments
|
52
|
-
unless @config.default_destination.nil?
|
53
|
-
set_destination(@config.default_destination.to_s)
|
54
|
-
return resolve
|
16
|
+
def specified
|
17
|
+
@path.reject { |n| n.name.nil? }
|
55
18
|
end
|
56
|
-
get_only_server
|
57
|
-
end
|
58
19
|
|
59
|
-
|
60
|
-
|
61
|
-
project, environment = get_project_and_environment(project_name, environment_name)
|
62
|
-
environment.servers[server_name]
|
20
|
+
def unspecified
|
21
|
+
@path - specified
|
63
22
|
end
|
64
23
|
end
|
65
24
|
|
66
|
-
def
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
[project, environment]
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
def get_only_server_for_project_and_environment(project, environment)
|
75
|
-
if environment.servers.one?
|
76
|
-
return environment.servers.first
|
77
|
-
else
|
78
|
-
raise_server_ambiguous!(project, environment)
|
25
|
+
def initialize(config, path)
|
26
|
+
@config = config
|
27
|
+
if String(path).empty? && !String(config.default_destination).empty?
|
28
|
+
path = config.default_destination
|
79
29
|
end
|
30
|
+
@path_str = path.dup
|
31
|
+
@path = Path.new(path)
|
80
32
|
end
|
81
33
|
|
82
|
-
def
|
83
|
-
|
84
|
-
@config.projects[project_name]
|
85
|
-
end
|
34
|
+
def resolve
|
35
|
+
resolve_by_global_alias || resolve_by_path
|
86
36
|
end
|
87
37
|
|
88
|
-
def
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
38
|
+
def get_node(node = @config, remaining_path = @path.specified)
|
39
|
+
handling_failure do
|
40
|
+
return node if remaining_path.empty?
|
41
|
+
next_in_path = remaining_path.shift
|
42
|
+
node = node.find(next_in_path.singular, next_in_path.name)
|
43
|
+
get_node(node, remaining_path)
|
94
44
|
end
|
95
45
|
end
|
96
46
|
|
97
|
-
|
98
|
-
if @config.projects.one?
|
99
|
-
project = @config.projects.first
|
100
|
-
get_only_server_for_project(project)
|
101
|
-
else
|
102
|
-
raise_project_ambiguous!
|
103
|
-
end
|
104
|
-
end
|
47
|
+
private
|
105
48
|
|
106
|
-
def
|
107
|
-
|
49
|
+
def resolve_by_global_alias
|
50
|
+
aliases_and_servers = Hash[servers_with_aliases]
|
51
|
+
aliases_and_servers[@path_str.to_sym] unless String(@path_str).empty?
|
108
52
|
end
|
109
53
|
|
110
|
-
def
|
111
|
-
|
112
|
-
|
54
|
+
def resolve_by_path
|
55
|
+
node = get_node
|
56
|
+
get_only_server(node)
|
113
57
|
end
|
114
58
|
|
115
|
-
def
|
116
|
-
|
117
|
-
|
59
|
+
def get_only_server(node, remaining_path = @path.unspecified)
|
60
|
+
return node if remaining_path.empty?
|
61
|
+
next_in_path = remaining_path.shift
|
62
|
+
nested_nodes = node.nodes(next_in_path.plural)
|
63
|
+
if nested_nodes.one?
|
64
|
+
node = nested_nodes.first
|
65
|
+
get_only_server(node, remaining_path)
|
66
|
+
else
|
67
|
+
raise AmbiguousDestinationError, "There are multiple #{next_in_path.plural} for #{node.node_type} #{node.name}: #{nested_nodes.map(&:name).join(", ")}"
|
68
|
+
end
|
118
69
|
end
|
119
70
|
|
120
|
-
def handling_failure(message)
|
71
|
+
def handling_failure(message = nil)
|
121
72
|
yield
|
122
73
|
rescue KeyError, NonExistentDestinationError
|
123
|
-
raise NonExistentDestinationError, message
|
74
|
+
raise NonExistentDestinationError, message || $!.message
|
75
|
+
end
|
76
|
+
|
77
|
+
def servers_with_aliases
|
78
|
+
@config.nodes(:projects).map { |p| p.nodes(:environments).map { |e| e.nodes(:servers).reject { |s| s.global_alias.nil? }.map { |s| [s.global_alias, s] } } }.flatten(2)
|
124
79
|
end
|
125
80
|
end
|
126
81
|
end
|
data/lib/taketo/dsl.rb
CHANGED
@@ -61,6 +61,7 @@ module Taketo
|
|
61
61
|
define_attribute(:port, :server) { |port_number| current_scope_object.port = port_number }
|
62
62
|
define_attribute(:user, :server) { |username| current_scope_object.username = username }
|
63
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 }
|
64
65
|
define_attribute(:env, :server) { |env| current_scope_object.env(env) }
|
65
66
|
define_attribute(:execute, :command) { |command| current_scope_object.command = command }
|
66
67
|
define_attribute(:desc, :command) { |description| current_scope_object.description = description }
|
@@ -19,14 +19,13 @@ describe "SSH Command" do
|
|
19
19
|
let(:ssh_command) { SSHCommand.new(server) }
|
20
20
|
|
21
21
|
it "should compose command based on provided server object" do
|
22
|
-
|
23
|
-
ssh_command.render(command).should == %q[ssh -t -p 22 deployer@1.2.3.4 "foobar"]
|
22
|
+
ssh_command.render("foobar").should == %q[ssh -t -p 22 deployer@1.2.3.4 "foobar"]
|
24
23
|
end
|
25
24
|
|
26
25
|
it "should ignore absent parts" do
|
27
26
|
server.stub(:port => nil)
|
28
27
|
server.stub(:username => nil)
|
29
|
-
ssh_command.render(
|
28
|
+
ssh_command.render("foobar").should == %q[ssh -t 1.2.3.4 "foobar"]
|
30
29
|
end
|
31
30
|
|
32
31
|
it "should require host" do
|
@@ -6,8 +6,9 @@ include Taketo
|
|
6
6
|
describe "ConfigPrinter" do
|
7
7
|
describe "#render" do
|
8
8
|
it "should render based on node class name" do
|
9
|
-
|
10
|
-
printer.
|
9
|
+
construct = stub(:Server, :node_type => :server)
|
10
|
+
printer.should_receive(:render_server)
|
11
|
+
printer.render(construct)
|
11
12
|
end
|
12
13
|
end
|
13
14
|
|
@@ -33,6 +33,26 @@ describe "ConfigValidator" do
|
|
33
33
|
expect { validator(config).validate! }.not_to raise_error ConfigError, /environment_2/i
|
34
34
|
end
|
35
35
|
|
36
|
+
describe "global server aliases" do
|
37
|
+
let(:server_1) { stub(:Server) }
|
38
|
+
let(:server_2) { stub(:Server) }
|
39
|
+
let(:environment) { stub(:Environment, :name => :environment, :servers => [server_1, server_2]) }
|
40
|
+
let(:project) { stub(:Project, :name => :project, :environments => [environment]) }
|
41
|
+
let(:config) { stub(:Config, :projects => [project]) }
|
42
|
+
|
43
|
+
it "should not raise error if unique" do
|
44
|
+
server_1.stub(:global_alias => :foo)
|
45
|
+
server_2.stub(:global_alias => :bar)
|
46
|
+
expect { validator(config).validate! }.not_to raise_error(ConfigError, /alias/i)
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should raise error unless unique" do
|
50
|
+
server_1.stub(:global_alias => :foo)
|
51
|
+
server_2.stub(:global_alias => :foo)
|
52
|
+
expect { validator(config).validate! }.to raise_error(ConfigError, /alias/i)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
36
56
|
def validator(config)
|
37
57
|
Taketo::ConfigValidator.new(config)
|
38
58
|
end
|
@@ -40,6 +40,45 @@ describe "BaseConstruct" do
|
|
40
40
|
end
|
41
41
|
end
|
42
42
|
end
|
43
|
+
|
44
|
+
describe "#node_type" do
|
45
|
+
it "should return demodulized snake-cased class name" do
|
46
|
+
construct.node_type.should == :test_construct
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "nodes" do
|
51
|
+
class TestConstruct2 < Constructs::BaseConstruct
|
52
|
+
has_nodes :foos, :foo
|
53
|
+
end
|
54
|
+
|
55
|
+
let(:construct) { TestConstruct2.new(:node_name) }
|
56
|
+
|
57
|
+
let(:foo) { stub(:name => :bar) }
|
58
|
+
|
59
|
+
describe ".has_nodes" do
|
60
|
+
it "should define add node type to class's node_types" do
|
61
|
+
TestConstruct2.node_types.should include(:foos)
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should make nodes accessible via added methods" do
|
65
|
+
construct.append_foo(foo)
|
66
|
+
construct.foos.should include(foo)
|
67
|
+
construct.find_foo(:bar).should == foo
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe "#nodes" do
|
72
|
+
it "should return nodes collection by plural name" do
|
73
|
+
construct.append_foo(foo)
|
74
|
+
construct.nodes(:foos).should include(foo)
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should raise NodesNotDefinedError if non-specified node requested" do
|
78
|
+
expect { construct.nodes(:bars) }.to raise_error(NodesNotDefinedError, /bars/)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
43
82
|
end
|
44
83
|
|
45
84
|
|
@@ -4,23 +4,26 @@ require 'taketo/constructs/command'
|
|
4
4
|
include Taketo
|
5
5
|
|
6
6
|
describe "Command" do
|
7
|
-
|
7
|
+
subject { Taketo::Constructs::Command.new(:the_command) }
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
cmd.command.should == "rails c"
|
12
|
-
end
|
13
|
-
|
14
|
-
specify "#description= should set command description" do
|
15
|
-
cmd.description= "Run rails console"
|
16
|
-
cmd.description.should == "Run rails console"
|
17
|
-
end
|
9
|
+
it { should have_accessor(:command) }
|
10
|
+
it { should have_accessor(:description) }
|
18
11
|
|
19
12
|
describe "#render" do
|
13
|
+
let(:server) do
|
14
|
+
mock(:Server,
|
15
|
+
:environment_variables => { :FOO => "bar baz" },
|
16
|
+
:default_location => "/var/apps/the app")
|
17
|
+
end
|
18
|
+
|
20
19
|
it "should pick up server's environment variables and location" do
|
21
|
-
|
22
|
-
|
23
|
-
|
20
|
+
subject.command = "rails c"
|
21
|
+
subject.render(server).should == "cd /var/apps/the\\ app; FOO=bar\\ baz rails c"
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should let user override default directory" do
|
25
|
+
subject.command = "rails c"
|
26
|
+
subject.render(server, :directory => "/var/qux").should == "cd /var/qux; FOO=bar\\ baz rails c"
|
24
27
|
end
|
25
28
|
end
|
26
29
|
end
|
@@ -1,30 +1,18 @@
|
|
1
1
|
require File.expand_path('../../../../spec_helper', __FILE__)
|
2
|
+
require 'support/helpers/construct_spec_helper'
|
2
3
|
require 'taketo/constructs/config'
|
3
4
|
|
4
5
|
include Taketo
|
5
6
|
|
6
7
|
describe "Config" do
|
7
|
-
|
8
|
+
subject { Taketo::Constructs::Config.new }
|
8
9
|
|
9
|
-
|
10
|
-
it "should add project to config's projects collection" do
|
11
|
-
project = stub(:name => :foo)
|
12
|
-
config.append_project(project)
|
13
|
-
config.projects.should include(project)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
describe "#find_project" do
|
18
|
-
it "should find project by name" do
|
19
|
-
config.projects.should_receive(:find_by_name).with(:foo).and_return(:bar)
|
20
|
-
config.find_project(:foo).should == :bar
|
21
|
-
end
|
22
|
-
end
|
10
|
+
it_behaves_like "a construct with nodes", :projects, :project
|
23
11
|
|
24
12
|
it "should set default_destination" do
|
25
|
-
|
26
|
-
|
27
|
-
|
13
|
+
subject.default_destination.should be_nil
|
14
|
+
subject.default_destination = "foo:bar:baz"
|
15
|
+
subject.default_destination.should == "foo:bar:baz"
|
28
16
|
end
|
29
17
|
end
|
30
18
|
|
@@ -1,34 +1,22 @@
|
|
1
1
|
require File.expand_path('../../../../spec_helper', __FILE__)
|
2
|
+
require 'support/helpers/construct_spec_helper'
|
2
3
|
require 'taketo/constructs/environment'
|
3
4
|
|
4
5
|
include Taketo
|
5
6
|
|
6
7
|
describe "Environment" do
|
7
|
-
|
8
|
+
subject { Taketo::Constructs::Environment.new(:foo) }
|
8
9
|
|
9
10
|
it "should have name" do
|
10
|
-
|
11
|
+
subject.name.should == :foo
|
11
12
|
end
|
12
13
|
|
13
|
-
|
14
|
-
let(:server) { mock(:Server, :name => :foo).as_null_object }
|
14
|
+
it_behaves_like "a construct with nodes", :servers, :server
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
it "should set environment attribute on a server to self" do
|
22
|
-
server.should_receive(:environment=).with(environment)
|
23
|
-
environment.append_server(server)
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
describe "#find_server" do
|
28
|
-
it "should find server by name" do
|
29
|
-
environment.servers.should_receive(:find_by_name).with(:foo).and_return(:bar)
|
30
|
-
environment.find_server(:foo).should == :bar
|
31
|
-
end
|
16
|
+
specify "#append_server should set environment attribute on a server to self" do
|
17
|
+
server = mock(:Server, :name => :foo)
|
18
|
+
server.should_receive(:environment=).with(subject)
|
19
|
+
subject.append_server(server)
|
32
20
|
end
|
33
21
|
end
|
34
22
|
|
@@ -1,28 +1,16 @@
|
|
1
1
|
require File.expand_path('../../../../spec_helper', __FILE__)
|
2
|
+
require 'support/helpers/construct_spec_helper'
|
2
3
|
require 'taketo/constructs/project'
|
3
4
|
|
4
5
|
include Taketo
|
5
6
|
|
6
7
|
describe "Project" do
|
7
|
-
|
8
|
+
subject { Taketo::Constructs::Project.new(:foo) }
|
8
9
|
|
9
10
|
it "should have name" do
|
10
|
-
|
11
|
-
end
|
12
|
-
|
13
|
-
describe "#append_environment" do
|
14
|
-
it "should add an environment to project's environments collection" do
|
15
|
-
environment = stub(:name => :foo)
|
16
|
-
project.append_environment(environment)
|
17
|
-
project.environments.should include(environment)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
describe "#find_environment" do
|
22
|
-
it "should find environment by name" do
|
23
|
-
project.environments.should_receive(:find_by_name).with(:foo).and_return(:bar)
|
24
|
-
project.find_environment(:foo).should == :bar
|
25
|
-
end
|
11
|
+
subject.name.should == :foo
|
26
12
|
end
|
13
|
+
|
14
|
+
it_behaves_like "a construct with nodes", :environments, :environment
|
27
15
|
end
|
28
16
|
|
@@ -1,72 +1,44 @@
|
|
1
1
|
require File.expand_path('../../../../spec_helper', __FILE__)
|
2
|
+
require 'support/helpers/construct_spec_helper'
|
2
3
|
require 'taketo/constructs/server'
|
3
4
|
|
4
5
|
include Taketo
|
5
6
|
|
6
7
|
describe "Server" do
|
7
|
-
|
8
|
-
let(:server) { Taketo::Constructs::Server.new(:foo) }
|
8
|
+
subject { Taketo::Constructs::Server.new(:foo) }
|
9
9
|
|
10
10
|
it "should have name" do
|
11
|
-
|
11
|
+
subject.name.should == :foo
|
12
12
|
end
|
13
13
|
|
14
|
-
it
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
it "should set port" do
|
20
|
-
server.port = "foo"
|
21
|
-
server.port.should == "foo"
|
22
|
-
end
|
23
|
-
|
24
|
-
it "should set username" do
|
25
|
-
server.username = "foo"
|
26
|
-
server.username.should == "foo"
|
27
|
-
end
|
28
|
-
|
29
|
-
it "should set default_location" do
|
30
|
-
server.default_location = "foo"
|
31
|
-
server.default_location.should == "foo"
|
32
|
-
end
|
14
|
+
it { should have_accessor(:host) }
|
15
|
+
it { should have_accessor(:port) }
|
16
|
+
it { should have_accessor(:username) }
|
17
|
+
it { should have_accessor(:default_location) }
|
18
|
+
it { should have_accessor(:global_alias) }
|
33
19
|
|
34
20
|
describe "#environment=" do
|
21
|
+
let(:environment) { environment = stub(:Environment, :name => :the_environment) }
|
22
|
+
|
35
23
|
it "should set environment" do
|
36
|
-
|
37
|
-
|
24
|
+
subject.environment = environment
|
25
|
+
subject.environment.should == environment
|
38
26
|
end
|
39
27
|
|
40
28
|
it "should set RAILS_ENV environment variable" do
|
41
|
-
|
42
|
-
|
43
|
-
|
29
|
+
subject.environment_variables.should == {}
|
30
|
+
subject.environment = environment
|
31
|
+
subject.environment_variables[:RAILS_ENV].should == environment.name.to_s
|
44
32
|
end
|
45
33
|
end
|
46
34
|
|
47
35
|
it "should set environment variables" do
|
48
|
-
|
49
|
-
|
50
|
-
|
36
|
+
subject.env :FOO => "bar"
|
37
|
+
subject.env :BAR => "baz"
|
38
|
+
subject.environment_variables.should include(:FOO => "bar", :BAR => "baz")
|
51
39
|
end
|
52
40
|
|
53
|
-
|
54
|
-
let(:command) { mock(:Command, :name => :foo).as_null_object }
|
55
|
-
|
56
|
-
describe "#append_command" do
|
57
|
-
it "should add a command to servers's commands collection" do
|
58
|
-
server.append_command(command)
|
59
|
-
server.commands.should include(command)
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
describe "#find_command" do
|
64
|
-
it "should find command by name" do
|
65
|
-
server.commands.should_receive(:find_by_name).with(:foo).and_return(:bar)
|
66
|
-
server.find_command(:foo).should == :bar
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
41
|
+
it_behaves_like "a construct with nodes", :commands, :command
|
70
42
|
end
|
71
43
|
|
72
44
|
|
@@ -5,36 +5,57 @@ require 'taketo/support/named_nodes_collection'
|
|
5
5
|
include Taketo
|
6
6
|
|
7
7
|
describe "DestinationResolver" do
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
stub(:name => :waldo, :servers => list(anything))
|
26
|
-
))
|
27
|
-
))
|
8
|
+
class TestNode
|
9
|
+
attr_reader :name, :node_type
|
10
|
+
def initialize(node_type, name, *nodes)
|
11
|
+
@node_type, @name, @nodes = node_type, name, nodes
|
12
|
+
end
|
13
|
+
|
14
|
+
def find(type, name)
|
15
|
+
@nodes.detect { |s| s.name == name } or raise KeyError, name.to_s
|
16
|
+
end
|
17
|
+
|
18
|
+
def nodes(type)
|
19
|
+
@nodes
|
20
|
+
end
|
21
|
+
|
22
|
+
def global_alias
|
23
|
+
:the_alias if name == :s1 && node_type == :server
|
24
|
+
end
|
28
25
|
end
|
29
26
|
|
27
|
+
[:project, :environment, :server].each do |node_type|
|
28
|
+
define_method node_type do |name, *nodes|
|
29
|
+
TestNode.new(node_type, name, *nodes)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
let(:server1) { server(:s1) }
|
34
|
+
let(:environment1) { environment(:bar, server1) }
|
35
|
+
let(:project1) { project(:foo, environment1) }
|
36
|
+
|
37
|
+
let(:server2) { server(:s2) }
|
38
|
+
let(:environment2) { environment(:qux, server2) }
|
39
|
+
let(:project2) { project(:baz, environment2) }
|
40
|
+
|
41
|
+
let(:server3) { server(:s3) }
|
42
|
+
let(:server4) { server(:s4) }
|
43
|
+
let(:environment3) { environment(:corge, server3, server4) }
|
44
|
+
let(:project3) { environment(:quux, environment3) }
|
45
|
+
|
46
|
+
let(:environment4) { environment(:garply, server(:s5), server(:s6)) }
|
47
|
+
let(:environment5) { environment(:waldo, server(:s7)) }
|
48
|
+
let(:project4) { project(:grault, environment4, environment5) }
|
49
|
+
|
50
|
+
let(:config) { TestNode.new(:config, nil, project1, project2, project3, project4) }
|
51
|
+
|
30
52
|
context "when project, environment and server specified" do
|
31
53
|
it "should return server if it exists" do
|
32
54
|
resolver(config, "foo:bar:s1").resolve.should == server1
|
33
55
|
end
|
34
56
|
|
35
57
|
it "should raise error if server does not exist" do
|
36
|
-
|
37
|
-
expect { resolver(config, "foo:bar:noserver").resolve }.to raise_error(NonExistentDestinationError, /no such/i)
|
58
|
+
expect { resolver(config, "foo:bar:noserver").resolve }.to raise_error(NonExistentDestinationError)
|
38
59
|
end
|
39
60
|
end
|
40
61
|
|
@@ -46,13 +67,13 @@ describe "DestinationResolver" do
|
|
46
67
|
end
|
47
68
|
|
48
69
|
it "should raise error if there are multiple servers" do
|
49
|
-
expect { resolver(config, "quux:corge").resolve }.to raise_error(AmbiguousDestinationError
|
70
|
+
expect { resolver(config, "quux:corge").resolve }.to raise_error(AmbiguousDestinationError)
|
50
71
|
end
|
51
72
|
end
|
52
73
|
|
53
74
|
context "when there is no matching project - environment pair" do
|
54
75
|
it "should raise error if no such project - environment pair exist" do
|
55
|
-
expect { resolver(config, "chunky:bacon").resolve }.to raise_error(NonExistentDestinationError
|
76
|
+
expect { resolver(config, "chunky:bacon").resolve }.to raise_error(NonExistentDestinationError)
|
56
77
|
end
|
57
78
|
end
|
58
79
|
end
|
@@ -68,21 +89,21 @@ describe "DestinationResolver" do
|
|
68
89
|
|
69
90
|
context "when there are multiple servers" do
|
70
91
|
it "should raise error" do
|
71
|
-
expect { resolver(config, "quux").resolve }.to raise_error(AmbiguousDestinationError
|
92
|
+
expect { resolver(config, "quux").resolve }.to raise_error(AmbiguousDestinationError)
|
72
93
|
end
|
73
94
|
end
|
74
95
|
end
|
75
96
|
|
76
97
|
context "when there are multiple environments" do
|
77
98
|
it "should raise error" do
|
78
|
-
expect { resolver(config, "grault").resolve }.to raise_error(AmbiguousDestinationError
|
99
|
+
expect { resolver(config, "grault").resolve }.to raise_error(AmbiguousDestinationError)
|
79
100
|
end
|
80
101
|
end
|
81
102
|
end
|
82
103
|
|
83
104
|
context "when there is no such project" do
|
84
105
|
it "should raise error" do
|
85
|
-
expect { resolver(config, "chunky").resolve }.to raise_error(NonExistentDestinationError
|
106
|
+
expect { resolver(config, "chunky").resolve }.to raise_error(NonExistentDestinationError)
|
86
107
|
end
|
87
108
|
end
|
88
109
|
end
|
@@ -93,31 +114,16 @@ describe "DestinationResolver" do
|
|
93
114
|
context "when there's one environment" do
|
94
115
|
context "when there's one server" do
|
95
116
|
it "should execute command without asking project/environment/server" do
|
96
|
-
config =
|
97
|
-
|
98
|
-
stub(:name => :bar, :servers => list(
|
99
|
-
server1
|
100
|
-
))
|
101
|
-
))
|
102
|
-
))
|
103
|
-
|
117
|
+
config = TestNode.new(:config, nil, project1)
|
118
|
+
config.stub(:default_destination => nil)
|
104
119
|
resolver(config, "").resolve.should == server1
|
105
120
|
end
|
106
121
|
end
|
107
122
|
|
108
123
|
context "when there are multiple servers" do
|
109
|
-
let(:server1) { stub(:Server, :name => :s1) }
|
110
|
-
let(:server2) { stub(:Server, :name => :s2) }
|
111
|
-
|
112
124
|
it "should ask for server" do
|
113
|
-
config =
|
114
|
-
|
115
|
-
stub(:name => :bar, :servers => list(
|
116
|
-
server1, server2
|
117
|
-
))
|
118
|
-
))
|
119
|
-
))
|
120
|
-
|
125
|
+
config = TestNode.new(:config, nil, project3)
|
126
|
+
config.stub(:default_destination => nil)
|
121
127
|
expect { resolver(config, "").resolve }.to raise_error AmbiguousDestinationError, /server/i
|
122
128
|
end
|
123
129
|
end
|
@@ -125,13 +131,8 @@ describe "DestinationResolver" do
|
|
125
131
|
|
126
132
|
context "when there are multiple environments" do
|
127
133
|
it "should ask for environment" do
|
128
|
-
config =
|
129
|
-
|
130
|
-
stub(:name => :bar, :servers => [anything]),
|
131
|
-
stub(:name => :baz, :servers => [anything])
|
132
|
-
))
|
133
|
-
))
|
134
|
-
|
134
|
+
config = TestNode.new(:config, nil, project4)
|
135
|
+
config.stub(:default_destination => nil)
|
135
136
|
expect { resolver(config, "").resolve }.to raise_error AmbiguousDestinationError, /environment/i
|
136
137
|
end
|
137
138
|
end
|
@@ -139,10 +140,8 @@ describe "DestinationResolver" do
|
|
139
140
|
|
140
141
|
context "when there are multiple projects" do
|
141
142
|
it "should ask for project" do
|
142
|
-
config =
|
143
|
-
|
144
|
-
stub(:name => :bar, :environments => [anything])
|
145
|
-
))
|
143
|
+
config = TestNode.new(:config, nil, project3, project4)
|
144
|
+
config.stub(:default_destination => nil)
|
146
145
|
|
147
146
|
expect { resolver(config, "").resolve }.to raise_error AmbiguousDestinationError, /projects/i
|
148
147
|
end
|
@@ -157,24 +156,32 @@ describe "DestinationResolver" do
|
|
157
156
|
end
|
158
157
|
end
|
159
158
|
|
159
|
+
context "when there is global matching server alias" do
|
160
|
+
it "should resolve by alias" do
|
161
|
+
resolver(config, "the_alias").resolve.should == server1
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
160
165
|
describe "#get_node" do
|
161
166
|
it "should return server when path has 3 segments and is correct" do
|
162
167
|
resolver(config, "foo:bar:s1").get_node.should == server1
|
163
168
|
end
|
164
169
|
|
165
170
|
it "should return environment when path has 2 segments and is correct" do
|
166
|
-
resolver(config, "foo:bar").get_node.
|
171
|
+
resolver(config, "foo:bar").get_node.should == environment1
|
167
172
|
end
|
168
173
|
|
169
174
|
it "should return project when path has 1 segment and is correct" do
|
170
|
-
resolver(config, "foo").get_node.
|
175
|
+
resolver(config, "foo").get_node.should == project1
|
171
176
|
end
|
172
177
|
|
173
|
-
it "should return the config if path has is empty" do
|
178
|
+
it "should return the config if path has is empty and there's no default destination" do
|
179
|
+
config.stub(:default_destination => nil)
|
174
180
|
resolver(config, "").get_node.should == config
|
175
181
|
end
|
176
182
|
|
177
183
|
it "should raise NonExistentDestinationError when path is not correct" do
|
184
|
+
config.should_receive(:find).with(:project, :i).and_raise(KeyError)
|
178
185
|
expect { resolver(config, "i").get_node }.to raise_error(NonExistentDestinationError)
|
179
186
|
end
|
180
187
|
end
|
data/spec/lib/taketo/dsl_spec.rb
CHANGED
@@ -107,6 +107,10 @@ describe "DSL" do
|
|
107
107
|
it_behaves_like "an attribute", :env, :server, :env, { :FOO => "bar" }
|
108
108
|
end
|
109
109
|
|
110
|
+
describe "#global_alias" do
|
111
|
+
it_behaves_like "an attribute", :global_alias, :server, :global_alias=, "foobared"
|
112
|
+
end
|
113
|
+
|
110
114
|
describe "#command" do
|
111
115
|
it_behaves_like "a scope", :command, :server
|
112
116
|
|
@@ -0,0 +1,15 @@
|
|
1
|
+
shared_examples "a construct with nodes" do |name_plural, name_singular|
|
2
|
+
specify "#append_#{name_singular} should add a #{name_singular} to " + # specify "#append_server should add a server to " +
|
3
|
+
"#{subject.class.name}'s #{name_plural} collection" do # "environment's servers collection" do
|
4
|
+
node = mock(:name => :foo).as_null_object # server = mock(:name => :foo).as_null_object
|
5
|
+
subject.send("append_#{name_singular}", node) # environment.append_server(server)
|
6
|
+
subject.send(name_plural).should include(node) # environment.servers.should include(server)
|
7
|
+
end # end
|
8
|
+
|
9
|
+
specify "#find_#{name_singular} should find #{name_singular} by name" do # specify "#find_server should find server by name" do
|
10
|
+
subject.send(name_plural).should_receive(:find_by_name). # environment.servers.should_receive(:find_by_name).
|
11
|
+
with(:foo).and_return(:bar) # with(:foo).and_return(:bar)
|
12
|
+
subject.send("find_#{name_singular}", :foo).should == :bar # environment.find_server(:foo).should == :bar
|
13
|
+
end # end
|
14
|
+
end
|
15
|
+
|
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.
|
4
|
+
version: 0.0.5
|
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-
|
12
|
+
date: 2012-07-24 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
@@ -118,12 +118,15 @@ files:
|
|
118
118
|
- spec/lib/taketo/support/eval_delegator_spec.rb
|
119
119
|
- spec/lib/taketo/support/named_nodes_collection_spec.rb
|
120
120
|
- spec/spec_helper.rb
|
121
|
+
- spec/support/helpers/construct_spec_helper.rb
|
121
122
|
- spec/support/helpers/dsl_spec_helper.rb
|
122
123
|
- spec/support/matchers/be_appropriate_construct_matcher.rb
|
123
124
|
- spec/support/matchers/enclose_scope_matcher.rb
|
125
|
+
- spec/support/matchers/have_accessor_matcher.rb
|
124
126
|
- features/commands.feature
|
125
127
|
- features/config_validation.feature
|
126
128
|
- features/connect_to_server.feature
|
129
|
+
- features/error_handling.feature
|
127
130
|
- features/help.feature
|
128
131
|
- features/step_definitions/main_steps.rb
|
129
132
|
- features/support/env.rb
|