Codebase list capistrano / 2332f38
Imported Upstream version 3.4.0 Antonio Terceiro 9 years ago
64 changed file(s) with 1696 addition(s) and 1162 deletion(s). Raw diff Collapse all Expand all
22 - 2.1.0
33 - 2.0.0
44 - 1.9.3
5 - 1.9.2
6 - rbx
5 - rbx-2
76 script: bundle exec rake spec
7 install: bundle install --jobs=1
88 cache: bundler
9 bundler_args: --without cucumber
9 branches:
10 except:
11 - legacy-v2
12 sudo: false
33
44 ## master
55
6 https://github.com/capistrano/capistrano/compare/v3.2.0...HEAD
6 https://github.com/capistrano/capistrano/compare/v3.4.0...HEAD
7
8 ## `3.4.0`
9
10 https://github.com/capistrano/capistrano/compare/v3.3.5...v3.4.0
11
12 * Fixed fetch revision for annotated git tags. (@igorsokolov)
13 * Fixed updating roles when custom user or port is specified. (@ayastreb)
14 * Disables statistics collection.
15
16 * `bin/` is not suggested to be in `linked_dirs` anymore (@kirs)
17 * bin/ is often checked out into repo
18 * https://github.com/capistrano/bundler/issues/45#issuecomment-69349237
19
20 * Bugfix:
21 * release_roles did not honour additional property filtering (@townsen)
22 * Refactored and simplified property filtering code (@townsen)
23
24 * Breaking Changes
25 * Hosts with the same name are now consolidated into one irrespective of the
26 user and port. This allows multiple declarations of a server to be made safely.
27 The last declared properties will win. See capistrnorb.com Properties documentation
28 for details.
29 * Inside the on() block the host variable is now a copy of the host, so changes can be
30 made within the block (such as dynamically overriding the user) that will not persist.
31 This is very convenient for switching the SSH user temporarily to 'root' for example.
32
33 * Minor changes
34 * Add role_properties() method (see capistrano.github.io PR for doc) (@townsen)
35 * Add equality syntax ( eg. port: 1234) for property filtering (@townsen)
36 * Add documentation regarding property filtering (@townsen)
37 * Clarify wording and recommendation in stage template. (@Kriechi)
38 * Both available syntaxes provide similar functionality, do not use both for the same server+role combination.
39 * Allow specification of repo_path using stage variable
40 default is as before (@townsen)
41
42 ## `3.3.5`
43
44 https://github.com/capistrano/capistrano/compare/v3.3.4...v3.3.5
45
46 * Fixed setting properties twice when creating new server. See [issue
47 #1214](https://github.com/capistrano/capistrano/issues/1214) (@ayastreb)
48
49 ## `3.3.4`
50
51 https://github.com/capistrano/capistrano/compare/v3.3.3...v3.3.4
52
53 * Minor changes:
54 * Rely on a newer version of capistrano-stats with better privacy (@leehambley)
55 * Fix cucumber spec for loading tasks from stage configs (@sponomarev)
56 * Minor documentation fixes (@deeeki, @seuros, @andresilveira)
57 * Spec improvements (@dimitrid, @sponomarev)
58 * Fix to CLI flags for git-ls-remote (@dimitrid)
59
60 ## `3.3.3`
61
62 https://github.com/capistrano/capistrano/compare/v3.2.1...v3.3.3
63
64 * Enhancement (@townsen)
65 * Added the variable `:repo_tree` which allows the specification of a sub-tree that
66 will be extracted from the repository. This is useful when deploying a project
67 that lives in a subdirectory of a larger repository.
68 Implemented only for git and hg.
69 If not defined then the behaviour is as previously and the whole repository is
70 extracted (subject to git-archive `.gitattributes` of course).
71
72 * Enhancement (@townsen): Remove unnecessary entries from default backtrace
73
74 When the `--backtrace` (or `--trace`) command line option is not supplied
75 Rake lowers the noise level in exception backtraces by building
76 a regular expression containing all the system library paths and
77 using it to exclude backtrace entries that match.
78
79 This does not always go far enough, particularly in RVM environments when
80 many gem paths are added. This commit reverses that approach and _only_
81 include backtrace entries that fall within the Capfile and list of tasks
82 imported thereafter. This makes reading exceptions much easier on the eye.
83
84 If the full unexpurgated backtrace is required then the --backtrace
85 and --trace options supply it as before.
86
87 * Disable loading stages configs on `cap -T` (@sponomarev)
88
89 * Enhancements (@townsen)
90 * Fix matching on hosts with custom ports or users set
91 * Previously filtering would affect any generated configuration files so that
92 files newly deployed would not be the same as those on the hosts previously
93 deployed (and now excluded by filters). This is almost certainly not what is
94 wanted: the filters should apply only to the on() method and thus any
95 configuration files deployed will be identical across the set of servers
96 making up the stage.
97 * Host and Role filtering now affects only `on()` commands
98 and not the `roles()`, `release_roles()` and `primary()` methods.
99 * This applies to filters defined via the command line, the environment
100 and the :filter variable.
101 * Filtering now supports Regular expressions
102 * This change _could_ cause existing scripts that use filtering and depend on
103 the old behaviour to fail, though it is unlikely. Users who rely on
104 filtering should check that generated configuration files are correct, and
105 where not introduce server properties to do the filtering. For example, if a
106 filter was used to specify an active subset of servers (by hostname), it should
107 be removed and replaced with an 'active' property (set to true or false) on the
108 server definitions. This keeps the stage file as the canonical model of the
109 deployment environment.
110
111 * See the documentation in the README.md file
112
113 * Enhancements (@townsen)
114 * Added set_if_empty method to DSL to allow conditional setting
115 * Altered standard Capistrano defaults so that they are not set
116 at the start of a stage if they have been previously set. This
117 allows variables like :default_env to be set in deploy.rb.
118 * Deep copy properties added using the 'roles' keyword
119 * If a property exists on a server when another definition is
120 encountered and is an Array, Set or Hash then add the new values
121
122 This allows roles to specify properties common to all servers and
123 then for individual servers to modify them, keeping things DRY
124
125 Breaking Changes:
126 * By using Ruby's noecho method introduced in Ruby version 1.9.3, we dropped support for Ruby versions prior to 1.9.3. See [issue #878](https://github.com/capistrano/capistrano/issues/878) and [PR #1112](https://github.com/capistrano/capistrano/pull/1112) for more information. (@kaikuchn)
127 * Track (anonymous) statistics, see https://github.com/capistrano/stats. This breaks automated deployment on continuous integration servers until the `.capistrano/metrics` file is created (with content `full` to simulate a "yes") via the interactive prompt or manually.
128
129 * Bug Fixes:
130 * Fixed compatibility with FreeBSD tar (@robbertkl)
131 * remote_file can be used inside a namespace (@mikz)
132
133 * Minor Changes
134 * Remove -v flag from mkdir call. (@caligo-mentis)
135 * Capistrano now allows to customize `local_user` for revision log. (@sauliusgrigaitis)
136 * Added tests for after/before hooks features (@juanibiapina, @miry)
137 * Added `--force` flag to `svn export` command to fix errors when the release directory already exists.
138 * Improved the output of `cap --help`. (@mbrictson)
139 * Cucumber suite now runs on the latest version of Vagrant (@tpett)
140 * The `ask` method now supports the `echo: false` option. (@mbrictson, @kaikuchn)
141 * Cucumber scenario improvements (@bruno-)
142 * Added suggestion to Capfile to use 'capistrano-passenger' gem, replacing suggestion in config/deploy.rb to re-implement 'deploy:restart' (@betesh)
143 * Updated svn fetch_revision method to use `svnversion`
144 * `cap install` no longer overwrites existing files. (@dmarkow)
7145
8146 ## `3.2.1`
147
148 https://github.com/capistrano/capistrano/compare/v3.2.0...v3.2.1
9149
10150 * Bug Fixes:
11151 * 3.2.0 introduced some behaviour to modify the way before/after hooks were called, to allow the optional
18158 * Changed asking question to more standard format (like common unix commandline tools) (@sponomarev)
19159 * Fixed typos in the README. (@sponomarev)
20160 * Added `keys` method to Configuration to allow introspection of configuration options. (@juanibiapina)
161 * Improve error message when git:check fails (raise instead of silently `exit 1`) (@mbrictson)
21162
22163 ## `3.2.0`
23164
39180 Breaking changes:
40181
41182 * `deploy:restart` task **is no longer run by default**.
42 From this version, developers who restart the app on each deploy need to declare it in their deploy flow (eg `after 'deploy:publishing', 'deploy:restart'`).
183 From this version, developers who restart the app on each deploy need to declare it in their deploy flow (eg `after 'deploy:publishing', 'deploy:restart'`)
184 or, for passenger applications, use the capistrano-passenger gem.
43185
44186 Please, check https://github.com/capistrano/capistrano/commit/4e6523e1f50707499cf75eb53dce37a89528a9b0 for more information. (@kirs)
45187
33 gemspec
44
55 group :cucumber do
6 gem 'kuroko'
76 gem 'cucumber'
7 gem 'rspec', '~> 3.0.0'
88 end
9
10 platforms :rbx do
11 gem 'rubysl', '~> 2.0'
12 end
0 # Capistrano [![Build Status](https://travis-ci.org/capistrano/capistrano.png?branch=v3)](https://travis-ci.org/capistrano/capistrano) [![Code Climate](https://codeclimate.com/github/capistrano/capistrano.png)](https://codeclimate.com/github/capistrano/capistrano) <a href="http://codersclan.net/?repo_id=325&source=small"><img src="http://www.codersclan.net/gs_button/?repo_id=325&size=small" width="69"></a>
0 # Capistrano [![Build Status](https://travis-ci.org/capistrano/capistrano.svg?branch=master)](https://travis-ci.org/capistrano/capistrano) [![Code Climate](http://img.shields.io/codeclimate/github/capistrano/capistrano.svg)](https://codeclimate.com/github/capistrano/capistrano) <a href="http://codersclan.net/?repo_id=325&source=small"><img src="http://img.shields.io/badge/get-support-blue.svg"></a>
11
2 ## Requirements
2 ## Documentation
33
4 * Ruby >= 1.9 (JRuby and C-Ruby/YARV are supported)
4 Check out the [online documentation](http://capistranorb.com) of Capistrano 3 hosted via this [repository](https://github.com/capistrano/capistrano.github.io).
55
66 ## Support
77
88 Need help with getting Capistrano up and running? Got a code problem you want to get solved quickly?
99
10 Get <a href="http://codersclan.net/?repo_id=325&source=link">Capistrano support on CodersClan.</a>
10 Get <a href="http://codersclan.net/?repo_id=325&source=link">Capistrano support on CodersClan.</a> <a href="http://codersclan.net/?repo_id=325&source=big"><img src="http://www.codersclan.net/gs_button/?repo_id=325" width="150"></a>
1111
12 <a href="http://codersclan.net/?repo_id=325&source=big"><img src="http://www.codersclan.net/gs_button/?repo_id=325" width="200"></a>
12 ## Requirements
13
14 * Ruby >= 1.9.3 (JRuby and C-Ruby/YARV are supported)
15
16 Capistrano support these source code version control systems out of the box:
17
18 * Git 1.8 or higher
19 * Mercurial
20 * SVN
21
22 Binaries for these VCS might be required on the local and/or the remote systems.
1323
1424 ## Installation
1525
1626 Add this line to your application's Gemfile:
1727
1828 ``` ruby
19 gem 'capistrano', '~> 3.2.0'
29 gem 'capistrano', '~> 3.3.0'
2030 ```
2131
2232 And then execute:
5464 ## Usage
5565
5666 ``` sh
57 $ bundle exec cap -vT
67 # list all available tasks
68 $ bundle exec cap -T
5869
70 # deploy to the staging environment
5971 $ bundle exec cap staging deploy
72
73 # deploy to the production environment
6074 $ bundle exec cap production deploy
6175
76 # simulate deploying to the production environment
77 # does not actually do anything
6278 $ bundle exec cap production deploy --dry-run
79
80 # list task dependencies
6381 $ bundle exec cap production deploy --prereqs
82
83 # trace through task invocations
6484 $ bundle exec cap production deploy --trace
6585 ```
6686
67 ## Tasks
87 ## Testing
6888
69 ``` ruby
70 server 'example.com', roles: [:web, :app]
71 server 'example.org', roles: [:db, :workers]
72 desc "Report Uptimes"
73 task :uptime do
74 on roles(:all) do |host|
75 execute :any_command, "with args", :here, "and here"
76 info "Host #{host} (#{host.roles.to_a.join(', ')}):\t#{capture(:uptime)}"
77 end
78 end
89 Capistrano has two test suites: an RSpec suite and a Cucumber suite. The
90 RSpec suite handles quick feedback unit specs. The Cucumber features are
91 an integration suite that uses Vagrant to deploy to a real virtual
92 server. In order to run the Cucumber suite you will need to install
93 [Vagrant](http://www.vagrantup.com/) and Vagrant supported
94 virtualization software like
95 [VirtualBox](https://www.virtualbox.org/wiki/Downloads).
96
7997 ```
98 # To run the RSpec suite
99 $ rake spec
80100
81 **Note**:
101 # To run the Cucumber suite
102 $ rake features
82103
83 **tl;dr**: `execute(:bundle, :install)` and `execute('bundle install')` don't behave identically!
84
85 `execute()` has a subtle behaviour. When calling `within './directory' { execute(:bundle, :install) }` for example, the first argument to `execute()` is a *Stringish* with ***no whitespace***. This allows the command to pass through the [SSHKit::CommandMap](https://github.com/capistrano/sshkit#the-command-map) which enables a number of powerful features.
86
87 When the first argument to `execute()` contains whitespace, for example `within './directory' { execute('bundle install') }` (or when using a heredoc), neither Capistrano, nor SSHKit can reliably predict how it should be shell escaped, and thus cannot perform any context, or command mapping, that means that the `within(){}` (as well as `with()`, `as()`, etc) have no effect. There have been a few attempts to resolve this, but we don't consider it a bug although we acknowledge that it might be a little counter intuitive.
88 ## Before / After
89
90 Where calling on the same task name, executed in order of inclusion
91
92 ``` ruby
93 # call an existing task
94 before :starting, :ensure_user
95
96 after :finishing, :notify
97
98
99 # or define in block
100 before :starting, :ensure_user do
101 #
102 end
103
104 after :finishing, :notify do
105 #
106 end
104 # To run the Cucumber suite and leave the VM running (faster for subsequent runs)
105 $ rake features KEEP_RUNNING=1
107106 ```
108
109 If it makes sense for your use case (often, that means *generating a file*)
110 the Rake prerequisite mechanism can be used:
111
112 ``` ruby
113 desc "Create Important File"
114 file 'important.txt' do |t|
115 sh "touch #{t.name}"
116 end
117 desc "Upload Important File"
118 task :upload => 'important.txt' do |t|
119 on roles(:all) do
120 upload!(t.prerequisites.first, '/tmp')
121 end
122 end
123 ```
124
125 The final way to call out to other tasks is to simply `invoke()` them:
126
127 ``` ruby
128 namespace :example do
129 task :one do
130 on roles(:all) { info "One" }
131 end
132 task :two do
133 invoke "example:one"
134 on roles(:all) { info "Two" }
135 end
136 end
137 ```
138
139 This method is widely used.
140
141 ## Getting User Input
142
143 ``` ruby
144 desc "Ask about breakfast"
145 task :breakfast do
146 ask(:breakfast, "pancakes")
147 on roles(:all) do |h|
148 execute "echo \"$(whoami) wants #{fetch(:breakfast)} for breakfast!\""
149 end
150 end
151 ```
152
153 Perfect, who needs telephones.
154
155
156 ## Using password authentication
157
158 Password authentication can be done via `set` and `ask` in your deploy environment file (e.g.: config/deploy/production.rb)
159
160 ```ruby
161 set :password, ask('Server password', nil)
162 server 'server.domain.com', user: 'ssh_user_name', port: 22, password: fetch(:password), roles: %w{web app db}
163 ```
164
165 ## Running local tasks
166
167 Local tasks can be run by replacing `on` with `run_locally`
168
169 ``` ruby
170 desc 'Notify service of deployment'
171 task :notify do
172 run_locally do
173 with rails_env: :development do
174 rake 'service:notify'
175 end
176 end
177 end
178 ```
179
180 Of course, you can always just use standard ruby syntax to run things locally
181 ``` ruby
182 desc 'Notify service of deployment'
183 task :notify do
184 %x('RAILS_ENV=development bundle exec rake "service:notify"')
185 end
186 ```
187
188 Alternatively you could use the rake syntax
189 ``` ruby
190 desc "Notify service of deployment"
191 task :notify do
192 sh 'RAILS_ENV=development bundle exec rake "service:notify"'
193 end
194 ```
195 ## Console
196
197 **Note:** Here be dragons. The console is very immature, but it's much more
198 cleanly architected than previous incarnations and it'll only get better from
199 here on in.
200
201 Execute arbitrary remote commands, to use this simply add
202 `require 'capistrano/console'` which will add the necessary tasks to your
203 environment:
204
205 ``` sh
206 $ bundle exec cap staging console
207 ```
208
209 Then, after setting up the server connections, this is how that might look:
210
211 ``` sh
212 $ bundle exec cap production console
213 capistrano console - enter command to execute on production
214 production> uptime
215 INFO [94db8027] Running /usr/bin/env uptime on leehambley@example.com:22
216 DEBUG [94db8027] Command: /usr/bin/env uptime
217 DEBUG [94db8027] 17:11:17 up 50 days, 22:31, 1 user, load average: 0.02, 0.02, 0.05
218 INFO [94db8027] Finished in 0.435 seconds command successful.
219 production> who
220 INFO [9ce34809] Running /usr/bin/env who on leehambley@example.com:22
221 DEBUG [9ce34809] Command: /usr/bin/env who
222 DEBUG [9ce34809] leehambley pts/0 2013-06-13 17:11 (port-11262.pppoe.wtnet.de)
223 INFO [9ce34809] Finished in 0.420 seconds command successful.
224 ```
225
226 ## A word about PTYs
227
228 There is a configuration option which asks the backend driver to ask the remote host
229 to assign the connection a *pty*. A *pty* is a pseudo-terminal, which in effect means
230 *tell the backend that this is an __interactive__ session*. This is normally a bad idea.
231
232 Most of the differences are best explained by [this page](https://github.com/sstephenson/rbenv/wiki/Unix-shell-initialization) from the author of *rbenv*.
233
234 **When Capistrano makes a connection it is a *non-login*, *non-interactive* shell.
235 This was not an accident!**
236
237 It's often used as a band aid to cure issues related to RVM and rbenv not loading login
238 and shell initialisation scripts. In these scenarios RVM and rbenv are the tools at fault,
239 or at least they are being used incorrectly.
240
241 Whilst, especially in the case of language runtimes (Ruby, Node, Python and friends in
242 particular) there is a temptation to run multiple versions in parallel on a single server
243 and to switch between them using environmental variables, this is an anti-pattern, and
244 symptomatic of bad design (e.g. you're testing a second version of Ruby in production because
245 your company lacks the infrastructure to test this in a staging environment).
246
247 ## Configuration
248
249 The following variables are settable:
250
251 | Variable Name | Description | Notes |
252 |:---------------------:|----------------------------------------------------------------------|-----------------------------------------------------------------|
253 | `:repo_url` | The URL of your scm repository (git, hg, svn) | file://, https://, ssh://, or svn+ssh:// are all supported |
254 | `:branch` | The branch you wish to deploy | This only has meaning for git and hg repos, to specify the branch of an svn repo, set `:repo_url` to the branch location. |
255 | `:scm` | The source control system used | `:git`, `:hg`, `:svn` are currently supported |
256 | `:tmp_dir` | The (optional) temp directory that will be used (default: /tmp) | if you have a shared web host, this setting may need to be set (i.e. /home/user/tmp/capistrano). |
257
258 __Support removed__ for following variables:
259
260 | Variable Name | Description | Notes |
261 |:---------------------:|---------------------------------------------------------------------|-----------------------------------------------------------------|
262 | `:copy_exclude` | The (optional) array of files and/or folders excluded from deploy | Replaced by Git's native `.gitattributes`, see [#515](https://github.com/capistrano/capistrano/issues/515) for more info. |
263107
264108 ## SSHKit
265109
272116
273117 MIT License (MIT)
274118
275 Copyright (c) 2012-2013 Tom Clements, Lee Hambley
119 Copyright (c) 2012-2015 Tom Clements, Lee Hambley
276120
277121 Permission is hereby granted, free of charge, to any person obtaining a copy
278122 of this software and associated documentation files (the "Software"), to deal
00 require "bundler/gem_tasks"
1 require "cucumber/rake/task"
2 require "rspec/core/rake_task"
13
24 task :default => :spec
3 require 'rspec/core/rake_task'
45 RSpec::Core::RakeTask.new
6
7 Cucumber::Rake::Task.new(:features)
8
1919 gem.licenses = ['MIT']
2020
2121 gem.post_install_message = <<eos
22 Capistrano 3.1 has some breaking changes, like `deploy:restart` callback should be added manually to your deploy.rb. Please, check the CHANGELOG: http://goo.gl/SxB0lr
22 Capistrano 3.1 has some breaking changes. Please check the CHANGELOG: http://goo.gl/SxB0lr
2323
2424 If you're upgrading Capistrano from 2.x, we recommend to read the upgrade guide: http://goo.gl/4536kB
25
26 The `deploy:restart` hook for passenger applications is now in a separate gem called capistrano-passenger. Just add it to your Gemfile and require it in your Capfile.
2527 eos
2628
29 gem.required_ruby_version = '>= 1.9.3'
2730 gem.add_dependency 'sshkit', '~> 1.3'
2831 gem.add_dependency 'rake', '>= 10.0.0'
2932 gem.add_dependency 'i18n'
checksums.yaml.gz less more
Binary diff not shown
1818 Then the task is successful
1919 And contains "install" in the output
2020
21 Scenario: Show install task with configuration in a custom location
21 Scenario: Hide install task with configuration in a custom location
2222 And config stage file has line "desc 'Special Task'"
2323 And config stage file has line "task :special_stage_task"
2424 But the configuration is in a custom location
2525 When I run "cap -T"
2626 Then the task is successful
27 And contains "special_stage_task" in the output
27 And doesn't contain "special_stage_task" in the output
55
66 Scenario: Creating the repo
77 When I run cap "git:check"
8 Then references in the remote repo are listed
8 Then the task is successful
9 And references in the remote repo are listed
910
1011 Scenario: Creating the directory structure
1112 When I run cap "deploy:check:directories"
2122 Then directories referenced in :linked_files are created in shared
2223
2324 Scenario: Checking linked files - missing file
24 Given a required file
25 But the file does not exist
25 Given a linked file "missing_file.txt"
26 But file "missing_file.txt" does not exist in shared path
2627 When I run cap "deploy:check:linked_files"
27 Then the task will exit
28 Then the task fails
2829
2930 Scenario: Checking linked files - file exists
30 Given a required file
31 And that file exists
31 Given a linked file "existing_file.txt"
32 And file "existing_file.txt" exists in shared path
3233 When I run cap "deploy:check:linked_files"
33 Then the task will be successful
34 Then the task is successful
3435
3536 Scenario: Creating a release
3637 Given I run cap "deploy:check:directories"
3940 And the release is created
4041
4142 Scenario: Symlink linked files
42 When I run cap "deploy:symlink:linked_files" as part of a release
43 When I run cap "deploy:symlink:linked_files deploy:symlink:release" as part of a release
4344 Then file symlinks are created in the new release
4445
4546 Scenario: Symlink linked dirs
0 Feature: SSH Connection
1
2 Background:
3 Given a test app with the default configuration
4 And servers with the roles app and web
5 And a task which executes as root
6
7 Scenario: Switching from default user to root and back again
8 When I run cap "am_i_root"
9 Then the task is successful
10 And the output matches "I am uid=0\(root\)" followed by "I am uid=\d+\(vagrant\)"
00 Then(/^references in the remote repo are listed$/) do
1 expect(@output).to include('refs/heads/master')
12 end
23
34 Then(/^the shared path is created$/) do
2122 end
2223 end
2324
24 Then(/^the task will be successful$/) do
25 end
26
27
28 Then(/^the task will exit$/) do
29 end
30
3125 Then(/^the repo is cloned$/) do
3226 run_vagrant_command(test_dir_exists(TestApp.repo_path))
3327 end
3731 end
3832
3933 Then(/^file symlinks are created in the new release$/) do
40 pending
4134 TestApp.linked_files.each do |file|
42 run_vagrant_command(test_symlink_exists(TestApp.release_path.join(file)))
35 run_vagrant_command(test_symlink_exists(TestApp.current_path.join(file)))
4336 end
4437 end
4538
5649
5750 Then(/^the deploy\.rb file is created$/) do
5851 file = TestApp.test_app_path.join('config/deploy.rb')
59 expect(File.exists?(file)).to be_true
52 expect(File.exists?(file)).to be true
6053 end
6154
6255 Then(/^the default stage files are created$/) do
6356 staging = TestApp.test_app_path.join('config/deploy/staging.rb')
6457 production = TestApp.test_app_path.join('config/deploy/production.rb')
65 expect(File.exists?(staging)).to be_true
66 expect(File.exists?(production)).to be_true
58 expect(File.exists?(staging)).to be true
59 expect(File.exists?(production)).to be true
6760 end
6861
6962 Then(/^the tasks folder is created$/) do
7063 path = TestApp.test_app_path.join('lib/capistrano/tasks')
71 expect(Dir.exists?(path)).to be_true
64 expect(Dir.exists?(path)).to be true
7265 end
7366
7467 Then(/^the specified stage files are created$/) do
7568 qa = TestApp.test_app_path.join('config/deploy/qa.rb')
7669 production = TestApp.test_app_path.join('config/deploy/production.rb')
77 expect(File.exists?(qa)).to be_true
78 expect(File.exists?(production)).to be_true
70 expect(File.exists?(qa)).to be true
71 expect(File.exists?(production)).to be true
7972 end
8073
8174 Then(/^it creates the file with the remote_task prerequisite$/) do
8982 end
9083
9184 Then(/^the task is successful$/) do
92 expect(@success).to be_true
85 expect(@success).to be true
86 end
87
88 Then(/^the task fails$/) do
89 expect(@success).to be_falsey
9390 end
9491
9592 Then(/^the failure task will run$/) do
9996
10097 Then(/^the failure task will not run$/) do
10198 failed = TestApp.shared_path.join('failed')
102 !run_vagrant_command(test_file_exists(failed))
99 expect { run_vagrant_command(test_file_exists(failed)) }
100 .to raise_error(VagrantHelpers::VagrantSSHCommandError)
103101 end
104102
105103 When(/^an error is raised$/) do
107105 run_vagrant_command(test_file_exists(error))
108106 end
109107
110 Then(/contains "(.*?)" in the output/) do |expected|
108 Then(/contains "([^"]*)" in the output/) do |expected|
111109 expect(@output).to include(expected)
112110 end
111
112 Then(/the output matches "([^"]*)" followed by "([^"]*)"/) do |expected, followedby|
113 expect(@output).to match(/#{expected}.*#{followedby}/m)
114 end
115
116 Then(/doesn't contain "([^"]*)" in the output/) do |expected|
117 expect(@output).not_to include(expected)
118 end
00 When(/^I run cap "(.*?)"$/) do |task|
1 @success = TestApp.cap(task)
1 @success, @output = TestApp.cap(task)
22 end
33
44 When(/^I run cap "(.*?)" as part of a release$/) do |task|
55 vagrant_cli_command('up') rescue nil
66 end
77
8 Given(/^a required file$/) do
8 Given(/^a linked file "(.*?)"$/) do |file|
9 # ignoring other linked files
10 TestApp.append_to_deploy_file("set :linked_files, ['#{file}']")
911 end
1012
11 Given(/^that file exists$/) do
12 run_vagrant_command("touch #{TestApp.linked_file}")
13 Given(/^file "(.*?)" exists in shared path$/) do |file|
14 file_shared_path = TestApp.shared_path.join(file)
15 run_vagrant_command("mkdir -p #{TestApp.shared_path}")
16 run_vagrant_command("touch #{file_shared_path}")
1317 end
1418
15 Given(/^the file does not exist$/) do
16 pending
17 file = TestApp.linked_file
18 run_vagrant_command("[ -f #{file} ] && rm #{file}")
19 Given(/^file "(.*?)" does not exist in shared path$/) do |file|
20 file_shared_path = TestApp.shared_path.join(file)
21 run_vagrant_command("mkdir -p #{TestApp.shared_path}")
22 run_vagrant_command("touch #{file_shared_path} && rm #{file_shared_path}")
1923 end
2024
2125 Given(/^a custom task to generate a file$/) do
2226 TestApp.copy_task_to_test_app('spec/support/tasks/database.rake')
27 end
28
29 Given(/^a task which executes as root$/) do
30 TestApp.copy_task_to_test_app('spec/support/tasks/root.rake')
2331 end
2432
2533 Given(/config stage file has line "(.*?)"/) do |line|
0 require 'kuroko'
0 PROJECT_ROOT = File.expand_path('../../../', __FILE__)
1 VAGRANT_ROOT = File.join(PROJECT_ROOT, 'spec/support')
2 VAGRANT_BIN = ENV['VAGRANT_BIN'] || "vagrant"
13
2 project_root = File.expand_path('../../../', __FILE__)
3 vagrant_root = File.join(project_root, 'spec/support')
4
5 Kuroko.configure do |config|
6 config.vagrant_root = 'spec/support'
4 at_exit do
5 if ENV['KEEP_RUNNING']
6 VagrantHelpers.run_vagrant_command("rm -rf /home/vagrant/var")
7 end
78 end
89
9 puts vagrant_root.inspect
10
1110 require_relative '../../spec/support/test_app'
00 module RemoteCommandHelpers
1
21 def test_dir_exists(path)
32 exists?('d', path)
43 end
1211 end
1312
1413 def exists?(type, path)
15 %{[ -#{type} "#{path}" ] && echo "#{path} exists." || echo "Error: #{path} does not exist."}
14 %{[ -#{type} "#{path}" ]}
1615 end
1716
1817 def safely_remove_file(path)
19 run_vagrant_command("rm #{test_file}") rescue Vagrant::Errors::VagrantError
18 run_vagrant_command("rm #{test_file}") rescue VagrantHelpers::VagrantSSHCommandError
2019 end
2120 end
2221
0 module VagrantHelpers
1 extend self
2
3 class VagrantSSHCommandError < RuntimeError; end
4
5 at_exit do
6 if ENV['KEEP_RUNNING']
7 puts "Vagrant vm will be left up because KEEP_RUNNING is set."
8 puts "Rerun without KEEP_RUNNING set to cleanup the vm."
9 else
10 vagrant_cli_command("destroy -f")
11 end
12 end
13
14 def vagrant_cli_command(command)
15 puts "[vagrant] #{command}"
16 Dir.chdir(VAGRANT_ROOT) do
17 `#{VAGRANT_BIN} #{command} 2>&1`.split("\n").each do |line|
18 puts "[vagrant] #{line}"
19 end
20 end
21 $?
22 end
23
24 def run_vagrant_command(command)
25 if (status = vagrant_cli_command("ssh -c #{command.inspect}")).success?
26 true
27 else
28 fail VagrantSSHCommandError, status
29 end
30 end
31
32 end
33
34 World(VagrantHelpers)
00 require 'rake'
11 require 'sshkit'
2 require 'sshkit/dsl'
2
3 require 'io/console'
34
45 Rake.application.options.trace = true
56
1515 end
1616
1717 def sort_options(options)
18 options.push(version, roles, dry_run, hostfilter)
19 super
18 not_applicable_to_capistrano = %w(quiet silent verbose)
19 options.reject! do |(switch, *)|
20 switch =~ /--#{Regexp.union(not_applicable_to_capistrano)}/
21 end
22
23 super.push(version, dry_run, roles, hostfilter)
2024 end
25
26 def handle_options
27 options.rakelib = ['rakelib']
28 options.trace_output = $stderr
29
30 OptionParser.new do |opts|
31 opts.banner = "See full documentation at http://capistranorb.com/."
32 opts.separator ""
33 opts.separator "Install capistrano in a project:"
34 opts.separator " bundle exec cap install [STAGES=qa,staging,production,...]"
35 opts.separator ""
36 opts.separator "Show available tasks:"
37 opts.separator " bundle exec cap -T"
38 opts.separator ""
39 opts.separator "Invoke (or simulate invoking) a task:"
40 opts.separator " bundle exec cap [--dry-run] STAGE TASK"
41 opts.separator ""
42 opts.separator "Advanced options:"
43
44 opts.on_tail("-h", "--help", "-H", "Display this help message.") do
45 puts opts
46 exit
47 end
48
49 standard_rake_options.each { |args| opts.on(*args) }
50 opts.environment('RAKEOPT')
51 end.parse!
52 end
53
2154
2255 def top_level_tasks
2356 if tasks_without_stage_dependency.include?(@top_level_tasks.first)
2558 else
2659 @top_level_tasks.unshift(ensure_stage.to_s)
2760 end
61 end
62
63 def display_error_message(ex)
64 unless options.backtrace
65 if loc = Rake.application.find_rakefile_location
66 whitelist = (@imported.dup << loc[0]).map{|f| File.absolute_path(f, loc[1])}
67 pattern = %r@^(?!#{whitelist.map{|p| Regexp.quote(p)}.join('|')})@
68 Rake.application.options.suppress_backtrace_pattern = pattern
69 end
70 trace "(Backtrace restricted to imported tasks)"
71 end
72 super
2873 end
2974
3075 def exit_because_of_exception(ex)
4186 if options.show_tasks
4287 invoke 'load:defaults'
4388 set(:stage, '')
44 Dir[deploy_config_path, stage_definitions].each { |f| add_import f }
89 Dir[deploy_config_path].each { |f| add_import f }
4590 end
4691
4792 super
73118
74119 def roles
75120 ['--roles ROLES', '-r',
76 "Filter command to only apply to these roles (separate multiple roles with a comma)",
121 "Run SSH commands only on hosts matching these roles",
77122 lambda { |value|
78 Configuration.env.set(:filter, roles: value.split(","))
123 Configuration.env.add_cmdline_filter(:role, value)
79124 }
80125 ]
81126 end
82127
83128 def hostfilter
84129 ['--hosts HOSTS', '-z',
85 "Filter command to only apply to these hosts (separate multiple hosts with a comma)",
130 "Run SSH commands only on matching hosts",
86131 lambda { |value|
87 Configuration.env.set(:filter, hosts: value.split(","))
132 Configuration.env.add_cmdline_filter(:host, value)
88133 }
89134 ]
90135 end
0 require 'capistrano/configuration'
1
2 module Capistrano
3 class Configuration
4 class Filter
5 def initialize type, values = nil
6 raise "Invalid filter type #{type}" unless [:host,:role].include? type
7 av = Array(values).dup
8 @mode = case
9 when av.size == 0 then :none
10 when av.include?(:all) then :all
11 else type
12 end
13 @rex = case @mode
14 when :host
15 av.map!{|v| (v.is_a?(String) && v =~ /^(?<name>[-A-Za-z0-9.]+)(,\g<name>)*$/) ? v.split(',') : v }
16 av.flatten!
17 av.map! do |v|
18 case v
19 when Regexp then v
20 else
21 vs = v.to_s
22 vs =~ /^[-A-Za-z0-9.]+$/ ? vs : Regexp.new(vs)
23 end
24 end
25 Regexp.union av
26 when :role
27 av.map!{|v| v.is_a?(String) ? v.split(',') : v }
28 av.flatten!
29 av.map! do |v|
30 case v
31 when Regexp then v
32 else
33 vs = v.to_s
34 vs =~ %r{^/(.+)/$} ? Regexp.new($1) : %r{^#{vs}$}
35 end
36 end
37 Regexp.union av
38 else
39 nil
40 end
41 end
42 def filter servers
43 as = Array(servers)
44 case @mode
45 when :none then return []
46 when :all then return servers
47 when :host
48 as.select {|s| @rex.match s.hostname}
49 when :role
50 as.select {|s| s.roles.any? {|r| @rex.match r} }
51 end
52 end
53 end
54 end
55 end
11 class Configuration
22 class Question
33
4 def initialize(env, key, default)
5 @env, @key, @default = env, key, default
4 def initialize(key, default, options = {})
5 @key, @default, @options = key, default, options
66 end
77
88 def call
99 ask_question
10 save_response
10 value_or_default
1111 end
1212
1313 private
14 attr_reader :env, :key, :default
14 attr_reader :key, :default, :options
1515
1616 def ask_question
1717 $stdout.print question
1818 end
1919
20 def save_response
21 env.set(key, value)
22 end
23
24 def value
20 def value_or_default
2521 if response.empty?
2622 default
2723 else
3026 end
3127
3228 def response
33 @response ||= $stdin.gets.chomp
29 return @response if defined? @response
30
31 @response = (gets || "").chomp
32 end
33
34 def gets
35 if echo?
36 $stdin.gets
37 else
38 $stdin.noecho(&:gets).tap{ $stdout.print "\n" }
39 end
40 rescue Errno::EIO
41 # when stdio gets closed
42 end
43
44 def question
45 I18n.t(:question, key: key, default_value: default, scope: :capistrano)
3446 end
3547
36 def question
37 I18n.t(:question, key: key, default_value: default, scope: :capistrano)
48 def echo?
49 (options || {}).fetch(:echo, true)
3850 end
3951 end
4052 end
1010
1111 def add_roles(roles)
1212 Array(roles).each { |role| add_role(role) }
13 self
1314 end
1415 alias roles= add_roles
1516
1617 def add_role(role)
1718 roles.add role.to_sym
19 self
1820 end
1921
2022 def has_role?(role)
2224 end
2325
2426 def select?(options)
25 selector = Selector.for(options)
26 selector.call(self)
27 options.each do |k,v|
28 callable = v.respond_to?(:call) ? v: ->(server){server.fetch(v)}
29 result = case k
30 when :filter, :select
31 callable.call(self)
32 when :exclude
33 !callable.call(self)
34 else
35 self.fetch(k) == v
36 end
37 return false unless result
38 end
39 return true
2740 end
2841
2942 def primary
3952 @properties ||= Properties.new
4053 end
4154
42 def netssh_options_with_options
43 @netssh_options ||= netssh_options_without_options.merge( fetch(:ssh_options) || {} )
55 def netssh_options
56 @netssh_options ||= super.merge( fetch(:ssh_options) || {} )
4457 end
45 alias_method :netssh_options_without_options, :netssh_options
46 alias_method :netssh_options, :netssh_options_with_options
4758
4859 def roles_array
4960 roles.to_a
5061 end
5162
5263 def matches?(other)
53 user == other.user && hostname == other.hostname && port == other.port
64 hostname == other.hostname
5465 end
5566
5667 private
7081 end
7182
7283 def set(key, value)
73 @properties[key] = value
84 pval = @properties[key]
85 if pval.is_a? Hash and value.is_a? Hash
86 pval.merge!(value)
87 elsif pval.is_a? Set and value.is_a? Set
88 pval.merge(value)
89 elsif pval.is_a? Array and value.is_a? Array
90 pval.concat value
91 else
92 @properties[key] = value
93 end
7494 end
7595
7696 def fetch(key)
7797 @properties[key]
7898 end
7999
80 def respond_to?(method)
100 def respond_to?(method, include_all=false)
81101 @properties.has_key?(method)
82102 end
83103
105125
106126 end
107127
108 class Selector
109 def initialize(options)
110 @options = options
111 end
112
113 def self.for(options)
114 if options.has_key?(:exclude)
115 Exclusive
116 else
117 self
118 end.new(options)
119 end
120
121 def callable
122 if key.respond_to?(:call)
123 key
124 else
125 ->(server) { server.fetch(key) }
126 end
127 end
128
129 def call(server)
130 callable.call(server)
131 end
132
133 private
134 attr_reader :options
135
136 def key
137 options[:filter] || options[:select] || all
138 end
139
140 def all
141 ->(server) { :all }
142 end
143
144 class Exclusive < Selector
145
146 def key
147 options[:exclude]
148 end
149
150 def call(server)
151 !callable.call(server)
152 end
153 end
154
155 end
156
157128 end
158129 end
159130 end
+0
-82
lib/capistrano/configuration/servers/host_filter.rb less more
0 module Capistrano
1 class Configuration
2 class Servers
3 class HostFilter
4
5 def initialize(available)
6 @available = available
7 end
8
9 def self.for(available)
10 new(available).hosts
11 end
12
13 def hosts
14 if host_filter.any?
15 @available.select { |server| host_filter.include? server.hostname }
16 else
17 @available
18 end
19 end
20
21 private
22
23 def filter
24 if host_filter.any?
25 host_filter
26 else
27 @available
28 end
29 end
30
31 def host_filter
32 env_filter | configuration_filter
33 end
34
35 def configuration_filter
36 ConfigurationFilter.new.hosts
37 end
38
39 def env_filter
40 EnvFilter.new.hosts
41 end
42
43 class ConfigurationFilter
44
45 def hosts
46 if filter
47 Array(filter.fetch(:hosts, []))
48 else
49 []
50 end
51 end
52
53 def config
54 Configuration.env
55 end
56
57 def filter
58 config.fetch(:filter) || config.fetch(:select)
59 end
60 end
61
62
63 class EnvFilter
64
65 def hosts
66 if filter
67 filter.split(',')
68 else
69 []
70 end
71 end
72
73 def filter
74 ENV['HOSTS']
75 end
76 end
77
78 end
79 end
80 end
81 end
+0
-86
lib/capistrano/configuration/servers/role_filter.rb less more
0 module Capistrano
1 class Configuration
2 class Servers
3 class RoleFilter
4
5 def initialize(required, available)
6 @required, @available = required, available
7 end
8
9 def self.for(required, available)
10 new(required, available).roles
11 end
12
13 def roles
14 if required.include?(:all)
15 available
16 else
17 required.select { |name| available.include? name }
18 end
19 end
20
21 private
22
23 def required
24 Array(@required).flat_map(&:to_sym)
25 end
26
27 def available
28 if role_filter.any?
29 role_filter
30 else
31 @available
32 end
33 end
34
35 def role_filter
36 env_filter | configuration_filter
37 end
38
39 def configuration_filter
40 ConfigurationFilter.new.roles
41 end
42
43 def env_filter
44 EnvFilter.new.roles
45 end
46
47 class ConfigurationFilter
48
49 def roles
50 if filter
51 Array(filter.fetch(:roles, [])).map(&:to_sym)
52 else
53 []
54 end
55 end
56
57 def config
58 Configuration.env
59 end
60
61 def filter
62 config.fetch(:filter) || config.fetch(:select)
63 end
64 end
65
66
67 class EnvFilter
68
69 def roles
70 if filter
71 filter.split(',').map(&:to_sym)
72 else
73 []
74 end
75 end
76
77 def filter
78 ENV['ROLES']
79 end
80 end
81
82 end
83 end
84 end
85 end
00 require 'set'
1 require_relative 'servers/role_filter'
2 require_relative 'servers/host_filter'
1 require 'capistrano/configuration'
2 require 'capistrano/configuration/filter'
3
34 module Capistrano
45 class Configuration
56 class Servers
67 include Enumerable
78
89 def add_host(host, properties={})
9 servers.add server(host).with(properties)
10 new_host = Server[host]
11 if server = servers.find { |s| s.matches? new_host }
12 server.user = new_host.user if new_host.user
13 server.port = new_host.port if new_host.port
14 server.with(properties)
15 else
16 servers << new_host.with(properties)
17 end
1018 end
1119
1220 def add_role(role, hosts, options={})
13 Array(hosts).each { |host| add_host(host, options.merge(roles: role)) }
21 options_deepcopy = Marshal.dump(options.merge(roles: role))
22 Array(hosts).each { |host| add_host(host, Marshal.load(options_deepcopy)) }
1423 end
1524
1625 def roles_for(names)
1726 options = extract_options(names)
18 fetch_roles(names, options)
27 s = Filter.new(:role, names).filter(servers)
28 s.select { |server| server.select?(options) }
29 end
30
31 def role_properties_for(rolenames)
32 roles = rolenames.to_set
33 rps = Set.new unless block_given?
34 roles_for(rolenames).each do |host|
35 host.roles.intersection(roles).each do |role|
36 [host.properties.fetch(role)].flatten(1).each do |props|
37 if block_given?
38 yield host, role, props
39 else
40 rps << (props || {}).merge( role: role, hostname: host.hostname )
41 end
42 end
43 end
44 end
45 block_given? ? nil: rps
1946 end
2047
2148 def fetch_primary(role)
22 hosts = fetch(role)
49 hosts = roles_for([role])
2350 hosts.find(&:primary) || hosts.first
2451 end
2552
2956
3057 private
3158
32 def server(host)
33 servers.find { |server| server.matches? Server[host] } || Server[host]
34 end
35
36 def fetch(role)
37 servers.find_all { |server| server.has_role? role}
38 end
39
40 def fetch_roles(required, options)
41 filter_roles = RoleFilter.for(required, available_roles)
42 HostFilter.for(select(servers_with_roles(filter_roles), options))
43 end
44
45 def servers_with_roles(roles)
46 roles.flat_map { |role| fetch role }.uniq
47 end
48
49 def select(servers, options)
50 servers.select { |server| server.select?(options) }
51 end
52
53 def available_roles
54 servers.flat_map { |server| server.roles_array }.uniq
55 end
56
5759 def servers
58 @servers ||= Set.new
60 @servers ||= []
5961 end
6062
6163 def extract_options(array)
0 require_relative 'configuration/filter'
01 require_relative 'configuration/question'
2 require_relative 'configuration/server'
13 require_relative 'configuration/servers'
2 require_relative 'configuration/server'
34
45 module Capistrano
56 class Configuration
67
7 class << self
8 def env
9 @env ||= new
10 end
11
12 def reset!
13 @env = new
14 end
8 def initialize(config = nil)
9 @config ||= config
1510 end
1611
17 def ask(key, default=nil)
18 question = Question.new(self, key, default)
12 def self.env
13 @env ||= new
14 end
15
16 def self.reset!
17 @env = new
18 end
19
20 def ask(key, default=nil, options={})
21 question = Question.new(key, default, options)
1922 set(key, question)
2023 end
2124
2225 def set(key, value)
2326 config[key] = value
27 end
28
29 def set_if_empty(key, value)
30 config[key] = value unless config.has_key? key
2431 end
2532
2633 def delete(key)
5562 servers.roles_for(names)
5663 end
5764
65 def role_properties_for(names, &block)
66 servers.role_properties_for(names, &block)
67 end
68
5869 def primary(role)
5970 servers.fetch_primary(role)
6071 end
7485 sshkit.backend.configure do |backend|
7586 backend.pty = fetch(:pty)
7687 backend.connection_timeout = fetch(:connection_timeout)
77 backend.ssh_options = fetch(:ssh_options) if fetch(:ssh_options)
88 backend.ssh_options = (backend.ssh_options || {}).merge(fetch(:ssh_options,{}))
7889 end
7990 end
8091 end
8394 @timestamp ||= Time.now.utc
8495 end
8596
97 def setup_filters
98 @filters = cmdline_filters.clone
99 @filters << Filter.new(:role, ENV['ROLES']) if ENV['ROLES']
100 @filters << Filter.new(:host, ENV['HOSTS']) if ENV['HOSTS']
101 fh = fetch_for(:filter,{})
102 @filters << Filter.new(:host, fh[:host]) if fh[:host]
103 @filters << Filter.new(:role, fh[:role]) if fh[:role]
104 end
105
106 def add_cmdline_filter(type, values)
107 cmdline_filters << Filter.new(type, values)
108 end
109
110 def filter list
111 setup_filters if @filters.nil?
112 @filters.reduce(list) { |l,f| f.filter l }
113 end
114
86115 private
116
117 def cmdline_filters
118 @cmdline_filters ||= []
119 end
87120
88121 def servers
89122 @servers ||= Servers.new
0 set :scm, :git
1 set :branch, :master
2 set :deploy_to, -> { "/var/www/#{fetch(:application)}" }
3 set :tmp_dir, "/tmp"
0 set_if_empty :scm, :git
1 set_if_empty :branch, :master
2 set_if_empty :deploy_to, -> { "/var/www/#{fetch(:application)}" }
3 set_if_empty :tmp_dir, "/tmp"
44
5 set :default_env, {}
6 set :keep_releases, 5
5 set_if_empty :default_env, {}
6 set_if_empty :keep_releases, 5
77
8 set :format, :pretty
9 set :log_level, :debug
8 set_if_empty :format, :pretty
9 set_if_empty :log_level, :debug
1010
11 set :pty, false
11 set_if_empty :pty, false
12
13 set_if_empty :local_user, -> { Etc.getlogin }
2222 env.set(key, value)
2323 end
2424
25 def set_if_empty(key, value)
26 env.set_if_empty(key, value)
27 end
28
2529 def delete(key)
2630 env.delete(key)
2731 end
2832
29 def ask(key, value)
30 env.ask(key, value)
33 def ask(key, value, options={})
34 env.ask(key, value, options)
3135 end
3236
3337 def role(name, servers, options={})
4246 env.roles_for(names.flatten)
4347 end
4448
49 def role_properties(*names, &block)
50 env.role_properties_for(names, &block)
51 end
52
4553 def release_roles(*names)
46 names << { exclude: :no_release } unless names.last.is_a? Hash
54 if names.last.is_a? Hash
55 names.last.merge!({ :exclude => :no_release })
56 else
57 names << { exclude: :no_release }
58 end
4759 roles(*names)
4860 end
4961
5353 end
5454
5555 def repo_path
56 deploy_path.join('repo')
56 Pathname.new(fetch(:repo_path, ->(){deploy_path.join('repo')}))
5757 end
5858
5959 def shared_path
0 require 'capistrano/upload_task'
1
02 module Capistrano
13 module TaskEnhancements
24 def before(task, prerequisite, *args, &block)
1820 end
1921
2022 def define_remote_file_task(task, target_roles)
21 Rake::Task.define_task(task) do |t|
23 Capistrano::UploadTask.define_task(task) do |t|
2224 prerequisite_file = t.prerequisites.first
2325 file = shared_path.join(t.name)
2426
2527 on roles(target_roles) do
26 unless test "[ -f #{file} ]"
28 unless test "[ -f #{file.to_s.shellescape} ]"
2729 info "Uploading #{prerequisite_file} to #{file}"
2830 upload! File.open(prerequisite_file), file
2931 end
5052 end
5153
5254 def exit_deploy_because_of_exception(ex)
53 warn t(:deploy_failed, ex: ex.inspect)
55 warn t(:deploy_failed, ex: ex.message)
5456 invoke 'deploy:failed'
5557 exit(false)
5658 end
22 require 'capistrano/dsl/paths'
33 require 'capistrano/dsl/stages'
44 require 'capistrano/dsl/env'
5 require 'capistrano/configuration/filter'
56
67 module Capistrano
78 module DSL
3233 branch: fetch(:branch),
3334 user: local_user,
3435 sha: fetch(:current_revision),
35 release: release_timestamp)
36 release: fetch(:release_timestamp))
3637 )
3738 end
3839
4142 end
4243
4344 def local_user
44 Etc.getlogin
45 fetch(:local_user)
4546 end
4647
4748 def lock(locked_version)
4849 VersionValidator.new(locked_version).verify
4950 end
51
52 def on(hosts, options={}, &block)
53 subset_copy = Marshal.dump(Configuration.env.filter(hosts))
54 SSHKit::Coordinator.new(Marshal.load(subset_copy)).each(options, &block)
55 end
56
57 def run_locally(&block)
58 SSHKit::Backend::Local.new(&block).run
59 end
60
5061 end
5162 end
5263 self.extend Capistrano::DSL
1717 end
1818
1919 def check
20 test! :git, :'ls-remote -h', repo_url
20 git :'ls-remote --heads', repo_url
2121 end
2222
2323 def clone
2929 end
3030
3131 def release
32 git :archive, fetch(:branch), '| tar -x -C', release_path
32 if tree = fetch(:repo_tree)
33 tree = tree.slice %r#^/?(.*?)/?$#, 1
34 components = tree.split('/').size
35 git :archive, fetch(:branch), tree, "| tar -x --strip-components #{components} -f - -C", release_path
36 else
37 git :archive, fetch(:branch), '| tar -x -f - -C', release_path
38 end
3339 end
3440
3541 def fetch_revision
36 context.capture(:git, "rev-parse --short #{fetch(:branch)}")
42 context.capture(:git, "rev-list --max-count=1 --abbrev-commit #{fetch(:branch)}")
3743 end
3844 end
3945 end
2626 end
2727
2828 def release
29 hg "archive", release_path, "--rev", fetch(:branch)
29 if tree = fetch(:repo_tree)
30 tree = tree.slice %r#^/?(.*?)/?$#, 1
31 components = tree.split('/').size
32 hg "archive --type tgz -p . -I", tree, "--rev", fetch(:branch), "| tar -x --strip-components #{components} -f - -C", release_path
33 else
34 hg "archive", release_path, "--rev", fetch(:branch)
35 end
3036 end
3137
3238 def fetch_revision
2727 end
2828
2929 def release
30 svn :export, '.', release_path
30 svn :export, '--force', '.', release_path
3131 end
3232
3333 def fetch_revision
34 context.capture(:svn, "log -r HEAD -q | tail -n 2 | head -n 1 | sed s/\ \|.*/''/")
34 context.capture(:svnversion, repo_path)
3535 end
3636 end
3737 end
4343 desc 'Check shared and release directories exist'
4444 task :directories do
4545 on release_roles :all do
46 execute :mkdir, '-pv', shared_path, releases_path
46 execute :mkdir, '-p', shared_path, releases_path
4747 end
4848 end
4949
5151 task :linked_dirs do
5252 next unless any? :linked_dirs
5353 on release_roles :all do
54 execute :mkdir, '-pv', linked_dirs(shared_path)
54 execute :mkdir, '-p', linked_dirs(shared_path)
5555 end
5656 end
5757
5959 task :make_linked_dirs do
6060 next unless any? :linked_files
6161 on release_roles :all do |host|
62 execute :mkdir, '-pv', linked_file_dirs(shared_path)
62 execute :mkdir, '-p', linked_file_dirs(shared_path)
6363 end
6464 end
6565
8181 desc 'Symlink release to current'
8282 task :release do
8383 on release_roles :all do
84 execute :rm, '-rf', current_path
85 execute :ln, '-s', release_path, current_path
84 tmp_current_path = release_path.parent.join(current_path.basename)
85 execute :ln, '-s', release_path, tmp_current_path
86 execute :mv, tmp_current_path, current_path.parent
8687 end
8788 end
8889
9697 task :linked_dirs do
9798 next unless any? :linked_dirs
9899 on release_roles :all do
99 execute :mkdir, '-pv', linked_dir_parents(release_path)
100 execute :mkdir, '-p', linked_dir_parents(release_path)
100101
101102 fetch(:linked_dirs).each do |dir|
102103 target = release_path.join(dir)
115116 task :linked_files do
116117 next unless any? :linked_files
117118 on release_roles :all do
118 execute :mkdir, '-pv', linked_file_dirs(release_path)
119 execute :mkdir, '-p', linked_file_dirs(release_path)
119120
120121 fetch(:linked_files).each do |file|
121122 target = release_path.join(file)
134135 desc 'Clean up old releases'
135136 task :cleanup do
136137 on release_roles :all do |host|
137 releases = capture(:ls, '-x', releases_path).split
138 releases = capture(:ls, '-xtr', releases_path).split
138139 if releases.count >= fetch(:keep_releases)
139140 info t(:keeping_releases, host: host.to_s, keep_releases: fetch(:keep_releases), releases: releases.count)
140141 directories = (releases - releases.last(fetch(:keep_releases)))
153154 desc 'Remove and archive rolled-back release.'
154155 task :cleanup_rollback do
155156 on release_roles(:all) do
156 last_release = capture(:ls, '-xr', releases_path).split.first
157 last_release = capture(:ls, '-xt', releases_path).split.first
157158 last_release_path = releases_path.join(last_release)
158159 if test "[ `readlink #{current_path}` != #{last_release_path} ]"
159160 execute :tar, '-czf',
188189
189190 task :rollback_release_path do
190191 on release_roles(:all) do
191 releases = capture(:ls, '-xr', releases_path).split
192 releases = capture(:ls, '-xt', releases_path).split
192193 if releases.count < 2
193194 error t(:cannot_rollback)
194195 exit 1
2424 fetch(:branch)
2525 on release_roles :all do
2626 with fetch(:git_environmental_variables) do
27 exit 1 unless strategy.check
27 strategy.check
2828 end
2929 end
3030 end
1313
1414 mkdir_p deploy_dir
1515
16 template = File.read(deploy_rb)
17 file = config_dir.join('deploy.rb')
18 File.open(file, 'w+') do |f|
19 f.write(ERB.new(template).result(binding))
20 puts I18n.t(:written_file, scope: :capistrano, file: file)
21 end
16 entries = [{template: deploy_rb, file: config_dir.join('deploy.rb')}]
17 entries += envs.split(',').map { |stage| {template: stage_rb, file: deploy_dir.join("#{stage}.rb")} }
2218
23 template = File.read(stage_rb)
24 envs.split(',').each do |stage|
25 file = deploy_dir.join("#{stage}.rb")
26 File.open(file, 'w+') do |f|
27 f.write(ERB.new(template).result(binding))
28 puts I18n.t(:written_file, scope: :capistrano, file: file)
19 entries.each do |entry|
20 if File.exists?(entry[:file])
21 warn "[skip] #{entry[:file]} already exists"
22 else
23 File.open(entry[:file], 'w+') do |f|
24 f.write(ERB.new(File.read(entry[:template])).result(binding))
25 puts I18n.t(:written_file, scope: :capistrano, file: entry[:file])
26 end
2927 end
3028 end
3129
3230 mkdir_p tasks_dir
3331
34 FileUtils.cp(capfile, 'Capfile')
32 if File.exists?('Capfile')
33 warn "[skip] Capfile already exists"
34 else
35 FileUtils.cp(capfile, 'Capfile')
36 puts I18n.t(:written_file, scope: :capistrano, file: 'Capfile')
37 end
3538
3639
3740 puts I18n.t :capified, scope: :capistrano
0 # Load DSL and Setup Up Stages
0 # Load DSL and set up stages
11 require 'capistrano/setup'
22
3 # Includes default deployment tasks
3 # Include default deployment tasks
44 require 'capistrano/deploy'
55
6 # Includes tasks from other gems included in your Gemfile
6 # Include tasks from other gems included in your Gemfile
77 #
88 # For documentation on these, see for example:
99 #
1212 # https://github.com/capistrano/chruby
1313 # https://github.com/capistrano/bundler
1414 # https://github.com/capistrano/rails
15 # https://github.com/capistrano/passenger
1516 #
1617 # require 'capistrano/rvm'
1718 # require 'capistrano/rbenv'
1920 # require 'capistrano/bundler'
2021 # require 'capistrano/rails/assets'
2122 # require 'capistrano/rails/migrations'
23 # require 'capistrano/passenger'
2224
23 # Loads custom tasks from `lib/capistrano/tasks' if you have any defined.
25 # Load custom tasks from `lib/capistrano/tasks` if you have any defined
2426 Dir.glob('lib/capistrano/tasks/*.rake').each { |r| import r }
0 # config valid only for Capistrano 3.1
0 # config valid only for current version of Capistrano
11 lock '<%= Capistrano::VERSION %>'
22
33 set :application, 'my_app_name'
44 set :repo_url, 'git@example.com:me/my_repo.git'
55
66 # Default branch is :master
7 # ask :branch, proc { `git rev-parse --abbrev-ref HEAD`.chomp }.call
7 # ask :branch, `git rev-parse --abbrev-ref HEAD`.chomp
88
9 # Default deploy_to directory is /var/www/my_app
10 # set :deploy_to, '/var/www/my_app'
9 # Default deploy_to directory is /var/www/my_app_name
10 # set :deploy_to, '/var/www/my_app_name'
1111
1212 # Default value for :scm is :git
1313 # set :scm, :git
2222 # set :pty, true
2323
2424 # Default value for :linked_files is []
25 # set :linked_files, %w{config/database.yml}
25 # set :linked_files, fetch(:linked_files, []).push('config/database.yml', 'config/secrets.yml')
2626
2727 # Default value for linked_dirs is []
28 # set :linked_dirs, %w{bin log tmp/pids tmp/cache tmp/sockets vendor/bundle public/system}
28 # set :linked_dirs, fetch(:linked_dirs, []).push('log', 'tmp/pids', 'tmp/cache', 'tmp/sockets', 'vendor/bundle', 'public/system')
2929
3030 # Default value for default_env is {}
3131 # set :default_env, { path: "/opt/ruby/bin:$PATH" }
3434 # set :keep_releases, 5
3535
3636 namespace :deploy do
37
38 desc 'Restart application'
39 task :restart do
40 on roles(:app), in: :sequence, wait: 5 do
41 # Your restart mechanism here, for example:
42 # execute :touch, release_path.join('tmp/restart.txt')
43 end
44 end
45
46 after :publishing, :restart
4737
4838 after :restart, :clear_cache do
4939 on roles(:web), in: :groups, limit: 3, wait: 10 do
0 # Simple Role Syntax
1 # ==================
2 # Supports bulk-adding hosts to roles, the primary server in each group
3 # is considered to be the first unless any hosts have the primary
4 # property set. Don't declare `role :all`, it's a meta role.
0 # server-based syntax
1 # ======================
2 # Defines a single server with a list of roles and multiple properties.
3 # You can define all roles on a single server, or split them:
54
6 role :app, %w{deploy@example.com}
7 role :web, %w{deploy@example.com}
8 role :db, %w{deploy@example.com}
5 # server 'example.com', user: 'deploy', roles: %w{app db web}, my_property: :my_value
6 # server 'example.com', user: 'deploy', roles: %w{app web}, other_property: :other_value
7 # server 'db.example.com', user: 'deploy', roles: %w{db}
98
109
11 # Extended Server Syntax
12 # ======================
13 # This can be used to drop a more detailed server definition into the
14 # server list. The second argument is a, or duck-types, Hash and is
15 # used to set extended properties on the server.
1610
17 server 'example.com', user: 'deploy', roles: %w{web app}, my_property: :my_value
11 # role-based syntax
12 # ==================
13
14 # Defines a role with one or multiple servers. The primary server in each
15 # group is considered to be the first unless any hosts have the primary
16 # property set. Specify the username and a domain or IP for the server.
17 # Don't use `:all`, it's a meta role.
18
19 # role :app, %w{deploy@example.com}, my_property: :my_value
20 # role :web, %w{user1@primary.com user2@additional.com}, other_property: :other_value
21 # role :db, %w{deploy@example.com}
22
23
24
25 # Configuration
26 # =============
27 # You can set any configuration variable like in config/deploy.rb
28 # These variables are then only loaded and set in this stage.
29 # For available Capistrano configuration variables see the documentation page.
30 # http://capistranorb.com/documentation/getting-started/configuration/
31 # Feel free to add new variables to customise your setup.
32
1833
1934
2035 # Custom SSH Options
2136 # ==================
2237 # You may pass any option but keep in mind that net/ssh understands a
23 # limited set of options, consult[net/ssh documentation](http://net-ssh.github.io/net-ssh/classes/Net/SSH.html#method-c-start).
38 # limited set of options, consult the Net::SSH documentation.
39 # http://net-ssh.github.io/net-ssh/classes/Net/SSH.html#method-c-start
2440 #
2541 # Global options
2642 # --------------
3046 # auth_methods: %w(password)
3147 # }
3248 #
33 # And/or per server (overrides global)
49 # The server-based syntax can be used to override options:
3450 # ------------------------------------
3551 # server 'example.com',
3652 # user: 'user_name',
0 require 'rake/file_creation_task'
1
2 module Capistrano
3 class UploadTask < Rake::FileCreationTask
4 def needed?
5 true # always needed because we can't check remote hosts
6 end
7 end
8 end
00 module Capistrano
1 VERSION = "3.2.1"
1 VERSION = "3.4.0"
22 end
00 --- !ruby/object:Gem::Specification
11 name: capistrano
22 version: !ruby/object:Gem::Version
3 version: 3.2.1
3 version: 3.4.0
44 platform: ruby
55 authors:
66 - Tom Clements
88 autorequire:
99 bindir: bin
1010 cert_chain: []
11 date: 2014-04-22 00:00:00.000000000 Z
11 date: 2015-03-02 00:00:00.000000000 Z
1212 dependencies:
1313 - !ruby/object:Gem::Dependency
1414 name: sshkit
1515 requirement: !ruby/object:Gem::Requirement
1616 requirements:
17 - - ~>
17 - - "~>"
1818 - !ruby/object:Gem::Version
1919 version: '1.3'
2020 type: :runtime
2121 prerelease: false
2222 version_requirements: !ruby/object:Gem::Requirement
2323 requirements:
24 - - ~>
24 - - "~>"
2525 - !ruby/object:Gem::Version
2626 version: '1.3'
2727 - !ruby/object:Gem::Dependency
2828 name: rake
2929 requirement: !ruby/object:Gem::Requirement
3030 requirements:
31 - - '>='
31 - - ">="
3232 - !ruby/object:Gem::Version
3333 version: 10.0.0
3434 type: :runtime
3535 prerelease: false
3636 version_requirements: !ruby/object:Gem::Requirement
3737 requirements:
38 - - '>='
38 - - ">="
3939 - !ruby/object:Gem::Version
4040 version: 10.0.0
4141 - !ruby/object:Gem::Dependency
4242 name: i18n
4343 requirement: !ruby/object:Gem::Requirement
4444 requirements:
45 - - '>='
45 - - ">="
4646 - !ruby/object:Gem::Version
4747 version: '0'
4848 type: :runtime
4949 prerelease: false
5050 version_requirements: !ruby/object:Gem::Requirement
5151 requirements:
52 - - '>='
52 - - ">="
5353 - !ruby/object:Gem::Version
5454 version: '0'
5555 - !ruby/object:Gem::Dependency
5656 name: rspec
5757 requirement: !ruby/object:Gem::Requirement
5858 requirements:
59 - - '>='
59 - - ">="
6060 - !ruby/object:Gem::Version
6161 version: '0'
6262 type: :development
6363 prerelease: false
6464 version_requirements: !ruby/object:Gem::Requirement
6565 requirements:
66 - - '>='
66 - - ">="
6767 - !ruby/object:Gem::Version
6868 version: '0'
6969 - !ruby/object:Gem::Dependency
7070 name: mocha
7171 requirement: !ruby/object:Gem::Requirement
7272 requirements:
73 - - '>='
73 - - ">="
7474 - !ruby/object:Gem::Version
7575 version: '0'
7676 type: :development
7777 prerelease: false
7878 version_requirements: !ruby/object:Gem::Requirement
7979 requirements:
80 - - '>='
80 - - ">="
8181 - !ruby/object:Gem::Version
8282 version: '0'
8383 description: Capistrano is a utility and framework for executing commands in parallel
9191 extensions: []
9292 extra_rdoc_files: []
9393 files:
94 - .gitignore
95 - .travis.yml
94 - ".gitignore"
95 - ".travis.yml"
9696 - CHANGELOG.md
9797 - CONTRIBUTING.md
9898 - Gemfile
107107 - features/deploy_failure.feature
108108 - features/installation.feature
109109 - features/remote_file_task.feature
110 - features/sshconnect.feature
110111 - features/step_definitions/assertions.rb
111112 - features/step_definitions/cap_commands.rb
112113 - features/step_definitions/setup.rb
113114 - features/support/env.rb
114115 - features/support/remote_command_helpers.rb
116 - features/support/vagrant_helpers.rb
115117 - lib/Capfile
116118 - lib/capistrano.rb
117119 - lib/capistrano/all.rb
118120 - lib/capistrano/application.rb
119121 - lib/capistrano/configuration.rb
122 - lib/capistrano/configuration/filter.rb
120123 - lib/capistrano/configuration/question.rb
121124 - lib/capistrano/configuration/server.rb
122125 - lib/capistrano/configuration/servers.rb
123 - lib/capistrano/configuration/servers/host_filter.rb
124 - lib/capistrano/configuration/servers/role_filter.rb
125126 - lib/capistrano/console.rb
126127 - lib/capistrano/defaults.rb
127128 - lib/capistrano/deploy.rb
149150 - lib/capistrano/templates/Capfile
150151 - lib/capistrano/templates/deploy.rb.erb
151152 - lib/capistrano/templates/stage.rb.erb
153 - lib/capistrano/upload_task.rb
152154 - lib/capistrano/version.rb
153155 - lib/capistrano/version_validator.rb
154156 - spec/integration/dsl_spec.rb
155157 - spec/integration_spec_helper.rb
156158 - spec/lib/capistrano/application_spec.rb
159 - spec/lib/capistrano/configuration/filter_spec.rb
157160 - spec/lib/capistrano/configuration/question_spec.rb
158161 - spec/lib/capistrano/configuration/server_spec.rb
159 - spec/lib/capistrano/configuration/servers/host_filter_spec.rb
160 - spec/lib/capistrano/configuration/servers/role_filter_spec.rb
161162 - spec/lib/capistrano/configuration/servers_spec.rb
162163 - spec/lib/capistrano/configuration_spec.rb
163164 - spec/lib/capistrano/dsl/paths_spec.rb
165 - spec/lib/capistrano/dsl/task_enhancements_spec.rb
164166 - spec/lib/capistrano/dsl_spec.rb
165167 - spec/lib/capistrano/git_spec.rb
166168 - spec/lib/capistrano/hg_spec.rb
167169 - spec/lib/capistrano/scm_spec.rb
168170 - spec/lib/capistrano/svn_spec.rb
171 - spec/lib/capistrano/upload_task_spec.rb
169172 - spec/lib/capistrano/version_validator_spec.rb
170173 - spec/lib/capistrano_spec.rb
171174 - spec/spec_helper.rb
175178 - spec/support/tasks/database.rake
176179 - spec/support/tasks/fail.rake
177180 - spec/support/tasks/failed.rake
181 - spec/support/tasks/root.rake
178182 - spec/support/test_app.rb
179183 homepage: http://capistranorb.com/
180184 licenses:
181185 - MIT
182186 metadata: {}
183187 post_install_message: |
184 Capistrano 3.1 has some breaking changes, like `deploy:restart` callback should be added manually to your deploy.rb. Please, check the CHANGELOG: http://goo.gl/SxB0lr
188 Capistrano 3.1 has some breaking changes. Please check the CHANGELOG: http://goo.gl/SxB0lr
185189
186190 If you're upgrading Capistrano from 2.x, we recommend to read the upgrade guide: http://goo.gl/4536kB
191
192 The `deploy:restart` hook for passenger applications is now in a separate gem called capistrano-passenger. Just add it to your Gemfile and require it in your Capfile.
187193 rdoc_options: []
188194 require_paths:
189195 - lib
190196 required_ruby_version: !ruby/object:Gem::Requirement
191197 requirements:
192 - - '>='
198 - - ">="
193199 - !ruby/object:Gem::Version
194 version: '0'
200 version: 1.9.3
195201 required_rubygems_version: !ruby/object:Gem::Requirement
196202 requirements:
197 - - '>='
203 - - ">="
198204 - !ruby/object:Gem::Version
199205 version: '0'
200206 requirements: []
201207 rubyforge_project:
202 rubygems_version: 2.0.3
208 rubygems_version: 2.4.3
203209 signing_key:
204210 specification_version: 4
205211 summary: Capistrano - Welcome to easy deployment with Ruby over SSH
209215 - features/deploy_failure.feature
210216 - features/installation.feature
211217 - features/remote_file_task.feature
218 - features/sshconnect.feature
212219 - features/step_definitions/assertions.rb
213220 - features/step_definitions/cap_commands.rb
214221 - features/step_definitions/setup.rb
215222 - features/support/env.rb
216223 - features/support/remote_command_helpers.rb
224 - features/support/vagrant_helpers.rb
217225 - spec/integration/dsl_spec.rb
218226 - spec/integration_spec_helper.rb
219227 - spec/lib/capistrano/application_spec.rb
228 - spec/lib/capistrano/configuration/filter_spec.rb
220229 - spec/lib/capistrano/configuration/question_spec.rb
221230 - spec/lib/capistrano/configuration/server_spec.rb
222 - spec/lib/capistrano/configuration/servers/host_filter_spec.rb
223 - spec/lib/capistrano/configuration/servers/role_filter_spec.rb
224231 - spec/lib/capistrano/configuration/servers_spec.rb
225232 - spec/lib/capistrano/configuration_spec.rb
226233 - spec/lib/capistrano/dsl/paths_spec.rb
234 - spec/lib/capistrano/dsl/task_enhancements_spec.rb
227235 - spec/lib/capistrano/dsl_spec.rb
228236 - spec/lib/capistrano/git_spec.rb
229237 - spec/lib/capistrano/hg_spec.rb
230238 - spec/lib/capistrano/scm_spec.rb
231239 - spec/lib/capistrano/svn_spec.rb
240 - spec/lib/capistrano/upload_task_spec.rb
232241 - spec/lib/capistrano/version_validator_spec.rb
233242 - spec/lib/capistrano_spec.rb
234243 - spec/spec_helper.rb
238247 - spec/support/tasks/database.rake
239248 - spec/support/tasks/fail.rake
240249 - spec/support/tasks/failed.rake
250 - spec/support/tasks/root.rake
241251 - spec/support/test_app.rb
242 has_rdoc:
1414 dsl.server 'example2.com', roles: %w{web}
1515 dsl.server 'example3.com', roles: %w{app web}, active: true
1616 dsl.server 'example4.com', roles: %w{app}, primary: true
17 dsl.server 'example5.com', roles: %w{db}, no_release: true
17 dsl.server 'example5.com', roles: %w{db}, no_release: true, active:true
1818 end
1919
2020 describe 'fetching all servers' do
3535 end
3636 end
3737
38 context 'with filter options' do
38 context 'with property filter options' do
3939 subject { dsl.release_roles(:all, filter: :active) }
4040
41 it 'returns all release servers that match the filter' do
41 it 'returns all release servers that match the property filter' do
4242 expect(subject.map(&:hostname)).to eq %w{example1.com example3.com}
4343 end
4444 end
9191 end
9292 end
9393
94 context 'when the attribute `primary` is explicity set' do
94 context 'when the attribute `primary` is explicitly set' do
9595 subject { dsl.primary(:app) }
9696 it 'returns the servers' do
9797 expect(subject.hostname).to eq 'example4.com'
9898 end
99 end
100 end
101
102 describe 'setting an internal host filter' do
103 subject { dsl.roles(:app) }
104 it 'is ignored' do
105 dsl.set :filter, { host: 'example3.com' }
106 expect(subject.map(&:hostname)).to eq(['example3.com', 'example4.com'])
107 end
108 end
109
110 describe 'setting an internal role filter' do
111 subject { dsl.roles(:app) }
112 it 'ignores it' do
113 dsl.set :filter, { role: :web }
114 expect(subject.map(&:hostname)).to eq(['example3.com','example4.com'])
115 end
116 end
117
118 describe 'setting an internal host and role filter' do
119 subject { dsl.roles(:app) }
120 it 'ignores it' do
121 dsl.set :filter, { role: :web, host: 'example1.com' }
122 expect(subject.map(&:hostname)).to eq(['example3.com','example4.com'])
123 end
124 end
125
126 describe 'setting an internal regexp host filter' do
127 subject { dsl.roles(:all) }
128 it 'is ignored' do
129 dsl.set :filter, { host: /1/ }
130 expect(subject.map(&:hostname)).to eq(%w{example1.com example2.com example3.com example4.com example5.com})
99131 end
100132 end
101133
208240 end
209241
210242 describe 'fetching all servers' do
211 subject { dsl.roles(:all).map { |server| "#{server.user}@#{server.hostname}:#{server.port}" } }
212
213 it 'creates a server instance for each unique user@host:port combination' do
214 expect(subject).to eq %w{db@example1.com:1234 root@example1.com:1234 @example1.com:5678 deployer@example1.com:1234}
243 it 'creates one server per hostname, ignoring user and port combinations' do
244 expect(dsl.roles(:all).size).to eq(1)
215245 end
216246 end
217247
218248 describe 'fetching servers for a role' do
219249 it 'roles defined using the `server` syntax are included' do
220 expect(dsl.roles(:web)).to have(2).items
250 as = dsl.roles(:web).map { |server| "#{server.user}@#{server.hostname}:#{server.port}" }
251 expect(as.size).to eq(1)
252 expect(as[0]).to eq("deployer@example1.com:5678")
221253 end
222254
223255 it 'roles defined using the `role` syntax are included' do
224 expect(dsl.roles(:app)).to have(2).items
225 end
226 end
227
256 as = dsl.roles(:app).map { |server| "#{server.user}@#{server.hostname}:#{server.port}" }
257 expect(as.size).to eq(1)
258 expect(as[0]).to eq("deployer@example1.com:5678")
259 end
260 end
261
262 end
263
264 describe 'when setting user and port' do
265 subject { dsl.roles(:all).map { |server| "#{server.user}@#{server.hostname}:#{server.port}" }.first }
266
267 describe "using the :user property" do
268 it "takes precedence over in the host string" do
269 dsl.server 'db@example1.com:1234', roles: %w{db}, active: true, user: 'brian'
270 expect(subject).to eq("brian@example1.com:1234")
271 end
272 end
273
274 describe "using the :port property" do
275 it "takes precedence over in the host string" do
276 dsl.server 'db@example1.com:9090', roles: %w{db}, active: true, port: 1234
277 expect(subject).to eq("db@example1.com:1234")
278 end
279 end
228280 end
229281
230282 end
316368 context 'variable is an non-empty array' do
317369 let(:linked_files) { %w{1} }
318370
319 it { should be_true }
371 it { expect(subject).to be_truthy }
320372 end
321373
322374 context 'variable is an empty array' do
323375 let(:linked_files) { [] }
324 it { should be_false }
376 it { expect(subject).to be_falsey }
325377 end
326378
327379 context 'variable exists, is not an array' do
328380 let(:linked_files) { stub }
329 it { should be_true }
381 it { expect(subject).to be_truthy }
330382 end
331383
332384 context 'variable is nil' do
333385 let(:linked_files) { nil }
334 it { should be_false }
386 it { expect(subject).to be_falsey }
335387 end
336388 end
337389
367419 end
368420
369421 it 'sets the backend pty' do
370 expect(backend.pty).to be_true
422 expect(backend.pty).to be_truthy
371423 end
372424
373425 it 'sets the backend connection timeout' do
382434
383435 end
384436
385 describe 'release path' do
386
387 before do
388 dsl.set(:deploy_to, '/var/www')
389 end
390
391 describe 'fetching release path' do
392 subject { dsl.release_path }
393
394 context 'where no release path has been set' do
437 describe 'local_user' do
438 before do
439 dsl.set :local_user, -> { Etc.getlogin }
440 end
441
442 describe 'fetching local_user' do
443 subject { dsl.local_user }
444
445 context 'where a local_user is not set' do
395446 before do
396 dsl.delete(:release_path)
397 end
398
399 it 'returns the `current_path` value' do
400 expect(subject.to_s).to eq '/var/www/current'
401 end
402 end
403
404 context 'where the release path has been set' do
447 Etc.expects(:getlogin).returns('login')
448 end
449
450 it 'returns the login name' do
451 expect(subject.to_s).to eq 'login'
452 end
453 end
454
455 context 'where a local_user is set' do
405456 before do
406 dsl.set(:release_path, '/var/www/release_path')
407 end
408
409 it 'returns the set `release_path` value' do
410 expect(subject.to_s).to eq '/var/www/release_path'
411 end
412 end
413 end
414
415 describe 'setting release path' do
416 let(:now) { Time.parse("Oct 21 16:29:00 2015") }
417 subject { dsl.release_path }
418
419 context 'without a timestamp' do
420 before do
421 dsl.env.expects(:timestamp).returns(now)
422 dsl.set_release_path
423 end
424
425 it 'returns the release path with the current env timestamp' do
426 expect(subject.to_s).to eq '/var/www/releases/20151021162900'
427 end
428 end
429
430 context 'with a timestamp' do
431 before do
432 dsl.set_release_path('timestamp')
433 end
434
435 it 'returns the release path with the timestamp' do
436 expect(subject.to_s).to eq '/var/www/releases/timestamp'
437 end
438 end
439 end
440
441 describe 'setting deploy configuration path' do
442 subject { dsl.deploy_config_path.to_s }
443
444 context 'where no config path is set' do
445 before do
446 dsl.delete(:deploy_config_path)
447 end
448
449 it 'returns "config/deploy.rb"' do
450 expect(subject).to eq 'config/deploy.rb'
451 end
452 end
453
454 context 'where a custom path is set' do
455 before do
456 dsl.set(:deploy_config_path, 'my/custom/path.rb')
457 end
458
459 it 'returns the custom path' do
460 expect(subject).to eq 'my/custom/path.rb'
461 end
462 end
463 end
464
465 describe 'setting stage configuration path' do
466 subject { dsl.stage_config_path.to_s }
467
468 context 'where no config path is set' do
469
470 before do
471 dsl.delete(:stage_config_path)
472 end
473
474 it 'returns "config/deploy"' do
475 expect(subject).to eq 'config/deploy'
476 end
477 end
478
479 context 'where a custom path is set' do
480 before do
481 dsl.set(:stage_config_path, 'my/custom/path')
482 end
483
484 it 'returns the custom path' do
485 expect(subject).to eq 'my/custom/path'
486 end
487 end
488 end
489 end
457 dsl.set(:local_user, -> { 'custom login' })
458 end
459
460 it 'returns the custom name' do
461 expect(subject.to_s).to eq 'custom login'
462 end
463 end
464 end
465 end
466
467 describe 'on()' do
468
469 before do
470 dsl.server 'example1.com', roles: %w{web}, active: true
471 dsl.server 'example2.com', roles: %w{web}
472 dsl.server 'example3.com', roles: %w{app web}, active: true
473 dsl.server 'example4.com', roles: %w{app}, primary: true
474 dsl.server 'example5.com', roles: %w{db}, no_release: true
475 @coordinator = mock('coordinator')
476 @coordinator.expects(:each).returns(nil)
477 ENV.delete 'ROLES'
478 ENV.delete 'HOSTS'
479
480 end
481
482 it 'filters by role from the :filter variable' do
483 hosts = dsl.roles(:web)
484 all = dsl.roles(:all)
485 SSHKit::Coordinator.expects(:new).with(hosts).returns(@coordinator)
486 dsl.set :filter, { role: 'web' }
487 dsl.on(all)
488 end
489
490 it 'filters by host and role from the :filter variable' do
491 all = dsl.roles(:all)
492 SSHKit::Coordinator.expects(:new).with([]).returns(@coordinator)
493 dsl.set :filter, { role: 'db', host: 'example3.com' }
494 dsl.on(all)
495 end
496
497 it 'filters from ENV[ROLES]' do
498 hosts = dsl.roles(:db)
499 all = dsl.roles(:all)
500 SSHKit::Coordinator.expects(:new).with(hosts).returns(@coordinator)
501 ENV['ROLES'] = 'db'
502 dsl.on(all)
503 end
504
505 it 'filters from ENV[HOSTS]' do
506 hosts = dsl.roles(:db)
507 all = dsl.roles(:all)
508 SSHKit::Coordinator.expects(:new).with(hosts).returns(@coordinator)
509 ENV['HOSTS'] = 'example5.com'
510 dsl.on(all)
511 end
512
513 it 'filters by ENV[HOSTS] && ENV[ROLES]' do
514 all = dsl.roles(:all)
515 SSHKit::Coordinator.expects(:new).with([]).returns(@coordinator)
516 ENV['HOSTS'] = 'example5.com'
517 ENV['ROLES'] = 'web'
518 dsl.on(all)
519 end
520
521 end
522
523 describe 'role_properties()' do
524
525 before do
526 dsl.role :redis, %w[example1.com example2.com], redis: { port: 6379, type: :slave }
527 dsl.server 'example1.com', roles: %w{web}, active: true, web: { port: 80 }
528 dsl.server 'example2.com', roles: %w{web redis}, web: { port: 81 }, redis: { type: :master }
529 dsl.server 'example3.com', roles: %w{app}, primary: true
530 end
531
532 it 'retrieves properties for a single role as a set' do
533 rps = dsl.role_properties(:app)
534 expect(rps).to eq(Set[{ hostname: 'example3.com', role: :app}])
535 end
536
537 it 'retrieves properties for multiple roles as a set' do
538 rps = dsl.role_properties(:app, :web)
539 expect(rps).to eq(Set[{ hostname: 'example3.com', role: :app},{ hostname: 'example1.com', role: :web, port: 80},{ hostname: 'example2.com', role: :web, port: 81}])
540 end
541
542 it 'yields the properties for a single role' do
543 recipient = mock('recipient')
544 recipient.expects(:doit).with('example1.com', :redis, { port: 6379, type: :slave})
545 recipient.expects(:doit).with('example2.com', :redis, { port: 6379, type: :master})
546 dsl.role_properties(:redis) do |host, role, props|
547 recipient.doit(host, role, props)
548 end
549 end
550
551 it 'yields the properties for multiple roles' do
552 recipient = mock('recipient')
553 recipient.expects(:doit).with('example1.com', :redis, { port: 6379, type: :slave})
554 recipient.expects(:doit).with('example2.com', :redis, { port: 6379, type: :master})
555 recipient.expects(:doit).with('example3.com', :app, nil)
556 dsl.role_properties(:redis, :app) do |host, role, props|
557 recipient.doit(host, role, props)
558 end
559 end
560
561 it 'yields the merged properties for multiple roles' do
562 recipient = mock('recipient')
563 recipient.expects(:doit).with('example1.com', :redis, { port: 6379, type: :slave})
564 recipient.expects(:doit).with('example2.com', :redis, { port: 6379, type: :master})
565 recipient.expects(:doit).with('example1.com', :web, { port: 80 })
566 recipient.expects(:doit).with('example2.com', :web, { port: 81 })
567 dsl.role_properties(:redis, :web) do |host, role, props|
568 recipient.doit(host, role, props)
569 end
570 end
571
572 it 'honours a property filter before yielding' do
573 recipient = mock('recipient')
574 recipient.expects(:doit).with('example1.com', :redis, { port: 6379, type: :slave})
575 recipient.expects(:doit).with('example1.com', :web, { port: 80 })
576 dsl.role_properties(:redis, :web, select: :active) do |host, role, props|
577 recipient.doit(host, role, props)
578 end
579 end
580 end
581
490582 end
55
66 it "provides a --format option which enables the choice of output formatting"
77
8 it "identifies itself as cap and not rake" do
8 let(:help_output) do
99 out, _ = capture_io do
1010 flags '--help', '-h'
1111 end
12 out.lines.first.should match(/cap \[-f rakefile\]/)
12 out
13 end
14
15 it "displays documentation URL as help banner" do
16 expect(help_output.lines.first).to match(/capistranorb.com/)
17 end
18
19 %w(quiet silent verbose).each do |switch|
20 it "doesn't include --#{switch} in help" do
21 expect(help_output).not_to match(/--#{switch}/)
22 end
1323 end
1424
1525 it "overrides the rake method, but still prints the rake version" do
1626 out, _ = capture_io do
1727 flags '--version', '-V'
1828 end
19 out.should match(/\bCapistrano Version\b/)
20 out.should match(/\b#{Capistrano::VERSION}\b/)
21 out.should match(/\bRake Version\b/)
22 out.should match(/\b#{RAKEVERSION}\b/)
29 expect(out).to match(/\bCapistrano Version\b/)
30 expect(out).to match(/\b#{Capistrano::VERSION}\b/)
31 expect(out).to match(/\bRake Version\b/)
32 expect(out).to match(/\b#{RAKEVERSION}\b/)
33 end
34
35 it "overrides the rake method, and sets the sshkit_backend to SSHKit::Backend::Printer" do
36 out, _ = capture_io do
37 flags '--dry-run', '-n'
38 end
39 sshkit_backend = Capistrano::Configuration.fetch(:sshkit_backend)
40 expect(sshkit_backend).to eq(SSHKit::Backend::Printer)
2341 end
2442
2543 def flags(*sets)
0 require 'spec_helper'
1
2 module Capistrano
3 class Configuration
4
5 describe Filter do
6 let(:available) { [ Server.new('server1').add_roles([:web,:db]),
7 Server.new('server2').add_role(:web),
8 Server.new('server3').add_role(:redis),
9 Server.new('server4').add_role(:db),
10 Server.new('server5').add_role(:stageweb) ] }
11
12 describe '#new' do
13 it "won't create an invalid type of filter" do
14 expect {
15 f = Filter.new(:zarg)
16 }.to raise_error RuntimeError
17 end
18
19 it 'creates an empty host filter' do
20 expect(Filter.new(:host).filter(available)).to be_empty
21 end
22
23 it 'creates a null host filter' do
24 expect(Filter.new(:host, :all).filter(available)).to eq(available)
25 end
26
27 it 'creates an empty role filter' do
28 expect(Filter.new(:role).filter(available)).to be_empty
29 end
30
31 it 'creates a null role filter' do
32 expect(Filter.new(:role, :all).filter(available)).to eq(available)
33 end
34
35 end
36
37 describe 'host filter' do
38 it 'works with a single server' do
39 set = Filter.new(:host, 'server1').filter(available.first)
40 expect(set.map(&:hostname)).to eq(%w{server1})
41 end
42 it 'returns all hosts matching a string' do
43 set = Filter.new(:host, 'server1').filter(available)
44 expect(set.map(&:hostname)).to eq(%w{server1})
45 end
46 it 'returns all hosts matching a comma-separated string' do
47 set = Filter.new(:host, 'server1,server3').filter(available)
48 expect(set.map(&:hostname)).to eq(%w{server1 server3})
49 end
50 it 'returns all hosts matching an array of strings' do
51 set = Filter.new(:host, %w{server1 server3}).filter(available)
52 expect(set.map(&:hostname)).to eq(%w{server1 server3})
53 end
54 it 'returns all hosts matching regexp' do
55 set = Filter.new(:host, 'server[13]$').filter(available)
56 expect(set.map(&:hostname)).to eq(%w{server1 server3})
57 end
58 it 'correctly identifies a regex with a comma in' do
59 set = Filter.new(:host, 'server\d{1,3}$').filter(available)
60 expect(set.map(&:hostname)).to eq(%w{server1 server2 server3 server4 server5})
61 end
62 end
63
64 describe 'role filter' do
65 it 'returns all hosts' do
66 set = Filter.new(:role, [:all]).filter(available)
67 expect(set.size).to eq(available.size)
68 expect(set.first.hostname).to eq('server1')
69 end
70 it 'returns hosts in a single string role' do
71 set = Filter.new(:role, 'web').filter(available)
72 expect(set.size).to eq(2)
73 expect(set.map(&:hostname)).to eq(%w{server1 server2})
74 end
75 it 'returns hosts in a single role' do
76 set = Filter.new(:role, [:web]).filter(available)
77 expect(set.size).to eq(2)
78 expect(set.map(&:hostname)).to eq(%w{server1 server2})
79 end
80 it 'returns hosts in multiple roles specified by a string' do
81 set = Filter.new(:role, 'web,db').filter(available)
82 expect(set.size).to eq(3)
83 expect(set.map(&:hostname)).to eq(%w{server1 server2 server4})
84 end
85 it 'returns hosts in multiple roles' do
86 set = Filter.new(:role, [:web, :db]).filter(available)
87 expect(set.size).to eq(3)
88 expect(set.map(&:hostname)).to eq(%w{server1 server2 server4})
89 end
90 it 'returns only hosts for explicit roles' do
91 set = Filter.new(:role, [:web]).filter(available)
92 expect(set.size).to eq(2)
93 expect(set.map(&:hostname)).to eq(%w{server1 server2})
94 end
95 it 'returns hosts with regex role selection' do
96 set = Filter.new(:role, /red/).filter(available)
97 expect(set.map(&:hostname)).to eq(%w{server3})
98 end
99 it 'returns hosts with regex role selection using a string' do
100 set = Filter.new(:role, '/red|web/').filter(available)
101 expect(set.map(&:hostname)).to eq(%w{server1 server2 server3 server5})
102 end
103 it 'returns hosts with combination of string role and regex' do
104 set = Filter.new(:role, 'db,/red/').filter(available)
105 expect(set.map(&:hostname)).to eq(%w{server1 server3 server4})
106 end
107 end
108 end
109 end
110 end
44
55 describe Question do
66
7 let(:question) { Question.new(env, key, default) }
7 let(:question) { Question.new(key, default, options) }
8 let(:question_without_echo) { Question.new(key, default, echo: false) }
89 let(:default) { :default }
910 let(:key) { :branch }
10 let(:env) { stub }
11 let(:options) { nil }
1112
1213 describe '.new' do
13 it 'takes a key, default' do
14 it 'takes a key, default, options' do
1415 question
1516 end
1617 end
1718
1819 describe '#call' do
19 subject { question.call }
20
2120 context 'value is entered' do
2221 let(:branch) { 'branch' }
2322
2423 before do
2524 $stdout.expects(:print).with('Please enter branch (default): ')
26 $stdin.expects(:gets).returns(branch)
2725 end
2826
29 it 'sets the value' do
30 env.expects(:set).with(key, branch)
31 question.call
27 it 'returns the echoed value' do
28 $stdin.expects(:gets).returns(branch)
29 $stdin.expects(:noecho).never
30
31 expect(question.call).to eq(branch)
32 end
33
34 it 'returns the value but does not echo it' do
35 $stdin.expects(:noecho).returns(branch)
36 $stdout.expects(:print).with("\n")
37
38 expect(question_without_echo.call).to eq(branch)
3239 end
3340 end
3441
4047 $stdin.expects(:gets).returns('')
4148 end
4249
43 it 'sets the default as the value' do
44 env.expects(:set).with(key, branch)
45 question.call
50
51 it 'returns the default as the value' do
52 expect(question.call).to eq(branch)
4653 end
47
4854 end
4955 end
5056 end
2727 end
2828
2929 it 'adds the role' do
30 expect{subject}.to be_true
30 expect(subject).to be_truthy
3131 end
3232 end
3333
3434 describe 'comparing identity' do
35 subject { server.matches? Server[hostname] }
35 subject { server.hostname == Server[hostname].hostname }
3636
3737 context 'with the same user, hostname and port' do
3838 let(:hostname) { 'root@hostname:1234' }
39 it { should be_true }
39 it { expect(subject).to be_truthy }
4040 end
4141
4242 context 'with a different user' do
4343 let(:hostname) { 'deployer@hostname:1234' }
44 it { should be_false }
44 it { expect(subject).to be_truthy }
4545 end
4646
4747 context 'with a different port' do
4848 let(:hostname) { 'root@hostname:5678' }
49 it { should be_false }
49 it { expect(subject).to be_truthy }
5050 end
5151
5252 context 'with a different hostname' do
5353 let(:hostname) { 'root@otherserver:1234' }
54 it { should be_false }
54 it { expect(subject).to be_falsey }
5555 end
5656 end
5757
6868
6969 context 'server is not primary' do
7070 it 'is falesy' do
71 expect(subject).to be_false
71 expect(subject).to be_falsey
7272 end
7373 end
7474 end
9292
9393 it 'sets the user' do
9494 expect(server.user).to eq 'tomc'
95 end
96
97 it 'sets the netssh_options user' do
98 expect(server.netssh_options[:user]).to eq 'tomc'
9599 end
96100 end
97101
148152 end
149153
150154 context 'options are empty' do
151 it { should be_true }
155 it { expect(subject).to be_truthy }
152156 end
153157
154158 context 'value is a symbol' do
156160
157161 context 'with :filter' do
158162 let(:options) { { filter: :active }}
159 it { should be_true }
163 it { expect(subject).to be_truthy }
160164 end
161165
162166 context 'with :select' do
163167 let(:options) { { select: :active }}
164 it { should be_true }
168 it { expect(subject).to be_truthy }
165169 end
166170
167171 context 'with :exclude' do
168172 let(:options) { { exclude: :active }}
169 it { should be_false }
173 it { expect(subject).to be_falsey }
174 end
175 end
176
177 context 'value does not match server properly' do
178 context 'with :active true' do
179 let(:options) { { active: true }}
180 it { expect(subject).to be_truthy }
181 end
182
183 context 'with :active false' do
184 let(:options) { { active: false }}
185 it { expect(subject).to be_falsey }
170186 end
171187 end
172188
173189 context 'value does not match server properly' do
174190 context 'with :filter' do
175191 let(:options) { { filter: :inactive }}
176 it { should be_false }
192 it { expect(subject).to be_falsey }
177193 end
178194
179195 context 'with :select' do
180196 let(:options) { { select: :inactive }}
181 it { should be_false }
197 it { expect(subject).to be_falsey }
182198 end
183199
184200 context 'with :exclude' do
185201 let(:options) { { exclude: :inactive }}
186 it { should be_true }
187 end
202 it { expect(subject).to be_truthy }
203 end
204 end
205 end
206
207 context 'key is a property' do
208 context 'with :active true' do
209 let(:options) { { active: true }}
210 it { expect(subject).to be_truthy }
211 end
212
213 context 'with :active false' do
214 let(:options) { { active: false }}
215 it { expect(subject).to be_falsey }
188216 end
189217 end
190218
193221
194222 context 'with :filter' do
195223 let(:options) { { filter: ->(s) { s.properties.active } } }
196 it { should be_true }
224 it { expect(subject).to be_truthy }
197225 end
198226
199227 context 'with :select' do
200228 let(:options) { { select: ->(s) { s.properties.active } } }
201 it { should be_true }
229 it { expect(subject).to be_truthy }
202230 end
203231
204232 context 'with :exclude' do
205233 let(:options) { { exclude: ->(s) { s.properties.active } } }
206 it { should be_false }
234 it { expect(subject).to be_falsey }
207235 end
208236
209237 end
211239 context 'value does not match server properly' do
212240 context 'with :filter' do
213241 let(:options) { { filter: ->(s) { s.properties.inactive } } }
214 it { should be_false }
242 it { expect(subject).to be_falsey }
215243 end
216244
217245 context 'with :select' do
218246 let(:options) { { select: ->(s) { s.properties.inactive } } }
219 it { should be_false }
247 it { expect(subject).to be_falsey }
220248 end
221249
222250 context 'with :exclude' do
223251 let(:options) { { exclude: ->(s) { s.properties.inactive } } }
224 it { should be_true }
252 it { expect(subject).to be_truthy }
225253 end
226254
227255 end
260288 it 'contains correct user' do
261289 expect(server.netssh_options[:user]).to eq 'another_user'
262290 end
291 it 'does not affect server user in host' do
292 expect(server.user).to eq 'user_name'
293 end
263294 it 'contains keys' do
264295 expect(server.netssh_options[:keys]).to eq %w(/home/another_user/.ssh/id_rsa)
265296 end
+0
-84
spec/lib/capistrano/configuration/servers/host_filter_spec.rb less more
0 require 'spec_helper'
1
2 module Capistrano
3 class Configuration
4 class Servers
5
6 describe HostFilter do
7 let(:host_filter) { HostFilter.new(available) }
8 let(:available) { [ Server.new('server1'), Server.new('server2'), Server.new('server3') ] }
9
10 describe '#new' do
11 it 'takes one array of hostnames' do
12 expect(host_filter)
13 end
14 end
15
16 describe '.for' do
17
18 subject { HostFilter.for(available) }
19
20 context 'without env vars' do
21 it 'returns all available hosts' do
22 expect(subject).to eq available
23 end
24 end
25
26 context 'with ENV vars' do
27 before do
28 ENV.stubs(:[]).with('HOSTS').returns('server1,server2')
29 end
30
31 it 'returns all required hosts defined in HOSTS' do
32 expect(subject).to eq [Server.new('server1'), Server.new('server2')]
33 end
34 end
35
36 context 'with configuration filters' do
37 before do
38 Configuration.env.set(:filter, hosts: %w{server1 server2})
39 end
40
41 it 'returns all required hosts defined in the filter' do
42 expect(subject).to eq [Server.new('server1'), Server.new('server2')]
43 end
44
45 after do
46 Configuration.env.delete(:filter)
47 end
48 end
49
50 context 'with a single configuration filter' do
51 before do
52 Configuration.env.set(:filter, hosts: 'server3')
53 end
54
55 it 'returns all required hosts defined in the filter' do
56 expect(subject).to eq [Server.new('server3')]
57 end
58
59 after do
60 Configuration.env.delete(:filter)
61 end
62 end
63
64 context 'with configuration filters and ENV vars' do
65 before do
66 Configuration.env.set(:filter, hosts: 'server1')
67 ENV.stubs(:[]).with('HOSTS').returns('server3')
68 end
69
70 it 'returns all required hosts defined in the filter' do
71 expect(subject).to eq [Server.new('server1'), Server.new('server3')]
72 end
73
74 after do
75 Configuration.env.delete(:filter)
76 end
77 end
78 end
79 end
80
81 end
82 end
83 end
+0
-140
spec/lib/capistrano/configuration/servers/role_filter_spec.rb less more
0 require 'spec_helper'
1
2 module Capistrano
3 class Configuration
4 class Servers
5
6 describe RoleFilter do
7 let(:role_filter) { RoleFilter.new(required, available) }
8 let(:required) { [] }
9 let(:available) { [:web, :app, :db] }
10
11 describe '#new' do
12 it 'takes two arrays of role names' do
13 expect(role_filter)
14 end
15 end
16
17 describe '.for' do
18
19 subject { RoleFilter.for(required, available) }
20
21 context 'without env vars' do
22 context ':all required' do
23 let(:required) { [:all] }
24
25 it 'returns all available names' do
26 expect(subject).to eq available
27 end
28 end
29
30 context 'role names required' do
31 let(:required) { [:web, :app] }
32 it 'returns all required names' do
33 expect(subject).to eq required
34 end
35 end
36 end
37
38 context 'with ENV vars' do
39 before do
40 ENV.stubs(:[]).with('ROLES').returns('app,web')
41 end
42
43 context ':all required' do
44 let(:required) { [:all] }
45
46 it 'returns available names defined in ROLES' do
47 expect(subject).to eq [:app, :web]
48 end
49 end
50
51 context 'role names required' do
52 let(:required) { [:web, :db] }
53 it 'returns all required names defined in ROLES' do
54 expect(subject).to eq [:web]
55 end
56 end
57 end
58
59 context 'with configuration filters' do
60 before do
61 Configuration.env.set(:filter, roles: %w{app web})
62 end
63
64 context ':all required' do
65 let(:required) { [:all] }
66
67 it 'returns available names defined in the filter' do
68 expect(subject).to eq [:app, :web]
69 end
70 end
71
72 context 'role names required' do
73 let(:required) { [:web, :db] }
74 it 'returns all required names defined in the filter' do
75 expect(subject).to eq [:web]
76 end
77 end
78
79 after do
80 Configuration.env.delete(:filter)
81 end
82 end
83
84 context 'with a single configuration filter' do
85 before do
86 Configuration.env.set(:filter, roles: 'web')
87 end
88
89 context ':all required' do
90 let(:required) { [:all] }
91
92 it 'returns available names defined in the filter' do
93 expect(subject).to eq [:web]
94 end
95 end
96
97 context 'role names required' do
98 let(:required) { [:web, :db] }
99 it 'returns all required names defined in the filter' do
100 expect(subject).to eq [:web]
101 end
102 end
103
104 after do
105 Configuration.env.delete(:filter)
106 end
107 end
108
109 context 'with configuration filters and ENV vars' do
110 before do
111 Configuration.env.set(:filter, roles: %w{app})
112 ENV.stubs(:[]).with('ROLES').returns('web')
113 end
114
115 context ':all required' do
116 let(:required) { [:all] }
117
118 it 'returns available names defined in the filter' do
119 expect(subject).to eq [:web, :app]
120 end
121 end
122
123 context 'role names required' do
124 let(:required) { [:web, :db] }
125 it 'returns all required names defined in the filter' do
126 expect(subject).to eq [:web]
127 end
128 end
129
130 after do
131 Configuration.env.delete(:filter)
132 end
133 end
134 end
135 end
136
137 end
138 end
139 end
1717 expect(servers.count).to eq 1
1818 end
1919
20 it 'handles de-duplification within roles with users' do
21 servers.add_role(:app, %w{1}, user: 'nick')
22 servers.add_role(:app, %w{1}, user: 'fred')
23 expect(servers.count).to eq 1
24 end
25
2026 it 'accepts instances of server objects' do
2127 servers.add_role(:app, [Capistrano::Configuration::Server.new('example.net'), 'example.com'])
2228 expect(servers.roles_for([:app]).length).to eq 2
2531 it 'accepts non-enumerable types' do
2632 servers.add_role(:app, '1')
2733 expect(servers.roles_for([:app]).count).to eq 1
34 end
35
36 it 'creates distinct server properties' do
37 servers.add_role(:db, %w{1 2}, db: { port: 1234 } )
38 servers.add_host('1', db: { master: true })
39 expect(servers.count).to eq(2)
40 expect(servers.roles_for([:db]).count).to eq 2
41 expect(servers.find(){|s| s.hostname == '1'}.properties.db).to eq({ port: 1234, master: true })
42 expect(servers.find(){|s| s.hostname == '2'}.properties.db).to eq({ port: 1234 })
2843 end
2944
3045 end
5873 end
5974
6075 describe 'finding the primary server' do
76 after do
77 Configuration.reset!
78 end
6179 it 'takes the first server if none have the primary property' do
6280 servers.add_role(:app, %w{1 2})
63 servers.fetch_primary(:app).hostname.should == '1'
81 expect(servers.fetch_primary(:app).hostname).to eq('1')
6482 end
6583
6684 it 'takes the first server with the primary have the primary flag' do
6785 servers.add_role(:app, %w{1 2})
6886 servers.add_host('2', primary: true)
69 servers.fetch_primary(:app).hostname.should == '2'
87 expect(servers.fetch_primary(:app).hostname).to eq('2')
88 end
89
90 it 'ignores any on_filters' do
91 Configuration.env.set :filter, { host: '1'}
92 servers.add_role(:app, %w{1 2})
93 servers.add_host('2', primary: true)
94 expect(servers.fetch_primary(:app).hostname).to eq('2')
7095 end
7196 end
7297
114139 servers.add_host('1', roles: [:app, 'web'], test: :value, user: 'root', port: 34)
115140 servers.add_host('1', roles: [:app, 'web'], test: :value, user: 'deployer', port: 34)
116141 servers.add_host('1', roles: [:app, 'web'], test: :value, user: 'deployer', port: 56)
117 servers.should have(8).items
118 end
142 expect(servers.count).to eq(1)
143 end
144
145 describe "with a :user property" do
146
147 it 'sets the server ssh username' do
148 servers.add_host('1', roles: [:app, 'web'], user: 'nick')
149 expect(servers.count).to eq(1)
150 expect(servers.roles_for([:all]).first.user).to eq 'nick'
151 end
152
153 it 'overwrites the value of a user specified in the hostname' do
154 servers.add_host('brian@1', roles: [:app, 'web'], user: 'nick')
155 expect(servers.count).to eq(1)
156 expect(servers.roles_for([:all]).first.user).to eq 'nick'
157 end
158
159 end
160
161 it 'overwrites the value of a previously defined scalar property' do
162 servers.add_host('1', roles: [:app, 'web'], test: :volatile)
163 expect(servers.count).to eq(1)
164 expect(servers.roles_for([:all]).first.properties.test).to eq :volatile
165 end
166
167 it 'merges previously defined hash properties' do
168 servers.add_host('1', roles: [:b], db: { port: 1234 })
169 servers.add_host('1', roles: [:b], db: { master: true })
170 expect(servers.count).to eq(1)
171 expect(servers.roles_for([:b]).first.properties.db).to eq({ port: 1234, master: true })
172 end
173
174 it 'concatenates previously defined array properties' do
175 servers.add_host('1', roles: [:b], steps: [1,3,5])
176 servers.add_host('1', roles: [:b], steps: [1,9])
177 expect(servers.count).to eq(1)
178 expect(servers.roles_for([:b]).first.properties.steps).to eq([1,3,5,1,9])
179 end
180
181 it 'merges previously defined set properties' do
182 servers.add_host('1', roles: [:b], endpoints: Set[123,333])
183 servers.add_host('1', roles: [:b], endpoints: Set[222,333])
184 expect(servers.count).to eq(1)
185 expect(servers.roles_for([:b]).first.properties.endpoints).to eq(Set[123,222,333])
186 end
187
188 it 'adds array property value only ones for a new host' do
189 servers.add_host('2', roles: [:array_test], array_property: [1,2])
190 expect(servers.roles_for([:array_test]).first.properties.array_property).to eq [1,2]
191 end
192
193 it 'updates roles when custom user defined' do
194 servers.add_host('1', roles: ['foo'], user: 'custom')
195 servers.add_host('1', roles: ['bar'], user: 'custom')
196 expect(servers.roles_for([:foo]).first.hostname).to eq '1'
197 expect(servers.roles_for([:bar]).first.hostname).to eq '1'
198 end
199
200 it 'updates roles when custom port defined' do
201 servers.add_host('1', roles: ['foo'], port: 1234)
202 servers.add_host('1', roles: ['bar'], port: 1234)
203 expect(servers.roles_for([:foo]).first.hostname).to eq '1'
204 expect(servers.roles_for([:bar]).first.hostname).to eq '1'
205 end
206
119207 end
120208
121209 describe 'selecting roles' do
180268
181269 end
182270
183 describe 'filtering roles' do
184
185 before do
186 ENV.stubs(:[]).with('ROLES').returns('web,db')
187 ENV.stubs(:[]).with('HOSTS').returns(nil)
271 describe 'filtering roles internally' do
272
273 before do
188274 servers.add_host('1', roles: :app, active: true)
189275 servers.add_host('2', roles: :app)
190276 servers.add_host('3', roles: :web)
194280
195281 subject { servers.roles_for(roles).map(&:hostname) }
196282
197 context 'when selecting all roles' do
198 let(:roles) { [:all] }
199
200 it 'returns the roles specified by ROLE' do
201 expect(subject).to eq %w{3 4 5}
202 end
203 end
204
205 context 'when selecting roles included in ROLE' do
206 let(:roles) { [:app, :web] }
207
208 it 'returns only roles that match ROLE' do
209 expect(subject).to eq %w{3 4}
210 end
211 end
212
213 context 'when selecting roles not included in ROLE' do
214 let(:roles) { [:app] }
215
216 it 'is empty' do
217 expect(subject).to be_empty
218 end
219 end
220 end
221
283 context 'with the ROLES environment variable set' do
284
285 before do
286 ENV.stubs(:[]).with('ROLES').returns('web,db')
287 ENV.stubs(:[]).with('HOSTS').returns(nil)
288 end
289
290 context 'when selecting all roles' do
291 let(:roles) { [:all] }
292 it 'ignores it' do
293 expect(subject).to eq %w{1 2 3 4 5}
294 end
295 end
296
297 context 'when selecting specific roles' do
298 let(:roles) { [:app, :web] }
299 it 'ignores it' do
300 expect(subject).to eq %w{1 2 3 4}
301 end
302 end
303
304 context 'when selecting roles not included in ROLE' do
305 let(:roles) { [:app] }
306 it 'ignores it' do
307 expect(subject).to eq %w{1 2}
308 end
309 end
310
311 end
312
313 context 'with the HOSTS environment variable set' do
314
315 before do
316 ENV.stubs(:[]).with('ROLES').returns(nil)
317 ENV.stubs(:[]).with('HOSTS').returns('3,5')
318 end
319
320 context 'when selecting all roles' do
321 let(:roles) { [:all] }
322 it 'ignores it' do
323 expect(subject).to eq %w{1 2 3 4 5}
324 end
325 end
326
327 context 'when selecting specific roles' do
328 let(:roles) { [:app, :web] }
329 it 'ignores it' do
330 expect(subject).to eq %w{1 2 3 4}
331 end
332 end
333
334 context 'when selecting no roles' do
335 let(:roles) { [] }
336 it 'ignores it' do
337 expect(subject).to be_empty
338 end
339 end
340
341 end
342
343 end
222344 end
223345 end
224346 end
44 let(:config) { Configuration.new }
55 let(:servers) { stub }
66
7 describe '.new' do
8 it 'accepts initial hash' do
9 configuration = described_class.new(custom: 'value')
10 expect(configuration.fetch(:custom)).to eq('value')
11 end
12 end
13
714 describe '.env' do
815 it 'is a global accessor to a single instance' do
916 Configuration.env.set(:test, true)
10 expect(Configuration.env.fetch(:test)).to be_true
17 expect(Configuration.env.fetch(:test)).to be_truthy
1118 end
1219 end
1320
4350 end
4451
4552 it 'returns the set value' do
53 expect(subject).to eq :value
54 end
55 end
56
57 context 'set_if_empty' do
58 it 'sets the value when none is present' do
59 config.set_if_empty(:key, :value)
60 expect(subject).to eq :value
61 end
62
63 it 'does not overwrite the value' do
64 config.set(:key, :value)
65 config.set_if_empty(:key, :update)
4666 expect(subject).to eq :value
4767 end
4868 end
137157
138158 describe 'asking' do
139159 let(:question) { stub }
160 let(:options) { Hash.new }
140161
141162 before do
142 Configuration::Question.expects(:new).with(config, :branch, :default).
163 Configuration::Question.expects(:new).with(:branch, :default, options).
143164 returns(question)
144165 end
145166
146167 it 'prompts for the value when fetching' do
147 config.ask(:branch, :default)
168 config.ask(:branch, :default, options)
148169 expect(config.fetch(:branch)).to eq question
149170 end
150171 end
158179 config.backend = :test
159180 expect(config.backend).to eq :test
160181 end
182
183 describe "ssh_options for Netssh" do
184 it 'merges them with the :ssh_options variable' do
185 config.set :format, :pretty
186 config.set :log_level, :debug
187 config.set :ssh_options, { user: 'albert' }
188 SSHKit::Backend::Netssh.configure do |ssh| ssh.ssh_options = { password: 'einstein' } end
189 config.configure_backend
190 expect(config.backend.config.backend.config.ssh_options).to eq({ user: 'albert', password: 'einstein' })
191 end
192 end
161193 end
162194 end
163195 end
00 require 'spec_helper'
11
2 module Capistrano
3 module DSL
2 describe Capistrano::DSL::Paths do
43
5 class DummyPaths
6 include Paths
4 let(:dsl) { Class.new.extend Capistrano::DSL }
5 let(:parent) { Pathname.new('/var/shared') }
6 let(:paths) { Class.new.extend Capistrano::DSL::Paths }
7
8 let(:linked_dirs) { %w{log public/system} }
9 let(:linked_files) { %w{config/database.yml log/my.log} }
10
11 before do
12 dsl.set(:deploy_to, '/var/www')
13 end
14
15 describe '#linked_dirs' do
16 subject { paths.linked_dirs(parent) }
17
18 before do
19 paths.expects(:fetch).with(:linked_dirs).returns(linked_dirs)
720 end
821
9 describe Paths do
10 let(:paths) { DummyPaths.new }
11 let(:parent) { Pathname.new('/var/shared') }
12
13 let(:linked_dirs) { %w{log public/system} }
14 let(:linked_files) { %w{config/database.yml log/my.log} }
22 it 'returns the full pathnames' do
23 expect(subject).to eq [Pathname.new('/var/shared/log'), Pathname.new('/var/shared/public/system')]
24 end
25 end
1526
1627
17 describe '#linked_dirs' do
18 subject { paths.linked_dirs(parent) }
28 describe '#linked_files' do
29 subject { paths.linked_files(parent) }
1930
20 before do
21 paths.expects(:fetch).with(:linked_dirs).returns(linked_dirs)
22 end
31 before do
32 paths.expects(:fetch).with(:linked_files).returns(linked_files)
33 end
2334
24 it 'returns the full pathnames' do
25 expect(subject).to eq [Pathname.new('/var/shared/log'), Pathname.new('/var/shared/public/system')]
26 end
35 it 'returns the full pathnames' do
36 expect(subject).to eq [Pathname.new('/var/shared/config/database.yml'), Pathname.new('/var/shared/log/my.log')]
37 end
38 end
39
40 describe '#linked_file_dirs' do
41 subject { paths.linked_file_dirs(parent) }
42
43 before do
44 paths.expects(:fetch).with(:linked_files).returns(linked_files)
45 end
46
47 it 'returns the full paths names of the parent dirs' do
48 expect(subject).to eq [Pathname.new('/var/shared/config'), Pathname.new('/var/shared/log')]
49 end
50 end
51
52 describe '#linked_dir_parents' do
53 subject { paths.linked_dir_parents(parent) }
54
55 before do
56 paths.expects(:fetch).with(:linked_dirs).returns(linked_dirs)
57 end
58
59 it 'returns the full paths names of the parent dirs' do
60 expect(subject).to eq [Pathname.new('/var/shared'), Pathname.new('/var/shared/public')]
61 end
62 end
63
64 describe '#release path' do
65
66 subject { dsl.release_path }
67
68 context 'where no release path has been set' do
69 before do
70 dsl.delete(:release_path)
2771 end
2872
73 it 'returns the `current_path` value' do
74 expect(subject.to_s).to eq '/var/www/current'
75 end
76 end
2977
30 describe '#linked_files' do
31 subject { paths.linked_files(parent) }
32
33 before do
34 paths.expects(:fetch).with(:linked_files).returns(linked_files)
35 end
36
37 it 'returns the full pathnames' do
38 expect(subject).to eq [Pathname.new('/var/shared/config/database.yml'), Pathname.new('/var/shared/log/my.log')]
39 end
78 context 'where the release path has been set' do
79 before do
80 dsl.set(:release_path,'/var/www/release_path')
4081 end
4182
42 describe '#linked_file_dirs' do
43 subject { paths.linked_file_dirs(parent) }
83 it 'returns the set `release_path` value' do
84 expect(subject.to_s).to eq '/var/www/release_path'
85 end
86 end
87 end
4488
45 before do
46 paths.expects(:fetch).with(:linked_files).returns(linked_files)
47 end
89 describe '#set_release_path' do
90 let(:now) { Time.parse("Oct 21 16:29:00 2015") }
91 subject { dsl.release_path }
4892
49 it 'returns the full paths names of the parent dirs' do
50 expect(subject).to eq [Pathname.new('/var/shared/config'), Pathname.new('/var/shared/log')]
51 end
93 context 'without a timestamp' do
94 before do
95 dsl.env.expects(:timestamp).returns(now)
96 dsl.set_release_path
5297 end
5398
54 describe '#linked_dir_parents' do
55 subject { paths.linked_dir_parents(parent) }
99 it 'returns the release path with the current env timestamp' do
100 expect(subject.to_s).to eq '/var/www/releases/20151021162900'
101 end
102 end
56103
57 before do
58 paths.expects(:fetch).with(:linked_dirs).returns(linked_dirs)
59 end
60
61 it 'returns the full paths names of the parent dirs' do
62 expect(subject).to eq [Pathname.new('/var/shared'), Pathname.new('/var/shared/public')]
63 end
104 context 'with a timestamp' do
105 before do
106 dsl.set_release_path('timestamp')
64107 end
65108
109 it 'returns the release path with the timestamp' do
110 expect(subject.to_s).to eq '/var/www/releases/timestamp'
111 end
112 end
113 end
114
115 describe '#deploy_config_path' do
116 subject { dsl.deploy_config_path.to_s }
117
118 context 'when not specified' do
119 before do
120 dsl.delete(:deploy_config_path)
121 end
122
123 it 'returns "config/deploy.rb"' do
124 expect(subject).to eq 'config/deploy.rb'
125 end
126 end
127
128 context 'when the variable :deploy_config_path is set' do
129 before do
130 dsl.set(:deploy_config_path, 'my/custom/path.rb')
131 end
132
133 it 'returns the custom path' do
134 expect(subject).to eq 'my/custom/path.rb'
135 end
136 end
137 end
138
139 describe '#stage_config_path' do
140 subject { dsl.stage_config_path.to_s }
141
142 context 'when not specified' do
143
144 before do
145 dsl.delete(:stage_config_path)
146 end
147
148 it 'returns "config/deploy"' do
149 expect(subject).to eq 'config/deploy'
150 end
151 end
152
153 context 'when the variable :stage_config_path is set' do
154 before do
155 dsl.set(:stage_config_path, 'my/custom/path')
156 end
157
158 it 'returns the custom path' do
159 expect(subject).to eq 'my/custom/path'
160 end
161 end
162 end
163
164 describe '#repo_path' do
165 subject { dsl.repo_path.to_s }
166
167 context 'when not specified' do
168
169 before do
170 dsl.delete(:repo_path)
171 end
172
173 it 'returns the default #{deploy_to}/repo' do
174 dsl.set(:deploy_to, '/var/www')
175 expect(subject).to eq '/var/www/repo'
176 end
177 end
178
179 context 'when the variable :repo_path is set' do
180 before do
181 dsl.set(:repo_path, 'my/custom/path')
182 end
183
184 it 'returns the custom path' do
185 expect(subject).to eq 'my/custom/path'
186 end
66187 end
67188 end
68189 end
0 require 'spec_helper'
1
2 module Capistrano
3 class DummyTaskEnhancements
4 include TaskEnhancements
5 end
6
7 describe TaskEnhancements do
8 let(:task_enhancements) { DummyTaskEnhancements.new }
9
10 describe 'ordering' do
11
12 after do
13 task.clear
14 before_task.clear
15 after_task.clear
16 Rake::Task.clear
17 end
18
19 let(:order) { [] }
20 let!(:task) do
21 Rake::Task.define_task('task', [:order]) do |t, args|
22 args['order'].push 'task'
23 end
24 end
25
26 let!(:before_task) do
27 Rake::Task.define_task('before_task') do
28 order.push 'before_task'
29 end
30 end
31
32 let!(:after_task) do
33 Rake::Task.define_task('after_task') do
34 order.push 'after_task'
35 end
36 end
37
38 it 'invokes in proper order if define after than before' do
39 task_enhancements.after('task', 'after_task')
40 task_enhancements.before('task', 'before_task')
41
42 Rake::Task['task'].invoke order
43
44 expect(order).to eq(['before_task', 'task', 'after_task'])
45 end
46
47 it 'invokes in proper order if define before than after' do
48 task_enhancements.before('task', 'before_task')
49 task_enhancements.after('task', 'after_task')
50
51 Rake::Task['task'].invoke order
52
53 expect(order).to eq(['before_task', 'task', 'after_task'])
54 end
55
56 it 'invokes in proper order and with arguments and block' do
57 task_enhancements.after('task', 'after_task_custom', :order) do |t, args|
58 order.push 'after_task'
59 end
60
61 task_enhancements.before('task', 'before_task_custom', :order) do |t, args|
62 order.push 'before_task'
63 end
64
65 Rake::Task['task'].invoke(order)
66
67 expect(order).to eq(['before_task', 'task', 'after_task'])
68 end
69
70 end
71
72 describe 'remote_file' do
73 subject(:remote_file) { task_enhancements.remote_file('source' => 'destination') }
74
75 it { expect(remote_file.name).to eq('source') }
76 it { is_expected.to be_a(Capistrano::UploadTask) }
77
78 describe 'namespaced' do
79 let(:app) { Rake.application }
80 around { |ex| app.in_namespace('namespace', &ex) }
81
82 it { expect(remote_file.name).to eq('source') }
83 it { is_expected.to be_a(Capistrano::UploadTask) }
84 end
85 end
86 end
87 end
2626 before do
2727 dsl.set(:stage, :sandbox)
2828 end
29 it { should be_true }
29 it { expect(subject).to be_truthy }
3030 end
3131
3232 context 'stage is not set' do
3333 before do
3434 dsl.set(:stage, nil)
3535 end
36 it { should be_false }
36 it { expect(subject).to be_falsey }
3737 end
3838 end
3939
4747 dsl.sudo(:my, :command)
4848 end
4949 end
50
51 describe '#local_user' do
52
53 before do
54 Etc.expects(:getlogin)
55 end
56
57 it 'delegates to Etc#getlogin' do
58 dsl.local_user
59 end
60 end
6150 end
6251 end
3030 describe "#check" do
3131 it "should test the repo url" do
3232 context.expects(:repo_url).returns(:url)
33 context.expects(:test).with(:git, :'ls-remote -h', :url).returns(true)
33 context.expects(:execute).with(:git, :'ls-remote --heads', :url).returns(true)
3434
3535 subject.check
3636 end
5656 end
5757
5858 describe "#release" do
59 it "should run git archive" do
60 context.expects(:fetch).returns(:branch)
59 it "should run git archive without a subtree" do
60 context.expects(:fetch).with(:repo_tree).returns(nil)
61 context.expects(:fetch).with(:branch).returns(:branch)
6162 context.expects(:release_path).returns(:path)
6263
63 context.expects(:execute).with(:git, :archive, :branch, '| tar -x -C', :path)
64 context.expects(:execute).with(:git, :archive, :branch, '| tar -x -f - -C', :path)
65
66 subject.release
67 end
68
69 it "should run git archive with a subtree" do
70 context.expects(:fetch).with(:repo_tree).returns('tree')
71 context.expects(:fetch).with(:branch).returns(:branch)
72 context.expects(:release_path).returns(:path)
73
74 context.expects(:execute).with(:git, :archive, :branch, 'tree', '| tar -x --strip-components 1 -f - -C', :path)
6475
6576 subject.release
6677 end
5656 end
5757
5858 describe "#release" do
59 it "should run hg archive" do
60 context.expects(:fetch).returns(:branch)
59 it "should run hg archive without a subtree" do
60 context.expects(:fetch).with(:repo_tree).returns(nil)
61 context.expects(:fetch).with(:branch).returns(:branch)
6162 context.expects(:release_path).returns(:path)
6263
6364 context.expects(:execute).with(:hg, "archive", :path, "--rev", :branch)
6465
6566 subject.release
6667 end
68
69 it "should run hg archive with a subtree" do
70 context.expects(:fetch).with(:repo_tree).returns('tree')
71 context.expects(:fetch).with(:branch).returns(:branch)
72 context.expects(:release_path).returns(:path)
73
74 context.expects(:execute).with(:hg, "archive --type tgz -p . -I", 'tree', "--rev", :branch, '| tar -x --strip-components 1 -f - -C', :path)
75
76 subject.release
77 end
6778 end
6879 end
6980 end
4949 describe "#repo_url" do
5050 it "should return the repo url according to the context" do
5151 context.expects(:repo_url).returns(:url)
52 subject.repo_url.should == :url
52 expect(subject.repo_url).to eq(:url)
5353 end
5454 end
5555
5656 describe "#repo_path" do
5757 it "should return the repo path according to the context" do
5858 context.expects(:repo_path).returns(:path)
59 subject.repo_path.should == :path
59 expect(subject.repo_path).to eq(:path)
6060 end
6161 end
6262
6363 describe "#release_path" do
6464 it "should return the release path according to the context" do
6565 context.expects(:release_path).returns('/path/to/nowhere')
66 subject.release_path.should == '/path/to/nowhere'
66 expect(subject.release_path).to eq('/path/to/nowhere')
6767 end
6868 end
6969
5959 it "should run svn export" do
6060 context.expects(:release_path).returns(:path)
6161
62 context.expects(:execute).with(:svn, :export, '.', :path)
62 context.expects(:execute).with(:svn, :export, '--force', '.', :path)
6363
6464 subject.release
6565 end
6666 end
67
68 describe "#fetch_revision" do
69 it "should run fetch revision" do
70 context.expects(:repo_path).returns(:path)
71
72 context.expects(:capture).with(:svnversion, :path)
73
74 subject.fetch_revision
75 end
76 end
6777 end
6878 end
0 require 'spec_helper'
1
2 describe Capistrano::UploadTask do
3 let(:app) { Rake.application = Rake::Application.new }
4
5 subject(:upload_task) { described_class.define_task('path/file.yml') }
6
7 it { is_expected.to be_a(Rake::FileCreationTask) }
8 it { is_expected.to be_needed }
9
10 context 'inside namespace' do
11 let(:normal_task) { Rake::Task.define_task('path/other_file.yml') }
12
13 around { |ex| app.in_namespace('namespace', &ex) }
14
15 it { expect(upload_task.name).to eq('path/file.yml') }
16 it { expect(upload_task.scope.path).to eq('namespace') }
17 end
18 end
2323 context 'with exact version' do
2424 context 'valid' do
2525 let(:version) { '3.0.1' }
26 it { should be_true }
26 it { expect(subject).to be_truthy }
2727 end
2828
2929 context 'invalid - lower' do
4747 context 'with optimistic versioning' do
4848 context 'valid' do
4949 let(:version) { '>= 3.0.0' }
50 it { should be_true }
50 it { expect(subject).to be_truthy }
5151 end
5252
5353 context 'invalid - lower' do
6565 context '2 decimal places' do
6666 context 'valid' do
6767 let(:version) { '~> 3.0.0' }
68 it { should be_true }
68 it { expect(subject).to be_truthy }
6969 end
7070
7171 context 'invalid' do
8282
8383 context 'valid' do
8484 let(:version) { '~> 3.1' }
85 it { should be_true }
85 it { expect(subject).to be_truthy }
8686 end
8787
8888 context 'invalid' do
22 require 'capistrano/all'
33 require 'rspec'
44 require 'mocha/api'
5 require 'time'
56
67 # Requires supporting files with custom matchers and macros, etc,
78 # in ./support/ and its subdirectories.
89 Dir['#{File.dirname(__FILE__)}/support/**/*.rb'].each {|f| require f}
910
1011 RSpec.configure do |config|
11 config.treat_symbols_as_metadata_keys_with_true_values = true
12 config.raise_errors_for_deprecations!
1213 config.mock_framework = :mocha
1314 config.order = 'random'
1415 end
0 Vagrant::Config.run do |config|
0 require 'open-uri'
1
2 Vagrant.configure("2") do |config|
3
4 config.ssh.insert_key = false
15
26 [:app].each_with_index do |role, i|
37 config.vm.define(role, primary: true) do |config|
4 config.vm.box = role
5 config.vm.box = 'precise64'
6 config.vm.box_url = 'http://files.vagrantup.com/precise64.box'
7 config.vm.forward_port 22, "222#{i}".to_i
8 config.vm.provision :shell, inline: 'yes | sudo apt-get install git-core'
8 config.vm.define role
9 config.vm.box = 'hashicorp/precise64'
10 config.vm.network "forwarded_port", guest: 22, host: "222#{i}".to_i
11 config.vm.provision :shell, inline: 'sudo apt-get -y install git-core'
12
13 vagrantkey = open("https://raw.githubusercontent.com/mitchellh/vagrant/master/keys/vagrant.pub", "r",&:read)
14
15 config.vm.provision :shell,
16 inline: <<-INLINE
17 install -d -m 700 /root/.ssh
18 echo -e "#{vagrantkey}" > /root/.ssh/authorized_keys
19 chmod 0600 /root/.ssh/authorized_keys
20 INLINE
921 end
1022 end
11
1223 end
0 task :am_i_root do
1 on roles(:all) do |host|
2 host.user = 'root'
3 ident = capture :id, '-a'
4 info "I am #{ident}"
5 end
6 on roles(:all) do |host|
7 ident = capture :id, '-a'
8 info "I am #{ident}"
9 end
10 end
00 require 'fileutils'
1 require 'pathname'
2
13 module TestApp
24 extend self
35
1012 set :deploy_to, '#{deploy_to}'
1113 set :repo_url, 'git://github.com/capistrano/capistrano.git'
1214 set :branch, 'master'
13 set :ssh_options, { keys: "\#{ENV['HOME']}/.vagrant.d/insecure_private_key" }
15 set :ssh_options, { keys: "\#{ENV['HOME']}/.vagrant.d/insecure_private_key", auth_methods: ['publickey'] }
1416 server 'vagrant@localhost:2220', roles: %w{web app}
1517 set :linked_files, #{linked_files}
1618 set :linked_dirs, #{linked_dirs}