realityforge-buildr 1.5.9

Sign up to get free protection for your applications and to get access to all the features.
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,922 @@
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 File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helpers'))
18
+
19
+ RSpec.shared_examples 'local task' do
20
+ it "should execute task for project in current directory" do
21
+ define 'foobar'
22
+ lambda { @task.invoke }.should run_task("foobar:#{@task.name}")
23
+ end
24
+
25
+ it "should not execute task for projects in other directory" do
26
+ define 'foobar', :base_dir=>'elsewhere'
27
+ lambda { task('build').invoke }.should_not run_task('foobar:build')
28
+ end
29
+ end
30
+
31
+
32
+ describe 'build task' do
33
+ it_should_behave_like 'local task'
34
+ before(:each) { @task = task('build') }
35
+ end
36
+
37
+ describe 'clean task' do
38
+ it_should_behave_like 'local task'
39
+ before(:each) { @task = task('clean') }
40
+ end
41
+
42
+ describe 'package task' do
43
+ it_should_behave_like 'local task'
44
+ before(:each) { @task = task('package') }
45
+
46
+ it 'should execute build task as prerequisite' do
47
+ lambda { @task.invoke }.should run_task('build')
48
+ end
49
+ end
50
+
51
+ describe 'install task' do
52
+ it_should_behave_like 'local task'
53
+ before(:each) { @task = task('install') }
54
+
55
+ it 'should execute package task as prerequisite' do
56
+ lambda { @task.invoke }.should run_task('package')
57
+ end
58
+ end
59
+
60
+ describe 'uninstall task' do
61
+ it_should_behave_like 'local task'
62
+ before(:each) { @task = task('uninstall') }
63
+ end
64
+
65
+ describe 'upload task' do
66
+ it_should_behave_like 'local task'
67
+ before(:each) { @task = task('upload') }
68
+
69
+ it 'should execute package task as prerequisite' do
70
+ lambda { @task.invoke }.should run_task('package')
71
+ end
72
+ end
73
+
74
+
75
+ describe Project, '#build' do
76
+ it 'should return the project\'s build task' do
77
+ define('foo').build.should eql(task('foo:build'))
78
+ end
79
+
80
+ it 'should enhance the project\'s build task' do
81
+ task 'prereq'
82
+ task 'action'
83
+ define 'foo' do
84
+ build 'prereq' do
85
+ task('action').invoke
86
+ end
87
+ end
88
+ lambda { project('foo').build.invoke }.should run_tasks('prereq', 'action')
89
+ end
90
+
91
+ it 'should execute build task for sub-project' do
92
+ define 'foo' do
93
+ define 'bar'
94
+ end
95
+ lambda { task('foo:build').invoke }.should run_task('foo:bar:build')
96
+ end
97
+
98
+ it 'should not execute build task of other projects' do
99
+ define 'foo'
100
+ define 'bar'
101
+ lambda { task('foo:build').invoke }.should_not run_task('bar:build')
102
+ end
103
+ end
104
+
105
+
106
+ describe Project, '#clean' do
107
+ it 'should return the project\'s clean task' do
108
+ define('foo').clean.should eql(task('foo:clean'))
109
+ end
110
+
111
+ it 'should enhance the project\'s clean task' do
112
+ task 'prereq'
113
+ task 'action'
114
+ define 'foo' do
115
+ clean 'prereq' do
116
+ task('action').invoke
117
+ end
118
+ end
119
+ lambda { project('foo').clean.invoke }.should run_tasks('prereq', 'action')
120
+ end
121
+
122
+ it 'should remove target directory' do
123
+ define 'foo' do
124
+ self.layout[:target] = 'targeted'
125
+ end
126
+ mkpath 'targeted'
127
+ lambda { project('foo').clean.invoke }.should change { File.exist?('targeted') }.from(true).to(false)
128
+ end
129
+
130
+ it 'should remove reports directory' do
131
+ define 'foo' do
132
+ self.layout[:reports] = 'reported'
133
+ end
134
+ mkpath 'reported'
135
+ lambda { project('foo').clean.invoke }.should change { File.exist?('reported') }.from(true).to(false)
136
+ end
137
+
138
+ it 'should execute clean task for sub-project' do
139
+ define 'foo' do
140
+ define 'bar'
141
+ end
142
+ lambda { task('foo:clean').invoke }.should run_task('foo:bar:clean')
143
+ end
144
+
145
+ it 'should not execute clean task of other projects' do
146
+ define 'foo'
147
+ define 'bar'
148
+ lambda { task('foo:clean').invoke }.should_not run_task('bar:clean')
149
+ end
150
+ end
151
+
152
+ describe Hg do
153
+ describe '#current_branch' do
154
+ it 'should return the correct branch' do
155
+ Hg.should_receive(:hg).with('branch').and_return("default\n")
156
+ Hg.send(:current_branch).should == 'default'
157
+ end
158
+ end
159
+
160
+ describe '#uncommitted_files' do
161
+ it 'should return an array of modified files' do
162
+ Hg.should_receive(:`).with('hg status').and_return <<-EOF
163
+ M abc.txt
164
+ M xyz.txt
165
+ R hello
166
+ R removed
167
+ ! conflict
168
+ A README
169
+ ? ignore.txt
170
+ EOF
171
+ Hg.uncommitted_files.should include('abc.txt', 'xyz.txt', 'hello', 'README', 'conflict', 'ignore.txt')
172
+ end
173
+ end
174
+
175
+ describe '#uncommitted_files' do
176
+ it 'should return an empty array on a clean repository' do
177
+ Hg.should_receive(:`).with('hg status').and_return "\n"
178
+ Hg.uncommitted_files.should be_empty
179
+ end
180
+ end
181
+
182
+ describe '#remote' do
183
+ it 'should return the aliases of the default remote repositories' do
184
+ Hg.should_receive(:hg).with('paths').and_return <<-EOF
185
+ default = https://hg.apache.org/repo/my-repo
186
+ EOF
187
+ Hg.send(:remote).should include('https://hg.apache.org/repo/my-repo')
188
+ end
189
+
190
+ it 'should return the aliases of the default push remote repositories' do
191
+ Hg.should_receive(:hg).with('paths').and_return <<-EOF
192
+ default-push = https://hg.apache.org/repo/my-repo
193
+ EOF
194
+ Hg.send(:remote).should include('https://hg.apache.org/repo/my-repo')
195
+ end
196
+
197
+ it 'should return empty array when no remote repositories found' do
198
+ Hg.should_receive(:hg).with('paths').and_return "\n"
199
+ Hg.send(:remote).should be_empty
200
+ end
201
+
202
+ it 'should return empty array when no default-push remote repository found' do
203
+ Hg.should_receive(:hg).with('paths').and_return <<-EOF
204
+ blah = https://bitbucket.org/sample-repo
205
+ EOF
206
+ Hg.send(:remote).should be_empty
207
+ end
208
+ end
209
+ end # end of Hg
210
+
211
+
212
+ describe Git do
213
+ describe '#uncommitted_files' do
214
+ it 'should return an empty array on a clean repository' do
215
+ Git.should_receive(:`).with('git status').and_return <<-EOF
216
+ # On branch master
217
+ nothing to commit (working directory clean)
218
+ EOF
219
+ Git.uncommitted_files.should be_empty
220
+ end
221
+
222
+ it 'should reject a dirty repository, Git 1.4.2 or former' do
223
+ Git.should_receive(:`).with('git status').and_return <<-EOF
224
+ # On branch master
225
+ #
226
+ # Changed but not updated:
227
+ # (use "git add <file>..." to update what will be committed)
228
+ # (use "git checkout -- <file>..." to discard changes in working directory)
229
+ #
230
+ # modified: lib/buildr.rb
231
+ # modified: spec/buildr_spec.rb
232
+ #
233
+ # Untracked files:
234
+ # (use "git add <file>..." to include in what will be committed)
235
+ #
236
+ # error.log
237
+ EOF
238
+ Git.uncommitted_files.should include('lib/buildr.rb', 'error.log')
239
+ end
240
+
241
+ it 'should reject a dirty repository, Git 1.4.3 or higher' do
242
+ Git.should_receive(:`).with('git status').and_return <<-EOF
243
+ # On branch master
244
+ # Changed but not updated:
245
+ # (use "git add <file>..." to update what will be committed)
246
+ #
247
+ #\tmodified: lib/buildr.rb
248
+ #\tmodified: spec/buildr_spec.rb
249
+ #
250
+ # Untracked files:
251
+ # (use "git add <file>..." to include in what will be committed)
252
+ #
253
+ #\terror.log
254
+ no changes added to commit (use "git add" and/or "git commit -a")
255
+ EOF
256
+ Git.uncommitted_files.should include('lib/buildr.rb', 'error.log')
257
+ end
258
+ end
259
+
260
+ describe '#remote' do
261
+ it 'should return the name of the corresponding remote' do
262
+ Git.should_receive(:git).with('config', '--get', 'branch.master.remote').and_return "origin\n"
263
+ Git.should_receive(:git).with('remote').and_return "upstream\norigin\n"
264
+ Git.send(:remote, 'master').should == 'origin'
265
+ end
266
+
267
+ it 'should return nil if no remote for the given branch' do
268
+ Git.should_receive(:git).with('config', '--get', 'branch.master.remote').and_return "\n"
269
+ Git.should_not_receive(:git).with('remote')
270
+ Git.send(:remote, 'master').should be_nil
271
+ end
272
+ end
273
+
274
+ describe '#current_branch' do
275
+ it 'should return the current branch' do
276
+ Git.should_receive(:git).with('branch').and_return(" master\n* a-clever-idea\n ze-great-idea")
277
+ Git.send(:current_branch).should == 'a-clever-idea'
278
+ end
279
+ end
280
+
281
+ end # of Git
282
+
283
+
284
+ describe Svn do
285
+ describe '#tag' do
286
+ it 'should remove any existing tag with the same name' do
287
+ Svn.stub(:repo_url).and_return('http://my.repo.org/foo/trunk')
288
+ Svn.stub(:copy)
289
+ Svn.should_receive(:remove).with('http://my.repo.org/foo/tags/1.0.0', 'Removing old copy')
290
+
291
+ Svn.tag '1.0.0'
292
+ end
293
+
294
+ it 'should do an svn copy with the release version' do
295
+ Svn.stub(:repo_url).and_return('http://my.repo.org/foo/trunk')
296
+ Svn.stub(:remove)
297
+ Svn.should_receive(:copy).with(Dir.pwd, 'http://my.repo.org/foo/tags/1.0.0', 'Release 1.0.0')
298
+
299
+ Svn.tag '1.0.0'
300
+ end
301
+ end
302
+
303
+ # Reference: http://svnbook.red-bean.com/en/1.4/svn.reposadmin.planning.html#svn.reposadmin.projects.chooselayout
304
+ describe '#tag_url' do
305
+ it 'should accept to tag foo/trunk' do
306
+ Svn.tag_url('http://my.repo.org/foo/trunk', '1.0.0').should == 'http://my.repo.org/foo/tags/1.0.0'
307
+ end
308
+
309
+ it 'should accept to tag foo/branches/1.0' do
310
+ Svn.tag_url('http://my.repo.org/foo/branches/1.0', '1.0.1').should == 'http://my.repo.org/foo/tags/1.0.1'
311
+ end
312
+
313
+ it 'should accept to tag trunk/foo' do
314
+ Svn.tag_url('http://my.repo.org/trunk/foo', '1.0.0').should == 'http://my.repo.org/tags/foo/1.0.0'
315
+ end
316
+
317
+ it 'should accept to tag branches/foo/1.0' do
318
+ Svn.tag_url('http://my.repo.org/branches/foo/1.0', '1.0.0').should == 'http://my.repo.org/tags/foo/1.0.0'
319
+ end
320
+
321
+ describe '#repo_url' do
322
+ it 'should extract the SVN URL from svn info' do
323
+ Svn.should_receive(:svn).and_return <<-XML
324
+ <?xml version="1.0"?>
325
+ <info>
326
+ <entry
327
+ kind="dir"
328
+ path="."
329
+ revision="724987">
330
+ <url>http://my.repo.org/foo/trunk</url>
331
+ <repository>
332
+ <root>http://my.repo.org</root>
333
+ <uuid>13f79535-47bb-0310-9956-ffa450edef68</uuid>
334
+ </repository>
335
+ <wc-info>
336
+ <schedule>normal</schedule>
337
+ <depth>infinity</depth>
338
+ </wc-info>
339
+ <commit
340
+ revision="724955">
341
+ <author>boisvert</author>
342
+ <date>2008-12-10T01:53:51.240936Z</date>
343
+ </commit>
344
+ </entry>
345
+ </info>
346
+ XML
347
+ Svn.repo_url.should == 'http://my.repo.org/foo/trunk'
348
+ end
349
+ end
350
+
351
+ end
352
+
353
+ end # of Buildr::Svn
354
+
355
+
356
+ describe Release do
357
+ describe 'find' do
358
+ it 'should return HgRelease if project uses Hg' do
359
+ write '.hg/requires'
360
+ Release.find.should be_instance_of(HgRelease)
361
+ end
362
+
363
+ it 'should return GitRelease if project uses Git' do
364
+ write '.git/config'
365
+ Release.find.should be_instance_of(GitRelease)
366
+ end
367
+
368
+ it 'should return SvnRelease if project uses SVN' do
369
+ write '.svn/xml'
370
+ Release.find.should be_instance_of(SvnRelease)
371
+ end
372
+
373
+ # TravisCI seems to place the tmp directory
374
+ # sub-ordinate to git repository so this will not work
375
+ unless ENV['TRAVIS_BUILD_ID']
376
+ it 'should return nil if no known release process' do
377
+ Dir.chdir(Dir.tmpdir) do
378
+ Release.find.should be_nil
379
+ end
380
+ end
381
+ end
382
+
383
+ after :each do
384
+ Release.instance_exec { @release = nil }
385
+ end
386
+ end
387
+ end
388
+
389
+
390
+ RSpec.shared_examples 'a release process' do
391
+
392
+ describe '#make' do
393
+ before do
394
+ write 'buildfile', "VERSION_NUMBER = '1.0.0-SNAPSHOT'"
395
+ # Prevent a real call to a spawned buildr process.
396
+ @release.stub(:buildr)
397
+ @release.stub(:check)
398
+ @release.should_receive(:sh).with('buildr', '--buildfile', File.expand_path('buildfile.next'),
399
+ '--environment', 'development', 'clean', 'upload', 'DEBUG=no')
400
+ end
401
+
402
+ it 'should tag a release with the release version' do
403
+ @release.stub(:update_version_to_next)
404
+ @release.should_receive(:tag_release).with('1.0.0')
405
+ @release.make
406
+ end
407
+
408
+ it 'should not alter the buildfile before tagging' do
409
+ @release.stub(:update_version_to_next)
410
+ @release.should_receive(:tag_release).with('1.0.0')
411
+ @release.make
412
+ file('buildfile').should contain('VERSION_NUMBER = "1.0.0"')
413
+ end
414
+
415
+ it 'should update the buildfile with the next version number' do
416
+ @release.stub(:tag_release)
417
+ @release.make
418
+ file('buildfile').should contain('VERSION_NUMBER = "1.0.1-SNAPSHOT"')
419
+ end
420
+
421
+ it 'should keep leading zeros in the next version number' do
422
+ write 'buildfile', "VERSION_NUMBER = '1.0.001-SNAPSHOT'"
423
+ @release.stub(:tag_release)
424
+ @release.make
425
+ file('buildfile').should contain('VERSION_NUMBER = "1.0.002-SNAPSHOT"')
426
+ end
427
+
428
+ it 'should commit the updated buildfile' do
429
+ @release.stub(:tag_release)
430
+ @release.make
431
+ file('buildfile').should contain('VERSION_NUMBER = "1.0.1-SNAPSHOT"')
432
+ end
433
+
434
+ it 'should not consider "-rc" as "-SNAPSHOT"' do
435
+ write 'buildfile', "VERSION_NUMBER = '1.0.0-rc1'"
436
+ @release.stub(:tag_release)
437
+ @release.make
438
+ file('buildfile').should contain('VERSION_NUMBER = "1.0.0-rc1"')
439
+ end
440
+
441
+ it 'should only commit the updated buildfile if the version changed' do
442
+ write 'buildfile', "VERSION_NUMBER = '1.0.0-rc1'"
443
+ @release.should_not_receive(:update_version_to_next)
444
+ @release.stub(:tag_release)
445
+ @release.make
446
+ end
447
+ end
448
+
449
+ describe '#resolve_next_version' do
450
+
451
+ it 'should increment the version number if SNAPSHOT' do
452
+ @release.send(:resolve_next_version, "1.0.0-SNAPSHOT").should == '1.0.1-SNAPSHOT'
453
+ end
454
+
455
+ it 'should NOT increment the version number if no SNAPSHOT' do
456
+ @release.send(:resolve_next_version, "1.0.0").should == '1.0.0'
457
+ end
458
+
459
+ it 'should return the version specified by NEXT_VERSION env var' do
460
+ ENV['NEXT_VERSION'] = "version_from_env"
461
+ @release.send(:resolve_next_version, "1.0.0").should == 'version_from_env'
462
+ end
463
+
464
+ it 'should return the version specified by next_version' do
465
+ Release.next_version = "ze_next_version"
466
+ @release.send(:resolve_next_version, "1.0.0").should == 'ze_next_version'
467
+ end
468
+
469
+ it 'should return the version specified by next_version if next_version is a proc' do
470
+ Release.next_version = lambda {|version| "#{version}++"}
471
+ @release.send(:resolve_next_version, "1.0.0").should == '1.0.0++'
472
+ end
473
+
474
+ it "should return the version specified by 'NEXT_VERSION' env var even if next_version is non nil" do
475
+ ENV['NEXT_VERSION'] = "ze_version_from_env"
476
+ Release.next_version = lambda {|version| "#{version}++"}
477
+ @release.send(:resolve_next_version, "1.0.0").should == 'ze_version_from_env'
478
+ end
479
+
480
+ it "should return the version specified by 'next_version' env var even if next_version is non nil" do
481
+ ENV['NEXT_VERSION'] = nil
482
+ ENV['next_version'] = "ze_version_from_env_lowercase"
483
+ Release.next_version = lambda {|version| "#{version}++"}
484
+ @release.send(:resolve_next_version, "1.0.0").should == 'ze_version_from_env_lowercase'
485
+ end
486
+ after {
487
+ Release.next_version = nil
488
+ ENV['NEXT_VERSION'] = nil
489
+ ENV['next_version'] = nil
490
+ }
491
+ end
492
+
493
+ describe '#resolve_next_version' do
494
+
495
+ it 'should increment the version number if SNAPSHOT' do
496
+ @release.send(:resolve_next_version, "1.0.0-SNAPSHOT").should == '1.0.1-SNAPSHOT'
497
+ end
498
+
499
+ it 'should NOT increment the version number if no SNAPSHOT' do
500
+ @release.send(:resolve_next_version, "1.0.0").should == '1.0.0'
501
+ end
502
+
503
+ it 'should return the version specified by NEXT_VERSION env var' do
504
+ ENV['NEXT_VERSION'] = "version_from_env"
505
+ @release.send(:resolve_next_version, "1.0.0").should == 'version_from_env'
506
+ end
507
+
508
+ it 'should return the version specified by next_version' do
509
+ Release.next_version = "ze_next_version"
510
+ @release.send(:resolve_next_version, "1.0.0").should == 'ze_next_version'
511
+ end
512
+
513
+ it 'should return the version specified by next_version if next_version is a proc' do
514
+ Release.next_version = lambda {|version| "#{version}++"}
515
+ @release.send(:resolve_next_version, "1.0.0").should == '1.0.0++'
516
+ end
517
+
518
+ it "should return the version specified by 'NEXT_VERSION' env var even if next_version is non nil" do
519
+ ENV['NEXT_VERSION'] = "ze_version_from_env"
520
+ Release.next_version = lambda {|version| "#{version}++"}
521
+ @release.send(:resolve_next_version, "1.0.0").should == 'ze_version_from_env'
522
+ end
523
+
524
+ it "should return the version specified by 'next_version' env var even if next_version is non nil" do
525
+ ENV['NEXT_VERSION'] = nil
526
+ ENV['next_version'] = "ze_version_from_env_lowercase"
527
+ Release.next_version = lambda {|version| "#{version}++"}
528
+ @release.send(:resolve_next_version, "1.0.0").should == 'ze_version_from_env_lowercase'
529
+ end
530
+ after {
531
+ Release.next_version = nil
532
+ ENV['NEXT_VERSION'] = nil
533
+ ENV['next_version'] = nil
534
+ }
535
+ end
536
+
537
+ describe '#resolve_next_version' do
538
+
539
+ it 'should increment the version number if SNAPSHOT' do
540
+ @release.send(:resolve_next_version, "1.0.0-SNAPSHOT").should == '1.0.1-SNAPSHOT'
541
+ end
542
+
543
+ it 'should NOT increment the version number if no SNAPSHOT' do
544
+ @release.send(:resolve_next_version, "1.0.0").should == '1.0.0'
545
+ end
546
+
547
+ it 'should return the version specified by NEXT_VERSION env var' do
548
+ ENV['NEXT_VERSION'] = "version_from_env"
549
+ @release.send(:resolve_next_version, "1.0.0").should == 'version_from_env'
550
+ end
551
+
552
+ it 'should return the version specified by next_version' do
553
+ Release.next_version = "ze_next_version"
554
+ @release.send(:resolve_next_version, "1.0.0").should == 'ze_next_version'
555
+ end
556
+
557
+ it 'should return the version specified by next_version if next_version is a proc' do
558
+ Release.next_version = lambda {|version| "#{version}++"}
559
+ @release.send(:resolve_next_version, "1.0.0").should == '1.0.0++'
560
+ end
561
+
562
+ it "should return the version specified by 'NEXT_VERSION' env var even if next_version is non nil" do
563
+ ENV['NEXT_VERSION'] = "ze_version_from_env"
564
+ Release.next_version = lambda {|version| "#{version}++"}
565
+ @release.send(:resolve_next_version, "1.0.0").should == 'ze_version_from_env'
566
+ end
567
+
568
+ it "should return the version specified by 'next_version' env var even if next_version is non nil" do
569
+ ENV['NEXT_VERSION'] = nil
570
+ ENV['next_version'] = "ze_version_from_env_lowercase"
571
+ Release.next_version = lambda {|version| "#{version}++"}
572
+ @release.send(:resolve_next_version, "1.0.0").should == 'ze_version_from_env_lowercase'
573
+ end
574
+ after {
575
+ Release.next_version = nil
576
+ ENV['NEXT_VERSION'] = nil
577
+ ENV['next_version'] = nil
578
+ }
579
+ end
580
+
581
+ describe '#resolve_tag' do
582
+ before do
583
+ @release.stub(:extract_version).and_return('1.0.0')
584
+ end
585
+
586
+ it 'should return tag specified by tag_name' do
587
+ Release.tag_name = 'first'
588
+ @release.send(:resolve_tag).should == 'first'
589
+ end
590
+
591
+ it 'should use tag returned by tag_name if tag_name is a proc' do
592
+ Release.tag_name = lambda { |version| "buildr-#{version}" }
593
+ @release.send(:resolve_tag).should == 'buildr-1.0.0'
594
+ end
595
+ after { Release.tag_name = nil }
596
+ end
597
+
598
+ describe '#tag_release' do
599
+ it 'should inform the user' do
600
+ @release.stub(:extract_version).and_return('1.0.0')
601
+ lambda { @release.tag_release('1.0.0') }.should show_info('Tagging release 1.0.0')
602
+ end
603
+ end
604
+
605
+ describe '#extract_version' do
606
+ it 'should extract VERSION_NUMBER with single quotes' do
607
+ write 'buildfile', "VERSION_NUMBER = '1.0.0-SNAPSHOT'"
608
+ @release.extract_version.should == '1.0.0-SNAPSHOT'
609
+ end
610
+
611
+ it 'should extract VERSION_NUMBER with double quotes' do
612
+ write 'buildfile', %{VERSION_NUMBER = "1.0.1-SNAPSHOT"}
613
+ @release.extract_version.should == '1.0.1-SNAPSHOT'
614
+ end
615
+
616
+ it 'should extract VERSION_NUMBER without any spaces' do
617
+ write 'buildfile', "VERSION_NUMBER='1.0.2-SNAPSHOT'"
618
+ @release.extract_version.should == '1.0.2-SNAPSHOT'
619
+ end
620
+
621
+ it 'should extract THIS_VERSION as an alternative to VERSION_NUMBER' do
622
+ write 'buildfile', "THIS_VERSION = '1.0.3-SNAPSHOT'"
623
+ @release.extract_version.should == '1.0.3-SNAPSHOT'
624
+ end
625
+
626
+ it 'should complain if no current version number' do
627
+ write 'buildfile', 'define foo'
628
+ lambda { @release.extract_version }.should raise_error('Looking for THIS_VERSION = "..." in your Buildfile, none found')
629
+ end
630
+
631
+ it 'should use version.rb instead of buildfile, if present' do
632
+ write 'version.rb', "VERSION_NUMBER = '1.0.0-SNAPSHOT'"
633
+ @release.extract_version.should == '1.0.0-SNAPSHOT'
634
+ end
635
+
636
+ it 'should complain if there is a version.rb file, but it contains no version number' do
637
+ write 'version.rb', "#SOMETHING SOMETHING"
638
+ lambda { @release.extract_version }.should raise_error('Looking for THIS_VERSION = "..." in your Buildfile, none found')
639
+ end
640
+ end
641
+
642
+ describe '#with_release_candidate_version' do
643
+ before do
644
+ Buildr.application.stub(:buildfile).and_return(file('buildfile'))
645
+ write 'buildfile', "THIS_VERSION = '1.1.0-SNAPSHOT'"
646
+ end
647
+
648
+ it 'should yield the name of the release candidate buildfile' do
649
+ @release.send :with_release_candidate_version do |new_filename|
650
+ File.read(new_filename).should == %{THIS_VERSION = "1.1.0"}
651
+ end
652
+ end
653
+
654
+ it 'should yield a name different from the original buildfile' do
655
+ @release.send :with_release_candidate_version do |new_filename|
656
+ new_filename.should_not point_to_path('buildfile')
657
+ end
658
+ end
659
+ end
660
+
661
+ describe '#update_version_to_next' do
662
+ before do
663
+ write 'buildfile', "VERSION_NUMBER = '1.0.5-SNAPSHOT'"
664
+ @release.send(:this_version=, "1.0.5-SNAPSHOT")
665
+ end
666
+
667
+ it 'should update the buildfile with a new version number' do
668
+ @release.send :update_version_to_next
669
+ `cp buildfile /tmp/out`
670
+ file('buildfile').should contain('VERSION_NUMBER = "1.0.6-SNAPSHOT"')
671
+ end
672
+
673
+ it 'should commit the new buildfile on the trunk' do
674
+ @release.should_receive(:message).and_return('Changed version number to 1.0.1-SNAPSHOT')
675
+ @release.update_version_to_next
676
+ end
677
+
678
+ it 'should use the commit message specified by commit_message' do
679
+ Release.commit_message = 'Here is my custom message'
680
+ @release.should_receive(:message).and_return('Here is my custom message')
681
+ @release.update_version_to_next
682
+ end
683
+
684
+ it 'should use the commit message returned by commit_message if commit_message is a proc' do
685
+ Release.commit_message = lambda { |new_version|
686
+ new_version.should == '1.0.1-SNAPSHOT'
687
+ "increment version number to #{new_version}"
688
+ }
689
+ @release.should_receive(:message).and_return('increment version number to 1.0.1-SNAPSHOT')
690
+ @release.update_version_to_next
691
+ end
692
+
693
+ it 'should inform the user of the new version' do
694
+ lambda { @release.update_version_to_next }.should show_info('Current version is now 1.0.6-SNAPSHOT')
695
+ end
696
+ after { Release.commit_message = nil }
697
+ end
698
+
699
+
700
+ describe '#check' do
701
+ before { @release.send(:this_version=, "1.0.0-SNAPSHOT") }
702
+ it 'should fail if THIS_VERSION equals the next_version' do
703
+ @release.stub(:resolve_next_version).and_return('1.0.0-SNAPSHOT')
704
+ lambda { @release.check }.should raise_error("The next version can't be equal to the current version 1.0.0-SNAPSHOT.\nUpdate THIS_VERSION/VERSION_NUMBER, specify Release.next_version or use NEXT_VERSION env var")
705
+ end
706
+ end
707
+ end
708
+
709
+
710
+ describe HgRelease do
711
+ it_should_behave_like 'a release process'
712
+
713
+ before do
714
+ write 'buildfile', "VERSION_NUMBER = '1.0.0-SNAPSHOT'"
715
+ @release = HgRelease.new
716
+ Hg.stub(:hg)
717
+ Hg.stub(:remote).and_return('https://bitbucket.org/sample-repo')
718
+ Hg.stub(:current_branch).and_return('default')
719
+ end
720
+
721
+ describe '#applies_to?' do
722
+ it 'should reject a non-hg repo' do
723
+ Dir.chdir(Dir.tmpdir) do
724
+ HgRelease.applies_to?.should be_false
725
+ end
726
+ end
727
+
728
+ it 'should accept a hg repo' do
729
+ FileUtils.mkdir '.hg'
730
+ FileUtils.touch File.join('.hg', 'requires')
731
+ HgRelease.applies_to?.should be_true
732
+ end
733
+ end
734
+
735
+ describe '#check' do
736
+ before do
737
+ @release = HgRelease.new
738
+ @release.send(:this_version=, '1.0.0-SNAPSHOT')
739
+ end
740
+
741
+ it 'should accept a clean repo' do
742
+ Hg.should_receive(:uncommitted_files).and_return([])
743
+ Hg.should_receive(:remote).and_return(["http://bitbucket.org/sample-repo"])
744
+ lambda { @release.check }.should_not raise_error
745
+ end
746
+
747
+ it 'should reject a dirty repo' do
748
+ Hg.should_receive(:uncommitted_files).and_return(['dirty_file.txt'])
749
+ lambda { @release.check }.should raise_error(RuntimeError, /uncommitted files/i)
750
+ end
751
+
752
+ it 'should reject a local branch not tracking a remote repo' do
753
+ Hg.should_receive(:uncommitted_files).and_return([])
754
+ Hg.should_receive(:remote).and_return([])
755
+ lambda{ @release.check }.should raise_error(RuntimeError,
756
+ "You are releasing from a local branch that does not track a remote!")
757
+ end
758
+ end
759
+ end
760
+
761
+
762
+ describe GitRelease do
763
+ it_should_behave_like 'a release process'
764
+
765
+ before do
766
+ write 'buildfile', "VERSION_NUMBER = '1.0.0-SNAPSHOT'"
767
+ @release = GitRelease.new
768
+ Git.stub(:git)
769
+ Git.stub(:current_branch).and_return('master')
770
+ end
771
+
772
+ describe '#applies_to?' do
773
+
774
+ # TravisCI seems to place the tmp directory
775
+ # sub-ordinate to git repository so this will not work
776
+ unless ENV['TRAVIS_BUILD_ID']
777
+ it 'should reject a non-git repo' do
778
+ Dir.chdir(Dir.tmpdir) do
779
+ GitRelease.applies_to?.should be_false
780
+ end
781
+ end
782
+ end
783
+
784
+ it 'should accept a git repo' do
785
+ FileUtils.mkdir '.git'
786
+ FileUtils.touch File.join('.git', 'config')
787
+ GitRelease.applies_to?.should be_true
788
+ end
789
+ end
790
+
791
+ describe '#check' do
792
+ before do
793
+ @release = GitRelease.new
794
+ @release.send(:this_version=, '1.0.0-SNAPSHOT')
795
+ end
796
+
797
+ it 'should accept a clean repository' do
798
+ Git.should_receive(:`).with('git status').and_return <<-EOF
799
+ # On branch master
800
+ nothing to commit (working directory clean)
801
+ EOF
802
+ Git.should_receive(:remote).and_return('master')
803
+ lambda { @release.check }.should_not raise_error
804
+ end
805
+
806
+ it 'should reject a dirty repository' do
807
+ Git.should_receive(:`).with('git status').and_return <<-EOF
808
+ # On branch master
809
+ # Untracked files:
810
+ # (use "git add <file>..." to include in what will be committed)
811
+ #
812
+ # foo.temp
813
+ EOF
814
+ lambda { @release.check }.should raise_error(RuntimeError, /uncommitted files/i)
815
+ end
816
+
817
+ it 'should reject a repository not tracking remote branch' do
818
+ Git.should_receive(:uncommitted_files).and_return([])
819
+ Git.should_receive(:remote).and_return(nil)
820
+ lambda{ @release.check }.should raise_error(RuntimeError,
821
+ "You are releasing from a local branch that does not track a remote!")
822
+ end
823
+ end
824
+
825
+ describe '#tag_release' do
826
+ before do
827
+ @release = GitRelease.new
828
+ @release.stub(:extract_version).and_return('1.0.1')
829
+ @release.stub(:resolve_tag).and_return('TEST_TAG')
830
+ Git.stub(:git).with('tag', '-a', 'TEST_TAG', '-m', '[buildr] Cutting release TEST_TAG')
831
+ Git.stub(:git).with('push', 'origin', 'tag', 'TEST_TAG')
832
+ Git.stub(:commit)
833
+ Git.stub(:push)
834
+ Git.stub(:remote).and_return('origin')
835
+ end
836
+
837
+ it 'should delete any existing tag with the same name' do
838
+ Git.should_receive(:git).with('tag', '-d', 'TEST_TAG')
839
+ Git.should_receive(:git).with('push', 'origin', ':refs/tags/TEST_TAG')
840
+ @release.tag_release 'TEST_TAG'
841
+ end
842
+
843
+ it 'should commit the buildfile before tagging' do
844
+ Git.should_receive(:commit).with(File.basename(Buildr.application.buildfile.to_s), "Changed version number to 1.0.1")
845
+ @release.tag_release 'TEST_TAG'
846
+ end
847
+
848
+ it 'should push the tag if a remote is tracked' do
849
+ Git.should_receive(:git).with('tag', '-d', 'TEST_TAG')
850
+ Git.should_receive(:git).with('push', 'origin', ':refs/tags/TEST_TAG')
851
+ Git.should_receive(:git).with('tag', '-a', 'TEST_TAG', '-m', '[buildr] Cutting release TEST_TAG')
852
+ Git.should_receive(:git).with('push', 'origin', 'tag', 'TEST_TAG')
853
+ @release.tag_release 'TEST_TAG'
854
+ end
855
+
856
+ it 'should NOT push the tag if no remote is tracked' do
857
+ Git.stub(:remote).and_return(nil)
858
+ Git.should_not_receive(:git).with('push', 'origin', 'tag', 'TEST_TAG')
859
+ @release.tag_release 'TEST_TAG'
860
+ end
861
+ end
862
+ end
863
+
864
+
865
+ describe SvnRelease do
866
+ it_should_behave_like 'a release process'
867
+
868
+ before do
869
+ write 'buildfile', "VERSION_NUMBER = '1.0.0-SNAPSHOT'"
870
+ @release = SvnRelease.new
871
+ Svn.stub(:svn)
872
+ Svn.stub(:repo_url).and_return('http://my.repo.org/foo/trunk')
873
+ Svn.stub(:tag)
874
+ end
875
+
876
+ describe '#applies_to?' do
877
+ it 'should reject a non-git repo' do
878
+ SvnRelease.applies_to?.should be_false
879
+ end
880
+
881
+ it 'should accept a git repo' do
882
+ FileUtils.touch '.svn'
883
+ SvnRelease.applies_to?.should be_true
884
+ end
885
+ end
886
+
887
+ describe '#check' do
888
+ before do
889
+ Svn.stub(:uncommitted_files).and_return([])
890
+ @release = SvnRelease.new
891
+ @release.send(:this_version=, "1.0.0-SNAPSHOT")
892
+ end
893
+
894
+ it 'should accept to release from the trunk' do
895
+ Svn.stub(:repo_url).and_return('http://my.repo.org/foo/trunk')
896
+ lambda { @release.check }.should_not raise_error
897
+ end
898
+
899
+ it 'should accept to release from a branch' do
900
+ Svn.stub(:repo_url).and_return('http://my.repo.org/foo/branches/1.0')
901
+ lambda { @release.check }.should_not raise_error
902
+ end
903
+
904
+ it 'should reject releasing from a tag' do
905
+ Svn.stub(:repo_url).and_return('http://my.repo.org/foo/tags/1.0.0')
906
+ lambda { @release.check }.should raise_error(RuntimeError, "SVN URL must contain 'trunk' or 'branches/...'")
907
+ end
908
+
909
+ it 'should reject a non standard repository layout' do
910
+ Svn.stub(:repo_url).and_return('http://my.repo.org/foo/bar')
911
+ lambda { @release.check }.should raise_error(RuntimeError, "SVN URL must contain 'trunk' or 'branches/...'")
912
+ end
913
+
914
+ it 'should reject an uncommitted file' do
915
+ Svn.stub(:repo_url).and_return('http://my.repo.org/foo/trunk')
916
+ Svn.stub(:uncommitted_files).and_return(['foo.rb'])
917
+ lambda { @release.check }.should raise_error(RuntimeError,
918
+ "Uncommitted files violate the First Principle Of Release!\n" +
919
+ "foo.rb")
920
+ end
921
+ end
922
+ end