foreplay 0.9.8 → 0.9.9
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.
- checksums.yaml +4 -4
- data/.rubocop.yml +2 -9
- data/lib/foreplay.rb +1 -0
- data/lib/foreplay/engine.rb +16 -43
- data/lib/foreplay/engine/port.rb +66 -0
- data/lib/foreplay/engine/remote.rb +1 -1
- data/lib/foreplay/engine/remote/step.rb +14 -23
- data/lib/foreplay/engine/server.rb +25 -79
- data/lib/foreplay/engine/step.rb +69 -23
- data/lib/foreplay/version.rb +1 -1
- data/lib/hash.rb +30 -0
- data/spec/lib/foreplay/deploy_spec.rb +1 -1
- data/spec/lib/hash_spec.rb +30 -0
- metadata +6 -4
- data/spec/lib/foreplay/engine_spec.rb +0 -32
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 54fa14c8cd58bcbcfa3d6ae58721785d2cbedf60
|
|
4
|
+
data.tar.gz: 78bfd857d56736431725d9d3b9eddc307f327c85
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: df13a59675a8e854d44d4b09c85723af3d8ef482c1fd726a5f3c1dd7169d5d0e17b77b8b4a6088fe122c74a6942dc42989ae44a4cf6edfe2bb0ee4f5a6d59dab
|
|
7
|
+
data.tar.gz: d98356701a491e17c6beea0abeedf0530515f13f6952bb3278d289089990a87b984fbf64bcf3e91671f7cc2658acca1f3737eb1609f31078ab0239ec52c53266
|
data/.rubocop.yml
CHANGED
|
@@ -42,14 +42,7 @@ LineLength:
|
|
|
42
42
|
|
|
43
43
|
MethodLength:
|
|
44
44
|
Description: 'Avoid methods longer than 10 lines of code.'
|
|
45
|
-
Max: 27 # 85
|
|
46
|
-
|
|
47
|
-
CyclomaticComplexity:
|
|
48
|
-
Description: 'Avoid complex methods.'
|
|
49
|
-
Max: 9
|
|
50
|
-
|
|
51
|
-
PerceivedComplexity:
|
|
52
|
-
Max: 11 # 17
|
|
45
|
+
Max: 18 # 27 # 85
|
|
53
46
|
|
|
54
47
|
AbcSize:
|
|
55
|
-
Max:
|
|
48
|
+
Max: 23 # 62
|
data/lib/foreplay.rb
CHANGED
|
@@ -5,6 +5,7 @@ require 'foreplay/engine'
|
|
|
5
5
|
require 'foreplay/engine/remote'
|
|
6
6
|
require 'foreplay/engine/remote/check'
|
|
7
7
|
require 'foreplay/engine/remote/step'
|
|
8
|
+
require 'foreplay/engine/port'
|
|
8
9
|
require 'foreplay/engine/role'
|
|
9
10
|
require 'foreplay/engine/secrets'
|
|
10
11
|
require 'foreplay/engine/server'
|
data/lib/foreplay/engine.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
require 'yaml'
|
|
2
2
|
require 'string'
|
|
3
|
-
require '
|
|
3
|
+
require 'hash'
|
|
4
4
|
|
|
5
5
|
class Foreplay::Engine
|
|
6
6
|
include Foreplay
|
|
@@ -29,49 +29,19 @@ class Foreplay::Engine
|
|
|
29
29
|
puts "#{mode.capitalize}ing #{environment.dup.yellow} environment, "\
|
|
30
30
|
"#{explanatory_text(filters, 'role')}, #{explanatory_text(filters, 'server')}"
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
roles.each do |role, additional_instructions|
|
|
35
|
-
next if role == DEFAULTS_KEY # 'defaults' is not a role
|
|
36
|
-
next if filters.key?('role') && filters['role'] != role
|
|
37
|
-
|
|
38
|
-
threads.concat Foreplay::Engine::Role.new(
|
|
32
|
+
actionable_roles.map do |role, instructions|
|
|
33
|
+
Foreplay::Engine::Role.new(
|
|
39
34
|
environment,
|
|
40
35
|
mode,
|
|
41
|
-
build_instructions(role,
|
|
36
|
+
build_instructions(role, instructions)
|
|
42
37
|
).threads
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
threads.each(&:join)
|
|
38
|
+
end.flatten.each(&:join)
|
|
46
39
|
|
|
47
40
|
puts mode == :deploy ? 'Finished deployment' : 'Deployment configuration check was successful'
|
|
48
41
|
end
|
|
49
42
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
# h1 = { x: { y: [4,5,6] }, z: [7,8,9] }
|
|
53
|
-
# h2 = { x: { y: [7,8,9] }, z: 'xyz' }
|
|
54
|
-
# h1.supermerge(h2)
|
|
55
|
-
# #=> {:x=>{:y=>[4, 5, 6, 7, 8, 9]}, :z=>[7, 8, 9, "xyz"]}
|
|
56
|
-
def supermerge(hash, other_hash)
|
|
57
|
-
fail 'supermerge only works if you pass two hashes. '\
|
|
58
|
-
"You passed a #{hash.class} and a #{other_hash.class}." unless hash.is_a?(Hash) && other_hash.is_a?(Hash)
|
|
59
|
-
|
|
60
|
-
new_hash = hash.deep_dup
|
|
61
|
-
|
|
62
|
-
other_hash.each_pair do |k, v|
|
|
63
|
-
tv = new_hash[k]
|
|
64
|
-
|
|
65
|
-
if tv.is_a?(Hash) && v.is_a?(Hash)
|
|
66
|
-
new_hash[k] = supermerge(tv, v)
|
|
67
|
-
elsif tv.is_a?(Array) || v.is_a?(Array)
|
|
68
|
-
new_hash[k] = Array.wrap(tv) + Array.wrap(v)
|
|
69
|
-
else
|
|
70
|
-
new_hash[k] = v
|
|
71
|
-
end
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
new_hash
|
|
43
|
+
def actionable_roles
|
|
44
|
+
roles.select { |role, _i| role != DEFAULTS_KEY && role != filters['role'] }
|
|
75
45
|
end
|
|
76
46
|
|
|
77
47
|
private
|
|
@@ -81,7 +51,7 @@ class Foreplay::Engine
|
|
|
81
51
|
end
|
|
82
52
|
|
|
83
53
|
def build_instructions(role, additional_instructions)
|
|
84
|
-
instructions = supermerge(
|
|
54
|
+
instructions = defaults.supermerge(additional_instructions)
|
|
85
55
|
instructions['role'] = role
|
|
86
56
|
required_keys = %w(name environment role servers path repository)
|
|
87
57
|
|
|
@@ -115,16 +85,19 @@ class Foreplay::Engine
|
|
|
115
85
|
'port' => 50_000
|
|
116
86
|
}
|
|
117
87
|
|
|
118
|
-
|
|
119
|
-
secrets = Foreplay::Engine::Secrets.new(environment, roles_all['secrets']).fetch || {}
|
|
120
|
-
@defaults['env'] = @defaults['env'].merge secrets
|
|
88
|
+
@defaults['env'].merge! secrets
|
|
121
89
|
@defaults['application'] = secrets
|
|
122
90
|
|
|
123
|
-
@defaults = supermerge(
|
|
124
|
-
@defaults = supermerge(
|
|
91
|
+
@defaults = @defaults.supermerge(roles_all[DEFAULTS_KEY]) if roles_all.key? DEFAULTS_KEY
|
|
92
|
+
@defaults = @defaults.supermerge(roles[DEFAULTS_KEY]) if roles.key? DEFAULTS_KEY
|
|
125
93
|
@defaults
|
|
126
94
|
end
|
|
127
95
|
|
|
96
|
+
# Secret environment variables
|
|
97
|
+
def secrets
|
|
98
|
+
@secrets ||= Foreplay::Engine::Secrets.new(environment, roles_all['secrets']).fetch || {}
|
|
99
|
+
end
|
|
100
|
+
|
|
128
101
|
def roles
|
|
129
102
|
@roles ||= roles_all[environment]
|
|
130
103
|
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
module Foreplay::Engine::Port
|
|
2
|
+
include Foreplay
|
|
3
|
+
|
|
4
|
+
def host
|
|
5
|
+
return @host if @host
|
|
6
|
+
@host, _p = server.split(':') # Parse host + port
|
|
7
|
+
@host
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def name
|
|
11
|
+
@name ||= instructions['name']
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def current_port
|
|
15
|
+
@current_port ||= port_details['current_port']
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def current_service
|
|
19
|
+
@current_service ||= port_details['current_service']
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def former_port
|
|
23
|
+
@former_port ||= port_details['former_port']
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def former_service
|
|
27
|
+
@former_service ||= port_details['former_service']
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def current_port_file
|
|
31
|
+
@current_port_file ||= ".foreplay/#{name}/current_port"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def port_steps
|
|
35
|
+
@port_steps ||= [
|
|
36
|
+
{
|
|
37
|
+
'command' => "mkdir -p .foreplay/#{name} && touch #{current_port_file} && cat #{current_port_file}",
|
|
38
|
+
'silent' => true
|
|
39
|
+
}
|
|
40
|
+
]
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def port_details
|
|
44
|
+
return @port_details if @port_details
|
|
45
|
+
|
|
46
|
+
current_port_string = Foreplay::Engine::Remote.new(server, port_steps, instructions).__send__(mode).strip!
|
|
47
|
+
|
|
48
|
+
if current_port_string.blank?
|
|
49
|
+
puts "#{host}#{INDENT}No instance is currently deployed"
|
|
50
|
+
else
|
|
51
|
+
puts "#{host}#{INDENT}Current instance is using port #{current_port_string}"
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
cp = current_port_string.to_i
|
|
55
|
+
port = instructions['port']
|
|
56
|
+
ports = [port + 1000, port]
|
|
57
|
+
cp, fp = cp == port ? ports : ports.reverse
|
|
58
|
+
|
|
59
|
+
@port_details = {
|
|
60
|
+
'current_port' => cp,
|
|
61
|
+
'current_service' => "#{name}-#{cp}",
|
|
62
|
+
'former_port' => fp,
|
|
63
|
+
'former_service' => "#{name}-#{fp}"
|
|
64
|
+
}
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -22,7 +22,7 @@ class Foreplay::Engine::Remote
|
|
|
22
22
|
puts "#{host}#{INDENT}Successfully connected to #{host} on port #{port}"
|
|
23
23
|
|
|
24
24
|
session.shell do |sh|
|
|
25
|
-
steps.each { |step| output += Foreplay::Engine::Remote::Step.new(host, sh, step, instructions).
|
|
25
|
+
steps.each { |step| output += Foreplay::Engine::Remote::Step.new(host, sh, step, instructions).execute }
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
session.close
|
|
@@ -9,31 +9,22 @@ class Foreplay::Engine::Remote::Step
|
|
|
9
9
|
@instructions = i
|
|
10
10
|
end
|
|
11
11
|
|
|
12
|
-
def
|
|
12
|
+
def execute
|
|
13
13
|
puts "#{host}#{INDENT}#{(step['commentary'] || step['command']).yellow}" unless step['silent'] == true
|
|
14
|
+
output Foreplay::Engine::Step.new(step, instructions).build.map { |command| execute_command(command) }.join
|
|
15
|
+
end
|
|
14
16
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
process.on_output do |_, o|
|
|
24
|
-
previous = o
|
|
25
|
-
output += previous
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
shell.wait!
|
|
29
|
-
|
|
30
|
-
if step['ignore_error'] == true || process.exit_status == 0
|
|
31
|
-
print output.gsub!(/^/, "#{host}#{INDENT * 2}") unless step['silent'] == true || output.blank?
|
|
32
|
-
else
|
|
33
|
-
terminate(output)
|
|
34
|
-
end
|
|
35
|
-
end
|
|
17
|
+
def execute_command(command)
|
|
18
|
+
o = ''
|
|
19
|
+
process = shell.execute command
|
|
20
|
+
process.on_output { |_, po| o = po }
|
|
21
|
+
shell.wait!
|
|
22
|
+
terminate(o) unless step['ignore_error'] == true || process.exit_status == 0
|
|
23
|
+
o
|
|
24
|
+
end
|
|
36
25
|
|
|
37
|
-
|
|
26
|
+
def output(o)
|
|
27
|
+
puts o.gsub!(/^/, "#{host}#{INDENT * 2}") unless step['silent'] == true || o.blank?
|
|
28
|
+
o
|
|
38
29
|
end
|
|
39
30
|
end
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
class Foreplay::Engine::Server
|
|
2
|
-
include Foreplay
|
|
2
|
+
include Foreplay::Engine::Port
|
|
3
3
|
attr_reader :environment, :mode, :instructions, :server
|
|
4
4
|
|
|
5
5
|
def initialize(e, m, i, s)
|
|
@@ -10,24 +10,33 @@ class Foreplay::Engine::Server
|
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
def execute
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
execute_announce
|
|
14
|
+
foreman
|
|
15
|
+
env
|
|
16
|
+
Foreplay::Engine::Remote.new(server, steps, instructions).__send__ mode
|
|
17
|
+
end
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
def execute_announce
|
|
20
|
+
preposition = mode == :deploy ? 'to' : 'for'
|
|
21
|
+
puts "#{mode.capitalize}ing #{name.yellow} #{preposition} #{host.yellow} "\
|
|
22
|
+
"for the #{role.dup.yellow} role in the #{environment.dup.yellow} environment"
|
|
23
|
+
end
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
instructions['
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
def foreman
|
|
26
|
+
instructions['foreman'].merge!(
|
|
27
|
+
'app' => current_service,
|
|
28
|
+
'port' => current_port,
|
|
29
|
+
'user' => user,
|
|
30
|
+
'log' => "$HOME/#{path}/#{current_port}/log"
|
|
31
|
+
)
|
|
32
|
+
end
|
|
29
33
|
|
|
30
|
-
|
|
34
|
+
def env
|
|
35
|
+
instructions['env'].merge!(
|
|
36
|
+
'HOME' => '$HOME',
|
|
37
|
+
'SHELL' => '$SHELL',
|
|
38
|
+
'PATH' => '$PATH:`which bundle`'
|
|
39
|
+
)
|
|
31
40
|
end
|
|
32
41
|
|
|
33
42
|
def role
|
|
@@ -38,10 +47,6 @@ class Foreplay::Engine::Server
|
|
|
38
47
|
@user ||= instructions['user']
|
|
39
48
|
end
|
|
40
49
|
|
|
41
|
-
def name
|
|
42
|
-
@name ||= instructions['name']
|
|
43
|
-
end
|
|
44
|
-
|
|
45
50
|
def path
|
|
46
51
|
return @path if @path
|
|
47
52
|
|
|
@@ -51,12 +56,6 @@ class Foreplay::Engine::Server
|
|
|
51
56
|
@path
|
|
52
57
|
end
|
|
53
58
|
|
|
54
|
-
def host
|
|
55
|
-
return @host if @host
|
|
56
|
-
@host, _p = server.split(':') # Parse host + port
|
|
57
|
-
@host
|
|
58
|
-
end
|
|
59
|
-
|
|
60
59
|
def steps
|
|
61
60
|
@steps ||= YAML.load(
|
|
62
61
|
ERB.new(
|
|
@@ -66,57 +65,4 @@ class Foreplay::Engine::Server
|
|
|
66
65
|
).result(binding)
|
|
67
66
|
)
|
|
68
67
|
end
|
|
69
|
-
|
|
70
|
-
def current_port
|
|
71
|
-
@current_port ||= port_details['current_port']
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
def current_service
|
|
75
|
-
@current_service ||= port_details['current_service']
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
def former_port
|
|
79
|
-
@former_port ||= port_details['former_port']
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
def former_service
|
|
83
|
-
@former_service ||= port_details['former_service']
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
def current_port_file
|
|
87
|
-
@current_port_file ||= ".foreplay/#{name}/current_port"
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
def port_steps
|
|
91
|
-
@port_steps ||= [
|
|
92
|
-
{
|
|
93
|
-
'command' => "mkdir -p .foreplay/#{name} && touch #{current_port_file} && cat #{current_port_file}",
|
|
94
|
-
'silent' => true
|
|
95
|
-
}
|
|
96
|
-
]
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
def port_details
|
|
100
|
-
return @port_details if @port_details
|
|
101
|
-
|
|
102
|
-
current_port_string = Foreplay::Engine::Remote.new(server, port_steps, instructions).__send__(mode).strip!
|
|
103
|
-
|
|
104
|
-
if current_port_string.blank?
|
|
105
|
-
puts "#{host}#{INDENT}No instance is currently deployed"
|
|
106
|
-
else
|
|
107
|
-
puts "#{host}#{INDENT}Current instance is using port #{current_port_string}"
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
cp = current_port_string.to_i
|
|
111
|
-
port = instructions['port']
|
|
112
|
-
ports = [port + 1000, port]
|
|
113
|
-
cp, fp = cp == port ? ports : ports.reverse
|
|
114
|
-
|
|
115
|
-
@port_details = {
|
|
116
|
-
'current_port' => cp,
|
|
117
|
-
'current_service' => "#{name}-#{cp}",
|
|
118
|
-
'former_port' => fp,
|
|
119
|
-
'former_service' => "#{name}-#{fp}"
|
|
120
|
-
}
|
|
121
|
-
end
|
|
122
68
|
end
|
data/lib/foreplay/engine/step.rb
CHANGED
|
@@ -9,44 +9,90 @@ class Foreplay::Engine::Step
|
|
|
9
9
|
def build
|
|
10
10
|
# Each step can be (1) a command or (2) a series of values to add to a file
|
|
11
11
|
if step.key?('key')
|
|
12
|
-
instructions.key?(step['key']) ?
|
|
12
|
+
instructions.key?(step['key']) ? commands : []
|
|
13
13
|
else
|
|
14
14
|
# ...or just execute the command specified
|
|
15
15
|
[step['command']]
|
|
16
16
|
end
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
def
|
|
20
|
-
|
|
21
|
-
key = step['key']
|
|
22
|
-
prefix = step['prefix'] || ''
|
|
23
|
-
suffix = step['suffix'] || ''
|
|
24
|
-
path = step['path'] || ''
|
|
25
|
-
before = step['before'] || ''
|
|
26
|
-
delimiter = step['delimiter'] || ''
|
|
27
|
-
after = step['after'] || ''
|
|
19
|
+
def commands
|
|
20
|
+
return @commands if @commands
|
|
28
21
|
|
|
29
22
|
step['silent'] = true
|
|
30
|
-
filename = "#{path}#{prefix}#{key}#{suffix}"
|
|
31
23
|
|
|
32
|
-
if
|
|
33
|
-
commands = ["echo \"#{
|
|
34
|
-
redirect
|
|
24
|
+
if header?
|
|
25
|
+
@commands = ["echo \"#{header}\" > #{filename}"]
|
|
26
|
+
redirect
|
|
35
27
|
else
|
|
36
|
-
commands = []
|
|
37
|
-
redirect = '>'
|
|
28
|
+
@commands = []
|
|
38
29
|
end
|
|
39
30
|
|
|
40
31
|
if instructions[key].is_a? Hash
|
|
41
|
-
|
|
42
|
-
commands << "echo \"#{before}#{k}#{delimiter}#{v}#{after}\" #{redirect} #{filename}"
|
|
43
|
-
redirect = '>>'
|
|
44
|
-
end
|
|
32
|
+
build_commands_from_hash
|
|
45
33
|
else
|
|
46
|
-
|
|
47
|
-
redirect = '>>'
|
|
34
|
+
build_commands_from_string
|
|
48
35
|
end
|
|
49
36
|
|
|
50
|
-
commands
|
|
37
|
+
@commands
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def build_commands_from_hash
|
|
41
|
+
instructions[key].each do |k, v|
|
|
42
|
+
@commands << "echo \"#{before}#{k}#{delimiter}#{v}#{after}\" #{redirect} #{filename}"
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def build_commands_from_string
|
|
47
|
+
@commands << "echo \"#{before}#{delimiter}#{instructions[key]}#{after}\" #{redirect} #{filename}"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def redirect
|
|
51
|
+
if @redirect
|
|
52
|
+
'>>'
|
|
53
|
+
else
|
|
54
|
+
@redirect = true
|
|
55
|
+
'>'
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def filename
|
|
60
|
+
@filename ||= "#{path}#{prefix}#{key}#{suffix}"
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def key
|
|
64
|
+
@key ||= step['key']
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def prefix
|
|
68
|
+
@prefix ||= step['prefix'] || ''
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def suffix
|
|
72
|
+
@suffix ||= step['suffix'] || ''
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def path
|
|
76
|
+
@path ||= step['path'] || ''
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def before
|
|
80
|
+
@before ||= step['before'] || ''
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def delimiter
|
|
84
|
+
@delimiter ||= step['delimiter'] || ''
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def after
|
|
88
|
+
@after ||= step['after'] || ''
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def header
|
|
92
|
+
@header ||= step['header']
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def header?
|
|
96
|
+
header.present?
|
|
51
97
|
end
|
|
52
98
|
end
|
data/lib/foreplay/version.rb
CHANGED
data/lib/hash.rb
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
require 'active_support/core_ext/object'
|
|
2
|
+
|
|
3
|
+
class Hash
|
|
4
|
+
# Returns a new hash with +hash+ and +other_hash+ merged recursively, including arrays.
|
|
5
|
+
#
|
|
6
|
+
# h1 = { x: { y: [4,5,6] }, z: [7,8,9] }
|
|
7
|
+
# h2 = { x: { y: [7,8,9] }, z: 'xyz' }
|
|
8
|
+
# h1.supermerge(h2)
|
|
9
|
+
# #=> {:x=>{:y=>[4, 5, 6, 7, 8, 9]}, :z=>[7, 8, 9, "xyz"]}
|
|
10
|
+
def supermerge(other_hash)
|
|
11
|
+
fail 'supermerge only works if you pass a hash. '\
|
|
12
|
+
"You passed a #{self.class} and a #{other_hash.class}." unless other_hash.is_a?(Hash)
|
|
13
|
+
|
|
14
|
+
new_hash = deep_dup
|
|
15
|
+
|
|
16
|
+
other_hash.each_pair do |k, v|
|
|
17
|
+
tv = new_hash[k]
|
|
18
|
+
|
|
19
|
+
if tv.is_a?(Hash) && v.is_a?(Hash)
|
|
20
|
+
new_hash[k] = tv.supermerge(v)
|
|
21
|
+
elsif tv.is_a?(Array) || v.is_a?(Array)
|
|
22
|
+
new_hash[k] = Array.wrap(tv) + Array.wrap(v)
|
|
23
|
+
else
|
|
24
|
+
new_hash[k] = v
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
new_hash
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -24,7 +24,7 @@ describe Foreplay::Launcher do
|
|
|
24
24
|
allow(session).to receive(:shell).and_yield(shell)
|
|
25
25
|
allow(shell).to receive(:execute).and_return(process)
|
|
26
26
|
allow(shell).to receive(:wait!).and_return(false)
|
|
27
|
-
allow(process).to receive(:on_output).and_yield(process, "output message\n")
|
|
27
|
+
allow(process).to receive(:on_output).and_yield(process, "output message 1\noutput message 2\n")
|
|
28
28
|
allow(process).to receive(:exit_status).and_return(0)
|
|
29
29
|
end
|
|
30
30
|
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'hash'
|
|
3
|
+
|
|
4
|
+
describe Hash do
|
|
5
|
+
context '#supermerge' do
|
|
6
|
+
it 'should complain unless two hashes are passed to it' do
|
|
7
|
+
expect { {}.supermerge('y') }.to raise_error(RuntimeError)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it 'should merge two simple hashes' do
|
|
11
|
+
expect({ a: 'x' }.supermerge(b: 'y')).to eq(a: 'x', b: 'y')
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it 'should merge two hashes both with arrays at the same key' do
|
|
15
|
+
expect({ a: ['x'] }.supermerge(a: ['y'])).to eq(a: %w(x y))
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it 'should merge an array and a value at the same key' do
|
|
19
|
+
expect({ a: 'x' }.supermerge(a: ['y'])).to eq(a: %w(x y))
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it 'should replace a value at the same key' do
|
|
23
|
+
expect({ a: 'x' }.supermerge(a: 'y')).to eq(a: 'y')
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it 'should merge two subhashes at the same key' do
|
|
27
|
+
expect({ a: { b: 'x' } }.supermerge(a: { c: 'y' })).to eq(a: { b: 'x', c: 'y' })
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: foreplay
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.9.
|
|
4
|
+
version: 0.9.9
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Xenapto
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2015-05-
|
|
11
|
+
date: 2015-05-07 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: foreman
|
|
@@ -222,6 +222,7 @@ files:
|
|
|
222
222
|
- lib/foreplay.rb
|
|
223
223
|
- lib/foreplay/cli.rb
|
|
224
224
|
- lib/foreplay/engine.rb
|
|
225
|
+
- lib/foreplay/engine/port.rb
|
|
225
226
|
- lib/foreplay/engine/remote.rb
|
|
226
227
|
- lib/foreplay/engine/remote/check.rb
|
|
227
228
|
- lib/foreplay/engine/remote/step.rb
|
|
@@ -235,11 +236,12 @@ files:
|
|
|
235
236
|
- lib/foreplay/setup.rb
|
|
236
237
|
- lib/foreplay/setup/foreplay.yml
|
|
237
238
|
- lib/foreplay/version.rb
|
|
239
|
+
- lib/hash.rb
|
|
238
240
|
- lib/string.rb
|
|
239
241
|
- spec/lib/foreplay/deploy_spec.rb
|
|
240
|
-
- spec/lib/foreplay/engine_spec.rb
|
|
241
242
|
- spec/lib/foreplay/secrets_spec.rb
|
|
242
243
|
- spec/lib/foreplay/setup_spec.rb
|
|
244
|
+
- spec/lib/hash_spec.rb
|
|
243
245
|
- spec/spec_helper.rb
|
|
244
246
|
homepage: https://github.com/Xenapto/foreplay
|
|
245
247
|
licenses:
|
|
@@ -271,7 +273,7 @@ test_files:
|
|
|
271
273
|
- features/setup.feature
|
|
272
274
|
- features/support/env.rb
|
|
273
275
|
- spec/lib/foreplay/deploy_spec.rb
|
|
274
|
-
- spec/lib/foreplay/engine_spec.rb
|
|
275
276
|
- spec/lib/foreplay/secrets_spec.rb
|
|
276
277
|
- spec/lib/foreplay/setup_spec.rb
|
|
278
|
+
- spec/lib/hash_spec.rb
|
|
277
279
|
- spec/spec_helper.rb
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
require 'foreplay'
|
|
3
|
-
|
|
4
|
-
describe Foreplay::Engine do
|
|
5
|
-
context '#supermerge' do
|
|
6
|
-
let(:engine) { Foreplay::Engine.new('b', 'b') }
|
|
7
|
-
|
|
8
|
-
it 'should complain unless two hashes are passed to it' do
|
|
9
|
-
expect { engine.supermerge('x', 'y') }.to raise_error(RuntimeError)
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
it 'should merge two simple hashes' do
|
|
13
|
-
expect(engine.supermerge({ a: 'x' }, b: 'y')).to eq(a: 'x', b: 'y')
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
it 'should merge two hashes both with arrays at the same key' do
|
|
17
|
-
expect(engine.supermerge({ a: ['x'] }, a: ['y'])).to eq(a: %w(x y))
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
it 'should merge an array and a value at the same key' do
|
|
21
|
-
expect(engine.supermerge({ a: 'x' }, a: ['y'])).to eq(a: %w(x y))
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
it 'should replace a value at the same key' do
|
|
25
|
-
expect(engine.supermerge({ a: 'x' }, a: 'y')).to eq(a: 'y')
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
it 'should merge two subhashes at the same key' do
|
|
29
|
-
expect(engine.supermerge({ a: { b: 'x' } }, a: { c: 'y' })).to eq(a: { b: 'x', c: 'y' })
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
end
|