Запуск сборок Jenkins с помощью вебхуков

Beginner

Введение

Интеграция через вебхуки (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) должны отображаться ветка вебхука, идентификатор коммита и тема коммита в логе сборки.

Вывод консоли сборки Jenkins по вебхуку

Резюме

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