简体   繁体   中英

Jenkins Pipeline Git commit message before scm checkout

I would like to be able to access the commit message in a Jenkins Pipeline before the actual checkout scm since I have huge repositories (>2GB) and many branches (>200) and for every branch the complete repo gets cloned again and I want to limit the amount of clones by filtering the commit messages for explicit "tags" (eg [ci] ). If you know a different approach that would solve my issue, please let me know.

Edit: I am using scripted jenkinsfiles and shared libraries with multibranch pipelines.. so I'm looking for a way to do that programmatically :)

Since I did not see any other way I did the following:

#!/usr/bin/env groovy

def getCommitMsg(branch, path_parent, path_mirror, url) {
    if (!(fileExists(path_mirror))) {
        echo "Directory $path_mirror doesn't exist, creating.."
        dir (path_parent) {
            bat("git clone --mirror $url mirror")
        }
    }
    dir (path_mirror) {
        bat("git fetch origin $branch:$branch")
        bat("git symbolic-ref HEAD refs/heads/$branch")
        return bat(script: "@git log -n 1 --pretty=format:'%%s'",
            returnStdout: true).trim().replaceAll("'","")
    }
}

def updateRepo(branch, path_parent, path_clone, url) {
    if (!(fileExists(path_clone))) {
        echo "Directory $path_clone doesn't exist, creating.."
        dir (path_parent) {
            bat("git clone --recurse-submodules $url clone")
        }
    }
    dir (path_clone) {
        bat("git pull")
    }
    dir (path_parent) {
        bat(script: "robocopy /MIR /NFL /NDL /NC /NS /NP " +
            path_clone + " " + path_parent + "\\" + branch.replaceAll("/","_"),
            returnStatus: true)
    }
}

node("some_label") {

    ws("workspace/${env.JOB_NAME}".replaceAll("%2F","_")) {

        def default_test = ["develop", "release", "feature/test"]
        def branch = env.BRANCH_NAME
        def path_current = bat(script: 'echo %CD%',
            returnStdout: true).split("\n")[2]        
        def path_parent = path_current.split("\\\\").dropRight(1).join("\\")
        def path_mirror = path_parent + "\\mirror"
        def path_clone = path_parent + "\\clone"
        def url = scm.userRemoteConfigs[0].url
        def commit = getCommitMsg(branch, path_parent, path_mirror, url)

        if (!(default_test.contains(branch)
            || commit.contains("[ci]"))) {
            echo "Branch should not be tested by default and commit message contains no [ci]-tag, aborting.."
            currentBuild.result = "FAILURE"
            return
        }

        stage("Checkout") {
            updateRepo(branch, path_parent, path_clone, url)
            checkout scm
        }

        stage("Build") {
            some stuff here
            }
        }

    }

}

This will parse the commit message in a mirror repo and also reduce the bandwidth on my bitbucket server since the repo will only be cloned once on each agent and then copied to other directories for each branch. This was the most useful approach for me. If you have questions, let me know :)

EDIT: I am parsing the Bitbucket REST API now, code looks like this:

// get commit hash
withCredentials([sshUserPrivateKey(credentialsId: 'SSH',
    keyFileVariable: 'SSHKEYFILE')]) {
    String commitHash = sh(script: """
        ssh-agent bash -c 'ssh-add ${env.SSHKEYFILE}; \
        git ls-remote ${url} refs/heads/${branch}'""",
        returnStdout: true).trim().split('\\s+')[0]

    echo("commitHash: ${commitHash}")
}

// create the curl url like this
String curlUrl = BBUrl + '/rest/api/1.0/projects/' + project + '/repos/' + repo + '/commits/' + commitHash

String commitMessage = null
withCredentials([usernameColonPassword(credentialsId: 'USERPASS',
    variable: 'USER_PASS')]) {

    String pwBase64 = "${env.USER_PASS}".bytes.encodeBase64().toString()
    String rawResponse = sh(script: """
        curl --request GET --url '${curlUrl}' \
        --header 'Authorization: Basic ${pwBase64}'""",
        returnStdout: true).trim()

    def rawMessage = readJSON(text: rawResponse)
    commitMessage = rawMessage.message
    echo("commitMessage: ${commitMessage}")
}

Just do that on a Jenkins master with curl installed, hope it helps..

You can use pre-scm-buildstep plugin

https://wiki.jenkins.io/display/JENKINS/pre-scm-buildstep

This plugin allows build step to run before SCM checkouts so that you perform any build step action on the the workspace, (cleanup, add a file with some settings for the SCM, etc) or call other scripts that need to be run before checking out from the SCM.

So basically, you can execute any command before SCM checkout/clone starts.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM