shuttle-deploy 0.2.0.beta4 → 0.2.0.beta5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/README.md +57 -2
- data/bin/shuttle +1 -52
- data/examples/wordpress.yml +16 -1
- data/lib/shuttle/cli.rb +108 -0
- data/lib/shuttle/deployment/wordpress/cli.rb +36 -8
- data/lib/shuttle/deployment/wordpress.rb +8 -3
- data/lib/shuttle/helpers.rb +3 -1
- data/lib/shuttle/hook.rb +33 -0
- data/lib/shuttle/runner.rb +9 -3
- data/lib/shuttle/strategy.rb +8 -14
- data/lib/shuttle/version.rb +1 -1
- data/lib/shuttle.rb +2 -1
- data/spec/cli_spec.rb +150 -0
- data/spec/helpers_spec.rb +4 -0
- data/spec/path_helpers_spec.rb +50 -0
- data/spec/spec_helper.rb +4 -0
- metadata +8 -4
- data/lib/shuttle/config.rb +0 -5
- data/lib/shuttle/support/foreman.rb +0 -7
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
NjM4NmQ3ZGZhOTQwNGNmMzkxYzM4ZjNiZTM3MjUwMzNhMTY2NWFhZQ==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
NzYyNTBlODY1NmE2ZTNmYjFmZmM0MDY1MzU4NzQzM2UwZmY0N2JjZg==
|
7
7
|
!binary "U0hBNTEy":
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
N2IzN2ZiZTdlNzg4ZWUyMjgzM2Q3NWYzYjZjZjllYTBiOGEwZDJkMTExMjRj
|
10
|
+
MGZiN2NmY2FhZGQ3MmUzYmY5Y2RiN2ZlNDYzODM4NGQ2YTk0MjRjNjIyYjBh
|
11
|
+
YWI2YzljNzYwMDUzMjYwODg4ZGI1ZDhmOTIxNmU0NzJhZDAyMzE=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
OTA3YzJjNTc3NDZjYzQ0ZDg2ZmUwOWFjYzUyMTUzZGMwOTRlZDJiNTJiOTZk
|
14
|
+
Y2FkMzRmMmIxYmY4YTg0YmY1Yzk3ZWY0MzU4NWFiMzM2ZGIwY2UyYWUyMmM4
|
15
|
+
NjZhMTc0YTQ3M2ZhYTNiOTUwYzA3Yzg0MDYyZmM4NDQ1YWE2ZGU=
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Shuttle
|
1
|
+
# Shuttle ![Build Status](https://magnum-ci.com/status/dea40dc3b6055d6a628a444149e2fead.png)
|
2
2
|
|
3
3
|
Shuttle is a minimalistic application deployment tool designed for small applications
|
4
4
|
and one-server deployments. Configuration is stored as YAML-encoded file, no need to use ruby code.
|
@@ -88,7 +88,62 @@ target:
|
|
88
88
|
### WordPress Strategy
|
89
89
|
|
90
90
|
This strategy is designed to deploy wordpress sites developed as a separate theme.
|
91
|
-
It requires `subversion` installed on the server (will be automatically installed).
|
91
|
+
It requires `subversion` installed on the server (will be automatically installed).
|
92
|
+
|
93
|
+
Define strategy:
|
94
|
+
|
95
|
+
```
|
96
|
+
app:
|
97
|
+
strategy: wordpress
|
98
|
+
```
|
99
|
+
|
100
|
+
Wordpress applications are configured and deployed with `wp` cli utility. On a clean setup
|
101
|
+
shuttle will attempt to install wp-cli and wordpress core first. CLI is installed from
|
102
|
+
main github repository and latest stable tag. Wordpress core will install latest version.
|
103
|
+
To specify required versions, use wordpress section:
|
104
|
+
|
105
|
+
```
|
106
|
+
wordpress:
|
107
|
+
core: 3.5.1
|
108
|
+
cli: 0.9.1
|
109
|
+
```
|
110
|
+
|
111
|
+
Then, you'll need to define theme and wp related options:
|
112
|
+
|
113
|
+
```
|
114
|
+
wordpress:
|
115
|
+
theme: my-theme
|
116
|
+
site:
|
117
|
+
title: "Site Title"
|
118
|
+
url: "http://sample-site.com"
|
119
|
+
admin_name: "admin"
|
120
|
+
admin_email: "admin@admin.com"
|
121
|
+
admin_password: "password"
|
122
|
+
```
|
123
|
+
|
124
|
+
Database options:
|
125
|
+
|
126
|
+
```
|
127
|
+
wordpress:
|
128
|
+
mysql:
|
129
|
+
host: 127.0.0.1
|
130
|
+
user: mysql-user
|
131
|
+
password: mysql-password
|
132
|
+
database: mysql-database
|
133
|
+
```
|
134
|
+
|
135
|
+
You can also provide a list of required plugins:
|
136
|
+
|
137
|
+
```
|
138
|
+
wordpress:
|
139
|
+
plugins:
|
140
|
+
- acf
|
141
|
+
- acf: git://github.com/elliotcondon/acf.git
|
142
|
+
- acf: http://my-site.com/acf.zip
|
143
|
+
- acf: http://my-site.com/acf.tar.gz
|
144
|
+
```
|
145
|
+
|
146
|
+
For more detailed example, check `examples/wordpress.yml`
|
92
147
|
|
93
148
|
### Rails Strategy
|
94
149
|
|
data/bin/shuttle
CHANGED
@@ -4,57 +4,6 @@ lib = File.expand_path(File.dirname(__FILE__) + '/../lib')
|
|
4
4
|
$LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
|
5
5
|
|
6
6
|
require 'rubygems'
|
7
|
-
require 'optparse'
|
8
7
|
require 'shuttle'
|
9
8
|
|
10
|
-
|
11
|
-
|
12
|
-
options = {
|
13
|
-
:path => File.join(ENV['HOME'], '.shuttle', config_name),
|
14
|
-
:target => 'production',
|
15
|
-
:log => false
|
16
|
-
}
|
17
|
-
|
18
|
-
optparse = OptionParser.new do |opts|
|
19
|
-
opts.on('-v', '--version', 'Show version') do
|
20
|
-
puts "Shuttle version #{Shuttle::VERSION}"
|
21
|
-
exit 0
|
22
|
-
end
|
23
|
-
|
24
|
-
opts.on('-e', '--environment NAME', 'Deployment target environment') do |v|
|
25
|
-
options[:target] = v
|
26
|
-
end
|
27
|
-
|
28
|
-
opts.on('-d', '--debug', 'Enable debugging') do
|
29
|
-
options[:log] = true
|
30
|
-
end
|
31
|
-
|
32
|
-
opts.on('-f', '--file PATH', 'Configuration file path') do |v|
|
33
|
-
options[:path] = v
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
begin
|
38
|
-
optparse.parse!
|
39
|
-
rescue OptionParser::ParseError => e
|
40
|
-
puts "Error: #{e.message}"
|
41
|
-
exit 1
|
42
|
-
end
|
43
|
-
|
44
|
-
case ARGV.size
|
45
|
-
when 2
|
46
|
-
options[:target] = ARGV.shift
|
47
|
-
command = ARGV.shift
|
48
|
-
when 1
|
49
|
-
command = ARGV.shift
|
50
|
-
else
|
51
|
-
puts "Command required"
|
52
|
-
exit 1
|
53
|
-
end
|
54
|
-
|
55
|
-
begin
|
56
|
-
runner = Shuttle::Runner.new(options)
|
57
|
-
runner.execute(command.dup)
|
58
|
-
rescue Shuttle::ConfigError => err
|
59
|
-
puts "Error: #{err.message}."
|
60
|
-
end
|
9
|
+
Shuttle::CLI.new.run
|
data/examples/wordpress.yml
CHANGED
@@ -1,32 +1,47 @@
|
|
1
1
|
app:
|
2
|
+
# name of the app
|
2
3
|
name: sample-site
|
3
4
|
strategy: wordpress
|
5
|
+
# source repository containing your theme
|
4
6
|
git: git@github.com/username/sample-site.git
|
7
|
+
# svn: https://some-svn-repo.com/sample-site
|
5
8
|
branch: production
|
6
9
|
|
10
|
+
# Where to deploy
|
7
11
|
target:
|
12
|
+
# host name or ip
|
8
13
|
host: sample-site.com
|
14
|
+
# Credentials for user that'll run deploy
|
9
15
|
user: deployer
|
10
16
|
password: password
|
17
|
+
# Deploy path
|
11
18
|
deploy_to: /home/deployer/www
|
12
19
|
|
13
20
|
wordpress:
|
21
|
+
# Core version
|
14
22
|
core: 3.5.1
|
23
|
+
# wp-cli version. See wp-cli.org
|
15
24
|
cli: 0.9.1
|
16
|
-
theme
|
25
|
+
# Theme name for source repo, should match theme slug
|
26
|
+
theme: sample-site
|
27
|
+
# Basic WP settings
|
17
28
|
site:
|
18
29
|
title: "Site Title"
|
19
30
|
url: "http://sample-site.com"
|
20
31
|
admin_name: "admin"
|
21
32
|
admin_email: "admin@admin.com"
|
22
33
|
admin_password: "password"
|
34
|
+
# MySQL config
|
23
35
|
mysql:
|
24
36
|
host: 127.0.0.1
|
25
37
|
user: mysql-user
|
26
38
|
password: mysql-password
|
27
39
|
database: mysql-dadtabase
|
40
|
+
# Plugins that you need for the site
|
28
41
|
plugins:
|
42
|
+
# Grab a plugin from any git/svn repo
|
29
43
|
- advanced-custom-fields: git://github.com/elliotcondon/acf.git
|
44
|
+
# Install directly from wp plugins repo
|
30
45
|
- be-subpages-widget
|
31
46
|
- contact-form-7
|
32
47
|
- contact-form-7-to-database-extension
|
data/lib/shuttle/cli.rb
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
module Shuttle
|
4
|
+
class CLI
|
5
|
+
attr_reader :options, :command
|
6
|
+
attr_reader :path
|
7
|
+
|
8
|
+
def initialize(path=nil)
|
9
|
+
@path = File.expand_path(path || Dir.pwd)
|
10
|
+
@options = default_options
|
11
|
+
end
|
12
|
+
|
13
|
+
def run
|
14
|
+
parse_options
|
15
|
+
parse_command
|
16
|
+
find_config
|
17
|
+
|
18
|
+
begin
|
19
|
+
runner = Shuttle::Runner.new(@options)
|
20
|
+
runner.execute(@command.dup)
|
21
|
+
rescue Shuttle::ConfigError => err
|
22
|
+
terminate(err.message)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def terminate(message, status=1)
|
27
|
+
STDERR.puts(message)
|
28
|
+
exit(status)
|
29
|
+
end
|
30
|
+
|
31
|
+
def default_options
|
32
|
+
{
|
33
|
+
:path => nil,
|
34
|
+
:target => 'production',
|
35
|
+
:log => false
|
36
|
+
}
|
37
|
+
end
|
38
|
+
|
39
|
+
def parse_options
|
40
|
+
parser = OptionParser.new do |opts|
|
41
|
+
opts.on('-v', '--version', 'Show version') do
|
42
|
+
puts "Shuttle version #{Shuttle::VERSION}"
|
43
|
+
exit 0
|
44
|
+
end
|
45
|
+
|
46
|
+
opts.on('-e', '--environment NAME', 'Deployment target environment') do |v|
|
47
|
+
@options[:target] = v
|
48
|
+
end
|
49
|
+
|
50
|
+
opts.on('-d', '--debug', 'Enable debugging') do
|
51
|
+
@options[:log] = true
|
52
|
+
end
|
53
|
+
|
54
|
+
opts.on('-f', '--file PATH', 'Configuration file path') do |v|
|
55
|
+
@options[:path] = v
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
begin
|
60
|
+
parser.parse!
|
61
|
+
rescue OptionParser::ParseError => e
|
62
|
+
terminate(e.message)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def parse_command
|
67
|
+
case ARGV.size
|
68
|
+
when 0
|
69
|
+
terminate("Command required")
|
70
|
+
when 1
|
71
|
+
@command = ARGV.shift
|
72
|
+
when 2
|
73
|
+
@options[:target] = ARGV.shift
|
74
|
+
@command = ARGV.shift
|
75
|
+
else
|
76
|
+
terminate("Maximum of 2 arguments allowed")
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def find_config
|
81
|
+
lookup_files.each { |path| break if try_config(path) }
|
82
|
+
|
83
|
+
if @options[:path].nil?
|
84
|
+
terminate("Please provide config with -f option.")
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def try_config(path)
|
89
|
+
if File.exists?(path)
|
90
|
+
@options[:path] = path
|
91
|
+
true
|
92
|
+
else
|
93
|
+
false
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
private
|
98
|
+
|
99
|
+
def lookup_files
|
100
|
+
[
|
101
|
+
"#{@path}/shuttle.yml",
|
102
|
+
"#{@path}/config/deploy.yml",
|
103
|
+
"#{@path}/config/deploy/#{options[:target]}.yml",
|
104
|
+
"#{ENV['HOME']}/.shuttle/#{File.basename(Dir.pwd)}.yml"
|
105
|
+
]
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -10,6 +10,29 @@ module Shuttle
|
|
10
10
|
def cli_install
|
11
11
|
log "Installing WordPress CLI"
|
12
12
|
|
13
|
+
rev, tag = cli_checkout_code
|
14
|
+
|
15
|
+
res = ssh.run("cd #{CLI_PATH} && sudo utils/dev-build")
|
16
|
+
|
17
|
+
if res.failure?
|
18
|
+
error "Unable to build cli: #{res.output}"
|
19
|
+
end
|
20
|
+
|
21
|
+
if cli_installed?
|
22
|
+
log "WordPress CLI (#{tag}) installed"
|
23
|
+
else
|
24
|
+
error "Wordpress CLI installation failed"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Checkout a proper wp-cli revision. By default it'll install
|
29
|
+
# latest available tag from git. That's considered a stable version.
|
30
|
+
# To install latest code, set `cli` option in config:
|
31
|
+
#
|
32
|
+
# wordpress:
|
33
|
+
# cli: master
|
34
|
+
#
|
35
|
+
def cli_checkout_code
|
13
36
|
ssh.run("sudo git clone --recursive --quiet #{CLI_GIT} #{CLI_PATH}")
|
14
37
|
|
15
38
|
if config.wordpress.cli.nil?
|
@@ -17,17 +40,22 @@ module Shuttle
|
|
17
40
|
tag = tags.first
|
18
41
|
rev = ssh.capture("cd #{CLI_PATH} && git rev-parse #{tag}").strip
|
19
42
|
else
|
20
|
-
tag =
|
43
|
+
tag = config.wordpress.cli
|
44
|
+
|
45
|
+
if tag =~ /^[\d\.]+$/ # version def
|
46
|
+
tag = "v#{tag}" unless tag =~ /v[\d]+/
|
47
|
+
end
|
48
|
+
|
49
|
+
rev = tag
|
21
50
|
end
|
22
51
|
|
23
|
-
ssh.run("cd #{CLI_PATH} && sudo git checkout #{rev}")
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
log "WordPress CLI (#{tag}) installed"
|
28
|
-
else
|
29
|
-
error "Unable to install WordPress CLI"
|
52
|
+
res = ssh.run("cd #{CLI_PATH} && sudo git checkout #{rev}")
|
53
|
+
|
54
|
+
if res.failure?
|
55
|
+
error "Unable to checkout revision #{rev}: #{res.output}"
|
30
56
|
end
|
57
|
+
|
58
|
+
#rev, tag
|
31
59
|
end
|
32
60
|
|
33
61
|
def cli_uninstall
|
@@ -24,15 +24,20 @@ module Shuttle
|
|
24
24
|
cli_install
|
25
25
|
else
|
26
26
|
version = ssh.capture("cd #{core_path} && wp --version")
|
27
|
-
version.gsub!('wp-cli', '').strip!
|
27
|
+
version.gsub!('wp-cli', '').to_s.strip!
|
28
28
|
log "WordPress CLI version: #{version}"
|
29
29
|
end
|
30
30
|
|
31
31
|
if !core_installed?
|
32
32
|
core_install
|
33
33
|
else
|
34
|
-
|
35
|
-
|
34
|
+
res = ssh.run("cd #{core_path} && wp core version")
|
35
|
+
|
36
|
+
if res.success?
|
37
|
+
log "WordPress core version: #{res.output}"
|
38
|
+
else
|
39
|
+
error "Unable to detect WordPress core version: #{res.output}"
|
40
|
+
end
|
36
41
|
end
|
37
42
|
|
38
43
|
check_config
|
data/lib/shuttle/helpers.rb
CHANGED
data/lib/shuttle/hook.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
module Shuttle
|
2
|
+
class Hook
|
3
|
+
def initialize(deploy)
|
4
|
+
@deploy = deploy
|
5
|
+
end
|
6
|
+
|
7
|
+
def run(commands, allow_failures=false)
|
8
|
+
[commands].flatten.compact.uniq.each do |cmd|
|
9
|
+
execute(cmd, allow_failures)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def execute(cmd, allow_failures)
|
16
|
+
@deploy.log %{Executing "#{cmd.strip}"}
|
17
|
+
|
18
|
+
command = cmd
|
19
|
+
|
20
|
+
if @deploy.ssh.directory_exists?(@deploy.release_path)
|
21
|
+
command = "cd #{@deploy.release_path} && #{command}"
|
22
|
+
end
|
23
|
+
|
24
|
+
result = @deploy.ssh.run(command)
|
25
|
+
|
26
|
+
if result.failure? && allow_failures == false
|
27
|
+
@deploy.error("Failed: #{result.output}")
|
28
|
+
else
|
29
|
+
@deploy.stream_output(result.output)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/shuttle/runner.rb
CHANGED
@@ -18,7 +18,11 @@ module Shuttle
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def load_config
|
21
|
-
data = File.read(config_path)
|
21
|
+
data = File.read(config_path).strip
|
22
|
+
|
23
|
+
if data.empty?
|
24
|
+
raise ConfigError, "Configuration file is empty"
|
25
|
+
end
|
22
26
|
|
23
27
|
if config_path =~ /\.toml$/
|
24
28
|
parse_toml_data(data)
|
@@ -129,7 +133,9 @@ module Shuttle
|
|
129
133
|
exit_code = 1
|
130
134
|
rescue Exception => err
|
131
135
|
integration.cleanup_release
|
132
|
-
integration.log("ERROR: #{err.message}", 'error')
|
136
|
+
integration.log("Shuttle ERROR: #{err.message}", 'error')
|
137
|
+
integration.log(err.backtrace.join("\n"), 'error')
|
138
|
+
|
133
139
|
exit_code = 1
|
134
140
|
ensure
|
135
141
|
integration.release_lock
|
@@ -150,7 +156,7 @@ module Shuttle
|
|
150
156
|
|
151
157
|
ssh.close
|
152
158
|
rescue Net::SSH::AuthenticationFailed
|
153
|
-
STDERR.puts "Authentication failed"
|
159
|
+
STDERR.puts "SSH Authentication failed"
|
154
160
|
exit 1
|
155
161
|
end
|
156
162
|
end
|
data/lib/shuttle/strategy.rb
CHANGED
@@ -26,6 +26,8 @@ module Shuttle
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def rollback
|
29
|
+
execute_hook(:before_rollback)
|
30
|
+
|
29
31
|
if last_version == 0
|
30
32
|
error "There are no releases to rollback to"
|
31
33
|
end
|
@@ -41,11 +43,15 @@ module Shuttle
|
|
41
43
|
error "Unable to create symlink to current path"
|
42
44
|
end
|
43
45
|
|
44
|
-
ssh.run("echo #{
|
46
|
+
ssh.run("echo #{release} > #{version_path}")
|
47
|
+
ssh.run("rm -rf #{deploy_path}/releases/#{last_version}")
|
48
|
+
|
45
49
|
log "Rolled back to release v#{release}"
|
46
50
|
else
|
47
51
|
error "There are no older releases"
|
48
52
|
end
|
53
|
+
|
54
|
+
execute_hook(:after_rollback)
|
49
55
|
end
|
50
56
|
|
51
57
|
def update_code
|
@@ -270,19 +276,7 @@ module Shuttle
|
|
270
276
|
end
|
271
277
|
|
272
278
|
def execute_commands(commands=[], allow_failures=false)
|
273
|
-
|
274
|
-
log %{Executing "#{cmd.strip}"}
|
275
|
-
command = cmd
|
276
|
-
command = "cd #{release_path} && #{command}" if ssh.directory_exists?(release_path)
|
277
|
-
|
278
|
-
result = ssh.run(command)
|
279
|
-
|
280
|
-
if result.failure? && allow_failures == false
|
281
|
-
error "Failed: #{result.output}"
|
282
|
-
else
|
283
|
-
stream_output(result.output)
|
284
|
-
end
|
285
|
-
end
|
279
|
+
Shuttle::Hook.new(self).run(commands, allow_failures)
|
286
280
|
end
|
287
281
|
end
|
288
282
|
end
|
data/lib/shuttle/version.rb
CHANGED
data/lib/shuttle.rb
CHANGED
@@ -13,6 +13,7 @@ require 'shuttle/version'
|
|
13
13
|
require 'shuttle/errors'
|
14
14
|
|
15
15
|
module Shuttle
|
16
|
+
autoload :CLI, 'shuttle/cli'
|
16
17
|
autoload :Session, 'shuttle/session'
|
17
18
|
autoload :Runner, 'shuttle/runner'
|
18
19
|
autoload :Deploy, 'shuttle/deploy'
|
@@ -20,6 +21,7 @@ module Shuttle
|
|
20
21
|
autoload :Helpers, 'shuttle/helpers'
|
21
22
|
autoload :PathHelpers, 'shuttle/path_helpers'
|
22
23
|
autoload :Strategy, 'shuttle/strategy'
|
24
|
+
autoload :Hook, 'shuttle/hook'
|
23
25
|
|
24
26
|
autoload :Static, 'shuttle/deployment/static'
|
25
27
|
autoload :Php, 'shuttle/deployment/php'
|
@@ -30,7 +32,6 @@ module Shuttle
|
|
30
32
|
|
31
33
|
module Support
|
32
34
|
autoload :Bundler, 'shuttle/support/bundler'
|
33
|
-
autoload :Foreman, 'shuttle/support/foreman'
|
34
35
|
autoload :Thin, 'shuttle/support/thin'
|
35
36
|
end
|
36
37
|
end
|
data/spec/cli_spec.rb
ADDED
@@ -0,0 +1,150 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Shuttle::CLI do
|
4
|
+
let(:cli) { Shuttle::CLI.new }
|
5
|
+
|
6
|
+
describe '#initialize' do
|
7
|
+
it 'assigns current path' do
|
8
|
+
Dir.stub(:pwd).and_return('/home/user')
|
9
|
+
cli = Shuttle::CLI.new
|
10
|
+
expect(cli.path).to eq '/home/user'
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'assigns specified path' do
|
14
|
+
cli = Shuttle::CLI.new('/foo/bar')
|
15
|
+
expect(cli.path).to eq '/foo/bar'
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'assigns default options' do
|
19
|
+
cli = Shuttle::CLI.new
|
20
|
+
expect(cli.options).to be_a Hash
|
21
|
+
expect(cli.options).not_to be_empty
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '#default_options' do
|
26
|
+
let(:opts) { cli.default_options }
|
27
|
+
|
28
|
+
it 'returns a hash with default options' do
|
29
|
+
expect(opts).to be_a Hash
|
30
|
+
expect(opts[:path]).to eq nil
|
31
|
+
expect(opts[:target]).to eq 'production'
|
32
|
+
expect(opts[:log]).to eq false
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe '#parse_command' do
|
37
|
+
context 'with no arguments' do
|
38
|
+
before do
|
39
|
+
ARGV.stub(:size).and_return(0)
|
40
|
+
cli.should_receive(:terminate).with("Command required")
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'terminates execution with message' do
|
44
|
+
cli.parse_command
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context 'with 1 argument' do
|
49
|
+
before do
|
50
|
+
ARGV = %w(deploy)
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'sets command' do
|
54
|
+
cli.parse_command
|
55
|
+
expect(cli.command).to eq 'deploy'
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context 'with 2 arguments' do
|
60
|
+
before do
|
61
|
+
ARGV = %w(staging deploy)
|
62
|
+
cli.parse_command
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'assigns deployment target' do
|
66
|
+
expect(cli.options[:target]).to eq 'staging'
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'assigns command' do
|
70
|
+
expect(cli.command).to eq 'deploy'
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
context 'with too many arguments' do
|
75
|
+
before do
|
76
|
+
ARGV.stub(:size).and_return(3)
|
77
|
+
cli.should_receive(:terminate).with("Maximum of 2 arguments allowed")
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'terminates execution with message' do
|
81
|
+
cli.parse_command
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe '#try_config' do
|
87
|
+
it 'does not change path if file does not exist' do
|
88
|
+
File.stub(:exists?).and_return(false)
|
89
|
+
|
90
|
+
expect(cli.try_config('foo/bar')).to eq false
|
91
|
+
expect(cli.options[:path]).to eq nil
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'changes config path if file exists' do
|
95
|
+
File.stub(:exists?).with('foo/bar').and_return(true)
|
96
|
+
|
97
|
+
expect(cli.try_config('foo/bar')).to eq true
|
98
|
+
expect(cli.options[:path]).to eq 'foo/bar'
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
describe '#find_config' do
|
103
|
+
let(:path) { "/tmp" }
|
104
|
+
let(:cli) { Shuttle::CLI.new(path) }
|
105
|
+
|
106
|
+
it 'searches for ./shuttle.yml file' do
|
107
|
+
File.should_receive(:exists?).with("/tmp/shuttle.yml").and_return(true)
|
108
|
+
cli.find_config
|
109
|
+
expect(cli.options[:path]).to eq "/tmp/shuttle.yml"
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'searches for ./config/deploy.yml file' do
|
113
|
+
File.should_receive(:exists?).with("/tmp/shuttle.yml").and_return(false)
|
114
|
+
File.should_receive(:exists?).with("/tmp/config/deploy.yml").and_return(true)
|
115
|
+
|
116
|
+
cli.find_config
|
117
|
+
expect(cli.options[:path]).to eq "/tmp/config/deploy.yml"
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'searches for ./config/deploy/production.yml' do
|
121
|
+
File.should_receive(:exists?).with("/tmp/shuttle.yml").and_return(false)
|
122
|
+
File.should_receive(:exists?).with("/tmp/config/deploy.yml").and_return(false)
|
123
|
+
File.should_receive(:exists?).with("/tmp/config/deploy/production.yml").and_return(true)
|
124
|
+
|
125
|
+
cli.find_config
|
126
|
+
expect(cli.options[:path]).to eq "/tmp/config/deploy/production.yml"
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'searches foe ~/.shuttle/NAME.yml' do
|
130
|
+
ENV['HOME'] = "/tmp"
|
131
|
+
File.should_receive(:exists?).with("/tmp/shuttle.yml").and_return(false)
|
132
|
+
File.should_receive(:exists?).with("/tmp/config/deploy.yml").and_return(false)
|
133
|
+
File.should_receive(:exists?).with("/tmp/config/deploy/production.yml").and_return(false)
|
134
|
+
File.should_receive(:exists?).with("/tmp/.shuttle/shuttle.yml").and_return(true)
|
135
|
+
|
136
|
+
cli.find_config
|
137
|
+
expect(cli.options[:path]).to eq '/tmp/.shuttle/shuttle.yml'
|
138
|
+
end
|
139
|
+
|
140
|
+
it 'terminates if no config files found' do
|
141
|
+
ENV['HOME'] = "/tmp"
|
142
|
+
File.should_receive(:exists?).with("/tmp/shuttle.yml").and_return(false)
|
143
|
+
File.should_receive(:exists?).with("/tmp/config/deploy.yml").and_return(false)
|
144
|
+
File.should_receive(:exists?).with("/tmp/config/deploy/production.yml").and_return(false)
|
145
|
+
File.should_receive(:exists?).with("/tmp/.shuttle/shuttle.yml").and_return(false)
|
146
|
+
|
147
|
+
expect { cli.find_config }.to raise_error SystemExit
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
data/spec/helpers_spec.rb
CHANGED
@@ -19,8 +19,12 @@ describe Shuttle::Helpers do
|
|
19
19
|
end
|
20
20
|
|
21
21
|
describe '#error' do
|
22
|
+
before { subject.stub(:version).and_return(1) }
|
23
|
+
|
22
24
|
it 'prints an error message' do
|
23
25
|
STDOUT.should_receive(:puts).with("\e[1m\e[31m----->\e[0m ERROR: message")
|
26
|
+
STDOUT.should_receive(:puts).with("\e[1m\e[31m----->\e[0m Release v1 aborted")
|
27
|
+
|
24
28
|
expect { subject.error('message') }.to raise_error Shuttle::DeployError
|
25
29
|
end
|
26
30
|
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class Helpers ; include Shuttle::PathHelpers ; end
|
4
|
+
|
5
|
+
describe Shuttle::PathHelpers do
|
6
|
+
let(:target) do
|
7
|
+
Hashr.new(:deploy_to => '/tmp')
|
8
|
+
end
|
9
|
+
|
10
|
+
subject { Helpers.new }
|
11
|
+
before { subject.stub(:target).and_return(target) }
|
12
|
+
|
13
|
+
describe '#deploy_path' do
|
14
|
+
it 'returns application deployment path' do
|
15
|
+
expect(subject.deploy_path).to eq '/tmp'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe '#shared_path' do
|
20
|
+
it 'returns shared deployment path' do
|
21
|
+
expect(subject.shared_path).to eq '/tmp/shared'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '#release_path' do
|
26
|
+
before { subject.stub(:version).and_return(1) }
|
27
|
+
|
28
|
+
it 'returns current release path' do
|
29
|
+
expect(subject.release_path).to eq '/tmp/releases/1'
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe '#current_path' do
|
34
|
+
it 'returns current linked release path' do
|
35
|
+
expect(subject.current_path).to eq '/tmp/current'
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe '#version_path' do
|
40
|
+
it 'returns version file path' do
|
41
|
+
expect(subject.version_path).to eq '/tmp/version'
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe '#scm_path' do
|
46
|
+
it 'returns project repository path' do
|
47
|
+
expect(subject.scm_path).to eq '/tmp/scm'
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shuttle-deploy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.0.
|
4
|
+
version: 0.2.0.beta5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dan Sosedoff
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-06-
|
11
|
+
date: 2013-06-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -170,7 +170,7 @@ files:
|
|
170
170
|
- examples/static.yml
|
171
171
|
- examples/wordpress.yml
|
172
172
|
- lib/shuttle.rb
|
173
|
-
- lib/shuttle/
|
173
|
+
- lib/shuttle/cli.rb
|
174
174
|
- lib/shuttle/deploy.rb
|
175
175
|
- lib/shuttle/deployment/nodejs.rb
|
176
176
|
- lib/shuttle/deployment/php.rb
|
@@ -184,20 +184,22 @@ files:
|
|
184
184
|
- lib/shuttle/deployment/wordpress/vip.rb
|
185
185
|
- lib/shuttle/errors.rb
|
186
186
|
- lib/shuttle/helpers.rb
|
187
|
+
- lib/shuttle/hook.rb
|
187
188
|
- lib/shuttle/path_helpers.rb
|
188
189
|
- lib/shuttle/runner.rb
|
189
190
|
- lib/shuttle/session.rb
|
190
191
|
- lib/shuttle/strategy.rb
|
191
192
|
- lib/shuttle/support/bundler.rb
|
192
|
-
- lib/shuttle/support/foreman.rb
|
193
193
|
- lib/shuttle/support/thin.rb
|
194
194
|
- lib/shuttle/target.rb
|
195
195
|
- lib/shuttle/version.rb
|
196
196
|
- shuttle-deploy.gemspec
|
197
|
+
- spec/cli_spec.rb
|
197
198
|
- spec/deploy_spec.rb
|
198
199
|
- spec/fixtures/.gitkeep
|
199
200
|
- spec/fixtures/static.yml
|
200
201
|
- spec/helpers_spec.rb
|
202
|
+
- spec/path_helpers_spec.rb
|
201
203
|
- spec/spec_helper.rb
|
202
204
|
- spec/target_spec.rb
|
203
205
|
homepage: https://github.com/sosedoff/shuttle
|
@@ -224,10 +226,12 @@ signing_key:
|
|
224
226
|
specification_version: 4
|
225
227
|
summary: Minimalistic deployment tool
|
226
228
|
test_files:
|
229
|
+
- spec/cli_spec.rb
|
227
230
|
- spec/deploy_spec.rb
|
228
231
|
- spec/fixtures/.gitkeep
|
229
232
|
- spec/fixtures/static.yml
|
230
233
|
- spec/helpers_spec.rb
|
234
|
+
- spec/path_helpers_spec.rb
|
231
235
|
- spec/spec_helper.rb
|
232
236
|
- spec/target_spec.rb
|
233
237
|
has_rdoc:
|
data/lib/shuttle/config.rb
DELETED