Ir al contenido

Comprobaciones obligatorias de CI

Las comprobaciones obligatorias se aprobaron. Las pruebas no se ejecutaron.

Cómo las tareas de prueba omitidas de forma condicional pueden satisfacer la protección de ramas y cómo los controles que siempre se ejecutan evitan fusiones sin pruebas.

4 min de lecturaPor

Una optimización útil abrió una brecha en la política

Las tareas Unit y E2E solo comenzaban después de añadir una etiqueta run-tests. Eso nos permitía aplazar los conjuntos de pruebas costosos mientras se preparaba una solicitud de cambios, pero se suponía que cada fusión debía ejecutarlos. La protección de ramas no imponía esa intención.

Cuando la condición de la tarea se evaluaba como false, se omitía el proceso de pruebas. GitHub aun así daba a la tarea omitida una conclusión satisfactoria para las comprobaciones obligatorias. Por tanto, la solicitud de cambios podía aparecer en verde aunque no se hubiera ejecutado ningún comando de prueba.

Mantener condicional el proceso de pruebas

Conservé la etiqueta porque resultaba útil durante la revisión. El error fue convertir el propio proceso condicional en una comprobación obligatoria. GitHub podía satisfacer esa comprobación cuando se omitía el proceso.

unit-tests:
  if: |
    github.event_name == 'workflow_dispatch' ||
    (github.event.action == 'labeled' && github.event.label.name == 'run-tests') ||
    (github.event.action == 'synchronize' &&
      contains(github.event.pull_request.labels.*.name, 'run-tests'))
  steps:
    - run: pnpm test:unit:coverage

El proceso decide si debe ejecutarse ahora. Un control independiente decide si la solicitud de cambios puede fusionarse con seguridad. Mezclar ambas decisiones creó el falso estado verde.

Separa el proceso de la política

Añadí un pequeño control después de cada proceso. Declara el proceso en needs, se ejecuta con if: always() y solo pasa cuando el resultado es success. Un conjunto de pruebas omitido, cancelado o fallido ahora bloquea la fusión con un mensaje útil.

ci-gate:
  name: CI Gate (Unit)
  runs-on: ubuntu-latest
  needs: [unit-tests]
  if: always()
  steps:
    - name: Check test results
      run: |
        result="${{ needs.unit-tests.result }}"
        if [[ "$result" != "success" ]]; then
          echo "::error::Unit tests did not pass (result: $result)"
          exit 1
        fi
        echo "Unit tests passed"
Resultado previo  Control obligatorio
success            aprobado
failure            fallo
cancelled          fallo
skipped            fallo con un mensaje útil sobre la etiqueta

Mantén condicionales los procesos costosos

Los controles se encuentran delante de conjuntos de pruebas reales. La cobertura unitaria incluía 73 archivos de Jest, umbrales obligatorios y un aumento progresivo de cobertura. Playwright se ejecutaba en Chromium y WebKit con cuatro procesos, dos reintentos en CI y un estado de autenticación compartido.

Unit y E2E recibieron nombres de control estables. La protección de ramas puede seguir exigiendo esos nombres aunque cambie más adelante la implementación del proceso.

Exige el control, no el proceso

La protección de ramas se modificó para exigir CI Gate (Unit) y CI Gate (E2E), no los procesos condicionales. Así quedó explícito el contrato de fusión: un conjunto de pruebas esperado debe ejecutarse correctamente o producir un fallo visible que explique por qué no se ejecutó.

  • Mantén condicional el trabajo costoso cuando el repositorio tenga una razón clara para hacerlo.
  • Recopila siempre todos los resultados finales de procesos que afecten a la política de fusión.
  • Exige el nombre estable del agregador en la protección de ramas.
  • Haz que una validación omitida requiera una acción en lugar de aparecer en verde silenciosamente.