Tag a Repo from a Jenkins Workflow Script

2019-03-18 14:05发布

问题:

I'm currently trying to tag a repo from a Jenkins Workflow script. I've tried using a sh step but this runs into problems because of credentials not being set.

fatal: could not read Username for 'https://<repo>': Device not configured

Is there an existing step that can be used either to tag a repo or to get round the credentials problem?

回答1:

I've managed to get this working by using the withCredentials step provided by the credentials binding plugin.

Its not great because it involved specifying it all in the URL but these values are masked in the console output.

withCredentials([[$class: 'UsernamePasswordMultiBinding', credentialsId: 'MyID', usernameVariable: 'GIT_USERNAME', passwordVariable: 'GIT_PASSWORD']]) {

    sh("git tag -a some_tag -m 'Jenkins'")
    sh("git push https://${env.GIT_USERNAME}:${env.GIT_PASSWORD}@<REPO> --tags")
}


回答2:

Here's an alternative that does not require knowing the URL of the remote:

try {
  withCredentials([[$class: 'UsernamePasswordMultiBinding', credentialsId: 'MyID', usernameVariable: 'GIT_USERNAME', passwordVariable: 'GIT_PASSWORD']]) {
    sh("${git} config credential.username ${env.GIT_USERNAME}")
    sh("${git} config credential.helper '!echo password=\$GIT_PASSWORD; echo'")
    sh("GIT_ASKPASS=true ${git} push origin --tags")
  }
} finally {
    sh("${git} config --unset credential.username")
    sh("${git} config --unset credential.helper")
}

This works by having git read the username from the config, and let the credential helper supply the password only. The extra echo at the end is for making the command that git passes as an argument to the helper not end up on the same line as the password.



回答3:

If your git password contains special characters such as "%", ":", "@", or "/", passing ${env.GIT_PASSWORD} as part of the git url ie https://${env.GIT_USERNAME}:${env.GIT_PASSWORD}@<REPO> without doing any encoding is likely to result in an Invalid username or password error.

To save any hassle using an inline credential.helper is a better way to go however the suggestion of !echo password=\$GIT_PASSWORD; echo' will result in a warning in your build logs warning: invalid credential line: get as the credential.helper is passed an argument to indicate the required operation (get,store,erase). In this case the credential helper is trying to interpret the get operation as a credential input. Valid inputs are protocol,host,path,username,password,url. See https://git-scm.com/docs/git-credential#IOFMT

A better inline credential.helper would be !f() { echo password=\$GIT_PASSWORD; }; f This way the credential.helper operation get is ignored.

Full example:

try {
  withCredentials([[$class: 'UsernamePasswordMultiBinding', credentialsId: 'MyID', usernameVariable: 'GIT_USERNAME', passwordVariable: 'GIT_PASSWORD']]) {
    sh("${git} config credential.username ${env.GIT_USERNAME}")
    sh("${git} config credential.helper '!f() { echo password=\$GIT_PASSWORD; }; f'")
    sh("GIT_ASKPASS=true ${git} push origin --tags")    
  }
} finally {
    sh("${git} config --unset credential.username")
    sh("${git} config --unset credential.helper")
}


回答4:

You can create your own personal API token (OAuth) and use it the same way as you would use your normal credentials (at: /settings/tokens). For example:

git tag -a some_tag -m 'Jenkins'
git push https://4UTHT0KEN@github.com/foo/bar


回答5:

So I tried the solution of @user3617723 but from some reason something was missing. after a while I found my issue. I have an upper job which responsible to pull the git repo and trigger the pipeline job with my workflow script which has different workspace:

//use the jenkins global credential id and create the env parametrs of GIT_PASSWORD and GIT_PASSWORD
withCredentials([[$class: 'UsernamePasswordMultiBinding', credentialsId: 'cred-github', usernameVariable: 'GIT_USERNAME', passwordVariable: 'GIT_PASSWORD']]) {

//change directory to the work dir with the ".git" files and create tags
sh("cd ${MANAGER_WORKSPACE} ; git tag -a v-${props.'VERSION_NUMBER'} -m ${BUILD_URL}")

//get only the url after the https
giturl_push = GIT_URL.split("//")[1]

// change directory to the work dir with the ".git" files and push the tags to the repo
sh("cd ${MANAGER_WORKSPACE} ; git push https://${env.GIT_USERNAME}:${env.GIT_PASSWORD}@${giturl_push} --tags")




}


回答6:

The following works for me

checkout scm

... build ... 

sh("git tag -a $branch-$buildVersion -m 'Jenkins tagging'");
sh("git push origin --tags")

I guess that it depends how the checkout is configured and if it somehow keeps the git credentials configured for the rest of the script.