Last Thursday I wrote about the kind of chained builds functionality that I want from CruiseControl.rb. I think I’ve got it hacked in, at least to the “good enough” stage.
The first big change was to change the @trigger instance variable for the Project class from a single trigger to an array of triggers. I modified its name to @triggers to reflect this change. So in the initialize method for the Project class, instead of saying:
@trigger = ChangeInSourceControlTrigger.new
We now say this:
@triggers = [ChangeInSourceControlTrigger.new]
Next, I modified the
buildifnecessary method to collect information from all of the triggers about which revisions need to be built.
revisions = []
@triggers.each { |trigger| revisions += trigger.getrevisionstobuild(self) }
revisions = revisions.uniq.sort
if revisions.empty?
...
I also made a change to the
triggeredby method for the
Project class so that it accepts multiple triggers, and so that it always adds triggers to the existing set (instead of replacing them). Here’s what my modified version of
triggeredby looks like.
def triggeredby(*things)
things.each do |thing|
if thing.is_a?(String) || thing.is_a?(Symbol)
@triggers << SuccessfulBuildTrigger.new(thing)
else
@triggers << thing
end
end
This allows me to declare dependencies in my
cruise_config.rb file like so:
project.triggered_by 'projectA', 'projectB', 'projectC'
I had to modify the logic
get_revisions_to_build method for the
SuccessfulBuildTrigger class a little bit, so that it wouldn’t return any build numbers from triggering projects that were older than the latest build of the “triggered” project. Here’s what that block looks like now.
if last_successful_build.nil? || project.find_build(last_successful_build.label)
[]
elsif project.last_build && project.last_build.label.to_i >= last_successful_build.label.to_i
[]
else
[Revision.new[last_successful_build.label]
end
The last step was to add the
spaceship operator to the
Revision class, so that I can sort arrays of them.
def <=>(other)
number.to_i <=> other.number.to_i
end
Note that the
number attribute for the
Revision class sometimes refer to an integer, and other times to a string. I suspect that this is a bug, but calling
to_i on it does the trick for this purpose.
It took a bit of experimenting to get it right, but this seems to be working properly now. It took maybe a couple of hours to get it working, and the code was easy to read and understand.