Release e tag manual

Os fronts da Alcance publicados na Vercel seguem o mesmo padrão: cada repositório tem um único workflow no GitHub Actions, o CI de PR, e a tag vX.Y.Z e o GitHub Release são criados à mão em toda versão. Não existe workflow de tag, de release, de smoke test agendado nem de auto-merge do Dependabot.

O motivo é custo: cada workflow extra (tag automática, release, cron de smoke test, automações do Dependabot, CI repetido no push em main) gastava minutos do Actions sem ser gate de qualidade. O deploy de produção não depende do Actions: é a integração Git da Vercel que publica o merge na branch padrão.

A tag não faz deploy

Nestes repositórios a tag é o registro da versão, não o gatilho. Produção muda no merge (Vercel). O oposto vale para a webapi-alcance, que não está na Vercel: lá o deploy é pela tag, no runner self-hosted, e ela fica fora deste padrão.

O workflow único

  • Gatilho: pull_request para a branch padrão e workflow_dispatch. Push na branch padrão não roda o CI: a Vercel já builda o merge.
  • Conteúdo: os gates de qualidade de cada repo (lint, typecheck, teste e build). Nenhum gate foi retirado.
  • Sempre com concurrency (cancel-in-progress: true) e timeout-minutes em todo job.
  • Dependabot: o .github/dependabot.yml continua abrindo os PRs, que são revisados e mesclados à mão (nada os mescla nem fecha sozinho).

Com o Actions bloqueado por billing, o run aparece vermelho com 0 steps. Isso não é falha do PR: confira com gh run view <id>.

Passo a passo (obrigatório em toda versão)

  1. A versão é bumpada no PR, no lugar que o repositório usa (ver a tabela abaixo), com a entrada da versão no CHANGELOG.md.

  2. O PR é aberto pela conta limarios. Confira com gh api user -q .login; troque com gh auth switch -u limarios.

  3. O merge é feito pela conta alcancecontabilidade, com merge commit: gh pr merge N --repo Alcance-Contabilidade/<repo> --merge --match-head-commit <sha-da-head>. Nunca squash: no squash o autor do commit é quem abriu o PR, e a Vercel bloqueia o deploy de produção ("Deployment was blocked"), porque só a alcancecontabilidade é membro do time.

  4. Confira o deploy de produção da Vercel no SHA do merge (tem de dar success):

    R=<repo>
    SHA=$(gh pr view N --repo Alcance-Contabilidade/$R --json mergeCommit -q .mergeCommit.oid)
    gh api repos/Alcance-Contabilidade/$R/commits/$SHA/status \
      -q '.statuses[] | select(.context=="Vercel") | .state'
  5. Crie a tag e o release como alcancecontabilidade, no SHA do merge, com as notas tiradas da entrada da versão no CHANGELOG.md. Rode no clone local, depois de git fetch origin:

    V=X.Y.Z
    gh api repos/Alcance-Contabilidade/$R/git/ref/tags/v$V >/dev/null 2>&1 \
      && echo "ERRO: v$V já tem tag, o PR está errado"
     
    # CHANGELOG com cabeçalho "## [X.Y.Z] - AAAA-MM-DD":
    git show $SHA:CHANGELOG.md \
      | awk -v v="$V" 'index($0, "## [" v "]")==1 {c=1; next} c && /^## / {exit} c {print}' \
      > /tmp/notas-v$V.md
    # CHANGELOG com cabeçalho de badge "## ![Version: X.Y.Z](...)":
    git show $SHA:CHANGELOG.md \
      | awk -v v="$V" 'index($0, "## ![Version: " v "]")==1 {c=1; next} c && /^## / {exit} c {print}' \
      > /tmp/notas-v$V.md
     
    test -s /tmp/notas-v$V.md || echo "ERRO: notas vazias, não crie o release"
    gh release create v$V --repo Alcance-Contabilidade/$R --target $SHA \
      --title "v$V" --notes-file /tmp/notas-v$V.md

    Use só o awk do formato do repositório. Extraia com awk (ou grep -E), nunca com grep BRE, que já apagou entrada de CHANGELOG. Confira que o arquivo de notas não está vazio antes de criar o release.

  6. Confira com gh release view v$V --repo Alcance-Contabilidade/$R: tag, commit alvo e notas.

  7. Uma tag por versão, sem pular e sem repetir. Se a versão do PR já tem tag, o PR está errado: corrija a versão antes do merge.

Repositórios

RepositórioBranch padrãoOnde fica a versãoCHANGELOG: formato e onde entra a versão novaWorkflow único
webapp-hubmasterpyproject.toml (version)Badge ## ![Version: X.Y.Z](...), no fim do arquivoci-cd.yml
webapp-siscontabilmainpackage.json (version)## [X.Y.Z] - AAAA-MM-DD, no topo, abaixo de ## [Unreleased]ci.yml
webapp-portaldoclientemainpackage.json (version)## [X.Y.Z] - AAAA-MM-DD, no topo, abaixo de ## [Unreleased]ci.yml
webapp-analyticsmainpackage.json (version)## [X.Y.Z] - AAAA-MM-DD, no fim do arquivoci.yml
webapp-certidaomainCabeçalho do CHANGELOG.md (package.json fica em 0.0.0)Badge ## ![Version: X.Y.Z](...), no fim, antes de ## Não lançadoci.yml
webapp-bobtaxintelligencemainpackage.json (version)Badge ## ![Version: X.Y.Z](...), no fim do arquivoci.yml
webapp-nfs-repasse-medicomainCabeçalho do CHANGELOG.md (package.json fica em 0.0.0)## [X.Y.Z] - AAAA-MM-DD, no topo, abaixo de ## [Não Lançado]ci.yml
site-alcancecontabilidademainpackage.json (version)## [X.Y.Z] - AAAA-MM-DD, no topo, abaixo de ## [Não lançado]ci.yml
mcp-alcancecontabilidademainpackage.json (version)## [X.Y.Z] - AAAA-MM-DD, no topo, abaixo de ## [Não lançado]ci.yml
site-docsmainpackage.json, siteConfig.version e o badge do README.md## [X.Y.Z] - AAAA-MM-DD, no topo, abaixo de ## [Não lançado]ci.yml

O passo a passo de cada repositório está no CLAUDE.md dele (no site-docs, no CONTRIBUTING.md), na seção "Release e tag (manual, obrigatório em toda versão)".