capistrano 3.8.2 → 3.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -0
- data/CHANGELOG.md +17 -1
- data/CONTRIBUTING.md +2 -0
- data/DEVELOPMENT.md +2 -3
- data/README.md +3 -1
- data/features/deploy.feature +18 -0
- data/features/step_definitions/assertions.rb +27 -1
- data/features/step_definitions/cap_commands.rb +6 -0
- data/features/step_definitions/setup.rb +31 -1
- data/features/support/remote_command_helpers.rb +4 -0
- data/features/support/vagrant_helpers.rb +9 -8
- data/lib/capistrano/dsl.rb +7 -1
- data/lib/capistrano/i18n.rb +1 -1
- data/lib/capistrano/tasks/deploy.rake +7 -5
- data/lib/capistrano/version.rb +1 -1
- data/spec/lib/capistrano/dsl_spec.rb +47 -6
- data/spec/support/test_app.rb +4 -4
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a4ae57e87cafad9fe7cb1307d847f5f3bd9d7ccb
|
4
|
+
data.tar.gz: e6ea828e10e6863b07c9fcd685a334464a3a3890
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 49fd63f868fdc87cefd58e047dc22c2b05cd95211a7a99080a010f627c3f32944539a16876ade7496257d4a8b71e18fc099a57ec126abf3f2efa7d2991d36c41
|
7
|
+
data.tar.gz: 35064cfd5c3da3a39e8ca044aa1eae03b8b0fbbea3c22a08fb08d5c2755b1fe18f7be8f2e7bccc431214d166f0d953e5c112d026b818a462105761528f3478cc
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -16,10 +16,26 @@ gem "capistrano", :github => "capistrano/capistrano"
|
|
16
16
|
|
17
17
|
## master
|
18
18
|
|
19
|
-
https://github.com/capistrano/capistrano/compare/v3.
|
19
|
+
https://github.com/capistrano/capistrano/compare/v3.9.0...HEAD
|
20
20
|
|
21
21
|
* Your contribution here!
|
22
22
|
|
23
|
+
## `3.9.0` (2017-07-28)
|
24
|
+
|
25
|
+
https://github.com/capistrano/capistrano/compare/v3.8.2...v3.9.0
|
26
|
+
|
27
|
+
### Breaking changes:
|
28
|
+
|
29
|
+
* None
|
30
|
+
|
31
|
+
### New features:
|
32
|
+
|
33
|
+
* [#1911](https://github.com/capistrano/capistrano/pull/1911): Add Capistrano::DSL#invoke! for repetetive tasks
|
34
|
+
|
35
|
+
### Fixes:
|
36
|
+
|
37
|
+
* [#1899](https://github.com/capistrano/capistrano/pull/1899): Updated `deploy:cleanup` to continue rotating the releases and skip the invalid directory names instead of skipping the whole rotation of releases. The warning message has changed slightly due to the change of behavior.
|
38
|
+
|
23
39
|
## `3.8.2` (2017-06-16)
|
24
40
|
|
25
41
|
https://github.com/capistrano/capistrano/compare/v3.8.1...v3.8.2
|
data/CONTRIBUTING.md
CHANGED
@@ -41,6 +41,8 @@ Also include in your report:
|
|
41
41
|
|
42
42
|
If you are an experienced Ruby programmer, take a few minutes to get the Capistrano test suite running (see [DEVELOPMENT.md][]), and do what you can to get a test case written that fails. *This will be a huge help!*
|
43
43
|
|
44
|
+
If you think you may have discovered a security vulnerability in Capistrano, do not open a GitHub issue. Instead, please send a report to <security@capistranorb.com>.
|
45
|
+
|
44
46
|
## Requesting new features or improvements
|
45
47
|
|
46
48
|
Capistrano continues to improve thanks to people like you! Feel free to open a GitHub issue for any or all of these ideas:
|
data/DEVELOPMENT.md
CHANGED
@@ -28,11 +28,10 @@ Capistrano is a Ruby project, so we expect you to have a functioning Ruby enviro
|
|
28
28
|
|
29
29
|
Make sure to install:
|
30
30
|
|
31
|
-
* [Bundler](https://bundler.io/)
|
31
|
+
* [Bundler](https://bundler.io/)
|
32
32
|
* [Vagrant](https://www.vagrantup.com/)
|
33
33
|
* [VirtualBox](https://www.virtualbox.org/wiki/Downloads) (or another [Vagrant-supported](https://docs.vagrantup.com/v2/getting-started/providers.html) VM host)
|
34
34
|
|
35
|
-
*Note: As of this writing (December 2015), Vagrant does not work with Bundler > 1.10.5. If you have multiple versions of Bundler installed, use the special underscore command-line argument to force a compatible version, like this: `bundle _1.10.5_ exec rake features`.*
|
36
35
|
|
37
36
|
### Running tests
|
38
37
|
|
@@ -45,7 +44,7 @@ $ bundle install
|
|
45
44
|
# Run the RSpec suite
|
46
45
|
$ bundle exec rake spec
|
47
46
|
|
48
|
-
# Run the Cucumber suite
|
47
|
+
# Run the Cucumber suite
|
49
48
|
$ bundle exec rake features
|
50
49
|
|
51
50
|
# Run the Cucumber suite and leave the VM running (faster for subsequent runs)
|
data/README.md
CHANGED
@@ -103,7 +103,7 @@ Add Capistrano to your project's Gemfile:
|
|
103
103
|
|
104
104
|
``` ruby
|
105
105
|
group :development do
|
106
|
-
gem "capistrano", "~> 3.
|
106
|
+
gem "capistrano", "~> 3.9"
|
107
107
|
end
|
108
108
|
```
|
109
109
|
|
@@ -186,6 +186,8 @@ Related GitHub repositories:
|
|
186
186
|
|
187
187
|
GitHub issues are for bug reports and feature requests. Please refer to the [CONTRIBUTING](CONTRIBUTING.md) document for guidelines on submitting GitHub issues.
|
188
188
|
|
189
|
+
If you think you may have discovered a security vulnerability in Capistrano, do not open a GitHub issue. Instead, please send a report to <security@capistranorb.com>.
|
190
|
+
|
189
191
|
## How to contribute
|
190
192
|
|
191
193
|
Contributions to Capistrano, in the form of code, documentation or idea, are gladly accepted. Read the [DEVELOPMENT](DEVELOPMENT.md) document to learn how to hack on Capistrano's code, run the tests, and contribute your first pull request.
|
data/features/deploy.feature
CHANGED
@@ -52,3 +52,21 @@ Feature: Deploy
|
|
52
52
|
When I run cap "deploy:symlink:release"
|
53
53
|
Then the current directory will be a symlink to the release
|
54
54
|
|
55
|
+
Scenario: Cleanup
|
56
|
+
Given config stage file has line "set :keep_releases, 3"
|
57
|
+
And 5 valid existing releases
|
58
|
+
And an invalid release named "new"
|
59
|
+
When I run cap "deploy:cleanup"
|
60
|
+
Then 3 valid releases are kept
|
61
|
+
And the invalid "new" release is ignored
|
62
|
+
|
63
|
+
Scenario: Rolling Back
|
64
|
+
Given I make 2 deployments
|
65
|
+
When I run cap "deploy:rollback"
|
66
|
+
Then the current symlink points to the previous release
|
67
|
+
|
68
|
+
Scenario: Rolling Back to a specific release
|
69
|
+
Given I make 3 deployments
|
70
|
+
When I rollback to a specific release
|
71
|
+
Then the current symlink points to that specific release
|
72
|
+
|
@@ -6,7 +6,9 @@ end
|
|
6
6
|
|
7
7
|
Then(/^git wrapper permissions are 0700$/) do
|
8
8
|
permissions_test = %Q([ $(stat -c "%a" #{TestApp.git_wrapper_path.shellescape}) == "700" ])
|
9
|
-
|
9
|
+
_stdout, _stderr, status = vagrant_cli_command("ssh -c #{permissions_test.shellescape}")
|
10
|
+
|
11
|
+
expect(status).to be_success
|
10
12
|
end
|
11
13
|
|
12
14
|
Then(/^the shared path is created$/) do
|
@@ -17,6 +19,18 @@ Then(/^the releases path is created$/) do
|
|
17
19
|
run_vagrant_command(test_dir_exists(TestApp.releases_path))
|
18
20
|
end
|
19
21
|
|
22
|
+
Then(/^(\d+) valid releases are kept/) do |num|
|
23
|
+
test = %Q([ $(ls -g #{TestApp.releases_path} | grep -E '[0-9]{14}' | wc -l) == "#{num}" ])
|
24
|
+
_, _, status = vagrant_cli_command("ssh -c #{test.shellescape}")
|
25
|
+
expect(status).to be_success
|
26
|
+
end
|
27
|
+
|
28
|
+
Then(/^the invalid (.+) release is ignored$/) do |filename|
|
29
|
+
test = "ls -g #{TestApp.releases_path} | grep #{filename}"
|
30
|
+
_, _, status = vagrant_cli_command("ssh -c #{test.shellescape}")
|
31
|
+
expect(status).to be_success
|
32
|
+
end
|
33
|
+
|
20
34
|
Then(/^directories in :linked_dirs are created in shared$/) do
|
21
35
|
TestApp.linked_dirs.each do |dir|
|
22
36
|
run_vagrant_command(test_dir_exists(TestApp.shared_path.join(dir)))
|
@@ -124,3 +138,15 @@ end
|
|
124
138
|
Then(/doesn't contain "([^"]*)" in the output/) do |expected|
|
125
139
|
expect(@output).not_to include(expected)
|
126
140
|
end
|
141
|
+
|
142
|
+
Then(/the current symlink points to the previous release/) do
|
143
|
+
previous_release_path = @release_paths[-2]
|
144
|
+
|
145
|
+
run_vagrant_command(symlinked?(TestApp.current_path, previous_release_path))
|
146
|
+
end
|
147
|
+
|
148
|
+
Then(/^the current symlink points to that specific release$/) do
|
149
|
+
specific_release_path = TestApp.releases_path.join(@rollback_release)
|
150
|
+
|
151
|
+
run_vagrant_command(symlinked?(TestApp.current_path, specific_release_path))
|
152
|
+
end
|
@@ -13,3 +13,9 @@ end
|
|
13
13
|
When(/^I run "(.*?)"$/) do |command|
|
14
14
|
@success, @output = TestApp.run(command)
|
15
15
|
end
|
16
|
+
|
17
|
+
When(/^I rollback to a specific release$/) do
|
18
|
+
@rollback_release = @release_paths.first.split("/").last
|
19
|
+
|
20
|
+
step %Q{I run cap "deploy:rollback ROLLBACK_RELEASE=#{@rollback_release}"}
|
21
|
+
end
|
@@ -21,10 +21,16 @@ end
|
|
21
21
|
|
22
22
|
Given(/^file "(.*?)" exists in shared path$/) do |file|
|
23
23
|
file_shared_path = TestApp.shared_path.join(file)
|
24
|
-
run_vagrant_command("mkdir -p #{
|
24
|
+
run_vagrant_command("mkdir -p #{file_shared_path.dirname}")
|
25
25
|
run_vagrant_command("touch #{file_shared_path}")
|
26
26
|
end
|
27
27
|
|
28
|
+
Given(/^all linked files exists in shared path$/) do
|
29
|
+
TestApp.linked_files.each do |linked_file|
|
30
|
+
step %Q{file "#{linked_file}" exists in shared path}
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
28
34
|
Given(/^file "(.*?)" does not exist in shared path$/) do |file|
|
29
35
|
file_shared_path = TestApp.shared_path.join(file)
|
30
36
|
run_vagrant_command("mkdir -p #{TestApp.shared_path}")
|
@@ -60,3 +66,27 @@ end
|
|
60
66
|
Given(/^a stage file named (.+)$/) do |filename|
|
61
67
|
TestApp.write_local_stage_file(filename)
|
62
68
|
end
|
69
|
+
|
70
|
+
Given(/^I make (\d+) deployments$/) do |count|
|
71
|
+
step "all linked files exists in shared path"
|
72
|
+
|
73
|
+
@release_paths = (1..count.to_i).map do
|
74
|
+
TestApp.cap("deploy")
|
75
|
+
stdout, _stderr = run_vagrant_command("readlink #{TestApp.current_path}")
|
76
|
+
|
77
|
+
stdout.strip
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
Given(/^(\d+) valid existing releases$/) do |num|
|
82
|
+
a_day = 86_400 # in seconds
|
83
|
+
offset = -(a_day * num.to_i)
|
84
|
+
num.to_i.times do
|
85
|
+
run_vagrant_command("mkdir -p #{TestApp.release_path(TestApp.timestamp(offset))}")
|
86
|
+
offset += a_day
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
Given(/^an invalid release named "(.+)"$/) do |filename|
|
91
|
+
run_vagrant_command("mkdir -p #{TestApp.release_path(filename)}")
|
92
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require "
|
1
|
+
require "open3"
|
2
2
|
|
3
3
|
module VagrantHelpers
|
4
4
|
extend self
|
@@ -16,17 +16,18 @@ module VagrantHelpers
|
|
16
16
|
|
17
17
|
def vagrant_cli_command(command)
|
18
18
|
puts "[vagrant] #{command}"
|
19
|
-
Dir.chdir(VAGRANT_ROOT) do
|
20
|
-
|
21
|
-
puts "[vagrant] #{line}"
|
22
|
-
end
|
19
|
+
stdout, stderr, status = Dir.chdir(VAGRANT_ROOT) do
|
20
|
+
Open3.capture3("#{VAGRANT_BIN} #{command}")
|
23
21
|
end
|
24
|
-
|
22
|
+
|
23
|
+
(stdout + stderr).each_line { |line| puts "[vagrant] #{line}" }
|
24
|
+
|
25
|
+
[stdout, stderr, status]
|
25
26
|
end
|
26
27
|
|
27
28
|
def run_vagrant_command(command)
|
28
|
-
status = vagrant_cli_command("ssh -c #{command.inspect}")
|
29
|
-
return
|
29
|
+
stdout, stderr, status = vagrant_cli_command("ssh -c #{command.inspect}")
|
30
|
+
return [stdout, stderr] if status.success?
|
30
31
|
raise VagrantSSHCommandError, status
|
31
32
|
end
|
32
33
|
end
|
data/lib/capistrano/dsl.rb
CHANGED
@@ -19,13 +19,19 @@ module Capistrano
|
|
19
19
|
colors = SSHKit::Color.new($stderr)
|
20
20
|
$stderr.puts colors.colorize("Skipping task `#{task_name}'.", :yellow)
|
21
21
|
$stderr.puts "Capistrano tasks may only be invoked once. Since task `#{task}' was previously invoked, invoke(\"#{task_name}\") at #{file}:#{line} will be skipped."
|
22
|
-
$stderr.puts "If you really meant to run this task again,
|
22
|
+
$stderr.puts "If you really meant to run this task again, use invoke!(\"#{task_name}\")"
|
23
23
|
$stderr.puts colors.colorize("THIS BEHAVIOR MAY CHANGE IN A FUTURE VERSION OF CAPISTRANO. Please join the conversation here if this affects you.", :red)
|
24
24
|
$stderr.puts colors.colorize("https://github.com/capistrano/capistrano/issues/1686", :red)
|
25
25
|
end
|
26
26
|
task.invoke(*args)
|
27
27
|
end
|
28
28
|
|
29
|
+
def invoke!(task_name, *args)
|
30
|
+
task = Rake::Task[task_name]
|
31
|
+
task.reenable
|
32
|
+
task.invoke(*args)
|
33
|
+
end
|
34
|
+
|
29
35
|
def t(key, options={})
|
30
36
|
I18n.t(key, options.merge(scope: :capistrano))
|
31
37
|
end
|
data/lib/capistrano/i18n.rb
CHANGED
@@ -13,7 +13,7 @@ en = {
|
|
13
13
|
question: "Please enter %{key}: ",
|
14
14
|
question_default: "Please enter %{key} (%{default_value}): ",
|
15
15
|
keeping_releases: "Keeping %{keep_releases} of %{releases} deployed releases on %{host}",
|
16
|
-
skip_cleanup: "Skipping cleanup of
|
16
|
+
skip_cleanup: "Skipping cleanup of invalid releases on %{host}; unexpected foldername found (should be timestamp)",
|
17
17
|
no_old_releases: "No old releases (keeping newest %{keep_releases}) on %{host}",
|
18
18
|
linked_file_does_not_exist: "linked file %{file} does not exist on %{host}",
|
19
19
|
cannot_rollback: "There are no older releases to rollback to",
|
@@ -149,11 +149,13 @@ namespace :deploy do
|
|
149
149
|
task :cleanup do
|
150
150
|
on release_roles :all do |host|
|
151
151
|
releases = capture(:ls, "-x", releases_path).split
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
152
|
+
valid, invalid = releases.partition { |e| /^\d{14}$/ =~ e }
|
153
|
+
|
154
|
+
warn t(:skip_cleanup, host: host.to_s) if invalid.any?
|
155
|
+
|
156
|
+
if valid.count >= fetch(:keep_releases)
|
157
|
+
info t(:keeping_releases, host: host.to_s, keep_releases: fetch(:keep_releases), releases: valid.count)
|
158
|
+
directories = (valid - valid.last(fetch(:keep_releases)))
|
157
159
|
if directories.any?
|
158
160
|
directories_str = directories.map do |release|
|
159
161
|
releases_path.join(release)
|
data/lib/capistrano/version.rb
CHANGED
@@ -71,13 +71,54 @@ module Capistrano
|
|
71
71
|
end
|
72
72
|
|
73
73
|
describe "#invoke" do
|
74
|
-
|
75
|
-
|
74
|
+
context "reinvoking" do
|
75
|
+
it "will not reenable invoking task" do
|
76
|
+
counter = 0
|
76
77
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
78
|
+
Rake::Task.define_task("A") do
|
79
|
+
counter += 1
|
80
|
+
end
|
81
|
+
|
82
|
+
expect do
|
83
|
+
dsl.invoke("A")
|
84
|
+
dsl.invoke("A")
|
85
|
+
end.to change { counter }.by(1)
|
86
|
+
end
|
87
|
+
|
88
|
+
it "will print a message on stderr" do
|
89
|
+
Rake::Task.define_task("B")
|
90
|
+
|
91
|
+
expect do
|
92
|
+
dsl.invoke("B")
|
93
|
+
dsl.invoke("B")
|
94
|
+
end.to output(/If you really meant to run this task again, use invoke!/).to_stderr
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
describe "#invoke!" do
|
100
|
+
context "reinvoking" do
|
101
|
+
it "will reenable invoking task" do
|
102
|
+
counter = 0
|
103
|
+
|
104
|
+
Rake::Task.define_task("C") do
|
105
|
+
counter += 1
|
106
|
+
end
|
107
|
+
|
108
|
+
expect do
|
109
|
+
dsl.invoke!("C")
|
110
|
+
dsl.invoke!("C")
|
111
|
+
end.to change { counter }.by(2)
|
112
|
+
end
|
113
|
+
|
114
|
+
it "will not print a message on stderr" do
|
115
|
+
Rake::Task.define_task("D")
|
116
|
+
|
117
|
+
expect do
|
118
|
+
dsl.invoke!("D")
|
119
|
+
dsl.invoke!("D")
|
120
|
+
end.to_not output(/If you really meant to run this task again, use invoke!/).to_stderr
|
121
|
+
end
|
81
122
|
end
|
82
123
|
end
|
83
124
|
end
|
data/spec/support/test_app.rb
CHANGED
@@ -132,12 +132,12 @@ module TestApp
|
|
132
132
|
deploy_to.join("releases")
|
133
133
|
end
|
134
134
|
|
135
|
-
def release_path
|
136
|
-
releases_path.join(
|
135
|
+
def release_path(t=timestamp)
|
136
|
+
releases_path.join(t)
|
137
137
|
end
|
138
138
|
|
139
|
-
def timestamp
|
140
|
-
Time.now.utc.strftime("%Y%m%d%H%M%S")
|
139
|
+
def timestamp(offset=0)
|
140
|
+
(Time.now.utc + offset).strftime("%Y%m%d%H%M%S")
|
141
141
|
end
|
142
142
|
|
143
143
|
def repo_path
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: capistrano
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tom Clements
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2017-
|
12
|
+
date: 2017-07-28 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: airbrussh
|
@@ -285,7 +285,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
285
285
|
version: '0'
|
286
286
|
requirements: []
|
287
287
|
rubyforge_project:
|
288
|
-
rubygems_version: 2.6.
|
288
|
+
rubygems_version: 2.6.12
|
289
289
|
signing_key:
|
290
290
|
specification_version: 4
|
291
291
|
summary: Capistrano - Welcome to easy deployment with Ruby over SSH
|