taketo 0.0.7 → 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +34 -7
- data/VERSION +1 -1
- data/features/commands.feature +5 -5
- data/features/config.feature +11 -11
- data/features/config_validation.feature +6 -6
- data/features/connect_to_server.feature +8 -8
- data/features/default_server_config.feature +41 -0
- data/features/error_handling.feature +3 -3
- data/features/help.feature +4 -4
- data/features/step_definitions/main_steps.rb +9 -3
- data/lib/taketo/constructs/base_construct.rb +13 -1
- data/lib/taketo/constructs/environment.rb +0 -5
- data/lib/taketo/constructs/server.rb +2 -1
- data/lib/taketo/dsl.rb +36 -24
- data/spec/integration/dsl_integration_spec.rb +2 -2
- data/spec/lib/taketo/config_validator_spec.rb +7 -7
- data/spec/lib/taketo/constructs/base_construct_spec.rb +30 -0
- data/spec/lib/taketo/constructs/environment_spec.rb +1 -7
- data/spec/lib/taketo/constructs/project_spec.rb +1 -1
- data/spec/lib/taketo/constructs/server_spec.rb +3 -3
- data/spec/lib/taketo/dsl_spec.rb +66 -15
- data/spec/support/helpers/dsl_spec_helper.rb +5 -5
- metadata +3 -2
data/README.md
CHANGED
@@ -66,7 +66,7 @@ Destination resolving works intelligently. Given the following config:
|
|
66
66
|
end
|
67
67
|
end
|
68
68
|
end
|
69
|
-
|
69
|
+
|
70
70
|
project :my_project2 do
|
71
71
|
environment :staging do
|
72
72
|
server :s2 do
|
@@ -76,8 +76,8 @@ Destination resolving works intelligently. Given the following config:
|
|
76
76
|
end
|
77
77
|
```
|
78
78
|
|
79
|
-
```taketo my_project:staging``` will ssh to s1 with host = 1.2.3.4
|
80
|
-
```taketo my_project2``` will ssh to s2 with host = 2.3.4.5
|
79
|
+
```taketo my_project:staging``` will ssh to s1 with host = 1.2.3.4
|
80
|
+
```taketo my_project2``` will ssh to s2 with host = 2.3.4.5
|
81
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
|
@@ -105,29 +105,45 @@ You can use shared server configs to reduce duplication:
|
|
105
105
|
|
106
106
|
server :s2 do
|
107
107
|
host :s2 do
|
108
|
-
include_shared_server_config(:my_staging
|
108
|
+
include_shared_server_config(:my_staging, :some_other_shared_config => "qux")
|
109
109
|
end
|
110
110
|
end
|
111
111
|
end
|
112
112
|
```
|
113
113
|
|
114
|
-
This will give you ```console``` commands available both on s1 and s2
|
114
|
+
This will give you ```console``` commands available both on s1 and s2
|
115
115
|
|
116
116
|
The Changelog:
|
117
117
|
--------------
|
118
118
|
|
119
|
+
### v0.0.8 (17.11.2012) ###
|
120
|
+
* Add per-config, per-project and per-environment default server config support, i.e.
|
121
|
+
```ruby
|
122
|
+
default_server_config { env :TERM => 'xterm-256color' } # Global default server config
|
123
|
+
|
124
|
+
project :p1 do
|
125
|
+
default_server_config { env :FOO => 'bar' } # global default server config is merged
|
126
|
+
...
|
127
|
+
end
|
128
|
+
```
|
129
|
+
|
130
|
+
* Shared server configs can be included without redundant empty-array arguments, i.e.
|
131
|
+
```ruby
|
132
|
+
include_shared_server_configs(:foo, :bar, :baz => [:arg1, :arg2], :qux => :arg3)
|
133
|
+
```
|
134
|
+
|
119
135
|
### v0.0.7 (08.10.2012) ###
|
120
136
|
* Add ability to include several shared server config at once
|
121
137
|
Use hash as include_shared_server_config parameter to include
|
122
138
|
multiple shared server configs with arguments, like:
|
123
139
|
```ruby
|
124
|
-
|
140
|
+
include_shared_server_configs(:foo => :some_arg, :bar => [:arg1, :arg2])
|
125
141
|
```
|
126
142
|
or just enumerate them if no arguments needed:
|
127
143
|
```ruby
|
128
144
|
include_shared_server_configs(:baz, :quux)
|
129
145
|
```
|
130
|
-
|
146
|
+
|
131
147
|
NOTE: This change will break your config if you've used parametrized
|
132
148
|
shared server configs before; rewrite them using hash-form
|
133
149
|
|
@@ -155,3 +171,14 @@ The Changelog:
|
|
155
171
|
* Initial release
|
156
172
|
* Support for simplest configs
|
157
173
|
|
174
|
+
|
175
|
+
TO-DO:
|
176
|
+
------
|
177
|
+
|
178
|
+
* Shared server configs without arguments
|
179
|
+
* Global server defaults
|
180
|
+
* Override default commands per server
|
181
|
+
* Define servers outside projects and environments
|
182
|
+
* Export SSH config (i.e. for scp)
|
183
|
+
* Destination completion
|
184
|
+
* Command completion
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.8
|
data/features/commands.feature
CHANGED
@@ -1,11 +1,11 @@
|
|
1
|
-
Feature:
|
1
|
+
Feature:
|
2
2
|
In order to be able to quickly run commands on my servers
|
3
3
|
As a developer
|
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
|
-
When I have the following config
|
8
|
+
When I have the following config
|
9
9
|
"""
|
10
10
|
project :slots do
|
11
11
|
environment :staging do
|
@@ -21,21 +21,21 @@ Feature:
|
|
21
21
|
"""
|
22
22
|
|
23
23
|
Scenario: Run explicit command
|
24
|
-
When I
|
24
|
+
When I run taketo --dry-run --command "TERM=xterm-256color bash"
|
25
25
|
Then the output should contain
|
26
26
|
"""
|
27
27
|
ssh -t 1.2.3.4 "cd /var/apps/slots; RAILS_ENV=staging TERM=xterm-256color bash"
|
28
28
|
"""
|
29
29
|
|
30
30
|
Scenario: Run command defined in config
|
31
|
-
When I
|
31
|
+
When I run taketo --dry-run --command console slots:staging
|
32
32
|
Then the output should contain
|
33
33
|
"""
|
34
34
|
ssh -t 1.2.3.4 "cd /var/apps/slots; RAILS_ENV=staging rails c"
|
35
35
|
"""
|
36
36
|
|
37
37
|
Scenario: Override default location specified for server
|
38
|
-
When I
|
38
|
+
When I run taketo --dry-run --directory /var/www slots:staging
|
39
39
|
Then the output should contain
|
40
40
|
"""
|
41
41
|
ssh -t 1.2.3.4 "cd /var/www; RAILS_ENV=staging bash"
|
data/features/config.feature
CHANGED
@@ -4,7 +4,7 @@ Feature: taketo config
|
|
4
4
|
I want to be able configure taketo
|
5
5
|
|
6
6
|
Scenario: Shared server configs
|
7
|
-
When I have the following config
|
7
|
+
When I have the following config
|
8
8
|
"""
|
9
9
|
shared_server_config :sc1 do
|
10
10
|
port 9999 #can contain any server config options
|
@@ -20,14 +20,14 @@ Feature: taketo config
|
|
20
20
|
end
|
21
21
|
end
|
22
22
|
"""
|
23
|
-
And I
|
23
|
+
And I run taketo slots:staging:s1 --dry-run
|
24
24
|
Then the output should contain
|
25
25
|
"""
|
26
26
|
ssh -t -p 9999 1.2.3.4 "cd /var/qux; RAILS_ENV=staging bash"
|
27
27
|
"""
|
28
28
|
|
29
29
|
Scenario: Shared server configs with arguments
|
30
|
-
When I have the following config
|
30
|
+
When I have the following config
|
31
31
|
"""
|
32
32
|
shared_server_config :sc_args1 do |port_num|
|
33
33
|
port port_num
|
@@ -46,14 +46,14 @@ Feature: taketo config
|
|
46
46
|
end
|
47
47
|
end
|
48
48
|
"""
|
49
|
-
And I
|
49
|
+
And I run taketo slots:staging:s1 --dry-run
|
50
50
|
Then the output should contain
|
51
51
|
"""
|
52
52
|
ssh -t -p 9999 1.2.3.4 "cd /var/qux; RAILS_ENV=staging bash"
|
53
53
|
"""
|
54
54
|
|
55
55
|
Scenario: Set environment variables
|
56
|
-
When I have the following config
|
56
|
+
When I have the following config
|
57
57
|
"""
|
58
58
|
project :slots do
|
59
59
|
environment :staging do
|
@@ -65,7 +65,7 @@ Feature: taketo config
|
|
65
65
|
end
|
66
66
|
end
|
67
67
|
"""
|
68
|
-
And I
|
68
|
+
And I run taketo --dry-run
|
69
69
|
Then the output should contain
|
70
70
|
"""
|
71
71
|
RAILS_ENV=staging
|
@@ -74,9 +74,9 @@ Feature: taketo config
|
|
74
74
|
"""
|
75
75
|
FOO=the\ value
|
76
76
|
"""
|
77
|
-
|
77
|
+
|
78
78
|
Scenario: Reopen config scopes
|
79
|
-
When I have the following config
|
79
|
+
When I have the following config
|
80
80
|
"""
|
81
81
|
project :slots do
|
82
82
|
environment :staging do
|
@@ -94,11 +94,11 @@ Feature: taketo config
|
|
94
94
|
end
|
95
95
|
end
|
96
96
|
"""
|
97
|
-
And I
|
97
|
+
And I run taketo slots:staging --dry-run
|
98
98
|
Then the output should match /ssh -t 1\.2\.3\.4 "(RAILS_ENV=staging FOO=bar|FOO=bar RAILS_ENV=staging) bash"/
|
99
99
|
|
100
100
|
Scenario: Unique server alias
|
101
|
-
When I have the following config
|
101
|
+
When I have the following config
|
102
102
|
"""
|
103
103
|
project :slots do
|
104
104
|
environment :staging do
|
@@ -112,7 +112,7 @@ Feature: taketo config
|
|
112
112
|
end
|
113
113
|
end
|
114
114
|
"""
|
115
|
-
And I
|
115
|
+
And I run taketo ss2 --dry-run
|
116
116
|
Then the output should contain
|
117
117
|
"""
|
118
118
|
ssh -t 2.3.4.5 "RAILS_ENV=staging bash"
|
@@ -4,11 +4,11 @@ Feature:
|
|
4
4
|
I want to be guided if there are any errors in my configuration
|
5
5
|
|
6
6
|
Scenario Outline: Config validation
|
7
|
-
When I have the following config
|
7
|
+
When I have the following config
|
8
8
|
"""
|
9
9
|
<config>
|
10
10
|
"""
|
11
|
-
And I run
|
11
|
+
And I run taketo
|
12
12
|
Then the stderr should contain "<error>"
|
13
13
|
|
14
14
|
Examples:
|
@@ -19,18 +19,18 @@ Feature:
|
|
19
19
|
| project(:foo) { environment(:bar) { server {} }} | Server foo:bar:default: host is not defined |
|
20
20
|
|
21
21
|
Scenario: Global server alias clash
|
22
|
-
When I have the following config
|
22
|
+
When I have the following config
|
23
23
|
"""
|
24
24
|
project(:foo) { environment(:bar) {
|
25
25
|
server(:s1) { host '1.2.3.4'; global_alias :a1 }
|
26
26
|
server(:s2) { host '2.3.4.5'; global_alias :a1 }
|
27
27
|
}}
|
28
28
|
"""
|
29
|
-
And I run
|
29
|
+
And I run taketo
|
30
30
|
Then the stderr should contain "Server foo:bar:s2: global alias 'a1' has already been taken by server foo:bar:s1"
|
31
31
|
|
32
32
|
Scenario: Bad command
|
33
|
-
When I have the following config
|
33
|
+
When I have the following config
|
34
34
|
"""
|
35
35
|
project(:foo) { environment(:bar) {
|
36
36
|
server(:s1) { host '1.2.3.4'
|
@@ -38,6 +38,6 @@ Feature:
|
|
38
38
|
}
|
39
39
|
}}
|
40
40
|
"""
|
41
|
-
And I run
|
41
|
+
And I run taketo
|
42
42
|
Then the stderr should contain "Don't know what to execute on command foo"
|
43
43
|
|
@@ -5,7 +5,7 @@ Feature:
|
|
5
5
|
configurable with simple DSL
|
6
6
|
|
7
7
|
Scenario: SSH to server
|
8
|
-
When I have the following config
|
8
|
+
When I have the following config
|
9
9
|
"""
|
10
10
|
project :slots do
|
11
11
|
environment :staging do
|
@@ -22,14 +22,14 @@ Feature:
|
|
22
22
|
end
|
23
23
|
|
24
24
|
"""
|
25
|
-
And I
|
25
|
+
And I run taketo --dry-run slots:staging:s1
|
26
26
|
Then the output should contain
|
27
27
|
"""
|
28
28
|
ssh -t deployer@1.2.3.4 "cd /var/apps/slots; RAILS_ENV=staging bash"
|
29
29
|
"""
|
30
30
|
|
31
31
|
Scenario: SSH to the only server
|
32
|
-
When I have the following config
|
32
|
+
When I have the following config
|
33
33
|
"""
|
34
34
|
project :slots do
|
35
35
|
environment :staging do
|
@@ -40,14 +40,14 @@ Feature:
|
|
40
40
|
end
|
41
41
|
end
|
42
42
|
"""
|
43
|
-
And I
|
43
|
+
And I run taketo --dry-run
|
44
44
|
Then the output should contain
|
45
45
|
"""
|
46
46
|
ssh -t 1.2.3.4 "cd /var/apps/slots; RAILS_ENV=staging bash"
|
47
47
|
"""
|
48
48
|
|
49
49
|
Scenario: Default destination
|
50
|
-
When I have the following config
|
50
|
+
When I have the following config
|
51
51
|
"""
|
52
52
|
default_destination "slots:staging:s2"
|
53
53
|
project :slots do
|
@@ -61,14 +61,14 @@ Feature:
|
|
61
61
|
end
|
62
62
|
end
|
63
63
|
"""
|
64
|
-
And I
|
64
|
+
And I run taketo --dry-run
|
65
65
|
Then the output should contain
|
66
66
|
"""
|
67
67
|
ssh -t 2.3.4.5 "RAILS_ENV=staging bash"
|
68
68
|
"""
|
69
69
|
|
70
70
|
Scenario: SSH key file
|
71
|
-
When I have the following config
|
71
|
+
When I have the following config
|
72
72
|
"""
|
73
73
|
project :slots do
|
74
74
|
environment :staging do
|
@@ -79,7 +79,7 @@ Feature:
|
|
79
79
|
end
|
80
80
|
end
|
81
81
|
"""
|
82
|
-
And I
|
82
|
+
And I run taketo --dry-run
|
83
83
|
Then the output should contain
|
84
84
|
"""
|
85
85
|
ssh -t -i /home/gor/.ssh/foo\ bar 2.3.4.5 "RAILS_ENV=staging bash"
|
@@ -0,0 +1,41 @@
|
|
1
|
+
Feature: taketo config's default server config
|
2
|
+
In order to reduce duplication
|
3
|
+
As a taketo user
|
4
|
+
I want to be able set default configs for servers in particular scopes
|
5
|
+
|
6
|
+
Background:
|
7
|
+
When I have the following config
|
8
|
+
"""
|
9
|
+
default_server_config do
|
10
|
+
env :FOO => 'bar'
|
11
|
+
end
|
12
|
+
|
13
|
+
project :slots do
|
14
|
+
default_server_config do
|
15
|
+
location '/mnt/apps'
|
16
|
+
end
|
17
|
+
|
18
|
+
environment :staging do
|
19
|
+
server :s1 do
|
20
|
+
host "1.2.3.4"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
project :shoes do
|
26
|
+
environment :production do
|
27
|
+
server do
|
28
|
+
host "2.3.4.5"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
"""
|
33
|
+
|
34
|
+
Scenario: Global default server config
|
35
|
+
When I run taketo shoes --dry-run
|
36
|
+
Then the output should match /ssh -t 2\.3\.4\.5 "(RAILS_ENV=production FOO=bar|FOO=bar RAILS_ENV=production) bash"/
|
37
|
+
|
38
|
+
Scenario: Project default server config
|
39
|
+
When I run taketo slots --dry-run
|
40
|
+
Then the output should match /ssh -t 1\.2\.3\.4 "cd .mnt.apps; (RAILS_ENV=staging FOO=bar|FOO=bar RAILS_ENV=staging) bash"/
|
41
|
+
|
@@ -4,7 +4,7 @@ Feature:
|
|
4
4
|
I want to see meaningful errors when I accidentally specify bad location
|
5
5
|
|
6
6
|
Background:
|
7
|
-
When I have the following config
|
7
|
+
When I have the following config
|
8
8
|
"""
|
9
9
|
default_destination "slots:staging:s2"
|
10
10
|
project :slots do
|
@@ -20,10 +20,10 @@ Feature:
|
|
20
20
|
"""
|
21
21
|
|
22
22
|
Scenario: Non-existent location
|
23
|
-
And I run
|
23
|
+
And I run taketo slots:staging:qqq --dry-run
|
24
24
|
Then the stderr should contain "server qqq not found for environment staging"
|
25
25
|
|
26
26
|
Scenario: Ambiguous location
|
27
|
-
And I run
|
27
|
+
And I run taketo slots:staging --dry-run
|
28
28
|
Then the stderr should contain "There are multiple servers for environment staging: s1, s2"
|
29
29
|
|
data/features/help.feature
CHANGED
@@ -4,7 +4,7 @@ Feature:
|
|
4
4
|
I want to view what's set up in config quickly
|
5
5
|
|
6
6
|
Background:
|
7
|
-
When I have the following config
|
7
|
+
When I have the following config
|
8
8
|
"""
|
9
9
|
project :foo do
|
10
10
|
environment :bar do
|
@@ -34,7 +34,7 @@ Feature:
|
|
34
34
|
"""
|
35
35
|
|
36
36
|
Scenario: View full config
|
37
|
-
When I run
|
37
|
+
When I run taketo --view
|
38
38
|
Then the output should contain exactly:
|
39
39
|
"""
|
40
40
|
|
@@ -55,11 +55,11 @@ Feature:
|
|
55
55
|
Environment: RAILS_ENV=qux
|
56
56
|
console
|
57
57
|
killall - Kill ALL humans
|
58
|
-
|
58
|
+
|
59
59
|
"""
|
60
60
|
|
61
61
|
Scenario: View particular server
|
62
|
-
When I run
|
62
|
+
When I run taketo --view foo:bar:default
|
63
63
|
Then the output should contain exactly:
|
64
64
|
"""
|
65
65
|
Server: default
|
@@ -1,10 +1,16 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
DEFAULT_TEST_CONFIG_PATH = "/tmp/taketo_test_cfg.rb".freeze
|
2
|
+
|
3
|
+
When /^I have the following config$/ do |config|
|
4
|
+
@config_path = DEFAULT_TEST_CONFIG_PATH
|
5
|
+
File.open(@config_path, "w") do |f|
|
4
6
|
f.write(config)
|
5
7
|
end
|
6
8
|
end
|
7
9
|
|
10
|
+
When /^I run taketo\s?(.*)$/ do |arguments|
|
11
|
+
step "I run `taketo --config=/tmp/taketo_test_cfg.rb #{arguments}`"
|
12
|
+
end
|
13
|
+
|
8
14
|
Then /^the output should contain$/ do |expected|
|
9
15
|
assert_partial_output(expected, all_output)
|
10
16
|
end
|
@@ -6,11 +6,12 @@ module Taketo
|
|
6
6
|
class BaseConstruct
|
7
7
|
|
8
8
|
include AssociatedNodes
|
9
|
-
attr_reader :name
|
9
|
+
attr_reader :name, :default_server_config
|
10
10
|
|
11
11
|
def initialize(name)
|
12
12
|
super
|
13
13
|
@name = name
|
14
|
+
@default_server_config = proc {}
|
14
15
|
end
|
15
16
|
|
16
17
|
def node_type
|
@@ -18,6 +19,17 @@ module Taketo
|
|
18
19
|
demodulized.gsub(/([a-z])([A-Z])/, '\\1_\\2').downcase.to_sym
|
19
20
|
end
|
20
21
|
|
22
|
+
##
|
23
|
+
# Override in subclasses if needed
|
24
|
+
def parent=(parent)
|
25
|
+
@default_server_config = parent.default_server_config
|
26
|
+
end
|
27
|
+
|
28
|
+
def default_server_config=(config)
|
29
|
+
default = @default_server_config
|
30
|
+
@default_server_config = proc { instance_eval(&default); instance_eval(&config) }
|
31
|
+
end
|
32
|
+
|
21
33
|
def qualified_name
|
22
34
|
"#{node_type} #{self.name}"
|
23
35
|
end
|
data/lib/taketo/dsl.rb
CHANGED
@@ -2,30 +2,27 @@ require 'taketo/constructs_factory'
|
|
2
2
|
|
3
3
|
module Taketo
|
4
4
|
class DSL
|
5
|
-
class ScopeError
|
5
|
+
class ScopeError < StandardError; end
|
6
6
|
class ConfigError < StandardError; end
|
7
7
|
|
8
8
|
class << self
|
9
|
-
def define_scope(scope, parent_scope, options = {})
|
10
|
-
define_method scope do |*args, &
|
11
|
-
|
12
|
-
raise ScopeError,
|
13
|
-
"#{scope} can't be defined in #{current_scope} scope"
|
14
|
-
end
|
9
|
+
def define_scope(scope, parent_scope, options = {}, &block)
|
10
|
+
define_method scope do |*args, &blk|
|
11
|
+
ensure_nesting_allowed!(scope, parent_scope)
|
15
12
|
name = args.shift || options[:default_name] or raise(ArgumentError, "Name not specified")
|
13
|
+
|
16
14
|
scope_object = current_scope_object.find(scope, name) { @factory.create(scope, name) }
|
15
|
+
|
17
16
|
in_scope(scope, scope_object) do
|
18
|
-
block
|
17
|
+
instance_exec(current_scope_object, &block) if block
|
18
|
+
blk.call
|
19
19
|
end
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
-
def define_method_in_scope(name,
|
23
|
+
def define_method_in_scope(name, *parent_scopes, &block)
|
24
24
|
define_method name do |*args, &blk|
|
25
|
-
|
26
|
-
raise ScopeError,
|
27
|
-
"#{name} can't be defined in #{current_scope} scope"
|
28
|
-
end
|
25
|
+
ensure_nesting_allowed!(name, parent_scopes)
|
29
26
|
args.push blk if blk
|
30
27
|
instance_exec(*args, &block)
|
31
28
|
end
|
@@ -56,7 +53,11 @@ module Taketo
|
|
56
53
|
|
57
54
|
define_scope :project, :config
|
58
55
|
define_scope :environment, :project
|
59
|
-
|
56
|
+
|
57
|
+
define_scope :server, :environment, :default_name => :default do |s|
|
58
|
+
instance_eval(&s.default_server_config)
|
59
|
+
end
|
60
|
+
|
60
61
|
define_scope :command, :server
|
61
62
|
|
62
63
|
define_method_in_scope(:default_destination, :config) { |destination| current_scope_object.default_destination = destination }
|
@@ -70,20 +71,17 @@ module Taketo
|
|
70
71
|
define_method_in_scope(:execute, :command) { |command| current_scope_object.command = command }
|
71
72
|
define_method_in_scope(:desc, :command) { |description| current_scope_object.description = description }
|
72
73
|
|
74
|
+
define_method_in_scope(:default_server_config, :config, :project, :environment) do |blk|
|
75
|
+
current_scope_object.default_server_config = blk
|
76
|
+
end
|
77
|
+
|
73
78
|
define_method_in_scope(:shared_server_config, :config) do |name, blk|
|
74
79
|
@shared_server_configs.store(name.to_sym, blk)
|
75
80
|
end
|
76
81
|
|
77
82
|
define_method_in_scope(:include_shared_server_config, :server) do |*args|
|
78
|
-
|
79
|
-
|
80
|
-
configs_and_arguments.each do |config_name, arguments|
|
81
|
-
instance_exec(*arguments, &shared_server_configs[config_name])
|
82
|
-
end
|
83
|
-
else
|
84
|
-
args.each do |config_name|
|
85
|
-
instance_exec(&shared_server_configs[config_name])
|
86
|
-
end
|
83
|
+
extract_config_names_and_arguments(args).each do |config_name, arguments|
|
84
|
+
instance_exec(*arguments, &shared_server_configs[config_name])
|
87
85
|
end
|
88
86
|
end
|
89
87
|
alias :include_shared_server_configs :include_shared_server_config
|
@@ -106,12 +104,26 @@ module Taketo
|
|
106
104
|
def in_scope(scope, new_scope_object)
|
107
105
|
parent_scope_object, @current_scope_object = @current_scope_object, new_scope_object
|
108
106
|
@scope.push(scope)
|
109
|
-
yield
|
110
107
|
parent_scope_object.send("append_#{scope}", current_scope_object)
|
108
|
+
current_scope_object.parent = parent_scope_object
|
109
|
+
yield
|
111
110
|
@scope.pop
|
112
111
|
@current_scope_object = parent_scope_object
|
113
112
|
end
|
114
113
|
|
114
|
+
def ensure_nesting_allowed!(scope, parent_scopes)
|
115
|
+
if Array(parent_scopes).none? { |s| current_scope?(s) }
|
116
|
+
raise ScopeError, "#{scope} can't be defined in #{current_scope} scope"
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def extract_config_names_and_arguments(args)
|
121
|
+
hashes, names = args.partition { |arg| arg.is_a? Hash }
|
122
|
+
configs_from_hashes = hashes.inject({}, &:merge)
|
123
|
+
configs_from_names = Hash[names.map { |config_name| [config_name.to_sym, []] }]
|
124
|
+
configs_from_hashes.merge(configs_from_names)
|
125
|
+
end
|
126
|
+
|
115
127
|
end
|
116
128
|
end
|
117
129
|
|
@@ -2,7 +2,7 @@ require 'spec_helper'
|
|
2
2
|
require 'taketo/dsl'
|
3
3
|
|
4
4
|
describe "Taketo DSL" do
|
5
|
-
it "
|
5
|
+
it "parses config and instantiate objects" do
|
6
6
|
factory = Taketo::ConstructsFactory.new
|
7
7
|
config = Taketo::DSL.new(factory).configure do
|
8
8
|
shared_server_config(:commands) do
|
@@ -44,7 +44,7 @@ describe "Taketo DSL" do
|
|
44
44
|
|
45
45
|
project.environments.length.should == 2
|
46
46
|
staging = project.environments[:staging]
|
47
|
-
|
47
|
+
|
48
48
|
staging.servers.length.should == 1
|
49
49
|
staging_server = staging.servers[:default]
|
50
50
|
staging_server.name.should == :default
|
@@ -7,7 +7,7 @@ describe "ConfigValidator" do
|
|
7
7
|
let(:traverser) { stub(:ConfigTraverser) }
|
8
8
|
|
9
9
|
describe "#validate!" do
|
10
|
-
it "
|
10
|
+
it "visits all nodes with an instance of ConfigValidator::ConfigValidatorVisitor" do
|
11
11
|
validator = ConfigValidator.new(traverser)
|
12
12
|
traverser.should_receive(:visit_depth_first).with(an_instance_of(ConfigValidator::ConfigValidatorVisitor))
|
13
13
|
validator.validate!
|
@@ -18,7 +18,7 @@ end
|
|
18
18
|
describe "ConfigValidator::ConfigValidatorVisitor" do
|
19
19
|
subject(:visitor) { ConfigValidator::ConfigValidatorVisitor.new }
|
20
20
|
|
21
|
-
it "
|
21
|
+
it "requires config to have projects" do
|
22
22
|
config = stub(:Config, :has_projects? => false)
|
23
23
|
error_message = /no projects/
|
24
24
|
expect { visitor.visit_config(config) }.to raise_error ConfigError, error_message
|
@@ -27,7 +27,7 @@ describe "ConfigValidator::ConfigValidatorVisitor" do
|
|
27
27
|
expect { visitor.visit_config(config) }.not_to raise_error ConfigError, error_message
|
28
28
|
end
|
29
29
|
|
30
|
-
it "
|
30
|
+
it "requires projects to have environments" do
|
31
31
|
project = stub(:Project, :has_environments? => false, :path => "my_project")
|
32
32
|
error_message = /my_project: no environments/
|
33
33
|
expect { visitor.visit_project(project) }.to raise_error ConfigError, error_message
|
@@ -36,7 +36,7 @@ describe "ConfigValidator::ConfigValidatorVisitor" do
|
|
36
36
|
expect { visitor.visit_project(project) }.not_to raise_error ConfigError, error_message
|
37
37
|
end
|
38
38
|
|
39
|
-
it "
|
39
|
+
it "requires environments to have servers" do
|
40
40
|
environment = stub(:Environment, :has_servers? => false, :path => "my_project:my_environment")
|
41
41
|
error_message = /my_project:my_environment: no servers/
|
42
42
|
expect { visitor.visit_environment(environment) }.to raise_error ConfigError, error_message
|
@@ -45,7 +45,7 @@ describe "ConfigValidator::ConfigValidatorVisitor" do
|
|
45
45
|
expect { visitor.visit_environment(environment) }.not_to raise_error ConfigError, error_message
|
46
46
|
end
|
47
47
|
|
48
|
-
it "
|
48
|
+
it "requires servers to have host" do
|
49
49
|
server = stub(:Server, :host => '', :path => "my_project:my_environment:my_server", :global_alias => nil)
|
50
50
|
error_message = /my_project:my_environment:my_server: host is not defined/
|
51
51
|
expect { visitor.visit_server(server) }.to raise_error ConfigError, error_message
|
@@ -54,7 +54,7 @@ describe "ConfigValidator::ConfigValidatorVisitor" do
|
|
54
54
|
expect { visitor.visit_server(server) }.not_to raise_error ConfigError, error_message
|
55
55
|
end
|
56
56
|
|
57
|
-
it "
|
57
|
+
it "requires servers to have unique global server aliases" do
|
58
58
|
server1 = stub(:Server, :host => 'the-host1', :path => "my_project:my_environment:my_server", :global_alias => 'foo')
|
59
59
|
server2 = stub(:Server, :host => 'the-host2', :path => "my_project:my_environment2:my_server3", :global_alias => 'foo')
|
60
60
|
error_message = /my_project:my_environment2:my_server3: global alias 'foo' has already been taken.*my_project:my_environment:my_server/
|
@@ -63,7 +63,7 @@ describe "ConfigValidator::ConfigValidatorVisitor" do
|
|
63
63
|
expect { @visitor.visit_server(server2) }.to raise_error ConfigError, error_message
|
64
64
|
end
|
65
65
|
|
66
|
-
it "
|
66
|
+
it "requires commands to have command specified" do
|
67
67
|
command = stub(:Command, :command => '', :name => 'qux')
|
68
68
|
error_message = /execute/
|
69
69
|
expect { visitor.visit_command(command) }.to raise_error ConfigError, error_message
|
@@ -16,6 +16,36 @@ describe "BaseConstruct" do
|
|
16
16
|
expect(construct.qualified_name).to eq('test_base_construct my_node')
|
17
17
|
end
|
18
18
|
|
19
|
+
specify "#parent= sets default server config to parent's default server config" do
|
20
|
+
parent_default_server_config = proc {}
|
21
|
+
construct.parent = stub(:default_server_config => parent_default_server_config)
|
22
|
+
expect(construct.default_server_config).to eq(parent_default_server_config)
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "#default_server_config=" do
|
26
|
+
let(:default_server_config) { proc { call_from_self } }
|
27
|
+
let(:context) { stub }
|
28
|
+
|
29
|
+
it "sets default server config" do
|
30
|
+
construct.default_server_config = default_server_config
|
31
|
+
context.should_receive(:call_from_self)
|
32
|
+
context.instance_eval(&construct.default_server_config)
|
33
|
+
end
|
34
|
+
|
35
|
+
it "merges given config to parent's default server config" do
|
36
|
+
construct.parent = stub(:default_server_config => proc { call_from_parent })
|
37
|
+
construct.default_server_config = default_server_config
|
38
|
+
|
39
|
+
context.should_receive(:call_from_parent).ordered
|
40
|
+
context.should_receive(:call_from_self).ordered
|
41
|
+
context.instance_eval(&construct.default_server_config)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
it "has an empty proc as an initial default server config" do
|
46
|
+
expect(construct.default_server_config.call).to eq(nil)
|
47
|
+
end
|
48
|
+
|
19
49
|
end
|
20
50
|
|
21
51
|
|
@@ -13,16 +13,10 @@ describe "Environment" do
|
|
13
13
|
|
14
14
|
it_behaves_like "a construct with nodes", :servers, :server
|
15
15
|
|
16
|
-
specify "#append_server sets environment attribute on a server to self" do
|
17
|
-
server = mock(:Server, :name => :foo)
|
18
|
-
server.should_receive(:environment=).with(environment)
|
19
|
-
environment.append_server(server)
|
20
|
-
end
|
21
|
-
|
22
16
|
specify "#project_name returns project name" do
|
23
17
|
environment.project = stub(:Project, :name => "TheProject")
|
24
18
|
expect(environment.project_name).to eq("TheProject")
|
25
|
-
end
|
19
|
+
end
|
26
20
|
end
|
27
21
|
|
28
22
|
|
@@ -10,7 +10,7 @@ describe "Project" do
|
|
10
10
|
it "has name" do
|
11
11
|
expect(project.name).to eq(:foo)
|
12
12
|
end
|
13
|
-
|
13
|
+
|
14
14
|
specify "#append_environment sets project attribute on an environment to self" do
|
15
15
|
environment = mock(:Environment, :name => :bar)
|
16
16
|
environment.should_receive(:project=).with(project)
|
@@ -30,14 +30,14 @@ describe "Server" do
|
|
30
30
|
expect(server.default_command).to eq(:qux)
|
31
31
|
end
|
32
32
|
|
33
|
-
describe "#
|
34
|
-
let(:environment) { environment = stub(:Environment, :name => :the_environment) }
|
33
|
+
describe "#parent=" do
|
34
|
+
let(:environment) { environment = stub(:Environment, :name => :the_environment, :default_server_config => proc {}) }
|
35
35
|
|
36
36
|
it { should have_accessor(:environment, environment) }
|
37
37
|
|
38
38
|
it "sets RAILS_ENV environment variable" do
|
39
39
|
server.environment_variables.should == {}
|
40
|
-
server.
|
40
|
+
server.parent = environment
|
41
41
|
expect(server.environment_variables[:RAILS_ENV]).to eq(environment.name.to_s)
|
42
42
|
end
|
43
43
|
end
|
data/spec/lib/taketo/dsl_spec.rb
CHANGED
@@ -8,11 +8,15 @@ describe "DSL" do
|
|
8
8
|
extend DSLSpec
|
9
9
|
include DSLSpec
|
10
10
|
|
11
|
-
shared_examples "a scoped construct" do |name,
|
12
|
-
|
13
|
-
|
11
|
+
shared_examples "a scoped construct" do |name, parents, with_block|
|
12
|
+
parents = Array(parents)
|
13
|
+
|
14
|
+
parents.each do |parent_scope_name|
|
15
|
+
parent_scope = scopes[parent_scope_name]
|
16
|
+
it { should be_appropriate_construct(name, :foo).with_block(with_block).under(parent_scope) }
|
17
|
+
end
|
14
18
|
|
15
|
-
scopes.except(
|
19
|
+
scopes.except(*parents).each do |inappropriate_scope|
|
16
20
|
it { should_not be_appropriate_construct(name, :foo).with_block(with_block).under(inappropriate_scope) }
|
17
21
|
end
|
18
22
|
end
|
@@ -52,16 +56,26 @@ describe "DSL" do
|
|
52
56
|
c.send(scope_name, :bar) {} # c.project(:bar) {}
|
53
57
|
end # end
|
54
58
|
end # end
|
59
|
+
|
60
|
+
it "sets #{scope_name}'s parent to the #{parent_scope_name} scope object" do # it "sets project's parent to the config scope object" do
|
61
|
+
dsl(parent_scope, factory.create(parent_scope_name)) do |c| # dsl([:config], factory.create(:config)) do |c|
|
62
|
+
stub_find_or_create_scope_object(c, scope_name, :bar) # stub_find_or_create_scope_object(c, :project, :bar)
|
63
|
+
factory.send(scope_name).should_receive(:parent=).with(c.current_scope_object) # factory.project.should_receive(:parent=).with(c.current_scope_object)
|
64
|
+
c.send(scope_name, :bar) {} # c.project(:bar) {}
|
65
|
+
end # end
|
66
|
+
end #
|
55
67
|
end
|
56
68
|
|
57
|
-
shared_examples "a scoped method" do |attribute_name,
|
58
|
-
it_behaves_like "a scoped construct", attribute_name,
|
69
|
+
shared_examples "a scoped method" do |attribute_name, parent_scope_names, parent_scope_method, example_value|
|
70
|
+
it_behaves_like "a scoped construct", attribute_name, parent_scope_names, false
|
59
71
|
|
60
|
-
|
61
|
-
|
62
|
-
factory.
|
63
|
-
|
64
|
-
|
72
|
+
Array(parent_scope_names).each do |parent_scope_name|
|
73
|
+
it "calls #{parent_scope_method} on current #{parent_scope_name}" do # it "calls default_location= on current server" do
|
74
|
+
dsl(scopes[parent_scope_name], factory.create(parent_scope_name, :foo)) do |c| # dsl([:config, :project, :environment, :server], factory.create(:server, :foo)) do |c|
|
75
|
+
factory.send(parent_scope_name).should_receive(parent_scope_method).with(example_value) # factory.server.should_receive(:default_location=).with('/var/app/')
|
76
|
+
c.send(attribute_name, example_value) # c.location "/var/app"
|
77
|
+
end # end
|
78
|
+
end
|
65
79
|
end
|
66
80
|
end
|
67
81
|
|
@@ -69,6 +83,18 @@ describe "DSL" do
|
|
69
83
|
it_behaves_like "a scoped method", :default_destination, :config, :default_destination=, "foo:bar:baz"
|
70
84
|
end
|
71
85
|
|
86
|
+
describe "#default_server_config" do
|
87
|
+
it_behaves_like "a scoped construct", :default_server_config, [:config, :project, :environment]
|
88
|
+
|
89
|
+
it "stores a block" do
|
90
|
+
dsl(scopes[:config], factory.create(:config)) do |c|
|
91
|
+
cfg = proc { any_method_call_here }
|
92
|
+
factory.config.should_receive(:default_server_config=).with(cfg)
|
93
|
+
c.default_server_config(&cfg)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
72
98
|
describe "#shared_server_config" do
|
73
99
|
it_behaves_like "a scoped construct", :shared_server_config, :config
|
74
100
|
|
@@ -84,14 +110,14 @@ describe "DSL" do
|
|
84
110
|
describe "#include_shared_server_config" do
|
85
111
|
it "executes the block on dsl object in server scope for given shared config names" do
|
86
112
|
dsl(scopes[:server], factory.create(:server)) do |c|
|
87
|
-
c.stub(:shared_server_configs => { :foo => proc {
|
88
|
-
c.should_receive(:
|
89
|
-
c.should_receive(:
|
113
|
+
c.stub(:shared_server_configs => { :foo => proc { call_from_foo }, :bar => proc { call_from_bar } })
|
114
|
+
c.should_receive(:call_from_foo)
|
115
|
+
c.should_receive(:call_from_bar)
|
90
116
|
c.include_shared_server_config(:foo, :bar)
|
91
117
|
end
|
92
118
|
end
|
93
119
|
|
94
|
-
context "when the
|
120
|
+
context "when the argument is hash where shared config names are keys" do
|
95
121
|
context "when hash values are arrays" do
|
96
122
|
it "includes config corresponding to hash key and passes exploded arguments" do
|
97
123
|
dsl(scopes[:server], factory.create(:server)) do |c|
|
@@ -113,6 +139,17 @@ describe "DSL" do
|
|
113
139
|
end
|
114
140
|
end
|
115
141
|
|
142
|
+
context "whne there are symbol arguments (names of shared configs) and a hash" do
|
143
|
+
it "includes config corresponding to symbol arguments and hash keys" do
|
144
|
+
dsl(scopes[:server], factory.create(:server)) do |c|
|
145
|
+
c.stub(:shared_server_configs => { :foo => proc { call_from_foo }, :bar => proc { |qux| call_from_bar(qux) } })
|
146
|
+
c.should_receive(:call_from_foo)
|
147
|
+
c.should_receive(:call_from_bar).with(123)
|
148
|
+
c.include_shared_server_config(:foo, :bar => 123)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
116
153
|
it "raises ConfigError if non-existent config included" do
|
117
154
|
dsl(scopes[:server], factory.create(:server)) do |c|
|
118
155
|
expect { c.include_shared_server_config(:foo) }.to raise_error(Taketo::DSL::ConfigError, "Shared server config 'foo' is not defined!")
|
@@ -131,6 +168,20 @@ describe "DSL" do
|
|
131
168
|
describe "#server" do
|
132
169
|
it_behaves_like "a scope", :server, :environment
|
133
170
|
|
171
|
+
it "evaluates default_server_config" do
|
172
|
+
dsl(scopes[:environment], factory.create(:environment, :foo)) do |c|
|
173
|
+
stub_find_or_create_scope_object(c, :server, :bar)
|
174
|
+
|
175
|
+
default_server_config = proc { some_setup }
|
176
|
+
factory.server.stub(:default_server_config => default_server_config)
|
177
|
+
|
178
|
+
c.should_receive(:some_setup)
|
179
|
+
|
180
|
+
c.server(:bar) do
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
134
185
|
it "has name optional" do
|
135
186
|
dsl(scopes[:environment], factory.create(:environment, :foo)) do |c|
|
136
187
|
stub_find_or_create_scope_object(c, :server, :default)
|
@@ -7,23 +7,23 @@ module DSLSpec
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def create_config(*args)
|
10
|
-
@config ||= RSpec::Mocks::Mock.new(:Config).as_null_object
|
10
|
+
@config ||= RSpec::Mocks::Mock.new(:Config, :default_server_config => proc {}).as_null_object
|
11
11
|
end
|
12
12
|
|
13
13
|
def create_project(name = :foo)
|
14
|
-
@project ||= RSpec::Mocks::Mock.new(:Project, :name => name).as_null_object
|
14
|
+
@project ||= RSpec::Mocks::Mock.new(:Project, :name => name, :default_server_config => proc {}).as_null_object
|
15
15
|
end
|
16
16
|
|
17
17
|
def create_environment(name = :foo)
|
18
|
-
@environment ||= RSpec::Mocks::Mock.new(:Environment, :name => name).as_null_object
|
18
|
+
@environment ||= RSpec::Mocks::Mock.new(:Environment, :name => name, :default_server_config => proc {}).as_null_object
|
19
19
|
end
|
20
20
|
|
21
21
|
def create_server(name = :foo)
|
22
|
-
@server ||= RSpec::Mocks::Mock.new(:Server, :name => name).as_null_object
|
22
|
+
@server ||= RSpec::Mocks::Mock.new(:Server, :name => name, :default_server_config => proc {}).as_null_object
|
23
23
|
end
|
24
24
|
|
25
25
|
def create_command(name = :the_cmd)
|
26
|
-
@command ||= RSpec::Mocks::Mock.new(:Command, :name => name).as_null_object
|
26
|
+
@command ||= RSpec::Mocks::Mock.new(:Command, :name => name, :default_server_config => proc {}).as_null_object
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
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.8
|
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-
|
12
|
+
date: 2012-11-17 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
@@ -138,6 +138,7 @@ files:
|
|
138
138
|
- features/config.feature
|
139
139
|
- features/config_validation.feature
|
140
140
|
- features/connect_to_server.feature
|
141
|
+
- features/default_server_config.feature
|
141
142
|
- features/error_handling.feature
|
142
143
|
- features/help.feature
|
143
144
|
- features/step_definitions/main_steps.rb
|