如何使用 Job DSL 配置 Jenkins GitHubPullRequestBuilder 插件

How to configure Jenkins GitHubPullRequestBuilder plugin using Job DSL

我正在私有 GitHub 存储库和 Jenkins 构建之间设置 Webhook 集成。我只使用 Job DSL groovy 脚本配置作业(我愿意切换到另一种编程作业配置机制,但我不会接受任何要求我手动配置作业的答案)。 II 想设置提交状态上下文和一组基于构建状态的自定义消息。

Job DSL API documentation embedded in Jenkins 没有帮助,只给我这个签名:githubPullRequest(Closure closure),但没有告诉我如何构造合适的闭包。

以下是我工作 DSL 的相关部分:

triggers {
    githubPush()
    githubPullRequest {
        useGitHubHooks()
        buildStatus {
            completedStatus('SUCCESS', 'Build succeeded!')
            completedStatus('FAILURE', 'Build failed. ')
            completedStatus('ERROR', 'Build errored. This is probably a problem with Jenkins or related infrastructure and not an issue with your code changes.')
        }
    }
}

(...)

scm {
    git {
        remote {
            github('privateorg/myrepo', 'ssh')
            credentials('my-credential-id')
            refspec('+refs/pull/*:refs/remotes/origin/pr/*')
        }
        branch('${sha1}')
    }
}

此错误如下:

ERROR: (build.groovy, line 8) No signature of method: javaposse.jobdsl.dsl.helpers.triggers.TriggerContext.buildStatus() is applicable for argument types: 
(build$_run_closure1$_closure2$_closure10$_closure11) values: 
[build$_run_closure1$_closure2$_closure10$_closure11@602572cb]

第 8 行是:

buildStatus {

如果我删除整个 buildStatus 块,那么 Jenkins 会接受脚本并成功创建作业。我的推送挂钩有效,但我的拉取请求挂钩无效。

我不是 Groovy 程序员,也不熟悉 Jenkins 的任何方面。我知道没有与我编写的 DSL 兼容的方法,但我不知道去哪里寻找有效的方法签名。我不明白 DSL 如何很好地映射到方法调用以找到甚至识别适当的方法并构建兼容的 DSL。

谷歌搜索错误消息让我找到了一些在 2016-2017 年遇到过类似问题的人:1, 2, . Their issue seemed to stem from the deprecation of the Github Pull Request Builder plugin as a core, bundled plugin, and a corresponding change in syntax. That led me to discover a new syntax, given here:

triggers {
    githubPush()
    githubPullRequest {
        useGitHubHooks()
        extensions {
            'org.jenkinsci.plugins.ghprb.extensions.status.GhprbSimpleStatus' {
                buildStatus {
                    'org.jenkinsci.plugins.ghprb.extensions.comments.GhprbBuildResultMessage' {
                        message 'Build in progress...'
                        result 'PENDING'
                    }
                    'org.jenkinsci.plugins.ghprb.extensions.comments.GhprbBuildResultMessage' {
                        message 'Build succeeded! It is safe to merge ${ghprbSourceBranch} into ${ghprbTargetBranch}.'
                        result 'SUCCESS'
                    }
                    'org.jenkinsci.plugins.ghprb.extensions.comments.GhprbBuildResultMessage' {
                        message 'Build failed.'
                        result 'FAILURE'
                    }
                    'org.jenkinsci.plugins.ghprb.extensions.comments.GhprbBuildResultMessage' {
                        message 'Build errored. This is probably a problem with Jenkins or related infrastructure and not an issue with your code changes.'
                        result 'ERROR'
                    }
                }
            }
        }
    }
}

但这也无济于事;失败本质上是一样的:

ERROR: (build.groovy, line 9) No signature of method: javaposse.jobdsl.dsl.helpers.triggers.TriggerContext.org.jenkinsci.plugins.ghprb.extensions.status.GhprbSimpleStatus() is applicable for argument types: 
(build$_run_closure1$_closure2$_closure10$_closure11$_closure12) values: 
[build$_run_closure1$_closure2$_closure10$_closure11$_closure12@707221f0]

第 9 行是:

'org.jenkinsci.plugins.ghprb.extensions.status.GhprbSimpleStatus' {

在这一切之中,我很难理解 buildStatus、commitStatus、completedStatus 等之间的区别。这些是什么意思?

与此同时,我将 DSL 恢复到没有任何 buildStatus 的版本,并尝试创建一个 PR 以查看它是否会触发构建。它没有。我检查了“GitHub 挂钩日志”:

Started on Aug 4, 2020 6:16:47 PM
Started by event from 10.101.32.177 ⇒ https://my-jenkins-host.com/github-webhook/ on Tue Aug 04 18:16:47 UTC 2020
Using strategy: Default
[poll] Last Built Revision: Revision 91170fb44c40737a6410acfba820d6555a0475bb (refs/remotes/origin/dev)
using credential my-credential-id
 > git --version # timeout=10
using GIT_ASKPASS to set credentials 
 > git ls-remote -h -- git@github.com:privateorg/myrepo.git # timeout=10
Found 64 remote heads on git@github.com:privateorg/myrepo.git
Ignoring refs/heads/branch1 as it doesn't match any of the configured refspecs
Ignoring refs/heads/branch2 as it doesn't match any of the configured refspecs
...
Ignoring refs/heads/branch64 as it doesn't match any of the configured refspecs
Done. Took 0.71 sec
No changes

也许 Hook Log 不是查看的正确位置,但是在对 git ls-remote 的调用中使用 -h 导致它只列出分支 -- 而不是 PR。如果我在本地使用相同的命令但没有 -h,则会列出我确信会匹配我的 refspec 的 PR。

我最初使用 CloudBees Core Client Master 版本 2.204.3.7,修订版 3 遇到这些问题。升级到最新版本 (2.235.2.3) 没有帮助。

正在使用的插件版本:

如果还有其他与此处相关的插件,请告诉我,我会添加它们。

我的问题总结:

  1. 配置将在 GitHub 中显示的自定义状态消息的正确语法是什么?
  2. 我原本有效的配置有什么问题,以至于远程轮询会忽略 PR,并且打开新的 PR 不会触发构建?
  3. 还有其他地方我应该寻找这些东西的文档吗?或者其他可以帮助我了解我在做什么的资源?

明白了。有几个问题,但问题的症结在于身份验证:各种插件和组件接受并需要不同类型的凭据。我现在使用的设置使用个人访问令牌和 SSH 密钥对的组合来验证 GitHub。

设置身份验证的方法如下:

  1. Generate a new public-private keypair。我是在我的本地机器上做的,但你可以在任何地方做。私钥文件的内容将提供对您的 GitHub 帐户的访问权限,因此当您决定将文件保存在何处时要格外小心,并相应地自行清理。
  2. 转到 GitHub 并以您希望 Jenkins 用于对 GitHub 进行身份验证的用户身份登录。
  3. 导航至 Settings -> SSH and GPG keys。 (注意:那是用户的设置,不是仓库的设置)
  4. 创建一个新的 SSH 密钥。给它起一个名字(我以 Jenkins 实例命名我的名字)并粘贴在步骤 1 中生成的 public 键的内容。
  5. 导航到 Settings -> Developer settings -> Personal access tokens
  6. 生成一个新令牌。授予它访问“repo”的权限。确保在安全的地方捕获令牌值——我将我的令牌值保存在我的密码管理器中。如果你丢失了它,你将不得不再次完成所有这些步骤来制作一个新的并配置 Jenkins 来使用它。
    • 我的公司使用具有 SAML-based 身份验证和 SSO 的私有 GitHub 组织。如果这对您也是如此,请确保在相应组织的令牌上启用 SSO。
  7. 在 Jenkins 中,转到 Manage Jenkins -> Manage Credentials
  8. 在系统/全局域中创建一个新的“带私钥的 SSH 用户名”凭据。在“用户名”字段中,输入 GitHub 用户名。私钥选择“直接输入”,选择“添加”,将步骤1生成的私钥密钥文件的文本内容粘贴进去。
    • 您将在创建凭据时为凭据提供一个 ID 和描述。 ID 在 XML 配置文件中使用,描述在 Jenkins 配置中使用 UI。我喜欢对两者使用相同的值,以便存储在 XML 配置文件中的值与我在用户界面中看到的值相同。 ID 可以是大写和小写字母加上分隔符。为了获得最佳可读性,i-like-to-use-kebab-case.
  9. 在系统/全局域中创建一个新的“Secret Text”凭据。在“Secret”字段中,输入第 6 步中生成的令牌值 GitHub。再次为其提供描述和 ID。
  10. Manage Jenkins -> Configure System -> GitHub Pull Request Builder -> Credentials 中,选择您在第 9 步中创建的 token-based 凭据。

这是为 PR 工作的工作 DSL,使用 jenkins-ghprb 插件:

scm {
    git {
        remote {
            github('privateorg/myrepo', 'ssh')
            credentials('ssh-credential-id')
            refspec('+refs/pull/*:refs/remotes/origin/pr/*')
        }
        branch('${sha1}')
    }
}

triggers {
    githubPullRequest {
        useGitHubHooks()
        orgWhitelist('privateorg')
        allowMembersOfWhitelistedOrgsAsAdmin()
        extensions {
            commitStatus {
                context('Jenkins')
                completedStatus('SUCCESS', 'Build succeeded!')
                completedStatus('FAILURE', 'Build failed. ')
                completedStatus('ERROR', 'Build errored. This is probably a problem with Jenkins or related infrastructure and not an issue with your code changes.')
            }
        }
    }
}

备注:

  • 我们私人组织中的每个人都可以提交自动触发构建的 PR。您的情况可能有所不同,在这种情况下,您需要配置不同的白名单(PR 自动触发构建的人)and/or 一组不同的管理员(可以为 non-whitelisted 贡献者触发构建的人) .

GitHub端的webhook配置如下:

备注:

  • 有效载荷URL:https://your-jenkins-host/ghprbhook/
    • 请注意主机 URL 必须 public 可以访问。我的不是,但我们有一个 public-facing 代理。我在这里使用了代理的主机名。我还必须在 Manage Jenkins -> Configure System -> GitHub Pull Request Builder -> Jenkins URL override.
    • 中配置代理主机名
  • Content-type 必须application/json.
  • 这里使用的秘密是我用密码管理器生成的随机字符串。这是可选的。如果提供,您需要在 Manage Jenkins -> Configure System -> GitHub Pull Request Builder -> Shared secret.
  • 中输入相同的密码
  • webhook 应该在拉取请求和发布评论时触发。
    • 我已经修剪了屏幕截图以隐藏不重要的事件。

最终结果:

这用于推送:

scm {
    git {
        remote {
            github('privateorg/myrepo', 'ssh')
            credentials('ssh-credential-id')
        }
        branch('refs/heads/*')
    }
}

triggers {
    githubPush()
}

网络钩子:

备注:

  • 有效载荷URL:https://your-jenkins-host/github-webhook/
    • 请注意主机 URL 必须 public 可以访问。我的不是,但我们有一个 public-facing 代理。我在这里使用了代理的主机名。
  • Content-type 必须application/x-www-form-urlencoded.
  • 我没有配置密文。有没有办法在Jenkins这边配置一个,我没找到。
  • webhook 应该在拉取请求和推送时触发。
    • 我已经修剪了屏幕截图以隐藏不重要的事件。
  • 无论分支如何,此配置都会为每次推送生成一个版本。那就是我想要的;它可能不是你想要的。如果您想要其他东西,只需更改 branch 说明符即可。

由于 branchrefspec 参数的差异,我无法有一个工作同时处理 PR 和推送。我发现了一些证据表明 Git 支持多个 refspecs,并且能够在 CLI 上与 git 一起使用该功能,但在我试图控制时没有成功设想詹金斯也这样做。我没有创建对两者都适用的分支说明符。我也许可以设置一个单一的参数化构建,然后让 mini-jobs 使用这些触发器,然后调用参数化构建,但此时我认为不值得再添加一项工作。切线地,我还建立了第三个工作,每晚针对我们的主要开发部门运行。我们将为此构建构建一个广泛的 (long-running) 测试套件,同时保持 PR 和推送构建器的快速。

至于我应该在哪里寻找文档:我在谷歌上搜索了又搜索,并通过反复试验将其拼凑在一起,并在许多地方找到了提示和零碎的配置。我在阅读 Job DSL 插件的 API 文档方面有所进步,但这本身还不够。同样有用:对于 push-triggered 作业,GitHub Hook 日志,可在 Jenkins 作业摘要页面上找到。对于 PR-triggered 作业,Jenkins 系统日志,可从 Manage Jenkins -> System Log.

获得