Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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..

like image 928
vehovmar Avatar asked Feb 05 '16 15:02

vehovmar


2 Answers

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()
}
like image 138
Jesse Glick Avatar answered Nov 15 '22 09:11

Jesse Glick


Using the accepted answer, this is how I have setup my declarative pipeline to skip some expensive stages that depend on a job being up to date or not

stages {
    stage('Need to build?') {
        steps {
            script {
                env.changesPending = Jenkins.instance.getItemByFullName('expensive').poll(hudson.model.TaskListener.NULL).hasChanges()
                echo "env.changesPending=" +env.changesPending
            }
        }
    }
    stage('Pre-requisites') {
        when {
            expression { env.changesPending == true }
        }
        steps {
            build 'expensive'
        }
    }
    ...

This required several script authorizations in http://your-jenkins/scriptApproval/ before it worked

like image 37
xverges Avatar answered Nov 15 '22 10:11

xverges