'script: "git rev-parse ${latestTag}^{commit}" fails in Jenkinsfile

Below line in Jenkinsfile

latestTagSHA1 = sh(returnStdout: true, script: "git rev-parse ${latestTag}^{commit}")

results in script.sh: ^{commit}: not found error.

Is there a way to escape ^{commit} part?

I tried to use ^\{commit\} to no avail.

It's important to note that i want to actually run command

git rev-parse ${latestTag}^{commit}, for example git rev-parse 2.0.0^{commit} where latestTag equals 2.0.0.

This command returns SHA1 of git tag. For example, for existing tagged commit 850d25580a894befbce6d922bee954c7669cf70c with tag 1.0 below command will return the SHA1 of the tag:

git rev-parse 1.0^{commit}
850d25580a894befbce6d922bee954c7669cf70c

added full Jenkinsfile using the failing line:

pipeline {
    agent  {
        node {
            label 'some_label'
            customWorkspace "workspace/${JOB_NAME}/${params.PROJECT}/${params.REPO_NAME}/${BUILD_NUMBER}/"
        }
    }

    parameters {
        string defaultValue: "${REPO_NAME}", name: 'REPO_NAME', trim: true
        string defaultValue: "${PROJECT}", name: 'PROJECT', trim: true
        string defaultValue: "${SRC_BRANCH_NAME}", name: 'SRC_BRANCH_NAME', trim: true
        string defaultValue: "${PR_MERGER_EMAIL}", name: 'PR_MERGER_EMAIL', trim: true
        string defaultValue: "${SHA1}", name: 'SHA1', trim: true
    }
    options {
        lock resource: "${params.REPO_NAME}" // lock on repo to avoid concurrent releases on the same repo
    }

    stages {
        stage("package") {
            steps {
                dir("/tmp/${params.PROJECT}/${params.REPO_NAME}") {                    
                    checkout(
                        [
                            $class: 'GitSCM',
                            branches: [[name: 'refs/heads/master']],
                            extensions: [
                                            [$class: 'LocalBranch', localBranch: "master"]
                                        ],
                            userRemoteConfigs: [[
                                    url: env.GIT_URL, credentialsId: "smth"
                                ]]
                        ]
                    )
                    script {                    
                        sh "cd /tmp/${params.PROJECT}/${params.REPO_NAME}"                    
                        latestTag = sh(returnStdout: true, script: "git describe --tags `git rev-list --tags --max-count=1`")
                        latestTagSHA1 = sh(returnStdout: true, script: "git rev-parse ${latestTag}^{commit}")
                        latestSHA1Timestamp = sh(returnStdout: true, script: "git show -s  --format='%ct' ${latestTagSHA1}")
                        currentCommitSHA1Timestamp = sh(returnStdout: true, script: "git show -s  --format='%ct' ${params.SHA1}")
                        if (latestSHA1Timestamp > currentCommitSHA1Timestamp) {
                            currentBuild.result = 'ABORTED'
                            error('some')
                        }
                    }
                }
            }
        }
    }
}


Solution 1:[1]

You don't have to escape anything in line that throws the error. The problem is that the sh step returns an output with a trailing newline.

returnStdout (optional)
If checked, standard output from the task is returned as the step value as a String, rather than being printed to the build log. (Standard error, if any, will still be printed to the log.) You will often want to call .trim() on the result to strip off a trailing newline.


Source: https://www.jenkins.io/doc/pipeline/steps/workflow-durable-task-step/#sh-shell-script

That is why what Jenkins is trying to execute in your case is:

git rev-parse 1.0.0
^{commit}

instead of

git rev-parse 1.0.0^{commit}

The solution to this problem is simple: when you return the output of the sh step, call trim() in the end to remove a trailing newline.

latestTag = sh(returnStdout: true, script: "git describe --tags `git rev-list --tags --max-count=1`").trim()

Keep in mind that you will have to trim the output of all variables that are later use as a part of the next command.

Solution 2:[2]

You can try: "git rev-parse ${latestTag}"^${commit}""

You need to add the $ for all variables you want to call

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Szymon Stepniak
Solution 2 DevOps QA