Shared library: determine SVN revision

Context:

  • a build job is a declarative pipeline, almost always part of a multibranch pipeline job
  • a Subversion checkout will have been performed either implicitly, or, if there are multiple parallel builds involved, via checkout scm: scm (with poll and changelog set to true for one of them, and false for the rest)

I now need to obtain the Subversion revision number corresponding to that checkout (for the main source, not any externals) from a shared pipeline function (currently just a groovy file in vars).

My existing approach is to run svnversion.
Drawback there is that this requires running a sh or bat step (depending on OS) with returnStdout: true; that feels like unnecessary extra overhead, and also causes these steps to be registered and visible in the pipeline info, and I would prefer to keep the internals of my function, well, internal.

So, first question: is there an exposed API that enables running a process on the current node and file path and capturing its output without having to go through a sh or bat step?

Alternatively, I could also try to get the revision directly from the SCM object.

Looking at SubversionSCM, there are 2 promising APIs:

  1. getRevisionFile() gives me a File object (pointing to a path like /var/lib/jenkins/jobs/…/branches/trunk/builds/17/revision.txt)

    However, this has two significant drawbacks:

    1. I need to pass a Run to getRevisionFile(), and the script approval is not happy about granting access to currentBuild.getRawBuild()
    2. while I can get its contents that way, I’d need to assume that the first line is the most relevant one, and would then also need to parse out the revision number (does not seem that hard, but I don’t know how official and document those file contents are).
  2. getLocations() gets me a list of locations, and it looks like scm.getLocations()[0].getRevision(null).getNumber() gets me what I want (obviously the real code would have size and null checks), but I’m not sure how guaranteed that information is, and whether it’s always the first one that has the info I need.

Which of these is the safest / most supported approach? Are there others?

Note that the Subversion plugin claims to set environment variables:

The Subversion SCM plugin exports the svn revisions and URLs of the build’s subversion modules as environment variables. These are $SVN_REVISION_n and $SVN_URL_n, where n is the 1-based index of the module in the configuration.

For backwards compatibility if there’s only a single module, its values are also exported as $SVN_REVISION and $SVN_URL.

which would be a lot more convenient to use. However, when I try

script {
  println env.SVN_REVISION
  println env.SVN_REVISION_1
  println env.SVN_REVISION_0
}

after the checkout step, they all print null (and without the env. they error out entirely).

Welcome back, @Zastai! :waving_hand:

You might find that the most straightforward and supported option in a Jenkins Pipeline is to rely on the environment variables provided by the Subversion plugin, typically SVN_REVISION. These are usually available when the Subversion checkout is done using the built-in checkout step. However, in multibranch pipelines, where the SCM checkout is handled differently, these variables may not always be set.

Here are a few alternative approaches you could consider:

  • Parsing the revision file:
    While technically possible, using getRevisionFile() isn’t usually recommended in Pipelines because it can require broader script permissions and direct access to build internals.
  • Using the SCM object:
    Some users experiment with calls like scm.getLocations()[0].getRevision(null).getNumber(), but this isn’t part of the documented or guaranteed API and might behave differently across plugin versions.
  • Running svnversion via sh or bat:
    This tends to be the most consistent approach across platforms. The downside is that it exposes internal details in the pipeline log, but in many cases, it’s a reasonable tradeoff for reliability.

In summary:
You might want to start by checking if the environment variables are being set automatically; that’s the cleanest and most future-proof option. If they aren’t available, running svnversion from a shell step is probably your safest fallback. Accessing Subversion internals directly from the SCM object or revision file tends to be less stable and isn’t generally recommended for production use.

Examples:

// Linux example using sh
def svnRevision = sh(script: 'svnversion .', returnStdout: true).trim()

// Using environment variable if it exists
def svnRevision = env.SVN_REVISION ?: env.SVN_REVISION_1

If the environment variable isn’t there, it might help to fall back to the shell-based command. There’s no officially supported Pipeline API for capturing this information without using sh or bat, but these methods should cover most use cases.

You might also save the return value of checkout scm. It returns name / value pairs that may already include the information that you are seeking.

I think I’ll try that, thanks; while it means that I can’t work with the implicit checkout, that’s not a terrible thing. I could even take relevant scm object as a parameter and do the checkout myself, keeping the calling pipeline simple.