18

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?

user3617723
  • 1,355
  • 3
  • 17
  • 37

5 Answers5

24

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")
}
user3617723
  • 1,355
  • 3
  • 17
  • 37
  • 1
    That is your best bet for now. [JENKINS-28335](https://issues.jenkins-ci.org/browse/JENKINS-28335) suggests a more convenient system. – Jesse Glick Nov 17 '15 at 01:30
  • 2
    I confirm that using [`sshagent(['git-credentials-id'])`](https://issues.jenkins-ci.org/browse/JENKINS-28335?focusedCommentId=269000&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-269000) does work and is a bit easier. I used it [here](http://stackoverflow.com/questions/40618449/how-to-checkout-ssh-remote-in-github-organization-and-use-ssh-credentials-in-jen) – GabLeRoux Nov 15 '16 at 20:41
  • The values may be masked in the console output, but anyone who has access to the machine can read the password from the process command-line. Let's hope we get a secure alternative soon! – Gili Dec 01 '16 at 21:14
  • 1
    If your password contains special characters, like the '@' for example, using it directly in the URL will not work. You can then set the password in the git-credentials like in Magnus Reftel's answer and pushing to the url like this: `GIT_ASKPASS=true git push http://${env.GIT_USERNAME}@some-git-server.com/some-project.git HEAD:master`. – Leon S. Apr 06 '17 at 08:51
  • Finally got his working. My problem, was that I had other git operations inside the "withCredentials" block. Like cloning, etc. Putting the tag operations (tag, then push), inside another withCredentials block got it working. – Eric Manley Apr 21 '17 at 18:55
  • 1
    The Answer by Magnus Reftler is much better. It supports passwords with any characters – herm Jul 25 '17 at 16:02
  • This worked for me. And I solved the "involved specifying it all in the URL" mentioned by user3617723 to match my needs: Add this to environment section -> REPO = sh(returnStdout: true, script: 'echo ${GIT_URL#*https://}').trim() – Lovato Apr 05 '19 at 13:37
15

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.

Magnus Reftel
  • 967
  • 6
  • 19
12

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")
}
Evan McLean
  • 121
  • 1
  • 2
  • 1
    I've been using this solution so far and it works fine however we get intermittent issues and it seems to be a racing condition. I think adding `sleep 2` to `credential.helper` can help to fix the intermittent issue – xbmono Oct 08 '19 at 03:18
2

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
kenorb
  • 155,785
  • 88
  • 678
  • 743
0

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")




}
dsaydon
  • 4,421
  • 6
  • 48
  • 52