blob: 8df189a11d2d49e786edd946ad674c6e528e36e8 [file] [log] [blame]
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with this
# work for additional information regarding copyright ownership. The ASF
# licenses this file to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helpers'))
RSpec.shared_examples 'local task' do
it "should execute task for project in current directory" do
define 'foobar'
lambda { @task.invoke }.should run_task("foobar:#{@task.name}")
end
it "should not execute task for projects in other directory" do
define 'foobar', :base_dir=>'elsewhere'
lambda { task('build').invoke }.should_not run_task('foobar:build')
end
end
describe 'build task' do
it_should_behave_like 'local task'
before(:each) { @task = task('build') }
end
describe 'clean task' do
it_should_behave_like 'local task'
before(:each) { @task = task('clean') }
end
describe 'package task' do
it_should_behave_like 'local task'
before(:each) { @task = task('package') }
it 'should execute build task as prerequisite' do
lambda { @task.invoke }.should run_task('build')
end
end
describe 'install task' do
it_should_behave_like 'local task'
before(:each) { @task = task('install') }
it 'should execute package task as prerequisite' do
lambda { @task.invoke }.should run_task('package')
end
end
describe 'uninstall task' do
it_should_behave_like 'local task'
before(:each) { @task = task('uninstall') }
end
describe 'upload task' do
it_should_behave_like 'local task'
before(:each) { @task = task('upload') }
it 'should execute package task as prerequisite' do
lambda { @task.invoke }.should run_task('package')
end
end
describe Project, '#build' do
it 'should return the project\'s build task' do
define('foo').build.should eql(task('foo:build'))
end
it 'should enhance the project\'s build task' do
task 'prereq'
task 'action'
define 'foo' do
build 'prereq' do
task('action').invoke
end
end
lambda { project('foo').build.invoke }.should run_tasks('prereq', 'action')
end
it 'should execute build task for sub-project' do
define 'foo' do
define 'bar'
end
lambda { task('foo:build').invoke }.should run_task('foo:bar:build')
end
it 'should not execute build task of other projects' do
define 'foo'
define 'bar'
lambda { task('foo:build').invoke }.should_not run_task('bar:build')
end
end
describe Project, '#clean' do
it 'should return the project\'s clean task' do
define('foo').clean.should eql(task('foo:clean'))
end
it 'should enhance the project\'s clean task' do
task 'prereq'
task 'action'
define 'foo' do
clean 'prereq' do
task('action').invoke
end
end
lambda { project('foo').clean.invoke }.should run_tasks('prereq', 'action')
end
it 'should remove target directory' do
define 'foo' do
self.layout[:target] = 'targeted'
end
mkpath 'targeted'
lambda { project('foo').clean.invoke }.should change { File.exist?('targeted') }.from(true).to(false)
end
it 'should remove reports directory' do
define 'foo' do
self.layout[:reports] = 'reported'
end
mkpath 'reported'
lambda { project('foo').clean.invoke }.should change { File.exist?('reported') }.from(true).to(false)
end
it 'should execute clean task for sub-project' do
define 'foo' do
define 'bar'
end
lambda { task('foo:clean').invoke }.should run_task('foo:bar:clean')
end
it 'should not execute clean task of other projects' do
define 'foo'
define 'bar'
lambda { task('foo:clean').invoke }.should_not run_task('bar:clean')
end
end
describe Hg do
describe '#current_branch' do
it 'should return the correct branch' do
Hg.should_receive(:hg).with('branch').and_return("default\n")
Hg.send(:current_branch).should == 'default'
end
end
describe '#uncommitted_files' do
it 'should return an array of modified files' do
Hg.should_receive(:`).with('hg status').and_return <<-EOF
M abc.txt
M xyz.txt
R hello
R removed
! conflict
A README
? ignore.txt
EOF
Hg.uncommitted_files.should include('abc.txt', 'xyz.txt', 'hello', 'README', 'conflict', 'ignore.txt')
end
end
describe '#uncommitted_files' do
it 'should return an empty array on a clean repository' do
Hg.should_receive(:`).with('hg status').and_return "\n"
Hg.uncommitted_files.should be_empty
end
end
describe '#remote' do
it 'should return the aliases of the default remote repositories' do
Hg.should_receive(:hg).with('paths').and_return <<-EOF
default = https://hg.apache.org/repo/my-repo
EOF
Hg.send(:remote).should include('https://hg.apache.org/repo/my-repo')
end
it 'should return the aliases of the default push remote repositories' do
Hg.should_receive(:hg).with('paths').and_return <<-EOF
default-push = https://hg.apache.org/repo/my-repo
EOF
Hg.send(:remote).should include('https://hg.apache.org/repo/my-repo')
end
it 'should return empty array when no remote repositories found' do
Hg.should_receive(:hg).with('paths').and_return "\n"
Hg.send(:remote).should be_empty
end
it 'should return empty array when no default-push remote repository found' do
Hg.should_receive(:hg).with('paths').and_return <<-EOF
blah = https://bitbucket.org/sample-repo
EOF
Hg.send(:remote).should be_empty
end
end
end # end of Hg
describe Git do
describe '#uncommitted_files' do
it 'should return an empty array on a clean repository' do
Git.should_receive(:`).with('git status').and_return <<-EOF
# On branch master
nothing to commit (working directory clean)
EOF
Git.uncommitted_files.should be_empty
end
it 'should reject a dirty repository, Git 1.4.2 or former' do
Git.should_receive(:`).with('git status').and_return <<-EOF
# On branch master
#
# Changed but not updated:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: lib/buildr.rb
# modified: spec/buildr_spec.rb
#
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
# error.log
EOF
Git.uncommitted_files.should include('lib/buildr.rb', 'error.log')
end
it 'should reject a dirty repository, Git 1.4.3 or higher' do
Git.should_receive(:`).with('git status').and_return <<-EOF
# On branch master
# Changed but not updated:
# (use "git add <file>..." to update what will be committed)
#
#\tmodified: lib/buildr.rb
#\tmodified: spec/buildr_spec.rb
#
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
#\terror.log
no changes added to commit (use "git add" and/or "git commit -a")
EOF
Git.uncommitted_files.should include('lib/buildr.rb', 'error.log')
end
end
describe '#remote' do
it 'should return the name of the corresponding remote' do
Git.should_receive(:git).with('config', '--get', 'branch.master.remote').and_return "origin\n"
Git.should_receive(:git).with('remote').and_return "upstream\norigin\n"
Git.send(:remote, 'master').should == 'origin'
end
it 'should return nil if no remote for the given branch' do
Git.should_receive(:git).with('config', '--get', 'branch.master.remote').and_return "\n"
Git.should_not_receive(:git).with('remote')
Git.send(:remote, 'master').should be_nil
end
end
describe '#current_branch' do
it 'should return the current branch' do
Git.should_receive(:git).with('branch').and_return(" master\n* a-clever-idea\n ze-great-idea")
Git.send(:current_branch).should == 'a-clever-idea'
end
end
end # of Git
describe Svn do
describe '#tag' do
it 'should remove any existing tag with the same name' do
Svn.stub(:repo_url).and_return('http://my.repo.org/foo/trunk')
Svn.stub(:copy)
Svn.should_receive(:remove).with('http://my.repo.org/foo/tags/1.0.0', 'Removing old copy')
Svn.tag '1.0.0'
end
it 'should do an svn copy with the release version' do
Svn.stub(:repo_url).and_return('http://my.repo.org/foo/trunk')
Svn.stub(:remove)
Svn.should_receive(:copy).with(Dir.pwd, 'http://my.repo.org/foo/tags/1.0.0', 'Release 1.0.0')
Svn.tag '1.0.0'
end
end
# Reference: http://svnbook.red-bean.com/en/1.4/svn.reposadmin.planning.html#svn.reposadmin.projects.chooselayout
describe '#tag_url' do
it 'should accept to tag foo/trunk' do
Svn.tag_url('http://my.repo.org/foo/trunk', '1.0.0').should == 'http://my.repo.org/foo/tags/1.0.0'
end
it 'should accept to tag foo/branches/1.0' do
Svn.tag_url('http://my.repo.org/foo/branches/1.0', '1.0.1').should == 'http://my.repo.org/foo/tags/1.0.1'
end
it 'should accept to tag trunk/foo' do
Svn.tag_url('http://my.repo.org/trunk/foo', '1.0.0').should == 'http://my.repo.org/tags/foo/1.0.0'
end
it 'should accept to tag branches/foo/1.0' do
Svn.tag_url('http://my.repo.org/branches/foo/1.0', '1.0.0').should == 'http://my.repo.org/tags/foo/1.0.0'
end
describe '#repo_url' do
it 'should extract the SVN URL from svn info' do
Svn.should_receive(:svn).and_return <<-XML
<?xml version="1.0"?>
<info>
<entry
kind="dir"
path="."
revision="724987">
<url>http://my.repo.org/foo/trunk</url>
<repository>
<root>http://my.repo.org</root>
<uuid>13f79535-47bb-0310-9956-ffa450edef68</uuid>
</repository>
<wc-info>
<schedule>normal</schedule>
<depth>infinity</depth>
</wc-info>
<commit
revision="724955">
<author>boisvert</author>
<date>2008-12-10T01:53:51.240936Z</date>
</commit>
</entry>
</info>
XML
Svn.repo_url.should == 'http://my.repo.org/foo/trunk'
end
end
end
end # of Buildr::Svn
describe Release do
describe 'find' do
it 'should return HgRelease if project uses Hg' do
write '.hg/requires'
Release.find.should be_instance_of(HgRelease)
end
it 'should return GitRelease if project uses Git' do
write '.git/config'
Release.find.should be_instance_of(GitRelease)
end
it 'should return SvnRelease if project uses SVN' do
write '.svn/xml'
Release.find.should be_instance_of(SvnRelease)
end
# TravisCI seems to place the tmp directory
# sub-ordinate to git repository so this will not work
unless ENV['TRAVIS_BUILD_ID']
it 'should return nil if no known release process' do
Dir.chdir(Dir.tmpdir) do
Release.find.should be_nil
end
end
end
after :each do
Release.instance_exec { @release = nil }
end
end
end
RSpec.shared_examples 'a release process' do
describe '#make' do
before do
write 'buildfile', "VERSION_NUMBER = '1.0.0-SNAPSHOT'"
# Prevent a real call to a spawned buildr process.
@release.stub(:buildr)
@release.stub(:check)
@release.should_receive(:sh).with('buildr', '--buildfile', File.expand_path('buildfile.next'),
'--environment', 'development', 'clean', 'upload', 'DEBUG=no')
end
it 'should tag a release with the release version' do
@release.stub(:update_version_to_next)
@release.should_receive(:tag_release).with('1.0.0')
@release.make
end
it 'should not alter the buildfile before tagging' do
@release.stub(:update_version_to_next)
@release.should_receive(:tag_release).with('1.0.0')
@release.make
file('buildfile').should contain('VERSION_NUMBER = "1.0.0"')
end
it 'should update the buildfile with the next version number' do
@release.stub(:tag_release)
@release.make
file('buildfile').should contain('VERSION_NUMBER = "1.0.1-SNAPSHOT"')
end
it 'should keep leading zeros in the next version number' do
write 'buildfile', "VERSION_NUMBER = '1.0.001-SNAPSHOT'"
@release.stub(:tag_release)
@release.make
file('buildfile').should contain('VERSION_NUMBER = "1.0.002-SNAPSHOT"')
end
it 'should commit the updated buildfile' do
@release.stub(:tag_release)
@release.make
file('buildfile').should contain('VERSION_NUMBER = "1.0.1-SNAPSHOT"')
end
it 'should not consider "-rc" as "-SNAPSHOT"' do
write 'buildfile', "VERSION_NUMBER = '1.0.0-rc1'"
@release.stub(:tag_release)
@release.make
file('buildfile').should contain('VERSION_NUMBER = "1.0.0-rc1"')
end
it 'should only commit the updated buildfile if the version changed' do
write 'buildfile', "VERSION_NUMBER = '1.0.0-rc1'"
@release.should_not_receive(:update_version_to_next)
@release.stub(:tag_release)
@release.make
end
end
describe '#resolve_next_version' do
it 'should increment the version number if SNAPSHOT' do
@release.send(:resolve_next_version, "1.0.0-SNAPSHOT").should == '1.0.1-SNAPSHOT'
end
it 'should NOT increment the version number if no SNAPSHOT' do
@release.send(:resolve_next_version, "1.0.0").should == '1.0.0'
end
it 'should return the version specified by NEXT_VERSION env var' do
ENV['NEXT_VERSION'] = "version_from_env"
@release.send(:resolve_next_version, "1.0.0").should == 'version_from_env'
end
it 'should return the version specified by next_version' do
Release.next_version = "ze_next_version"
@release.send(:resolve_next_version, "1.0.0").should == 'ze_next_version'
end
it 'should return the version specified by next_version if next_version is a proc' do
Release.next_version = lambda {|version| "#{version}++"}
@release.send(:resolve_next_version, "1.0.0").should == '1.0.0++'
end
it "should return the version specified by 'NEXT_VERSION' env var even if next_version is non nil" do
ENV['NEXT_VERSION'] = "ze_version_from_env"
Release.next_version = lambda {|version| "#{version}++"}
@release.send(:resolve_next_version, "1.0.0").should == 'ze_version_from_env'
end
it "should return the version specified by 'next_version' env var even if next_version is non nil" do
ENV['NEXT_VERSION'] = nil
ENV['next_version'] = "ze_version_from_env_lowercase"
Release.next_version = lambda {|version| "#{version}++"}
@release.send(:resolve_next_version, "1.0.0").should == 'ze_version_from_env_lowercase'
end
after {
Release.next_version = nil
ENV['NEXT_VERSION'] = nil
ENV['next_version'] = nil
}
end
describe '#resolve_next_version' do
it 'should increment the version number if SNAPSHOT' do
@release.send(:resolve_next_version, "1.0.0-SNAPSHOT").should == '1.0.1-SNAPSHOT'
end
it 'should NOT increment the version number if no SNAPSHOT' do
@release.send(:resolve_next_version, "1.0.0").should == '1.0.0'
end
it 'should return the version specified by NEXT_VERSION env var' do
ENV['NEXT_VERSION'] = "version_from_env"
@release.send(:resolve_next_version, "1.0.0").should == 'version_from_env'
end
it 'should return the version specified by next_version' do
Release.next_version = "ze_next_version"
@release.send(:resolve_next_version, "1.0.0").should == 'ze_next_version'
end
it 'should return the version specified by next_version if next_version is a proc' do
Release.next_version = lambda {|version| "#{version}++"}
@release.send(:resolve_next_version, "1.0.0").should == '1.0.0++'
end
it "should return the version specified by 'NEXT_VERSION' env var even if next_version is non nil" do
ENV['NEXT_VERSION'] = "ze_version_from_env"
Release.next_version = lambda {|version| "#{version}++"}
@release.send(:resolve_next_version, "1.0.0").should == 'ze_version_from_env'
end
it "should return the version specified by 'next_version' env var even if next_version is non nil" do
ENV['NEXT_VERSION'] = nil
ENV['next_version'] = "ze_version_from_env_lowercase"
Release.next_version = lambda {|version| "#{version}++"}
@release.send(:resolve_next_version, "1.0.0").should == 'ze_version_from_env_lowercase'
end
after {
Release.next_version = nil
ENV['NEXT_VERSION'] = nil
ENV['next_version'] = nil
}
end
describe '#resolve_next_version' do
it 'should increment the version number if SNAPSHOT' do
@release.send(:resolve_next_version, "1.0.0-SNAPSHOT").should == '1.0.1-SNAPSHOT'
end
it 'should NOT increment the version number if no SNAPSHOT' do
@release.send(:resolve_next_version, "1.0.0").should == '1.0.0'
end
it 'should return the version specified by NEXT_VERSION env var' do
ENV['NEXT_VERSION'] = "version_from_env"
@release.send(:resolve_next_version, "1.0.0").should == 'version_from_env'
end
it 'should return the version specified by next_version' do
Release.next_version = "ze_next_version"
@release.send(:resolve_next_version, "1.0.0").should == 'ze_next_version'
end
it 'should return the version specified by next_version if next_version is a proc' do
Release.next_version = lambda {|version| "#{version}++"}
@release.send(:resolve_next_version, "1.0.0").should == '1.0.0++'
end
it "should return the version specified by 'NEXT_VERSION' env var even if next_version is non nil" do
ENV['NEXT_VERSION'] = "ze_version_from_env"
Release.next_version = lambda {|version| "#{version}++"}
@release.send(:resolve_next_version, "1.0.0").should == 'ze_version_from_env'
end
it "should return the version specified by 'next_version' env var even if next_version is non nil" do
ENV['NEXT_VERSION'] = nil
ENV['next_version'] = "ze_version_from_env_lowercase"
Release.next_version = lambda {|version| "#{version}++"}
@release.send(:resolve_next_version, "1.0.0").should == 'ze_version_from_env_lowercase'
end
after {
Release.next_version = nil
ENV['NEXT_VERSION'] = nil
ENV['next_version'] = nil
}
end
describe '#resolve_tag' do
before do
@release.stub(:extract_version).and_return('1.0.0')
end
it 'should return tag specified by tag_name' do
Release.tag_name = 'first'
@release.send(:resolve_tag).should == 'first'
end
it 'should use tag returned by tag_name if tag_name is a proc' do
Release.tag_name = lambda { |version| "buildr-#{version}" }
@release.send(:resolve_tag).should == 'buildr-1.0.0'
end
after { Release.tag_name = nil }
end
describe '#tag_release' do
it 'should inform the user' do
@release.stub(:extract_version).and_return('1.0.0')
lambda { @release.tag_release('1.0.0') }.should show_info('Tagging release 1.0.0')
end
end
describe '#extract_version' do
it 'should extract VERSION_NUMBER with single quotes' do
write 'buildfile', "VERSION_NUMBER = '1.0.0-SNAPSHOT'"
@release.extract_version.should == '1.0.0-SNAPSHOT'
end
it 'should extract VERSION_NUMBER with double quotes' do
write 'buildfile', %{VERSION_NUMBER = "1.0.1-SNAPSHOT"}
@release.extract_version.should == '1.0.1-SNAPSHOT'
end
it 'should extract VERSION_NUMBER without any spaces' do
write 'buildfile', "VERSION_NUMBER='1.0.2-SNAPSHOT'"
@release.extract_version.should == '1.0.2-SNAPSHOT'
end
it 'should extract THIS_VERSION as an alternative to VERSION_NUMBER' do
write 'buildfile', "THIS_VERSION = '1.0.3-SNAPSHOT'"
@release.extract_version.should == '1.0.3-SNAPSHOT'
end
it 'should complain if no current version number' do
write 'buildfile', 'define foo'
lambda { @release.extract_version }.should raise_error('Looking for THIS_VERSION = "..." in your Buildfile, none found')
end
it 'should use version.rb instead of buildfile, if present' do
write 'version.rb', "VERSION_NUMBER = '1.0.0-SNAPSHOT'"
@release.extract_version.should == '1.0.0-SNAPSHOT'
end
it 'should complain if there is a version.rb file, but it contains no version number' do
write 'version.rb', "#SOMETHING SOMETHING"
lambda { @release.extract_version }.should raise_error('Looking for THIS_VERSION = "..." in your Buildfile, none found')
end
end
describe '#with_release_candidate_version' do
before do
Buildr.application.stub(:buildfile).and_return(file('buildfile'))
write 'buildfile', "THIS_VERSION = '1.1.0-SNAPSHOT'"
end
it 'should yield the name of the release candidate buildfile' do
@release.send :with_release_candidate_version do |new_filename|
File.read(new_filename).should == %{THIS_VERSION = "1.1.0"}
end
end
it 'should yield a name different from the original buildfile' do
@release.send :with_release_candidate_version do |new_filename|
new_filename.should_not point_to_path('buildfile')
end
end
end
describe '#update_version_to_next' do
before do
write 'buildfile', "VERSION_NUMBER = '1.0.5-SNAPSHOT'"
@release.send(:this_version=, "1.0.5-SNAPSHOT")
end
it 'should update the buildfile with a new version number' do
@release.send :update_version_to_next
`cp buildfile /tmp/out`
file('buildfile').should contain('VERSION_NUMBER = "1.0.6-SNAPSHOT"')
end
it 'should commit the new buildfile on the trunk' do
@release.should_receive(:message).and_return('Changed version number to 1.0.1-SNAPSHOT')
@release.update_version_to_next
end
it 'should use the commit message specified by commit_message' do
Release.commit_message = 'Here is my custom message'
@release.should_receive(:message).and_return('Here is my custom message')
@release.update_version_to_next
end
it 'should use the commit message returned by commit_message if commit_message is a proc' do
Release.commit_message = lambda { |new_version|
new_version.should == '1.0.1-SNAPSHOT'
"increment version number to #{new_version}"
}
@release.should_receive(:message).and_return('increment version number to 1.0.1-SNAPSHOT')
@release.update_version_to_next
end
it 'should inform the user of the new version' do
lambda { @release.update_version_to_next }.should show_info('Current version is now 1.0.6-SNAPSHOT')
end
after { Release.commit_message = nil }
end
describe '#check' do
before { @release.send(:this_version=, "1.0.0-SNAPSHOT") }
it 'should fail if THIS_VERSION equals the next_version' do
@release.stub(:resolve_next_version).and_return('1.0.0-SNAPSHOT')
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")
end
end
end
describe HgRelease do
it_should_behave_like 'a release process'
before do
write 'buildfile', "VERSION_NUMBER = '1.0.0-SNAPSHOT'"
@release = HgRelease.new
Hg.stub(:hg)
Hg.stub(:remote).and_return('https://bitbucket.org/sample-repo')
Hg.stub(:current_branch).and_return('default')
end
describe '#applies_to?' do
it 'should reject a non-hg repo' do
Dir.chdir(Dir.tmpdir) do
HgRelease.applies_to?.should be_false
end
end
it 'should accept a hg repo' do
FileUtils.mkdir '.hg'
FileUtils.touch File.join('.hg', 'requires')
HgRelease.applies_to?.should be_true
end
end
describe '#check' do
before do
@release = HgRelease.new
@release.send(:this_version=, '1.0.0-SNAPSHOT')
end
it 'should accept a clean repo' do
Hg.should_receive(:uncommitted_files).and_return([])
Hg.should_receive(:remote).and_return(["http://bitbucket.org/sample-repo"])
lambda { @release.check }.should_not raise_error
end
it 'should reject a dirty repo' do
Hg.should_receive(:uncommitted_files).and_return(['dirty_file.txt'])
lambda { @release.check }.should raise_error(RuntimeError, /uncommitted files/i)
end
it 'should reject a local branch not tracking a remote repo' do
Hg.should_receive(:uncommitted_files).and_return([])
Hg.should_receive(:remote).and_return([])
lambda{ @release.check }.should raise_error(RuntimeError,
"You are releasing from a local branch that does not track a remote!")
end
end
end
describe GitRelease do
it_should_behave_like 'a release process'
before do
write 'buildfile', "VERSION_NUMBER = '1.0.0-SNAPSHOT'"
@release = GitRelease.new
Git.stub(:git)
Git.stub(:current_branch).and_return('master')
end
describe '#applies_to?' do
# TravisCI seems to place the tmp directory
# sub-ordinate to git repository so this will not work
unless ENV['TRAVIS_BUILD_ID']
it 'should reject a non-git repo' do
Dir.chdir(Dir.tmpdir) do
GitRelease.applies_to?.should be_false
end
end
end
it 'should accept a git repo' do
FileUtils.mkdir '.git'
FileUtils.touch File.join('.git', 'config')
GitRelease.applies_to?.should be_true
end
end
describe '#check' do
before do
@release = GitRelease.new
@release.send(:this_version=, '1.0.0-SNAPSHOT')
end
it 'should accept a clean repository' do
Git.should_receive(:`).with('git status').and_return <<-EOF
# On branch master
nothing to commit (working directory clean)
EOF
Git.should_receive(:remote).and_return('master')
lambda { @release.check }.should_not raise_error
end
it 'should reject a dirty repository' do
Git.should_receive(:`).with('git status').and_return <<-EOF
# On branch master
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
# foo.temp
EOF
lambda { @release.check }.should raise_error(RuntimeError, /uncommitted files/i)
end
it 'should reject a repository not tracking remote branch' do
Git.should_receive(:uncommitted_files).and_return([])
Git.should_receive(:remote).and_return(nil)
lambda{ @release.check }.should raise_error(RuntimeError,
"You are releasing from a local branch that does not track a remote!")
end
end
describe '#tag_release' do
before do
@release = GitRelease.new
@release.stub(:extract_version).and_return('1.0.1')
@release.stub(:resolve_tag).and_return('TEST_TAG')
Git.stub(:git).with('tag', '-a', 'TEST_TAG', '-m', '[buildr] Cutting release TEST_TAG')
Git.stub(:git).with('push', 'origin', 'tag', 'TEST_TAG')
Git.stub(:commit)
Git.stub(:push)
Git.stub(:remote).and_return('origin')
end
it 'should delete any existing tag with the same name' do
Git.should_receive(:git).with('tag', '-d', 'TEST_TAG')
Git.should_receive(:git).with('push', 'origin', ':refs/tags/TEST_TAG')
@release.tag_release 'TEST_TAG'
end
it 'should commit the buildfile before tagging' do
Git.should_receive(:commit).with(File.basename(Buildr.application.buildfile.to_s), "Changed version number to 1.0.1")
@release.tag_release 'TEST_TAG'
end
it 'should push the tag if a remote is tracked' do
Git.should_receive(:git).with('tag', '-d', 'TEST_TAG')
Git.should_receive(:git).with('push', 'origin', ':refs/tags/TEST_TAG')
Git.should_receive(:git).with('tag', '-a', 'TEST_TAG', '-m', '[buildr] Cutting release TEST_TAG')
Git.should_receive(:git).with('push', 'origin', 'tag', 'TEST_TAG')
@release.tag_release 'TEST_TAG'
end
it 'should NOT push the tag if no remote is tracked' do
Git.stub(:remote).and_return(nil)
Git.should_not_receive(:git).with('push', 'origin', 'tag', 'TEST_TAG')
@release.tag_release 'TEST_TAG'
end
end
end
describe SvnRelease do
it_should_behave_like 'a release process'
before do
write 'buildfile', "VERSION_NUMBER = '1.0.0-SNAPSHOT'"
@release = SvnRelease.new
Svn.stub(:svn)
Svn.stub(:repo_url).and_return('http://my.repo.org/foo/trunk')
Svn.stub(:tag)
end
describe '#applies_to?' do
it 'should reject a non-git repo' do
SvnRelease.applies_to?.should be_false
end
it 'should accept a git repo' do
FileUtils.touch '.svn'
SvnRelease.applies_to?.should be_true
end
end
describe '#check' do
before do
Svn.stub(:uncommitted_files).and_return([])
@release = SvnRelease.new
@release.send(:this_version=, "1.0.0-SNAPSHOT")
end
it 'should accept to release from the trunk' do
Svn.stub(:repo_url).and_return('http://my.repo.org/foo/trunk')
lambda { @release.check }.should_not raise_error
end
it 'should accept to release from a branch' do
Svn.stub(:repo_url).and_return('http://my.repo.org/foo/branches/1.0')
lambda { @release.check }.should_not raise_error
end
it 'should reject releasing from a tag' do
Svn.stub(:repo_url).and_return('http://my.repo.org/foo/tags/1.0.0')
lambda { @release.check }.should raise_error(RuntimeError, "SVN URL must contain 'trunk' or 'branches/...'")
end
it 'should reject a non standard repository layout' do
Svn.stub(:repo_url).and_return('http://my.repo.org/foo/bar')
lambda { @release.check }.should raise_error(RuntimeError, "SVN URL must contain 'trunk' or 'branches/...'")
end
it 'should reject an uncommitted file' do
Svn.stub(:repo_url).and_return('http://my.repo.org/foo/trunk')
Svn.stub(:uncommitted_files).and_return(['foo.rb'])
lambda { @release.check }.should raise_error(RuntimeError,
"Uncommitted files violate the First Principle Of Release!\n" +
"foo.rb")
end
end
end