Category Archives: Agile

Using cruisecontrol.rb with repositories without anonymous access

I decided to use cruisecontrol.rb for continuous integration of an application that I’m working on at Bezurk. So I downloaded the 1.2.1 release from RubyForge and proceeded to add the project repository to the local installation of cruisecontrol.rb.

douglas@macbookpro:~$ ./cruise add MyProject --url http://path.to/repository --username 'douglas' --password 'guessable'
douglas@macbookpro:~$ ./cruise build MyProject
Builder for project 'MyProject' started
Logging to: /Users/douglas/Development/Ruby/cruisecontrolrb-1.2.1/log/MyProject_builder.log
Build loop failed
BuilderError: svn: PROPFIND request failed on '/svn/my_project/trunk'
./script/../config/../app/models/subversion.rb:98:in `execute_in_local_copy'
./script/../config/../lib/command_line.rb:86:in `call'
./script/../config/../lib/command_line.rb:86:in `e'
./script/../config/../lib/command_line.rb:84:in `popen'
./script/../config/../lib/command_line.rb:84:in `e'
./script/../config/../lib/command_line.rb:71:in `execute'
./script/../config/../lib/command_line.rb:70:in `chdir'
./script/../config/../lib/command_line.rb:70:in `execute'
./script/../config/../app/models/subversion.rb:89:in `execute_in_local_copy'
./script/../config/../app/models/subversion.rb:85:in `chdir'
./script/../config/../app/models/subversion.rb:85:in `execute_in_local_copy'
./script/../config/../app/models/subversion.rb:44:in `latest_revision'
./script/../config/../app/models/project.rb:228:in `new_revisions'
./script/../config/../app/models/change_in_source_control_trigger.rb:8:in `revisions_to_build'
./script/../config/../vendor/rails/actionpack/lib/../../activesupport/lib/active_support/core_ext/symbol.rb:10:in `__send__'
./script/../config/../vendor/rails/actionpack/lib/../../activesupport/lib/active_support/core_ext/symbol.rb:10:in `to_proc'
./script/../config/../app/models/project.rb:223:in `collect'
./script/../config/../app/models/project.rb:223:in `revisions_to_build'
./script/../config/../app/models/project.rb:202:in `build_if_necessary'
./script/../config/../app/models/polling_scheduler.rb:13:in `run'
./script/builder:79
./script/builder:78:in `catch'
./script/builder:78
./cruise:14:in `load'
./cruise:14:in `builder'
./cruise:68:in `send'
./cruise:68
/opt/local/lib/ruby/1.8/fileutils.rb:121:in `chdir'
/opt/local/lib/ruby/1.8/fileutils.rb:121:in `cd'
./cruise:67

Hmm, what’s with the svn: PROPFIND error? Looking at the stracktrace doesn’t tell me alot about what’s going wrong here, let’s try logging errors to the console.

--SNIP--
douglas$ svn --non-interactive info --xml
douglas$ svn --non-interactive log --revision HEAD:20 --verbose --xml
svn: PROPFIND request failed on '/repository/trunk'
svn: PROPFIND of '/repository/trunk': authorization failed (http://svnhost.com)
--SNIP--

It happens that my repository does not have anonymous access and requires a subversion user account to do anything useful. So it should be obvious that cruisecontrol.rb is trying to get log info from the repository but subversion is quitting with authentication errors because no user credentials are being supplied.

I need to have cruisecontrol.rb make use of the –username and –password options when making queries to the repository when I give it the credentials for access.

My first stop is the app/models/subversion.rb. Only the checkout method uses the username and password instance variables. Subversion should only include the –username and –password options when executing svn commands when both the username and password instance variables are present.

[ruby]
test/unit/subversion_test.rb

def test_svn_command_uses_user_password_when_provided
	svn = Subversion.new(:username => 'jer', :password => "crap")

	svn.expects(:info).with(dummy_project).returns(Subversion::Info.new(10, 10))
	svn.expects(:execute).with(["svn", "--non-interactive", "log", "--revision", "HEAD:10", "--verbose", "--xml",
								"--username", "jer", "--password", "crap"],
								{:stderr => './svn.err'}).yields(StringIO.new(LOG_ENTRY))

	svn.latest_revision(dummy_project)
end

app/models/subversion.rb

def checkout(target_directory, revision = nil, stdout = $stdout)
	@url or raise 'URL not specified'

	options = [@url, target_directory]
	options < < "--revision" << revision_number(revision) if revision

	# need to read from command output, because otherwise tests break
	execute(svn('co', options)) do |io|
	begin
		while line = io.gets
			stdout.puts line
		end
		rescue EOFError
		end
	end
end

def svn(operation, *options)
	command = ["svn"]
	command << "--non-interactive" unless @interactive
	command << operation
	command += options.compact.flatten
	command += ['--username', @username, '--password', @password] if @username and @password
	command
end
[/ruby]

The username and password would then be injected into the project’s Subversion instance in the cruise_config.rb file for each project.

[ruby]
Project.configure do |project|
    project.source_control.username = 'douglas'
    project.source_control.password = 'guessable'
end
[/ruby]

I’ve submitted a ticket along with a patch for this on cruisecontrol.rb’s tracker. Keep a lookout for it if you happen to encounter the same problem.