GitHub Actions
Tres flujos de trabajo por aplicación, cada uno con un solo trabajo de su tipo. La plantilla .github/workflows/{pr,main,release}.yaml es la fuente de verdad; se reproducen con notas en references/workflows.md.
pull request ──► pr.yaml solo verificaciones, nada publicado
merge a main ─► main.yaml imagen construida una vez → ghcr.io/nuvraxis/<app>:sha-<short>, :main
tag vX.Y.Z ────► release.yaml misma imagen retagueada :vX.Y.Z, :latest · chart X.Y.Z → OCI · GitHub Release
Reglas para cada flujo de trabajo
-
permissions: contents: readen la parte superior; ampliar por trabajo solo cuando sea necesario.packages: writepara trabajos que suben a GHCR,contents: writesolo para el trabajo que crea el Release. Noid-token: writeniattestations: write: la proveniencia y el SBOM provienen de BuildKit, no deactions/attest*(que necesita GitHub Enterprise para repositorios privados). -
Solo
GITHUB_TOKEN. El inicio de sesión en GHCR usa${{ github.actor }}/${{ secrets.GITHUB_TOKEN }};ghusaGH_TOKEN: ${{ github.token }}. Sin tokens de acceso personal en CI. (Extraer paquetes privados desde el clúster es una credencial diferente; consultehelm-nextjs). -
Fijar versiones mayores de acciones (
@v7) y mantener la tabla de SHA actualizada. La plantilla usa etiquetas principales para legibilidad. Si la organización requiere fijación por SHA, reemplace cada@vNcon el SHA de references/action-pins.md y mantenga el comentario# vN.M.P. Versiones mayores actuales: checkout v7, setup-node v7, pnpm/action-setup v6, setup-qemu v4, setup-buildx v4, login v4, metadata v6, build-push v7, azure/setup-helm v5. -
Cadena de herramientas:
pnpm/action-setupantes queactions/setup-node. action-setup lee la versión de pnpm desdepackageManager; setup-node lee.node-versiony almacena en caché el almacén de pnpm (cache: pnpmnecesita pnpm en PATH primero). Luegopnpm install --frozen-lockfile. Nuncanpm ci. -
concurrencypor flujo de trabajo y ref; cancelar en curso solo en PRs. Una nueva subida a un PR cancela la ejecución anterior. En main y tags, las ejecuciones siempre terminan: release.yaml necesita la imagen de ese commit exacto. -
Nunca hacer eco de secretos ni interpolar entradas no confiables en
run:. Pasar valores a través deenv:y citarlos ("${APP}").${{ github.event.pull_request.title }}y similares nunca van dentro de un script.persist-credentials: falseen checkout cuando el trabajo no sube a git. -
Cada trabajo tiene
timeout-minutes. De lo contrario, una construcción de Docker colgada consume seis horas. -
Los nombres están en minúsculas. GHCR rechaza repositorios en mayúsculas.
IMAGE: ghcr.io/nuvraxis/<app>se escribe en minúsculas enenv; el andamio convierte el nombre de la aplicación a minúsculas.
pr.yaml
-
on: pull_requestcontypes: [opened, synchronize, reopened, ready_for_review]y sin filtrobranches, para que también se verifiquen los PRs apilados contra ramas de características. Cada trabajo tieneif: ${{ !github.event.pull_request.draft }}; marcar como listo activa la ejecución. -
Cuatro trabajos en paralelo:
quality(biome ci --reporter=github, stylelint,turbo run typecheck test --affected,pnpm audit --audit-level high),build(turbo run build --affected),docker(construir una plataforma conload: true, ejecutarla como solo lectura con capacidades eliminadas, curl/api/health),helm(helm lint --stricty kubeconform en ambos archivos de valores).--affectednecesitafetch-depth: 0. -
No se sube nada desde un PR.
push: false, caché de solo lectura (cache-fromsolo), sin inicio de sesión en el registro.
main.yaml
-
on: push: branches: [main]construye la imagen una vez, para ambas arquitecturas, y la sube. Etiquetas dedocker/metadata-action:type=sha,format=short,prefix=sha-ytype=raw,value=main,flavor: latest=false.latestpertenece a los lanzamientos. -
provenance: mode=max,sbom: true,cache-from/to: type=gha,scope=<app>,mode=max. La proveniencia y el SBOM se adjuntan al índice de la imagen; release.yaml los transporta cuando retaguea.NEXT_DEPLOYMENT_ID=${{ github.sha }}es el argumento de compilación para la protección contra sesgos. -
main.yaml no publica el chart ni vuelve a ejecutar las comprobaciones del PR. La protección de ramas requiere pr.yaml; main solo produce el artefacto.
release.yaml
-
on: push: tags: ['v*.*.*'], luego en orden:- Fallar a menos que la etiqueta sea exactamente
vMAJOR.MINOR.PATCHy su commit sea un ancestro deorigin/main. - No reconstruir. Si
ghcr.io/nuvraxis/<app>:sha-<short>no existe, fallar con "deje que main.yaml termine, luego vuelva a ejecutar". Sin construcción de respaldo. docker buildx imagetools create --tag :vX.Y.Z --tag :latest <sha-image>: una copia a nivel de manifiesto que mantiene ambas arquitecturas, proveniencia y SBOM, en el mismo resumen.helm package --version X.Y.Z --app-version vX.Y.Z,helm pushaoci://ghcr.io/nuvraxis/charts.gh release create vX.Y.Z --verify-tag --generate-notescon el chart.tgz,image-digest.txtysbom.spdx.jsonadjuntos.
- Fallar a menos que la etiqueta sea exactamente
-
El ritual de lanzamiento: fusionar a main → esperar a que main.yaml se ponga verde →
git tag vX.Y.Z && git push origin vX.Y.Z. Etiquetar antes de que main.yaml termine provoca que el paso 2 falle a propósito; vuelva a ejecutar el trabajo de lanzamiento una vez que la imagen exista. Un lanzamiento defectuoso se corrige con una nueva etiqueta de parche, nunca moviendo una etiqueta.
Acelerar las cosas (solo cuando sea necesario)
- arm64 bajo QEMU es la parte lenta de main.yaml. Reemplazar con una matriz en
ubuntu-24.04-arm+ubuntu-latestsubiendo por resumen, luego un trabajo de fusión conimagetools create. Mantener las etiquetas y el índice único. - Caché remota de Turborepo para pr.yaml: consulte
pnpm-turborepo.
Verificar
docker run --rm -v "$PWD:/repo" -w /repo rhysd/actionlint:latest # lint de todos los flujos de trabajo
gh workflow list && gh run list --limit 5
gh run view <run-id> --log-failed
Después de un lanzamiento: docker buildx imagetools inspect ghcr.io/nuvraxis/<app>:vX.Y.Z muestra ambas plataformas, y helm show chart oci://ghcr.io/nuvraxis/charts/<app> --version X.Y.Z muestra appVersion: vX.Y.Z.
Fuentes
- https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions
- https://docs.github.com/en/actions/security-for-github-actions/security-guides/security-hardening-for-github-actions
- https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/controlling-permissions-for-github_token
- https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry
- https://github.com/pnpm/action-setup
- https://github.com/actions/setup-node
- https://github.com/docker/metadata-action
- https://github.com/docker/build-push-action
- https://docs.docker.com/build/ci/github-actions/cache/#github-cache
- https://docs.docker.com/build/metadata/attestations/
- https://docs.docker.com/reference/cli/docker/buildx/imagetools/create/
- https://helm.sh/docs/topics/registries/
- https://cli.github.com/manual/gh_release_create
- https://turborepo.dev/docs/reference/run#--affected