GitHub Actions
Três workflows por aplicativo, cada um com um job do seu tipo. O template .github/workflows/{pr,main,release}.yaml é a fonte da verdade; eles são reproduzidos com notas em references/workflows.md.
pull request ──► pr.yaml verificações apenas, nada publicado
merge para main ─► main.yaml imagem construída uma vez → ghcr.io/nuvraxis/<app>:sha-<short>, :main
tag vX.Y.Z ────► release.yaml mesma imagem retagada :vX.Y.Z, :latest · chart X.Y.Z → OCI · GitHub Release
Regras para todos os workflows
-
permissions: contents: readno topo; amplie por job apenas conforme necessário.packages: writepara jobs que enviam para GHCR,contents: writeapenas para o job que cria o Release. Semid-token: writeouattestations: write: proveniência e SBOM vêm do BuildKit, não deactions/attest*(que precisa do GitHub Enterprise para repositórios privados). -
Apenas
GITHUB_TOKEN. O login no GHCR usa${{ github.actor }}/${{ secrets.GITHUB_TOKEN }};ghusaGH_TOKEN: ${{ github.token }}. Sem tokens de acesso pessoal no CI. (Puxar pacotes privados do cluster é uma credencial diferente; vejahelm-nextjs.) -
Fixar actions por major (
@v7) e manter a tabela de SHA atualizada. O template usa tags major para legibilidade. Se a organização exigir pinagem por SHA, substitua cada@vNpelo SHA de references/action-pins.md e mantenha o comentário# vN.M.P. Atuais majors: 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. -
Toolchain:
pnpm/action-setupantes deactions/setup-node. O action-setup lê a versão do pnpm depackageManager; o setup-node lê.node-versione armazena em cache o store do pnpm (cache: pnpmprecisa do pnpm no PATH primeiro). Em seguida,pnpm install --frozen-lockfile. Nuncanpm ci. -
concurrencypor workflow e ref; cancela em andamento apenas em PRs. Um novo push para uma PR cancela a execução antiga. Em main e tags, as execuções sempre terminam: release.yaml precisa da imagem daquele commit exato. -
Nunca ecoar segredos ou interpolar entrada não confiável em
run:. Passe valores através deenv:e cite-os ("${APP}").${{ github.event.pull_request.title }}e similares nunca entram em um script.persist-credentials: falseno checkout quando o job não faz push para git. -
Todo job tem
timeout-minutes. Um build Docker pendurado, caso contrário, queima seis horas. -
Nomes são em minúsculas. GHCR rejeita repositórios em maiúsculas.
IMAGE: ghcr.io/nuvraxis/<app>é escrito em minúsculas emenv; o scaffold converte o nome do app para minúsculas.
pr.yaml
-
on: pull_requestcomtypes: [opened, synchronize, reopened, ready_for_review]e sem filtrobranches, para que PRs empilhadas contra branches de funcionalidade também sejam verificadas. Todo job temif: ${{ !github.event.pull_request.draft }}; marcar como pronto dispara a execução. -
Quatro jobs paralelos:
quality(biome ci --reporter=github, stylelint,turbo run typecheck test --affected,pnpm audit --audit-level high),build(turbo run build --affected),docker(construir uma plataforma comload: true, executar apenas leitura com capacidades removidas, curl/api/health),helm(helm lint --stricte kubeconform em ambos os arquivos de valores).--affectedprecisa defetch-depth: 0. -
Nada é enviado de uma PR.
push: false, cache somente leitura (apenascache-from), sem login no registro.
main.yaml
-
on: push: branches: [main]constrói a imagem uma vez, para ambas as arquiteturas, e a envia. Tags dedocker/metadata-action:type=sha,format=short,prefix=sha-etype=raw,value=main,flavor: latest=false.latestpertence aos releases. -
provenance: mode=max,sbom: true,cache-from/to: type=gha,scope=<app>,mode=max. Proveniência e SBOM são anexados ao índice da imagem; o release.yaml os carrega ao retagar.NEXT_DEPLOYMENT_ID=${{ github.sha }}é o argumento de build para proteção contra skew. -
main.yaml não publica o chart e não reexecuta as verificações da PR. A proteção de branch exige pr.yaml; main apenas produz o artefato.
release.yaml
-
on: push: tags: ['v*.*.*'], então, em ordem:- Falhar a menos que a tag seja exatamente
vMAJOR.MINOR.PATCHe seu commit seja um ancestral deorigin/main. - Não reconstruir. Se
ghcr.io/nuvraxis/<app>:sha-<short>não existir, falhar com "deixe main.yaml terminar, então reexecute". Sem build de fallback. docker buildx imagetools create --tag :vX.Y.Z --tag :latest <sha-image>: uma cópia no nível do manifesto que mantém ambas as arquiteturas, proveniência e SBOM, no mesmo digest.helm package --version X.Y.Z --app-version vX.Y.Z,helm pushparaoci://ghcr.io/nuvraxis/charts.gh release create vX.Y.Z --verify-tag --generate-notescom o chart.tgz,image-digest.txtesbom.spdx.jsonanexados.
- Falhar a menos que a tag seja exatamente
-
O ritual de release: merge para main → aguardar o main.yaml ficar verde →
git tag vX.Y.Z && git push origin vX.Y.Z. Marcar a tag antes do main.yaml terminar faz com que o passo 2 falhe de propósito; reexecute o job de release assim que a imagem existir. Um release ruim é corrigido com uma nova tag de patch, nunca movendo uma tag.
Acelerando (apenas quando necessário)
- arm64 sob QEMU é a parte lenta do main.yaml. Substitua por uma matrix em
ubuntu-24.04-arm+ubuntu-latestenviando por digest, depois um job de merge comimagetools create. Mantenha as tags e o índice único. - Cache remoto do Turborepo para pr.yaml: veja
pnpm-turborepo.
Verificar
docker run --rm -v "$PWD:/repo" -w /repo rhysd/actionlint:latest # lint em todos os workflows
gh workflow list && gh run list --limit 5
gh run view <run-id> --log-failed
Após um release: docker buildx imagetools inspect ghcr.io/nuvraxis/<app>:vX.Y.Z mostra ambas as plataformas, e helm show chart oci://ghcr.io/nuvraxis/charts/<app> --version X.Y.Z mostra appVersion: vX.Y.Z.
Fontes
- 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