如何重播使用通用 Webhook HTTP POST 内容的 Jenkins 管道作业?

How to replay Jenkins pipeline job that uses generic webhook HTTP POST content?

我有一个由 Bitbucket 通用 webhook 触发的 Jenkins 管道作业。 IE。 Jenkins 有通用的 Webhook 触发器: ...并且 Bitbucket 项目通过添加像 http://my_jenkins_server:8080/generic-webhook-trigger/invoke?token=foo

这样的 webhook 来触发这个 Jenkins 项目

我的 Jenkinsfile 使用 HTTP POST 内容——这是 JSON 格式——随调用 webhook 一起提供。例如。我的 Jenkinsfile 有这样的部分:

pipeline {
  agent any
  triggers {
    GenericTrigger (
      genericVariables: [
        [ key: "POST_actor_name", value: "$.actor.name" ],
        [ key: "POST_actor_email", value: "$.actor.emailAddress" ],
        [ key: "POST_ref_id", value: "$.changes[0].refId" ],
        [ key: "POST_ref_display_id", value: "$.changes[0].ref.displayId" ],
        [ key: "POST_commit", value: "$.changes[0].toHash" ],
        [ key: "POST_repo_slug", value: "$.repository.slug" ],
        [ key: "POST_project_key", value: "$.repository.project.key" ],
        [ key: "POST_clone_url", value: "$.repository.links.clone[1].href" ],
        [ key: "POST_pull_req_clone_url", value: "$.pullRequest.fromRef.repository.links.clone[1].href" ],
        [ key: "POST_pull_req_id", value: "$.pullRequest.id" ],
        [ key: "POST_pull_req_from_branch", value: "$.pullRequest.fromRef.displayId" ],
        [ key: "POST_pull_req_to_branch", value: "$.pullRequest.toRef.displayId" ],
        [ key: "POST_pull_req_repo_slug", value: "$.pullRequest.toRef.repository.slug" ],
        [ key: "POST_pull_req", value: "$.pullRequest.links.self[0].href" ],
        [ key: "POST_pull_req_url", value: "$.pullRequest.links.self[0].href" ],
      ],

      causeString: '$committer_name pushed ref $ref to $clone_url referencing $commit',
      token: "foo", 
      printContributedVariables: true,
      printPostContent: true,
    )
  }
...

问题:如何重播现有版本?

如果我点击现有构建的 Replay 按钮: ...构建失败,我在构建日志中得到了这个小片段:

[Pipeline] readJSON (hide)
[Pipeline] readJSON
[Pipeline] error

我认为这表示读取JSON 错误,因为 replayed 作业不是由真正的 HTTP POST 触发的,因此没有JSON 要解析的 triggers.GenericTrigger.genericVariables 部分(在上面发布)的内容。 这是对构建错误的正确评估吗?

我认为触发读取 HTTP POST 内容的 Jenkins 管道作业的通用 Webhook 很常见。我还认为需要重放过去的 Jenkins 构建是很常见的。因此,我想知道是否有一种习惯用法或通用方法来提供一种方法来重新触发过去的 Jenkins 管道作业,这些作业依赖于来自触发通用 webhook 的 HTTP POST 内容。我在这里太缺乏经验,不知道是否有某种机制可以缓存原始 HTTP POST 内容并重新发送到重播作业。 或者是否有一种方法可以在不推动虚拟更改的情况下从 Bitbucket 重新触发管道?(Git 将新提交推送到 Bitbucket 存储库的活动会触发存储库的 webhooks)。

解决方案:使用后备参数

然后以你的例子的最小版本为例,我相信你需要像下面这样的东西。我还没有测试过这个确切的例子,但希望你能理解。

主要思想是:使用与您创建的通用变量键完全相同的名称创建后备参数。事实上,如果您从作业的“配置”页面查看通用 webhook 触发器,您会看到一条关于使用参数支持通用 webhook 变量的注释:

If your job is not parameterized, then the resolved variables will just be contributed to the build. If your job is parameterized, and you resolve variables that have the same name as those parameters, then the plugin will populate the parameters when triggering job. That means you can, for example, use the parameters in combination with an SCM plugin, like GIT Plugin, to pick a branch.

要点:参数 names 必须与通用变量的 keys 完全匹配。

pipeline {
  agent any

//This is I believe the main bit you were missing
parameters{
    //Note: you can also use choice parameters instead of string here.
    string(name: 'committer_name', description: 'ENTER A DESCRIPTION FOR YOUR PARAMETER HERE'),        
    string(name: 'ref', description: 'ENTER A DESCRIPTION FOR YOUR PARAMETER HERE'),
    string(name: 'clone_url', description: 'ENTER A DESCRIPTION FOR YOUR PARAMETER HERE'),
    string(name: 'commit', description: 'ENTER A DESCRIPTION FOR YOUR PARAMETER HERE')
}

  triggers {
    GenericTrigger (
      genericVariables: [
        //Using single quotes for values because AFAIK they should just be strings corresponding to JSON path in JSON payload of POST request
        [ key: 'committer_name', value: '$.actor.name' ],        
        [ key: 'ref', value: '$.changes[0].refId' ],
        [ key: 'clone_url', value: '$.repository.links.clone[1].href' ],
        [key: 'commit', value: '$.changes[0].fromHash'] ]
      ],

      //Using single quotes to avoid interpolating the parameters here. In practice, I've observed that this sets the cause string after the parameters are read from the POST data. If you try to interpolate with double quotes, you either get a premature/default parameter value, or worse, if the parameter is unknown to Jenkins yet because you're running from SCM and the parameter isn't loaded yet, you can get a vicious circle where the job fails before the parameter even loads, and you then have to add it manually to get it to work
      causeString: '$committer_name pushed ref $ref to $clone_url referencing $commit',
      token: "foo", 
      printContributedVariables: true,
      printPostContent: true,
    )
  }
...
//You can use the parameters in the rest of your job, and they will also be captured in the build so that you can replay the build - which is what this Q. asks

我的建议:将作业分成 Trigger/Workhorse

这不是直接的答案 - 只是我自己的建议。我发现将作业分成两部分是一种更简洁的方法:

  • 比方说,一项工作是“主力军”,它接受参数列表并做一些工作
  • 另一项工作是“触发”工作 - 这个工作的职责只是接收通用 webhook 请求,执行任何 validation/cleaning 参数,然后作为下游工作触发主力。为此,我使用“Pipeline: Build Step”插件。

这里的一个优点是关注点分离 - 主力不必担心或被通用 webhook 的东西搞得一团糟,通用 webhook 可以专注于处理 webhook。

另一件好事是,触发器作业至少可以处理 webhook 参数的一些验证、清理它们,并为人们提供一个很好的详细视图,了解 webhook 发生了什么,而不需要主力作业的细节。

在实践中,因为我是这样做的,所以我很少以重播触发作业结束——我通常只重播主力作业,所有参数都传递给它。话虽如此,即使有我的触发作业,如果我愿意,我也可以重播它们,因为我用参数备份了所有内容——按照上面介绍的解决方案。

备注

  • 不确定为什么要在原始问题中为通用变量添加前缀 POST_ - 如前所述,使用的键应该与参数名称完全匹配。
  • 如果您从 SCM 脚本 运行 宁此,那么您第一次 运行 作业或者如果您添加任何新参数或修改任何参数名称,它不会有参数 - 这是带有参数 AFAIK 的标准 Jenkins 行为,你只需要重新 运行 作业 - 第二次它将具有参数并且可以工作。
  • 这个问题有点偏离主题,但我从捕获 Bitbucket 推送事件中注意到它似乎是填充的 fromHash。对我来说,我观察到 toHash 始终只是一串零。但我只是在查看推送事件 - 也许您正在此处处理其他事件。