Search code examples
jenkinsjenkins-workflow

Jenkins workflow (pipeline) - build job only when there are SCM changes


I'm creating quite complicated workflow using the workflow-plugin (Renamed to Pipeline Plugin). For simplicity let's assume I need to build a job, but this job is quite expensive and it doesn't need to be build every time. Only when there are some SCM changes.

So let's call this job expensiveJob and it's Source Code Management there is SCMRepositoryA.

So I basically want to say

build job: 'expensiveJob'

And I want to poll for SCM changes and build the job based on that information.

Is there a way how to do this?

My current solution is that I have to checkout in pipeline script the SCMRepositoryA and then check the currentBuild.rawBuild.changeSets seems to me like quite a lot of unnecessary work and possibly have to align with whatever Source Code Management changes in my jobs..


Solution

  • There is not currently an equivalent of the build step that would merely initiate polling, as opposed to unconditionally scheduling a build.

    Writing such a step, or making it an option of the build step, would not be particularly difficult I think. In the meantime, for a non-sandboxed script, you could do the same with direct Jenkins API calls: if the downstream project had a configured SCM trigger (need only poll @daily, or have no schedule at all), then

    Jenkins.instance.getItemByFullName('downstream').SCMTrigger.run()
    

    would probably suffice to schedule polling immediately (untested). Alternately, if you wanted to run the polling directly, or did not want to assume even a blank `SCMTrigger, then

    if (Jenkins.instance.getItemByFullName('downstream').poll(TaskListener.NULL).hasChanges()) {
        build 'downstream'
    }
    

    (again untested) could work. The API calls would probably need to be wrapped in a @NonCPS method, though, since intermediate results are not Serializable:

    if (poll('downstream')) {
        build 'downstream'
    }
    @NonCPS boolean poll(String job) {
        Jenkins.instance.getItemByFullName(job).poll(TaskListener.NULL).hasChanges()
    }