capistrano 3.7.0 → 3.17.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.circleci/config.yml +113 -0
- data/.github/pull_request_template.md +0 -4
- data/.github/release-drafter.yml +17 -0
- data/.github/workflows/push.yml +12 -0
- data/.rubocop.yml +13 -0
- data/CHANGELOG.md +1 -484
- data/CONTRIBUTING.md +2 -0
- data/DEVELOPMENT.md +5 -6
- data/Dangerfile +1 -54
- data/Gemfile +39 -3
- data/LICENSE.txt +1 -1
- data/README.md +10 -4
- data/RELEASING.md +3 -3
- data/Rakefile +13 -5
- data/UPGRADING-3.7.md +1 -12
- data/capistrano.gemspec +9 -8
- data/features/deploy.feature +34 -1
- data/features/installation.feature +8 -3
- data/features/step_definitions/assertions.rb +31 -3
- data/features/step_definitions/cap_commands.rb +10 -0
- data/features/step_definitions/setup.rb +37 -1
- data/features/subdirectory.feature +9 -0
- data/features/support/remote_command_helpers.rb +4 -0
- data/features/support/vagrant_helpers.rb +15 -8
- data/lib/Capfile +0 -4
- data/lib/capistrano/application.rb +11 -3
- data/lib/capistrano/configuration/filter.rb +1 -1
- data/lib/capistrano/configuration/host_filter.rb +1 -2
- data/lib/capistrano/configuration/question.rb +22 -3
- data/lib/capistrano/configuration/role_filter.rb +1 -2
- data/lib/capistrano/configuration/scm_resolver.rb +8 -3
- data/lib/capistrano/configuration/server.rb +1 -0
- data/lib/capistrano/configuration/servers.rb +16 -8
- data/lib/capistrano/configuration/variables.rb +2 -2
- data/lib/capistrano/configuration.rb +7 -3
- data/lib/capistrano/defaults.rb +1 -1
- data/lib/capistrano/doctor/servers_doctor.rb +1 -1
- data/lib/capistrano/doctor/variables_doctor.rb +12 -3
- data/lib/capistrano/dsl/paths.rb +3 -16
- data/lib/capistrano/dsl.rb +10 -2
- data/lib/capistrano/i18n.rb +7 -2
- data/lib/capistrano/immutable_task.rb +3 -2
- data/lib/capistrano/scm/git.rb +34 -7
- data/lib/capistrano/scm/hg.rb +8 -1
- data/lib/capistrano/scm/svn.rb +9 -0
- data/lib/capistrano/scm/tasks/git.rake +10 -9
- data/lib/capistrano/scm/tasks/hg.rake +1 -1
- data/lib/capistrano/tasks/deploy.rake +22 -10
- data/lib/capistrano/templates/deploy.rb.erb +10 -4
- data/lib/capistrano/templates/stage.rb.erb +1 -1
- data/lib/capistrano/version.rb +1 -1
- data/spec/integration/dsl_spec.rb +5 -3
- data/spec/lib/capistrano/application_spec.rb +16 -40
- data/spec/lib/capistrano/configuration/filter_spec.rb +1 -1
- data/spec/lib/capistrano/configuration/host_filter_spec.rb +10 -5
- data/spec/lib/capistrano/configuration/plugin_installer_spec.rb +1 -1
- data/spec/lib/capistrano/configuration/question_spec.rb +47 -11
- data/spec/lib/capistrano/configuration/role_filter_spec.rb +2 -2
- data/spec/lib/capistrano/configuration/scm_resolver_spec.rb +55 -0
- data/spec/lib/capistrano/configuration/server_spec.rb +1 -1
- data/spec/lib/capistrano/configuration/servers_spec.rb +6 -5
- data/spec/lib/capistrano/configuration_spec.rb +2 -2
- data/spec/lib/capistrano/doctor/environment_doctor_spec.rb +1 -1
- data/spec/lib/capistrano/doctor/gems_doctor_spec.rb +1 -1
- data/spec/lib/capistrano/doctor/servers_doctor_spec.rb +1 -1
- data/spec/lib/capistrano/doctor/variables_doctor_spec.rb +9 -1
- data/spec/lib/capistrano/dsl/paths_spec.rb +30 -0
- data/spec/lib/capistrano/dsl/task_enhancements_spec.rb +6 -6
- data/spec/lib/capistrano/dsl_spec.rb +48 -7
- data/spec/lib/capistrano/immutable_task_spec.rb +1 -1
- data/spec/lib/capistrano/plugin_spec.rb +2 -2
- data/spec/lib/capistrano/scm/git_spec.rb +54 -1
- data/spec/lib/capistrano/scm/hg_spec.rb +6 -1
- data/spec/lib/capistrano/scm/svn_spec.rb +21 -0
- data/spec/lib/capistrano/version_validator_spec.rb +23 -0
- data/spec/spec_helper.rb +13 -0
- data/spec/support/Vagrantfile +1 -1
- data/spec/support/test_app.rb +28 -14
- metadata +20 -80
- data/.travis.yml +0 -26
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)
|
@@ -54,7 +53,7 @@ $ bundle exec rake features KEEP_RUNNING=1
|
|
54
53
|
|
55
54
|
### Report failing Cucumber features!
|
56
55
|
|
57
|
-
Currently, the Capistrano
|
56
|
+
Currently, the Capistrano CI build does *not* run the Cucumber suite. This means it is possible for a failing Cucumber feature to sneak in without being noticed by our continuous integration checks.
|
58
57
|
|
59
58
|
**If you come across a failing Cucumber feature, this is a bug.** Please report it by opening a GitHub issue. Or even better: do your best to fix the feature and submit a pull request!
|
60
59
|
|
@@ -64,7 +63,7 @@ This project uses [RuboCop](https://github.com/bbatsov/rubocop) to enforce stand
|
|
64
63
|
|
65
64
|
* Test that your contributions pass with `rake rubocop`
|
66
65
|
* Rubocop is also run as part of the full test suite with `rake`
|
67
|
-
* Note the
|
66
|
+
* Note the CI build will fail and your PR cannot be merged if Rubocop finds errors
|
68
67
|
|
69
68
|
## Submitting a pull request
|
70
69
|
|
@@ -72,7 +71,7 @@ Pull requests are awesome, and if they arrive with decent tests, and conform to
|
|
72
71
|
|
73
72
|
Your code should conform to these guidelines:
|
74
73
|
|
75
|
-
* The code is MIT
|
74
|
+
* The code is MIT licensed, your code will fall under the same license if we merge it.
|
76
75
|
* We can't merge it without a [good commit message](http://robots.thoughtbot.com/5-useful-tips-for-a-better-commit-message). If you do this right, Github will use the commit message as the body of your pull request, double win.
|
77
76
|
* If you are making an improvement/fix for an existing issue, make sure to mention the issue number (if we have not yet merged it )
|
78
77
|
* Add an entry to the `CHANGELOG` under the `### master` section, but please don't mess with the version.
|
data/Dangerfile
CHANGED
@@ -1,54 +1 @@
|
|
1
|
-
|
2
|
-
# Q: What is a Dangerfile, anyway? A: See http://danger.systems/
|
3
|
-
|
4
|
-
# ------------------------------------------------------------------------------
|
5
|
-
# Additional pull request data
|
6
|
-
# ------------------------------------------------------------------------------
|
7
|
-
project_name = github.pr_json["base"]["repo"]["name"]
|
8
|
-
pr_number = github.pr_json["number"]
|
9
|
-
pr_url = github.pr_json["_links"]["html"]["href"]
|
10
|
-
|
11
|
-
# ------------------------------------------------------------------------------
|
12
|
-
# What changed?
|
13
|
-
# ------------------------------------------------------------------------------
|
14
|
-
has_lib_changes = !git.modified_files.grep(/^lib/).empty?
|
15
|
-
has_test_changes = !git.modified_files.grep(/^(features|spec)/).empty?
|
16
|
-
has_changelog_changes = git.modified_files.include?("CHANGELOG.md")
|
17
|
-
|
18
|
-
# ------------------------------------------------------------------------------
|
19
|
-
# You've made changes to lib, but didn't write any tests?
|
20
|
-
# ------------------------------------------------------------------------------
|
21
|
-
if has_lib_changes && !has_test_changes
|
22
|
-
warn("There are code changes, but no corresponding tests. "\
|
23
|
-
"Please include tests if this PR introduces any modifications in "\
|
24
|
-
"#{project_name}'s behavior.",
|
25
|
-
:sticky => false)
|
26
|
-
end
|
27
|
-
|
28
|
-
# ------------------------------------------------------------------------------
|
29
|
-
# Have you updated CHANGELOG.md?
|
30
|
-
# ------------------------------------------------------------------------------
|
31
|
-
if !has_changelog_changes && has_lib_changes
|
32
|
-
markdown <<-MARKDOWN
|
33
|
-
Here's an example of a CHANGELOG.md entry (place it immediately under the `* Your contribution here!` line):
|
34
|
-
|
35
|
-
```markdown
|
36
|
-
* [##{pr_number}](#{pr_url}): #{github.pr_title} - [@#{github.pr_author}](https://github.com/#{github.pr_author}).
|
37
|
-
```
|
38
|
-
MARKDOWN
|
39
|
-
warn("Please update CHANGELOG.md with a description of your changes. "\
|
40
|
-
"If this PR is not a user-facing change (e.g. just refactoring), "\
|
41
|
-
"you can disregard this.", :sticky => false)
|
42
|
-
end
|
43
|
-
|
44
|
-
# ------------------------------------------------------------------------------
|
45
|
-
# Did you remove the CHANGELOG's "Your contribution here!" line?
|
46
|
-
# ------------------------------------------------------------------------------
|
47
|
-
if has_changelog_changes
|
48
|
-
unless IO.read("CHANGELOG.md") =~ /^\* Your contribution here/i
|
49
|
-
fail(
|
50
|
-
"Please put the `* Your contribution here!` line back into CHANGELOG.md.",
|
51
|
-
:sticky => false
|
52
|
-
)
|
53
|
-
end
|
54
|
-
end
|
1
|
+
danger.import_dangerfile(github: "capistrano/danger", branch: "no-changelog")
|
data/Gemfile
CHANGED
@@ -3,8 +3,44 @@ source "https://rubygems.org"
|
|
3
3
|
# Specify your gem's dependencies in capistrano.gemspec
|
4
4
|
gemspec
|
5
5
|
|
6
|
+
gem "mocha"
|
7
|
+
gem "rspec"
|
8
|
+
gem "rspec-core", "~> 3.4.4"
|
9
|
+
|
6
10
|
group :cucumber do
|
7
|
-
|
8
|
-
|
9
|
-
|
11
|
+
# Latest versions of cucumber don't support Ruby < 2.1
|
12
|
+
# rubocop:disable Bundler/DuplicatedGem
|
13
|
+
if Gem::Requirement.new("< 2.1").satisfied_by?(Gem::Version.new(RUBY_VERSION))
|
14
|
+
gem "cucumber", "< 3.0.1"
|
15
|
+
else
|
16
|
+
gem "cucumber"
|
17
|
+
end
|
18
|
+
# rubocop:enable Bundler/DuplicatedGem
|
19
|
+
end
|
20
|
+
|
21
|
+
# Latest versions of net-ssh don't support Ruby < 2.2.6
|
22
|
+
if Gem::Requirement.new("< 2.2.6").satisfied_by?(Gem::Version.new(RUBY_VERSION))
|
23
|
+
gem "net-ssh", "< 5.0.0"
|
24
|
+
end
|
25
|
+
|
26
|
+
# Latest versions of public_suffix don't support Ruby < 2.1
|
27
|
+
if Gem::Requirement.new("< 2.1").satisfied_by?(Gem::Version.new(RUBY_VERSION))
|
28
|
+
gem "public_suffix", "< 3.0.0"
|
29
|
+
end
|
30
|
+
|
31
|
+
# Latest versions of i18n don't support Ruby < 2.4
|
32
|
+
if Gem::Requirement.new("< 2.4").satisfied_by?(Gem::Version.new(RUBY_VERSION))
|
33
|
+
gem "i18n", "< 1.3.0"
|
34
|
+
end
|
35
|
+
|
36
|
+
# Latest versions of rake don't support Ruby < 2.2
|
37
|
+
if Gem::Requirement.new("< 2.2").satisfied_by?(Gem::Version.new(RUBY_VERSION))
|
38
|
+
gem "rake", "< 13.0.0"
|
39
|
+
end
|
40
|
+
|
41
|
+
# We only run danger and rubocop on a new-ish ruby; no need to install them otherwise
|
42
|
+
if Gem::Requirement.new("> 2.4").satisfied_by?(Gem::Version.new(RUBY_VERSION))
|
43
|
+
gem "danger"
|
44
|
+
gem "psych", "< 4" # Ensures rubocop works on Ruby 3.1
|
45
|
+
gem "rubocop", "0.48.1"
|
10
46
|
end
|
data/LICENSE.txt
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
MIT License (MIT)
|
2
2
|
|
3
|
-
Copyright (c) 2012-
|
3
|
+
Copyright (c) 2012-2020 Tom Clements, Lee Hambley
|
4
4
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
data/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
|
2
2
|
# Capistrano: A deployment automation tool built on Ruby, Rake, and SSH.
|
3
3
|
|
4
|
-
[![Gem Version](https://badge.fury.io/rb/capistrano.svg)](http://badge.fury.io/rb/capistrano) [![Build Status](https://
|
4
|
+
[![Gem Version](https://badge.fury.io/rb/capistrano.svg)](http://badge.fury.io/rb/capistrano) [![Build Status](https://circleci.com/gh/capistrano/capistrano/tree/master.svg?style=shield)](https://app.circleci.com/pipelines/github/capistrano/capistrano?branch=master) [![Code Climate](https://codeclimate.com/github/capistrano/capistrano/badges/gpa.svg)](https://codeclimate.com/github/capistrano/capistrano) [![CodersClan](https://img.shields.io/badge/get-support-blue.svg)](http://codersclan.net/?repo_id=325&source=small)
|
5
5
|
|
6
6
|
Capistrano is a framework for building automated deployment scripts. Although Capistrano itself is written in Ruby, it can easily be used to deploy projects of any language or framework, be it Rails, Java, or PHP.
|
7
7
|
|
@@ -88,6 +88,10 @@ Likewise, your server(s) will likely need supporting software installed before y
|
|
88
88
|
|
89
89
|
Capistrano is designed to deploy using a single, non-privileged SSH user, using a *non-interactive* SSH session. If your deployment requires `sudo`, interactive prompts, authenticating as one user but running commands as another, you can probably accomplish this with Capistrano, but it may be difficult. Your automated deployments will be much smoother if you can avoid such requirements.
|
90
90
|
|
91
|
+
#### Shells
|
92
|
+
|
93
|
+
Capistrano 3 expects a POSIX shell like Bash or Sh. Shells like tcsh, csh, and such may work, but probably will not.
|
94
|
+
|
91
95
|
## Quick start
|
92
96
|
|
93
97
|
### Requirements
|
@@ -99,11 +103,11 @@ Capistrano is designed to deploy using a single, non-privileged SSH user, using
|
|
99
103
|
|
100
104
|
### Install the Capistrano gem
|
101
105
|
|
102
|
-
Add Capistrano to your project's Gemfile:
|
106
|
+
Add Capistrano to your project's Gemfile using `require: false`:
|
103
107
|
|
104
108
|
``` ruby
|
105
109
|
group :development do
|
106
|
-
gem "capistrano", "~> 3.
|
110
|
+
gem "capistrano", "~> 3.17", require: false
|
107
111
|
end
|
108
112
|
```
|
109
113
|
|
@@ -186,6 +190,8 @@ Related GitHub repositories:
|
|
186
190
|
|
187
191
|
GitHub issues are for bug reports and feature requests. Please refer to the [CONTRIBUTING](CONTRIBUTING.md) document for guidelines on submitting GitHub issues.
|
188
192
|
|
193
|
+
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>.
|
194
|
+
|
189
195
|
## How to contribute
|
190
196
|
|
191
197
|
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.
|
@@ -194,7 +200,7 @@ Contributions to Capistrano, in the form of code, documentation or idea, are gla
|
|
194
200
|
|
195
201
|
MIT License (MIT)
|
196
202
|
|
197
|
-
Copyright (c) 2012-
|
203
|
+
Copyright (c) 2012-2020 Tom Clements, Lee Hambley
|
198
204
|
|
199
205
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
200
206
|
of this software and associated documentation files (the "Software"), to deal
|
data/RELEASING.md
CHANGED
@@ -11,7 +11,7 @@
|
|
11
11
|
2. **Ensure all tests are passing by running `rake spec` and `rake features`.**
|
12
12
|
3. Determine which would be the correct next version number according to [semver](http://semver.org/).
|
13
13
|
4. Update the version in `./lib/capistrano/version.rb`.
|
14
|
-
|
15
|
-
|
16
|
-
6. Commit the changelog and version in a single commit, the message should be "Preparing vX.Y.Z"
|
14
|
+
5. Update the version in the `./README.md` Gemfile example (`gem "capistrano", "~> X.Y"`).
|
15
|
+
6. Commit the `version.rb` and `README.md` changes in a single commit, the message should be "Release vX.Y.Z"
|
17
16
|
7. Run `rake release`; this will tag, push to GitHub, and publish to rubygems.org.
|
17
|
+
8. Update the draft release on the [GitHub releases page](https://github.com/capistrano/capistrano/releases) to point to the new tag and publish the release
|
data/Rakefile
CHANGED
@@ -1,12 +1,20 @@
|
|
1
1
|
require "bundler/gem_tasks"
|
2
2
|
require "cucumber/rake/task"
|
3
3
|
require "rspec/core/rake_task"
|
4
|
-
require "rubocop/rake_task"
|
5
4
|
|
6
|
-
|
7
|
-
|
5
|
+
begin
|
6
|
+
require "rubocop/rake_task"
|
7
|
+
desc "Run RuboCop checks"
|
8
|
+
RuboCop::RakeTask.new
|
9
|
+
task default: %i(spec rubocop)
|
10
|
+
rescue LoadError
|
11
|
+
task default: :spec
|
12
|
+
end
|
8
13
|
|
14
|
+
RSpec::Core::RakeTask.new
|
9
15
|
Cucumber::Rake::Task.new(:features)
|
10
16
|
|
11
|
-
|
12
|
-
|
17
|
+
Rake::Task["release"].enhance do
|
18
|
+
puts "Don't forget to publish the release on GitHub!"
|
19
|
+
system "open https://github.com/capistrano/capistrano/releases"
|
20
|
+
end
|
data/UPGRADING-3.7.md
CHANGED
@@ -1,16 +1,5 @@
|
|
1
1
|
# Capistrano 3.7.0 upgrade guide
|
2
2
|
|
3
|
-
Capistrano 3.7.0 has not yet been released. This guide serves as a preview of
|
4
|
-
what is *planned* for 3.7.0, so that you can be prepared to update your
|
5
|
-
Capistrano deployment if necessary once it becomes available.
|
6
|
-
|
7
|
-
If you wish to try the new 3.7.0 behavior today, you can do so by using the
|
8
|
-
`master` branch in your Gemfile:
|
9
|
-
|
10
|
-
```ruby
|
11
|
-
gem "capistrano", :github => "capistrano/capistrano"
|
12
|
-
```
|
13
|
-
|
14
3
|
## The :scm variable is deprecated
|
15
4
|
|
16
5
|
Up until now, Capistrano's SCM was configured using the `:scm` variable:
|
@@ -23,7 +12,7 @@ set :scm, :svn
|
|
23
12
|
To avoid deprecation warnings:
|
24
13
|
|
25
14
|
1. Remove `set :scm, ...` from your Capistrano configuration.
|
26
|
-
2. Add *one* of the following SCM declarations to your `Capfile`:
|
15
|
+
2. Add *one* of the following SCM declarations to your `Capfile` after `require "capistrano/deploy"`:
|
27
16
|
|
28
17
|
```ruby
|
29
18
|
# To use Git
|
data/capistrano.gemspec
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
+
|
2
3
|
lib = File.expand_path("../lib", __FILE__)
|
3
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
5
|
require "capistrano/version"
|
@@ -10,8 +11,14 @@ Gem::Specification.new do |gem|
|
|
10
11
|
gem.email = ["seenmyfate@gmail.com", "lee.hambley@gmail.com"]
|
11
12
|
gem.description = "Capistrano is a utility and framework for executing commands in parallel on multiple remote machines, via SSH."
|
12
13
|
gem.summary = "Capistrano - Welcome to easy deployment with Ruby over SSH"
|
13
|
-
gem.homepage = "
|
14
|
-
|
14
|
+
gem.homepage = "https://capistranorb.com/"
|
15
|
+
gem.metadata = {
|
16
|
+
"bug_tracker_uri" => "https://github.com/capistrano/capistrano/issues",
|
17
|
+
"changelog_uri" => "https://github.com/capistrano/capistrano/releases",
|
18
|
+
"source_code_uri" => "https://github.com/capistrano/capistrano",
|
19
|
+
"homepage_uri" => "https://capistranorb.com/",
|
20
|
+
"documentation_uri" => "https://capistranorb.com/"
|
21
|
+
}
|
15
22
|
gem.files = `git ls-files -z`.split("\x0").reject { |f| f =~ /^docs/ }
|
16
23
|
gem.executables = %w(cap capify)
|
17
24
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
@@ -24,10 +31,4 @@ Gem::Specification.new do |gem|
|
|
24
31
|
gem.add_dependency "i18n"
|
25
32
|
gem.add_dependency "rake", ">= 10.0.0"
|
26
33
|
gem.add_dependency "sshkit", ">= 1.9.0"
|
27
|
-
gem.add_dependency "capistrano-harrow"
|
28
|
-
|
29
|
-
gem.add_development_dependency "danger"
|
30
|
-
gem.add_development_dependency "mocha"
|
31
|
-
gem.add_development_dependency "rspec"
|
32
|
-
gem.add_development_dependency "rubocop"
|
33
34
|
end
|
data/features/deploy.feature
CHANGED
@@ -7,7 +7,6 @@ Feature: Deploy
|
|
7
7
|
Scenario: Creating the repo
|
8
8
|
When I run cap "git:check"
|
9
9
|
Then the task is successful
|
10
|
-
And references in the remote repo are listed
|
11
10
|
And git wrapper permissions are 0700
|
12
11
|
|
13
12
|
Scenario: Creating the directory structure
|
@@ -53,3 +52,37 @@ Feature: Deploy
|
|
53
52
|
When I run cap "deploy:symlink:release"
|
54
53
|
Then the current directory will be a symlink to the release
|
55
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: Cleanup after many failed releases doesn't remove last good release
|
64
|
+
Given config stage file has line "set :keep_releases, 2"
|
65
|
+
And I make 2 deployments
|
66
|
+
And an invalid release named "77777777777777"
|
67
|
+
And an invalid release named "88888888888888"
|
68
|
+
And an invalid release named "99999999999999"
|
69
|
+
When I run cap "deploy:cleanup"
|
70
|
+
Then 3 valid releases are kept
|
71
|
+
And the current directory will be a symlink to the release
|
72
|
+
|
73
|
+
Scenario: Cleanup when there are more releases than arguments can handle
|
74
|
+
Given config stage file has line "set :keep_releases, 3"
|
75
|
+
And 5000 valid existing releases
|
76
|
+
When I run cap "deploy:cleanup"
|
77
|
+
Then 3 valid releases are kept
|
78
|
+
|
79
|
+
Scenario: Rolling Back
|
80
|
+
Given I make 2 deployments
|
81
|
+
When I run cap "deploy:rollback"
|
82
|
+
Then the current symlink points to the previous release
|
83
|
+
|
84
|
+
Scenario: Rolling Back to a specific release
|
85
|
+
Given I make 3 deployments
|
86
|
+
When I rollback to a specific release
|
87
|
+
Then the current symlink points to that specific release
|
88
|
+
|
@@ -1,16 +1,21 @@
|
|
1
1
|
Feature: Installation
|
2
2
|
|
3
3
|
Background:
|
4
|
-
Given a test app
|
4
|
+
Given a test app without any configuration
|
5
|
+
|
6
|
+
Scenario: The "install" task documentation can be viewed
|
7
|
+
When I run "cap -T"
|
8
|
+
Then the task is successful
|
9
|
+
And contains "cap install" in the output
|
5
10
|
|
6
11
|
Scenario: With default stages
|
7
|
-
When I run cap
|
12
|
+
When I run "cap install"
|
8
13
|
Then the deploy.rb file is created
|
9
14
|
And the default stage files are created
|
10
15
|
And the tasks folder is created
|
11
16
|
|
12
17
|
Scenario: With specified stages
|
13
|
-
When I run cap
|
18
|
+
When I run "cap install STAGES=qa,production"
|
14
19
|
Then the deploy.rb file is created
|
15
20
|
And the specified stage files are created
|
16
21
|
And the tasks folder is created
|
@@ -1,10 +1,14 @@
|
|
1
|
+
require "shellwords"
|
2
|
+
|
1
3
|
Then(/^references in the remote repo are listed$/) do
|
2
4
|
expect(@output).to include("refs/heads/master")
|
3
5
|
end
|
4
6
|
|
5
7
|
Then(/^git wrapper permissions are 0700$/) do
|
6
|
-
permissions_test = %Q([ $(stat -c "%a" #{TestApp.
|
7
|
-
|
8
|
+
permissions_test = %Q([ $(stat -c "%a" #{TestApp.git_wrapper_path_glob}) == "700" ])
|
9
|
+
_stdout, _stderr, status = vagrant_cli_command("ssh -c #{permissions_test.shellescape}")
|
10
|
+
|
11
|
+
expect(status).to be_success
|
8
12
|
end
|
9
13
|
|
10
14
|
Then(/^the shared path is created$/) do
|
@@ -15,6 +19,18 @@ Then(/^the releases path is created$/) do
|
|
15
19
|
run_vagrant_command(test_dir_exists(TestApp.releases_path))
|
16
20
|
end
|
17
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
|
+
|
18
34
|
Then(/^directories in :linked_dirs are created in shared$/) do
|
19
35
|
TestApp.linked_dirs.each do |dir|
|
20
36
|
run_vagrant_command(test_dir_exists(TestApp.shared_path.join(dir)))
|
@@ -50,7 +66,7 @@ Then(/^directory symlinks are created in the new release$/) do
|
|
50
66
|
end
|
51
67
|
|
52
68
|
Then(/^the current directory will be a symlink to the release$/) do
|
53
|
-
run_vagrant_command(
|
69
|
+
run_vagrant_command(exists?("e", TestApp.current_path))
|
54
70
|
end
|
55
71
|
|
56
72
|
Then(/^the deploy\.rb file is created$/) do
|
@@ -122,3 +138,15 @@ end
|
|
122
138
|
Then(/doesn't contain "([^"]*)" in the output/) do |expected|
|
123
139
|
expect(@output).not_to include(expected)
|
124
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
|
@@ -2,6 +2,10 @@ When(/^I run cap "(.*?)"$/) do |task|
|
|
2
2
|
@success, @output = TestApp.cap(task)
|
3
3
|
end
|
4
4
|
|
5
|
+
When(/^I run cap "(.*?)" within the "(.*?)" directory$/) do |task, directory|
|
6
|
+
@success, @output = TestApp.cap(task, directory)
|
7
|
+
end
|
8
|
+
|
5
9
|
When(/^I run cap "(.*?)" as part of a release$/) do |task|
|
6
10
|
TestApp.cap("deploy:new_release_path #{task}")
|
7
11
|
end
|
@@ -9,3 +13,9 @@ end
|
|
9
13
|
When(/^I run "(.*?)"$/) do |command|
|
10
14
|
@success, @output = TestApp.run(command)
|
11
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
|
@@ -2,6 +2,10 @@ Given(/^a test app with the default configuration$/) do
|
|
2
2
|
TestApp.install
|
3
3
|
end
|
4
4
|
|
5
|
+
Given(/^a test app without any configuration$/) do
|
6
|
+
TestApp.create_test_app
|
7
|
+
end
|
8
|
+
|
5
9
|
Given(/^servers with the roles app and web$/) do
|
6
10
|
begin
|
7
11
|
vagrant_cli_command("up")
|
@@ -17,10 +21,16 @@ end
|
|
17
21
|
|
18
22
|
Given(/^file "(.*?)" exists in shared path$/) do |file|
|
19
23
|
file_shared_path = TestApp.shared_path.join(file)
|
20
|
-
run_vagrant_command("mkdir -p #{
|
24
|
+
run_vagrant_command("mkdir -p #{file_shared_path.dirname}")
|
21
25
|
run_vagrant_command("touch #{file_shared_path}")
|
22
26
|
end
|
23
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
|
+
|
24
34
|
Given(/^file "(.*?)" does not exist in shared path$/) do |file|
|
25
35
|
file_shared_path = TestApp.shared_path.join(file)
|
26
36
|
run_vagrant_command("mkdir -p #{TestApp.shared_path}")
|
@@ -56,3 +66,29 @@ end
|
|
56
66
|
Given(/^a stage file named (.+)$/) do |filename|
|
57
67
|
TestApp.write_local_stage_file(filename)
|
58
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
|
+
(1...num).each_slice(100) do |num_batch|
|
84
|
+
dirs = num_batch.map do |i|
|
85
|
+
offset = -(a_day * i)
|
86
|
+
TestApp.release_path(TestApp.timestamp(offset))
|
87
|
+
end
|
88
|
+
run_vagrant_command("mkdir -p #{dirs.join(' ')}")
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
Given(/^an invalid release named "(.+)"$/) do |filename|
|
93
|
+
run_vagrant_command("mkdir -p #{TestApp.release_path(filename)}")
|
94
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
Feature: cap can be run from a subdirectory, and will still find the Capfile
|
2
|
+
|
3
|
+
Background:
|
4
|
+
Given a test app with the default configuration
|
5
|
+
And servers with the roles app and web
|
6
|
+
|
7
|
+
Scenario: Running cap from a subdirectory
|
8
|
+
When I run cap "git:check" within the "config" directory
|
9
|
+
Then the task is successful
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require "
|
1
|
+
require "open3"
|
2
2
|
|
3
3
|
module VagrantHelpers
|
4
4
|
extend self
|
@@ -16,19 +16,26 @@ 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
|
33
|
+
|
34
|
+
def puts(message)
|
35
|
+
# Attach log messages to the current cucumber feature (`log`),
|
36
|
+
# or simply puts to the console (`super`) if we are outside of cucumber.
|
37
|
+
respond_to?(:log) ? log(message) : super(message)
|
38
|
+
end
|
32
39
|
end
|
33
40
|
|
34
41
|
World(VagrantHelpers)
|
data/lib/Capfile
CHANGED
@@ -2,7 +2,7 @@ module Capistrano
|
|
2
2
|
class Application < Rake::Application
|
3
3
|
def initialize
|
4
4
|
super
|
5
|
-
@rakefiles = %w{capfile Capfile capfile.rb Capfile.rb}
|
5
|
+
@rakefiles = %w{capfile Capfile capfile.rb Capfile.rb}
|
6
6
|
end
|
7
7
|
|
8
8
|
def name
|
@@ -76,6 +76,15 @@ module Capistrano
|
|
76
76
|
end
|
77
77
|
end
|
78
78
|
|
79
|
+
# allows the `cap install` task to load without a capfile
|
80
|
+
def find_rakefile_location
|
81
|
+
if (location = super).nil?
|
82
|
+
[capfile, Dir.pwd]
|
83
|
+
else
|
84
|
+
location
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
79
88
|
private
|
80
89
|
|
81
90
|
def backtrace_pattern
|
@@ -87,7 +96,7 @@ module Capistrano
|
|
87
96
|
end
|
88
97
|
|
89
98
|
def load_imports
|
90
|
-
if options.show_tasks
|
99
|
+
if options.show_tasks && Rake::Task.task_defined?("load:defaults")
|
91
100
|
invoke "load:defaults"
|
92
101
|
set(:stage, "")
|
93
102
|
Dir[deploy_config_path].each { |f| add_import f }
|
@@ -96,7 +105,6 @@ module Capistrano
|
|
96
105
|
super
|
97
106
|
end
|
98
107
|
|
99
|
-
# allows the `cap install` task to load without a capfile
|
100
108
|
def capfile
|
101
109
|
File.expand_path(File.join(File.dirname(__FILE__), "..", "Capfile"))
|
102
110
|
end
|
@@ -8,7 +8,7 @@ module Capistrano
|
|
8
8
|
class Configuration
|
9
9
|
class Filter
|
10
10
|
def initialize(type, values=nil)
|
11
|
-
raise "Invalid filter type #{type}" unless
|
11
|
+
raise "Invalid filter type #{type}" unless %i(host role).include? type
|
12
12
|
av = Array(values)
|
13
13
|
@strategy = if av.empty? then EmptyFilter.new
|
14
14
|
elsif av.include?(:all) || av.include?("all") then NullFilter.new
|