首页 > 解决方案 > 如何重播使用通用 webhook HTTP POST 内容的 Jenkins 管道作业?

问题描述

我有一个由 Bitbucket 通用 webhook 触发的 Jenkins Pipeline 作业。即 Jenkins 有 Generic Webhook Trigger: 在此处输入图像描述 ...和 ​​Bitbucket 项目通过添加一个 webhook 来触发这个 Jenkins 项目http://my_jenkins_server:8080/generic-webhook-trigger/invoke?token=foo

我的 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

我相信这表明 readJSON 错误,因为重播的作业不是由真正的 HTTP POST 触发的,因此该部分(上面发布)没有 JSON 内容triggers.GenericTrigger.genericVariables可以解析。这是对构建错误的正确评估吗?

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

标签: jenkinsjenkins-pipelinebitbucketwebhooksjenkins-generic-webhook-trigger

解决方案


解决方案:使用支持参数

然后,以您的示例的最小版本为例,我相信您需要类似下面的内容。我没有测试过这个确切的例子,但希望你能明白。

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

如果你的工作没有参数化,那么解析的变量只会被贡献到构建中。如果您的作业是参数化的,并且您解析与这些参数同名的变量,那么插件将在触发作业时填充参数。这意味着您可以将参数与 SCM 插件(如 GIT 插件)结合使用来选择分支。

关键要点:参数names 必须与key泛型变量的 s 完全匹配。

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

我的建议:将工作分成触发器/主力

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

  • 比方说,一项工作是“主力”,它需要一个参数列表并做一些工作
  • 另一项工作是“触发”工作——这个工作的职责只是接收通用 webhook 请求,对参数进行任何验证/清理,然后将主力作为下游工作触发。我为此使用了“管道:构建步骤”插件。

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

另一个好处是,触发器作业至少可以处理 webhook 参数的一些验证、清理它们,并在没有主力作业细节的情况下为人们提供关于 webhook 发生了什么的一个很好的详细视图。

在实践中,因为我以这种方式做事,所以我很少会最终重播触发器作业——我通常只是重播主力作业,该作业将所有参数传递给它。话虽如此,即使使用我的触发作业,如果我愿意,我也可以重播它们,因为我使用参数备份所有内容 - 根据上面介绍的解决方案。

笔记

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

推荐阅读