Как обработать полезную нагрузку github webhook в Jenkins?
В настоящее время я запускаю свои сборки Jenkins через веб-крючок GitHub. Как бы я проанализировал полезную нагрузку JSON? Если я пытаюсь параметризовать мою сборку и использую переменную $payload, веб-крючок GitHub завершается с ошибкой:
<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 ответа
Есть несколько уловок, чтобы заставить это работать, и я нашел (теперь несуществующий) chloky.com
сообщение в блоге, чтобы быть полезным для большей части этого. Похоже, что веб-крюк по крайней мере связался с вашим экземпляром Jenkins, я пока пропущу эти шаги. Но, если вы хотите больше подробностей, просто прокрутите конец моего ответа, чтобы увидеть содержание, от которого я смог спасти chloky.com
- Я не знаю оригинального автора, и информация может быть устаревшей, но я нашел ее полезной.
Таким образом, чтобы подвести итог, вы можете сделать следующее, чтобы иметь дело с полезной нагрузкой:
- Установите строковый параметр под названием "полезная нагрузка" в вашем задании Jenkins. Если вы планируете запускать сборку вручную, было бы неплохо в какой-то момент дать ему документ JSON по умолчанию, но он вам сейчас не нужен. Это имя параметра чувствительно к регистру (я использую Linux, так что это не удивительно...)
Настройте webhook в github для использования конечной точки buildWithParameters вместо конечной точки сборки, т.е.
http://<<yourserver>>/job/<<yourjob>>/buildWithParameters?token=<<yourtoken>>
Сконфигурируйте ваш webhook для использования application/x-www-form-encoded вместо application/json. В первом подходе данные JSON упаковываются в переменную формы, называемую "полезной нагрузкой", что, по-видимому, и позволяет Jenkins назначить их переменной среды. Подход application/json просто POSTs raw JSON, который, кажется, ни к чему не применим (я не мог заставить его работать). Вы можете увидеть разницу, указав вашему веб-крюку что-то вроде requestbin и проверив результаты.
- На этом этапе вы должны получить переменную $ payload при запуске сборки. Чтобы проанализировать JSON, я настоятельно рекомендую установить jq на ваш сервер Jenkins и попробовать здесь синтаксический анализ. JQ особенно хорош, потому что он кроссплатформенный.
- Отсюда просто разберите то, что вам нужно из JSON, в другие переменные окружения. В сочетании с этапами условной сборки это может дать вам большую гибкость.
Надеюсь это поможет!
РЕДАКТИРОВАТЬ вот что я мог бы взять из оригинальных сообщений в блоге на http://chloky.com/tag/jenkins/
, который был мертв на некоторое время. Надеюсь, этот контент тоже кому-нибудь пригодится.
Пост № 1 - июль 2012
Github предоставляет хороший способ отправлять уведомления системе CI, например jenkins, всякий раз, когда совершается фиксация для репозитория. Это действительно полезно для запуска заданий сборки в jenkins для проверки коммитов, которые были только что сделаны в репо. Вам просто нужно перейти в раздел администрирования хранилища, щелкнуть сервисные хуки слева, нажать "URL-адреса веб-крючка" в верхней части списка, а затем ввести URL-адрес веб-крючка, которого ожидает Дженкинс (посмотрите на этого Дженкинса). плагин для настройки jenkins для получения этих хуков от github).
Недавно, однако, я искал способ запустить webhook, когда к репо делается пул-запрос, а не когда в репо делается коммит. Это сделано для того, чтобы jenkins мог выполнить кучу тестов по запросу pull, прежде чем решить, следует ли объединять запрос pull - полезно, когда у вас много разработчиков, работающих над своими собственными форками, и регулярно отправляющих запросы pull на главный сервер. Сделки рЕПО.
Оказывается, это не так очевидно, как можно было бы надеяться, и требует немного возиться с API github.
По умолчанию, когда вы настраиваете github webhook, он настроен на запуск только тогда, когда сделана фиксация против репо. Нет простого способа увидеть или изменить это в веб-интерфейсе github при настройке webhook. Для того, чтобы каким-либо образом манипулировать webhook, вам нужно использовать API.
Чтобы внести изменения в репо через github API, нам нужно авторизоваться. Мы будем использовать 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"
}
Теперь мы можем использовать этот токен в последующих запросах для управления нашей учетной записью github через API. Итак, давайте запросим наш репозиторий и найдем веб-крючок, который мы настроили в веб-интерфейсе ранее:
# 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"
]
По сути, это говорит о том, что этот веб-крючок будет срабатывать только тогда, когда в репо будет сделан коммит (push). Документация по github API описывает множество различных типов событий, которые можно добавить в этот список - для наших целей мы хотим добавить pull_request, и вот как мы это делаем (обратите внимание, что мы получаем идентификатор webhook из вывода json выше. Если у вас определено несколько хуков, ваш вывод будет содержать все эти хуки, поэтому убедитесь, что вы получили правильный 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, чтобы протестировать предложенный патч, а затем фактически объединить и закрыть (снова используя API) запрос на извлечение автоматически. Довольно мило.
Пост № 2 - сентябрь 2012
В предыдущем посте я говорил о настройке github webhook для запуска по запросу, а не просто по фиксации. Как уже упоминалось, в репозитории github происходит много событий, и, согласно документации по github, многие из них могут быть использованы для запуска webhook.
Независимо от того, какое событие вы решили активировать, когда веб-крюк запускается из github, он по существу создает POST для URL-адреса, настроенного в веб-крюке, включая полезную нагрузку 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, у нас есть несколько вариантов. Я обсуждаю один ниже.
Получение полезной нагрузки
В jenkins при создании нового задания сборки у нас есть возможность указать имена параметров, которые мы ожидаем передать в задание в POST, который запускает сборку. В этом случае мы передадим один параметр payload
, как видно здесь:
Передача параметров в работу сборки jenkins
Далее в конфигурации задания мы можем указать, что мы хотим иметь возможность запускать сборку удаленно (то есть, что мы хотим разрешить github запускать сборку, публикуя наш URL с полезной нагрузкой):
Затем, когда мы настраиваем webhook в нашем репозитории github (как описано в первом посте), мы даем ему URL-адрес, на который нам говорит jenkins:
Вы не можете видеть все это на экране, но URL, который я указал для webhook, был тем, на который мне сказал Дженкинс:
http://jenkins-server.chloky.com:8080/job/mytestbuild//buildWithParameters?token=asecuretoken
Теперь, когда я построил свою новую работу в jenkins, для целей этого теста я просто сказал ему выводить содержимое параметра 'payload' (который доступен в параметризованных сборках как переменная оболочки с тем же именем), используя простой скрипт:
#!/bin/bash
echo "the build worked! The payload is $payload"
Теперь, чтобы протестировать все это, нам просто нужно сделать коммит в нашем репо, а затем перейти к Дженкинсу, чтобы посмотреть на сработавшую работу:
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 и доступен для использования:
Так здорово, вся информация о нашем мероприятии на github здесь. и полностью доступны в нашей работе Дженкинс! Правда, он в большом json-объекте, но с небольшим хитрым ударом ты должен быть в порядке.
Конечно, в этом примере использовался простой коммит, чтобы продемонстрировать принципы получения полезной нагрузки внутри jenkins. Как мы уже говорили в предыдущем посте, фиксация - это одно из многих событий в репо, которое может вызвать веб-крючок. То, что вы делаете внутри jenkins после запуска, зависит от вас, но самое интересное приходит, когда вы начинаете взаимодействовать с github, чтобы выполнять дальнейшие действия в репо (публиковать комментарии, запросы на слияние, отклонять коммиты и т. Д.) На основе результатов ваши рабочие задания сборки, которые были вызваны начальным событием.
Посмотрите на следующий пост, где я свяжу все это вместе и покажу вам, как обрабатывать, выполнять тесты и, наконец, объединять запрос на извлечение в случае успеха - все автоматически внутри jenkins. Автоматизация это весело!
Существует плагин Generic Webhook Trigger, который может добавлять значения из содержимого публикации в сборку.
Если содержание публикации:
{
"app":{
"name":"GitHub API",
"url":"http://developer.github.com/v3/oauth/#oauth-authorizations-api"
}
}
И при запуске с некоторым содержимым сообщения:
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/"
}
}
}
}