capistrano-distribution 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.yardopts +1 -0
- data/LICENSE +22 -0
- data/NEWS.md +35 -0
- data/README.md +165 -0
- data/Rakefile +243 -0
- data/lib/capistrano/distribution/distributor/abstract.rb +85 -0
- data/lib/capistrano/distribution/distributor/abstract_archiver.rb +60 -0
- data/lib/capistrano/distribution/distributor/abstract_curl.rb +28 -0
- data/lib/capistrano/distribution/distributor/abstract_git.rb +56 -0
- data/lib/capistrano/distribution/distributor/curl_tar.rb +36 -0
- data/lib/capistrano/distribution/distributor/curl_zip.rb +40 -0
- data/lib/capistrano/distribution/distributor/git_pull.rb +67 -0
- data/lib/capistrano/distribution/distributor/git_push.rb +73 -0
- data/lib/capistrano/distribution/distributor/tar.rb +35 -0
- data/lib/capistrano/distribution/distributor/tar_helper.rb +40 -0
- data/lib/capistrano/distribution/distributor/zip.rb +31 -0
- data/lib/capistrano/distribution/distributor.rb +102 -0
- data/lib/capistrano/distribution/version.rb +9 -0
- data/lib/capistrano/distribution.rb +68 -0
- data/lib/capistrano/tasks/distribution.cap +33 -0
- metadata +152 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 51e2dcb1ba15f838b76d6eaf72e6f451c793f32b
|
4
|
+
data.tar.gz: 1cb882b4e420dc6c2292e897657f681b831d5515
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8f0275b355b9ee5311373aff3b70640ddb381fecd3dd3b6b57b9eab3817e17217a2c25667b53047dc69aa8fc3065050203fe7d828026c2f4bcfa1dc63ac2788c
|
7
|
+
data.tar.gz: 20a82ec2110fe7bfebd8ae1dfcd149e249f75332b1cde1d1fbeb4ac86afa6df2dff926958b2473b26c19882627f13414a02bc954540bc4cda5d87a2b5b70b78d
|
data/.yardopts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--protected --private abstract lib/**/*.rb - README.md NEWS.md LICENSE
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
(The MIT License)
|
2
|
+
|
3
|
+
Copyright (c) 2014 Spiceworks, Inc.
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
'Software'), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
19
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
20
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
21
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
22
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/NEWS.md
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# News and Notifications by Version
|
2
|
+
|
3
|
+
This file lists noteworthy changes which may affect users of this project. More
|
4
|
+
detailed information is available in the rest of the documentation.
|
5
|
+
|
6
|
+
**NOTE:** Date stamps in the following entries are in YYYY/MM/DD format.
|
7
|
+
|
8
|
+
|
9
|
+
## v0.2.0 (2016/02/29)
|
10
|
+
|
11
|
+
* Provide a setting (`:distribution_runner_opts`) to configure runner options.
|
12
|
+
* Must be a hash of options acceptable by the `on` method of sshkit.
|
13
|
+
* Git distributables can now change the repo URL without manual intervention.
|
14
|
+
* Pruning of dead Git branches now happens during repository update.
|
15
|
+
* Avoids too many dead branches causing updates to run forever.
|
16
|
+
|
17
|
+
## v0.1.0 (2016/02/09)
|
18
|
+
|
19
|
+
* Incompatible changes
|
20
|
+
* The `distribution` setting is now a stack of distributor definitions to be
|
21
|
+
applied in order as a series of overlays in the release area.
|
22
|
+
* Provides the `distribution:set_current_revision` task used by newer
|
23
|
+
Capistrano releases.
|
24
|
+
* A `release_id` setting is required to provide a reasonable value.
|
25
|
+
|
26
|
+
## v0.0.2 (2014/03/17)
|
27
|
+
|
28
|
+
* Ensure that the internal_path attribute of AbstractArchiver is a Pathname
|
29
|
+
* Fixes extraction of ZIP archives.
|
30
|
+
* Silence curl and unzip in the CurlZip distributor
|
31
|
+
* Silence unzip in the Zip distributor
|
32
|
+
|
33
|
+
## v0.0.1 (2014/02/27)
|
34
|
+
|
35
|
+
* Birthday
|
data/README.md
ADDED
@@ -0,0 +1,165 @@
|
|
1
|
+
# Capistrano Distribution: More Than Just Git Deployments
|
2
|
+
|
3
|
+
Flexible distribution for Capistrano 3.x.
|
4
|
+
|
5
|
+
## LINKS
|
6
|
+
|
7
|
+
* Homepage :: http://github.com/spiceworks/capistrano-distribution
|
8
|
+
* Documentation :: http://rdoc.info/gems/capistrano-distribution/frames
|
9
|
+
* Source :: http://github.com/spiceworks/capistrano-distribution
|
10
|
+
|
11
|
+
## DESCRIPTION
|
12
|
+
|
13
|
+
This gem hooks into the SCM functionality of Capistrano 3.x in order to provide
|
14
|
+
a more generic distribution strategy. Not only is it possible to deploy from a
|
15
|
+
simple Git repository, but deployment of contents from Tar and ZIP files is also
|
16
|
+
possible. It is even easy to create deployments based on multiple sources.
|
17
|
+
|
18
|
+
With the exception of the Git push method, all distribution operations pull
|
19
|
+
content from providers on each target host. For Git-based distributions
|
20
|
+
whether using the push or pull method, this is very efficient after the first
|
21
|
+
deployment because a mirror git repository is saved on each host such that only
|
22
|
+
differentials are needed for future deployments. All other types perform a
|
23
|
+
full download of the source artifact, so these could be expensive and/or slow.
|
24
|
+
|
25
|
+
## Features
|
26
|
+
|
27
|
+
* Distribute from Git repositories and Tar/Zip archives.
|
28
|
+
* Use remote and local sources, anything supported by Git and Curl.
|
29
|
+
* Create homogenous deployments from multiple sources.
|
30
|
+
|
31
|
+
## Known Bugs/Limitations
|
32
|
+
|
33
|
+
* None so far...
|
34
|
+
|
35
|
+
## SYNOPSIS
|
36
|
+
|
37
|
+
Simple Git-based distribution (master branch of the current repository):
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
# config/deploy.rb
|
41
|
+
...
|
42
|
+
set :scm, :distribution
|
43
|
+
set :release_id, ->{ `git rev-parse HEAD`.chomp }
|
44
|
+
set :distribution, ->{
|
45
|
+
[[
|
46
|
+
'http://example.com/repositories/example.git',
|
47
|
+
fetch(:release_id)
|
48
|
+
]]
|
49
|
+
}
|
50
|
+
...
|
51
|
+
```
|
52
|
+
|
53
|
+
Simple Tar-based distribution (everything in the `example.tar.gz` archive is
|
54
|
+
within an `example` subdirectory):
|
55
|
+
|
56
|
+
```ruby
|
57
|
+
# config/deploy.rb
|
58
|
+
...
|
59
|
+
set :scm, :distribution
|
60
|
+
set :release_id, ->{ "example-#{fetch(:release_timestamp)}" }
|
61
|
+
set :distribution, 'http://example.com/tarballs/example.tar.gz'
|
62
|
+
...
|
63
|
+
```
|
64
|
+
|
65
|
+
Heterogenous distribution (a Redmine deployment with plugins):
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
# config/deploy.rb
|
69
|
+
...
|
70
|
+
set :scm, :distribution
|
71
|
+
set :release_id, ->{ "2.3.4-#{fetch(:release_timestamp)}" }
|
72
|
+
set :distribution,
|
73
|
+
[
|
74
|
+
'http://www.redmine.org/releases/redmine-2.3.4.tar.gz'
|
75
|
+
],
|
76
|
+
[
|
77
|
+
'https://bitbucket.org/akiko_pusu/redmine_issue_templates/get/0.0.4.tar.gz',
|
78
|
+
{
|
79
|
+
subtree: 'akiko_pusu-redmine_issue_templates-b885dfe8263d',
|
80
|
+
target: 'plugins/redmine_issue_templates'
|
81
|
+
}
|
82
|
+
],
|
83
|
+
[
|
84
|
+
'https://bitbucket.org/haru_iida/redmine_code_review/get/0.6.2.tar.gz',
|
85
|
+
{
|
86
|
+
subtree: 'haru_iida-redmine_code_review-e79f98b8a77f',
|
87
|
+
target: 'plugins/redmine_code_review'
|
88
|
+
}
|
89
|
+
],
|
90
|
+
[
|
91
|
+
'https://github.com/Undev/notify_custom_users/archive/0.0.5.tar.gz',
|
92
|
+
{
|
93
|
+
subtree: 'notify_custom_users-0.0.5',
|
94
|
+
target: 'plugins/notify_custom_users'
|
95
|
+
}
|
96
|
+
],
|
97
|
+
[
|
98
|
+
'https://github.com/thorin/redmine_ldap_sync/archive/2.0.3.tar.gz',
|
99
|
+
{
|
100
|
+
subtree: 'redmine_ldap_sync-2.0.3',
|
101
|
+
target: 'plugins/redmine_ldap_sync'
|
102
|
+
}
|
103
|
+
]
|
104
|
+
...
|
105
|
+
```
|
106
|
+
|
107
|
+
## REQUIREMENTS
|
108
|
+
|
109
|
+
* Git binary (for Git repositories)
|
110
|
+
* Curl binary (for remote archives)
|
111
|
+
* Unzip binary (for ZIP archives)
|
112
|
+
* Tar binary (for Tar archives)
|
113
|
+
|
114
|
+
## DEVELOPERS
|
115
|
+
|
116
|
+
After checking out the source, run:
|
117
|
+
|
118
|
+
$ bundle install
|
119
|
+
$ bundle exec rake test yard
|
120
|
+
|
121
|
+
This will install all dependencies, run the tests/specs, and generate the
|
122
|
+
documentation.
|
123
|
+
|
124
|
+
## AUTHORS
|
125
|
+
|
126
|
+
Thanks to all contributors. Without your help this project would not exist.
|
127
|
+
|
128
|
+
* Jeremy Bopp :: jeremyb@spiceworks.com
|
129
|
+
|
130
|
+
## Contributing
|
131
|
+
|
132
|
+
Contributions for bug fixes, documentation, extensions, tests, etc. are
|
133
|
+
encouraged.
|
134
|
+
|
135
|
+
1. Clone the repository.
|
136
|
+
2. Fix a bug or add a feature.
|
137
|
+
3. Add tests for the fix or feature.
|
138
|
+
4. Make a pull request.
|
139
|
+
|
140
|
+
## LICENSE
|
141
|
+
|
142
|
+
```
|
143
|
+
(The MIT License)
|
144
|
+
|
145
|
+
Copyright (c) 2014 Spiceworks, Inc.
|
146
|
+
|
147
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
148
|
+
a copy of this software and associated documentation files (the
|
149
|
+
'Software'), to deal in the Software without restriction, including
|
150
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
151
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
152
|
+
permit persons to whom the Software is furnished to do so, subject to
|
153
|
+
the following conditions:
|
154
|
+
|
155
|
+
The above copyright notice and this permission notice shall be
|
156
|
+
included in all copies or substantial portions of the Software.
|
157
|
+
|
158
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
159
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
160
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
161
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
162
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
163
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
164
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
165
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1,243 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# -*- ruby -*-
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
|
6
|
+
require 'erb'
|
7
|
+
require 'rake/testtask'
|
8
|
+
require 'rubygems/package_task'
|
9
|
+
require 'rake/clean'
|
10
|
+
require 'yard'
|
11
|
+
|
12
|
+
# Load the gemspec file for this project.
|
13
|
+
GEMSPEC = Dir['*.gemspec'].first
|
14
|
+
SPEC = eval(File.read(GEMSPEC), nil, GEMSPEC)
|
15
|
+
|
16
|
+
# The path to the version.rb file and a string to eval to find the version.
|
17
|
+
VERSION_RB = "lib/#{SPEC.name.gsub('-', '/')}/version.rb"
|
18
|
+
VERSION_REF =
|
19
|
+
"#{SPEC.name.split('-').map { |p| p.split('_').map(&:capitalize).join }.join('::')}::VERSION"
|
20
|
+
|
21
|
+
# A dynamically generated list of files that should match the manifest (the
|
22
|
+
# combined contents of SPEC.files and SPEC.test_files). The idea is for this
|
23
|
+
# list to contain all project files except for those that have been explicitly
|
24
|
+
# excluded. This list will be compared with the manifest from the SPEC in order
|
25
|
+
# to help catch the addition or removal of files to or from the project that
|
26
|
+
# have not been accounted for either by an exclusion here or an inclusion in the
|
27
|
+
# SPEC manifest.
|
28
|
+
#
|
29
|
+
# NOTE:
|
30
|
+
# It is critical that the manifest is *not* automatically generated via globbing
|
31
|
+
# and the like; otherwise, this will yield a simple comparison between
|
32
|
+
# redundantly generated lists of files that probably will not protect the
|
33
|
+
# project from the unintentional inclusion or exclusion of files in the
|
34
|
+
# distribution.
|
35
|
+
PKG_FILES = FileList.new(Dir.glob('**/*', File::FNM_DOTMATCH)) do |files|
|
36
|
+
# Exclude anything that doesn't exist as well as directories.
|
37
|
+
files.exclude {|file| ! File.exist?(file) || File.directory?(file)}
|
38
|
+
# Exclude Git administrative files.
|
39
|
+
files.exclude(%r{(^|[/\\])\.git(ignore|modules|keep)?([/\\]|$)})
|
40
|
+
# Exclude editor swap/temporary files.
|
41
|
+
files.exclude('**/.*.sw?')
|
42
|
+
# Exclude the gemspec file.
|
43
|
+
files.exclude(GEMSPEC)
|
44
|
+
# Exclude the README template file.
|
45
|
+
files.exclude('README.md.erb')
|
46
|
+
# Exclude resources for bundler.
|
47
|
+
files.exclude('Gemfile', 'Gemfile.lock')
|
48
|
+
files.exclude(%r{^.bundle([/\\]|$)})
|
49
|
+
files.exclude(%r{^vendor/bundle([/\\]|$)})
|
50
|
+
# Exclude generated content, except for the README file.
|
51
|
+
files.exclude(%r{^(pkg|doc|.yardoc)([/\\]|$)})
|
52
|
+
# Exclude Rubinius compiled Ruby files.
|
53
|
+
files.exclude('**/*.rbc')
|
54
|
+
end
|
55
|
+
|
56
|
+
# Make sure that :clean and :clobber will not whack the repository files.
|
57
|
+
CLEAN.exclude('.git/**')
|
58
|
+
# Vim swap files are fair game for clean up.
|
59
|
+
CLEAN.include('**/.*.sw?')
|
60
|
+
|
61
|
+
# Returns the value of the VERSION environment variable as a Gem::Version object
|
62
|
+
# assuming it is set and a valid Gem version string. Otherwise, raises an
|
63
|
+
# exception.
|
64
|
+
def get_version_argument
|
65
|
+
version = ENV['VERSION']
|
66
|
+
if version.to_s.empty?
|
67
|
+
raise "No version specified: Add VERSION=X.Y.Z to the command line"
|
68
|
+
end
|
69
|
+
begin
|
70
|
+
Gem::Version.create(version.dup)
|
71
|
+
rescue ArgumentError
|
72
|
+
raise "Invalid version specified in `VERSION=#{version}'"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# Performs an in place, per line edit of the file indicated by _path_ by calling
|
77
|
+
# the sub method on each line and passing _pattern_, _replacement_, and _b_ as
|
78
|
+
# arguments.
|
79
|
+
def file_sub(path, pattern, replacement = nil, &b)
|
80
|
+
tmp_path = "#{path}.tmp"
|
81
|
+
File.open(path) do |infile|
|
82
|
+
File.open(tmp_path, 'w') do |outfile|
|
83
|
+
infile.each do |line|
|
84
|
+
outfile.write(line.sub(pattern, replacement, &b))
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
File.rename(tmp_path, path)
|
89
|
+
end
|
90
|
+
|
91
|
+
# Updates the version string in the gemspec file and a version.rb file it to the
|
92
|
+
# string in _version_.
|
93
|
+
def set_version(version)
|
94
|
+
file_sub(GEMSPEC, /(\.version\s*=\s*).*/, "\\1'#{version}'")
|
95
|
+
file_sub(VERSION_RB, /^(\s*VERSION\s*=\s*).*/, "\\1'#{version}'")
|
96
|
+
end
|
97
|
+
|
98
|
+
# Returns a string that is line wrapped at word boundaries, where each line is
|
99
|
+
# no longer than _line_width_ characters.
|
100
|
+
#
|
101
|
+
# This is mostly lifted directly from ActionView::Helpers::TextHelper.
|
102
|
+
def word_wrap(text, line_width = 80)
|
103
|
+
text.split("\n").collect do |line|
|
104
|
+
line.length > line_width ?
|
105
|
+
line.gsub(/(.{1,#{line_width}})(\s+|$)/, "\\1\n").strip :
|
106
|
+
line
|
107
|
+
end * "\n"
|
108
|
+
end
|
109
|
+
|
110
|
+
desc 'Alias for build:gem'
|
111
|
+
task :build => 'build:gem'
|
112
|
+
|
113
|
+
# Build related tasks.
|
114
|
+
namespace :build do
|
115
|
+
# Create the gem and package tasks.
|
116
|
+
Gem::PackageTask.new(SPEC).define
|
117
|
+
|
118
|
+
# Ensure that the that the manifest is consulted when building the gem. Any
|
119
|
+
# generated/compiled files should be available at that time.
|
120
|
+
task :gem => :check_manifest
|
121
|
+
|
122
|
+
desc 'Verify the manifest'
|
123
|
+
task :check_manifest do
|
124
|
+
manifest_files = (SPEC.files + SPEC.test_files).sort.uniq
|
125
|
+
pkg_files = PKG_FILES.sort.uniq
|
126
|
+
if manifest_files != pkg_files then
|
127
|
+
common_files = manifest_files & pkg_files
|
128
|
+
manifest_files -= common_files
|
129
|
+
pkg_files -= common_files
|
130
|
+
message = ["The manifest does not match the automatic file list."]
|
131
|
+
unless manifest_files.empty? then
|
132
|
+
message << " Extraneous files:\n " + manifest_files.join("\n ")
|
133
|
+
end
|
134
|
+
unless pkg_files.empty?
|
135
|
+
message << " Missing files:\n " + pkg_files.join("\n ")
|
136
|
+
end
|
137
|
+
raise message.join("\n")
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
# Creates the README.md file from a template and the gemspec contents.
|
142
|
+
file 'README.md' => ['README.md.erb', GEMSPEC] do
|
143
|
+
spec = SPEC
|
144
|
+
File.open('README.md', 'w') do |readme|
|
145
|
+
readme.write(
|
146
|
+
ERB.new(File.read('README.md.erb'), nil, '-').result(binding)
|
147
|
+
)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
# Ensure that the clobber task also clobbers package files.
|
153
|
+
task :clobber => 'build:clobber_package'
|
154
|
+
|
155
|
+
# Create the documentation task.
|
156
|
+
YARD::Rake::YardocTask.new
|
157
|
+
# Ensure that the README file is (re)generated first.
|
158
|
+
task :yard => 'README.md'
|
159
|
+
|
160
|
+
# Gem related tasks.
|
161
|
+
namespace :gem do
|
162
|
+
desc 'Alias for build:gem'
|
163
|
+
task :build => 'build:gem'
|
164
|
+
|
165
|
+
desc 'Publish the gemfile'
|
166
|
+
task :publish => ['version:check', :test, 'repo:tag', :build] do
|
167
|
+
sh "gem push pkg/#{SPEC.name}-#{SPEC.version}*.gem"
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
Rake::TestTask.new do |t|
|
172
|
+
t.pattern = 'spec/**/*_spec.rb'
|
173
|
+
end
|
174
|
+
|
175
|
+
# Version string management tasks.
|
176
|
+
namespace :version do
|
177
|
+
desc 'Set the version for the project to a specified version'
|
178
|
+
task :set do
|
179
|
+
set_version(get_version_argument)
|
180
|
+
end
|
181
|
+
|
182
|
+
desc 'Set the version for the project back to 0.0.0'
|
183
|
+
task :reset do
|
184
|
+
set_version('0.0.0')
|
185
|
+
end
|
186
|
+
|
187
|
+
desc 'Check that all version strings are correctly set'
|
188
|
+
task :check => ['version:check:spec', 'version:check:version_rb', 'version:check:news']
|
189
|
+
|
190
|
+
namespace :check do
|
191
|
+
desc 'Check that the version in the gemspec is correctly set'
|
192
|
+
task :spec do
|
193
|
+
version = get_version_argument
|
194
|
+
if version != SPEC.version
|
195
|
+
raise "The given version `#{version}' does not match the gemspec version `#{SPEC.version}'"
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
desc 'Check that the version in the version.rb file is correctly set'
|
200
|
+
task :version_rb do
|
201
|
+
version = get_version_argument
|
202
|
+
begin
|
203
|
+
load VERSION_RB
|
204
|
+
internal_version = Gem::Version.create(eval(VERSION_REF))
|
205
|
+
if version != internal_version
|
206
|
+
raise "The given version `#{version}' does not match the version.rb version `#{internal_version}'"
|
207
|
+
end
|
208
|
+
rescue ArgumentError
|
209
|
+
raise "Invalid version specified in `#{VERSION_RB}'"
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
desc 'Check that the NEWS.md file mentions the version'
|
214
|
+
task :news do
|
215
|
+
version = get_version_argument
|
216
|
+
begin
|
217
|
+
File.open('NEWS.md') do |news|
|
218
|
+
unless news.each_line.any? {|l| l =~ /^## v#{Regexp.escape(version.to_s)} /}
|
219
|
+
raise "The NEWS.md file does not mention version `#{version}'"
|
220
|
+
end
|
221
|
+
end
|
222
|
+
rescue Errno::ENOENT
|
223
|
+
raise 'No NEWS.md file found'
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
# Repository and workspace management tasks.
|
230
|
+
namespace :repo do
|
231
|
+
desc 'Tag the current HEAD with the version string'
|
232
|
+
task :tag => :check_workspace do
|
233
|
+
version = get_version_argument
|
234
|
+
sh "git tag -s -m 'Release v#{version}' v#{version}"
|
235
|
+
end
|
236
|
+
|
237
|
+
desc 'Ensure the workspace is fully committed and clean'
|
238
|
+
task :check_workspace => ['README.md'] do
|
239
|
+
unless `git status --untracked-files=all --porcelain`.empty?
|
240
|
+
raise 'Workspace has been modified. Commit pending changes and try again.'
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module Capistrano
|
2
|
+
class Distribution
|
3
|
+
module Distributor
|
4
|
+
|
5
|
+
##
|
6
|
+
# @abstract Subclass and override {#check} and {#distribute} to create a
|
7
|
+
# distributor.
|
8
|
+
#
|
9
|
+
# An abstract distributor upon which all distributors should ultimately be
|
10
|
+
# based.
|
11
|
+
#
|
12
|
+
# See the existing concrete distributor definitions for examples.
|
13
|
+
class Abstract
|
14
|
+
##
|
15
|
+
# @param context [(#test, #execute)] a Capistrano context used to run
|
16
|
+
# commands.
|
17
|
+
# @param url [URI, String] a URL to be used for fetching the artifact to be
|
18
|
+
# distributed
|
19
|
+
# @param opts [Hash] options to override default settings
|
20
|
+
# @option opts [String] :target ('') a path within the release area to be the
|
21
|
+
# root of the distribution.
|
22
|
+
def initialize(context, url, opts = {})
|
23
|
+
@context = context
|
24
|
+
@url = URI === url ? url : URI.parse(url)
|
25
|
+
@target = opts.fetch(:target, '')
|
26
|
+
|
27
|
+
@repo_id = Digest::SHA1.hexdigest(url.to_s)
|
28
|
+
end
|
29
|
+
|
30
|
+
##
|
31
|
+
# @abstract Override to provide a meaningful check for prerequisites during
|
32
|
+
# deployment.
|
33
|
+
#
|
34
|
+
# @return [Boolean] +true+ when prerequisites are met and +false+
|
35
|
+
# otherwise.
|
36
|
+
def check
|
37
|
+
false
|
38
|
+
end
|
39
|
+
|
40
|
+
##
|
41
|
+
# @abstract Override to provide meaningful distribution logic during
|
42
|
+
# deployment.
|
43
|
+
#
|
44
|
+
# @return [nil]
|
45
|
+
#
|
46
|
+
# @raise [exception] when distribution fails.
|
47
|
+
def distribute
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
##
|
53
|
+
# The source URL for the artifact to be distributed.
|
54
|
+
attr_reader :url
|
55
|
+
|
56
|
+
##
|
57
|
+
# The Capistrano context in which the distributor will operate.
|
58
|
+
attr_reader :context
|
59
|
+
|
60
|
+
##
|
61
|
+
# A unique identifier for the distributor for use under {#repo_path}.
|
62
|
+
attr_reader :repo_id
|
63
|
+
|
64
|
+
##
|
65
|
+
# A path relative to the release location in which to distribute the artifact.
|
66
|
+
attr_reader :target
|
67
|
+
|
68
|
+
##
|
69
|
+
# @return [Pathname] a path to the release location in which to distribute the
|
70
|
+
# artifact based on {#target}
|
71
|
+
def release_path
|
72
|
+
context.release_path.join(target)
|
73
|
+
end
|
74
|
+
|
75
|
+
##
|
76
|
+
# @return [Pathname] a path under the repo location to a unique workspace for
|
77
|
+
# the distributor
|
78
|
+
def repo_path
|
79
|
+
context.repo_path.join(repo_id)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
3
|
+
require 'capistrano/distribution/distributor/abstract'
|
4
|
+
|
5
|
+
module Capistrano
|
6
|
+
class Distribution
|
7
|
+
module Distributor
|
8
|
+
|
9
|
+
##
|
10
|
+
# @abstract Subclass and override {#distribute} to create a distributor that
|
11
|
+
# extracts archives found on the local filesystem.
|
12
|
+
#
|
13
|
+
# A convenience class for distributors that extract an archive file.
|
14
|
+
class AbstractArchiver < Abstract
|
15
|
+
##
|
16
|
+
# A regexp that matches file extentions typically found on archives used to
|
17
|
+
# distribute program binaries and source releases.
|
18
|
+
EXT_MATCHER = %r{(\.[^\d.]+[^.]*)+$}
|
19
|
+
|
20
|
+
##
|
21
|
+
# @param context [{#test, #execute}] a Capistrano context used to run
|
22
|
+
# commands.
|
23
|
+
# @param url [URI, String] a URL to be used for fetching the artifact to be
|
24
|
+
# distributed
|
25
|
+
# @param opts [Hash] options to override default settings
|
26
|
+
# @option opts [String] :subtree a path within the archive to extract as if
|
27
|
+
# its contents were at the root of the archive
|
28
|
+
def initialize(context, url, opts = {})
|
29
|
+
super(context, url, opts)
|
30
|
+
@subtree = Pathname.new(
|
31
|
+
opts.fetch(:subtree, File.basename(url).sub(ext_matcher, ''))
|
32
|
+
)
|
33
|
+
end
|
34
|
+
|
35
|
+
##
|
36
|
+
# Tests whether or not the archive indicated by {#url} is locally available.
|
37
|
+
#
|
38
|
+
# @return [Boolean] +true+ if the archive is available; otherwise, +false+.
|
39
|
+
#
|
40
|
+
# @see Abstract#check
|
41
|
+
def check
|
42
|
+
context.test '[', '-f', url.path, ']'
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
##
|
48
|
+
# The path within the archive to extract. May be an empty string.
|
49
|
+
attr_reader :subtree
|
50
|
+
|
51
|
+
##
|
52
|
+
# @return [Regexp] a regexp that matches file extentions.
|
53
|
+
def ext_matcher
|
54
|
+
EXT_MATCHER
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'capistrano/distribution/distributor/abstract_archiver'
|
2
|
+
|
3
|
+
module Capistrano
|
4
|
+
class Distribution
|
5
|
+
module Distributor
|
6
|
+
|
7
|
+
##
|
8
|
+
# @abstract Subclass and override {#distribute} to create a distributor that
|
9
|
+
# extracts archives reachable via +curl+ command.
|
10
|
+
#
|
11
|
+
# A convenience class for distributors that extract an archive downloaded using
|
12
|
+
# the +curl+ command.
|
13
|
+
class AbstractCurl < AbstractArchiver
|
14
|
+
##
|
15
|
+
# Tests whether or not the archive indicated by {#url} is available via the
|
16
|
+
# +curl+ command.
|
17
|
+
#
|
18
|
+
# @return [Boolean] +true+ if the archive is available; otherwise, +false+.
|
19
|
+
#
|
20
|
+
# @see Abstract#check
|
21
|
+
def check
|
22
|
+
context.test 'curl', '--fail', '--location', '--silent', '--head', '--request', 'GET', url
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|