taketo 0.0.4 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +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
|