Acionando Builds do Jenkins com Webhooks

Beginner

Introdução

As integrações via Webhook permitem que sistemas de controle de versão notifiquem o Jenkins quando um repositório sofre alterações. Um webhook real do GitHub ou GitLab envia uma requisição HTTP para o Jenkins. Para garantir um laboratório confiável, você simulará essa requisição localmente usando curl, em vez de depender de um serviço externo.

Neste laboratório, você criará um repositório Git local, configurará um job do tipo Freestyle no Jenkins que aceita parâmetros de branch e commit no estilo webhook, enviará uma requisição de webhook local e inspecionará o log do build acionado.

Preparar um Repositório de Origem Local

Nesta etapa, você criará um pequeno repositório Git que atuará como o sistema de controle de versão. Um webhook normalmente carrega a branch e o commit que foram alterados, portanto, você salvará esses valores para as etapas seguintes.

O comando git init -b main cria um repositório com uma branch chamada main. Os comandos git config definem a identidade do autor para que o commit possa ser criado sem solicitações adicionais.

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"

Crie um arquivo e faça o commit dele:

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

Salve a branch e o ID curto do commit em um arquivo de ambiente. O comando tee escreve os valores em um arquivo e também os exibe no terminal para que você possa conferi-los.

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

A saída deve ser semelhante a esta:

WEBHOOK_BRANCH=main
WEBHOOK_COMMIT=...

O job do Jenkins será executado dentro do container Docker do Jenkins. Copie o repositório para /var/jenkins_home/webhook-repo para que o processo de build possa lê-lo de dentro do container:

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

Criar um Job Parametrizado no Jenkins

Nesta etapa, você criará um job do tipo Freestyle no Jenkins chamado webhook-trigger-demo. O job aceitará dois parâmetros de string: WEBHOOK_BRANCH e WEBHOOK_COMMIT. Isso reflete os dados importantes que um webhook de controle de versão envia.

Crie o XML de configuração do job do Jenkins. O comando shell no job imprime a branch e o commit, e então verifica se o commit existe no repositório 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 o job para o Jenkins e recarregue o controlador com o script auxiliar criado durante a configuração:

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 se o Jenkins consegue visualizar o job:

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

A saída esperada é:

"name":"webhook-trigger-demo"

Criar um Arquivo de Payload de Webhook

Nesta etapa, você criará um arquivo JSON que simula um pequeno payload de webhook de controle de versão. Payloads de webhook reais contêm muitos campos. Este laboratório mantém apenas os campos necessários para o build: ref para a branch e after para o ID do commit.

Carregue os valores de branch e commit salvos e, em seguida, escreva o payload 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

Use o formatador JSON do Python para confirmar se o arquivo é válido e legível:

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

Você deverá ver a referência da branch refs/heads/main e o ID do commit do seu repositório Git.

Enviar a Requisição de Webhook com curl

Nesta etapa, você simulará o envio do webhook. O Jenkins usa um token "crumb" para proteger requisições POST, portanto, o comando primeiro solicita um crumb e armazena o cookie correspondente. Em seguida, ele envia a branch e o commit como parâmetros de build para o endpoint buildWithParameters.

Extraia a branch e o commit do payload JSON para um arquivo de ambiente do 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

Agora, envie a requisição de build para o 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

Aguarde até que o build #1 seja concluído:

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 se o build foi bem-sucedido:

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

Inspecionar o Log do Build Acionado

Nesta etapa, você inspecionará a saída do console do Jenkins. O log do build é a evidência mais direta de que o payload do webhook chegou ao job, pois ele exibe a branch, o ID do commit e o assunto do commit.

Imprima as linhas relevantes do console:

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

A saída deve incluir a branch main e o assunto do commit:

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

Abra o Firefox na interface Desktop e acesse http://localhost:8080/job/webhook-trigger-demo/1/console. A página "Console Output" deve mostrar a branch do webhook, o ID do commit e o assunto do commit no log do build.

Saída do console do build via webhook no Jenkins

Resumo

Você criou um repositório Git local, configurou um job do Jenkins para aceitar parâmetros de build no estilo webhook, enviou uma requisição de webhook local com curl e verificou as evidências da branch e do commit no log do build do Jenkins. Este é o mesmo fluxo central utilizado por sistemas de controle de versão quando notificam o Jenkins sobre alterações em repositórios.