buildr 1.3.5-x86-mswin32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (186) hide show
  1. data/CHANGELOG +998 -0
  2. data/LICENSE +176 -0
  3. data/NOTICE +26 -0
  4. data/README.rdoc +134 -0
  5. data/Rakefile +45 -0
  6. data/_buildr +29 -0
  7. data/_jbuildr +29 -0
  8. data/addon/buildr/antlr.rb +65 -0
  9. data/addon/buildr/cobertura.rb +22 -0
  10. data/addon/buildr/drb.rb +281 -0
  11. data/addon/buildr/emma.rb +22 -0
  12. data/addon/buildr/hibernate.rb +142 -0
  13. data/addon/buildr/javacc.rb +85 -0
  14. data/addon/buildr/jdepend.rb +60 -0
  15. data/addon/buildr/jetty.rb +248 -0
  16. data/addon/buildr/jibx.rb +86 -0
  17. data/addon/buildr/nailgun.rb +221 -0
  18. data/addon/buildr/openjpa.rb +90 -0
  19. data/addon/buildr/org/apache/buildr/BuildrNail$Main.class +0 -0
  20. data/addon/buildr/org/apache/buildr/BuildrNail.class +0 -0
  21. data/addon/buildr/org/apache/buildr/BuildrNail.java +41 -0
  22. data/addon/buildr/org/apache/buildr/JettyWrapper$1.class +0 -0
  23. data/addon/buildr/org/apache/buildr/JettyWrapper$BuildrHandler.class +0 -0
  24. data/addon/buildr/org/apache/buildr/JettyWrapper.class +0 -0
  25. data/addon/buildr/org/apache/buildr/JettyWrapper.java +144 -0
  26. data/addon/buildr/xmlbeans.rb +93 -0
  27. data/bin/buildr +19 -0
  28. data/buildr.buildfile +58 -0
  29. data/buildr.gemspec +65 -0
  30. data/doc/_config.yml +1 -0
  31. data/doc/_layouts/default.html +88 -0
  32. data/doc/_layouts/preface.html +22 -0
  33. data/doc/artifacts.textile +211 -0
  34. data/doc/building.textile +244 -0
  35. data/doc/contributing.textile +252 -0
  36. data/doc/css/default.css +236 -0
  37. data/doc/css/print.css +101 -0
  38. data/doc/css/syntax.css +23 -0
  39. data/doc/download.textile +79 -0
  40. data/doc/extending.textile +186 -0
  41. data/doc/images/1442160941-frontcover.jpg +0 -0
  42. data/doc/images/asf-logo.gif +0 -0
  43. data/doc/images/asf-logo.png +0 -0
  44. data/doc/images/buildr-hires.png +0 -0
  45. data/doc/images/buildr.png +0 -0
  46. data/doc/images/favicon.png +0 -0
  47. data/doc/images/growl-icon.tiff +0 -0
  48. data/doc/images/note.png +0 -0
  49. data/doc/images/project-structure.png +0 -0
  50. data/doc/images/tip.png +0 -0
  51. data/doc/images/zbuildr.png +0 -0
  52. data/doc/images/zbuildr.tif +0 -0
  53. data/doc/index.textile +69 -0
  54. data/doc/installing.textile +266 -0
  55. data/doc/languages.textile +459 -0
  56. data/doc/mailing_lists.textile +25 -0
  57. data/doc/more_stuff.textile +457 -0
  58. data/doc/packaging.textile +430 -0
  59. data/doc/preface.textile +54 -0
  60. data/doc/projects.textile +271 -0
  61. data/doc/quick_start.textile +210 -0
  62. data/doc/scripts/buildr-git.rb +512 -0
  63. data/doc/scripts/gitflow.rb +296 -0
  64. data/doc/scripts/install-jruby.sh +44 -0
  65. data/doc/scripts/install-linux.sh +72 -0
  66. data/doc/scripts/install-osx.sh +52 -0
  67. data/doc/settings_profiles.textile +280 -0
  68. data/doc/testing.textile +222 -0
  69. data/etc/KEYS +151 -0
  70. data/lib/buildr.rb +36 -0
  71. data/lib/buildr/core.rb +35 -0
  72. data/lib/buildr/core/application.rb +656 -0
  73. data/lib/buildr/core/build.rb +452 -0
  74. data/lib/buildr/core/checks.rb +254 -0
  75. data/lib/buildr/core/common.rb +150 -0
  76. data/lib/buildr/core/compile.rb +608 -0
  77. data/lib/buildr/core/environment.rb +129 -0
  78. data/lib/buildr/core/filter.rb +362 -0
  79. data/lib/buildr/core/generate.rb +195 -0
  80. data/lib/buildr/core/help.rb +119 -0
  81. data/lib/buildr/core/osx.rb +46 -0
  82. data/lib/buildr/core/progressbar.rb +156 -0
  83. data/lib/buildr/core/project.rb +866 -0
  84. data/lib/buildr/core/shell.rb +198 -0
  85. data/lib/buildr/core/test.rb +723 -0
  86. data/lib/buildr/core/transports.rb +559 -0
  87. data/lib/buildr/core/util.rb +449 -0
  88. data/lib/buildr/groovy.rb +19 -0
  89. data/lib/buildr/groovy/bdd.rb +106 -0
  90. data/lib/buildr/groovy/compiler.rb +138 -0
  91. data/lib/buildr/groovy/shell.rb +48 -0
  92. data/lib/buildr/ide.rb +19 -0
  93. data/lib/buildr/ide/eclipse.rb +334 -0
  94. data/lib/buildr/ide/eclipse/java.rb +53 -0
  95. data/lib/buildr/ide/eclipse/plugin.rb +68 -0
  96. data/lib/buildr/ide/eclipse/scala.rb +66 -0
  97. data/lib/buildr/ide/idea.ipr.template +300 -0
  98. data/lib/buildr/ide/idea.rb +190 -0
  99. data/lib/buildr/ide/idea7x.ipr.template +290 -0
  100. data/lib/buildr/ide/idea7x.rb +212 -0
  101. data/lib/buildr/java.rb +23 -0
  102. data/lib/buildr/java/ant.rb +94 -0
  103. data/lib/buildr/java/bdd.rb +459 -0
  104. data/lib/buildr/java/cobertura.rb +274 -0
  105. data/lib/buildr/java/commands.rb +213 -0
  106. data/lib/buildr/java/compiler.rb +349 -0
  107. data/lib/buildr/java/deprecated.rb +141 -0
  108. data/lib/buildr/java/emma.rb +244 -0
  109. data/lib/buildr/java/jruby.rb +117 -0
  110. data/lib/buildr/java/jtestr_runner.rb.erb +116 -0
  111. data/lib/buildr/java/org/apache/buildr/JavaTestFilter.class +0 -0
  112. data/lib/buildr/java/org/apache/buildr/JavaTestFilter.java +137 -0
  113. data/lib/buildr/java/packaging.rb +716 -0
  114. data/lib/buildr/java/pom.rb +174 -0
  115. data/lib/buildr/java/rjb.rb +155 -0
  116. data/lib/buildr/java/test_result.rb +353 -0
  117. data/lib/buildr/java/tests.rb +333 -0
  118. data/lib/buildr/java/version_requirement.rb +172 -0
  119. data/lib/buildr/packaging.rb +24 -0
  120. data/lib/buildr/packaging/archive.rb +488 -0
  121. data/lib/buildr/packaging/artifact.rb +749 -0
  122. data/lib/buildr/packaging/artifact_namespace.rb +972 -0
  123. data/lib/buildr/packaging/artifact_search.rb +140 -0
  124. data/lib/buildr/packaging/gems.rb +102 -0
  125. data/lib/buildr/packaging/package.rb +238 -0
  126. data/lib/buildr/packaging/tar.rb +186 -0
  127. data/lib/buildr/packaging/version_requirement.rb +172 -0
  128. data/lib/buildr/packaging/zip.rb +73 -0
  129. data/lib/buildr/packaging/ziptask.rb +316 -0
  130. data/lib/buildr/resources/buildr.icns +0 -0
  131. data/lib/buildr/scala.rb +25 -0
  132. data/lib/buildr/scala/bdd.rb +109 -0
  133. data/lib/buildr/scala/compiler.rb +195 -0
  134. data/lib/buildr/scala/org/apache/buildr/SpecsSingletonRunner$.class +0 -0
  135. data/lib/buildr/scala/org/apache/buildr/SpecsSingletonRunner.class +0 -0
  136. data/lib/buildr/scala/org/apache/buildr/SpecsSingletonRunner.scala +35 -0
  137. data/lib/buildr/scala/shell.rb +55 -0
  138. data/lib/buildr/scala/tests.rb +157 -0
  139. data/lib/buildr/shell.rb +180 -0
  140. data/rakelib/checks.rake +57 -0
  141. data/rakelib/doc.rake +92 -0
  142. data/rakelib/jekylltask.rb +120 -0
  143. data/rakelib/package.rake +73 -0
  144. data/rakelib/release.rake +149 -0
  145. data/rakelib/rspec.rake +73 -0
  146. data/rakelib/setup.rake +54 -0
  147. data/rakelib/stage.rake +213 -0
  148. data/rakelib/stage.rake~ +213 -0
  149. data/spec/addon/drb_spec.rb +328 -0
  150. data/spec/core/application_spec.rb +502 -0
  151. data/spec/core/build_spec.rb +677 -0
  152. data/spec/core/checks_spec.rb +519 -0
  153. data/spec/core/common_spec.rb +670 -0
  154. data/spec/core/compile_spec.rb +583 -0
  155. data/spec/core/extension_spec.rb +93 -0
  156. data/spec/core/generate_spec.rb +33 -0
  157. data/spec/core/project_spec.rb +762 -0
  158. data/spec/core/test_spec.rb +1098 -0
  159. data/spec/core/transport_spec.rb +537 -0
  160. data/spec/core/util_spec.rb +67 -0
  161. data/spec/groovy/bdd_spec.rb +80 -0
  162. data/spec/groovy/compiler_spec.rb +240 -0
  163. data/spec/ide/eclipse_spec.rb +501 -0
  164. data/spec/ide/idea7x_spec.rb +84 -0
  165. data/spec/java/ant_spec.rb +33 -0
  166. data/spec/java/bdd_spec.rb +382 -0
  167. data/spec/java/cobertura_spec.rb +85 -0
  168. data/spec/java/compiler_spec.rb +446 -0
  169. data/spec/java/emma_spec.rb +119 -0
  170. data/spec/java/java_spec.rb +124 -0
  171. data/spec/java/packaging_spec.rb +1134 -0
  172. data/spec/java/test_coverage_helper.rb +257 -0
  173. data/spec/java/tests_spec.rb +493 -0
  174. data/spec/packaging/archive_spec.rb +527 -0
  175. data/spec/packaging/artifact_namespace_spec.rb +654 -0
  176. data/spec/packaging/artifact_spec.rb +795 -0
  177. data/spec/packaging/packaging_helper.rb +63 -0
  178. data/spec/packaging/packaging_spec.rb +684 -0
  179. data/spec/sandbox.rb +142 -0
  180. data/spec/scala/bdd_spec.rb +119 -0
  181. data/spec/scala/compiler_spec.rb +284 -0
  182. data/spec/scala/scala.rb +38 -0
  183. data/spec/scala/tests_spec.rb +261 -0
  184. data/spec/spec_helpers.rb +340 -0
  185. data/spec/version_requirement_spec.rb +129 -0
  186. metadata +383 -0
@@ -0,0 +1,452 @@
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
+
17
+ require 'buildr/core/project'
18
+ require 'buildr/core/common'
19
+ require 'buildr/core/checks'
20
+ require 'buildr/core/environment'
21
+
22
+
23
+ module Buildr
24
+
25
+ class Options
26
+
27
+ # Runs the build in parallel when true (defaults to false). You can force a parallel build by
28
+ # setting this option directly, or by running the parallel task ahead of the build task.
29
+ #
30
+ # This option only affects recursive tasks. For example:
31
+ # buildr parallel package
32
+ # will run all package tasks (from the sub-projects) in parallel, but each sub-project's package
33
+ # task runs its child tasks (prepare, compile, resources, etc) in sequence.
34
+ attr_accessor :parallel
35
+
36
+ end
37
+
38
+ task('parallel') { Buildr.options.parallel = true }
39
+
40
+
41
+ module Build
42
+
43
+ include Extension
44
+
45
+ first_time do
46
+ desc 'Build the project'
47
+ Project.local_task('build') { |name| "Building #{name}" }
48
+ desc 'Clean files generated during a build'
49
+ Project.local_task('clean') { |name| "Cleaning #{name}" }
50
+
51
+ desc 'The default task is build'
52
+ task 'default'=>'build'
53
+ end
54
+
55
+ before_define do |project|
56
+ project.recursive_task 'build'
57
+ project.recursive_task 'clean'
58
+ project.clean do
59
+ rm_rf project.path_to(:target)
60
+ rm_rf project.path_to(:reports)
61
+ end
62
+ end
63
+
64
+
65
+ # *Deprecated:* Use +path_to(:target)+ instead.
66
+ def target
67
+ Buildr.application.deprecated 'Use path_to(:target) instead'
68
+ layout.expand(:target)
69
+ end
70
+
71
+ # *Deprecated:* Use Layout instead.
72
+ def target=(dir)
73
+ Buildr.application.deprecated 'Use Layout instead'
74
+ layout[:target] = _(dir)
75
+ end
76
+
77
+ # *Deprecated:* Use +path_to(:reports)+ instead.
78
+ def reports()
79
+ Buildr.application.deprecated 'Use path_to(:reports) instead'
80
+ layout.expand(:reports)
81
+ end
82
+
83
+ # *Deprecated:* Use Layout instead.
84
+ def reports=(dir)
85
+ Buildr.application.deprecated 'Use Layout instead'
86
+ layout[:reports] = _(dir)
87
+ end
88
+
89
+ # :call-seq:
90
+ # build(*prereqs) => task
91
+ # build { |task| .. } => task
92
+ #
93
+ # Returns the project's build task. With arguments or block, also enhances that task.
94
+ def build(*prereqs, &block)
95
+ task('build').enhance prereqs, &block
96
+ end
97
+
98
+ # :call-seq:
99
+ # clean(*prereqs) => task
100
+ # clean { |task| .. } => task
101
+ #
102
+ # Returns the project's clean task. With arguments or block, also enhances that task.
103
+ def clean(*prereqs, &block)
104
+ task('clean').enhance prereqs, &block
105
+ end
106
+
107
+ end
108
+
109
+
110
+ module Git #:nodoc:
111
+ module_function
112
+
113
+ # :call-seq:
114
+ # git(*args)
115
+ #
116
+ # Executes a Git command and returns the output. Throws exception if the exit status
117
+ # is not zero. For example:
118
+ # git 'commit'
119
+ # git 'remote', 'show', 'origin'
120
+ def git(*args)
121
+ cmd = "git #{args.shift} #{args.map { |arg| arg.inspect }.join(' ')}"
122
+ output = `#{cmd}`
123
+ fail "GIT command \"#{cmd}\" failed with status #{$?.exitstatus}\n#{output}" unless $?.exitstatus == 0
124
+ return output
125
+ end
126
+
127
+ # Returns list of uncommited/untracked files as reported by git status.
128
+ def uncommitted_files
129
+ `git status`.scan(/^#(\t|\s{7})(\S.*)$/).map { |match| match.last.split.last }
130
+ end
131
+
132
+ # Commit the given file with a message.
133
+ # The file has to be known to Git meaning that it has either to have been already committed in the past
134
+ # or freshly added to the index. Otherwise it will fail.
135
+ def commit(file, message)
136
+ git 'commit', '-m', message, file
137
+ end
138
+
139
+ # Update the remote refs using local refs
140
+ #
141
+ # By default, the "remote" destination of the push is the the remote repo linked to the current branch.
142
+ # The default remote branch is the current local branch.
143
+ def push(remote_repo = remote, remote_branch = current_branch)
144
+ git 'push', remote, current_branch
145
+ end
146
+
147
+ # Return the name of the remote repository whose branch the current local branch tracks,
148
+ # or nil if none.
149
+ def remote(branch = current_branch)
150
+ remote = git('config', '--get', "branch.#{branch}.remote").to_s.strip
151
+ remote if !remote.empty? && git('remote').include?(remote)
152
+ end
153
+
154
+ # Return the name of the current branch
155
+ def current_branch
156
+ git('branch')[/^\* (.*)$/, 1]
157
+ end
158
+ end
159
+
160
+
161
+ module Svn #:nodoc:
162
+ module_function
163
+
164
+ # :call-seq:
165
+ # svn(*args)
166
+ #
167
+ # Executes a SVN command and returns the output. Throws exception if the exit status
168
+ # is not zero. For example:
169
+ # svn 'commit'
170
+ def svn(*args)
171
+ output = `svn #{args.shift} #{args.map { |arg| arg.inspect }.join(' ')}`
172
+ fail "SVN command failed with status #{$?.exitstatus}" unless $?.exitstatus == 0
173
+ return output
174
+ end
175
+
176
+ def tag(tag_name)
177
+ url = tag_url repo_url, tag_name
178
+ remove url, 'Removing old copy' rescue nil
179
+ copy Dir.pwd, url, "Release #{tag_name}"
180
+ end
181
+
182
+ # Status check reveals modified files, but also SVN externals which we can safely ignore.
183
+ def uncommitted_files
184
+ svn('status', '--ignore-externals').split("\n").reject { |line| line =~ /^X\s/ }
185
+ end
186
+
187
+ def commit(file, message)
188
+ svn 'commit', '-m', message, file
189
+ end
190
+
191
+ # :call-seq:
192
+ # tag_url(svn_url, version) => tag_url
193
+ #
194
+ # Returns the SVN url for the tag.
195
+ # Can tag from the trunk or from branches.
196
+ # Can handle the two standard repository layouts.
197
+ # - http://my.repo/foo/trunk => http://my.repo/foo/tags/1.0.0
198
+ # - http://my.repo/trunk/foo => http://my.repo/tags/foo/1.0.0
199
+ def tag_url(svn_url, tag)
200
+ trunk_or_branches = Regexp.union(%r{^(.*)/trunk(.*)$}, %r{^(.*)/branches(.*)/([^/]*)$})
201
+ match = trunk_or_branches.match(svn_url)
202
+ prefix = match[1] || match[3]
203
+ suffix = match[2] || match[4]
204
+ prefix + '/tags' + suffix + '/' + tag
205
+ end
206
+
207
+ # Return the current SVN URL
208
+ def repo_url
209
+ svn('info', '--xml')[/<url>(.*?)<\/url>/, 1].strip
210
+ end
211
+
212
+ def copy(dir, url, message)
213
+ svn 'copy', dir, url, '-m', message
214
+ end
215
+
216
+ def remove(url, message)
217
+ svn 'remove', url, '-m', message
218
+ end
219
+
220
+ end
221
+
222
+
223
+ class Release #:nodoc:
224
+
225
+ THIS_VERSION_PATTERN = /(THIS_VERSION|VERSION_NUMBER)\s*=\s*(["'])(.*)\2/
226
+
227
+ class << self
228
+
229
+ # :call-seq:
230
+ # add(MyReleaseClass)
231
+ #
232
+ # Add a Release implementation to the list of available Release classes.
233
+ def add(release)
234
+ @list ||= []
235
+ @list |= [release]
236
+ end
237
+ alias :<< :add
238
+
239
+ # The list of supported Release implementations
240
+ def list
241
+ @list ||= []
242
+ end
243
+
244
+ # Finds and returns the Release instance for this project.
245
+ def find
246
+ unless @release
247
+ klass = list.detect { |impl| impl.applies_to? }
248
+ @release = klass.new if klass
249
+ end
250
+ @release
251
+ end
252
+
253
+ end
254
+
255
+ # Use this to specify a different tag name for tagging the release in source control.
256
+ # You can set the tag name or a proc that will be called with the version number,
257
+ # for example:
258
+ # Release.tag_name = lambda { |ver| "foo-#{ver}" }
259
+ attr_accessor :tag_name
260
+
261
+ # Use this to specify a different commit message to commit the buildfile with the next version in source control.
262
+ # You can set the commit message or a proc that will be called with the next version number,
263
+ # for example:
264
+ # Release.commit_message = lambda { |ver| "Changed version number to #{ver}" }
265
+ attr_accessor :commit_message
266
+
267
+ # :call-seq:
268
+ # make()
269
+ #
270
+ # Make a release.
271
+ def make
272
+ check
273
+ with_release_candidate_version do |release_candidate_buildfile|
274
+ args = '-S', 'buildr', "_#{Buildr::VERSION}_", '--buildfile', release_candidate_buildfile
275
+ args << '--environment' << Buildr.environment unless Buildr.environment.to_s.empty?
276
+ args << 'clean' << 'upload' << 'DEBUG=no'
277
+ ruby *args
278
+ end
279
+ tag_release resolve_tag
280
+ update_version_to_next
281
+ end
282
+
283
+ # :call-seq:
284
+ # extract_version() => this_versin
285
+ #
286
+ # Extract the current version number from the buildfile.
287
+ # Raise an error if not found.
288
+ def extract_version
289
+ buildfile = File.read(Buildr.application.buildfile.to_s)
290
+ buildfile.scan(THIS_VERSION_PATTERN)[0][2]
291
+ rescue
292
+ fail 'Looking for THIS_VERSION = "..." in your Buildfile, none found'
293
+ end
294
+
295
+ protected
296
+
297
+ # :call-seq:
298
+ # with_release_candidate_version() { |filename| ... }
299
+ #
300
+ # Yields to block with release candidate buildfile, before committing to use it.
301
+ #
302
+ # We need a Buildfile with upgraded version numbers to run the build, but we don't want the
303
+ # Buildfile modified unless the build succeeds. So this method updates the version number in
304
+ # a separate (Buildfile.next) file, yields to the block with that filename, and if successful
305
+ # copies the new file over the existing one.
306
+ #
307
+ # The release version is the current version without '-SNAPSHOT'. So:
308
+ # THIS_VERSION = 1.1.0-SNAPSHOT
309
+ # becomes:
310
+ # THIS_VERSION = 1.1.0
311
+ # for the release buildfile.
312
+ def with_release_candidate_version
313
+ release_candidate_buildfile = Buildr.application.buildfile.to_s + '.next'
314
+ release_candidate_buildfile_contents = change_version { |version| version[-1] = version[-1].split('-')[0] }
315
+ File.open(release_candidate_buildfile, 'w') { |file| file.write release_candidate_buildfile_contents }
316
+ begin
317
+ yield release_candidate_buildfile
318
+ mv release_candidate_buildfile, Buildr.application.buildfile.to_s
319
+ ensure
320
+ rm release_candidate_buildfile rescue nil
321
+ end
322
+ end
323
+
324
+ # :call-seq:
325
+ # change_version() { |this_version| ... } => buildfile
326
+ #
327
+ # Change version number in the current Buildfile, but without writing a new file (yet).
328
+ # Returns the contents of the Buildfile with the modified version number.
329
+ #
330
+ # This method yields to the block with the current (this) version number as an array and expects
331
+ # the block to update it.
332
+ def change_version
333
+ this_version = extract_version
334
+ new_version = this_version.split('.')
335
+ yield(new_version)
336
+ new_version = new_version.join('.')
337
+ buildfile = File.read(Buildr.application.buildfile.to_s)
338
+ buildfile.gsub(THIS_VERSION_PATTERN) { |ver| ver.sub(/(["']).*\1/, %Q{"#{new_version}"}) }
339
+ end
340
+
341
+ # Return the name of the tag to tag the release with.
342
+ def resolve_tag
343
+ version = extract_version
344
+ tag = tag_name || version
345
+ tag = tag.call(version) if Proc === tag
346
+ tag
347
+ end
348
+
349
+ # Move the version to next and save the updated buildfile
350
+ def update_buildfile
351
+ buildfile = change_version { |version| version[-1] = sprintf("%0#{version[-1].size}d", version[-1].to_i + 1) + '-SNAPSHOT' }
352
+ File.open(Buildr.application.buildfile.to_s, 'w') { |file| file.write buildfile }
353
+ end
354
+
355
+ # Return the message to use to cimmit the buildfile with the next version
356
+ def message
357
+ version = extract_version
358
+ msg = commit_message || "Changed version number to #{version}"
359
+ msg = msg.call(version) if Proc === msg
360
+ msg
361
+ end
362
+
363
+ def update_version_to_next
364
+ update_buildfile
365
+ end
366
+ end
367
+
368
+
369
+ class GitRelease < Release
370
+ class << self
371
+ def applies_to?
372
+ if File.exist? '.git/config'
373
+ true
374
+ else
375
+ File.expand_path(Dir.pwd) != '/' && Dir.chdir('..') do
376
+ applies_to?
377
+ end
378
+ end
379
+ end
380
+ end
381
+
382
+ # Fails if one of theses 2 conditions are not met:
383
+ # 1. the repository is clean: no content staged or unstaged
384
+ # 2. some remote repositories are defined but the current branch does not track any
385
+ def check
386
+ uncommitted = Git.uncommitted_files
387
+ fail "Uncommitted files violate the First Principle Of Release!\n#{uncommitted.join("\n")}" unless uncommitted.empty?
388
+ fail "You are releasing from a local branch that does not track a remote!" unless Git.remote
389
+ end
390
+
391
+ # Add a tag reference in .git/refs/tags and push it to the remote if any.
392
+ # If a tag with the same name already exists it will get deleted (in both local and remote repositories).
393
+ def tag_release(tag)
394
+ info "Committing buildfile with version number #{extract_version}"
395
+ Git.commit File.basename(Buildr.application.buildfile.to_s), message
396
+ Git.push if Git.remote
397
+ info "Tagging release #{tag}"
398
+ Git.git 'tag', '-d', tag rescue nil
399
+ Git.git 'push', Git.remote, ":refs/tags/#{tag}" rescue nil if Git.remote
400
+ Git.git 'tag', '-a', tag, '-m', "[buildr] Cutting release #{tag}"
401
+ Git.git 'push', Git.remote, 'tag', tag if Git.remote
402
+ end
403
+
404
+ def update_version_to_next
405
+ super
406
+ info "Current version is now #{extract_version}"
407
+ Git.commit File.basename(Buildr.application.buildfile.to_s), message
408
+ Git.push if Git.remote
409
+ end
410
+ end
411
+
412
+
413
+ class SvnRelease < Release
414
+ class << self
415
+ def applies_to?
416
+ File.exist?('.svn')
417
+ end
418
+ end
419
+
420
+ def check
421
+ fail "Uncommitted files violate the First Principle Of Release!\n"+Svn.uncommitted_files.join("\n") unless Svn.uncommitted_files.empty?
422
+ fail "SVN URL must contain 'trunk' or 'branches/...'" unless Svn.repo_url =~ /(trunk)|(branches.*)$/
423
+ end
424
+
425
+ def tag_release(tag)
426
+ info "Tagging release #{tag}"
427
+ Svn.tag tag
428
+ end
429
+
430
+ def update_version_to_next
431
+ super
432
+ info "Current version is now #{extract_version}"
433
+ Svn.commit Buildr.application.buildfile.to_s, message
434
+ end
435
+ end
436
+
437
+ Release.add SvnRelease
438
+ Release.add GitRelease
439
+
440
+ desc 'Make a release'
441
+ task 'release' do |task|
442
+ release = Release.find
443
+ fail 'Unable to detect the Version Control System.' unless release
444
+ release.make
445
+ end
446
+
447
+ end
448
+
449
+
450
+ class Buildr::Project
451
+ include Buildr::Build
452
+ end
@@ -0,0 +1,254 @@
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
+
17
+ require 'buildr/core/project'
18
+ autoload :Spec, 'spec'
19
+
20
+
21
+ module Buildr
22
+ # Methods added to Project to allow checking the build.
23
+ module Checks
24
+
25
+ module Matchers #:nodoc:
26
+
27
+ class << self
28
+
29
+ # Define matchers that operate by calling a method on the tested object.
30
+ # For example:
31
+ # foo.should contain(bar)
32
+ # calls:
33
+ # foo.contain(bar)
34
+ def match_using(*names)
35
+ names.each do |name|
36
+ matcher = Class.new do
37
+ # Initialize with expected arguments (i.e. contain(bar) initializes with bar).
38
+ define_method(:initialize) { |*args| @expects = args }
39
+ # Matches against actual value (i.e. foo.should exist called with foo).
40
+ define_method(:matches?) do |actual|
41
+ @actual = actual
42
+ return actual.send("#{name}?", *@expects) if actual.respond_to?("#{name}?")
43
+ return actual.send(name, *@expects) if actual.respond_to?(name)
44
+ raise "You can't check #{actual}, it doesn't respond to #{name}."
45
+ end
46
+ # Some matchers have arguments, others don't, treat appropriately.
47
+ define_method :failure_message do
48
+ args = " " + @expects.map{ |arg| "'#{arg}'" }.join(", ") unless @expects.empty?
49
+ "Expected #{@actual} to #{name}#{args}"
50
+ end
51
+ define_method :negative_failure_message do
52
+ args = " " + @expects.map{ |arg| "'#{arg}'" }.join(", ") unless @expects.empty?
53
+ "Expected #{@actual} to not #{name}#{args}"
54
+ end
55
+ end
56
+ # Define method to create matcher.
57
+ define_method(name) { |*args| matcher.new(*args) }
58
+ end
59
+ end
60
+
61
+ end
62
+
63
+ # Define delegate matchers for exist and contain methods.
64
+ match_using :exist, :contain
65
+
66
+ end
67
+
68
+
69
+ # An expectation has subject, description and block. The expectation is validated by running the block,
70
+ # and can access the subject from the method #it. The description is used for reporting.
71
+ #
72
+ # The expectation is run by calling #run_against. You can share expectations by running them against
73
+ # different projects (or any other context for that matter).
74
+ #
75
+ # If the subject is missing, it is set to the argument of #run_against, typically the project itself.
76
+ # If the description is missing, it is set from the project. If the block is missing, the default behavior
77
+ # prints "Pending" followed by the description. You can use this to write place holders and fill them later.
78
+ class Expectation
79
+
80
+ attr_reader :description, :subject, :block
81
+
82
+ # :call-seq:
83
+ # initialize(subject, description?) { .... }
84
+ # initialize(description?) { .... }
85
+ #
86
+ # First argument is subject (returned from it method), second argument is description. If you omit the
87
+ # description, it will be set from the subject. If you omit the subject, it will be set from the object
88
+ # passed to run_against.
89
+ def initialize(*args, &block)
90
+ @description = args.pop if String === args.last
91
+ @subject = args.shift
92
+ raise ArgumentError, "Expecting subject followed by description, and either one is optional. Not quite sure what to do with this list of arguments." unless args.empty?
93
+ @block = block || lambda { info "Pending: #{description}" }
94
+ end
95
+
96
+ # :call-seq:
97
+ # run_against(context)
98
+ #
99
+ # Runs this expectation against the context object. The context object is different from the subject,
100
+ # but used as the subject if no subject specified (i.e. returned from the it method).
101
+ #
102
+ # This method creates a new context object modeled after the context argument, but a separate object
103
+ # used strictly for running this expectation, and used only once. The context object will pass methods
104
+ # to the context argument, so you can call any method, e.g. package(:jar).
105
+ #
106
+ # It also adds all matchers defined in Buildr and RSpec, and two additional methods:
107
+ # * it() -- Returns the subject.
108
+ # * description() -- Returns the description.
109
+ def run_against(context)
110
+ subject = @subject || context
111
+ description = @description ? "#{subject} #{@description}" : subject.to_s
112
+ # Define anonymous class and load it with:
113
+ # - All instance methods defined in context, so we can pass method calls to the context.
114
+ # - it() method to return subject, description() method to return description.
115
+ # - All matchers defined by Buildr and RSpec.
116
+ klass = Class.new
117
+ klass.instance_eval do
118
+ context.class.instance_methods.each do |method|
119
+ define_method(method) { |*args| context.send(method, *args) } unless instance_methods.include?(method)
120
+ end
121
+ define_method(:it) { subject }
122
+ define_method(:description) { description }
123
+ include Spec::Matchers
124
+ include Matchers
125
+ end
126
+
127
+ # Run the expectation. We only print the expectation name when tracing (to know they all ran),
128
+ # or when we get a failure.
129
+ begin
130
+ trace description
131
+ klass.new.instance_eval &@block
132
+ rescue Exception=>error
133
+ raise error.exception("#{description}\n#{error}").tap { |wrapped| wrapped.set_backtrace(error.backtrace) }
134
+ end
135
+ end
136
+
137
+ end
138
+
139
+
140
+ include Extension
141
+
142
+ before_define do |project|
143
+ # The check task can do any sort of interesting things, but the most important is running expectations.
144
+ project.task("check") do |task|
145
+ project.expectations.inject(true) do |passed, expect|
146
+ begin
147
+ expect.run_against project
148
+ passed
149
+ rescue Exception=>ex
150
+ if verbose
151
+ error ex.backtrace.select { |line| line =~ /#{Buildr.application.buildfile}/ }.join("\n")
152
+ error ex
153
+ end
154
+ false
155
+ end
156
+ end or fail "Checks failed for project #{project.name} (see errors above)."
157
+ end
158
+ project.task("package").enhance do |task|
159
+ # Run all actions before checks.
160
+ task.enhance { project.task("check").invoke }
161
+ end
162
+ end
163
+
164
+
165
+ # :call-seq:
166
+ # check(description) { ... }
167
+ # check(subject, description) { ... }
168
+ #
169
+ # Adds an expectation. The expectation is run against the project by the check task, executed after packaging.
170
+ # You can access any package created by the project.
171
+ #
172
+ # An expectation is written using a subject, description and block to validate the expectation. For example:
173
+ #
174
+ # For example:
175
+ # check package(:jar), "should exist" do
176
+ # it.should exist
177
+ # end
178
+ # check package(:jar), "should contain a manifest" do
179
+ # it.should contain("META-INF/MANIFEST.MF")
180
+ # end
181
+ # check package(:jar).path("com/acme"), "should contain classes" do
182
+ # it.should_not be_empty
183
+ # end
184
+ # check package(:jar).entry("META-INF/MANIFEST"), "should be a recent license" do
185
+ # it.should contain(/Copyright (C) 2007/)
186
+ # end
187
+ #
188
+ # If you omit the subject, the project is used as the subject. If you omit the description, the subject is
189
+ # used as description.
190
+ #
191
+ # During development you can write placeholder expectations by omitting the block. This will simply report
192
+ # the expectation as pending.
193
+ def check(*args, &block)
194
+ expectations << Checks::Expectation.new(*args, &block)
195
+ end
196
+
197
+ # :call-seq:
198
+ # expectations() => Expectation*
199
+ #
200
+ # Returns a list of expectations (see #check).
201
+ def expectations()
202
+ @expectations ||= []
203
+ end
204
+
205
+ end
206
+
207
+ end
208
+
209
+
210
+ module Rake #:nodoc:
211
+ class FileTask
212
+
213
+ # :call-seq:
214
+ # exist?() => boolean
215
+ #
216
+ # Returns true if this file exists.
217
+ def exist?()
218
+ File.exist?(name)
219
+ end
220
+
221
+ # :call-seq:
222
+ # empty?() => boolean
223
+ #
224
+ # Returns true if file/directory is empty.
225
+ def empty?()
226
+ File.directory?(name) ? Dir.glob("#{name}/*").empty? : File.read(name).empty?
227
+ end
228
+
229
+ # :call-seq:
230
+ # contain?(pattern*) => boolean
231
+ # contain?(file*) => boolean
232
+ #
233
+ # For a file, returns true if the file content matches against all the arguments. An argument may be
234
+ # a string or regular expression.
235
+ #
236
+ # For a directory, return true if the directory contains the specified files. You can use relative
237
+ # file names and glob patterns (using *, **, etc).
238
+ def contain?(*patterns)
239
+ if File.directory?(name)
240
+ patterns.map { |pattern| "#{name}/#{pattern}" }.all? { |pattern| !Dir[pattern].empty? }
241
+ else
242
+ contents = File.read(name)
243
+ patterns.map { |pattern| Regexp === pattern ? pattern : Regexp.new(Regexp.escape(pattern.to_s)) }.
244
+ all? { |pattern| contents =~ pattern }
245
+ end
246
+ end
247
+
248
+ end
249
+ end
250
+
251
+
252
+ class Buildr::Project
253
+ include Buildr::Checks
254
+ end