I have a bunch of interrelated jobs that do Maven releases.  For
various reasons, they're not using the Jenkins release plugin, but
rather invoke mvn release:prepare release:perform as one of a sequence
of steps.  I have all the jobs linked together using build triggers,
so if you run one of these release jobs, it knows which others depend
on it and need to be run afterward.  Before doing the release, each
job updates its pom.xml with the latest versions released by the
previous upstream jobs.

So far so good, that all works perfectly.  But, I wanted to automate
one more piece.  Currently, you have to know which parts of the
project have been updated since the last release, and manually start
those releases.  It seems like all the information is available to
Jenkins to figure that out for me, though.  It knows when each job
ran, it has hooks to talk to the SCM to find out if new changes have
been checked in, so a simple Groovy script should suffice.  But
there's a catch.

Maybe this would work with other SCMs, but I'm using svn, and here's
what happens.  When I run one of my release jobs, Jenkins first does
an SCM update to pull down all the changes.  Then it does the release,
which checks in two changes to the pom.xml file.  The state of the
workspace has now changed - the SCM revision that Jenkins originally
pulled down isn't the latest any more, it's been bumped twice.  The
workspace knows this, but I think Jenkins doesn't.  The svn plugin
keeps a file around called revision.txt, and this file appears to be a
cache of what revision the workspace is at.  So, in my Groovy script,
when I ask Jenkins whether that job has SCM changes, and therefore
needs to be run, Jenkins always answers yes.  This is because it's
looking at revision.txt to figure out if the workspace needs updating,
and revision.txt is out of date -- it still thinks the workspace
doesn't have the two changes committed during the release.  My Groovy
script looks like this:

job = <passed to my function>
def latestBuild = job.getLastCompletedBuild();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
def listener = new hudson.model.StreamBuildListener(baos);
def launcher = new hudson.Launcher.LocalLauncher(listener);
def scmrev = job.scm.calcRevisionsFromBuild(latestBuild, launcher,
listener);
def pollingResult = job.scm.compareRemoteRevisionWith(job, launcher,
job.workspace, listener, scmrev);
return pollingResult.hasChanges();

I've tried to force the workspace to do a checkout, to update
revision.txt, but ironically, that takes the workspace backward in
time.  Here's the script I'm using:

job = <passed to my function>
def latestBuild = job.getLastCompletedBuild();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
def listener = new hudson.model.StreamBuildListener(baos);
def launcher = new hudson.Launcher.LocalLauncher(listener);
job.scm.checkout(latestBuild, launcher, job.workspace, listener,
File.createTempFile("tempcheckout", "txt"));

When it runs, it decides for some reason to refresh the workspace to
the state described in revision.txt, rather than the state in the
depot.

So, I'm hoping someone can tell me that I'm just looking at this the
wrong way, and there's a simple thing I can do to force revision.txt
to get updated after the mvn release finishes.  Or maybe there's some
other way to invoke checkout so that it updates revision.txt to match
the workspace, rather than the other way around.  Thanks.

-Joel

Reply via email to