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.
Files changed (85) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +5 -0
  3. data/LICENSE +176 -0
  4. data/NOTICE +26 -0
  5. data/README.md +3 -0
  6. data/Rakefile +50 -0
  7. data/addon/buildr/checkstyle-report.xsl +104 -0
  8. data/addon/buildr/checkstyle.rb +254 -0
  9. data/addon/buildr/git_auto_version.rb +36 -0
  10. data/addon/buildr/gpg.rb +90 -0
  11. data/addon/buildr/gwt.rb +413 -0
  12. data/addon/buildr/jacoco.rb +161 -0
  13. data/addon/buildr/pmd.rb +185 -0
  14. data/addon/buildr/single_intermediate_layout.rb +71 -0
  15. data/addon/buildr/spotbugs.rb +265 -0
  16. data/addon/buildr/top_level_generate_dir.rb +37 -0
  17. data/addon/buildr/wsgen.rb +192 -0
  18. data/bin/buildr +20 -0
  19. data/buildr.gemspec +61 -0
  20. data/lib/buildr.rb +86 -0
  21. data/lib/buildr/core/application.rb +705 -0
  22. data/lib/buildr/core/assets.rb +96 -0
  23. data/lib/buildr/core/build.rb +587 -0
  24. data/lib/buildr/core/common.rb +167 -0
  25. data/lib/buildr/core/compile.rb +599 -0
  26. data/lib/buildr/core/console.rb +124 -0
  27. data/lib/buildr/core/doc.rb +275 -0
  28. data/lib/buildr/core/environment.rb +128 -0
  29. data/lib/buildr/core/filter.rb +405 -0
  30. data/lib/buildr/core/help.rb +114 -0
  31. data/lib/buildr/core/progressbar.rb +161 -0
  32. data/lib/buildr/core/project.rb +994 -0
  33. data/lib/buildr/core/test.rb +776 -0
  34. data/lib/buildr/core/transports.rb +456 -0
  35. data/lib/buildr/core/util.rb +77 -0
  36. data/lib/buildr/ide/idea.rb +1664 -0
  37. data/lib/buildr/java/commands.rb +230 -0
  38. data/lib/buildr/java/compiler.rb +85 -0
  39. data/lib/buildr/java/custom_pom.rb +300 -0
  40. data/lib/buildr/java/doc.rb +62 -0
  41. data/lib/buildr/java/packaging.rb +393 -0
  42. data/lib/buildr/java/pom.rb +191 -0
  43. data/lib/buildr/java/test_result.rb +54 -0
  44. data/lib/buildr/java/tests.rb +111 -0
  45. data/lib/buildr/packaging/archive.rb +586 -0
  46. data/lib/buildr/packaging/artifact.rb +1113 -0
  47. data/lib/buildr/packaging/artifact_namespace.rb +1010 -0
  48. data/lib/buildr/packaging/artifact_search.rb +138 -0
  49. data/lib/buildr/packaging/package.rb +237 -0
  50. data/lib/buildr/packaging/version_requirement.rb +189 -0
  51. data/lib/buildr/packaging/zip.rb +189 -0
  52. data/lib/buildr/packaging/ziptask.rb +387 -0
  53. data/lib/buildr/version.rb +18 -0
  54. data/rakelib/release.rake +99 -0
  55. data/spec/addon/checkstyle_spec.rb +58 -0
  56. data/spec/core/application_spec.rb +576 -0
  57. data/spec/core/build_spec.rb +922 -0
  58. data/spec/core/common_spec.rb +670 -0
  59. data/spec/core/compile_spec.rb +656 -0
  60. data/spec/core/console_spec.rb +65 -0
  61. data/spec/core/doc_spec.rb +194 -0
  62. data/spec/core/extension_spec.rb +200 -0
  63. data/spec/core/project_spec.rb +736 -0
  64. data/spec/core/test_spec.rb +1131 -0
  65. data/spec/core/transport_spec.rb +452 -0
  66. data/spec/core/util_spec.rb +154 -0
  67. data/spec/ide/idea_spec.rb +1952 -0
  68. data/spec/java/commands_spec.rb +79 -0
  69. data/spec/java/compiler_spec.rb +274 -0
  70. data/spec/java/custom_pom_spec.rb +165 -0
  71. data/spec/java/doc_spec.rb +55 -0
  72. data/spec/java/packaging_spec.rb +786 -0
  73. data/spec/java/pom_spec.rb +162 -0
  74. data/spec/java/test_coverage_helper.rb +257 -0
  75. data/spec/java/tests_spec.rb +224 -0
  76. data/spec/packaging/archive_spec.rb +686 -0
  77. data/spec/packaging/artifact_namespace_spec.rb +757 -0
  78. data/spec/packaging/artifact_spec.rb +1351 -0
  79. data/spec/packaging/packaging_helper.rb +63 -0
  80. data/spec/packaging/packaging_spec.rb +690 -0
  81. data/spec/sandbox.rb +166 -0
  82. data/spec/spec_helpers.rb +420 -0
  83. data/spec/version_requirement_spec.rb +145 -0
  84. data/spec/xpath_matchers.rb +123 -0
  85. metadata +295 -0
@@ -0,0 +1,776 @@
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
+ # The underlying test framework used by TestTask.
19
+ # To add a new test framework, extend TestFramework::Base and add your framework using:
20
+ # Buildr::TestFramework << MyFramework
21
+ module TestFramework
22
+
23
+ class << self
24
+
25
+ # Returns true if the specified test framework exists.
26
+ def has?(name)
27
+ frameworks.any? { |framework| framework.to_sym == name.to_sym }
28
+ end
29
+
30
+ # Select a test framework by its name.
31
+ def select(name)
32
+ frameworks.detect { |framework| framework.to_sym == name.to_sym }
33
+ end
34
+
35
+ # Identify which test framework applies for this project.
36
+ def select_from(project)
37
+ # Look for a suitable test framework based on the compiled language,
38
+ # which may return multiple candidates, e.g. JUnit and TestNG for Java.
39
+ # Pick the one used in the parent project, if not, whichever comes first.
40
+ candidates = frameworks.select { |framework| framework.applies_to?(project) }
41
+ parent = project.parent
42
+ parent && candidates.detect { |framework| framework.to_sym == parent.test.framework } || candidates.first
43
+ end
44
+
45
+ # Adds a test framework to the list of supported frameworks.
46
+ #
47
+ # For example:
48
+ # Buildr::TestFramework << Buildr::JUnit
49
+ def add(framework)
50
+ @frameworks ||= []
51
+ @frameworks |= [framework]
52
+ end
53
+ alias :<< :add
54
+
55
+ # Returns a list of available test frameworks.
56
+ def frameworks
57
+ @frameworks ||= []
58
+ end
59
+
60
+ end
61
+
62
+ # Base class for all test frameworks, with common functionality. Extend and over-ride as you see fit.
63
+ class Base
64
+
65
+ class << self
66
+
67
+ # The framework's identifier (e.g. :testng). Inferred from the class name.
68
+ def to_sym
69
+ @symbol ||= name.split('::').last.downcase.to_sym
70
+ end
71
+
72
+ # Returns true if this framework applies to the current project. For example, JUnit returns
73
+ # true if the tests are written in Java.
74
+ def applies_to?(project)
75
+ raise 'Not implemented'
76
+ end
77
+
78
+ # Returns a list of dependencies for this framework. Default is an empty list,
79
+ # override to add dependencies.
80
+ def dependencies
81
+ @dependencies ||= []
82
+ end
83
+ end
84
+
85
+ # Construct a new test framework with the specified options. Note that options may
86
+ # change before the framework is run.
87
+ def initialize(test_task, options)
88
+ @options = options
89
+ @task = test_task
90
+ end
91
+
92
+ # Options for this test framework.
93
+ attr_reader :options
94
+ # The test task we belong to
95
+ attr_reader :task
96
+
97
+ # Returns a list of dependenices for this framework. Defaults to calling the #dependencies
98
+ # method on the class.
99
+ def dependencies
100
+ self.class.dependencies
101
+ end
102
+
103
+ # TestTask calls this method to return a list of test names that can be run in this project.
104
+ # It then applies the include/exclude patterns to arrive at the list of tests that will be
105
+ # run, and call the #run method with that list.
106
+ #
107
+ # This method should return a list suitable for using with the #run method, but also suitable
108
+ # for the user to manage. For example, JUnit locates all the tests in the test.compile.target
109
+ # directory, and returns the class names, which are easier to work with than file names.
110
+ def tests(dependencies)
111
+ raise 'Not implemented'
112
+ end
113
+
114
+ # TestTask calls this method to run the named (and only those) tests. This method returns
115
+ # the list of tests that ran successfully.
116
+ def run(tests, dependencies)
117
+ raise 'Not implemented'
118
+ end
119
+ end
120
+ end
121
+
122
+
123
+ # The test task controls the entire test lifecycle.
124
+ #
125
+ # You can use the test task in three ways. You can access and configure specific test tasks,
126
+ # e.g. enhance the #compile task, or run code during #setup/#teardown.
127
+ #
128
+ # You can use convenient methods that handle the most common settings. For example,
129
+ # add dependencies using #with, or include only specific tests using #include.
130
+ #
131
+ # You can also enhance this task directly. This task will first execute the #compile task, followed
132
+ # by the #setup task, run the unit tests, any other enhancements, and end by executing #teardown.
133
+ #
134
+ # The test framework is determined based on the available test files, for example, if the test
135
+ # cases are written in Java, then JUnit is selected as the test framework. You can also select
136
+ # a specific test framework, for example, to use TestNG instead of JUnit:
137
+ # test.using :testng
138
+ class TestTask < ::Rake::Task
139
+
140
+ class << self
141
+
142
+ # Used by the local test and integration tasks to
143
+ # a) Find the local project(s),
144
+ # b) Find all its sub-projects and narrow down to those that have either unit or integration tests,
145
+ # c) Run all the (either unit or integration) tests, and
146
+ # d) Ignore failure if necessary.
147
+ def run_local_tests(integration) #:nodoc:
148
+ Project.local_projects do |project|
149
+ # !(foo ^ bar) tests for equality and accepts nil as false (and select is less obfuscated than reject on ^).
150
+ projects = ([project] + project.projects).select { |project| !(project.test.options[:integration] ^ integration) }
151
+ projects.each do |project|
152
+ info "Testing #{project.name}"
153
+ # Invoke the prerequisites outside of the rescue block, otherwise errors converging
154
+ # the prerequisites are swallowed (and treated like failed test results). Moving the
155
+ # code outside means problems such as test code that does not compile will result in a
156
+ # build failure even if Buildr.options.test is set to :all
157
+ project.test.prerequisites.each{|p|p.is_a?(String) ? file(p).invoke : p.invoke}
158
+ begin
159
+ project.test.invoke
160
+ rescue
161
+ raise unless Buildr.options.test == :all
162
+ end
163
+ end
164
+ end
165
+ end
166
+
167
+ # Used by the test/integration rule to only run tests that match the specified names.
168
+ def only_run(tests) #:nodoc:
169
+ tests = wildcardify(tests)
170
+ # Since the tests may reside in a sub-project, we need to set the include/exclude pattern on
171
+ # all sub-projects, but only invoke test on the local project.
172
+ Project.projects.each { |project| project.test.send :only_run, tests }
173
+ end
174
+
175
+ # Used by the test/integration rule to only run tests that failed the last time.
176
+ def only_run_failed() #:nodoc:
177
+ # Since the tests may reside in a sub-project, we need to set the include/exclude pattern on
178
+ # all sub-projects, but only invoke test on the local project.
179
+ Project.projects.each { |project| project.test.send :only_run_failed }
180
+ end
181
+
182
+ # Used by the test/integration rule to clear all previously included/excluded tests.
183
+ def clear()
184
+ Project.projects.each do |project|
185
+ project.test.send :clear
186
+ end
187
+ end
188
+
189
+ # Used by the test/integration to include specific tests
190
+ def include(includes)
191
+ includes = wildcardify(Array(includes))
192
+ Project.projects.each do |project|
193
+ project.test.send :include, *includes if includes.size > 0
194
+ project.test.send :forced_need=, true
195
+ end
196
+ end
197
+
198
+ # Used by the test/integration to exclude specific tests
199
+ def exclude(excludes)
200
+ excludes = wildcardify(Array(excludes))
201
+ Project.projects.each do |project|
202
+ project.test.send :exclude, *excludes if excludes.size > 0
203
+ project.test.send :forced_need=, true
204
+ end
205
+ end
206
+
207
+ private
208
+
209
+ def wildcardify(strings)
210
+ strings.map { |name| name =~ /\*/ ? name : "*#{name}*" }
211
+ end
212
+ end
213
+
214
+ # Default options already set on each test task.
215
+ def default_options
216
+ { :fail_on_failure=>true, :fork=>:once, :properties=>{}, :environment=>{} }
217
+ end
218
+
219
+ def initialize(*args) #:nodoc:
220
+ super
221
+ @dependencies = FileList[]
222
+ @include = []
223
+ @exclude = []
224
+ @forced_need = false
225
+ parent_task = Project.parent_task(name)
226
+ if parent_task.respond_to?(:options)
227
+ @options = OpenObject.new { |hash, key| hash[key] = parent_task.options[key].clone rescue hash[key] = parent_task.options[key] }
228
+ else
229
+ @options = OpenObject.new(default_options)
230
+ end
231
+
232
+ unless ENV["IGNORE_BUILDFILE"] =~ /(true)|(yes)/i
233
+ enhance [ application.buildfile.name ]
234
+ enhance application.buildfile.prerequisites
235
+ end
236
+ enhance do
237
+ run_tests if framework
238
+ end
239
+ end
240
+
241
+ # The dependencies used for running the tests. Includes the compiled files (compile.target)
242
+ # and their dependencies. Will also include anything you pass to #with, shared between the
243
+ # testing compile and run dependencies.
244
+ attr_accessor :dependencies
245
+
246
+ # *Deprecated*: Use dependencies instead.
247
+ def classpath
248
+ Buildr.application.deprecated 'Use dependencies instead.'
249
+ @dependencies
250
+ end
251
+
252
+ # *Deprecated*: Use dependencies= instead.
253
+ def classpath=(artifacts)
254
+ Buildr.application.deprecated 'Use dependencies= instead.'
255
+ @dependencies = artifacts
256
+ end
257
+
258
+ def execute(args) #:nodoc:
259
+ if Buildr.options.test == false
260
+ trace "Skipping tests for #{project.name}"
261
+ return
262
+ end
263
+ setup.invoke
264
+ begin
265
+ super
266
+ rescue RuntimeError
267
+ raise if options[:fail_on_failure] && Buildr.options.test != :all
268
+ ensure
269
+ teardown.invoke
270
+ end
271
+ end
272
+
273
+ # :call-seq:
274
+ # compile(*sources) => CompileTask
275
+ # compile(*sources) { |task| .. } => CompileTask
276
+ #
277
+ # The compile task is similar to the Project's compile task. However, it compiles all
278
+ # files found in the src/test/{source} directory into the target/test/{code} directory.
279
+ # This task is executed by the test task before running any tests.
280
+ #
281
+ # Once the project definition is complete, all dependencies from the regular
282
+ # compile task are copied over, so you only need to specify dependencies
283
+ # specific to your tests. You can do so by calling #with on the test task.
284
+ # The dependencies used here are also copied over to the junit task.
285
+ def compile(*sources, &block)
286
+ @project.task('test:compile').from(sources).enhance &block
287
+ end
288
+
289
+ # :call-seq:
290
+ # resources(*prereqs) => ResourcesTask
291
+ # resources(*prereqs) { |task| .. } => ResourcesTask
292
+ #
293
+ # Executes by the #compile task to copy resource files over. See Project#resources.
294
+ def resources(*prereqs, &block)
295
+ @project.task('test:resources').enhance prereqs, &block
296
+ end
297
+
298
+ # :call-seq:
299
+ # setup(*prereqs) => task
300
+ # setup(*prereqs) { |task| .. } => task
301
+ #
302
+ # Returns the setup task. The setup task is executed at the beginning of the test task,
303
+ # after compiling the test files.
304
+ def setup(*prereqs, &block)
305
+ @project.task('test:setup').enhance prereqs, &block
306
+ end
307
+
308
+ # :call-seq:
309
+ # teardown(*prereqs) => task
310
+ # teardown(*prereqs) { |task| .. } => task
311
+ #
312
+ # Returns the teardown task. The teardown task is executed at the end of the test task.
313
+ def teardown(*prereqs, &block)
314
+ @project.task('test:teardown').enhance prereqs, &block
315
+ end
316
+
317
+ # :call-seq:
318
+ # with(*specs) => self
319
+ #
320
+ # Specify artifacts (specs, tasks, files, etc) to include in the dependencies list
321
+ # when compiling and running tests.
322
+ def with(*artifacts)
323
+ @dependencies |= Buildr.artifacts(artifacts.flatten).uniq
324
+ compile.with artifacts
325
+ self
326
+ end
327
+
328
+ # Returns various test options.
329
+ attr_reader :options
330
+
331
+ # :call-seq:
332
+ # using(options) => self
333
+ #
334
+ # Sets various test options from a hash and returns self. For example:
335
+ # test.using :fork=>:each, :properties=>{ 'url'=>'http://localhost:8080' }
336
+ #
337
+ # Can also be used to select the test framework, or to run these tests as
338
+ # integration tests. For example:
339
+ # test.using :testng
340
+ # test.using :integration
341
+ #
342
+ # The :fail_on_failure option specifies whether the task should fail if
343
+ # any of the tests fail (default), or should report the failures but continue
344
+ # running the build (when set to false).
345
+ #
346
+ # All other options depend on the capability of the test framework. These options
347
+ # should be used the same way across all frameworks that support them:
348
+ # * :fork -- Fork once for each project (:once, default), for each test in each
349
+ # project (:each), or don't fork at all (false).
350
+ # * :properties -- Properties pass to the test, e.g. in Java as system properties.
351
+ # * :environment -- Environment variables. This hash is made available in the
352
+ # form of environment variables.
353
+ def using(*args)
354
+ args.pop.each { |key, value| options[key.to_sym] = value } if Hash === args.last
355
+ args.each do |name|
356
+ if TestFramework.has?(name)
357
+ self.framework = name
358
+ elsif name == :integration
359
+ options[:integration] = true
360
+ end
361
+ end
362
+ self
363
+ end
364
+
365
+ # :call-seq:
366
+ # include(*names) => self
367
+ #
368
+ # Include only the specified tests. Unless specified, the default is to include
369
+ # all tests identified by the test framework. This method accepts multiple arguments
370
+ # and returns self.
371
+ #
372
+ # Tests are specified by their full name, but you can use glob patterns to select
373
+ # multiple tests, for example:
374
+ # test.include 'com.example.FirstTest' # FirstTest only
375
+ # test.include 'com.example.*' # All tests under com/example
376
+ # test.include 'com.example.Module*' # All tests starting with Module
377
+ # test.include '*.{First,Second}Test' # FirstTest, SecondTest
378
+ def include(*names)
379
+ @include += names
380
+ self
381
+ end
382
+
383
+ # :call-seq:
384
+ # exclude(*names) => self
385
+ #
386
+ # Exclude the specified tests. This method accepts multiple arguments and returns self.
387
+ # See #include for the type of arguments you can use.
388
+ def exclude(*names)
389
+ @exclude += names
390
+ self
391
+ end
392
+
393
+ # Clear all test includes and excludes and returns self
394
+ def clear
395
+ @include = []
396
+ @exclude = []
397
+ self
398
+ end
399
+
400
+ # *Deprecated*: Use tests instead.
401
+ def classes
402
+ Buildr.application.deprecated 'Call tests instead of classes'
403
+ tests
404
+ end
405
+
406
+ # After running the task, returns all tests selected to run, based on availability and include/exclude pattern.
407
+ attr_reader :tests
408
+ # After running the task, returns all the tests that failed, empty array if all tests passed.
409
+ attr_reader :failed_tests
410
+ # After running the task, returns all the tests that passed, empty array if no tests passed.
411
+ attr_reader :passed_tests
412
+
413
+ # :call-seq:
414
+ # framework => symbol
415
+ #
416
+ # Returns the test framework, e.g. :junit, :testng.
417
+ def framework
418
+ unless @framework
419
+ # Start with all frameworks that apply (e.g. JUnit and TestNG for Java),
420
+ # and pick the first (default) one, unless already specified in parent project.
421
+ candidates = TestFramework.frameworks.select { |cls| cls.applies_to?(@project) }
422
+ candidate = @project.parent && candidates.detect { |framework| framework.to_sym == @project.parent.test.framework } ||
423
+ candidates.first
424
+ self.framework = candidate if candidate
425
+ end
426
+ @framework && @framework.class.to_sym
427
+ end
428
+
429
+ # :call-seq:
430
+ # report_to => file
431
+ #
432
+ # Test frameworks that can produce reports, will write them to this directory.
433
+ #
434
+ # This is framework dependent, so unless you use the default test framework, call this method
435
+ # after setting the test framework.
436
+ def report_to
437
+ @report_to ||= file(@project.path_to(:reports, framework)=>self)
438
+ end
439
+
440
+ # :call-seq:
441
+ # failures_to => file
442
+ #
443
+ # We record the list of failed tests for the current framework in this file.
444
+ #
445
+ #
446
+ def failures_to
447
+ @failures_to ||= file(@project.path_to(:target, "#{framework}-failed")=>self)
448
+ end
449
+
450
+ # :call-seq:
451
+ # last_failures => array
452
+ #
453
+ # We read the last test failures if any and return them.
454
+ #
455
+ def last_failures
456
+ @last_failures ||= failures_to.exist? ? File.read(failures_to.to_s).split("\n") : []
457
+ end
458
+
459
+ # The path to the file that stores the time stamp of the last successful test run.
460
+ def last_successful_run_file #:nodoc:
461
+ File.join(report_to.to_s, 'last_successful_run')
462
+ end
463
+
464
+ # The time stamp of the last successful test run. Or Rake::EARLY if no successful test run recorded.
465
+ def timestamp #:nodoc:
466
+ File.exist?(last_successful_run_file) ? File.mtime(last_successful_run_file) : Rake::EARLY
467
+ end
468
+
469
+ # The project this task belongs to.
470
+ attr_reader :project
471
+
472
+ # Whether the tests are forced
473
+ attr_accessor :forced_need
474
+
475
+ protected
476
+
477
+ def associate_with(project)
478
+ @project = project
479
+ end
480
+
481
+ def framework=(name)
482
+ cls = TestFramework.select(name) or raise ArgumentError, "No #{name} test framework available. Did you install it?"
483
+ @framework = cls.new(self, options)
484
+ # Test framework dependency.
485
+ with @framework.dependencies
486
+ end
487
+
488
+ # :call-seq:
489
+ # include?(name) => boolean
490
+ #
491
+ # Returns true if the specified test name matches the inclusion/exclusion pattern. Used to determine
492
+ # which tests to execute.
493
+ def include?(name)
494
+ ((@include.empty? && !@forced_need)|| @include.any? { |pattern| File.fnmatch(pattern, name) }) &&
495
+ !@exclude.any? { |pattern| File.fnmatch(pattern, name) }
496
+ end
497
+
498
+ # Runs the tests using the selected test framework.
499
+ def run_tests
500
+ dependencies = (Buildr.artifacts(self.dependencies + compile.dependencies) + [compile.target]).map(&:to_s).uniq
501
+ rm_rf report_to.to_s
502
+ rm_rf failures_to.to_s
503
+ @tests = @framework.tests(dependencies).select { |test| include?(test) }.sort
504
+ if @tests.empty?
505
+ @passed_tests, @failed_tests = [], []
506
+ else
507
+ info "Running tests in #{@project.name}"
508
+ begin
509
+ # set the baseDir system property if not set
510
+ @framework.options[:properties] = { 'baseDir' => compile.target.to_s }.merge(@framework.options[:properties] || {})
511
+ @passed_tests = @framework.run(@tests, dependencies)
512
+ rescue Exception=>ex
513
+ error "Test framework error: #{ex.message}"
514
+ error ex.backtrace.join("\n") if trace?
515
+ @passed_tests = []
516
+ end
517
+ @failed_tests = @tests - @passed_tests
518
+ unless @failed_tests.empty?
519
+ Buildr::write(failures_to.to_s, @failed_tests.join("\n"))
520
+ error "The following tests failed:\n#{@failed_tests.join("\n")}"
521
+ fail 'Tests failed!'
522
+ end
523
+ end
524
+ record_successful_run unless @forced_need
525
+ end
526
+
527
+ # Call this method when a test run is successful to record the current system time.
528
+ def record_successful_run #:nodoc:
529
+ mkdir_p report_to.to_s
530
+ touch last_successful_run_file
531
+ end
532
+
533
+ # Limit running tests to specific list.
534
+ def only_run(tests)
535
+ @include = Array(tests)
536
+ @exclude.clear
537
+ @forced_need = true
538
+ end
539
+
540
+ # Limit running tests to those who failed the last time.
541
+ def only_run_failed()
542
+ @include = Array(last_failures)
543
+ @forced_need = true
544
+ end
545
+
546
+ def invoke_prerequisites(args, chain) #:nodoc:
547
+ @prerequisites |= FileList[@dependencies.uniq]
548
+ super
549
+ end
550
+
551
+ def needed? #:nodoc:
552
+ latest_prerequisite = @prerequisites.map { |p| application[p, @scope] }.max { |a,b| a.timestamp<=>b.timestamp }
553
+ needed = (timestamp == Rake::EARLY) || latest_prerequisite.timestamp > timestamp
554
+ trace "Testing#{needed ? ' ' : ' not '}needed. " +
555
+ "Latest prerequisite change: #{latest_prerequisite.timestamp} (#{latest_prerequisite.to_s}). " +
556
+ "Last successful test run: #{timestamp}."
557
+ return needed || @forced_need || Buildr.options.test == :all
558
+ end
559
+ end
560
+
561
+ # Methods added to Project to support compilation and running of tests.
562
+ module Test
563
+
564
+ include Extension
565
+
566
+ first_time do
567
+ desc 'Run all tests'
568
+ task('test') { TestTask.run_local_tests false }
569
+
570
+ desc 'Run failed tests'
571
+ task('test:failed') {
572
+ TestTask.only_run_failed
573
+ task('test').invoke
574
+ }
575
+
576
+ # This rule takes a suffix and runs that tests in the current project. For example;
577
+ # buildr test:MyTest
578
+ # will run the test com.example.MyTest, if such a test exists for this project.
579
+ #
580
+ # If you want to run multiple test, separate them with a comma. You can also use glob
581
+ # (* and ?) patterns to match multiple tests, see the TestTask#include method.
582
+ rule /^test:.*$/ do |task|
583
+ # The map works around a JRuby bug whereby the string looks fine, but fails in fnmatch.
584
+ tests = task.name.scan(/test:(.*)/)[0][0].split(',').map(&:to_s)
585
+ excludes, includes = tests.partition { |t| t =~ /^-/ }
586
+ if excludes.empty?
587
+ TestTask.only_run includes
588
+ else
589
+ # remove leading '-'
590
+ excludes.map! { |t| t[1..-1] }
591
+
592
+ TestTask.clear
593
+ TestTask.include(includes.empty? ? ['*'] : includes)
594
+ TestTask.exclude excludes
595
+ end
596
+ task('test').invoke
597
+ end
598
+
599
+ end
600
+
601
+ before_define(:test) do |project|
602
+ # Define a recursive test task, and pass it a reference to the project so it can discover all other tasks.
603
+ test = TestTask.define_task('test')
604
+ test.send :associate_with, project
605
+
606
+ # Similar to the regular resources task but using different paths.
607
+ resources = ResourcesTask.define_task('test:resources')
608
+ resources.send :associate_with, project, :test
609
+ project.path_to(:source, :test, :resources).tap { |dir| resources.from dir if File.exist?(dir) }
610
+
611
+ # We define a module inline that will inject cancelling the task if tests are skipped.
612
+ module SkipIfNoTest
613
+
614
+ def self.extended(base)
615
+ base.instance_eval {alias :execute_before_skip_if_no_test :execute}
616
+ base.instance_eval {alias :execute :execute_after_skip_if_no_test}
617
+ end
618
+
619
+ def execute_after_skip_if_no_test(args) #:nodoc:
620
+ if Buildr.options.test == false
621
+ trace "Skipping #{to_s} for #{project.name} as tests are skipped"
622
+ return
623
+ end
624
+ execute_before_skip_if_no_test(args)
625
+ end
626
+ end
627
+
628
+ # Similar to the regular compile task but using different paths.
629
+ compile = CompileTask.define_task('test:compile'=>[project.compile, resources])
630
+ compile.extend SkipIfNoTest
631
+ compile.send :associate_with, project, :test
632
+ test.enhance [compile]
633
+
634
+ # Define these tasks once, otherwise we may get a namespace error.
635
+ test.setup ; test.teardown
636
+ end
637
+
638
+
639
+
640
+ after_define(:test => :compile) do |project|
641
+ test = project.test
642
+ # Dependency on compiled tests and resources. Dependencies added using with.
643
+ test.dependencies.concat [test.compile.target, test.resources.target].compact
644
+ test.dependencies.concat test.compile.dependencies
645
+ # Dependency on compiled code, its dependencies and resources.
646
+ test.with [project.compile.target, project.resources.target].compact
647
+ test.with project.compile.dependencies
648
+ # Picking up the test frameworks adds further dependencies.
649
+ test.framework
650
+
651
+ project.build test unless test.options[:integration] || Buildr.options.test == :only
652
+
653
+ project.clean do
654
+ rm_rf test.compile.target.to_s if test.compile.target
655
+ rm_rf test.report_to.to_s
656
+ end
657
+ end
658
+
659
+
660
+ # :call-seq:
661
+ # test(*prereqs) => TestTask
662
+ # test(*prereqs) { |task| .. } => TestTask
663
+ #
664
+ # Returns the test task. The test task controls the entire test lifecycle.
665
+ #
666
+ # You can use the test task in three ways. You can access and configure specific
667
+ # test tasks, e.g. enhance the compile task by calling test.compile, setup for
668
+ # the tests by enhancing test.setup and so forth.
669
+ #
670
+ # You can use convenient methods that handle the most common settings. For example,
671
+ # add dependencies using test.with, or include only specific tests using test.include.
672
+ #
673
+ # You can also enhance this task directly. This method accepts a list of arguments
674
+ # that are used as prerequisites and an optional block that will be executed by the
675
+ # test task.
676
+ #
677
+ # This task compiles the project and the tests (in that order) before running any tests.
678
+ # It execute the setup task, runs all the tests, any enhancements, and ends with the
679
+ # teardown tasks.
680
+ def test(*prereqs, &block)
681
+ task('test').enhance prereqs, &block
682
+ end
683
+
684
+ # :call-seq:
685
+ # integration { |task| .... }
686
+ # integration => IntegrationTestTask
687
+ #
688
+ # Use this method to return the integration tests task, or enhance it with a block to execute.
689
+ #
690
+ # There is one integration tests task you can execute directly, or as a result of running the package
691
+ # task (or tasks that depend on it, like install and upload). It contains all the tests marked with
692
+ # :integration=>true, all other tests are considered unit tests and run by the test task before packaging.
693
+ # So essentially: build=>test=>packaging=>integration=>install/upload.
694
+ #
695
+ # You add new tests from projects that define integration tests using the regular test task,
696
+ # but with the following addition:
697
+ # test.using :integration
698
+ #
699
+ # Use this method to enhance the setup and teardown tasks that are executed before (and after) all
700
+ # integration tests are run, for example, to start a Web server or create a database.
701
+ def integration(*deps, &block)
702
+ Rake::Task['rake:integration'].enhance deps, &block
703
+ end
704
+
705
+ end
706
+
707
+
708
+ # :call-seq:
709
+ # integration { |task| .... }
710
+ # integration => IntegrationTestTask
711
+ #
712
+ # Use this method to return the integration tests task.
713
+ def integration(*deps, &block)
714
+ Rake::Task['rake:integration'].enhance deps, &block
715
+ end
716
+
717
+ class Options
718
+
719
+ # Runs tests after the build when true (default). This forces tests to execute
720
+ # after the build, including when running build related tasks like install, upload and release.
721
+ #
722
+ # Set to false to not run any tests. Set to :all to run all tests, ignoring failures.
723
+ #
724
+ # This option is set from the environment variable 'test', so you can also do:
725
+
726
+ # Returns the test option (environment variable TEST). Possible values are:
727
+ # * :false -- Do not run any tests (also accepts 'no' and 'skip').
728
+ # * :true -- Run all tests, stop on failure (default if not set).
729
+ # * :all -- Run all tests, ignore failures.
730
+ def test
731
+ case value = ENV['TEST'] || ENV['test']
732
+ when /^(no|off|false|skip)$/i
733
+ false
734
+ when /^all$/i
735
+ :all
736
+ when /^only$/i
737
+ :only
738
+ when /^(yes|on|true)$/i, nil
739
+ true
740
+ else
741
+ warn "Expecting the environment variable test to be 'no' or 'all', not sure what to do with #{value}, so I'm just going to run all the tests and stop at failure."
742
+ true
743
+ end
744
+ end
745
+
746
+ # Sets the test option (environment variable TEST). Possible values are true, false or :all.
747
+ #
748
+ # You can also set this from the environment variable, e.g.:
749
+ #
750
+ # buildr # With tests
751
+ # buildr test=no # Without tests
752
+ # buildr test=all # Ignore failures
753
+ # set TEST=no
754
+ # buildr # Without tests
755
+ def test=(flag)
756
+ ENV['test'] = nil
757
+ ENV['TEST'] = flag.to_s
758
+ end
759
+
760
+ end
761
+
762
+ Buildr.help << <<-HELP
763
+ To run a full build without running any tests:
764
+ buildr test=no
765
+ To run specific test:
766
+ buildr test:MyTest
767
+ To run integration tests:
768
+ buildr integration
769
+ HELP
770
+
771
+ end
772
+
773
+
774
+ class Buildr::Project
775
+ include Buildr::Test
776
+ end