如何在Jenkins中处理github webhook有效负载?

时间:2015-07-14 12:59:13

标签: json github jenkins jenkins-plugins webhooks

我目前通过GitHub webhook触发我的Jenkins构建。我将如何解析JSON有效负载?如果我尝试参数化我的构建并使用$ payload变量,GitHub webhook将失败,并显示以下错误:

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
<title>Error 400 This page expects a form submission</title>
</head>
<body><h2>HTTP ERROR 400</h2>
<p>Problem accessing /job/Jumph-CycleTest/build. Reason:
<pre>    This page expects a form submission</pre></p><hr /><i><small>Powered by Jetty://</small></i><br/>                                                
<br/>                                                
<br/>                                                
<br/>                                                
<br/>                                                
<br/>                                                
<br/>                                                
<br/>                                                
<br/>                                                
<br/>                                                
<br/>                                                
<br/>                                                
<br/>                                                
<br/>                                                
<br/>                                                
<br/>                                                
<br/>                                                
<br/>                                                
<br/>                                                
<br/>                                                

</body>
</html>

如何让我的GitHub webhook与参数化的Jenkins构建一起工作,然后如何解析webhook有效负载以使用某些行(例如提交者的用户名)作为构建中的条件?

2 个答案:

答案 0 :(得分:42)

有一些技巧可以让它发挥作用,我发现(现已不存在的)chloky.com博客文章对大部分内容都有帮助。既然听起来你至少已经与你的Jenkins实例进行了webhook通信,那么我现在就跳过这些步骤。但是,如果你想要更多的细节,只需滚动我的答案的末尾,看看我能够从chloky.com打捞的内容 - 我不知道原作者和信息可能已经过时但我做了觉得有帮助。

总而言之,您可以执行以下操作来处理有效负载:

  1. 设置一个名为&#34; payload&#34;的字符串参数。在你的詹金斯工作。如果您计划手动运行构建,那么在某个时候给它一个默认的JSON文档可能是一个好主意,但您现在不需要它。此参数名称似乎区分大小写(我使用Linux,因此毫不奇怪......)
  2. 在github中设置webhook以使用 buildWithParameters 端点而不是 build 端点,即 http://<<yourserver>>/job/<<yourjob>>/buildWithParameters?token=<<yourtoken>>

  3. 将您的webhook配置为使用 application / x-www-form-encoded 而不是 application / json 。前一种方法将JSON数据打包在一个名为&#34; payload&#34;的表单变量中,这可能是Jenkins如何将其分配给环境变量。 application / json 方法只是POST原始JSON,它似乎不能映射到任何东西(我无法使它工作)。您可以通过将您的webhook指向类似requestbin的内容并检查结果来查看差异。

  4. 此时,您应该在启动构建时获取 $ payload 变量。为了解析JSON,我强烈建议在Jenkins服务器上安装jq并尝试一些解析语法here。 JQ特别好,因为它是跨平台的。
  5. 从这里,只需将您需要的内容从JSON解析为其他环境变量。结合条件构建步骤,这可以为您提供很大的灵活性。
  6. 希望这有帮助!

    编辑这里是我可以从http://chloky.com/tag/jenkins/的原始博客文章中获取的内容,这篇博文已经死了一段时间。  希望这些内容对某人也有用。

    第1期 - 2012年7月

    Github提供了一种很好的方法,只要对存储库进行提交,就会向jenkins等CI系统发出通知。这对于在jenkins中启动构建作业以测试刚刚在repo上进行的提交非常有用。您只需要转到存储库的管理部分,单击左侧的服务挂钩,单击列表顶部的“webhook URL”,然后输入jenkins期望的webhook的URL(查看{{ 3}}用于设置jenkins从github接收这些钩子。

    this jenkins plugin

    最近,我正在寻找一种方法来在针对回购提出拉取请求时发出webhook,而不是在对回购进行提交时。这样我们可以让jenkins在拉取请求上运行一堆测试,然后再决定是否合并拉取请求 - 当你有很多开发人员在他们自己的forks上工作并定期向主要提交拉取请求时很有用回购。

    事实证明,这并不像人们希望的那样明显,并且需要对github API进行一些混乱。

    默认情况下,当您配置github webhook时,它被配置为仅在针对repo进行提交时触发。在设置webhook时,没有简单的方法可以在github Web界面中查看或更改此内容。为了以任何方式操纵webhook,您需要使用API​​。

    要通过github API对repo进行更改,我们需要授权自己。我们将使用curl,所以如果我们想每次都能传递我们的用户名和密码,就像这样:

    # curl https://api.github.com/users/mancdaz --user 'mancdaz'
    Enter host password for user 'mancdaz':
    

    或者,这是一个更好的选择,如果你想编写任何这些东西的脚本,我们可以获取一个oauth令牌并在后续请求中使用它来节省必须继续输入我们的密码。这就是我们在示例中要做的事情。首先,我们需要创建一个oauth授权并获取令牌:

    curl https://api.github.com/authorizations --user "mancdaz" \
    --data '{"scopes":["repo"]}' -X POST
    

    您将收到以下内容:

    {
       "app":{
          "name":"GitHub API",
          "url":"http://developer.github.com/v3/oauth/#oauth-authorizations-api"
       },
       "token":"b2067d190ab94698a592878075d59bb13e4f5e96",
       "scopes":[
          "repo"
       ],
       "created_at":"2012-07-12T12:55:26Z",
       "updated_at":"2012-07-12T12:55:26Z",
       "note_url":null,
       "note":null,
       "id":498182,
       "url":"https://api.github.com/authorizations/498182"
    }
    

    现在我们可以在后续的请求中使用此令牌来通过API操作我们的github帐户。因此,让我们查询我们的回购并找到我们之前在Web界面中设置的webhook:

    # curl  https://api.github.com/repos/mancdaz/mygithubrepo/hooks?access_token=b2067d190ab94698592878075d59bb13e4f5e96
    [
      {
        "created_at": "2012-07-12T11:18:16Z",
        "updated_at": "2012-07-12T11:18:16Z",
        "events": [
          "push"
        ],
        "last_response": {
          "status": "unused",
          "message": null,
          "code": null
        },
        "name": "web",
        "config": {
          "insecure_ssl": "1",
          "content_type": "form",
          "url": "http://jenkins-server.chloky.com/post-hook"
        },
        "id": 341673,
        "active": true,
        "url": "https://api.github.com/repos/mancdaz/mygithubrepo/hooks/341673"
      }
    ]
    

    注意json输出中的重要位:

    "events": [
          "push"
        ]
    

    这基本上说这个webhook只会在对repo进行提交(推送)时触发。 github API文档描述了可以添加到此列表中的众多不同事件类型 - 为了我们的目的,我们想要添加pull_request,这就是我们的工作方式(注意我们从上面的json输出中获取webhook的id。如果你定义了多个钩子,你的输出将包含所有这些钩子,所以一定要得到正确的ID):

    # curl  https://api.github.com/repos/mancdaz/mygithubrepo/hooks/341673?access_token=b2067d190ab94698592878075d59bb13e4f5e96 -X PATCH --data '{"events": ["push", "pull_request"]}'
    {
      "created_at": "2012-07-12T11:18:16Z",
      "updated_at": "2012-07-12T16:03:21Z",
      "last_response": {
        "status": "unused",
        "message": null,
        "code": null
      },
      "events": [
        "push",
        "pull_request"
      ],
      "name": "web",
      "config": {
        "insecure_ssl": "1",
        "content_type": "form",
        "url": "http://jenkins-server.chloky.com/post-hook"
      },
      "id": 341673,
      "active": true,
      "url": "https://api.github.com/repos/mancdaz/mygithubrepo/hooks/341673"
    }
    

    请参阅!

    "events": [
        "push",
        "pull_request"
      ],
    

    只要对我们的回购提交或提出拉取请求,此webhook就会触发。你在jenkins /这个webhook中所做的正是取决于你。我们使用它来启动jenkins中的一系列集成测试来测试建议的补丁,然后实际上合并并关闭(再次使用API​​)拉取请求。很甜蜜。

    第2期 - 2012年9月

    在之前的帖子中,我谈到配置github webhook来触发pull请求,而不仅仅是提交。如上所述,github repo上发生了许多事件,并且根据github文档,其中很多都可以用来触发webhook。

    无论你决定触发什么事件,当webhook从github触发时,它基本上对webhook中配置的URL进行POST,包括正文中的json有效负载。 json有效负载包含有关导致webhook触发的事件的各种详细信息。可以在此处看到在简单提交上触发的示例有效负载:

    payload
    {
       "after":"c04a2b2af96a5331bbee0f11fe12965902f5f571",
       "before":"78d414a69db29cdd790659924eb9b27baac67f60",
       "commits":[
          {
             "added":[
                "afile"
             ],
             "author":{
                "email":"myemailaddress@mydomain.com",
                "name":"Darren Birkett",
                "username":"mancdaz"
             },
             "committer":{
                "email":"myemailaddress@mydomain.com",
                "name":"Darren Birkett",
                "username":"mancdaz"
             },
             "distinct":true,
             "id":"c04a2b2af96a5331bbee0f11fe12965902f5f571",
             "message":"adding afile",
             "modified":[
    
             ],
             "removed":[
    
             ],
             "timestamp":"2012-09-03T02:35:59-07:00",
             "url":"https://github.com/mancdaz/mygithubrepo/commit/c04a2b2af96a5331bbee0f11fe12965902f5f571"
          }
       ],
       "compare":"https://github.com/mancdaz/mygithubrepo/compare/78d414a69db2...c04a2b2af96a",
       "created":false,
       "deleted":false,
       "forced":false,
       "head_commit":{
          "added":[
             "afile"
          ],
          "author":{
             "email":"myemailaddress@mydomain.com",
             "name":"Darren Birkett",
             "username":"mancdaz"
          },
          "committer":{
             "email":"myemailaddress@mydomain.com",
             "name":"Darren Birkett",
             "username":"mancdaz"
          },
          "distinct":true,
          "id":"c04a2b2af96a5331bbee0f11fe12965902f5f571",
          "message":"adding afile",
          "modified":[
    
          ],
          "removed":[
    
          ],
          "timestamp":"2012-09-03T02:35:59-07:00",
          "url":"https://github.com/mancdaz/mygithubrepo/commit/c04a2b2af96a5331bbee0f11fe12965902f5f571"
       },
       "pusher":{
          "email":"myemailaddress@mydomain.com",
          "name":"mancdaz"
       },
       "ref":"refs/heads/master",
       "repository":{
          "created_at":"2012-07-12T04:17:51-07:00",
          "description":"",
          "fork":false,
          "forks":1,
          "has_downloads":true,
          "has_issues":true,
          "has_wiki":true,
          "name":"mygithubrepo",
          "open_issues":0,
          "owner":{
             "email":"myemailaddress@mydomain.com",
             "name":"mancdaz"
          },
          "private":false,
          "pushed_at":"2012-09-03T02:36:06-07:00",
          "size":124,
          "stargazers":1,
          "url":"https://github.com/mancdaz/mygithubrepo",
          "watchers":1
       }
    }
    

    这整个有效负载作为单个参数在POST请求中传递,具有富有想象力的标题payload。它包含大量有关刚刚发生的事件的信息,当我们在触发后构建作业时,jenkins可以使用其中的全部或任何一个。为了在Jenkins中使用这个有效载荷,我们有几个选择。我在下面讨论一个。

    获取$ payload

    在jenkins中,在创建新的构建作业时,我们可以选择指定我们希望传递给POST中触发构建的作业的参数名称。在这种情况下,我们将传递一个参数payload,如下所示:

    Configure jenkins for webhook

    将参数传递给jenkins构建作业

    在作业配置中,我们可以指定我们希望能够远程触发构建(即,我们希望允许github通过使用有效负载发布到我们的URL来触发构建):

    Getting the payload

    然后,当我们在我们的github仓库中设置webhook时(如第一篇文章中所述),我们给它jenkins告诉我们的URL:

    Passing parameters

    你无法在screencap中看到它,但是我为webhook指定的URL是jenkins告诉我的那个:

    http://jenkins-server.chloky.com:8080/job/mytestbuild//buildWithParameters?token=asecuretoken 现在,当我在jenkins中构建我的新工作时,为了这个测试的目的,我只是告诉它回应'payload'参数的内容(在paramterized构建中可用作同名的shell变量),使用一个简单的脚本:

    #!/bin/bash
    
    echo "the build worked! The payload is $payload"
    

    现在要测试整个事情,我们只需要提交我们的回购,然后转到jenkins查看被触发的工作:

    mancdaz@chloky$ (git::master)$ touch myfile
    
    mancdaz@chloky$ (git::master) git add myfile
    
    mancdaz@chloky$ (git::master) git commit -m 'added my file'
    [master 4810490] added my file
    0 files changed, 0 insertions(+), 0 deletions(-)
    create mode 100644 myfile
    
    mancdaz@chloky$ (git::master) git push
    Counting objects: 3, done.
    Delta compression using up to 8 threads.
    Compressing objects: 100% (2/2), done.
    Writing objects: 100% (2/2), 232 bytes, done.
    Total 2 (delta 1), reused 0 (delta 0)
    To git@github.com:mancdaz/mygithubrepo.git
     c7ecafa..4810490 master -> master
    

    在我们的jenkins服务器中,我们可以查看触发的作业的控制台输出,并且看到$ payload变量中包含我们的'payload'并且可以供我们使用:

    太棒了,关于我们github活动的所有信息都在这里。并在我们的詹金斯工作中完全可用!真的,它是一个大json blob,但有一点狡猾的bash你应该很高兴去。

    当然,这个例子使用了一个简单的提交来演示获取jenkins内部有效负载的原则。正如我们在前面的文章中所讨论的,提交是可以触发webhook的repo上的许多事件之一。一旦你触发了你在jenkins中所做的事情取决于你,但真正有趣的是当你开始与github交互以对repo采取进一步行动(发表评论,合并拉取请求,拒绝提交等)时,基于结果您的构建作业由初始事件触发。

    请注意后续帖子,我将它们绑在一起并向您展示如何处理,运行测试,并在成功时合并拉取请求 - 所有这些都自动在jenkins中。自动化很有趣!

答案 1 :(得分:5)

有一个Generic Webhook Trigger插件可以提供从帖子内容到构建的值。

如果帖子内容是:

{
   "app":{
      "name":"GitHub API",
      "url":"http://developer.github.com/v3/oauth/#oauth-authorizations-api"
   }
}

您可以像这样配置: enter image description here

当触发一些帖子内容时:

curl -v -H "Content-Type: application/json" -X POST -d '{ "app":{ "name":"GitHub API", "url":"http://developer.github.com/v3/oauth/" }}' http://localhost:8080/jenkins/generic-webhook-trigger/invoke?token=sometoken

它将解析变量并使它们在构建作业中可用。

{  
   "status":"ok",
   "data":{  
      "triggerResults":{  
         "free":{  
            "id":2,
            "regexpFilterExpression":"",
            "regexpFilterText":"",
            "resolvedVariables":{  
               "app_name":"GitHub API",
               "everything_app_url":"http://developer.github.com/v3/oauth/",
               "everything":"{\"app\":{\"name\":\"GitHub API\",\"url\":\"http://developer.github.com/v3/oauth/\"}}",
               "everything_app_name":"GitHub API"
            },
            "searchName":"",
            "searchUrl":"",
            "triggered":true,
            "url":"queue/item/2/"
         }
      }
   }
}