Activación de builds de Jenkins mediante Webhooks

Beginner

Introducción

Las integraciones mediante webhooks permiten que los sistemas de control de versiones notifiquen a Jenkins cuando se produce un cambio en un repositorio. Un webhook real de GitHub o GitLab envía una solicitud HTTP a Jenkins. Para realizar este laboratorio de forma fiable, simulará dicha solicitud localmente mediante curl en lugar de depender de un servicio externo.

En este laboratorio, creará un repositorio Git local, configurará un job de tipo Freestyle en Jenkins que acepte parámetros de rama y commit al estilo webhook, enviará una solicitud de webhook local e inspeccionará el registro de la build resultante.

Preparar un repositorio de origen local

En este paso, creará un pequeño repositorio Git que actuará como el sistema de control de versiones. Un webhook normalmente transporta la rama y el commit que han cambiado, por lo que guardará estos valores para los pasos siguientes.

El comando git init -b main crea un repositorio con una rama main. Los comandos git config establecen la identidad del autor para que el commit pueda crearse sin solicitar datos adicionales.

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"

Cree un archivo y realice un commit:

echo "webhook demo build" > app.txt
git add app.txt
git commit -m "Add webhook demo app"

Guarde la rama y el ID corto del commit en un archivo de entorno. El comando tee escribe los valores en un archivo y también los imprime para que pueda verificarlos.

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

La salida debería ser similar a esta:

WEBHOOK_BRANCH=main
WEBHOOK_COMMIT=...

El job de Jenkins se ejecutará dentro del contenedor Docker de Jenkins. Copie el repositorio en /var/jenkins_home/webhook-repo para que el proceso de build pueda leerlo desde el interior del contenedor:

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

Crear un job de Jenkins parametrizado

En este paso, creará un job de Jenkins de tipo Freestyle llamado webhook-trigger-demo. El job aceptará dos parámetros de cadena: WEBHOOK_BRANCH y WEBHOOK_COMMIT. Esto replica los datos importantes que envía un webhook de control de versiones.

Cree el archivo XML de configuración del job de Jenkins. El comando shell en el job imprime la rama y el commit, y luego verifica que el commit exista en el repositorio Git local.

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

Copie el job en Jenkins y recargue el controlador con el script auxiliar creado durante la configuración:

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

Confirme que Jenkins puede ver el job:

curl -fsS http://localhost:8080/job/webhook-trigger-demo/api/json | grep -o '"name":"webhook-trigger-demo"'

La salida esperada es:

"name":"webhook-trigger-demo"

Crear un archivo de carga útil (payload) de webhook

En este paso, creará un archivo JSON que simula una pequeña carga útil de webhook de control de versiones. Las cargas útiles reales contienen muchos campos. Este laboratorio mantiene solo los campos necesarios para la build: ref para la rama y after para el ID del commit.

Cargue los valores de rama y commit guardados, luego escriba la carga útil 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

Utilice el formateador JSON de Python para confirmar que el archivo es válido y legible:

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

Debería ver la referencia de la rama refs/heads/main y el ID del commit de su repositorio Git.

Enviar la solicitud de webhook con curl

En este paso, simulará la entrega del webhook. Jenkins utiliza un token "crumb" para proteger las solicitudes POST, por lo que el comando primero solicita un crumb y almacena la cookie correspondiente. Luego, envía la rama y el commit como parámetros de build a buildWithParameters.

Extraiga la rama y el commit de la carga útil JSON a un archivo de entorno de 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

Ahora envíe la solicitud de build a 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

Espere hasta que la build #1 se complete:

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

Confirme que la build se realizó correctamente:

curl -fsS http://localhost:8080/job/webhook-trigger-demo/1/api/json | grep -o '"result":"SUCCESS"'

Inspeccionar el registro de la build activada

En este paso, inspeccionará la salida de la consola de Jenkins. El registro de la build es la prueba más directa de que la carga útil del webhook llegó al job, ya que muestra la rama, el ID del commit y el asunto del commit.

Imprima las líneas relevantes de la consola:

curl -fsS http://localhost:8080/job/webhook-trigger-demo/1/consoleText | grep -E 'Webhook branch|Webhook commit|Commit subject'

La salida debe incluir la rama main y el asunto del commit:

Webhook branch: main
Webhook commit: ...
Commit subject: Add webhook demo app

Abra Firefox desde la interfaz de escritorio y visite http://localhost:8080/job/webhook-trigger-demo/1/console. La página de salida de la consola (Console Output) debería mostrar la rama del webhook, el ID del commit y el asunto del commit en el registro de la build.

Salida de la consola de build de webhook en Jenkins

Resumen

Ha creado un repositorio Git local, configurado un job de Jenkins para aceptar parámetros de build al estilo webhook, enviado una solicitud de webhook local con curl y verificado la evidencia de la rama y el commit en el registro de la build de Jenkins. Este es el mismo flujo central que utilizan los sistemas de control de versiones cuando notifican a Jenkins sobre cambios en un repositorio.