capistrano 3.0.0.pre14 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +42 -0
  3. data/README.md +1 -1
  4. data/bin/cap +1 -1
  5. data/capistrano.gemspec +3 -0
  6. data/features/deploy.feature +52 -0
  7. data/features/installation.feature +16 -0
  8. data/features/remote_file_task.feature +14 -0
  9. data/features/step_definitions/assertions.rb +90 -0
  10. data/features/step_definitions/cap_commands.rb +8 -0
  11. data/features/step_definitions/setup.rb +25 -0
  12. data/features/support/env.rb +12 -0
  13. data/features/support/remote_command_helpers.rb +20 -0
  14. data/lib/Capfile +1 -0
  15. data/lib/capistrano.rb +0 -14
  16. data/lib/capistrano/all.rb +16 -0
  17. data/lib/capistrano/application.rb +1 -10
  18. data/lib/capistrano/configuration.rb +4 -0
  19. data/lib/capistrano/configuration/server.rb +44 -6
  20. data/lib/capistrano/configuration/servers.rb +14 -51
  21. data/lib/capistrano/configuration/servers/role_filter.rb +86 -0
  22. data/lib/capistrano/defaults.rb +0 -8
  23. data/lib/capistrano/dsl.rb +1 -1
  24. data/lib/capistrano/dsl/env.rb +6 -2
  25. data/lib/capistrano/dsl/paths.rb +7 -4
  26. data/lib/capistrano/dsl/task_enhancements.rb +38 -0
  27. data/lib/capistrano/hg.rb +1 -0
  28. data/lib/capistrano/i18n.rb +1 -1
  29. data/lib/capistrano/setup.rb +7 -3
  30. data/lib/capistrano/tasks/deploy.rake +39 -9
  31. data/lib/capistrano/tasks/framework.rake +0 -2
  32. data/lib/capistrano/tasks/git.rake +3 -6
  33. data/lib/capistrano/tasks/hg.rake +39 -0
  34. data/lib/capistrano/templates/Capfile +2 -23
  35. data/lib/capistrano/templates/deploy.rb.erb +23 -0
  36. data/lib/capistrano/templates/stage.rb.erb +1 -1
  37. data/lib/capistrano/version.rb +1 -1
  38. data/spec/integration/dsl_spec.rb +71 -0
  39. data/spec/lib/capistrano/configuration/server_spec.rb +69 -0
  40. data/spec/lib/capistrano/configuration/servers/role_filter_spec.rb +140 -0
  41. data/spec/lib/capistrano/configuration/servers_spec.rb +46 -9
  42. data/spec/lib/capistrano/configuration_spec.rb +11 -0
  43. data/spec/spec_helper.rb +1 -2
  44. data/spec/support/.gitignore +1 -0
  45. data/spec/support/Vagrantfile +13 -0
  46. data/spec/support/tasks/database.cap +11 -0
  47. data/spec/support/test_app.rb +55 -6
  48. metadata +74 -16
  49. data/lib/capistrano/bundler.rb +0 -1
  50. data/lib/capistrano/tasks/bundler.rake +0 -13
  51. data/spec/integration/deploy_finalize_spec.rb +0 -34
  52. data/spec/integration/deploy_finished_spec.rb +0 -36
  53. data/spec/integration/deploy_started_spec.rb +0 -74
  54. data/spec/integration/deploy_update_spec.rb +0 -45
  55. data/spec/integration/installation_spec.rb +0 -76
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8d396873548e6dd9e20c1853f741bc8808e7a529
4
- data.tar.gz: 24aa535d127498013298938e5effb7e38bd26fbb
3
+ metadata.gz: 6e84be755bb1beb1fa002d555a2a237a569fe0b0
4
+ data.tar.gz: 2fdcff3917f21ed061bc94fa74d09fb06e4b8bd0
5
5
  SHA512:
6
- metadata.gz: 828006f69722330dcfbf09833922f0547a00fde78bd2d59948b4ebd59b139afa779f69c87e7d69e22e1fff7e9377d84484594dc5edaa544919a644c39d9d9338
7
- data.tar.gz: 8cfb03d51c92cac8ab9c6bd8cd7ba4d3416731de893927db8ab1b0117e5478af71c4e9256aaea8350a7cf23f663432ae1f7b1b19b5cad80e10890a607bb4c245
6
+ metadata.gz: 9d330918070791f930fc5254574f633ec354b87ebd2b194b16392771f1d135c1d1352f412ca915e8c194b8776fa0b820e023f88829782807bb2c4d41cf37981d
7
+ data.tar.gz: bd9b0c4d70a9b420decc32592d7fd5d59e93d40e01558318e5f969dfb5add69ccb813a10a3518224940d8da6f40f1d6e30699e072ada18b97925a08aaa6426a5
data/CHANGELOG.md CHANGED
@@ -2,6 +2,48 @@
2
2
 
3
3
  Reverse Chronological Order:
4
4
 
5
+ ## `3.0.0`
6
+
7
+ If you are coming here to wonder why your Capfile doesn't work anymore, please
8
+ vendor lock your Capistrano at 2.5.x, whichever version was working for you
9
+ until today.
10
+
11
+ Capistrano 3 is a ground-up rewrite with modularity, stability, speed and
12
+ future proofing in mind. It's a big change, but now the code is 10x smaller,
13
+ runs faster, is easier to read, and quicker to extend. In the reduction we've
14
+ come up with a great gem based modular system for plugins and we're really
15
+ proud of this release.
16
+
17
+ The 3.0.0 release contains 38 patches from the following amazing people:
18
+
19
+ * Tom `seenmyfate` Clements: more than 28 patches including cucumber integration tests! Not to
20
+ mention Rails asset pipeline code, and bundler integrations.
21
+ * Lee Hambley: Small changes around compatibility and log formatting
22
+ * Kir Shatrov: for improvements in the core to make it easier to write extensions, for
23
+ improving documentation, and for effectively building the chruby, rvm and rbenv integrations.
24
+ * Michael Nikitochkin: Fixing a bug around linked files and directories.
25
+ * Jack Thorne: for improvements to the default `Capfile` to fix some bad example syntax.
26
+ * Erik Hetzner: for (what looks like great) work on the Mercurial (Hg) support. The Hg and Git
27
+ source control mechanisms do not work the same way, but rather lean on the strengths of the
28
+ underlying tools.
29
+
30
+ (If I missed anyone, I'm sorry, your contributions have been awesome)
31
+
32
+ The 2.x branch of code is now no longer maintained. Towards the end of it's
33
+ useful life there were an increasing number of features and pieces of code
34
+ which didn't make sense for certain groups of people, in certain situations,
35
+ leading a to a ping-pong tennis effect with pull requests every few weeks
36
+ "fixing" a use-case which had already been "fixed" shortly before. As many of
37
+ the use-cases are outside the scope of the testing environments I (and by
38
+ extension the trusted contributors and IRC regulars) were able to test for.
39
+
40
+ There's a more extensive post about my failure to be able to keep up with the
41
+ demands of maintaining v2 whilst trying to build something which is appropriate
42
+ for the current landscape. If you are affected by the unsupported 2 branch,
43
+ please contact me (Lee Hambley) to dicsuss how my company can help support you.
44
+ Otherwise, please try v3, we're sure you'll like it, and the code is designed
45
+ to be so simple that anyone can work on it.
46
+
5
47
  ## `3.0.0.pre14`
6
48
 
7
49
  * Thanks to numerous contributors, in particular (@teohm) for a series of improvements.
data/README.md CHANGED
@@ -19,7 +19,7 @@ $ bundle --binstubs
19
19
  ```
20
20
 
21
21
  Capify:
22
- *make sure there's no "Capfile" or "capfile" present*
22
+ *make sure there's no "Capfile" or "capfile" present*
23
23
  ``` shell
24
24
  $ cap install
25
25
  ```
data/bin/cap CHANGED
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env ruby
2
- require 'capistrano'
2
+ require 'capistrano/all'
3
3
  Capistrano::Application.new.run
data/capistrano.gemspec CHANGED
@@ -28,5 +28,8 @@ Gem::Specification.new do |gem|
28
28
 
29
29
  gem.add_development_dependency 'rspec'
30
30
  gem.add_development_dependency 'mocha'
31
+ gem.add_development_dependency 'vagrant', '~> 1.0.7'
32
+ gem.add_development_dependency 'kuroko'
33
+ gem.add_development_dependency 'cucumber'
31
34
 
32
35
  end
@@ -0,0 +1,52 @@
1
+ Feature: Deploy
2
+
3
+ Background:
4
+ Given a test app with the default configuration
5
+ And servers with the roles app and web
6
+
7
+ Scenario: Creating the repo
8
+ When I run cap "git:check"
9
+ Then references in the remote repo are listed
10
+
11
+ Scenario: Creating the directory structure
12
+ When I run cap "deploy:check:directories"
13
+ Then the shared path is created
14
+ And the releases path is created
15
+
16
+ Scenario: Creating linked directories
17
+ When I run cap "deploy:check:linked_dirs"
18
+ Then directories in :linked_dirs are created in shared
19
+
20
+ Scenario: Creating linked directories for linked files
21
+ When I run cap "deploy:check:make_linked_dirs"
22
+ Then directories referenced in :linked_files are created in shared
23
+
24
+ Scenario: Checking linked files - missing file
25
+ Given a required file
26
+ But the file does not exist
27
+ When I run cap "deploy:check:linked_files"
28
+ Then the task will exit
29
+
30
+ Scenario: Checking linked files - file exists
31
+ Given a required file
32
+ And that file exists
33
+ When I run cap "deploy:check:linked_files"
34
+ Then the task will be successful
35
+
36
+ Scenario: Creating a release
37
+ When I run cap "git:create_release" as part of a release
38
+ Then the repo is cloned
39
+ And the release is created
40
+
41
+ Scenario: Symlink linked files
42
+ When I run cap "deploy:symlink:linked_files" as part of a release
43
+ Then file symlinks are created in the new release
44
+
45
+ Scenario: Symlink linked dirs
46
+ When I run cap "deploy:symlink:linked_dirs" as part of a release
47
+ Then directory symlinks are created in the new release
48
+
49
+ Scenario: Publishing
50
+ When I run cap "deploy:symlink:release"
51
+ Then the current directory will be a symlink to the release
52
+
@@ -0,0 +1,16 @@
1
+ Feature: Installation
2
+
3
+ Background:
4
+ Given a test app with the default configuration
5
+
6
+ Scenario: With default stages
7
+ When I run cap "install"
8
+ Then the deploy.rb file is created
9
+ And the default stage files are created
10
+ And the tasks folder is created
11
+
12
+ Scenario: With specified stages
13
+ When I run cap "install STAGES=qa,production"
14
+ Then the deploy.rb file is created
15
+ And the specified stage files are created
16
+ And the tasks folder is created
@@ -0,0 +1,14 @@
1
+ Feature: Remote file task
2
+
3
+ Background:
4
+ Given a test app with the default configuration
5
+ And a custom task to generate a file
6
+ And servers with the roles app and web
7
+
8
+ Scenario: Where the file does not exist
9
+ When I run cap "deploy:check:linked_files"
10
+ Then it creates the file with the remote_task prerequisite
11
+
12
+ Scenario: Where the file already exists
13
+ When I run cap "deploy:check:linked_files"
14
+ Then it will not recreate the file
@@ -0,0 +1,90 @@
1
+ Then(/^references in the remote repo are listed$/) do
2
+ end
3
+
4
+ Then(/^the shared path is created$/) do
5
+ run_vagrant_command(test_dir_exists(TestApp.shared_path))
6
+ end
7
+
8
+ Then(/^the releases path is created$/) do
9
+ run_vagrant_command(test_dir_exists(TestApp.releases_path))
10
+ end
11
+
12
+ Then(/^directories in :linked_dirs are created in shared$/) do
13
+ TestApp.linked_dirs.each do |dir|
14
+ run_vagrant_command(test_dir_exists(TestApp.shared_path.join(dir)))
15
+ end
16
+ end
17
+
18
+ Then(/^directories referenced in :linked_files are created in shared$/) do
19
+ dirs = TestApp.linked_files.map { |path| TestApp.shared_path.join(path).dirname }
20
+ dirs.each do | dir|
21
+ run_vagrant_command(test_dir_exists(dir))
22
+ end
23
+ end
24
+
25
+ Then(/^the task will be successful$/) do
26
+ end
27
+
28
+
29
+ Then(/^the task will exit$/) do
30
+ end
31
+
32
+ Then(/^the repo is cloned$/) do
33
+ run_vagrant_command(test_dir_exists(TestApp.repo_path))
34
+ end
35
+
36
+ Then(/^the release is created$/) do
37
+ run_vagrant_command("ls -g #{TestApp.releases_path}")
38
+ end
39
+
40
+ Then(/^file symlinks are created in the new release$/) do
41
+ pending
42
+ TestApp.linked_files.each do |file|
43
+ run_vagrant_command(test_symlink_exists(TestApp.release_path.join(file)))
44
+ end
45
+ end
46
+
47
+ Then(/^directory symlinks are created in the new release$/) do
48
+ pending
49
+ TestApp.linked_dirs.each do |dir|
50
+ run_vagrant_command(test_symlink_exists(TestApp.release_path.join(dir)))
51
+ end
52
+ end
53
+
54
+ Then(/^the current directory will be a symlink to the release$/) do
55
+ run_vagrant_command(test_symlink_exists(TestApp.current_path))
56
+ end
57
+
58
+ Then(/^the deploy\.rb file is created$/) do
59
+ file = TestApp.test_app_path.join('config/deploy.rb')
60
+ expect(File.exists?(file)).to be_true
61
+ end
62
+
63
+ Then(/^the default stage files are created$/) do
64
+ staging = TestApp.test_app_path.join('config/deploy/staging.rb')
65
+ production = TestApp.test_app_path.join('config/deploy/production.rb')
66
+ expect(File.exists?(staging)).to be_true
67
+ expect(File.exists?(production)).to be_true
68
+ end
69
+
70
+ Then(/^the tasks folder is created$/) do
71
+ path = TestApp.test_app_path.join('lib/capistrano/tasks')
72
+ expect(Dir.exists?(path)).to be_true
73
+ end
74
+
75
+ Then(/^the specified stage files are created$/) do
76
+ qa = TestApp.test_app_path.join('config/deploy/qa.rb')
77
+ production = TestApp.test_app_path.join('config/deploy/production.rb')
78
+ expect(File.exists?(qa)).to be_true
79
+ expect(File.exists?(production)).to be_true
80
+ end
81
+
82
+ Then(/^it creates the file with the remote_task prerequisite$/) do
83
+ TestApp.linked_files.each do |file|
84
+ run_vagrant_command(test_file_exists(TestApp.shared_path.join(file)))
85
+ end
86
+ end
87
+
88
+ Then(/^it will not recreate the file$/) do
89
+ #
90
+ end
@@ -0,0 +1,8 @@
1
+ When(/^I run cap "(.*?)"$/) do |task|
2
+ TestApp.cap(task)
3
+ end
4
+
5
+ When(/^I run cap "(.*?)" as part of a release$/) do |task|
6
+ TestApp.cap("deploy:new_release_path #{task}")
7
+ end
8
+
@@ -0,0 +1,25 @@
1
+ Given(/^a test app with the default configuration$/) do
2
+ TestApp.install
3
+ end
4
+
5
+ Given(/^servers with the roles app and web$/) do
6
+ vagrant_cli_command('up')
7
+ end
8
+
9
+ Given(/^a required file$/) do
10
+ end
11
+
12
+ Given(/^that file exists$/) do
13
+ run_vagrant_command("touch #{TestApp.linked_file}")
14
+ end
15
+
16
+ Given(/^the file does not exist$/) do
17
+ pending
18
+ file = TestApp.linked_file
19
+ run_vagrant_command("[ -f #{file} ] && rm #{file}")
20
+ end
21
+
22
+ Given(/^a custom task to generate a file$/) do
23
+ TestApp.copy_task_to_test_app('spec/support/tasks/database.cap')
24
+ end
25
+
@@ -0,0 +1,12 @@
1
+ require 'kuroko'
2
+
3
+ project_root = File.expand_path('../../../', __FILE__)
4
+ vagrant_root = File.join(project_root, 'spec/support')
5
+
6
+ Kuroko.configure do |config|
7
+ config.vagrant_root = 'spec/support'
8
+ end
9
+
10
+ puts vagrant_root.inspect
11
+
12
+ require_relative '../../spec/support/test_app'
@@ -0,0 +1,20 @@
1
+ module RemoteCommandHelpers
2
+
3
+ def test_dir_exists(path)
4
+ exists?('d', path)
5
+ end
6
+
7
+ def test_symlink_exists(path)
8
+ exists?('L', path)
9
+ end
10
+
11
+ def test_file_exists(path)
12
+ exists?('f', path)
13
+ end
14
+
15
+ def exists?(type, path)
16
+ %{[ -#{type} "#{path}" ] && echo "#{path} exists." || echo "Error: #{path} does not exist."}
17
+ end
18
+ end
19
+
20
+ World(RemoteCommandHelpers)
data/lib/Capfile CHANGED
@@ -1,2 +1,3 @@
1
1
  #!/usr/bin/env cap
2
+ include Capistrano::DSL
2
3
  require 'capistrano/install'
data/lib/capistrano.rb CHANGED
@@ -1,14 +0,0 @@
1
- require 'rake'
2
- require 'sshkit'
3
-
4
- Rake.application.options.trace = true
5
-
6
- require 'capistrano/version'
7
- require 'capistrano/version_validator'
8
- require 'capistrano/i18n'
9
- require 'capistrano/dsl'
10
- require 'capistrano/application'
11
- require 'capistrano/configuration'
12
-
13
- module Capistrano
14
- end
@@ -0,0 +1,16 @@
1
+ require 'rake'
2
+ require 'sshkit'
3
+ require 'sshkit/dsl'
4
+
5
+ Rake.application.options.trace = true
6
+
7
+ require 'capistrano/version'
8
+ require 'capistrano/version_validator'
9
+ require 'capistrano/i18n'
10
+ require 'capistrano/dsl'
11
+ require 'capistrano/application'
12
+ require 'capistrano/configuration'
13
+
14
+ module Capistrano
15
+
16
+ end
@@ -26,7 +26,7 @@ module Capistrano
26
26
  if tasks_without_stage_dependency.include?(@top_level_tasks.first)
27
27
  @top_level_tasks
28
28
  else
29
- @top_level_tasks.unshift('deploy:ensure_stage')
29
+ @top_level_tasks.unshift(ensure_stage)
30
30
  end
31
31
  end
32
32
 
@@ -37,15 +37,6 @@ module Capistrano
37
37
  File.expand_path(File.join(File.dirname(__FILE__),'..','Capfile'))
38
38
  end
39
39
 
40
- def tasks_without_stage_dependency
41
- defined_stages = Dir['config/deploy/*.rb'].map { |f| File.basename(f, '.rb') }
42
- defined_stages + default_tasks
43
- end
44
-
45
- def default_tasks
46
- %w{install}
47
- end
48
-
49
40
  def version
50
41
  ['--version', '-V',
51
42
  "Display the program version.",
@@ -20,6 +20,10 @@ module Capistrano
20
20
  config[key] = value
21
21
  end
22
22
 
23
+ def delete(key)
24
+ config.delete(key)
25
+ end
26
+
23
27
  def fetch(key, default=nil, &block)
24
28
  value = fetch_for(key, default, &block)
25
29
  if value.respond_to?(:call)
@@ -22,6 +22,11 @@ module Capistrano
22
22
  hostname == Server.new(host).hostname
23
23
  end
24
24
 
25
+ def select?(options)
26
+ selector = Selector.new(options)
27
+ selector.call(self)
28
+ end
29
+
25
30
  def primary
26
31
  self if fetch(:primary)
27
32
  end
@@ -41,6 +46,20 @@ module Capistrano
41
46
  alias_method :netssh_options_without_options, :netssh_options
42
47
  alias_method :netssh_options, :netssh_options_with_options
43
48
 
49
+ def roles_array
50
+ roles.to_a
51
+ end
52
+
53
+ private
54
+
55
+ def add_property(key, value)
56
+ if respond_to?("#{key}=")
57
+ send("#{key}=", value)
58
+ else
59
+ set(key, value)
60
+ end
61
+ end
62
+
44
63
  class Properties
45
64
 
46
65
  def initialize
@@ -79,15 +98,34 @@ module Capistrano
79
98
 
80
99
  end
81
100
 
101
+ class Selector
102
+ def initialize(options)
103
+ @options = options
104
+ end
82
105
 
83
- private
106
+ def callable
107
+ if key.respond_to?(:call)
108
+ key
109
+ else
110
+ ->(server) { server.fetch(key) }
111
+ end
112
+ end
84
113
 
85
- def add_property(key, value)
86
- if respond_to?("#{key}=")
87
- send("#{key}=", value)
88
- else
89
- set(key, value)
114
+ def call(server)
115
+ callable.call(server)
90
116
  end
117
+
118
+ private
119
+ attr_reader :options
120
+
121
+ def key
122
+ options[:filter] || options[:select] || all
123
+ end
124
+
125
+ def all
126
+ ->(server) { :all }
127
+ end
128
+
91
129
  end
92
130
 
93
131
  end