-
Bug
-
Resolution: Unresolved
-
Minor
-
None
When using Pipeline Multibranch with a Pipeline script that checkout the branch scm and also a different branch of the same repo later on, the next build changelog contains all commit history (bounded to a maximum).
Here is a sample scenario:
- Use a Jenkinsfile like the following (you may use the declarative default checkout or not):
// With declarative default checkout pipeline { agent any stages { stage('Other Checkout') { steps { checkout([$class: 'GitSCM', branches: [[name: '*/otherBranch']], userRemoteConfigs: [[credentialsId: 'myCreds', name: 'origin', refspec: '+refs/heads/otherBranch:refs/remotes/origin/otherBranch', url: env.GIT_URL]] ]) } } } } // With explicit checkout scm // pipeline { // agent any // options { // skipDefaultCheckout() // } // stages { // stage('Checkout') { // steps { // checkout scm // } // } // stage('Other Checkout') { // steps { // // Must be the same repository // checkout([$class: 'GitSCM', // branches: [[name: '*/otherBranch']], // userRemoteConfigs: [[credentialsId: 'myCreds', name: 'origin', refspec: '+refs/heads/otherBranch:refs/remotes/origin/otherBranch', url: 'https://github.example.com/sameOwner/sameOwner.git']] // ]) // // Same problem if using git() // // git branch: 'otherBranch', credentialsId: 'myCreds', url: 'https://github.example.com/sameOwner/sameOwner.git' // } // } // } // }
- Create a Multibranch for this
- The first build shows no changelog (expected)
- The next builds (whether there is a change or not) shows the entire build history in the change log
Evidence
While collecting some evidence, I noticed that the git whatchanged command that is launched to calculate the changelog of the main branch (the one from checkout scm) refers to a commit of the other branch that is checked out.
Looking through the code, I narrowed this down to the SpecificRevisionBuildChooser that just returns the last recorded git build data when asked for the previous build revision of a branch.
The GitSCM#computeChangeLog kind of assume that the revision returned by the chooser is valid if found in the repo.
In the scenario shown above, the last git build data is from a different branch. While it exists in the repo apparently, it is from a different branch. In the console output we see something like this where 4e1243bd22c66e76c2ba9eddc1f91394e57f9f83 is from the branch of the checkout scm and d185a06ad42d21210864bb1abddf60289dfc59de is from the checkout of the otherBranch from the last build. Not even in the history of branch of interest...:
> git checkout -f 4e1243bd22c66e76c2ba9eddc1f91394e57f9f83 # timeout=10
> git branch -a -v --no-abbrev # timeout=10
> git checkout -b master 4e1243bd22c66e76c2ba9eddc1f91394e57f9f83 # timeout=10
Commit message: "[test] update"
> git rev-list --no-walk d185a06ad42d21210864bb1abddf60289dfc59de # timeout=10
Workaround
A workaround might be to not rely on git / checkout step for the checkout of other branches. For example:
def withGitCredentials(String credentialsId, Closure body) { withCredentials([usernamePassword(credentialsId: credentialsId, passwordVariable: 'GIT_PASSWORD', usernameVariable: 'GIT_USERNAME')]) { // Must be inside a git directory otherwise this would fail sh 'git config --local credential.helper \'!f() { [ -z \"$GIT_ASKPASS\" ] && printf \"username=$GIT_USERNAME\npassword=$GIT_PASSWORD\"; }; f\'' try { body() } finally { sh "git config --local --unset credential.helper" } } } pipeline { agent any stages { stage('Other Checkout') { steps { withGitCredentials('myCreds') { sh ''' git fetch --force --progress -- $GIT_URL +refs/heads/otherBranch:refs/remotes/origin/otherBranch git checkout otherBranch ''' } } } } }