3
votes

Goal

Build our repo more frequently for java changes and less frequently for docker base image changes.

Situation

We have two multibranch pipeline jobs: build-java and build-base-docker. We want the build-base-docker to trigger for master & feature branches only when pushes contain changes beneath /docker.

Approach

Following cloudbees How to Customize Checkout for Pipleine Multibranch? doc we implemented the changes below.

However, a changes to src/main/java/foo.java triggers the build-base-docker job for that branch when we'd don't want it to do so.

Is this really just JENKINS-36195 bug or am I doing something wrong which results in the unexpected trigger?

node('java-build') {

stage ('git checkout') {
    checkout([
            $class: 'GitSCM',
            branches: scm.branches,
            extensions: scm.extensions + [
                [$class: 'PathRestriction', excludedRegions: '.*', includedRegions: 'docker/.*']
            ],
            userRemoteConfigs: [[credentialsId: 'our-git-repo-deploy-key', url: '[email protected]:we/our-repo.git']]

    ])
}
...
}
1

1 Answers

3
votes

If Jenkins can't handle path restrictions on a multibranch pipelines well, then we do it from our pipeline code (or from a shared library to reduce duplication).

If we have multiple checkouts, this can get a little problematic as all will be reported. However, provided they don't use the same layout, the risk of false positives is low. E.g., the jenkins-shared-library usually sees changes beneath /vars dir not docker.

node() {
    if ( ! doChangesRequireBuild('^docker/.*')) {
        currentBuild.result = 'ABORTED'
        return 'Changes not made to docker/... base image files. Aborting build'
    }
}

/**
 * Provide List of changed file paths since last successful build
 */
def getChangedFiles() {
    def found = []

    for (def changeSet in currentBuild.getChangeSets()) {
        for (def change in changeSet.logs) {
            for (def path in change.paths) {
                found.add(path.path)
            }
        }
    }
    return found
}

/**
 * do changes since last successful build mandate a build?
 * @param pathRegex path restriction regex pattern
 * @return true if any file paths match the regex
 */
boolean doChangesRequireBuild(def pathRegex) {

    for (def path in getChangedFiles()) {
        if ( path ==~ pathRegex) {
            return true
        }
    }
    return false
}