foreplay 0.1.5 → 0.1.6
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 +11 -2
- data/Rakefile +1 -1
- data/foreplay.gemspec +6 -6
- data/lib/foreplay/cli.rb +48 -48
- data/lib/foreplay/deploy.rb +361 -344
- data/lib/foreplay/setup.rb +33 -33
- data/lib/foreplay/utility.rb +3 -3
- data/lib/foreplay/version.rb +1 -1
- data/spec/lib/foreplay/deploy_spec.rb +130 -122
- data/spec/lib/foreplay/setup_spec.rb +13 -13
- data/spec/lib/foreplay/utility_spec.rb +28 -28
- data/spec/spec_helper.rb +2 -2
- metadata +2 -2
data/lib/foreplay/setup.rb
CHANGED
|
@@ -1,33 +1,33 @@
|
|
|
1
|
-
require 'thor/group'
|
|
2
|
-
|
|
3
|
-
module Foreplay
|
|
4
|
-
class Setup < Thor::Group
|
|
5
|
-
include Thor::Actions
|
|
6
|
-
|
|
7
|
-
class_option :name, :
|
|
8
|
-
class_option :repository, :
|
|
9
|
-
class_option :user, :
|
|
10
|
-
class_option :password
|
|
11
|
-
class_option :keyfile
|
|
12
|
-
class_option :private_key, :
|
|
13
|
-
class_option :port, :
|
|
14
|
-
class_option :path, :
|
|
15
|
-
class_option :servers, :
|
|
16
|
-
class_option :db_adapter, :
|
|
17
|
-
class_option :db_encoding, :
|
|
18
|
-
class_option :db_pool, :
|
|
19
|
-
class_option :db_name, :
|
|
20
|
-
class_option :db_host, :
|
|
21
|
-
class_option :db_user
|
|
22
|
-
class_option :db_password
|
|
23
|
-
class_option :resque_redis
|
|
24
|
-
|
|
25
|
-
def self.source_root
|
|
26
|
-
File.dirname(__FILE__)
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def config
|
|
30
|
-
template('setup/foreplay.yml', 'config/foreplay.yml')
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
end
|
|
1
|
+
require 'thor/group'
|
|
2
|
+
|
|
3
|
+
module Foreplay
|
|
4
|
+
class Setup < Thor::Group
|
|
5
|
+
include Thor::Actions
|
|
6
|
+
|
|
7
|
+
class_option :name, aliases: '-n', default: File.basename(Dir.getwd)
|
|
8
|
+
class_option :repository, aliases: '-r'
|
|
9
|
+
class_option :user, aliases: '-u'
|
|
10
|
+
class_option :password
|
|
11
|
+
class_option :keyfile
|
|
12
|
+
class_option :private_key, aliases: '-k'
|
|
13
|
+
class_option :port, aliases: '-p', default: 50_000
|
|
14
|
+
class_option :path, aliases: '-f'
|
|
15
|
+
class_option :servers, aliases: '-s', type: :array
|
|
16
|
+
class_option :db_adapter, aliases: '-a', default: 'postgresql'
|
|
17
|
+
class_option :db_encoding, aliases: '-e', default: 'utf8'
|
|
18
|
+
class_option :db_pool, default: 5
|
|
19
|
+
class_option :db_name, aliases: '-d'
|
|
20
|
+
class_option :db_host, aliases: '-h'
|
|
21
|
+
class_option :db_user
|
|
22
|
+
class_option :db_password
|
|
23
|
+
class_option :resque_redis
|
|
24
|
+
|
|
25
|
+
def self.source_root
|
|
26
|
+
File.dirname(__FILE__)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def config
|
|
30
|
+
template('setup/foreplay.yml', 'config/foreplay.yml')
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
data/lib/foreplay/utility.rb
CHANGED
|
@@ -7,15 +7,15 @@ module Foreplay
|
|
|
7
7
|
# h1.supermerge(h2)
|
|
8
8
|
# #=> {:x=>{:y=>[4, 5, 6, 7, 8, 9]}, :z=>[7, 8, 9, "xyz"]}
|
|
9
9
|
def self.supermerge(hash, other_hash)
|
|
10
|
-
|
|
10
|
+
fail 'supermerge only works if you pass two hashes' unless hash.is_a?(Hash) && other_hash.is_a?(Hash)
|
|
11
11
|
|
|
12
12
|
new_hash = hash.deep_dup.with_indifferent_access
|
|
13
13
|
|
|
14
|
-
other_hash.each_pair do |k,v|
|
|
14
|
+
other_hash.each_pair do |k, v|
|
|
15
15
|
tv = new_hash[k]
|
|
16
16
|
|
|
17
17
|
if tv.is_a?(Hash) && v.is_a?(Hash)
|
|
18
|
-
new_hash[k] = Foreplay::Utility
|
|
18
|
+
new_hash[k] = Foreplay::Utility.supermerge(tv, v)
|
|
19
19
|
elsif tv.is_a?(Array) || v.is_a?(Array)
|
|
20
20
|
new_hash[k] = Array.wrap(tv) + Array.wrap(v)
|
|
21
21
|
else
|
data/lib/foreplay/version.rb
CHANGED
|
@@ -1,122 +1,130 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
require 'foreplay'
|
|
3
|
-
require 'net/ssh/shell'
|
|
4
|
-
|
|
5
|
-
describe Foreplay::Deploy do
|
|
6
|
-
let
|
|
7
|
-
let
|
|
8
|
-
let
|
|
9
|
-
let
|
|
10
|
-
|
|
11
|
-
before :each do
|
|
12
|
-
# Setup foreplay
|
|
13
|
-
`rm -f config/foreplay.yml`
|
|
14
|
-
`foreplay setup -r git@github.com:Xenapto/foreplay.git -s web.example.com -f apps/%a -u fred --password trollope`
|
|
15
|
-
|
|
16
|
-
# Stub all the things
|
|
17
|
-
Net::SSH.stub(:start).and_yield(session)
|
|
18
|
-
session.stub(:shell).and_yield(shell)
|
|
19
|
-
shell.stub(:execute).and_return(process)
|
|
20
|
-
shell.stub(:wait!).and_return(false)
|
|
21
|
-
process.stub(:on_output).and_yield(process, "output message\n")
|
|
22
|
-
process.stub(:exit_status).and_return(0)
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
it "should complain on check if there's no config file" do
|
|
26
|
-
`rm -f config/foreplay.yml`
|
|
27
|
-
expect { Foreplay::Deploy.start([:check, 'production', '']) }
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
it "should
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
'
|
|
75
|
-
'
|
|
76
|
-
'
|
|
77
|
-
'
|
|
78
|
-
'echo "
|
|
79
|
-
'
|
|
80
|
-
'echo "
|
|
81
|
-
'echo "
|
|
82
|
-
'echo "
|
|
83
|
-
'echo "
|
|
84
|
-
'echo "
|
|
85
|
-
'
|
|
86
|
-
'
|
|
87
|
-
'
|
|
88
|
-
'
|
|
89
|
-
'
|
|
90
|
-
'echo
|
|
91
|
-
'
|
|
92
|
-
'
|
|
93
|
-
'
|
|
94
|
-
'sudo
|
|
95
|
-
'sudo
|
|
96
|
-
'sudo
|
|
97
|
-
'
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'foreplay'
|
|
3
|
+
require 'net/ssh/shell'
|
|
4
|
+
|
|
5
|
+
describe Foreplay::Deploy do
|
|
6
|
+
let(:ssh) { double(Net::SSH) }
|
|
7
|
+
let(:session) { double(Net::SSH::Connection::Session) }
|
|
8
|
+
let(:shell) { double(Net::SSH::Shell) }
|
|
9
|
+
let(:process) { double(Net::SSH::Shell::Process) }
|
|
10
|
+
|
|
11
|
+
before :each do
|
|
12
|
+
# Setup foreplay
|
|
13
|
+
`rm -f config/foreplay.yml`
|
|
14
|
+
`foreplay setup -r git@github.com:Xenapto/foreplay.git -s web.example.com -f apps/%a -u fred --password trollope`
|
|
15
|
+
|
|
16
|
+
# Stub all the things
|
|
17
|
+
Net::SSH.stub(:start).and_yield(session)
|
|
18
|
+
session.stub(:shell).and_yield(shell)
|
|
19
|
+
shell.stub(:execute).and_return(process)
|
|
20
|
+
shell.stub(:wait!).and_return(false)
|
|
21
|
+
process.stub(:on_output).and_yield(process, "output message\n")
|
|
22
|
+
process.stub(:exit_status).and_return(0)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "should complain on check if there's no config file" do
|
|
26
|
+
`rm -f config/foreplay.yml`
|
|
27
|
+
expect { Foreplay::Deploy.start([:check, 'production', '']) }
|
|
28
|
+
.to raise_error(RuntimeError, /.*Please run foreplay setup or create the file manually.*/)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it "should complain on deploy if there's no config file" do
|
|
32
|
+
`rm -f config/foreplay.yml`
|
|
33
|
+
expect { Foreplay::Deploy.start([:deploy, 'production', '']) }
|
|
34
|
+
.to raise_error(RuntimeError, /.*Please run foreplay setup or create the file manually.*/)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it 'should complain if there are no authentication methods defined in the config file' do
|
|
38
|
+
`rm -f config/foreplay.yml`
|
|
39
|
+
`foreplay setup -r git@github.com:Xenapto/foreplay.git -s web.example.com -f apps/%a -u fred --password ""`
|
|
40
|
+
expect { Foreplay::Deploy.start([:deploy, 'production', '']) }
|
|
41
|
+
.to raise_error(
|
|
42
|
+
RuntimeError,
|
|
43
|
+
/.*No authentication methods supplied. You must supply a private key, key file or password in the configuration file*/
|
|
44
|
+
)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it "should complain if the private keyfile defined in the config file doesn't exist" do
|
|
48
|
+
`rm -f config/foreplay.yml`
|
|
49
|
+
`foreplay setup -r git@github.com:Xenapto/foreplay.git -s web.example.com -f apps/%a -u fred --keyfile "/home/fred/no-such-file"`
|
|
50
|
+
expect { Foreplay::Deploy.start([:deploy, 'production', '']) }
|
|
51
|
+
.to raise_error(Errno::ENOENT, %r{.*No such file or directory @ rb_sysopen - /home/fred/no-such-file*})
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it 'should terminate if a remote process exits with a non-zero status' do
|
|
55
|
+
process.stub(:exit_status).and_return(1)
|
|
56
|
+
expect { Foreplay::Deploy.start([:deploy, 'production', '']) }.to raise_error(RuntimeError, /.*output message*/)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it "should terminate if a connection can't be established with the remote server" do
|
|
60
|
+
Net::SSH.unstub(:start)
|
|
61
|
+
expect { Foreplay::Deploy.start([:deploy, 'production', '']) }
|
|
62
|
+
.to raise_error(RuntimeError, /.*There was a problem starting an ssh session on web.example.com*/)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it 'should check the config' do
|
|
66
|
+
$stdout.should_receive(:puts).at_least(:once)
|
|
67
|
+
Foreplay::Deploy.start [:check, 'production', '']
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
it 'should deploy to the environment' do
|
|
71
|
+
Net::SSH.should_receive(:start).with('web.example.com', 'fred', verbose: :warn, port: 22, password: 'trollope').and_yield(session)
|
|
72
|
+
|
|
73
|
+
[
|
|
74
|
+
'mkdir -p apps/foreplay && cd apps/foreplay && rm -rf 50000 && git clone git@github.com:Xenapto/foreplay.git 50000',
|
|
75
|
+
'rvm rvmrc trust 50000',
|
|
76
|
+
'rvm rvmrc warning ignore 50000',
|
|
77
|
+
'cd 50000',
|
|
78
|
+
'if [ -f .ruby-version ] ; then rvm install `cat .ruby-version` ; else echo "No .ruby-version file found" ; fi',
|
|
79
|
+
'mkdir -p config',
|
|
80
|
+
'echo "RAILS_ENV=production" > .env',
|
|
81
|
+
'echo "concurrency: web=1,worker=0,scheduler=0" > .foreman',
|
|
82
|
+
'echo "app: foreplay-50000" >> .foreman',
|
|
83
|
+
'echo "port: 50000" >> .foreman',
|
|
84
|
+
'echo "user: fred" >> .foreman',
|
|
85
|
+
'echo "production:" > config/database.yml',
|
|
86
|
+
'echo " adapter: postgresql" >> config/database.yml',
|
|
87
|
+
'echo " encoding: utf8" >> config/database.yml',
|
|
88
|
+
'echo " database: TODO Put the database name here" >> config/database.yml',
|
|
89
|
+
'echo " pool: 5" >> config/database.yml',
|
|
90
|
+
'echo " host: TODO Put here the database host name" >> config/database.yml',
|
|
91
|
+
'echo " username: TODO Put here the database user" >> config/database.yml',
|
|
92
|
+
'echo " password: TODO Put here the database user\'s password" >> config/database.yml',
|
|
93
|
+
'bundle install --deployment --without development test',
|
|
94
|
+
'sudo ln -f `which foreman` /usr/bin/foreman || echo Using default version of foreman',
|
|
95
|
+
'sudo foreman export upstart /etc/init',
|
|
96
|
+
'sudo start foreplay-50000 || sudo restart foreplay-50000',
|
|
97
|
+
'mkdir -p .foreplay/foreplay && touch .foreplay/foreplay/current_port && cat .foreplay/foreplay/current_port',
|
|
98
|
+
'echo 50000 > $HOME/.foreplay/foreplay/current_port',
|
|
99
|
+
'sleep 60',
|
|
100
|
+
'sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 50000',
|
|
101
|
+
'sudo iptables -t nat -D PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 51000',
|
|
102
|
+
'sudo iptables-save > /etc/iptables/rules.v4',
|
|
103
|
+
'sudo iptables-save > /etc/iptables.up.rules',
|
|
104
|
+
'sudo iptables-save -c | egrep REDIRECT --color=never',
|
|
105
|
+
'sudo stop foreplay-51000 || echo \'No previous instance running\''
|
|
106
|
+
].each do |command|
|
|
107
|
+
shell.should_receive(:execute).with(command).and_return(process)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
Foreplay::Deploy.start [:deploy, 'production', '']
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
it "should use another port if there's already an installed instance" do
|
|
114
|
+
process.stub(:on_output).and_yield(process, "50000\n")
|
|
115
|
+
shell.should_receive(:execute).with('echo 51000 > $HOME/.foreplay/foreplay/current_port').and_return(process)
|
|
116
|
+
Foreplay::Deploy.start [:deploy, 'production', '']
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
it 'should use the private key provided in the config file' do
|
|
120
|
+
`rm -f config/foreplay.yml`
|
|
121
|
+
`foreplay setup -r git@github.com:Xenapto/foreplay.git -s web.example.com -f apps/%a -u fred -k "top secret private key"`
|
|
122
|
+
Foreplay::Deploy.start([:deploy, 'production', ''])
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
it 'should add Redis details for Resque' do
|
|
126
|
+
`rm -f config/foreplay.yml`
|
|
127
|
+
`foreplay setup -r git@github.com:Xenapto/foreplay.git -s web.example.com -f apps/%a -u fred --resque-redis "redis://localhost:6379"`
|
|
128
|
+
Foreplay::Deploy.start([:deploy, 'production', ''])
|
|
129
|
+
end
|
|
130
|
+
end
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
require 'foreplay'
|
|
3
|
-
|
|
4
|
-
describe Foreplay::Setup do
|
|
5
|
-
before :each do
|
|
6
|
-
`rm -f config/foreplay.yml`
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
it
|
|
10
|
-
File.should_receive(:open)
|
|
11
|
-
Foreplay::Setup.start
|
|
12
|
-
end
|
|
13
|
-
end
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'foreplay'
|
|
3
|
+
|
|
4
|
+
describe Foreplay::Setup do
|
|
5
|
+
before :each do
|
|
6
|
+
`rm -f config/foreplay.yml`
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
it 'should create a config file' do
|
|
10
|
+
File.should_receive(:open)
|
|
11
|
+
Foreplay::Setup.start
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -1,28 +1,28 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
require 'foreplay'
|
|
3
|
-
|
|
4
|
-
describe Foreplay::Utility do
|
|
5
|
-
it
|
|
6
|
-
expect { Foreplay::Utility
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
it
|
|
10
|
-
expect(Foreplay::Utility
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
it
|
|
14
|
-
expect(Foreplay::Utility
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
it
|
|
18
|
-
expect(Foreplay::Utility
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
it
|
|
22
|
-
expect(Foreplay::Utility
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
it
|
|
26
|
-
expect(Foreplay::Utility
|
|
27
|
-
end
|
|
28
|
-
end
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'foreplay'
|
|
3
|
+
|
|
4
|
+
describe Foreplay::Utility do
|
|
5
|
+
it 'should complain unless two hashes are passed to it' do
|
|
6
|
+
expect { Foreplay::Utility.supermerge('x', 'y') }.to raise_error(RuntimeError)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
it 'should merge two simple hashes' do
|
|
10
|
+
expect(Foreplay::Utility.supermerge({ a: 'x' }, { b: 'y' })).to eq('a' => 'x', 'b' => 'y')
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it 'should merge two hashes both with arrays at the same key' do
|
|
14
|
+
expect(Foreplay::Utility.supermerge({ a: ['x'] }, { a: ['y'] })).to eq('a' => %w(x y))
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it 'should merge an array and a value at the same key' do
|
|
18
|
+
expect(Foreplay::Utility.supermerge({ a: 'x' }, { a: ['y'] })).to eq('a' => %w(x y))
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it 'should replace a value at the same key' do
|
|
22
|
+
expect(Foreplay::Utility.supermerge({ a: 'x' }, { a: 'y' })).to eq('a' => 'y')
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it 'should merge two subhashes at the same key' do
|
|
26
|
+
expect(Foreplay::Utility.supermerge({ a: { b: 'x' } }, { a: { c: 'y' } })).to eq('a' => { 'b' => 'x', 'c' => 'y' })
|
|
27
|
+
end
|
|
28
|
+
end
|
data/spec/spec_helper.rb
CHANGED
|
@@ -5,11 +5,11 @@ SimpleCov.start
|
|
|
5
5
|
Coveralls.wear!('rails') if ENV['COVERALLS_REPO_TOKEN']
|
|
6
6
|
|
|
7
7
|
RSpec.configure do |config|
|
|
8
|
-
|
|
8
|
+
# Run specs in random order to surface order dependencies. If you find an
|
|
9
9
|
# order dependency and want to debug it, you can fix the order by providing
|
|
10
10
|
# the seed, which is printed after each run.
|
|
11
11
|
# --seed 1234
|
|
12
|
-
config.order =
|
|
12
|
+
config.order = 'random'
|
|
13
13
|
|
|
14
14
|
# Manually-added
|
|
15
15
|
config.color_enabled = true
|
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.1.
|
|
4
|
+
version: 0.1.6
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Xenapto
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2014-06-
|
|
11
|
+
date: 2014-06-13 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activesupport
|