web-dev-qa-db-fra.com

Comment traiter une charge utile de webhook github dans Jenkins?

Je déclenche actuellement mes builds Jenkins via un webhook GitHub. Comment analyser la charge utile JSON? Si j'essaie de paramétrer ma build et d'utiliser la variable $ payload, le webhook GitHub échoue avec l'erreur suivante:

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

Comment puis-je faire fonctionner mon webhook GitHub avec une génération Jenkins paramétrée, et comment puis-je analyser la charge utile du webhook pour utiliser certaines lignes, telles que le nom d'utilisateur du committer, comme conditions dans la génération?

14
Grant

Il y a quelques astuces pour que cela fonctionne, et j'ai trouvé le (maintenant disparu) chloky.com blog pour être utile pour la plupart. Comme il semble que vous ayez au moins le webhook communiquant avec votre instance Jenkins, je vais ignorer ces étapes pour l'instant. Mais, si vous voulez plus de détails, faites défiler la fin de ma réponse pour voir le contenu que j'ai pu récupérer de chloky.com - Je ne connais pas l'auteur d'origine et les informations sont peut-être obsolètes mais je les ai trouvées utiles.

Donc, pour résumer, vous pouvez faire ce qui suit pour gérer la charge utile:

  1. Configurez un paramètre de chaîne appelé "payload" dans votre travail Jenkins. Si vous prévoyez d'exécuter manuellement la génération, il peut être judicieux de lui donner un document JSON par défaut à un moment donné, mais vous n'en avez pas besoin pour le moment. Ce nom de paramètre semble être sensible à la casse (j'utilise Linux donc ce n'est pas surprenant ...)
  2. Configurez le webhook dans github pour utiliser le point de terminaison buildWithParameters au lieu du point de terminaison build, c'est-à-dire http://<<yourserver>>/job/<<yourjob>>/buildWithParameters?token=<<yourtoken>>

  3. Configurez votre webhook pour utiliser application/x-www-form-encoded au lieu de application/json. L'ancienne approche regroupe les données JSON dans une variable de formulaire appelée "charge utile", ce qui est probablement la façon dont Jenkins peut l'affecter à une variable d'environnement. L'approche application/json POST juste du JSON brut qui ne semble pas être mappable à quoi que ce soit (je n'ai pas pu le faire fonctionner). Vous pouvez voir la différence en pointant votre webhook vers quelque chose comme requestbin et en inspectant les résultats.

  4. À ce stade, vous devriez obtenir votre variable $ payload lorsque vous lancez la génération. Pour analyser le JSON, je recommande fortement d'installer jq sur votre serveur Jenkins et d'essayer une partie de la syntaxe d'analyse ici . JQ est particulièrement agréable car il est multiplateforme.
  5. À partir d'ici, analysez simplement ce dont vous avez besoin du JSON dans d'autres variables d'environnement. Combiné avec des étapes de construction conditionnelles, cela pourrait vous donner beaucoup de flexibilité.

J'espère que cela t'aides!


[~ # ~] modifier [~ # ~] voici ce que j'ai pu récupérer dans les articles de blog originaux sur http://chloky.com/tag/jenkins/, mort depuis un moment. Espérons que ce contenu soit également utile pour quelqu'un.


Message n ° 1 - juillet 2012

Github fournit un bon moyen de déclencher des notifications vers un système CI comme jenkins chaque fois qu'un commit est effectué sur un référentiel. C'est vraiment utile pour lancer des travaux de build dans jenkins pour tester les commits qui viennent d'être effectués sur le repo. Il vous suffit d'aller dans la section d'administration du référentiel, de cliquer sur les hooks de service sur la gauche, de cliquer sur 'URL du webhook' en haut de la liste, puis de saisir l'URL du webhook attendu par jenkins (regardez - ce plugin jenkins pour configurer jenkins pour recevoir ces hooks de github).

Configure jenkins for webhook

Récemment cependant, je cherchais un moyen de déclencher un webhook lorsqu'une demande d'extraction est effectuée contre un référentiel, plutôt que lorsqu'un commit est effectué sur le référentiel. C'est ainsi que nous pourrions avoir jenkins exécuter un tas de tests sur la demande de tirage, avant de décider de fusionner la demande de tirage - utile lorsque vous avez beaucoup de développeurs travaillant sur leurs propres fourches et soumettant régulièrement des demandes de tirage au principal repo.

Il s'avère que ce n'est pas aussi évident qu'on pourrait l'espérer, et nécessite un peu de déconner avec l'API github.

Par défaut, lorsque vous configurez un webhook github, il est configuré pour ne se déclencher que lorsqu'un commit est effectué sur un référentiel. Il n'y a aucun moyen facile de voir ou de modifier cela dans l'interface Web de Github lorsque vous configurez le Webhook. Afin de manipuler le webhook de quelque manière que ce soit, vous devez utiliser l'API.

Pour effectuer des modifications sur un référentiel via l'API github, nous devons nous autoriser. Nous allons utiliser curl, donc si nous le voulions, nous pourrions passer notre nom d'utilisateur et notre mot de passe à chaque fois, comme ceci:

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

Ou bien, et c'est une bien meilleure option si vous souhaitez créer un script pour tout cela, nous pouvons saisir un jeton oauth et l'utiliser dans les demandes suivantes pour éviter d'avoir à saisir notre mot de passe. est ce que nous allons faire dans notre exemple. Nous devons d'abord créer une autorisation oauth et récupérer le jeton:

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

Vous serez retourné quelque chose comme ceci:

{
   "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"
}

Maintenant, nous pouvons utiliser ce jeton dans les demandes ultérieures de manipulation de notre compte github via l'API. Interrogons donc notre référentiel et trouvons le webhook que nous avons configuré dans l'interface Web plus tôt:

# 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"
  }
]

Notez le bit important de cette sortie json:

"events": [
      "Push"
    ]

Cela signifie essentiellement que ce webhook ne se déclenchera que lorsqu'un commit (Push) sera effectué sur le repo. La documentation de l'API github décrit de nombreux types d'événements différents qui peuvent être ajoutés à cette liste - pour nos besoins, nous voulons ajouter pull_request, et voici comment nous le faisons (notez que nous obtenons l'ID du webhook à partir de la sortie json ci-dessus. Si vous avez défini plusieurs crochets, votre sortie contiendra tous ces crochets, alors assurez-vous d'obtenir le bon 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"
}

Voir!

"events": [
    "Push",
    "pull_request"
  ],

Ce webhook se déclenchera désormais chaque fois qu'un commit OR une demande de pull sera faite contre notre repo. Exactement ce que vous faites dans vos jenkins/avec ce webhook dépend de vous. Nous l'utilisons pour lancer un tas de tests d'intégration dans jenkins pour tester le correctif proposé, puis fusionner et fermer (à nouveau en utilisant l'API) la demande de tirage automatiquement.

Message n ° 2 - septembre 2012

Dans un article précédent, j'ai parlé de la configuration du webhook github pour qu'il se déclenche sur une demande de tirage, plutôt que sur une simple validation. Comme mentionné, de nombreux événements se produisent sur un dépôt github, et selon la documentation de github, beaucoup d'entre eux peuvent être utilisés pour déclencher le webhook.

Quel que soit l'événement sur lequel vous décidez de déclencher, lorsque le webhook se déclenche à partir de github, il crée essentiellement un POST vers l'URL configurée dans le webhook, y compris une charge utile json dans le corps. La charge utile json contient divers détails sur l'événement qui a provoqué le déclenchement du webhook. Un exemple de charge utile qui s'est déclenché sur un simple commit peut être vu ici:

payload
{
   "after":"c04a2b2af96a5331bbee0f11fe12965902f5f571",
   "before":"78d414a69db29cdd790659924eb9b27baac67f60",
   "commits":[
      {
         "added":[
            "afile"
         ],
         "author":{
            "email":"[email protected]",
            "name":"Darren Birkett",
            "username":"mancdaz"
         },
         "committer":{
            "email":"[email protected]",
            "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":"[email protected]",
         "name":"Darren Birkett",
         "username":"mancdaz"
      },
      "committer":{
         "email":"[email protected]",
         "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":"[email protected]",
      "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":"[email protected]",
         "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
   }
}

Cette charge utile entière est transmise dans les requêtes POST en tant que paramètre unique, avec le titre imaginatif payload. Elle contient une tonne d'informations sur l'événement qui vient de se produire, tout ou partie) dont jenkins peut utiliser lorsque nous construisons des tâches après le déclenchement. Pour utiliser cette charge utile dans Jenkins, nous avons quelques options. J'en discute une ci-dessous.

Obtenir la charge utile $

Dans jenkins, lors de la création d'un nouveau travail de génération, nous avons la possibilité de spécifier les noms des paramètres que nous nous attendons à transmettre au travail dans le POST qui déclenche la génération. Dans ce cas, nous passerait un seul paramètre payload, comme on le voit ici:

Getting the payload

Passer des paramètres à un travail de génération Jenkins

Plus bas dans la configuration du travail, nous pouvons spécifier que nous aimerions pouvoir déclencher la construction à distance (c'est-à-dire que nous voulons permettre à github de déclencher la construction en publiant sur notre URL avec la charge utile):

Passing parameters

Ensuite, lorsque nous configurons le webhook dans notre dépôt github (comme décrit dans le premier article), nous lui donnons l'URL que jenkins nous dit de:

Configuring URL in Github

Vous ne pouvez pas tout voir dans la capture d'écran, mais l'URL que j'ai spécifiée pour le webhook était celle que jenkins m'a dit de:

http://jenkins-server.chloky.com:8080/job/mytestbuild//buildWithParameters?token=asecuretoken Maintenant, lorsque j'ai créé mon nouveau travail dans jenkins, pour les besoins de ce test, je lui ai simplement dit de faire écho au contenu du paramètre 'payload' (qui est disponible dans les versions paramétrées en tant que variable Shell du même nom) , à l'aide d'un simple script:

#!/bin/bash

echo "the build worked! The payload is $payload"

Maintenant, pour tester le tout, nous devons simplement nous engager dans notre référentiel, puis passer à jenkins pour regarder le travail qui a été déclenché:

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 [email protected]:mancdaz/mygithubrepo.git
 c7ecafa..4810490 master -> master

Et sur notre serveur jenkins, nous pouvons regarder la sortie console du travail qui a été déclenché, et voilà que notre "charge utile" est contenue dans la variable $ payload et disponible pour nous de consommer:

Tellement génial, toutes les informations sur notre événement github sont ici. et entièrement disponible dans notre travail jenkins! C'est vrai, c'est dans un gros blob json, mais avec un peu de bash astucieux, vous devriez être prêt à partir.

Bien sûr, cet exemple a utilisé un commit simple pour démontrer les principes d'accès à la charge utile dans jenkins. Comme nous en avons discuté dans le post précédent, une validation est l'un des nombreux événements d'un référentiel qui peut déclencher un webhook. Ce que vous faites dans jenkins une fois que vous avez déclenché vous appartient, mais le vrai plaisir vient lorsque vous commencez à interagir avec github pour entreprendre d'autres actions sur le dépôt (publier des commentaires, fusionner des demandes de tirage, rejeter des validations, etc.) en fonction des résultats de vos travaux de génération qui ont été déclenchés par l'événement initial.

Recherchez un article ultérieur où je lierai tout cela et vous montrerai comment traiter, exécuter des tests et enfin fusionner une demande d'extraction en cas de succès - le tout automatiquement dans jenkins. L'automatisation est amusante!

44
killthrush

Il existe un plugin Generic Webhook Trigger qui peut apporter des valeurs du contenu du post à la build.

Si le contenu du message est:

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

Vous pouvez le configurer comme ceci: enter image description here

Et lors du déclenchement avec du contenu de publication:

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

Il résoudra les variables et les rendra disponibles dans le travail de génération.

{  
   "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/"
         }
      }
   }
}
5
Tomas Bjerre