Jenkins 从 GitHub 构建 PR 失败

Jenkins build fail for PR from GitHub

我正在使用 jenkins 管道构建我的 github 项目。当我在 GitHub 上提出拉取请求 (PR) 时,它创建了一个工作 "pr-head"

一直失败并出现以下错误

如果您对此有任何建议,请告诉我

甚至 Git PullRequest job failed. Couldn't find any revision to build. Verify the repository and branch configuration for this job 中的答案也没有解决我的问题

2019/03/22 更新:

快答

使用适合您的 git 服务器 PR 处理的 refspec。例如。对于 Bitbucket,可能是:

+refs/pull-requests/*/merge:refs/remotes/@{remote}/PR-*

完整答案

有一个关于这个的公开票: https://issues.jenkins-ci.org/browse/JENKINS-52668?filter=18657

编辑:

我能够使用 Jenkins 多分支管道以及 github 插件和手动调用 checkout 步骤重现此问题。

对于 Bitbucket,我找到了几个构建 PR 的选项。我现在甚至找到了一种方法来跳过那里的条件。见下文。

推荐

如果可能,我建议使用 checkout scm,它很容易用于 PR。

如果您需要手动使用 checkout 步骤,您可以尝试调整 Jenkinsfile 以便手动执行操作,就像我检查 bitbucket 存储库时所做的那样。

最简单的方法应该是至少执行一次 checkout scm 以查看应该如何完成并在手动结帐步骤中相应地使用该值。如果您不构建 PR,则需要一些 if 条件。


Github

我终于使用以下代码从 github 获得了我的小型示例项目构建 PR。为了快速测试,我从某个分支做了一个 PR。如果您使用分叉作为 PR 的来源,则可能需要进一步调整。

如 中所述,您可以省略 'branches to build' 选项以避免出现此错误。但是,根据您的 PR 合并策略,您仍然需要相应地配置合并:

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,您必须执行几乎相同的操作。但是,您可以选择直接在 bitbucket 中完成合并提交,在这种情况下,您不需要在 Jenkins 中进行合并,而是需要切换到 PR 分支。 您可以使用条件 refspec 或有条件地选择分支。这使得四个选项如下所示。到目前为止,我还没有找到不涉及条件的选项。 :(

推荐的解决方案

以下解决方案对我来说似乎最有用。它们不涉及任何条件并使用 BRANCH_NAME 变量。然而,我突然想到,有时我会收到关于无效 refspec 的错误。在这些情况下,请使用下面所写的替代解决方案之一。

使用 Bitbucket 合并

使用 Bitbucket 服务器准备的合并

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>'
    ]]
])

使用詹金斯合并

或者您决定让 Jenkins 进行合并。您可以使用有条件的 refspec 或有条件的合并到 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>'
    ]]
])

共享库

要将 PR 分支与全局共享库一起使用,最直接的方法似乎是在为您的库配置源代码管理时使用 Discover other refs 选项。然而,这对我不起作用:(

要从某个拉取请求加载共享库,您必须做两件事:

  1. 将以下 refspec 添加到共享库的 Jenkins 全局配置中:

    +refs/pull-requests/*/merge:refs/remotes/@{remote}/PR-*
    
  2. 加载该库时,您必须使用"origin/${env.BRANCH_NAME}"而不是仅使用env.BRANCH_NAME,例如:

    libBranch = env.BRANCH_NAME
    libId= "myLib@origin/${libBranch}"
    lib = library(libId)
    

使用 Bitbucket Merge 的替代解决方案

有条件的 Refspec

作为备用;我记得包括 PR 在内的 refspec 有时对我不起作用。在这种情况下,您可以使用:

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>'
    ]]
])

条件分支名称

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>'
    ]]
])

在 Jenkins 中使用 Merge 的替代解决方案

条件参考规范

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>'
    ]]
])

条件合并

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>'
    ]]
])