Update 2019/03/22:
Quick anser
Use a refspec which fits your git server's PR handling. E.g. for Bitbucket that could be:
+refs/pull-requests/*/merge:refs/remotes/@{remote}/PR-*
Full Answer
There is an open ticket about this:
https://issues.jenkins-ci.org/browse/JENKINS-52668?filter=18657
EDIT:
I was able to reproduce this issue using a Jenkins multibranch pipeline together with the github plugin and a manual call to the checkout
step.
For Bitbucket I found several options how to build PRs. I now even found a way to skip the conditional there. See below.
Recommendation
Whenever possible I'd recommend using checkout scm
which works for PRs easily.
If you need to use the checkout
step manually you could try to adjust your Jenkinsfile in order to do things manually as I did for checking out a bitbucket repo.
Easiest way should be to do a checkout scm
at least one time to see how it should be done and use that values accordingly in the manual checkout steps. You'll need some if condition for the case that you're not building a PR.
Github
I finally got my small sample project buildin PRs from github using the following code. For my quick test I did a PR from some branch. In case you're using a fork as source for the PR it may need some further adjustment.
As stated in https://mcmap.net/q/274658/-git-pullrequest-job-failed-couldn-39-t-find-any-revision-to-build-verify-the-repository-and-branch-configuration-for-this-job you can leave out 'branches to build' option to not get this error. However depending on your PR merge strategy you'd still need to configure the merge accordingly:
def isPr() {
env.CHANGE_ID != null
}
// github-specific refspec
def refspec = "+refs/pull/${env.CHANGE_ID}/head:refs/remotes/origin/PR-${env.CHANGE_ID} +refs/heads/master:refs/remotes/origin/master"
def url = 'https://github.com/orgi/workflow-durable-task-step-plugin.git'
def extensions = []
if (isPr()) {
extensions = [[$class: 'PreBuildMerge', options: [mergeRemote: "refs/remotes/origin", mergeTarget: "PR-${env.CHANGE_ID}"]]]
}
checkout([
$class: 'GitSCM',
doGenerateSubmoduleConfigurations: false,
extensions: extensions,
submoduleCfg: [],
userRemoteConfigs: [[
refspec: refspec,
credentialsId: '<your credentials>',
url: url
]]
])
Bitbucket
For bitbucket you have to do the almost the same. However you'll have the option to the merge commit done in bitbucket directly in which case you do not need to do the merge in Jenkins but need to switch to the PR branch instead.
You may either work with a conditional refspec or choose the branch conditionally. That makes four options a shown below. So far I didn't find an option which does not involve a conditional. :(
Recommended solutions
Following solutions to me seems most usable. They do not involve any conditionals and make use of the BRANCH_NAME
variable. However it occurred to me that sometimes I got an error about an invalid refspec. In those cases please use one of the alternative solutions as written below.
Using Bitbucket Merge
Use the merge which as prepared by the Bitbucket server
def respec = '+refs/heads/*:refs/remotes/origin/* +refs/pull-requests/*/merge:refs/remotes/origin/PR-*'
checkout([$class: 'GitSCM',
branches: [[name: env.BRANCH_NAME]],
doGenerateSubmoduleConfigurations: false,
submoduleCfg: [],
userRemoteConfigs: [[
refspec: respec,
url: '<repo URL>'
]]
])
Using Jenkins Merge
Or you decide to let Jenkins do the merge. You may either use a conditional refspec or a conditional merge into the PR.
def refspec = '+refs/heads/*:refs/remotes/origin/* +refs/pull-requests/*/merge:refs/remotes/origin/PR-*'
checkout([$class: 'GitSCM',
doGenerateSubmoduleConfigurations: false,
extensions: [[$class: 'PreBuildMerge', options: [mergeRemote: "refs/remotes/origin", mergeTarget: env.BRANCH_NAME]]],
submoduleCfg: [],
userRemoteConfigs: [[
refspec: refspec,
url: '<repo URL>'
]]
])
Shared library
To use PR branches alongside a global shared library it would seem like the most straight-forward way would be to use the Discover other refs
option when configuring the source control for your library. However that didn't work for me :(
To load a shared library from some pull request you have to do two things:
Add the following refspec to your shared library's Jenkins global configuration:
+refs/pull-requests/*/merge:refs/remotes/@{remote}/PR-*
Instead of just using env.BRANCH_NAME
you have to use"origin/${env.BRANCH_NAME}"
when loading that library, like:
libBranch = env.BRANCH_NAME
libId= "myLib@origin/${libBranch}"
lib = library(libId)
Alternative Solution using Bitbucket Merge
Conditional Refspec
Just as a fallback; I can remember that the refspec including the PRs sometimes didn't work for me. In that case you could use:
def isPr() {
env.CHANGE_ID != null
}
def respec = '+refs/heads/*:refs/remotes/origin/*'
if (isPr()) {
respec += ' +refs/pull-requests/*/merge:refs/remotes/origin/PR-*'
}
checkout([$class: 'GitSCM',
branches: [[name: env.BRANCH_NAME]],
doGenerateSubmoduleConfigurations: false,
submoduleCfg: [],
userRemoteConfigs: [[
refspec: respec,
url: '<repo URL>'
]]
])
Conditional Branch Name
def isPr() {
env.CHANGE_ID != null
}
def branch
if (isPr()) {
branch = "refs/remotes/origin/pull-requests/${env.CHANGE_ID}/merge"
} else {
branch = "*/master"
}
checkout([$class: 'GitSCM',
branches: [[name: branch]],
doGenerateSubmoduleConfigurations: false,
submoduleCfg: [],
userRemoteConfigs: [[
refspec: '+refs/heads/*:refs/remotes/origin/* +refs/pull-requests/*:refs/remotes/origin/pull-requests/*',
url: '<repo URL>'
]]
])
Alternative Solution using Merge in Jenkins
Conditional refspec
def isPr() {
env.CHANGE_ID != null
}
def refspec = '+refs/heads/*:refs/remotes/origin/*'
if (isPr()) {
refspec += ' +refs/pull-requests/*/merge:refs/remotes/origin/PR-*'
}
checkout([$class: 'GitSCM',
doGenerateSubmoduleConfigurations: false,
extensions: [[$class: 'PreBuildMerge', options: [mergeRemote: "refs/remotes/origin", mergeTarget: env.BRANCH_NAME]]],
submoduleCfg: [],
userRemoteConfigs: [[
refspec: refspec,
url: '<repo URL>'
]]
])
Conditional merge
def isPr() {
env.CHANGE_ID != null
}
def extensions = []
if (isPr()) {
extensions = [[$class: 'PreBuildMerge', options: [mergeRemote: "refs/remotes/origin/pull-requests", mergeTarget: "${env.CHANGE_ID}/from"]]]
}
checkout([$class: 'GitSCM',
doGenerateSubmoduleConfigurations: false,
extensions: extensions,
submoduleCfg: [],
userRemoteConfigs: [[
refspec: '+refs/heads/*:refs/remotes/origin/* +refs/pull-requests/*:refs/remotes/origin/pull-requests/*',
url: '<repo URL>'
]]
])