capistrano 3.6.0 → 3.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/.github/issue_template.md +19 -0
  3. data/.github/pull_request_template.md +26 -0
  4. data/.gitignore +1 -0
  5. data/.travis.yml +10 -2
  6. data/CHANGELOG.md +63 -1
  7. data/DEVELOPMENT.md +7 -1
  8. data/Dangerfile +54 -0
  9. data/README.md +4 -5
  10. data/capistrano.gemspec +3 -2
  11. data/features/support/vagrant_helpers.rb +3 -5
  12. data/lib/capistrano/all.rb +1 -0
  13. data/lib/capistrano/configuration/host_filter.rb +1 -1
  14. data/lib/capistrano/configuration/plugin_installer.rb +20 -2
  15. data/lib/capistrano/configuration/role_filter.rb +1 -1
  16. data/lib/capistrano/configuration/scm_resolver.rb +144 -0
  17. data/lib/capistrano/configuration/validated_variables.rb +48 -13
  18. data/lib/capistrano/configuration/variables.rb +0 -8
  19. data/lib/capistrano/configuration.rb +30 -3
  20. data/lib/capistrano/defaults.rb +3 -1
  21. data/lib/capistrano/doctor/variables_doctor.rb +1 -1
  22. data/lib/capistrano/dsl/env.rb +2 -9
  23. data/lib/capistrano/dsl/paths.rb +1 -1
  24. data/lib/capistrano/dsl/task_enhancements.rb +0 -8
  25. data/lib/capistrano/dsl.rb +2 -1
  26. data/lib/capistrano/i18n.rb +1 -0
  27. data/lib/capistrano/scm/git.rb +73 -0
  28. data/lib/capistrano/scm/hg.rb +48 -0
  29. data/lib/capistrano/scm/plugin.rb +13 -0
  30. data/lib/capistrano/scm/svn.rb +47 -0
  31. data/lib/capistrano/{tasks → scm/tasks}/git.rake +9 -24
  32. data/lib/capistrano/{tasks → scm/tasks}/hg.rake +11 -10
  33. data/lib/capistrano/{tasks → scm/tasks}/svn.rake +11 -10
  34. data/lib/capistrano/setup.rb +1 -1
  35. data/lib/capistrano/tasks/deploy.rake +4 -5
  36. data/lib/capistrano/templates/Capfile +18 -7
  37. data/lib/capistrano/templates/deploy.rb.erb +7 -10
  38. data/lib/capistrano/templates/stage.rb.erb +8 -8
  39. data/lib/capistrano/version.rb +1 -1
  40. data/lib/capistrano/version_validator.rb +2 -5
  41. data/spec/lib/capistrano/configuration/host_filter_spec.rb +5 -0
  42. data/spec/lib/capistrano/configuration/plugin_installer_spec.rb +98 -0
  43. data/spec/lib/capistrano/configuration/role_filter_spec.rb +17 -1
  44. data/spec/lib/capistrano/configuration_spec.rb +61 -2
  45. data/spec/lib/capistrano/doctor/variables_doctor_spec.rb +0 -7
  46. data/spec/lib/capistrano/dsl/task_enhancements_spec.rb +0 -15
  47. data/spec/lib/capistrano/scm/git_spec.rb +131 -0
  48. data/spec/lib/capistrano/scm/hg_spec.rb +104 -0
  49. data/spec/lib/capistrano/scm/svn_spec.rb +116 -0
  50. data/spec/lib/capistrano/scm_spec.rb +1 -1
  51. metadata +37 -19
  52. data/features/remote_file_task.feature +0 -14
  53. data/issue_template.md +0 -21
  54. data/lib/capistrano/git.rb +0 -54
  55. data/lib/capistrano/hg.rb +0 -43
  56. data/lib/capistrano/svn.rb +0 -42
  57. data/spec/lib/capistrano/git_spec.rb +0 -109
  58. data/spec/lib/capistrano/hg_spec.rb +0 -90
  59. data/spec/lib/capistrano/svn_spec.rb +0 -105
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1dffc85194d6ad3db0812f96e216fe5d95a508e9
4
- data.tar.gz: f93a202158ed81afecc72d6d19db46b9c965fdad
3
+ metadata.gz: ce22b5f5826e88b5fd92b3369c02344f20e2191e
4
+ data.tar.gz: 491397aab719879777bec4153c3125575f86e62a
5
5
  SHA512:
6
- metadata.gz: 07cb65b0395968f71258ab6e0f6886d658f5c5f6a87e1780537474855f19453c2c09e77fc7b6d7d11ce062133aca191dc1be4e19ad9f21b22c37d82a86925e55
7
- data.tar.gz: 65d563a1ae4fce777c70c225f2f5d711d4c5e68493b3254215a372ba72f06fb4cf410637ab82758af6d2ac91d91ec8c11c8648da4c5a57deec7800838b30a6c4
6
+ metadata.gz: 37864d78dd2d14478f0e9edcb316ac5e68fe5dc83b02bfd4017b1790350b26d1c929f6b94890fe351101fd05257f4bf8ce427fb8f5be0d1758e36e48fcc70fd5
7
+ data.tar.gz: 6eec3f49c1e4867137d3d266d533c44bcba2bc076d1e8d003e51bcc8735a14f613ef8c49a86f69417cd40deca95b2827115885289113e490ea8bf0940639c50b
@@ -0,0 +1,19 @@
1
+ **Important:** GitHub issues are for feature requests or bug reports. The Capistrano team recommends you use [Stack Overflow](http://stackoverflow.com/questions/tagged/capistrano) for general questions. For more details, please see our [contribution policy](https://github.com/capistrano/capistrano/blob/master/CONTRIBUTING.md).
2
+
3
+ ---
4
+
5
+ ### Steps to reproduce
6
+ If reasonable, you can help by creating a Capistrano skeleton example project which reproduces the issue you are seeing. You can then upload the individual files to a GitHub Gist or a GitHub project. Others can simply modify the configuration to point at a test server/repository of their own. Often times, an issue is resolved simply by making this test case.
7
+
8
+ An example test case is here: https://gist.github.com/will-in-wi/527327e31af30b3eae2068e2965be05b
9
+
10
+ ### Expected behavior
11
+ Tell us what should happen
12
+
13
+ ### Actual behavior
14
+ Tell us what happens instead
15
+
16
+ ### System configuration
17
+ Please link to the output of `cap <stage> doctor` in a GitHub Gist.
18
+
19
+ Thanks for helping improve Capistrano!
@@ -0,0 +1,26 @@
1
+ ### Summary
2
+
3
+ (Guidelines for creating a bug report are available
4
+ here: https://github.com/capistrano/capistrano/blob/master/DEVELOPMENT.md)
5
+
6
+ Provide a general description of the code changes in your pull
7
+ request... were there any bugs you had fixed? If so, mention them. If
8
+ these bugs have open GitHub issues, be sure to tag them here as well,
9
+ to keep the conversation linked together.
10
+
11
+ ### Short checklist
12
+
13
+ - [ ] Did you run `bundle exec rubocop -a` to fix linter issues?
14
+ - [ ] If relevant, did you create a test?
15
+ - [ ] Did you confirm that the RSpec tests pass?
16
+ - [ ] If you are fixing a bug or introducing a new feature, did you add a CHANGELOG entry?
17
+
18
+ ### Other Information
19
+
20
+ If there's anything else that's important and relevant to your pull
21
+ request, mention that information here.
22
+
23
+ If you are updating any of the CHANGELOG files or are asked to update the
24
+ CHANGELOG files by reviewers, please add the CHANGELOG entry at the top of the file where indicated.
25
+
26
+ Thanks for helping improve Capistrano!
data/.gitignore CHANGED
@@ -21,4 +21,5 @@ tags
21
21
  test/tmp
22
22
  test/version_tmp
23
23
  tmp
24
+ /docs/_site/
24
25
  vendor/
data/.travis.yml CHANGED
@@ -1,14 +1,22 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.3.0
3
+ - 2.3.1
4
4
  - 2.2
5
5
  - 2.1
6
6
  - 2.0
7
7
  matrix:
8
+ # Rubinius periodically fails in general, and it always segfaults for RuboCop
9
+ # in particular. Until we figure out how to make it work consistently, allow
10
+ # it to fail without breaking the build.
11
+ allow_failures:
12
+ - rvm: rbx-2
8
13
  include:
9
- # Run specs on Rubinius, but not RuboCop, since it seg faults
10
14
  - rvm: rbx-2
11
15
  script: bundle exec rake spec
16
+ # Run Danger only once, on 2.3.1
17
+ - rvm: 2.3.1
18
+ before_script: bundle exec danger
19
+
12
20
  script: bundle exec rake spec rubocop
13
21
  install: bundle install --jobs=1
14
22
  cache: bundler
data/CHANGELOG.md CHANGED
@@ -4,10 +4,72 @@ Reverse Chronological Order:
4
4
 
5
5
  ## master
6
6
 
7
- https://github.com/capistrano/capistrano/compare/v3.6.0...HEAD
7
+ https://github.com/capistrano/capistrano/compare/v3.7.0...HEAD
8
8
 
9
9
  * Your contribution here!
10
10
 
11
+ ## `3.7.0` (2016-12-10)
12
+
13
+ https://github.com/capistrano/capistrano/compare/v3.6.1...v3.7.0
14
+
15
+ *Note: These release notes include all changes since 3.6.1, including the changes that were first published in 3.7.0.beta1.*
16
+
17
+ ### Deprecations:
18
+
19
+ * The `set :scm, ...` mechanism is now deprecated in favor of a new SCM plugin system. See the [UPGRADING-3.7](UPGRADING-3.7.md) document for details
20
+
21
+ ### Potentially breaking changes:
22
+
23
+ * The `:git_strategy`, `:hg_strategy`, and `:svn_strategy` settings have been removed with no replacement. If you have been using these to customize Capistrano's SCM behavior, you will need to rewrite your customization using the [new plugin system](http://capistranorb.com/documentation/advanced-features/custom-scm/)
24
+ * `remote_file` feature has been removed and is no longer available to use @SaiVardhan
25
+
26
+ ### New features:
27
+
28
+ * The `tar` used by the Git SCM now honors the SSHKit command map, allowing an alternative tar binary to be used (e.g. gtar) #1787 (@caius)
29
+ * Add support for custom on-filters [#1776](https://github.com/capistrano/capistrano/issues/1776)
30
+
31
+ ### Fixes:
32
+
33
+ * Fix test suite to work with Mocha 1.2.0 (@caius)
34
+ * Fix bug where host_filter and role_filter were overly greedy [#1766](https://github.com/capistrano/capistrano/issues/1766) (@cseeger-epages)
35
+ * Fix the removal of old releases `deploy:cleanup`. Logic is changed because of unreliable modification times on folders. Removal of directories is now decided by sorting on folder names (name is generated from current datetime format YmdHis). Cleanup is skipped, and a warning is given when a folder name is in a different format
36
+
37
+ ## `3.7.0.beta1` (2016-11-02)
38
+
39
+ https://github.com/capistrano/capistrano/compare/v3.6.1...v3.7.0.beta1
40
+
41
+ ### Deprecations:
42
+
43
+ * The `set :scm, ...` mechanism is now deprecated in favor of a new SCM plugin
44
+ system. See the [UPGRADING-3.7](UPGRADING-3.7.md) document for details.
45
+
46
+ ### Potentially breaking changes:
47
+
48
+ * The `:git_strategy`, `:hg_strategy`, and `:svn_strategy` settings have been
49
+ removed with no replacement. If you have been using these to customize
50
+ Capistrano's SCM behavior, you will need to rewrite your customization using
51
+ the [new plugin system](http://capistranorb.com/documentation/advanced-features/custom-scm/).
52
+ * `remote_file` feature has been removed and is no longer available to use @SaiVardhan
53
+
54
+ ### New features:
55
+
56
+ * The `tar` used by the Git SCM now honors the SSHKit command map, allowing an alternative tar binary to be used (e.g. gtar) #1787 (@caius)
57
+
58
+ ### Fixes:
59
+
60
+ * Fix test suite to work with Mocha 1.2.0 (@caius)
61
+ * Fix bug where host_filter and role_filter were overly greedy [#1766](https://github.com/capistrano/capistrano/issues/1766) (@cseeger-epages)
62
+
63
+ ## `3.6.1` (2016-08-23)
64
+
65
+ https://github.com/capistrano/capistrano/compare/v3.6.0...v3.6.1
66
+
67
+ ### Fixes:
68
+
69
+ * Restore compatibility with older versions of Rake (< 11.0.0) (@troelskn)
70
+ * Fix `NoMethodError: undefined method gsub` when setting `:application` to a Proc. The original fix released in 3.6.0 worked for values specified with blocks, but not for those specified with procs or lambdas (the latter syntax is much more common). [#1681](https://github.com/capistrano/capistrano/issues/1681)
71
+ * Fix a bug where deploy would fail if `:local_user` contained a space; spaces are now replaced with dashes when computing the git-ssh suffix. (@will_in_wi)
72
+
11
73
  ## `3.6.0` (2016-07-26)
12
74
 
13
75
  https://github.com/capistrano/capistrano/compare/v3.5.0...v3.6.0
data/DEVELOPMENT.md CHANGED
@@ -1,6 +1,7 @@
1
1
  Thanks for helping build Capistrano! Here are the development practices followed by our community.
2
2
 
3
3
  * [Who can help](#who-can-help)
4
+ * [Contributing documentation](#contributing-documentation)
4
5
  * [Setting up your development environment](#setting-up-your-development-environment)
5
6
  * [Coding guidelines](#coding-guidelines)
6
7
  * [Submitting a pull request](#submitting-a-pull-request)
@@ -17,6 +18,10 @@ Everyone can help improve Capistrano. There are ways to contribute even if you a
17
18
  * reviewing pull requests and suggesting improvements
18
19
  * reporting bugs or suggesting new features (see [CONTRIBUTING.md][])
19
20
 
21
+ ## Contributing documentation
22
+
23
+ Improvements and additions to Capistrano's documentation are very much appreciated. The official documention is stored in the `docs/` directory as Markdown files. These files are used to automatically generate the [capistranorb.com](http://capistranorb.com/) website, which is hosted by GitHub Pages. Feel free to make changes to this documentation as you see fit. Before opening a pull request, make sure your documentation renders correctly by previewing the website in your local environment. Refer to [docs/README.md][] for instructions.
24
+
20
25
  ## Setting up your development environment
21
26
 
22
27
  Capistrano is a Ruby project, so we expect you to have a functioning Ruby environment. To hack on Capistrano you will further need some specialized tools to run its test suite.
@@ -71,7 +76,7 @@ Your code should conform to these guidelines:
71
76
  * 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.
72
77
  * 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 )
73
78
  * Add an entry to the `CHANGELOG` under the `### master` section, but please don't mess with the version.
74
- * If you add a new feature, please make sure to document it, open a corresponding pull request in [the documentation](https://github.com/capistrano/documentation) and mention the code change pull request over there, and Github will link everything up. If it's a simple feature, or a new variable, or something changed, it may be appropriate simply to document it in the generated `Capfile` or `deploy.rb`, or in the `README`
79
+ * If you add a new feature, please make sure to document it by modifying the appropriate Markdown files in `docs/` (see [contributing documentation](#contributing-documentation), above). If it's a simple feature, or a new variable, or something changed, it may be appropriate simply to document it in the generated `Capfile` or `deploy.rb`, or in the `README`.
75
80
  * Take care to squash your commit into one single commit with a good message, it saves us a lot of work in maintaining the CHANGELOG if we can generate it from the commit messages between the release tags!
76
81
  * Tests! It's tricky to test some parts of Capistrano, but do your best, it might just serve as a starting point for us to build a reliable test on top of, and help us understand where you are coming from.
77
82
 
@@ -120,3 +125,4 @@ After a pull request is merged, it is assigned to a GitHub milestone for the upc
120
125
 
121
126
 
122
127
  [CONTRIBUTING.md]: https://github.com/capistrano/capistrano/blob/master/CONTRIBUTING.md
128
+ [docs/README.md]: https://github.com/capistrano/capistrano/blob/master/docs/README.md
data/Dangerfile ADDED
@@ -0,0 +1,54 @@
1
+ # Adapted from https://github.com/ruby-grape/danger/blob/master/Dangerfile
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
data/README.md CHANGED
@@ -58,7 +58,7 @@ Deploying to a fleet of app servers? Capistrano can run each deployment task con
58
58
 
59
59
  #### Server roles
60
60
 
61
- Your application may need many different types of servers: a database server, an app server, two app servers, and a job queue work server, for example. Capistrano lets you tag each server with one or more roles, so you can control what tasks are executed where.
61
+ Your application may need many different types of servers: a database server, an app server, two web servers, and a job queue work server, for example. Capistrano lets you tag each server with one or more roles, so you can control what tasks are executed where.
62
62
 
63
63
  #### Community driven
64
64
 
@@ -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.6"
106
+ gem "capistrano", "~> 3.7"
107
107
  end
108
108
  ```
109
109
 
@@ -141,7 +141,7 @@ To customize the stages that are created, use:
141
141
  $ bundle exec cap install STAGES=local,sandbox,qa,production
142
142
  ```
143
143
 
144
- Note that the files that Capistrano creates are simply templates to get you started. Make sure to edit the `deploy.rb` and stage files so they contain values appropriate for your project and your target servers.
144
+ Note that the files that Capistrano creates are simply templates to get you started. Make sure to edit the `deploy.rb` and stage files so that they contain values appropriate for your project and your target servers.
145
145
 
146
146
  ### Command-line usage
147
147
 
@@ -173,7 +173,7 @@ $ bundle exec cap production deploy --print-config-variables
173
173
 
174
174
  Capistrano is a large project encompassing multiple GitHub repositories and a community of plugins, and it can be overwhelming when you are just getting started. Here are resources that can help:
175
175
 
176
- * **[The Capistrano website](http://capistranorb.com) is the best place for official documentation**
176
+ * **The [docs](docs) directory contains the official documentation**, and is used to generate the [Capistrano website](http://capistranorb.com)
177
177
  * [Stack Overflow](http://stackoverflow.com/questions/tagged/capistrano) has a Capistrano tag with lots of activity
178
178
  * [The Capistrano mailing list](https://groups.google.com/forum/#!forum/capistrano) is low-traffic but is monitored by Capistrano contributors
179
179
  * [CodersClan](http://codersclan.net/?repo_id=325&source=link) has Capistrano experts available to solve problems for bounties
@@ -181,7 +181,6 @@ Capistrano is a large project encompassing multiple GitHub repositories and a co
181
181
  Related GitHub repositories:
182
182
 
183
183
  * [capistrano/sshkit](https://github.com/capistrano/sshkit) provides the SSH behavior that underlies Capistrano (when you use `execute` in a Capistrano task, you are using SSHKit)
184
- * [capistrano/documentation](https://github.com/capistrano/documentation) is what generates the official Capistrano website
185
184
  * [capistrano/rails](https://github.com/capistrano/rails) is a very popular gem that adds Ruby on Rails deployment tasks
186
185
  * [mattbrictson/airbrussh](https://github.com/mattbrictson/airbrussh) provides Capistrano's default log formatting
187
186
 
data/capistrano.gemspec CHANGED
@@ -12,7 +12,7 @@ Gem::Specification.new do |gem|
12
12
  gem.summary = "Capistrano - Welcome to easy deployment with Ruby over SSH"
13
13
  gem.homepage = "http://capistranorb.com/"
14
14
 
15
- gem.files = `git ls-files -z`.split("\x0")
15
+ gem.files = `git ls-files -z`.split("\x0").reject { |f| f =~ /^docs/ }
16
16
  gem.executables = %w(cap capify)
17
17
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
18
  gem.require_paths = ["lib"]
@@ -26,7 +26,8 @@ Gem::Specification.new do |gem|
26
26
  gem.add_dependency "sshkit", ">= 1.9.0"
27
27
  gem.add_dependency "capistrano-harrow"
28
28
 
29
- gem.add_development_dependency "rspec"
29
+ gem.add_development_dependency "danger"
30
30
  gem.add_development_dependency "mocha"
31
+ gem.add_development_dependency "rspec"
31
32
  gem.add_development_dependency "rubocop"
32
33
  end
@@ -25,11 +25,9 @@ module VagrantHelpers
25
25
  end
26
26
 
27
27
  def run_vagrant_command(command)
28
- if (status = vagrant_cli_command("ssh -c #{command.inspect}")).success?
29
- true
30
- else
31
- raise VagrantSSHCommandError, status
32
- end
28
+ status = vagrant_cli_command("ssh -c #{command.inspect}")
29
+ return true if status.success?
30
+ raise VagrantSSHCommandError, status
33
31
  end
34
32
  end
35
33
 
@@ -11,6 +11,7 @@ require "capistrano/i18n"
11
11
  require "capistrano/dsl"
12
12
  require "capistrano/application"
13
13
  require "capistrano/configuration"
14
+ require "capistrano/configuration/scm_resolver"
14
15
 
15
16
  module Capistrano
16
17
  end
@@ -20,7 +20,7 @@ module Capistrano
20
20
  when Regexp then v
21
21
  else
22
22
  vs = v.to_s
23
- vs =~ /^[-A-Za-z0-9.]+$/ ? vs : Regexp.new(vs)
23
+ vs =~ /^[-A-Za-z0-9.]+$/ ? /^#{Regexp.quote(vs)}$/ : Regexp.new(vs)
24
24
  end
25
25
  end
26
26
  Regexp.union values
@@ -18,16 +18,34 @@ module Capistrano
18
18
  # install(Capistrano::SCM::Git)
19
19
  # install(Capistrano::SCM::Git.new)
20
20
  #
21
- def install(plugin, load_hooks: true)
21
+ # Note that the :load_immediately flag is for internal use only and will
22
+ # be removed in an upcoming release.
23
+ #
24
+ def install(plugin, load_hooks: true, load_immediately: false)
22
25
  plugin = plugin.is_a?(Class) ? plugin.new : plugin
23
26
 
24
27
  plugin.define_tasks
25
28
  plugin.register_hooks if load_hooks
29
+ @scm_installed ||= provides_scm?(plugin)
26
30
 
27
- Rake::Task.define_task("load:defaults") do
31
+ if load_immediately
28
32
  plugin.set_defaults
33
+ else
34
+ Rake::Task.define_task("load:defaults") do
35
+ plugin.set_defaults
36
+ end
29
37
  end
30
38
  end
39
+
40
+ def scm_installed?
41
+ @scm_installed
42
+ end
43
+
44
+ private
45
+
46
+ def provides_scm?(plugin)
47
+ plugin.respond_to?(:scm?) && plugin.scm?
48
+ end
31
49
  end
32
50
  end
33
51
  end
@@ -20,7 +20,7 @@ module Capistrano
20
20
  when Regexp then v
21
21
  else
22
22
  vs = v.to_s
23
- vs =~ %r{^/(.+)/$} ? Regexp.new($1) : /^#{vs}$/
23
+ vs =~ %r{^/(.+)/$} ? Regexp.new($1) : /^#{Regexp.quote(vs)}$/
24
24
  end
25
25
  end
26
26
  Regexp.union values
@@ -0,0 +1,144 @@
1
+ module Capistrano
2
+ class Configuration
3
+ # In earlier versions of Capistrano, users would specify the desired SCM
4
+ # implementation using `set :scm, :git`, for example. Capistrano would then
5
+ # load the matching .rb file based on this variable.
6
+ #
7
+ # Now we expect users to explicitly `require` and call `new` on the desired
8
+ # SCM implementation in their Capfile. The `set` technique is deprecated.
9
+ #
10
+ # This SCMResolver class takes care of managing the transition from the old
11
+ # to new system. It maintains the legacy behavior, but prints deprecation
12
+ # warnings when it is used.
13
+ #
14
+ # To maintain backwards compatibility, the resolver will load the Git SCM by
15
+ # if default it determines that no SCM has been explicitly specified or
16
+ # loaded. To force no SCM to be used at all, use `set :scm, nil`. This hack
17
+ # won't be necessary once backwards compatibility is removed in a future
18
+ # version.
19
+ #
20
+ # TODO: Remove this class entirely in Capistrano 4.0.
21
+ #
22
+ class SCMResolver
23
+ DEFAULT_GIT = :"default-git"
24
+
25
+ include Capistrano::DSL
26
+
27
+ def resolve
28
+ return if scm_name.nil?
29
+ set(:scm, :git) if using_default_scm?
30
+
31
+ print_deprecation_warnings_if_applicable
32
+ # Note that `scm_plugin_installed?` comes from Capistrano::DSL
33
+ return if scm_plugin_installed?
34
+
35
+ if built_in_scm_name?
36
+ load_built_in_scm
37
+ else
38
+ # Compatibility with existing 3.x third-party SCMs
39
+ register_legacy_scm_hooks
40
+ load_legacy_scm_by_name
41
+ end
42
+ end
43
+
44
+ private
45
+
46
+ def using_default_scm?
47
+ return @using_default_scm if defined? @using_default_scm
48
+ @using_default_scm = (fetch(:scm) == DEFAULT_GIT)
49
+ end
50
+
51
+ def scm_name
52
+ fetch(:scm)
53
+ end
54
+
55
+ def load_built_in_scm
56
+ require "capistrano/scm/#{scm_name}"
57
+ scm_class = Object.const_get(built_in_scm_plugin_class_name)
58
+ # We use :load_immediately because we are initializing the SCM plugin
59
+ # late in the load process and therefore can't use the standard
60
+ # load:defaults technique.
61
+ install_plugin(scm_class, load_immediately: true)
62
+ end
63
+
64
+ def load_legacy_scm_by_name
65
+ load("capistrano/#{scm_name}.rb")
66
+ end
67
+
68
+ def third_party_scm_name?
69
+ !built_in_scm_name?
70
+ end
71
+
72
+ def built_in_scm_name?
73
+ %w(git hg svn).include?(scm_name.to_s.downcase)
74
+ end
75
+
76
+ def built_in_scm_plugin_class_name
77
+ "Capistrano::SCM::#{scm_name.to_s.capitalize}"
78
+ end
79
+
80
+ # rubocop:disable Style/GuardClause
81
+ def register_legacy_scm_hooks
82
+ if Rake::Task.task_defined?("deploy:new_release_path")
83
+ after "deploy:new_release_path", "#{scm_name}:create_release"
84
+ end
85
+
86
+ if Rake::Task.task_defined?("deploy:check")
87
+ before "deploy:check", "#{scm_name}:check"
88
+ end
89
+
90
+ if Rake::Task.task_defined?("deploy:set_current_revision")
91
+ before "deploy:set_current_revision",
92
+ "#{scm_name}:set_current_revision"
93
+ end
94
+ end
95
+ # rubocop:enable Style/GuardClause
96
+
97
+ def print_deprecation_warnings_if_applicable
98
+ if using_default_scm?
99
+ warn_add_git_to_capfile unless scm_plugin_installed?
100
+ elsif built_in_scm_name?
101
+ warn_set_scm_is_deprecated
102
+ elsif third_party_scm_name?
103
+ warn_third_party_scm_must_be_upgraded
104
+ end
105
+ end
106
+
107
+ def warn_set_scm_is_deprecated
108
+ $stderr.puts(<<-MESSAGE)
109
+ [Deprecation Notice] `set :scm, #{scm_name.inspect}` is deprecated.
110
+ To ensure your project is compatible with future versions of Capistrano,
111
+ remove the :scm setting and instead add these lines to your Capfile:
112
+
113
+ require "capistrano/scm/#{scm_name}"
114
+ install_plugin #{built_in_scm_plugin_class_name}
115
+
116
+ MESSAGE
117
+ end
118
+
119
+ def warn_add_git_to_capfile
120
+ $stderr.puts(<<-MESSAGE)
121
+ [Deprecation Notice] Future versions of Capistrano will not load the Git SCM
122
+ plugin by default. To silence this deprecation warning, add the following to
123
+ your Capfile:
124
+
125
+ require "capistrano/scm/git"
126
+ install_plugin Capistrano::SCM::Git
127
+
128
+ MESSAGE
129
+ end
130
+
131
+ def warn_third_party_scm_must_be_upgraded
132
+ $stderr.puts(<<-MESSAGE)
133
+ [Deprecation Notice] `set :scm, #{scm_name.inspect}` is deprecated.
134
+ To ensure this custom SCM will work with future versions of Capistrano,
135
+ please upgrade it to a version that uses the new SCM plugin mechanism
136
+ documented here:
137
+
138
+ http://capistranorb.com/documentation/advanced-features/custom-scm
139
+
140
+ MESSAGE
141
+ end
142
+ end
143
+ end
144
+ end
@@ -7,9 +7,9 @@ module Capistrano
7
7
  # user-supplied validation rules. Each rule for a given key is invoked
8
8
  # immediately whenever `set` is called with a value for that key.
9
9
  #
10
- # If `set` is called with a block, validation is not performed immediately.
11
- # Instead, the validation rules are invoked the first time `fetch` is used
12
- # to access the value.
10
+ # If `set` is called with a callable value or a block, validation is not
11
+ # performed immediately. Instead, the validation rules are invoked the first
12
+ # time `fetch` is used to access the value.
13
13
  #
14
14
  # A rule is simply a block that accepts two arguments: key and value. It is
15
15
  # up to the rule to raise an exception when it deems the value is invalid
@@ -31,10 +31,17 @@ module Capistrano
31
31
 
32
32
  # Decorate Variables#set to add validation behavior.
33
33
  def set(key, value=nil, &block)
34
- if value.nil? && callable_without_parameters?(block)
35
- super(key, nil, &assert_valid_later(key, &block))
34
+ assert_value_or_block_not_both(value, block)
35
+
36
+ # Skip validation behavior if no validators are registered for this key
37
+ return super unless validators.key?(key)
38
+
39
+ value_to_evaluate = block || value
40
+
41
+ if callable_without_parameters?(value_to_evaluate)
42
+ super(key, assert_valid_later(key, value_to_evaluate), &nil)
36
43
  else
37
- assert_valid_now(key, block || value)
44
+ assert_valid_now(key, value_to_evaluate)
38
45
  super
39
46
  end
40
47
  end
@@ -50,26 +57,54 @@ module Capistrano
50
57
 
51
58
  attr_reader :validators
52
59
 
53
- # Wrap a block with a proc that validates the value of the block. This
54
- # allows us to defer validation until the time the value is requested.
55
- def assert_valid_later(key)
56
- lambda do
57
- value = yield
60
+ # Given a callable that provides a value, wrap the callable with another
61
+ # object that responds to `call`. This new object will perform validation
62
+ # and then return the original callable's value.
63
+ #
64
+ # If the callable is a `Question`, the object returned by this method will
65
+ # also be a `Question` (a `ValidatedQuestion`, to be precise). This
66
+ # ensures that `is_a?(Question)` remains true even after the validation
67
+ # wrapper is applied. This is needed so that `Configuration#is_question?`
68
+ # works as expected.
69
+ #
70
+ def assert_valid_later(key, callable)
71
+ validation_callback = lambda do
72
+ value = callable.call
58
73
  assert_valid_now(key, value)
59
74
  value
60
75
  end
76
+
77
+ if callable.is_a?(Question)
78
+ ValidatedQuestion.new(validation_callback)
79
+ else
80
+ validation_callback
81
+ end
61
82
  end
62
83
 
63
84
  # Runs all validation rules registered for the given key against the
64
85
  # user-supplied value for that variable. If no validator raises an
65
86
  # exception, the value is assumed to be valid.
66
87
  def assert_valid_now(key, value)
67
- return unless validators.key?(key)
68
-
69
88
  validators[key].each do |validator|
70
89
  validator.call(key, value)
71
90
  end
72
91
  end
92
+
93
+ def assert_value_or_block_not_both(value, block)
94
+ return if value.nil? || block.nil?
95
+ raise Capistrano::ValidationError,
96
+ "Value and block both passed to Configuration#set"
97
+ end
98
+
99
+ class ValidatedQuestion < Question
100
+ def initialize(validator)
101
+ @validator = validator
102
+ end
103
+
104
+ def call
105
+ @validator.call
106
+ end
107
+ end
73
108
  end
74
109
  end
75
110
  end
@@ -35,7 +35,6 @@ module Capistrano
35
35
  end
36
36
 
37
37
  def set(key, value=nil, &block)
38
- assert_value_or_block_not_both(value, block)
39
38
  @trusted_keys << key if trusted?
40
39
  remember_location(key)
41
40
  values[key] = block || value
@@ -104,13 +103,6 @@ module Capistrano
104
103
  (locations[key] ||= []) << location
105
104
  end
106
105
 
107
- def assert_value_or_block_not_both(value, block)
108
- unless value.nil? || block.nil?
109
- raise Capistrano::ValidationError,
110
- "Value and block both passed to Configuration#set"
111
- end
112
- end
113
-
114
106
  def trace_set(key)
115
107
  return unless fetch(:print_config_variables, false)
116
108
  puts "Config variable set: #{key.inspect} => #{values[key].inspect}"