Введение
Интеграция через вебхуки (webhooks) позволяет системам контроля версий уведомлять Jenkins об изменениях в репозитории. Реальный вебхук GitHub или GitLab отправляет HTTP-запрос в Jenkins. Для надежности лабораторной работы вы будете имитировать этот запрос локально с помощью curl, не полагаясь на внешние сервисы.
В этой лабораторной работе вы создадите локальный Git-репозиторий, настроите задание Jenkins типа Freestyle, которое принимает параметры ветки и коммита в стиле вебхука, отправите локальный запрос вебхука и изучите лог запущенной сборки.
Подготовка локального репозитория исходного кода
На этом этапе вы создадите небольшой Git-репозиторий, который будет выступать в роли системы контроля версий. Вебхук обычно передает данные об измененной ветке и коммите, поэтому вы сохраните эти значения для последующих шагов.
Команда git init -b main создает репозиторий с веткой main. Команды git config устанавливают личность автора, чтобы коммит можно было создать без дополнительных запросов.
cd /home/labex/project
mkdir -p webhook-repo
cd webhook-repo
git init -b main
git config user.email "labex@example.com"
git config user.name "LabEx Webhook"
Создайте файл и закоммитьте его:
echo "webhook demo build" > app.txt
git add app.txt
git commit -m "Add webhook demo app"
Сохраните ветку и короткий идентификатор коммита в файл переменных окружения. Команда tee записывает значения в файл и одновременно выводит их на экран, чтобы вы могли их проверить.
COMMIT=$(git rev-parse --short=12 HEAD)
BRANCH=$(git branch --show-current)
printf 'WEBHOOK_BRANCH=%s\nWEBHOOK_COMMIT=%s\n' "$BRANCH" "$COMMIT" | tee /home/labex/project/webhook-values.env
Вывод должен выглядеть примерно так:
WEBHOOK_BRANCH=main
WEBHOOK_COMMIT=...
Задание Jenkins будет выполняться внутри Docker-контейнера Jenkins. Скопируйте репозиторий в /var/jenkins_home/webhook-repo, чтобы процесс сборки мог прочитать его изнутри контейнера:
docker exec jenkins rm -rf /var/jenkins_home/webhook-repo
docker cp /home/labex/project/webhook-repo jenkins:/var/jenkins_home/webhook-repo
docker exec -u root jenkins chown -R jenkins:jenkins /var/jenkins_home/webhook-repo
Создание параметризованного задания Jenkins
На этом этапе вы создадите задание Jenkins типа Freestyle с именем webhook-trigger-demo. Задание будет принимать два строковых параметра: WEBHOOK_BRANCH и WEBHOOK_COMMIT. Это имитирует важные данные, которые отправляет вебхук системы контроля версий.
Создайте XML-файл конфигурации задания Jenkins. Shell-команда в задании выводит ветку и коммит, а затем проверяет, существует ли этот коммит в локальном Git-репозитории.
cat > /home/labex/project/webhook-trigger-demo-config.xml <<'XML'
<?xml version='1.1' encoding='UTF-8'?>
<project>
<actions/>
<description>Build triggered by a local webhook payload.</description>
<keepDependencies>false</keepDependencies>
<properties>
<hudson.model.ParametersDefinitionProperty>
<parameterDefinitions>
<hudson.model.StringParameterDefinition>
<name>WEBHOOK_BRANCH</name>
<description>Branch name from the webhook payload.</description>
<defaultValue>main</defaultValue>
<trim>true</trim>
</hudson.model.StringParameterDefinition>
<hudson.model.StringParameterDefinition>
<name>WEBHOOK_COMMIT</name>
<description>Commit id from the webhook payload.</description>
<defaultValue></defaultValue>
<trim>true</trim>
</hudson.model.StringParameterDefinition>
</parameterDefinitions>
</hudson.model.ParametersDefinitionProperty>
</properties>
<scm class="hudson.scm.NullSCM"/>
<canRoam>true</canRoam>
<disabled>false</disabled>
<blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
<blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
<triggers/>
<concurrentBuild>false</concurrentBuild>
<builders>
<hudson.tasks.Shell>
<command>set -e
echo "Webhook branch: $WEBHOOK_BRANCH"
echo "Webhook commit: $WEBHOOK_COMMIT"
echo "Source repository: /var/jenkins_home/webhook-repo"
git -C /var/jenkins_home/webhook-repo rev-parse --verify "$WEBHOOK_COMMIT^{commit}"
git -C /var/jenkins_home/webhook-repo show --no-patch --format='Commit subject: %s' "$WEBHOOK_COMMIT"</command>
<configuredLocalRules/>
</hudson.tasks.Shell>
</builders>
<publishers/>
<buildWrappers/>
</project>
XML
Скопируйте задание в Jenkins и перезагрузите контроллер с помощью вспомогательного скрипта, созданного при настройке:
docker exec jenkins mkdir -p /var/jenkins_home/jobs/webhook-trigger-demo
docker cp /home/labex/project/webhook-trigger-demo-config.xml jenkins:/var/jenkins_home/jobs/webhook-trigger-demo/config.xml
/home/labex/project/reload-jenkins.sh
Убедитесь, что Jenkins видит задание:
curl -fsS http://localhost:8080/job/webhook-trigger-demo/api/json | grep -o '"name":"webhook-trigger-demo"'
Ожидаемый вывод:
"name":"webhook-trigger-demo"
Создание файла полезной нагрузки вебхука
На этом этапе вы создадите JSON-файл, который выглядит как небольшая полезная нагрузка (payload) вебхука системы контроля версий. Реальные полезные нагрузки вебхуков содержат множество полей. В этой лабораторной работе мы оставим только те поля, которые необходимы для сборки: ref для ветки и after для идентификатора коммита.
Загрузите сохраненные значения ветки и коммита, а затем запишите JSON-файл:
cd /home/labex/project
source webhook-values.env
cat > local-webhook-payload.json <<JSON
{
"ref": "refs/heads/${WEBHOOK_BRANCH}",
"after": "${WEBHOOK_COMMIT}",
"repository": {
"full_name": "labex/webhook-demo"
}
}
JSON
Используйте инструмент форматирования JSON в Python, чтобы убедиться, что файл корректен и читаем:
python3 -m json.tool /home/labex/project/local-webhook-payload.json
Вы должны увидеть ссылку на ветку refs/heads/main и идентификатор коммита из вашего Git-репозитория.
Отправка запроса вебхука с помощью curl
На этом этапе вы имитируете доставку вебхука. Jenkins использует crumb-токен для защиты POST-запросов, поэтому команда сначала запрашивает crumb и сохраняет соответствующий файл cookie. Затем она отправляет ветку и коммит в качестве параметров сборки в buildWithParameters.
Извлеките ветку и коммит из JSON-файла в файл переменных окружения shell:
python3 - <<'PY' > /tmp/webhook-trigger.env
import json
from pathlib import Path
payload = json.loads(Path("/home/labex/project/local-webhook-payload.json").read_text())
branch = payload["ref"].split("/")[-1]
commit = payload["after"]
print(f"WEBHOOK_BRANCH={branch}")
print(f"WEBHOOK_COMMIT={commit}")
PY
source /tmp/webhook-trigger.env
Теперь отправьте запрос на сборку в Jenkins:
CRUMB=$(curl -fsS -c /tmp/jenkins-webhook-build.cookies 'http://localhost:8080/crumbIssuer/api/xml?xpath=concat(//crumbRequestField,":",//crumb)')
curl -fsS -b /tmp/jenkins-webhook-build.cookies -H "$CRUMB" \
--data-urlencode "WEBHOOK_BRANCH=${WEBHOOK_BRANCH}" \
--data-urlencode "WEBHOOK_COMMIT=${WEBHOOK_COMMIT}" \
-X POST http://localhost:8080/job/webhook-trigger-demo/buildWithParameters
Дождитесь завершения сборки #1:
until curl -fsS http://localhost:8080/job/webhook-trigger-demo/1/api/json >/tmp/webhook-build-1.json 2>/dev/null && grep -q '"building":false' /tmp/webhook-build-1.json; do
echo "Waiting for webhook build #1..."
sleep 3
done
Убедитесь, что сборка прошла успешно:
curl -fsS http://localhost:8080/job/webhook-trigger-demo/1/api/json | grep -o '"result":"SUCCESS"'
Изучение лога запущенной сборки
На этом этапе вы изучите вывод консоли Jenkins. Лог сборки — это самое прямое доказательство того, что полезная нагрузка вебхука достигла задания, так как в нем отображаются ветка, идентификатор коммита и тема коммита.
Выведите соответствующие строки консоли:
curl -fsS http://localhost:8080/job/webhook-trigger-demo/1/consoleText | grep -E 'Webhook branch|Webhook commit|Commit subject'
Вывод должен включать ветку main и тему коммита:
Webhook branch: main
Webhook commit: ...
Commit subject: Add webhook demo app
Откройте Firefox в интерфейсе рабочего стола и перейдите по адресу http://localhost:8080/job/webhook-trigger-demo/1/console. На странице вывода консоли (Console Output) должны отображаться ветка вебхука, идентификатор коммита и тема коммита в логе сборки.

Резюме
Вы создали локальный Git-репозиторий, настроили задание Jenkins для приема параметров сборки в стиле вебхука, отправили локальный запрос вебхука с помощью curl и проверили данные о ветке и коммите в логе сборки Jenkins. Это тот же основной процесс, который используют системы контроля версий при уведомлении Jenkins об изменениях в репозитории.