shuttle-deploy 0.2.0.beta4 → 0.2.0.beta5
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 +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 
|
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