Corrección — proyecto 14: GitHub Actions + GitHub Pages

11 min

Este documento contiene las soluciones completas de las 4 misiones, las explicaciones línea a línea de los workflows suministrados, las reparaciones de las 3 averías y las respuestas a las preguntas de reflexión.

Ábrelo solo después de haberlo intentado de verdad. Leer la solución antes de haber tanteado es perderse el 80 % del aprendizaje.


Tabla de contenidos


Misión 1 — Personalizar config.json

Ejemplo de archivo válido:

json
{
  "titre": "Portfolio de <votre nom>",
  "sous_titre": "Deploiement automatique via GitHub Actions",
  "couleur_fond": "#7c3aed",
  "couleur_texte": "#f8fafc",
  "couleur_accent": "#22d3ee",
  "auteur": "<Votre Nom>",
  "version": "1.0.0"
}

Puntos a respetar:

  1. Las 7 claves (titre, sous_titre, couleur_fond, couleur_texte, couleur_accent, auteur, version) son obligatorias.
  2. Los 3 colores deben respetar el formato #RRGGBB (6 caracteres hexadecimales después del #).
  3. El archivo debe seguir siendo un JSON válido: coma después de cada campo salvo el último, comillas dobles en todas partes.

Validación local:

powershell
python .\outils\build.py

Debe mostrar OK dist/index.html genere y OK dist/css/style.css genere. Cualquier error ERREUR : detiene el script y bloqueará después el workflow GitHub.

Paleta sugerida para probar el bucle en la misión 2:

ColorFondoTextoAcento
Noche oscura#0f172a#f1f5f9#38bdf8
Violeta vivo#7c3aed#f8fafc#22d3ee
Rojo vivo#dc2626#fef2f2#facc15
Verde bosque#16a34a#f0fdf4#fbbf24
Azul océano#0891b2#ecfeff#f472b6

Misión 2 — Entender los workflows suministrados + probar el bucle push → Pages

Lectura línea a línea de deployer-pages.yml

yaml
name: Deployer sur GitHub Pages          # nombre que aparece en la UI Actions

Este nombre es puramente cosmético — ayuda a situar el workflow en la pestaña Actions del repositorio.

yaml
on:
  push:
    branches: [main]
  workflow_dispatch:

Dos disparadores:

  • Automático en cuanto se empuja a main (el caso normal).
  • Manual vía un botón Run workflow en la pestaña Actions (útil para volver a desplegar sin un commit nuevo).
yaml
permissions:
  contents: read
  pages: write
  id-token: write

El trío mágico de Pages. Sin esas tres líneas, se obtiene Resource not accessible by integration en el job deployer (es exactamente la avería 1 de la misión 3):

  • contents: read — permite a actions/checkout@v4 leer el código.
  • pages: write — autoriza a actions/deploy-pages@v4 a publicar.
  • id-token: write — necesario para la autenticación OIDC entre el runner y el servicio Pages.
yaml
concurrency:
  group: pages
  cancel-in-progress: false

Si dos git push llegan casi a la vez, GitHub Actions no lanza dos despliegues en paralelo sobre el mismo grupo pages — los runs se ejecutan uno detrás de otro. cancel-in-progress: false = se deja terminar el run en curso antes de arrancar el siguiente. Es crucial para Pages: dos publicaciones simultáneas producen estados incoherentes.

yaml
jobs:
  construire:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4                   # 1. recuperar el código
      - uses: actions/setup-python@v5               # 2. instalar Python
        with:
          python-version: "3.12"
      - run: python outils/build.py                  # 3. generar dist/
      - uses: actions/upload-pages-artifact@v3       # 4. preparar el artefacto
        with:
          path: dist                                 #    <-- IMPORTANTE: carpeta a publicar

Cuatro pasos secuenciales. Si uno falla, los siguientes no se ejecutan.

yaml
  deployer:
    needs: construire                                # espera a que "construire" acierte
    environment:
      name: github-pages                             # entorno oficial Pages
      url: ${{ steps.publication.outputs.page_url }} # muestra la URL en la UI
    steps:
      - uses: actions/deploy-pages@v4
        id: publication

El job deployer espera explícitamente a construire gracias a needs:. Al final, la UI de GitHub muestra un enlace clicable hacia https://<tu>.github.io/<repo>/.

Lectura línea a línea de verifier-config.yml

yaml
on:
  pull_request:
    branches: [main]
  push:
    branches-ignore: [main]

Se dispara en PR hacia main y en push hacia cualquier rama salvo main. El objetivo: validar antes de que el código se fusione. Nota que se excluye main del push: — si no, se duplicaría el trabajo con deployer-pages.yml.

El resto de los pasos es idéntico a deployer-pages.yml salvo que no se publica: basta con verificar que dist/ se genera sin error.

Prueba del bucle push → Pages

Secuencia a reproducir dos veces:

powershell
# --- Iteración 1: fondo violeta ---
# Edita site/config.json : "couleur_fond": "#7c3aed"
git add site/config.json
git commit -m "fond violet"
git push
# Esperar ~40 s -> abrir https://<tu>.github.io/<repo>/ -> fondo violeta

# --- Iteración 2: fondo rojo ---
# Edita site/config.json : "couleur_fond": "#dc2626"
git add site/config.json
git commit -m "fond rouge"
git push
# Esperar ~40 s -> abrir la misma URL -> fondo rojo

Comprobaciones a incluir en el informe:

  • git log --oneline: muestra los 2 commits con sus SHA cortos.
  • Pestaña Actions: los 2 runs de Deployer sur GitHub Pages están verdes.
  • Dos capturas de pantalla de la página pública con los 2 colores distintos.
  • En cada captura, la baldosa «Commit SHA» debe corresponder al commit que disparó ese run.

Misión 3 — Reparación de las 3 averías

Avería 1 — Permissions faltantes

Diff del correctivo en .github/workflows/casse-1-permissions-manquantes.yml:

diff
 name: Casse 1 - Permissions manquantes

 on:
   push:
     branches: [main]
   workflow_dispatch:

+permissions:
+  contents: read
+  pages: write
+  id-token: write
+
 concurrency:
   group: pages
   cancel-in-progress: false

 jobs:
   ...

Diagnóstico escrito a poner en el informe:

Sin el bloque permissions:, GitHub otorga al workflow solo contents: read (lectura del código) — no el permiso de publicar en Pages. La action actions/deploy-pages@v4 reclama explícitamente pages: write e id-token: write (token OIDC). De ahí el error Resource not accessible by integration (403 Forbidden) en el job deployer.

Regla de seguridad: se da el mínimo de permissions posible, pero no menos. El principio del menor privilegio aplicado al CI/CD.

Avería 2 — Disparador erróneo

Diff del correctivo:

diff
 name: Casse 2 - Declencheur errone

 on:
-  pushh:
+  push:
     branches: [main]

Diagnóstico escrito a poner en el informe:

GitHub Actions no señala los disparadores desconocidos en on: — los ignora en silencio. Un simple pushh (con dos h) hace que ningún run se dispare: no se ve error, no se ve nada en la pestaña Actions.

¿Cómo se descubre la avería? Se empuja un commit, se va a Actions, se constata que ningún run aparece para este workflow. El único indicio es la ausencia.

Truco anti-trampa: un Run workflow rápido (botón manual, disponible si está workflow_dispatch:) verifica que el workflow en sí es sintácticamente válido. El workflow_dispatch: funciona con independencia de push:.

Avería 3 — Ruta de artefacto errónea

Diff del correctivo:

diff
       - name: Preparer le dossier a publier
         uses: actions/upload-pages-artifact@v3
         with:
-          path: public
+          path: dist

Diagnóstico escrito a poner en el informe:

outils/build.py escribe sistemáticamente en dist/ (constante DIST = RACINE / "dist" en el código Python). El workflow pedía path: public — una carpeta que no existe. De ahí:

Error: Path does not exist: ./public

actions/upload-pages-artifact@v3 verifica la existencia de la carpeta antes de crear el artefacto y falla de inmediato si la ruta es falsa. La buena práctica: hacer siempre que el workflow apunte a la carpeta exacta que produce el script de build.


Misión 4 — Bonus

4.a — Badge de estado en README.md

En el README.md de tu repositorio GitHub (en la raíz, no en la carpeta projet14-github-actions-pages-tp/ del curso), añade:

markdown
# Mi sitio portfolio

![Deploy](https://github.com/<tu>/<repo>/actions/workflows/deployer-pages.yml/badge.svg)

Sitio publicado: https://<tu>.github.io/<repo>/

El badge se pone verde si el último run ha pasado, rojo si no. Se actualiza solo.

4.b — PR de prueba con config.json inválido

powershell
git checkout -b test-config-cassee
# Editar site/config.json y sustituir "couleur_fond": "#0f172a" por "couleur_fond": "rouge"
git add site/config.json
git commit -m "test : couleur invalide"
git push -u origin test-config-cassee
# Luego en GitHub: abrir una PR de test-config-cassee hacia main

El workflow Verifier la configuration se dispara, build.py grita:

ERREUR : couleur_fond doit etre au format #RRGGBB (recu : 'rouge')

La PR muestra un cuadrado rojo y el botón Merge pull request queda bloqueado si has configurado la protección de rama (Settings → Branches → Add rule → Require status checks to pass).

4.c — Workflow con secreto

.github/workflows/notifier.yml:

yaml
name: Notifier une URL

on:
  workflow_dispatch:

jobs:
  notifier:
    runs-on: ubuntu-latest
    steps:
      - name: Ping du webhook
        env:
          URL: ${{ secrets.URL_WEBHOOK }}
        run: |
          curl -X POST "$URL" \
            -H "Content-Type: application/json" \
            -d '{"texte":"Un utilisateur a declenche notifier.yml"}'

El secreto URL_WEBHOOK se define en Settings → Secrets and variables → Actions → New repository secret. Nunca aparecerá en los logs: GitHub enmascara automáticamente cualquier valor que coincida con un secreto.


Respuestas a las preguntas de reflexión

1. on: push sin branches: — ¿cuándo se dispara?

Se dispara en cada push en todas las ramas. Rara vez es deseable: un git push en una rama de feature en desarrollo lanzará un despliegue Pages en producción. Siempre limitar con branches: [main] o una lista explícita.

2. ¿Por qué id-token: write es necesario para Pages? ¿Para qué sirve el token OIDC?

actions/deploy-pages@v4 usa OIDC (OpenID Connect) para probar al servicio Pages que la petición viene de un run GitHub Actions autorizado, sin usar contraseña ni PAT (Personal Access Token). El token OIDC es efímero (vida limitada al run) y firmado por GitHub — más seguro que un secreto estático. id-token: write autoriza al runner a generar ese token para este workflow.

3. Dos pushes simultáneos en main — ¿qué hace concurrency?

Sin concurrency, GitHub lanza dos workflows en paralelo. El primero termina su upload de artefacto, el segundo arranca su propio upload, y Pages puede recibir las dos publicaciones en desorden → el orden final ya no está garantizado. Con concurrency: { group: pages, cancel-in-progress: false }, los dos runs se serializan: el segundo espera a que el primero termine. cancel-in-progress: true tendría otro efecto — cancelar el run en curso en cuanto arranca uno nuevo, útil para un rebuild ultra-rápido pero peligroso para Pages.

4. ¿Puede un secreto aparecer en los logs?

GitHub enmascara automáticamente cualquier valor registrado como secreto: aparece como *** en los logs. Pero si transformas el secreto (por ejemplo echo "$SECRET" | base64), el enmascaramiento ya no se aplica al valor transformado. Regla: nunca transformes un secreto en un run:, úsalo tal cual vía env: y pásalo directamente a la herramienta (aquí curl).

5. ¿Por qué conservar los dos workflows deployer-pages.yml y verifier-config.yml?

  • deployer-pages.yml publica en main: es el workflow de entrega. Solo corre después de un merge.
  • verifier-config.yml valida en las ramas de feature y en las PR: es el workflow de prevención. Impide que un config.json roto llegue a main.

Los dos forman una red de dos capas: la verificación bloquea aguas arriba, el despliegue entrega aguas abajo. Es el patrón CI (Continuous Integration) + CD (Continuous Deployment).

6. ¿Qué pasaría si build.py creara un archivo historique.log?

Nada duradero. El runner es una VM efímera destruida al final del run. El archivo desaparecería con la VM. Para conservar un historial entre runs, habría que commitearlo en el repositorio (regular, ensucia el repo), guardarlo en un artefacto con actions/upload-artifact (vida máxima 90 días), o enviarlo a un servicio externo (S3, Postgres, etc.).


Errores clásicos a evitar

SíntomaCausa probableSolución
Resource not accessible by integrationBloque permissions: ausente o incompletoAñadir pages: write + id-token: write
Ningún run se disparaErrata en on: (pushh:, pull_requests:)Verificar la ortografía de las claves YAML
Path does not exist: ./xxxLa ruta en upload-pages-artifact.path: no coincide con la carpeta de salida de build.pyVerificar path: = dist
La página publicada muestra el contenido antiguoCaché del navegadorCtrl+Shift+R para una recarga dura
El primer despliegue tarda > 5 minPropagación DNS de GitHub PagesNormal la primera vez, ~40 s después
Workflow rojo en el paso python outils/build.pyconfig.json inválidoLanzar python .\outils\build.py en local para ver el error exacto
El workflow corre pero la URL devuelve 404Source Pages sigue en modo «Deploy from a branch»Pasar a GitHub Actions en Settings → Pages
Dos runs Pages a la vez producen un contenido incoherenteconcurrency: ausenteAñadir el bloque concurrency: { group: pages }

Cómo evalúa el profesor tu trabajo

El profesor abre tres pestañas:

  1. Tu repositorio GitHub: estructura de archivos, contenido de config.json, presencia de .github/workflows/ con al menos los 3 workflows corregidos (los originales deployer-pages.yml y verifier-config.yml + las 3 averías reparadas).
  2. Tu pestaña Actions: al menos 2 runs verdes de Deployer sur GitHub Pages (misión 2), más los runs de la misión 3 (antes/después de la reparación).
  3. Tu sitio publicado: https://<tu>.github.io/<repo>/ — debe mostrarse con tus colores personalizados y un SHA reciente.

Luego lee tu RAPPORT.md:

  • Cuenta las capturas de pantalla (2 para la misión 2, 6 para la misión 3: antes/después × 3 averías).
  • Verifica que los diagnósticos de las averías están escritos con tus palabras, no copiados de este documento.
  • Nota la calidad de las respuestas a las 6 preguntas de reflexión.

Un informe limpio + un repositorio bien estructurado = nota alta fácil. La dificultad no es técnica, está en el rigor de la demostración.


Curso creado por el Dr. Haythem REHOUMA — Desarrollo y despliegue de soluciones de datos