feat(release): deploy de produção fecha as issues do release (approved → done) [INFRA-69129] #95

Closed
tmf-ia wants to merge 0 commits from feat/INFRA-69129-done-no-deploy into develop
Owner

O que

O deploy de produção por tag, quando termina com sucesso, leva a done as issues do Hub que estavam em approved e entraram no release. São três passos novos no job deploy do release.yml e um script novo, scripts/hub_done_no_deploy.py.

Por quê

Nenhum workflow da frota levava issue a done. O hub-issue-sync.yml para em approved no merge em develop e, por desenho, não faz nada no merge em main ("o deploy leva a done"), mas nenhum deploy fazia essa parte. Hoje há 224 issues paradas em approved. Decisão do operador: "o certo era ao fechar o release ele fechar".

Desenho

  • Gatilho: só depois que deploy, verificação pública e commit status passaram (if: sem always()), e só com environment == prod e deploy_hub_done == true.
  • Escopo: as chaves [PROJ-N] dos commits git log <tag anterior>..<tag>, lidas só do assunto. No merge do Forgejo o assunto já traz a branch (... from feat/KEY-slug). O corpo do commit nunca é lido, e a regex é a mesma do hub-issue-sync (um teste confere). A tag anterior é a PREV_TAG do deploy, se for uma tag estrita ancestral da atual. Se não for, vale a maior tag vX.Y.Z ancestral. No primeiro release entra o histórico todo, com teto de 300 chaves.
  • Todos os commits da chave na tag: a chave é pulada quando algum commit com ela no assunto está em origin/develop e não está na tag. Commits equivalentes por patch-id não contam (git log --cherry-pick --right-only <tag>...origin/develop), então um hotfix aplicado com cherry-pick conta como "na tag". Limite conhecido: dois commits vazios têm o mesmo patch-id, então um commit vazio em develop não é visto como "fora da tag".
  • Regra: a issue só passa de approved para done, pela API v2 (GET /api/v2/issues/{key} e POST .../transition, como o hub-issue-sync). Qualquer outro status fica como está e a issue é pulada, com o motivo. Se o Hub recusar (por exemplo, por filha aberta), a issue também é pulada, com o detail que o Hub devolveu.
  • Rastro: cada issue fechada recebe um comentário em HTML com a tag, o SHA e o link do run. O resumo vai para o $GITHUB_STEP_SUMMARY, com as fechadas, as puladas e o motivo de cada uma.
  • Nunca derruba o deploy: os três passos têm continue-on-error. O script sai sempre com 0 e transforma qualquer falha em ::warning::. Depois de 3 falhas de rede seguidas, ele para de chamar o Hub.
  • Token: o mesmo mecanismo do hub-issue-sync: HUB_TOKEN vem do Infisical do produto (infisical_project, infisical_env (vazio vira prod), infisical_path), pela action infisical-secrets. O token só passa por $GITHUB_ENV, nunca aparece como ${{ }} em run: e nunca é impresso. O reusável continua sem bloco secrets: (INFRA-64944).
  • Passo no release.yml em vez de um reusável novo: o job deploy já tem o que o fechamento precisa (resultado do deploy, TAG/TAG_SHA, prev_tag, o ci-shared na mesma ref). Fazendo como passo, o produto não precisa adotar nada.
  • Chave deploy_hub_done, ligada por padrão: o operador quer que feche, e ligar por padrão é seguro porque uma falha do Hub nunca derruba o deploy. Para desligar num produto, basta deploy_hub_done: false.

Validação

  • tests/hub-done-no-deploy/ (24 testes) monta um repo git temporário com tags e merges --no-ff de verdade e usa um Hub simulado. Os casos cobertos:
    • chaves dentro e fora do intervalo;
    • chave citada só no corpo do commit, que é ignorada;
    • chave com commit fora da tag, tanto commit avulso quanto merge de branch em develop;
    • hotfix com cherry-pick, que conta como "na tag";
    • status review e done, que são pulados sem regredir;
    • filha aberta: o Hub responde 409 e a issue é pulada;
    • Hub fora, cliente que lança exceção e processo real com conexão recusada: todos saem com 0 e aviso, sem imprimir o token;
    • comentário com tag, SHA e run, e o resumo no $GITHUB_STEP_SUMMARY;
    • estrutura do yaml: passos depois do deploy, continue-on-error, nenhum ${{ com segredo dentro de run:;
    • schema e ci_config release.
  • Todas as suítes passaram localmente: release 373, ci-config 150, ci-unico 118, hub-issue-sync, hub-done-no-deploy 24 e as demais. Em generate-docs, 2 testes falham só nesta máquina porque falta o binário python; com um alias de python para python3, a suíte passa inteira.

Não verificado: nenhum deploy real ainda. Para adotar, o produto que chama o reusável precisa ter HUB_TOKEN no Infisical. Este PR não fecha as issues paradas em approved de releases anteriores, só as do intervalo de cada deploy.

🤖 Generated with Claude Code

https://claude.ai/code/session_01ES1xwVdpQV69zEsuLLKzx2

## O que O deploy de produção por tag, quando termina com sucesso, leva a `done` as issues do Hub que estavam em `approved` e entraram no release. São três passos novos no job `deploy` do `release.yml` e um script novo, `scripts/hub_done_no_deploy.py`. ## Por quê Nenhum workflow da frota levava issue a `done`. O `hub-issue-sync.yml` para em `approved` no merge em `develop` e, por desenho, não faz nada no merge em `main` ("o deploy leva a done"), mas nenhum deploy fazia essa parte. Hoje há 224 issues paradas em `approved`. Decisão do operador: "o certo era ao fechar o release ele fechar". ## Desenho - **Gatilho:** só depois que deploy, verificação pública e commit status passaram (`if:` sem `always()`), e só com `environment == prod` e `deploy_hub_done == true`. - **Escopo:** as chaves `[PROJ-N]` dos commits `git log <tag anterior>..<tag>`, lidas só do **assunto**. No merge do Forgejo o assunto já traz a branch (`... from feat/KEY-slug`). O corpo do commit nunca é lido, e a regex é a mesma do `hub-issue-sync` (um teste confere). A tag anterior é a `PREV_TAG` do deploy, se for uma tag estrita ancestral da atual. Se não for, vale a maior tag `vX.Y.Z` ancestral. No primeiro release entra o histórico todo, com teto de 300 chaves. - **Todos os commits da chave na tag:** a chave é pulada quando algum commit com ela no assunto está em `origin/develop` e não está na tag. Commits equivalentes por patch-id não contam (`git log --cherry-pick --right-only <tag>...origin/develop`), então um hotfix aplicado com cherry-pick conta como "na tag". Limite conhecido: dois commits vazios têm o mesmo patch-id, então um commit vazio em develop não é visto como "fora da tag". - **Regra:** a issue só passa de `approved` para `done`, pela API v2 (`GET /api/v2/issues/{key}` e `POST .../transition`, como o hub-issue-sync). Qualquer outro status fica como está e a issue é pulada, com o motivo. Se o Hub recusar (por exemplo, por filha aberta), a issue também é pulada, com o `detail` que o Hub devolveu. - **Rastro:** cada issue fechada recebe um comentário em HTML com a tag, o SHA e o link do run. O resumo vai para o `$GITHUB_STEP_SUMMARY`, com as fechadas, as puladas e o motivo de cada uma. - **Nunca derruba o deploy:** os três passos têm `continue-on-error`. O script sai sempre com 0 e transforma qualquer falha em `::warning::`. Depois de 3 falhas de rede seguidas, ele para de chamar o Hub. - **Token:** o mesmo mecanismo do `hub-issue-sync`: `HUB_TOKEN` vem do Infisical do produto (`infisical_project`, `infisical_env` (vazio vira `prod`), `infisical_path`), pela action `infisical-secrets`. O token só passa por `$GITHUB_ENV`, nunca aparece como `${{ }}` em `run:` e nunca é impresso. O reusável continua sem bloco `secrets:` (INFRA-64944). - **Passo no `release.yml` em vez de um reusável novo:** o job `deploy` já tem o que o fechamento precisa (resultado do deploy, `TAG`/`TAG_SHA`, `prev_tag`, o ci-shared na mesma ref). Fazendo como passo, o produto não precisa adotar nada. - **Chave `deploy_hub_done`, ligada por padrão:** o operador quer que feche, e ligar por padrão é seguro porque uma falha do Hub nunca derruba o deploy. Para desligar num produto, basta `deploy_hub_done: false`. ## Validação - `tests/hub-done-no-deploy/` (24 testes) monta um repo git temporário com tags e merges `--no-ff` de verdade e usa um Hub simulado. Os casos cobertos: - chaves dentro e fora do intervalo; - chave citada só no corpo do commit, que é ignorada; - chave com commit fora da tag, tanto commit avulso quanto merge de branch em develop; - hotfix com cherry-pick, que conta como "na tag"; - status `review` e `done`, que são pulados sem regredir; - filha aberta: o Hub responde 409 e a issue é pulada; - Hub fora, cliente que lança exceção e processo real com conexão recusada: todos saem com 0 e aviso, sem imprimir o token; - comentário com tag, SHA e run, e o resumo no `$GITHUB_STEP_SUMMARY`; - estrutura do yaml: passos depois do deploy, `continue-on-error`, nenhum `${{` com segredo dentro de `run:`; - schema e `ci_config release`. - Todas as suítes passaram localmente: release 373, ci-config 150, ci-unico 118, hub-issue-sync, hub-done-no-deploy 24 e as demais. Em `generate-docs`, 2 testes falham só nesta máquina porque falta o binário `python`; com um alias de `python` para `python3`, a suíte passa inteira. **Não verificado:** nenhum deploy real ainda. Para adotar, o produto que chama o reusável precisa ter `HUB_TOKEN` no Infisical. Este PR não fecha as issues paradas em `approved` de releases anteriores, só as do intervalo de cada deploy. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01ES1xwVdpQV69zEsuLLKzx2
feat(release): deploy de produção fecha as issues do release (approved → done) [INFRA-69129]
All checks were successful
PR checks (ci-shared) / testes (pull_request) Successful in 3m27s
03e12b2bc7
Nada na frota levava issue a done: o hub-issue-sync para em approved no merge em develop
e não mexe no merge em main ("o deploy leva a done"), mas nenhum deploy fazia isso.

- release.yml (job deploy): três passos depois do deploy por tag com sucesso, só em prod,
  atrás da chave nova deploy_hub_done do ci-config (padrão true), todos com
  continue-on-error — falha do Hub vira :⚠️:, nunca derruba o deploy.
  HUB_TOKEN do Infisical do produto (infisical_*), mesmo mecanismo do hub-issue-sync.
- scripts/hub_done_no_deploy.py: chaves do assunto dos commits <tag anterior>..<tag>
  (branch do merge pelo assunto, corpo nunca, mesma regex do hub-issue-sync); pula chave
  com commit em origin/develop fora da tag (git log --cherry-pick --right-only); só
  approved → done (API v2); recusa do Hub (filha aberta) = pulada; comentário com tag,
  SHA e run; resumo no GITHUB_STEP_SUMMARY.
- tests/hub-done-no-deploy: repo git temporário com tags, Hub falso e contrato do yaml.
- docs (guia de adoção, scripts, workflows reusáveis), exemplo do ci-config e CHANGELOG.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ES1xwVdpQV69zEsuLLKzx2
Author
Owner

Substituído pelo PR da branch feat/INFRA-69129-done-no-deploy-v2 (Lineu, depois de revisão). Ajustes: só move chaves dos prefixos do produto (hub_done_prefixos), não move epic/initiative/story-container, pula Revert, considera commits em origin/epic/*, modo ensaio no 1º deploy e com mais de 50 candidatas, e documenta que a trava HUB_STATUS_HUMANO não se aplica (decisão do operador de 09/10). Política autorizada pelo operador na sessão ORG em 09/10.

Substituído pelo PR da branch feat/INFRA-69129-done-no-deploy-v2 (Lineu, depois de revisão). Ajustes: só move chaves dos prefixos do produto (hub_done_prefixos), não move epic/initiative/story-container, pula Revert, considera commits em origin/epic/*, modo ensaio no 1º deploy e com mais de 50 candidatas, e documenta que a trava HUB_STATUS_HUMANO não se aplica (decisão do operador de 09/10). Política autorizada pelo operador na sessão ORG em 09/10.
tmf-ia closed this pull request 2026-10-09 21:07:38 -03:00
All checks were successful
PR checks (ci-shared) / testes (pull_request) Successful in 3m27s

Pull request closed

Sign in to join this conversation.
No reviewers
No labels
seguranca
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
TMF/ci-shared!95
No description provided.