简介
Webhook 集成允许源代码控制系统在仓库发生变更时通知 Jenkins。标准的 GitHub 或 GitLab Webhook 会向 Jenkins 发送 HTTP 请求。为了确保实验的可靠性,我们将使用 curl 在本地模拟该请求,而无需依赖外部服务。
在本实验中,你将创建一个本地 Git 仓库,配置一个能够接收 Webhook 风格分支和提交参数的 Jenkins 自由风格(Freestyle)任务,发送本地 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_BRANCH 和 WEBHOOK_COMMIT。这模拟了源代码控制 Webhook 发送的关键数据。
创建 Jenkins 任务的 XML 配置文件。任务中的 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"
创建 Webhook 负载文件
在此步骤中,你将创建一个 JSON 文件,其格式类似于小型源代码控制 Webhook 的负载(Payload)。真实的 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 使用 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 控制台输出。构建日志是 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。控制台输出页面应在构建日志中显示 Webhook 的分支、提交 ID 和提交主题。

总结
你创建了一个本地 Git 仓库,配置了一个接收 Webhook 风格构建参数的 Jenkins 任务,使用 curl 发送了本地 Webhook 请求,并在 Jenkins 构建日志中验证了分支和提交信息。这与源代码控制系统在通知 Jenkins 仓库变更时所使用的核心流程完全一致。