capistrano 3.11.0 → 3.16.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 (42) hide show
  1. checksums.yaml +4 -4
  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 -651
  8. data/Dangerfile +1 -1
  9. data/Gemfile +33 -1
  10. data/LICENSE.txt +1 -1
  11. data/README.md +2 -2
  12. data/RELEASING.md +3 -3
  13. data/Rakefile +5 -0
  14. data/capistrano.gemspec +8 -3
  15. data/features/deploy.feature +6 -0
  16. data/features/step_definitions/assertions.rb +1 -1
  17. data/features/step_definitions/setup.rb +6 -4
  18. data/features/support/vagrant_helpers.rb +6 -0
  19. data/lib/capistrano/configuration/question.rb +16 -4
  20. data/lib/capistrano/dsl.rb +1 -1
  21. data/lib/capistrano/i18n.rb +2 -0
  22. data/lib/capistrano/scm/git.rb +10 -4
  23. data/lib/capistrano/scm/tasks/git.rake +8 -7
  24. data/lib/capistrano/tasks/deploy.rake +3 -2
  25. data/lib/capistrano/templates/stage.rb.erb +1 -1
  26. data/lib/capistrano/version.rb +1 -1
  27. data/spec/integration/dsl_spec.rb +5 -3
  28. data/spec/lib/capistrano/application_spec.rb +16 -40
  29. data/spec/lib/capistrano/configuration/plugin_installer_spec.rb +1 -1
  30. data/spec/lib/capistrano/configuration/question_spec.rb +31 -13
  31. data/spec/lib/capistrano/configuration/scm_resolver_spec.rb +3 -2
  32. data/spec/lib/capistrano/doctor/environment_doctor_spec.rb +1 -1
  33. data/spec/lib/capistrano/doctor/gems_doctor_spec.rb +1 -1
  34. data/spec/lib/capistrano/doctor/servers_doctor_spec.rb +1 -1
  35. data/spec/lib/capistrano/doctor/variables_doctor_spec.rb +1 -1
  36. data/spec/lib/capistrano/dsl/task_enhancements_spec.rb +6 -6
  37. data/spec/lib/capistrano/dsl_spec.rb +5 -5
  38. data/spec/lib/capistrano/plugin_spec.rb +2 -2
  39. data/spec/lib/capistrano/scm/git_spec.rb +27 -5
  40. data/spec/spec_helper.rb +13 -0
  41. data/spec/support/test_app.rb +8 -3
  42. metadata +15 -23
data/Gemfile CHANGED
@@ -4,7 +4,39 @@ source "https://rubygems.org"
4
4
  gemspec
5
5
 
6
6
  group :cucumber do
7
- gem "cucumber"
7
+ # Latest versions of cucumber don't support Ruby < 2.1
8
+ # rubocop:disable Bundler/DuplicatedGem
9
+ if Gem::Requirement.new("< 2.1").satisfied_by?(Gem::Version.new(RUBY_VERSION))
10
+ gem "cucumber", "< 3.0.1"
11
+ else
12
+ gem "cucumber"
13
+ end
14
+ # rubocop:enable Bundler/DuplicatedGem
8
15
  gem "rspec"
9
16
  gem "rspec-core", "~> 3.4.4"
10
17
  end
18
+
19
+ # Latest versions of net-ssh don't support Ruby < 2.2.6
20
+ if Gem::Requirement.new("< 2.2.6").satisfied_by?(Gem::Version.new(RUBY_VERSION))
21
+ gem "net-ssh", "< 5.0.0"
22
+ end
23
+
24
+ # Latest versions of public_suffix don't support Ruby < 2.1
25
+ if Gem::Requirement.new("< 2.1").satisfied_by?(Gem::Version.new(RUBY_VERSION))
26
+ gem "public_suffix", "< 3.0.0"
27
+ end
28
+
29
+ # Latest versions of i18n don't support Ruby < 2.4
30
+ if Gem::Requirement.new("< 2.4").satisfied_by?(Gem::Version.new(RUBY_VERSION))
31
+ gem "i18n", "< 1.3.0"
32
+ end
33
+
34
+ # Latest versions of rake don't support Ruby < 2.2
35
+ if Gem::Requirement.new("< 2.2").satisfied_by?(Gem::Version.new(RUBY_VERSION))
36
+ gem "rake", "< 13.0.0"
37
+ end
38
+
39
+ # We only run danger once on a new-ish ruby; no need to install it otherwise
40
+ if Gem::Requirement.new("> 2.4").satisfied_by?(Gem::Version.new(RUBY_VERSION))
41
+ gem "danger"
42
+ end
data/LICENSE.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License (MIT)
2
2
 
3
- Copyright (c) 2012-2018 Tom Clements, Lee Hambley
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
@@ -107,7 +107,7 @@ Add Capistrano to your project's Gemfile using `require: false`:
107
107
 
108
108
  ``` ruby
109
109
  group :development do
110
- gem "capistrano", "~> 3.11", require: false
110
+ gem "capistrano", "~> 3.16", require: false
111
111
  end
112
112
  ```
113
113
 
@@ -200,7 +200,7 @@ Contributions to Capistrano, in the form of code, documentation or idea, are gla
200
200
 
201
201
  MIT License (MIT)
202
202
 
203
- Copyright (c) 2012-2018 Tom Clements, Lee Hambley
203
+ Copyright (c) 2012-2020 Tom Clements, Lee Hambley
204
204
 
205
205
  Permission is hereby granted, free of charge, to any person obtaining a copy
206
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
- 4. Update the version in the `./README.md` Gemfile example (`gem "capistrano", "~> X.Y"`).
15
- 5. Update the `CHANGELOG`.
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
@@ -10,3 +10,8 @@ Cucumber::Rake::Task.new(:features)
10
10
 
11
11
  desc "Run RuboCop checks"
12
12
  RuboCop::RakeTask.new
13
+
14
+ Rake::Task["release"].enhance do
15
+ puts "Don't forget to publish the release on GitHub!"
16
+ system "open https://github.com/capistrano/capistrano/releases"
17
+ end
data/capistrano.gemspec CHANGED
@@ -11,8 +11,14 @@ Gem::Specification.new do |gem|
11
11
  gem.email = ["seenmyfate@gmail.com", "lee.hambley@gmail.com"]
12
12
  gem.description = "Capistrano is a utility and framework for executing commands in parallel on multiple remote machines, via SSH."
13
13
  gem.summary = "Capistrano - Welcome to easy deployment with Ruby over SSH"
14
- gem.homepage = "http://capistranorb.com/"
15
-
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
+ }
16
22
  gem.files = `git ls-files -z`.split("\x0").reject { |f| f =~ /^docs/ }
17
23
  gem.executables = %w(cap capify)
18
24
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
@@ -26,7 +32,6 @@ Gem::Specification.new do |gem|
26
32
  gem.add_dependency "rake", ">= 10.0.0"
27
33
  gem.add_dependency "sshkit", ">= 1.9.0"
28
34
 
29
- gem.add_development_dependency "danger"
30
35
  gem.add_development_dependency "mocha"
31
36
  gem.add_development_dependency "rspec"
32
37
  gem.add_development_dependency "rubocop", "0.48.1"
@@ -70,6 +70,12 @@ Feature: Deploy
70
70
  Then 3 valid releases are kept
71
71
  And the current directory will be a symlink to the release
72
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
+
73
79
  Scenario: Rolling Back
74
80
  Given I make 2 deployments
75
81
  When I run cap "deploy:rollback"
@@ -5,7 +5,7 @@ Then(/^references in the remote repo are listed$/) do
5
5
  end
6
6
 
7
7
  Then(/^git wrapper permissions are 0700$/) do
8
- permissions_test = %Q([ $(stat -c "%a" #{TestApp.git_wrapper_path.shellescape}) == "700" ])
8
+ permissions_test = %Q([ $(stat -c "%a" #{TestApp.git_wrapper_path_glob}) == "700" ])
9
9
  _stdout, _stderr, status = vagrant_cli_command("ssh -c #{permissions_test.shellescape}")
10
10
 
11
11
  expect(status).to be_success
@@ -80,10 +80,12 @@ end
80
80
 
81
81
  Given(/^(\d+) valid existing releases$/) do |num|
82
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
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(' ')}")
87
89
  end
88
90
  end
89
91
 
@@ -30,6 +30,12 @@ module VagrantHelpers
30
30
  return [stdout, stderr] if status.success?
31
31
  raise VagrantSSHCommandError, status
32
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
33
39
  end
34
40
 
35
41
  World(VagrantHelpers)
@@ -36,12 +36,12 @@ module Capistrano
36
36
  end
37
37
 
38
38
  def gets
39
- return unless $stdin.tty?
39
+ return unless stdin.tty?
40
40
 
41
41
  if echo?
42
- $stdin.gets
42
+ stdin.gets
43
43
  else
44
- $stdin.noecho(&:gets).tap { $stdout.print "\n" }
44
+ stdin.noecho(&:gets).tap { $stdout.print "\n" }
45
45
  end
46
46
  rescue Errno::EIO
47
47
  # when stdio gets closed
@@ -49,7 +49,11 @@ module Capistrano
49
49
  end
50
50
 
51
51
  def question
52
- if default.nil?
52
+ if prompt && default.nil?
53
+ I18n.t(:question_prompt, key: prompt, scope: :capistrano)
54
+ elsif prompt
55
+ I18n.t(:question_prompt_default, key: prompt, default_value: default, scope: :capistrano)
56
+ elsif default.nil?
53
57
  I18n.t(:question, key: key, scope: :capistrano)
54
58
  else
55
59
  I18n.t(:question_default, key: key, default_value: default, scope: :capistrano)
@@ -59,6 +63,14 @@ module Capistrano
59
63
  def echo?
60
64
  (options || {}).fetch(:echo, true)
61
65
  end
66
+
67
+ def stdin
68
+ (options || {}).fetch(:stdin, $stdin)
69
+ end
70
+
71
+ def prompt
72
+ (options || {}).fetch(:prompt, nil)
73
+ end
62
74
  end
63
75
  end
64
76
  end
@@ -33,7 +33,7 @@ module Capistrano
33
33
  end
34
34
 
35
35
  def t(key, options={})
36
- I18n.t(key, options.merge(scope: :capistrano))
36
+ I18n.t(key, **options.merge(scope: :capistrano))
37
37
  end
38
38
 
39
39
  def scm
@@ -12,6 +12,8 @@ en = {
12
12
  written_file: "create %{file}",
13
13
  question: "Please enter %{key}: ",
14
14
  question_default: "Please enter %{key} (%{default_value}): ",
15
+ question_prompt: "%{key}: ",
16
+ question_prompt_default: "%{key} (%{default_value}): ",
15
17
  keeping_releases: "Keeping %{keep_releases} of %{releases} deployed releases on %{host}",
16
18
  skip_cleanup: "Skipping cleanup of invalid releases on %{host}; unexpected foldername found (should be timestamp)",
17
19
  wont_delete_current_release: "Current release was marked for being removed but it's going to be skipped on %{host}",
@@ -1,5 +1,6 @@
1
1
  require "capistrano/scm/plugin"
2
2
  require "cgi"
3
+ require "securerandom"
3
4
  require "shellwords"
4
5
  require "uri"
5
6
 
@@ -7,10 +8,9 @@ class Capistrano::SCM::Git < Capistrano::SCM::Plugin
7
8
  def set_defaults
8
9
  set_if_empty :git_shallow_clone, false
9
10
  set_if_empty :git_wrapper_path, lambda {
10
- # Try to avoid permissions issues when multiple users deploy the same app
11
- # by using different file names in the same dir for each deployer and stage.
12
- suffix = %i(application stage local_user).map { |key| fetch(key).to_s }.join("-")
13
- "#{fetch(:tmp_dir)}/git-ssh-#{suffix}.sh"
11
+ # Use a unique name that won't collide with other deployments, and
12
+ # that cannot be guessed by other processes that have access to /tmp.
13
+ "#{fetch(:tmp_dir)}/git-ssh-#{SecureRandom.hex(10)}.sh"
14
14
  }
15
15
  set_if_empty :git_environmental_variables, lambda {
16
16
  {
@@ -18,6 +18,8 @@ class Capistrano::SCM::Git < Capistrano::SCM::Plugin
18
18
  git_ssh: fetch(:git_wrapper_path)
19
19
  }
20
20
  }
21
+ set_if_empty :git_max_concurrent_connections, 10
22
+ set_if_empty :git_wait_interval, 0
21
23
  end
22
24
 
23
25
  def register_hooks
@@ -58,6 +60,10 @@ class Capistrano::SCM::Git < Capistrano::SCM::Plugin
58
60
  end
59
61
  end
60
62
 
63
+ def verify_commit
64
+ git :"verify-commit", fetch_revision
65
+ end
66
+
61
67
  def archive_to_release_path
62
68
  if (tree = fetch(:repo_tree))
63
69
  tree = tree.slice %r#^/?(.*?)/?$#, 1
@@ -4,9 +4,9 @@ git_plugin = self
4
4
  namespace :git do
5
5
  desc "Upload the git wrapper script, this script guarantees that we can script git without getting an interactive prompt"
6
6
  task :wrapper do
7
- on release_roles :all do
7
+ on release_roles(:all), in: :groups, limit: fetch(:git_max_concurrent_connections), wait: fetch(:git_wait_interval) do
8
8
  execute :mkdir, "-p", File.dirname(fetch(:git_wrapper_path)).shellescape
9
- upload! StringIO.new("#!/bin/sh -e\nexec /usr/bin/ssh -o PasswordAuthentication=no -o StrictHostKeyChecking=no \"$@\"\n"), fetch(:git_wrapper_path)
9
+ upload! StringIO.new("#!/bin/sh -e\nexec /usr/bin/env ssh -o PasswordAuthentication=no -o StrictHostKeyChecking=no \"$@\"\n"), fetch(:git_wrapper_path)
10
10
  execute :chmod, "700", fetch(:git_wrapper_path).shellescape
11
11
  end
12
12
  end
@@ -14,7 +14,7 @@ namespace :git do
14
14
  desc "Check that the repository is reachable"
15
15
  task check: :'git:wrapper' do
16
16
  fetch(:branch)
17
- on release_roles :all do
17
+ on release_roles(:all), in: :groups, limit: fetch(:git_max_concurrent_connections), wait: fetch(:git_wait_interval) do
18
18
  with fetch(:git_environmental_variables) do
19
19
  git_plugin.check_repo_is_reachable
20
20
  end
@@ -23,7 +23,7 @@ namespace :git do
23
23
 
24
24
  desc "Clone the repo to the cache"
25
25
  task clone: :'git:wrapper' do
26
- on release_roles :all do
26
+ on release_roles(:all), in: :groups, limit: fetch(:git_max_concurrent_connections), wait: fetch(:git_wait_interval) do
27
27
  if git_plugin.repo_mirror_exists?
28
28
  info t(:mirror_exists, at: repo_path)
29
29
  else
@@ -38,10 +38,11 @@ namespace :git do
38
38
 
39
39
  desc "Update the repo mirror to reflect the origin state"
40
40
  task update: :'git:clone' do
41
- on release_roles :all do
41
+ on release_roles(:all), in: :groups, limit: fetch(:git_max_concurrent_connections), wait: fetch(:git_wait_interval) do
42
42
  within repo_path do
43
43
  with fetch(:git_environmental_variables) do
44
44
  git_plugin.update_mirror
45
+ git_plugin.verify_commit if fetch(:git_verify_commit)
45
46
  end
46
47
  end
47
48
  end
@@ -49,7 +50,7 @@ namespace :git do
49
50
 
50
51
  desc "Copy repo to releases"
51
52
  task create_release: :'git:update' do
52
- on release_roles :all do
53
+ on release_roles(:all), in: :groups, limit: fetch(:git_max_concurrent_connections), wait: fetch(:git_wait_interval) do
53
54
  with fetch(:git_environmental_variables) do
54
55
  within repo_path do
55
56
  execute :mkdir, "-p", release_path
@@ -61,7 +62,7 @@ namespace :git do
61
62
 
62
63
  desc "Determine the revision that will be deployed"
63
64
  task :set_current_revision do
64
- on release_roles :all do
65
+ on release_roles(:all), in: :groups, limit: fetch(:git_max_concurrent_connections), wait: fetch(:git_wait_interval) do
65
66
  within repo_path do
66
67
  with fetch(:git_environmental_variables) do
67
68
  set :current_revision, git_plugin.fetch_revision
@@ -168,8 +168,9 @@ namespace :deploy do
168
168
  debug t(:no_current_release, host: host.to_s)
169
169
  end
170
170
  if directories.any?
171
- directories_str = directories.join(" ")
172
- execute :rm, "-rf", directories_str
171
+ directories.each_slice(100) do |directories_batch|
172
+ execute :rm, "-rf", *directories_batch
173
+ end
173
174
  else
174
175
  info t(:no_old_releases, host: host.to_s, keep_releases: fetch(:keep_releases))
175
176
  end
@@ -42,7 +42,7 @@
42
42
  # Global options
43
43
  # --------------
44
44
  # set :ssh_options, {
45
- # keys: %w(/home/rlisowski/.ssh/id_rsa),
45
+ # keys: %w(/home/user_name/.ssh/id_rsa),
46
46
  # forward_agent: false,
47
47
  # auth_methods: %w(password)
48
48
  # }
@@ -1,3 +1,3 @@
1
1
  module Capistrano
2
- VERSION = "3.11.0".freeze
2
+ VERSION = "3.16.0".freeze
3
3
  end
@@ -356,14 +356,16 @@ describe Capistrano::DSL do
356
356
  end
357
357
 
358
358
  describe "asking for a variable" do
359
+ let(:stdin) { stub(tty?: true) }
360
+
359
361
  before do
360
- dsl.ask(:scm, :svn)
362
+ dsl.ask(:scm, :svn, stdin: stdin)
361
363
  $stdout.stubs(:print)
362
364
  end
363
365
 
364
366
  context "variable is provided" do
365
367
  before do
366
- $stdin.expects(:gets).returns("git")
368
+ stdin.expects(:gets).returns("git")
367
369
  end
368
370
 
369
371
  it "sets the input as the variable" do
@@ -373,7 +375,7 @@ describe Capistrano::DSL do
373
375
 
374
376
  context "variable is not provided" do
375
377
  before do
376
- $stdin.expects(:gets).returns("")
378
+ stdin.expects(:gets).returns("")
377
379
  end
378
380
 
379
381
  it "sets the variable as the default" do
@@ -5,46 +5,40 @@ describe Capistrano::Application do
5
5
 
6
6
  it "provides a --format option which enables the choice of output formatting"
7
7
 
8
- let(:help_output) do
9
- out, _err = capture_io do
10
- flags "--help", "-h"
11
- end
12
- out
13
- end
14
-
15
- it "displays documentation URL as help banner" do
16
- expect(help_output.lines.first).to match(/capistranorb.com/)
8
+ it "displays documentation URL as help banner", capture_io: true do
9
+ flags "--help", "-h"
10
+ expect($stdout.string.each_line.first).to match(/capistranorb.com/)
17
11
  end
18
12
 
19
13
  %w(quiet silent verbose).each do |switch|
20
- it "doesn't include --#{switch} in help" do
21
- expect(help_output).not_to match(/--#{switch}/)
14
+ it "doesn't include --#{switch} in help", capture_io: true do
15
+ flags "--help", "-h"
16
+ expect($stdout.string).not_to match(/--#{switch}/)
22
17
  end
23
18
  end
24
19
 
25
- it "overrides the rake method, but still prints the rake version" do
26
- out, _err = capture_io do
27
- flags "--version", "-V"
28
- end
20
+ it "overrides the rake method, but still prints the rake version", capture_io: true do
21
+ flags "--version", "-V"
22
+ out = $stdout.string
29
23
  expect(out).to match(/\bCapistrano Version\b/)
30
24
  expect(out).to match(/\b#{Capistrano::VERSION}\b/)
31
25
  expect(out).to match(/\bRake Version\b/)
32
26
  expect(out).to match(/\b#{Rake::VERSION}\b/)
33
27
  end
34
28
 
35
- it "overrides the rake method, and sets the sshkit_backend to SSHKit::Backend::Printer" do
36
- capture_io do
37
- flags "--dry-run", "-n"
38
- end
29
+ it "overrides the rake method, and sets the sshkit_backend to SSHKit::Backend::Printer", capture_io: true do
30
+ flags "--dry-run", "-n"
39
31
  sshkit_backend = Capistrano::Configuration.fetch(:sshkit_backend)
40
32
  expect(sshkit_backend).to eq(SSHKit::Backend::Printer)
41
33
  end
42
34
 
43
- it "enables printing all config variables on command line parameter" do
44
- capture_io do
35
+ it "enables printing all config variables on command line parameter", capture_io: true do
36
+ begin
45
37
  flags "--print-config-variables", "-p"
38
+ expect(Capistrano::Configuration.fetch(:print_config_variables)).to be true
39
+ ensure
40
+ Capistrano::Configuration.reset!
46
41
  end
47
- expect(Capistrano::Configuration.fetch(:print_config_variables)).to be true
48
42
  end
49
43
 
50
44
  def flags(*sets)
@@ -63,22 +57,4 @@ describe Capistrano::Application do
63
57
  subject.run
64
58
  subject.options
65
59
  end
66
-
67
- def capture_io
68
- require "stringio"
69
-
70
- orig_stdout = $stdout
71
- orig_stderr = $stderr
72
- captured_stdout = StringIO.new
73
- captured_stderr = StringIO.new
74
- $stdout = captured_stdout
75
- $stderr = captured_stderr
76
-
77
- yield
78
-
79
- return captured_stdout.string, captured_stderr.string
80
- ensure
81
- $stdout = orig_stdout
82
- $stderr = orig_stderr
83
- end
84
60
  end
@@ -49,7 +49,7 @@ module Capistrano
49
49
  expect(task.prerequisites).to eq([:example_prerequisite])
50
50
  end
51
51
 
52
- it "sets defaults when load:defaults is invoked" do
52
+ it "sets defaults when load:defaults is invoked", capture_io: true do
53
53
  expect(fetch(:example_variable)).to be_nil
54
54
  invoke "load:defaults"
55
55
  expect(fetch(:example_variable)).to eq("foo")
@@ -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,7 +68,7 @@ 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
@@ -58,10 +76,10 @@ module Capistrano
58
76
  end
59
77
  end
60
78
 
61
- context "tty unavailable" do
79
+ context "tty unavailable", capture_io: true do
62
80
  before do
63
- $stdin.expects(:gets).never
64
- $stdin.expects(:tty?).returns(false)
81
+ stdin.expects(:gets).never
82
+ stdin.expects(:tty?).returns(false)
65
83
  end
66
84
 
67
85
  it "returns the default as the value" do
@@ -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