realityforge-buildr 1.5.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +5 -0
- data/LICENSE +176 -0
- data/NOTICE +26 -0
- data/README.md +3 -0
- data/Rakefile +50 -0
- data/addon/buildr/checkstyle-report.xsl +104 -0
- data/addon/buildr/checkstyle.rb +254 -0
- data/addon/buildr/git_auto_version.rb +36 -0
- data/addon/buildr/gpg.rb +90 -0
- data/addon/buildr/gwt.rb +413 -0
- data/addon/buildr/jacoco.rb +161 -0
- data/addon/buildr/pmd.rb +185 -0
- data/addon/buildr/single_intermediate_layout.rb +71 -0
- data/addon/buildr/spotbugs.rb +265 -0
- data/addon/buildr/top_level_generate_dir.rb +37 -0
- data/addon/buildr/wsgen.rb +192 -0
- data/bin/buildr +20 -0
- data/buildr.gemspec +61 -0
- data/lib/buildr.rb +86 -0
- data/lib/buildr/core/application.rb +705 -0
- data/lib/buildr/core/assets.rb +96 -0
- data/lib/buildr/core/build.rb +587 -0
- data/lib/buildr/core/common.rb +167 -0
- data/lib/buildr/core/compile.rb +599 -0
- data/lib/buildr/core/console.rb +124 -0
- data/lib/buildr/core/doc.rb +275 -0
- data/lib/buildr/core/environment.rb +128 -0
- data/lib/buildr/core/filter.rb +405 -0
- data/lib/buildr/core/help.rb +114 -0
- data/lib/buildr/core/progressbar.rb +161 -0
- data/lib/buildr/core/project.rb +994 -0
- data/lib/buildr/core/test.rb +776 -0
- data/lib/buildr/core/transports.rb +456 -0
- data/lib/buildr/core/util.rb +77 -0
- data/lib/buildr/ide/idea.rb +1664 -0
- data/lib/buildr/java/commands.rb +230 -0
- data/lib/buildr/java/compiler.rb +85 -0
- data/lib/buildr/java/custom_pom.rb +300 -0
- data/lib/buildr/java/doc.rb +62 -0
- data/lib/buildr/java/packaging.rb +393 -0
- data/lib/buildr/java/pom.rb +191 -0
- data/lib/buildr/java/test_result.rb +54 -0
- data/lib/buildr/java/tests.rb +111 -0
- data/lib/buildr/packaging/archive.rb +586 -0
- data/lib/buildr/packaging/artifact.rb +1113 -0
- data/lib/buildr/packaging/artifact_namespace.rb +1010 -0
- data/lib/buildr/packaging/artifact_search.rb +138 -0
- data/lib/buildr/packaging/package.rb +237 -0
- data/lib/buildr/packaging/version_requirement.rb +189 -0
- data/lib/buildr/packaging/zip.rb +189 -0
- data/lib/buildr/packaging/ziptask.rb +387 -0
- data/lib/buildr/version.rb +18 -0
- data/rakelib/release.rake +99 -0
- data/spec/addon/checkstyle_spec.rb +58 -0
- data/spec/core/application_spec.rb +576 -0
- data/spec/core/build_spec.rb +922 -0
- data/spec/core/common_spec.rb +670 -0
- data/spec/core/compile_spec.rb +656 -0
- data/spec/core/console_spec.rb +65 -0
- data/spec/core/doc_spec.rb +194 -0
- data/spec/core/extension_spec.rb +200 -0
- data/spec/core/project_spec.rb +736 -0
- data/spec/core/test_spec.rb +1131 -0
- data/spec/core/transport_spec.rb +452 -0
- data/spec/core/util_spec.rb +154 -0
- data/spec/ide/idea_spec.rb +1952 -0
- data/spec/java/commands_spec.rb +79 -0
- data/spec/java/compiler_spec.rb +274 -0
- data/spec/java/custom_pom_spec.rb +165 -0
- data/spec/java/doc_spec.rb +55 -0
- data/spec/java/packaging_spec.rb +786 -0
- data/spec/java/pom_spec.rb +162 -0
- data/spec/java/test_coverage_helper.rb +257 -0
- data/spec/java/tests_spec.rb +224 -0
- data/spec/packaging/archive_spec.rb +686 -0
- data/spec/packaging/artifact_namespace_spec.rb +757 -0
- data/spec/packaging/artifact_spec.rb +1351 -0
- data/spec/packaging/packaging_helper.rb +63 -0
- data/spec/packaging/packaging_spec.rb +690 -0
- data/spec/sandbox.rb +166 -0
- data/spec/spec_helpers.rb +420 -0
- data/spec/version_requirement_spec.rb +145 -0
- data/spec/xpath_matchers.rb +123 -0
- metadata +295 -0
@@ -0,0 +1,96 @@
|
|
1
|
+
# Licensed to the Apache Software Foundation (ASF) under one or more
|
2
|
+
# contributor license agreements. See the NOTICE file distributed with this
|
3
|
+
# work for additional information regarding copyright ownership. The ASF
|
4
|
+
# licenses this file to you under the Apache License, Version 2.0 (the
|
5
|
+
# "License"); you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
12
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
13
|
+
# License for the specific language governing permissions and limitations under
|
14
|
+
# the License.
|
15
|
+
|
16
|
+
module Buildr #:nodoc:
|
17
|
+
|
18
|
+
module Assets #:nodoc:
|
19
|
+
|
20
|
+
# The base assets task that is responsible for
|
21
|
+
# collecting all of the assets into a single output
|
22
|
+
# directory
|
23
|
+
class AssetsTask < Rake::FileTask
|
24
|
+
attr_reader :project
|
25
|
+
|
26
|
+
def project=(project)
|
27
|
+
@project = project
|
28
|
+
end
|
29
|
+
|
30
|
+
# The list of input paths to add to output directory
|
31
|
+
def paths
|
32
|
+
unless @paths
|
33
|
+
@paths = []
|
34
|
+
@paths << project._(:source, :main, :assets) if File.exist?(project._(:source, :main, :assets))
|
35
|
+
end
|
36
|
+
@paths
|
37
|
+
end
|
38
|
+
|
39
|
+
protected
|
40
|
+
|
41
|
+
def initialize(*args) #:nodoc:
|
42
|
+
super
|
43
|
+
enhance do
|
44
|
+
paths = self.paths.flatten.compact
|
45
|
+
if paths.size > 0
|
46
|
+
mkdir_p name
|
47
|
+
paths.collect do |a|
|
48
|
+
a.is_a?(String) ? project.file(a) : a
|
49
|
+
end.each do |a|
|
50
|
+
a.invoke if a.respond_to?(:invoke)
|
51
|
+
end.each do |asset|
|
52
|
+
cp_r Dir["#{asset}/*"], "#{name}/"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def out_of_date?(stamp)
|
61
|
+
super ||
|
62
|
+
self.paths.any? { |n| n.respond_to?(:needed?) && n.needed? }
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
module ProjectExtension
|
68
|
+
include Extension
|
69
|
+
|
70
|
+
first_time do
|
71
|
+
desc "Prepare the assets"
|
72
|
+
Project.local_task("assets")
|
73
|
+
end
|
74
|
+
|
75
|
+
before_define do |project|
|
76
|
+
# Force the construction of the assets task
|
77
|
+
project.assets.paths
|
78
|
+
end
|
79
|
+
|
80
|
+
# Access the asset task
|
81
|
+
def assets
|
82
|
+
if @assets.nil?
|
83
|
+
@assets = AssetsTask.define_task(project._(:target, :main, :assets) => [])
|
84
|
+
@assets.project = self
|
85
|
+
project.task('assets').enhance([@assets])
|
86
|
+
project.build.enhance([@assets])
|
87
|
+
end
|
88
|
+
@assets
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
class Buildr::Project #:nodoc:
|
95
|
+
include ::Buildr::Assets::ProjectExtension
|
96
|
+
end
|
@@ -0,0 +1,587 @@
|
|
1
|
+
# Licensed to the Apache Software Foundation (ASF) under one or more
|
2
|
+
# contributor license agreements. See the NOTICE file distributed with this
|
3
|
+
# work for additional information regarding copyright ownership. The ASF
|
4
|
+
# licenses this file to you under the Apache License, Version 2.0 (the
|
5
|
+
# "License"); you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
12
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
13
|
+
# License for the specific language governing permissions and limitations under
|
14
|
+
# the License.
|
15
|
+
|
16
|
+
module Buildr #:nodoc:
|
17
|
+
|
18
|
+
class Options
|
19
|
+
|
20
|
+
# Runs the build in parallel when true (defaults to false). You can force a parallel build by
|
21
|
+
# setting this option directly, or by running the parallel task ahead of the build task.
|
22
|
+
#
|
23
|
+
# This option only affects recursive tasks. For example:
|
24
|
+
# buildr parallel package
|
25
|
+
# will run all package tasks (from the sub-projects) in parallel, but each sub-project's package
|
26
|
+
# task runs its child tasks (prepare, compile, resources, etc) in sequence.
|
27
|
+
attr_accessor :parallel
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
task('parallel') { Buildr.options.parallel = true }
|
32
|
+
|
33
|
+
|
34
|
+
module Build
|
35
|
+
|
36
|
+
include Extension
|
37
|
+
|
38
|
+
first_time do
|
39
|
+
desc 'Build the project'
|
40
|
+
Project.local_task('build') { |name| "Building #{name}" }
|
41
|
+
desc 'Clean files generated during a build'
|
42
|
+
Project.local_task('clean') { |name| "Cleaning #{name}" }
|
43
|
+
|
44
|
+
desc 'The default task is build'
|
45
|
+
task 'default'=>'build'
|
46
|
+
end
|
47
|
+
|
48
|
+
before_define(:build => [:compile, :test]) do |project|
|
49
|
+
project.recursive_task 'build'
|
50
|
+
project.recursive_task 'clean'
|
51
|
+
project.clean do
|
52
|
+
rm_rf project.path_to(:target)
|
53
|
+
rm_rf project.path_to(:reports)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
after_define(:build)
|
58
|
+
|
59
|
+
# :call-seq:
|
60
|
+
# build(*prereqs) => task
|
61
|
+
# build { |task| .. } => task
|
62
|
+
#
|
63
|
+
# Returns the project's build task. With arguments or block, also enhances that task.
|
64
|
+
def build(*prereqs, &block)
|
65
|
+
task('build').enhance prereqs, &block
|
66
|
+
end
|
67
|
+
|
68
|
+
# :call-seq:
|
69
|
+
# clean(*prereqs) => task
|
70
|
+
# clean { |task| .. } => task
|
71
|
+
#
|
72
|
+
# Returns the project's clean task. With arguments or block, also enhances that task.
|
73
|
+
def clean(*prereqs, &block)
|
74
|
+
task('clean').enhance prereqs, &block
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
module Hg #:nodoc:
|
80
|
+
module_function
|
81
|
+
|
82
|
+
# :call-seq:
|
83
|
+
# hg(*args)
|
84
|
+
#
|
85
|
+
# Executes a Mercurial (hg) command passing through the args and returns the output.
|
86
|
+
# Throws exception if the exit status is not zero. For example:
|
87
|
+
# hg 'commit'
|
88
|
+
# hg 'update', 'default'
|
89
|
+
def hg(*args)
|
90
|
+
cmd = "hg #{args.shift} #{args.map { |arg| arg.inspect }.join(' ')}"
|
91
|
+
output = `#{cmd}`
|
92
|
+
fail "Mercurial command \"#{cmd}\" failed with status #{$?.exitstatus}\n#{output}" unless $?.exitstatus == 0
|
93
|
+
return output
|
94
|
+
end
|
95
|
+
|
96
|
+
# Return a list of uncommitted / untracked files as reported by hg status
|
97
|
+
# The codes used to show the status of files are:
|
98
|
+
# M = modified
|
99
|
+
# A = added
|
100
|
+
# R = removed
|
101
|
+
# C = clean
|
102
|
+
# ! = missing (deleted by non-hg command, but still tracked)
|
103
|
+
# ? = not tracked
|
104
|
+
# I = ignored
|
105
|
+
# = origin of the previous file listed as A (added)
|
106
|
+
def uncommitted_files
|
107
|
+
`hg status`.scan(/^(A|M|R|!|\?) (\S.*)$/).map{ |match| match.last.split.last }
|
108
|
+
end
|
109
|
+
|
110
|
+
# Commit the given file with a message. The file should already be added to the Mercurial index.
|
111
|
+
def commit(file, message)
|
112
|
+
hg 'commit', '-m', message, file
|
113
|
+
end
|
114
|
+
|
115
|
+
# Update the remote branch with the local commits
|
116
|
+
# This will push the current remote destination and current branch.
|
117
|
+
def push
|
118
|
+
hg 'push'
|
119
|
+
end
|
120
|
+
|
121
|
+
# Return the name of the current local branch or nil if none.
|
122
|
+
def current_branch
|
123
|
+
hg('branch').to_s.strip
|
124
|
+
end
|
125
|
+
|
126
|
+
# Return the aliases (if any) of any remote repositories which the current local branch tracks
|
127
|
+
def remote
|
128
|
+
hg('paths').scan(/^(?:default|default-push)\s+=\s+(\S.*)/).map{ |match| match.last }
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
module Git #:nodoc:
|
133
|
+
module_function
|
134
|
+
|
135
|
+
# :call-seq:
|
136
|
+
# git(*args)
|
137
|
+
#
|
138
|
+
# Executes a Git command and returns the output. Throws exception if the exit status
|
139
|
+
# is not zero. For example:
|
140
|
+
# git 'commit'
|
141
|
+
# git 'remote', 'show', 'origin'
|
142
|
+
def git(*args)
|
143
|
+
cmd = "git #{args.shift} #{args.map { |arg| arg.inspect }.join(' ')}"
|
144
|
+
output = `#{cmd}`
|
145
|
+
fail "GIT command \"#{cmd}\" failed with status #{$?.exitstatus}\n#{output}" unless $?.exitstatus == 0
|
146
|
+
return output
|
147
|
+
end
|
148
|
+
|
149
|
+
# Returns list of uncommited/untracked files as reported by git status.
|
150
|
+
def uncommitted_files
|
151
|
+
`git status`.scan(/^#(\t|\s{7})(\S.*)$/).map { |match| match.last.split.last }
|
152
|
+
end
|
153
|
+
|
154
|
+
# Commit the given file with a message.
|
155
|
+
# The file has to be known to Git meaning that it has either to have been already committed in the past
|
156
|
+
# or freshly added to the index. Otherwise it will fail.
|
157
|
+
def commit(file, message)
|
158
|
+
git 'commit', '-m', message, file
|
159
|
+
end
|
160
|
+
|
161
|
+
# Update the remote refs using local refs
|
162
|
+
#
|
163
|
+
# By default, the "remote" destination of the push is the the remote repo linked to the current branch.
|
164
|
+
# The default remote branch is the current local branch.
|
165
|
+
def push(remote_repo = remote, remote_branch = current_branch)
|
166
|
+
git 'push', remote, current_branch
|
167
|
+
end
|
168
|
+
|
169
|
+
# Return the name of the remote repository whose branch the current local branch tracks,
|
170
|
+
# or nil if none.
|
171
|
+
def remote(branch = current_branch)
|
172
|
+
remote = git('config', '--get', "branch.#{branch}.remote").to_s.strip
|
173
|
+
remote if !remote.empty? && git('remote').include?(remote)
|
174
|
+
end
|
175
|
+
|
176
|
+
# Return the name of the current branch
|
177
|
+
def current_branch
|
178
|
+
git('branch')[/^\* (.*)$/, 1]
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
|
183
|
+
module Svn #:nodoc:
|
184
|
+
module_function
|
185
|
+
|
186
|
+
# :call-seq:
|
187
|
+
# svn(*args)
|
188
|
+
#
|
189
|
+
# Executes a SVN command and returns the output. Throws exception if the exit status
|
190
|
+
# is not zero. For example:
|
191
|
+
# svn 'commit'
|
192
|
+
def svn(*args)
|
193
|
+
output = `svn #{args.shift} #{args.map { |arg| arg.inspect }.join(' ')}`
|
194
|
+
fail "SVN command failed with status #{$?.exitstatus}" unless $?.exitstatus == 0
|
195
|
+
return output
|
196
|
+
end
|
197
|
+
|
198
|
+
def tag(tag_name)
|
199
|
+
url = tag_url repo_url, tag_name
|
200
|
+
remove url, 'Removing old copy' rescue nil
|
201
|
+
copy Dir.pwd, url, "Release #{tag_name}"
|
202
|
+
end
|
203
|
+
|
204
|
+
# Status check reveals modified files, but also SVN externals which we can safely ignore.
|
205
|
+
def uncommitted_files
|
206
|
+
svn('status', '--ignore-externals').split("\n").reject { |line| line =~ /^X\s/ }
|
207
|
+
end
|
208
|
+
|
209
|
+
def commit(file, message)
|
210
|
+
svn 'commit', '-m', message, file
|
211
|
+
end
|
212
|
+
|
213
|
+
# :call-seq:
|
214
|
+
# tag_url(svn_url, version) => tag_url
|
215
|
+
#
|
216
|
+
# Returns the SVN url for the tag.
|
217
|
+
# Can tag from the trunk or from branches.
|
218
|
+
# Can handle the two standard repository layouts.
|
219
|
+
# - http://my.repo/foo/trunk => http://my.repo/foo/tags/1.0.0
|
220
|
+
# - http://my.repo/trunk/foo => http://my.repo/tags/foo/1.0.0
|
221
|
+
def tag_url(svn_url, tag)
|
222
|
+
trunk_or_branches = Regexp.union(%r{^(.*)/trunk(.*)$}, %r{^(.*)/branches(.*)/([^/]*)$})
|
223
|
+
match = trunk_or_branches.match(svn_url)
|
224
|
+
prefix = match[1] || match[3]
|
225
|
+
suffix = match[2] || match[4]
|
226
|
+
prefix + '/tags' + suffix + '/' + tag
|
227
|
+
end
|
228
|
+
|
229
|
+
# Return the current SVN URL
|
230
|
+
def repo_url
|
231
|
+
svn('info', '--xml')[/<url>(.*?)<\/url>/, 1].strip
|
232
|
+
end
|
233
|
+
|
234
|
+
def copy(dir, url, message)
|
235
|
+
svn 'copy', '--parents', dir, url, '-m', message
|
236
|
+
end
|
237
|
+
|
238
|
+
def remove(url, message)
|
239
|
+
svn 'remove', url, '-m', message
|
240
|
+
end
|
241
|
+
|
242
|
+
end
|
243
|
+
|
244
|
+
|
245
|
+
class Release #:nodoc:
|
246
|
+
|
247
|
+
THIS_VERSION_PATTERN = /(THIS_VERSION|VERSION_NUMBER)\s*=\s*(["'])(.*)\2/
|
248
|
+
|
249
|
+
class << self
|
250
|
+
|
251
|
+
# Use this to specify a different tag name for tagging the release in source control.
|
252
|
+
# You can set the tag name or a proc that will be called with the version number,
|
253
|
+
# for example:
|
254
|
+
# Release.tag_name = lambda { |ver| "foo-#{ver}" }
|
255
|
+
attr_accessor :tag_name
|
256
|
+
|
257
|
+
# Use this to specify a different commit message to commit the buildfile with the next version in source control.
|
258
|
+
# You can set the commit message or a proc that will be called with the next version number,
|
259
|
+
# for example:
|
260
|
+
# Release.commit_message = lambda { |ver| "Changed version number to #{ver}" }
|
261
|
+
attr_accessor :commit_message
|
262
|
+
|
263
|
+
# Use this to specify the next version number to replace VERSION_NUMBER with in the buildfile.
|
264
|
+
# You can set the next version or a proc that will be called with the current version number.
|
265
|
+
# For example, with the following buildfile:
|
266
|
+
# THIS_VERSION = "1.0.0-rc1"
|
267
|
+
# Release.next_version = lambda { |version|
|
268
|
+
# version[-1] = version[-1].to_i + 1
|
269
|
+
# version
|
270
|
+
# }
|
271
|
+
#
|
272
|
+
# Release.next_version will return "1.0.0-rc2", so at the end of the release, the buildfile will contain VERSION_NUMBER = "1.0.0-rc2"
|
273
|
+
#
|
274
|
+
attr_accessor :next_version
|
275
|
+
|
276
|
+
# :call-seq:
|
277
|
+
# add(MyReleaseClass)
|
278
|
+
#
|
279
|
+
# Add a Release implementation to the list of available Release classes.
|
280
|
+
def add(release)
|
281
|
+
@list ||= []
|
282
|
+
@list |= [release]
|
283
|
+
end
|
284
|
+
alias :<< :add
|
285
|
+
|
286
|
+
# The list of supported Release implementations
|
287
|
+
def list
|
288
|
+
@list ||= []
|
289
|
+
end
|
290
|
+
|
291
|
+
# Finds and returns the Release instance for this project.
|
292
|
+
def find
|
293
|
+
unless @release
|
294
|
+
klass = list.detect { |impl| impl.applies_to? }
|
295
|
+
@release = klass.new if klass
|
296
|
+
end
|
297
|
+
@release
|
298
|
+
end
|
299
|
+
|
300
|
+
end
|
301
|
+
|
302
|
+
# :call-seq:
|
303
|
+
# make()
|
304
|
+
#
|
305
|
+
# Make a release.
|
306
|
+
def make
|
307
|
+
@this_version = extract_version
|
308
|
+
check
|
309
|
+
with_release_candidate_version do |release_candidate_buildfile|
|
310
|
+
args = []
|
311
|
+
args << 'buildr' << '--buildfile' << release_candidate_buildfile
|
312
|
+
args << '--environment' << Buildr.environment unless Buildr.environment.to_s.empty?
|
313
|
+
args << 'clean' << 'upload' << 'DEBUG=no'
|
314
|
+
sh *args
|
315
|
+
end
|
316
|
+
tag_release resolve_tag
|
317
|
+
update_version_to_next if this_version != resolve_next_version(this_version)
|
318
|
+
end
|
319
|
+
|
320
|
+
def check
|
321
|
+
if this_version == resolve_next_version(this_version) && this_version.match(/-SNAPSHOT$/)
|
322
|
+
fail "The next version can't be equal to the current version #{this_version}.\nUpdate THIS_VERSION/VERSION_NUMBER, specify Release.next_version or use NEXT_VERSION env var"
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
# :call-seq:
|
327
|
+
# extract_version() => this_version
|
328
|
+
#
|
329
|
+
# Extract the current version number from the buildfile.
|
330
|
+
# Raise an error if not found.
|
331
|
+
def extract_version
|
332
|
+
buildfile = File.read(version_file)
|
333
|
+
buildfile.scan(THIS_VERSION_PATTERN)[0][2]
|
334
|
+
rescue
|
335
|
+
fail 'Looking for THIS_VERSION = "..." in your Buildfile, none found'
|
336
|
+
end
|
337
|
+
|
338
|
+
protected
|
339
|
+
|
340
|
+
# the initial value of THIS_VERSION
|
341
|
+
attr_accessor :this_version
|
342
|
+
|
343
|
+
# :call-seq:
|
344
|
+
# version_file()
|
345
|
+
# Provides the file containing the version of the project.
|
346
|
+
# If the project contains a version.rb file next to the Buildr build file,
|
347
|
+
# it is used. Otherwise, always use the buildfile.
|
348
|
+
def version_file
|
349
|
+
version_rb_file = File.dirname(Buildr.application.buildfile.to_s) + '/version.rb'
|
350
|
+
return version_rb_file if File.exists?(version_rb_file)
|
351
|
+
return Buildr.application.buildfile.to_s
|
352
|
+
end
|
353
|
+
|
354
|
+
# :call-seq:
|
355
|
+
# with_release_candidate_version() { |filename| ... }
|
356
|
+
#
|
357
|
+
# Yields to block with release candidate buildfile, before committing to use it.
|
358
|
+
#
|
359
|
+
# We need a Buildfile with upgraded version numbers to run the build, but we don't want the
|
360
|
+
# Buildfile modified unless the build succeeds. So this method updates the version number in
|
361
|
+
# a separate (Buildfile.next) file, yields to the block with that filename, and if successful
|
362
|
+
# copies the new file over the existing one.
|
363
|
+
#
|
364
|
+
# The release version is the current version without '-SNAPSHOT'. So:
|
365
|
+
# THIS_VERSION = 1.1.0-SNAPSHOT
|
366
|
+
# becomes:
|
367
|
+
# THIS_VERSION = 1.1.0
|
368
|
+
# for the release buildfile.
|
369
|
+
def with_release_candidate_version
|
370
|
+
release_candidate_buildfile = version_file + '.next'
|
371
|
+
|
372
|
+
release_candidate_buildfile_contents = change_version { |version|
|
373
|
+
version.gsub(/-SNAPSHOT$/, "")
|
374
|
+
}
|
375
|
+
File.open(release_candidate_buildfile, 'w') { |file| file.write release_candidate_buildfile_contents }
|
376
|
+
begin
|
377
|
+
yield release_candidate_buildfile
|
378
|
+
mv release_candidate_buildfile, version_file
|
379
|
+
ensure
|
380
|
+
rm release_candidate_buildfile rescue nil
|
381
|
+
end
|
382
|
+
end
|
383
|
+
|
384
|
+
# :call-seq:
|
385
|
+
# change_version() { |this_version| ... } => buildfile
|
386
|
+
#
|
387
|
+
# Change version number in the current Buildfile, but without writing a new file (yet).
|
388
|
+
# Returns the contents of the Buildfile with the modified version number.
|
389
|
+
#
|
390
|
+
# This method yields to the block with the current (this) version number and expects
|
391
|
+
# the block to return the updated version.
|
392
|
+
def change_version
|
393
|
+
current_version = extract_version
|
394
|
+
new_version = yield(current_version)
|
395
|
+
buildfile = File.read(version_file)
|
396
|
+
buildfile.gsub(THIS_VERSION_PATTERN) { |ver| ver.sub(/(["']).*\1/, %Q{"#{new_version}"}) }
|
397
|
+
end
|
398
|
+
|
399
|
+
# Return the name of the tag to tag the release with.
|
400
|
+
def resolve_tag
|
401
|
+
version = extract_version
|
402
|
+
tag = Release.tag_name || version
|
403
|
+
tag = tag.call(version) if Proc === tag
|
404
|
+
tag
|
405
|
+
end
|
406
|
+
|
407
|
+
# Return the new value of THIS_VERSION based on the version passed.
|
408
|
+
#
|
409
|
+
# This method receives the existing value of THIS_VERSION
|
410
|
+
def resolve_next_version(current_version)
|
411
|
+
next_version = Release.next_version
|
412
|
+
next_version ||= lambda { |v|
|
413
|
+
snapshot = v.match(/-SNAPSHOT$/)
|
414
|
+
version = v.gsub(/-SNAPSHOT$/, "").split(/\./)
|
415
|
+
if snapshot
|
416
|
+
version[-1] = sprintf("%0#{version[-1].size}d", version[-1].to_i + 1) + '-SNAPSHOT'
|
417
|
+
end
|
418
|
+
version.join('.')
|
419
|
+
}
|
420
|
+
next_version = ENV['NEXT_VERSION'] if ENV['NEXT_VERSION']
|
421
|
+
next_version = ENV['next_version'] if ENV['next_version']
|
422
|
+
next_version = next_version.call(current_version) if Proc === next_version
|
423
|
+
next_version
|
424
|
+
end
|
425
|
+
|
426
|
+
# Move the version to next and save the updated buildfile
|
427
|
+
def update_buildfile
|
428
|
+
buildfile = change_version { |version| # THIS_VERSION minus SNAPSHOT
|
429
|
+
resolve_next_version(this_version) # THIS_VERSION
|
430
|
+
}
|
431
|
+
File.open(version_file, 'w') { |file| file.write buildfile }
|
432
|
+
end
|
433
|
+
|
434
|
+
# Return the message to use to commit the buildfile with the next version
|
435
|
+
def message
|
436
|
+
version = extract_version
|
437
|
+
msg = Release.commit_message || "Changed version number to #{version}"
|
438
|
+
msg = msg.call(version) if Proc === msg
|
439
|
+
msg
|
440
|
+
end
|
441
|
+
|
442
|
+
def update_version_to_next
|
443
|
+
update_buildfile
|
444
|
+
end
|
445
|
+
end
|
446
|
+
|
447
|
+
|
448
|
+
class HgRelease < Release
|
449
|
+
class << self
|
450
|
+
def applies_to?
|
451
|
+
if File.exist? '.hg/requires'
|
452
|
+
true
|
453
|
+
else
|
454
|
+
curr_pwd = Dir.pwd
|
455
|
+
Dir.chdir('..') do
|
456
|
+
return false if curr_pwd == Dir.pwd # Means going up one level is not possible.
|
457
|
+
applies_to?
|
458
|
+
end
|
459
|
+
end
|
460
|
+
end
|
461
|
+
end
|
462
|
+
|
463
|
+
# Fails if one of these 2 conditions are not met:
|
464
|
+
# 1. The reository is not 'clean'; no content staged or unstaged
|
465
|
+
# 2. The repository is only a local repository and has no remote refs
|
466
|
+
def check
|
467
|
+
super
|
468
|
+
info "Working in branch '#{Hg.current_branch}'"
|
469
|
+
uncommitted = Hg.uncommitted_files
|
470
|
+
fail "Uncommitted files violate the First Principle Of Release!\n#{uncommitted.join("\n")}" unless uncommitted.empty?
|
471
|
+
fail "You are releasing from a local branch that does not track a remote!" if Hg.remote.empty?
|
472
|
+
end
|
473
|
+
|
474
|
+
# Tag this release in Mercurial
|
475
|
+
def tag_release(tag)
|
476
|
+
unless this_version == extract_version
|
477
|
+
info "Committing buildfile with version number #{extract_version}"
|
478
|
+
Hg.commit File.basename(version_file), message
|
479
|
+
Hg.push if Hg.remote
|
480
|
+
end
|
481
|
+
info "Tagging release #{tag}"
|
482
|
+
Hg.hg 'tag', tag, '-m', "[buildr] Cutting release #{tag}"
|
483
|
+
Hg.push if Hg.remote
|
484
|
+
end
|
485
|
+
|
486
|
+
# Update buildfile with next version number
|
487
|
+
def update_version_to_next
|
488
|
+
super
|
489
|
+
info "Current version is now #{extract_version}"
|
490
|
+
Hg.commit File.basename(version_file), message
|
491
|
+
Hg.push if Hg.remote
|
492
|
+
end
|
493
|
+
end
|
494
|
+
|
495
|
+
|
496
|
+
class GitRelease < Release
|
497
|
+
class << self
|
498
|
+
def applies_to?
|
499
|
+
if File.exist? '.git/config'
|
500
|
+
true
|
501
|
+
else
|
502
|
+
curr_pwd = Dir.pwd
|
503
|
+
Dir.chdir('..') do
|
504
|
+
return false if curr_pwd == Dir.pwd # Means going up one level is not possible.
|
505
|
+
applies_to?
|
506
|
+
end
|
507
|
+
end
|
508
|
+
end
|
509
|
+
end
|
510
|
+
|
511
|
+
# Fails if one of these 2 conditions are not met:
|
512
|
+
# 1. the repository is clean: no content staged or unstaged
|
513
|
+
# 2. some remote repositories are defined but the current branch does not track any
|
514
|
+
def check
|
515
|
+
super
|
516
|
+
uncommitted = Git.uncommitted_files
|
517
|
+
fail "Uncommitted files violate the First Principle Of Release!\n#{uncommitted.join("\n")}" unless uncommitted.empty?
|
518
|
+
fail "You are releasing from a local branch that does not track a remote!" unless Git.remote
|
519
|
+
end
|
520
|
+
|
521
|
+
# Add a tag reference in .git/refs/tags and push it to the remote if any.
|
522
|
+
# If a tag with the same name already exists it will get deleted (in both local and remote repositories).
|
523
|
+
def tag_release(tag)
|
524
|
+
unless this_version == extract_version
|
525
|
+
info "Committing buildfile with version number #{extract_version}"
|
526
|
+
Git.commit File.basename(version_file), message
|
527
|
+
Git.push if Git.remote
|
528
|
+
end
|
529
|
+
info "Tagging release #{tag}"
|
530
|
+
Git.git 'tag', '-d', tag rescue nil
|
531
|
+
Git.git 'push', Git.remote, ":refs/tags/#{tag}" rescue nil if Git.remote
|
532
|
+
Git.git 'tag', '-a', tag, '-m', "[buildr] Cutting release #{tag}"
|
533
|
+
Git.git 'push', Git.remote, 'tag', tag if Git.remote
|
534
|
+
end
|
535
|
+
|
536
|
+
def update_version_to_next
|
537
|
+
super
|
538
|
+
info "Current version is now #{extract_version}"
|
539
|
+
Git.commit File.basename(version_file), message
|
540
|
+
Git.push if Git.remote
|
541
|
+
end
|
542
|
+
end
|
543
|
+
|
544
|
+
|
545
|
+
class SvnRelease < Release
|
546
|
+
class << self
|
547
|
+
def applies_to?
|
548
|
+
File.exist?('.svn')
|
549
|
+
end
|
550
|
+
end
|
551
|
+
|
552
|
+
def check
|
553
|
+
super
|
554
|
+
fail "Uncommitted files violate the First Principle Of Release!\n"+Svn.uncommitted_files.join("\n") unless Svn.uncommitted_files.empty?
|
555
|
+
fail "SVN URL must contain 'trunk' or 'branches/...'" unless Svn.repo_url =~ /(trunk)|(branches.*)$/
|
556
|
+
end
|
557
|
+
|
558
|
+
def tag_release(tag)
|
559
|
+
# Unlike Git, committing the buildfile with the released version is not necessary.
|
560
|
+
# svn tag does commit & tag.
|
561
|
+
info "Tagging release #{tag}"
|
562
|
+
Svn.tag tag
|
563
|
+
end
|
564
|
+
|
565
|
+
def update_version_to_next
|
566
|
+
super
|
567
|
+
info "Current version is now #{extract_version}"
|
568
|
+
Svn.commit version_file, message
|
569
|
+
end
|
570
|
+
end
|
571
|
+
|
572
|
+
Release.add HgRelease
|
573
|
+
Release.add SvnRelease
|
574
|
+
Release.add GitRelease
|
575
|
+
|
576
|
+
desc 'Make a release'
|
577
|
+
task 'release' do |task|
|
578
|
+
release = Release.find
|
579
|
+
fail 'Unable to detect the Version Control System.' unless release
|
580
|
+
release.make
|
581
|
+
end
|
582
|
+
|
583
|
+
end
|
584
|
+
|
585
|
+
class Buildr::Project #:nodoc:
|
586
|
+
include Buildr::Build
|
587
|
+
end
|