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

Jak*_*obb 6 github jenkins jenkins-job-dsl

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

Jenkins 中嵌入的Job DSL API 文档没有帮助,只给了我这个签名: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}')
    }
}
Run Code Online (Sandbox Code Playgroud)

这个错误如下:

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]
Run Code Online (Sandbox Code Playgroud)

第8行是:

buildStatus {
Run Code Online (Sandbox Code Playgroud)

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

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

谷歌搜索错误信息让我找到了一些在 2016-2017 年遇到类似问题的人:1 , 2 , 3。他们的问题似乎源于Github Pull Request Builder 插件作为核心、捆绑插件的弃用,以及相应的语法变化。这让我发现了一种新的语法,这里给出:

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'
                    }
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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]
Run Code Online (Sandbox Code Playgroud)

第 9 行是:

'org.jenkinsci.plugins.ghprb.extensions.status.GhprbSimpleStatus' {
Run Code Online (Sandbox Code Playgroud)

在所有这些中,我正在努力理解 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
Run Code Online (Sandbox Code Playgroud)

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

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

使用的插件版本:

  • 工作 DSL:1.77
  • GHPRB:1.42.1

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

我的问题总结:

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

Jak*_*obb 4

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

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

  1. 生成新的公钥-私钥对。我在本地计算机上执行此操作,但您可以在任何地方执行此操作。私钥文件的内容将提供对您的 GitHub 帐户的访问权限,因此在决定保存文件的位置时请务必谨慎,并相应地自行清理。
  2. 转到 GitHub 并以您希望 Jenkins 用于向 GitHub 进行身份验证的用户身份登录。
  3. 导航Settings -> SSH and GPG keys。(注意:这是用户的设置,而不是存储库的设置)
  4. 创建新的 SSH 密钥。为其命名(我以 Jenkins 实例命名)并粘贴步骤 1 中生成的公钥内容。
  5. 导航Settings -> Developer settings -> Personal access tokens
  6. 生成一个新的令牌。授予它对“repo”的访问权限。确保您在安全的地方捕获了令牌值——我将其保存在密码管理器中。如果您丢失了它,则必须再次执行所有这些步骤才能创建一个新的并配置 Jenkins 来使用它。
    • 我的公司使用带有基于 SAML 的身份验证和 SSO 的私有 GitHub 组织。如果您也遇到这种情况,请确保在适当组织的令牌上启用 SSO。
  7. 在詹金斯中,转到Manage Jenkins -> Manage Credentials.
  8. 在系统/全局域中创建新的“带私钥的 SSH 用户名”凭据。在“用户名”字段中,输入 GitHub 用户名。私钥选择“直接输入”,选择“添加”,粘贴步骤1中生成的私钥文件的文本内容。
    • 作为创建凭证的一部分,您将为其提供 ID 和描述。ID 用于 XML 配置文件,描述用于 Jenkins 配置 UI。我喜欢对两者使用相同的值,以便存储在 XML 配置文件中的值与我在用户界面中看到的值相同。ID 可以是大写和小写字母加上分隔符。为了获得最佳的可读性,我喜欢使用 kebab-case。
  9. 在系统/全局域中创建新的“秘密文本”凭证。在“Secret”字段中,输入在步骤 6 中生成的 GitHub 令牌值。再次为其提供描述和 ID。
  10. 在 中Manage Jenkins -> Configure System -> GitHub Pull Request Builder -> Credentials,选择您在步骤 9 中创建的基于令牌的凭据。

这是使用该插件为 PR 工作的 Job 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.')
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

笔记:

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

GitHub端的webhook配置如下: GitHub 拉取请求 Webhook 配置的屏幕截图,如下所述

笔记:

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

最终结果: GitHub 拉取请求中显示的成功 Jenkins 构建的屏幕截图

这用于推送:

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

triggers {
    githubPush()
}
Run Code Online (Sandbox Code Playgroud)

网络钩子: GitHub 推送 Webhook 配置的屏幕截图,如下所述

笔记:

  • 负载网址:https://your-jenkins-host/github-webhook/
    • 请注意,主机 URL 必须可公开访问。我的不是,但我们有一个面向公众的代理。我在这里使用了代理的主机名。
  • 内容类型必须是application/x-www-form-urlencoded.
  • 我没有配置秘密。如果有一种方法可以在 Jenkins 端配置一个,我没有找到。
  • Webhook 应在拉取请求和推送时触发。
    • 我已经修剪了屏幕截图以隐藏不重要的事件。
  • 此配置会导致每次推送都会生成一次,无论分支如何。这就是我想要的;这可能不是你想要的。如果您想要其他内容,只需更改branch说明符即可。

branch由于和params的差异,我无法拥有一个同时处理 PR 和推送的工作refspec。我发现一些证据表明 Git 支持多个 refspec,并且能够在 CLI 上使用该功能git,但在我尝试配置 Jenkins 执行相同操作时没有成功。我没有创建一个对两者都有效的分支说明符。我也许能够设置一个单一的参数化构建,然后使用这些触发器进行迷你作业,然后调用参数化构建,但目前我认为不值得添加另一个作业。顺便说一句,我还设置了第三项工作,每晚针对我们的主要开发分支运行。我们将为该构建构建一个广泛的(长期运行的)测试套件,同时保持 PR 和推送构建器的快速运行。

至于我应该在哪里寻找文档:我在谷歌上搜索了一遍,并通过反复试验将其拼凑在一起,并在几十个地方找到了提示和配置的碎片。我在阅读 Job DSL 插件的 API 文档方面有了一些进步,但这本身还不够。同样有用的是:对于推送触发的作业,可以在 Jenkins 作业摘要页面上找到 GitHub Hook 日志。对于 PR 触发的作业,可从 获取 Jenkins 系统日志Manage Jenkins -> System Log。