capistrano 3.9.0 → 3.15.0

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.
Files changed (54) hide show
  1. checksums.yaml +5 -5
  2. data/.github/pull_request_template.md +0 -4
  3. data/.github/release-drafter.yml +17 -0
  4. data/.github/workflows/push.yml +12 -0
  5. data/.rubocop.yml +1 -0
  6. data/.travis.yml +10 -7
  7. data/CHANGELOG.md +1 -589
  8. data/DEVELOPMENT.md +1 -1
  9. data/Dangerfile +1 -1
  10. data/Gemfile +33 -1
  11. data/LICENSE.txt +1 -1
  12. data/README.md +7 -3
  13. data/RELEASING.md +3 -3
  14. data/Rakefile +5 -0
  15. data/capistrano.gemspec +8 -3
  16. data/features/deploy.feature +16 -0
  17. data/features/step_definitions/assertions.rb +2 -2
  18. data/features/step_definitions/setup.rb +6 -4
  19. data/lib/capistrano/configuration/host_filter.rb +1 -2
  20. data/lib/capistrano/configuration/question.rb +18 -3
  21. data/lib/capistrano/configuration/role_filter.rb +1 -2
  22. data/lib/capistrano/configuration.rb +7 -3
  23. data/lib/capistrano/doctor/servers_doctor.rb +1 -1
  24. data/lib/capistrano/doctor/variables_doctor.rb +10 -3
  25. data/lib/capistrano/dsl/paths.rb +2 -2
  26. data/lib/capistrano/dsl.rb +1 -1
  27. data/lib/capistrano/i18n.rb +4 -0
  28. data/lib/capistrano/immutable_task.rb +3 -2
  29. data/lib/capistrano/scm/git.rb +6 -4
  30. data/lib/capistrano/scm/tasks/git.rake +7 -7
  31. data/lib/capistrano/tasks/deploy.rake +16 -6
  32. data/lib/capistrano/templates/deploy.rb.erb +6 -3
  33. data/lib/capistrano/templates/stage.rb.erb +1 -1
  34. data/lib/capistrano/version.rb +1 -1
  35. data/spec/integration/dsl_spec.rb +5 -3
  36. data/spec/lib/capistrano/application_spec.rb +16 -40
  37. data/spec/lib/capistrano/configuration/host_filter_spec.rb +10 -5
  38. data/spec/lib/capistrano/configuration/plugin_installer_spec.rb +1 -1
  39. data/spec/lib/capistrano/configuration/question_spec.rb +39 -10
  40. data/spec/lib/capistrano/configuration/scm_resolver_spec.rb +3 -2
  41. data/spec/lib/capistrano/doctor/environment_doctor_spec.rb +1 -1
  42. data/spec/lib/capistrano/doctor/gems_doctor_spec.rb +1 -1
  43. data/spec/lib/capistrano/doctor/servers_doctor_spec.rb +1 -1
  44. data/spec/lib/capistrano/doctor/variables_doctor_spec.rb +1 -1
  45. data/spec/lib/capistrano/dsl/paths_spec.rb +30 -0
  46. data/spec/lib/capistrano/dsl/task_enhancements_spec.rb +6 -6
  47. data/spec/lib/capistrano/dsl_spec.rb +5 -5
  48. data/spec/lib/capistrano/immutable_task_spec.rb +1 -1
  49. data/spec/lib/capistrano/plugin_spec.rb +2 -2
  50. data/spec/lib/capistrano/scm/git_spec.rb +16 -5
  51. data/spec/lib/capistrano/version_validator_spec.rb +23 -0
  52. data/spec/spec_helper.rb +13 -0
  53. data/spec/support/test_app.rb +8 -3
  54. metadata +15 -23
@@ -3,12 +3,14 @@ require "spec_helper"
3
3
  module Capistrano
4
4
  class Configuration
5
5
  describe Question do
6
- let(:question) { Question.new(key, default, options) }
7
- let(:question_without_echo) { Question.new(key, default, echo: false) }
8
- let(:question_without_default) { Question.new(key, nil) }
6
+ let(:question) { Question.new(key, default, stdin: stdin) }
7
+ let(:question_without_echo) { Question.new(key, default, echo: false, stdin: stdin) }
8
+ let(:question_without_default) { Question.new(key, nil, stdin: stdin) }
9
+ let(:question_prompt) { Question.new(key, default, stdin: stdin, prompt: "Your favorite branch") }
10
+ let(:question_prompt_without_default) { Question.new(key, nil, stdin: stdin, prompt: "Your favorite branch") }
9
11
  let(:default) { :default }
10
12
  let(:key) { :branch }
11
- let(:options) { nil }
13
+ let(:stdin) { stub(tty?: true) }
12
14
 
13
15
  describe ".new" do
14
16
  it "takes a key, default, options" do
@@ -22,15 +24,15 @@ module Capistrano
22
24
 
23
25
  it "returns the echoed value" do
24
26
  $stdout.expects(:print).with("Please enter branch (default): ")
25
- $stdin.expects(:gets).returns(branch)
26
- $stdin.expects(:noecho).never
27
+ stdin.expects(:gets).returns(branch)
28
+ stdin.expects(:noecho).never
27
29
 
28
30
  expect(question.call).to eq(branch)
29
31
  end
30
32
 
31
33
  it "returns the value but does not echo it" do
32
34
  $stdout.expects(:print).with("Please enter branch (default): ")
33
- $stdin.expects(:noecho).returns(branch)
35
+ stdin.expects(:noecho).returns(branch)
34
36
  $stdout.expects(:print).with("\n")
35
37
 
36
38
  expect(question_without_echo.call).to eq(branch)
@@ -38,11 +40,27 @@ module Capistrano
38
40
 
39
41
  it "returns the value but has no default between parenthesis" do
40
42
  $stdout.expects(:print).with("Please enter branch: ")
41
- $stdin.expects(:gets).returns(branch)
42
- $stdin.expects(:noecho).never
43
+ stdin.expects(:gets).returns(branch)
44
+ stdin.expects(:noecho).never
43
45
 
44
46
  expect(question_without_default.call).to eq(branch)
45
47
  end
48
+
49
+ it "uses prompt and returns the value" do
50
+ $stdout.expects(:print).with("Your favorite branch (default): ")
51
+ stdin.expects(:gets).returns(branch)
52
+ stdin.expects(:noecho).never
53
+
54
+ expect(question_prompt.call).to eq(branch)
55
+ end
56
+
57
+ it "uses prompt and returns the value but has no default between parenthesis" do
58
+ $stdout.expects(:print).with("Your favorite branch: ")
59
+ stdin.expects(:gets).returns(branch)
60
+ stdin.expects(:noecho).never
61
+
62
+ expect(question_prompt_without_default.call).to eq(branch)
63
+ end
46
64
  end
47
65
 
48
66
  context "value is not entered" do
@@ -50,13 +68,24 @@ module Capistrano
50
68
 
51
69
  before do
52
70
  $stdout.expects(:print).with("Please enter branch (default): ")
53
- $stdin.expects(:gets).returns("")
71
+ stdin.expects(:gets).returns("")
54
72
  end
55
73
 
56
74
  it "returns the default as the value" do
57
75
  expect(question.call).to eq(branch)
58
76
  end
59
77
  end
78
+
79
+ context "tty unavailable", capture_io: true do
80
+ before do
81
+ stdin.expects(:gets).never
82
+ stdin.expects(:tty?).returns(false)
83
+ end
84
+
85
+ it "returns the default as the value" do
86
+ expect(question.call).to eq(default)
87
+ end
88
+ end
60
89
  end
61
90
  end
62
91
  end
@@ -1,4 +1,5 @@
1
1
  require "spec_helper"
2
+ require "capistrano/scm"
2
3
 
3
4
  module Capistrano
4
5
  class Configuration
@@ -24,12 +25,12 @@ module Capistrano
24
25
  expect { resolver.resolve }.to output(/will not load the git scm/i).to_stderr
25
26
  end
26
27
 
27
- it "activates the git scm" do
28
+ it "activates the git scm", capture_io: true do
28
29
  resolver.resolve
29
30
  expect(Rake::Task["git:wrapper"]).not_to be_nil
30
31
  end
31
32
 
32
- it "sets :scm to :git" do
33
+ it "sets :scm to :git", capture_io: true do
33
34
  resolver.resolve
34
35
  expect(fetch(:scm)).to eq(:git)
35
36
  end
@@ -29,7 +29,7 @@ module Capistrano
29
29
  Rake::Task.clear
30
30
  end
31
31
 
32
- it "has an doctor:environment task that calls EnvironmentDoctor" do
32
+ it "has an doctor:environment task that calls EnvironmentDoctor", capture_io: true do
33
33
  EnvironmentDoctor.any_instance.expects(:call)
34
34
  Rake::Task["doctor:environment"].invoke
35
35
  end
@@ -53,7 +53,7 @@ module Capistrano
53
53
  Rake::Task.clear
54
54
  end
55
55
 
56
- it "has an doctor:gems task that calls GemsDoctor" do
56
+ it "has an doctor:gems task that calls GemsDoctor", capture_io: true do
57
57
  GemsDoctor.any_instance.expects(:call)
58
58
  Rake::Task["doctor:gems"].invoke
59
59
  end
@@ -71,7 +71,7 @@ module Capistrano
71
71
  Rake::Task.clear
72
72
  end
73
73
 
74
- it "has an doctor:servers task that calls ServersDoctor" do
74
+ it "has an doctor:servers task that calls ServersDoctor", capture_io: true do
75
75
  ServersDoctor.any_instance.expects(:call)
76
76
  Rake::Task["doctor:servers"].invoke
77
77
  end
@@ -74,7 +74,7 @@ module Capistrano
74
74
  Rake::Task.clear
75
75
  end
76
76
 
77
- it "has an doctor:variables task that calls VariablesDoctor" do
77
+ it "has an doctor:variables task that calls VariablesDoctor", capture_io: true do
78
78
  VariablesDoctor.any_instance.expects(:call)
79
79
  Rake::Task["doctor:variables"].invoke
80
80
  end
@@ -123,6 +123,36 @@ describe Capistrano::DSL::Paths do
123
123
  end
124
124
  end
125
125
 
126
+ describe "#releases_path" do
127
+ subject { paths.releases_path }
128
+
129
+ context "with custom releases directory" do
130
+ before do
131
+ paths.expects(:fetch).with(:releases_directory, "releases").returns("test123")
132
+ paths.expects(:fetch).with(:deploy_to).returns("/var/www")
133
+ end
134
+
135
+ it "returns the releases path with the custom directory" do
136
+ expect(subject.to_s).to eq "/var/www/test123"
137
+ end
138
+ end
139
+ end
140
+
141
+ describe "#shared_path" do
142
+ subject { paths.shared_path }
143
+
144
+ context "with custom shared directory" do
145
+ before do
146
+ paths.expects(:fetch).with(:shared_directory, "shared").returns("test123")
147
+ paths.expects(:fetch).with(:deploy_to).returns("/var/www")
148
+ end
149
+
150
+ it "returns the shared path with the custom directory" do
151
+ expect(subject.to_s).to eq "/var/www/test123"
152
+ end
153
+ end
154
+ end
155
+
126
156
  describe "#deploy_config_path" do
127
157
  subject { dsl.deploy_config_path.to_s }
128
158
 
@@ -35,7 +35,7 @@ module Capistrano
35
35
  end
36
36
  end
37
37
 
38
- it "invokes in proper order if define after than before" do
38
+ it "invokes in proper order if define after than before", capture_io: true do
39
39
  task_enhancements.after("task", "after_task")
40
40
  task_enhancements.before("task", "before_task")
41
41
 
@@ -44,7 +44,7 @@ module Capistrano
44
44
  expect(order).to eq(%w(before_task task after_task))
45
45
  end
46
46
 
47
- it "invokes in proper order if define before than after" do
47
+ it "invokes in proper order if define before than after", capture_io: true do
48
48
  task_enhancements.before("task", "before_task")
49
49
  task_enhancements.after("task", "after_task")
50
50
 
@@ -53,7 +53,7 @@ module Capistrano
53
53
  expect(order).to eq(%w(before_task task after_task))
54
54
  end
55
55
 
56
- it "invokes in proper order when referring to as-yet undefined tasks" do
56
+ it "invokes in proper order when referring to as-yet undefined tasks", capture_io: true do
57
57
  task_enhancements.after("task", "not_loaded_task")
58
58
 
59
59
  Rake::Task.define_task("not_loaded_task") do
@@ -65,7 +65,7 @@ module Capistrano
65
65
  expect(order).to eq(%w(task not_loaded_task))
66
66
  end
67
67
 
68
- it "invokes in proper order and with arguments and block" do
68
+ it "invokes in proper order and with arguments and block", capture_io: true do
69
69
  task_enhancements.after("task", "after_task_custom", :order) do |_t, _args|
70
70
  order.push "after_task"
71
71
  end
@@ -79,7 +79,7 @@ module Capistrano
79
79
  expect(order).to eq(%w(before_task task after_task))
80
80
  end
81
81
 
82
- it "invokes using the correct namespace when defined within a namespace" do
82
+ it "invokes using the correct namespace when defined within a namespace", capture_io: true do
83
83
  Rake.application.in_namespace("namespace") do
84
84
  Rake::Task.define_task("task") do |t|
85
85
  order.push(t.name)
@@ -99,7 +99,7 @@ module Capistrano
99
99
  )
100
100
  end
101
101
 
102
- it "raises a sensible error if the task isn't found" do
102
+ it "raises a sensible error if the task isn't found", capture_io: true do
103
103
  task_enhancements.after("task", "non_existent_task")
104
104
  expect { Rake::Task["task"].invoke order }.to raise_error(ArgumentError, 'Task "non_existent_task" not found')
105
105
  end
@@ -60,7 +60,7 @@ module Capistrano
60
60
  end
61
61
  end
62
62
 
63
- it "prints helpful message to stderr" do
63
+ it "prints helpful message to stderr", capture_io: true do
64
64
  expect do
65
65
  expect do
66
66
  task.invoke
@@ -72,7 +72,7 @@ module Capistrano
72
72
 
73
73
  describe "#invoke" do
74
74
  context "reinvoking" do
75
- it "will not reenable invoking task" do
75
+ it "will not reenable invoking task", capture_io: true do
76
76
  counter = 0
77
77
 
78
78
  Rake::Task.define_task("A") do
@@ -85,7 +85,7 @@ module Capistrano
85
85
  end.to change { counter }.by(1)
86
86
  end
87
87
 
88
- it "will print a message on stderr" do
88
+ it "will print a message on stderr", capture_io: true do
89
89
  Rake::Task.define_task("B")
90
90
 
91
91
  expect do
@@ -98,7 +98,7 @@ module Capistrano
98
98
 
99
99
  describe "#invoke!" do
100
100
  context "reinvoking" do
101
- it "will reenable invoking task" do
101
+ it "will reenable invoking task", capture_io: true do
102
102
  counter = 0
103
103
 
104
104
  Rake::Task.define_task("C") do
@@ -111,7 +111,7 @@ module Capistrano
111
111
  end.to change { counter }.by(2)
112
112
  end
113
113
 
114
- it "will not print a message on stderr" do
114
+ it "will not print a message on stderr", capture_io: true do
115
115
  Rake::Task.define_task("D")
116
116
 
117
117
  expect do
@@ -16,7 +16,7 @@ module Capistrano
16
16
  load_defaults.extend(Capistrano::ImmutableTask)
17
17
 
18
18
  $stderr.expects(:puts).with do |message|
19
- message =~ /^WARNING: load:defaults has already been invoked/
19
+ message =~ /^ERROR: load:defaults has already been invoked/
20
20
  end
21
21
 
22
22
  expect do
@@ -62,14 +62,14 @@ module Capistrano
62
62
  dummy.expects(:set_defaults).never
63
63
  end
64
64
 
65
- it "calls set_defaults during load:defaults" do
65
+ it "calls set_defaults during load:defaults", capture_io: true do
66
66
  dummy = DummyPlugin.new
67
67
  dummy.expects(:set_defaults).once
68
68
  install_plugin(dummy)
69
69
  Rake::Task["load:defaults"].invoke
70
70
  end
71
71
 
72
- it "is able to load tasks from a .rake file" do
72
+ it "is able to load tasks from a .rake file", capture_io: true do
73
73
  install_plugin(ExternalTasksPlugin)
74
74
  Rake::Task["plugin_test"].invoke
75
75
  expect(fetch(:plugin_result)).to eq("hello")
@@ -28,13 +28,24 @@ module Capistrano
28
28
  end
29
29
 
30
30
  describe "#set_defaults" do
31
- it "makes git_wrapper_path using application, stage, and local_user" do
31
+ it "makes git_wrapper_path using a random hex value" do
32
32
  env.set(:tmp_dir, "/tmp")
33
- env.set(:application, "my_app")
34
- env.set(:stage, "staging")
35
- env.set(:local_user, "(Git Web User) via ShipIt")
36
33
  subject.set_defaults
37
- expect(env.fetch(:git_wrapper_path)).to eq("/tmp/git-ssh-my_app-staging-(Git Web User) via ShipIt.sh")
34
+ expect(env.fetch(:git_wrapper_path)).to match(%r{/tmp/git-ssh-\h{20}\.sh})
35
+ end
36
+
37
+ it "makes git_max_concurrent_connections" do
38
+ subject.set_defaults
39
+ expect(env.fetch(:git_max_concurrent_connections)).to eq(10)
40
+ env.set(:git_max_concurrent_connections, 7)
41
+ expect(env.fetch(:git_max_concurrent_connections)).to eq(7)
42
+ end
43
+
44
+ it "makes git_wait_interval" do
45
+ subject.set_defaults
46
+ expect(env.fetch(:git_wait_interval)).to eq(0)
47
+ env.set(:git_wait_interval, 5)
48
+ expect(env.fetch(:git_wait_interval)).to eq(5)
38
49
  end
39
50
  end
40
51
 
@@ -89,6 +89,29 @@ module Capistrano
89
89
  end
90
90
  end
91
91
  end
92
+
93
+ context "with multiple versions" do
94
+ let(:current_version) { "3.5.9" }
95
+
96
+ context "valid" do
97
+ let(:version) { [">= 3.5.0", "< 3.5.10"] }
98
+ it { is_expected.to be_truthy }
99
+ end
100
+
101
+ context "invalid" do
102
+ let(:version) { [">= 3.5.0", "< 3.5.8"] }
103
+ it "fails" do
104
+ expect { subject }.to raise_error(RuntimeError)
105
+ end
106
+ end
107
+
108
+ context "invalid" do
109
+ let(:version) { ["> 3.5.9", "< 3.5.13"] }
110
+ it "fails" do
111
+ expect { subject }.to raise_error(RuntimeError)
112
+ end
113
+ end
114
+ end
92
115
  end
93
116
  end
94
117
  end
data/spec/spec_helper.rb CHANGED
@@ -13,4 +13,17 @@ RSpec.configure do |config|
13
13
  config.raise_errors_for_deprecations!
14
14
  config.mock_framework = :mocha
15
15
  config.order = "random"
16
+
17
+ config.around(:example, capture_io: true) do |example|
18
+ begin
19
+ Rake.application.options.trace_output = StringIO.new
20
+ $stdout = StringIO.new
21
+ $stderr = StringIO.new
22
+ example.run
23
+ ensure
24
+ Rake.application.options.trace_output = STDERR
25
+ $stdout = STDOUT
26
+ $stderr = STDERR
27
+ end
28
+ end
16
29
  end
@@ -185,12 +185,17 @@ module TestApp
185
185
  FileUtils.mv(config_path, location)
186
186
  end
187
187
 
188
- def git_wrapper_path
189
- "/tmp/git-ssh-my_app_name-#{stage}-#{current_user}.sh"
188
+ def git_wrapper_path_glob
189
+ "/tmp/git-ssh-*.sh"
190
190
  end
191
191
 
192
192
  def with_clean_bundler_env(&block)
193
193
  return yield unless defined?(Bundler)
194
- Bundler.with_clean_env(&block)
194
+
195
+ if Bundler.respond_to?(:with_unbundled_env)
196
+ Bundler.with_unbundled_env(&block)
197
+ else
198
+ Bundler.with_clean_env(&block)
199
+ end
195
200
  end
196
201
  end
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: capistrano
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.9.0
4
+ version: 3.15.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tom Clements
8
8
  - Lee Hambley
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2017-07-28 00:00:00.000000000 Z
12
+ date: 2021-01-05 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: airbrussh
@@ -67,20 +67,6 @@ dependencies:
67
67
  - - ">="
68
68
  - !ruby/object:Gem::Version
69
69
  version: 1.9.0
70
- - !ruby/object:Gem::Dependency
71
- name: danger
72
- requirement: !ruby/object:Gem::Requirement
73
- requirements:
74
- - - ">="
75
- - !ruby/object:Gem::Version
76
- version: '0'
77
- type: :development
78
- prerelease: false
79
- version_requirements: !ruby/object:Gem::Requirement
80
- requirements:
81
- - - ">="
82
- - !ruby/object:Gem::Version
83
- version: '0'
84
70
  - !ruby/object:Gem::Dependency
85
71
  name: mocha
86
72
  requirement: !ruby/object:Gem::Requirement
@@ -136,6 +122,8 @@ extra_rdoc_files: []
136
122
  files:
137
123
  - ".github/issue_template.md"
138
124
  - ".github/pull_request_template.md"
125
+ - ".github/release-drafter.yml"
126
+ - ".github/workflows/push.yml"
139
127
  - ".gitignore"
140
128
  - ".rubocop.yml"
141
129
  - ".travis.yml"
@@ -265,11 +253,16 @@ files:
265
253
  - spec/support/tasks/plugin.rake
266
254
  - spec/support/tasks/root.rake
267
255
  - spec/support/test_app.rb
268
- homepage: http://capistranorb.com/
256
+ homepage: https://capistranorb.com/
269
257
  licenses:
270
258
  - MIT
271
- metadata: {}
272
- post_install_message:
259
+ metadata:
260
+ bug_tracker_uri: https://github.com/capistrano/capistrano/issues
261
+ changelog_uri: https://github.com/capistrano/capistrano/releases
262
+ source_code_uri: https://github.com/capistrano/capistrano
263
+ homepage_uri: https://capistranorb.com/
264
+ documentation_uri: https://capistranorb.com/
265
+ post_install_message:
273
266
  rdoc_options: []
274
267
  require_paths:
275
268
  - lib
@@ -284,9 +277,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
284
277
  - !ruby/object:Gem::Version
285
278
  version: '0'
286
279
  requirements: []
287
- rubyforge_project:
288
- rubygems_version: 2.6.12
289
- signing_key:
280
+ rubygems_version: 3.2.4
281
+ signing_key:
290
282
  specification_version: 4
291
283
  summary: Capistrano - Welcome to easy deployment with Ruby over SSH
292
284
  test_files: