Webhook を使用した Jenkins ビルドのトリガー

Beginner

はじめに

Webhook 統合を使用すると、ソース管理システムはリポジトリに変更があった際に Jenkins へ通知を送ることができます。GitHub や GitLab の実際の Webhook は、Jenkins に対して HTTP リクエストを送信します。この実験では、外部サービスに依存することなく、curl を使用してローカル環境でそのリクエストをシミュレートします。

この実験では、ローカルの Git リポジトリを作成し、Webhook 形式のブランチおよびコミットパラメータを受け入れる Jenkins のフリースタイルジョブを設定します。その後、ローカルで Webhook リクエストを送信し、トリガーされたビルドログを検査します。

ローカルソースリポジトリの準備

このステップでは、ソース管理システムとして機能する小さな Git リポジトリを作成します。通常、Webhook には変更されたブランチとコミットの情報が含まれるため、後のステップで使用するためにこれらの値を保存しておきます。

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"

ブランチ名と短いコミット ID を環境ファイルに保存します。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 ジョブは Jenkins Docker コンテナ内で実行されます。ビルドプロセスがコンテナ内からリポジトリを読み取れるように、/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 ジョブの作成

このステップでは、webhook-trigger-demo という名前の Jenkins フリースタイルジョブを作成します。このジョブは WEBHOOK_BRANCHWEBHOOK_COMMIT という 2 つの文字列パラメータを受け入れます。これは、ソース管理の Webhook が送信する重要なデータを模倣したものです。

Jenkins ジョブの設定 XML を作成します。ジョブ内のシェルコマンドは、ブランチとコミットを出力し、そのコミットがローカルの 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"

Webhook ペイロードファイルの作成

このステップでは、ソース管理の Webhook ペイロードのような JSON ファイルを作成します。実際の Webhook ペイロードには多くのフィールドが含まれますが、この実験ではビルドに必要なフィールド(ブランチ用の ref とコミット ID 用の 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

Python の JSON フォーマッタを使用して、ファイルが有効で読み取り可能であることを確認します。

python3 -m json.tool /home/labex/project/local-webhook-payload.json

refs/heads/main ブランチ参照と、Git リポジトリのコミット ID が表示されるはずです。

curl を使用した Webhook リクエストの送信

このステップでは、Webhook の配信をシミュレートします。Jenkins は POST リクエストを保護するために Crumb トークンを使用するため、コマンドはまず Crumb を要求して一致するクッキーを保存します。その後、ビルドパラメータとしてブランチとコミットを buildWithParameters に送信します。

JSON ペイロードからブランチとコミットを抽出し、シェル環境ファイルに書き込みます。

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 のコンソール出力を検査します。ビルドログは、Webhook ペイロードがジョブに到達したことを示す最も直接的な証拠であり、ブランチ、コミット ID、コミットの件名が表示されます。

関連するコンソール行を表示します。

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」ページには、ビルドログ内に Webhook のブランチ、コミット ID、コミットの件名が表示されているはずです。

Jenkins webhook build console output

まとめ

ローカルの Git リポジトリを作成し、Webhook 形式のビルドパラメータを受け入れるように Jenkins ジョブを設定し、curl を使用してローカルの Webhook リクエストを送信し、Jenkins ビルドログでブランチとコミットの証拠を確認しました。これは、ソース管理システムがリポジトリの変更を Jenkins に通知する際に使用するのと同じコアフローです。