Skip to content

[DX-3325] Release automático del SDK al mergear PRs con label release:* - #138

Merged
pibahamondesw merged 3 commits into
masterfrom
dx-3325-release-automatico-de-fintoc-python-al-mergear-prs-con-label
Nov 6, 2026
Merged

pibahamondesw merged 3 commits into
masterfrom
dx-3325-release-automatico-de-fintoc-python-al-mergear-prs-con-label

Conversation

@pibahamondesw

@pibahamondesw pibahamondesw commented Nov 6, 2026 •

Copy link
Copy Markdown
Contributor

Description

Contexto. Hoy el SDK solo se publica disparando a mano el workflow release (workflow_dispatch). Queremos que los SDK se publiquen solos al mergear, sin darle a Compose actions: write para disparar el workflow. Se acordó que el release salga de GitHub Actions al mergear a la rama principal, con la misma convención en fintoc-ruby, fintoc-node y fintoc-cli. Issue: DX-3325.

¿Qué hay de nuevo?

  • release también corre en push a master. El workflow_dispatch queda igual, como respaldo manual.
  • Un job resolve decide bump y notas:
    • En push busca el PR mergeado cuyo merge_commit_sha es el commit pusheado (commits/{sha}/pulls, con hasta 3 intentos cada 10 s si GitHub todavía no lo asocia). El bump sale de su label release:patch|minor|major.
    • Sin PR o sin label release:* no se publica: el job release queda skipped, no falla. Esto cubre también el commit de versión que empuja prepare, que no tiene PR.
    • Más de un label release:* (o uno desconocido) hace fallar el workflow con un mensaje claro.
    • Las notas son la sección ## Release notes del body del PR, hasta el siguiente ## , sin comentarios HTML.
  • Si las notas quedan vacías, se usan las notas autogeneradas de GitHub (releases/generate-notes con el tag de prepare). Aplica también al workflow_dispatch sin notas.
  • El job release tiene concurrency: release sin cancel-in-progress, para que nunca corran dos releases a la vez. Está a nivel de job para que los pushes sin release (que solo corren resolve) no ocupen el grupo ni desplacen un release pendiente.
  • Los jobs corren en blacksmith-2vcpu-ubuntu-2404. PyPI se publica con PYPI_API_TOKEN y no con trusted publishing, así que release puede correr en Blacksmith.
  • release parte de master y, en push, aborta antes de publicar si master tiene otros commits después del PR mergeado (ver Consideraciones).
  • El PR template tiene una sección ## Release notes, justo después de Description, que explica la convención. RELEASING.md documenta el flujo nuevo.

Tests

  • .github/scripts/resolve-release.test.sh (corre en CI, job release-scripts de tests) cubre: sección al final con comentarios, sección seguida de otra (con \r\n), solo comentario, sin sección, sin label, dos labels, label desconocido, PR no mergeado, workflow_dispatch con y sin notas.
  • El script corrido contra el payload real de [ONB-4205] [Compose] [Compose] Agregar actualización de organizations #137 (merge commit de Compose): sin label se salta, y con label y sección las notas se cortan antes del footer de Compose.
  • La consulta de compare del chequeo, probada contra este repo: con el mismo SHA no lista nada, un commit release: v2.29.0 posterior se ignora, y commits de otro PR se listan.
  • generate-notes probado contra este repo con un tag inexistente y el SHA completo de master.
  • actionlint y shellcheck: lo nuevo no tiene hallazgos. Solo quedan los que ya existían en master (actions @v3, el typo steps.poetry-cache, $HOME sin comillas), que no toqué.

Release notes

Requirements

Ver Consideraciones: hay que crear los labels antes de mergear.

Additional changes

None.

Consideraciones

  • Antes de mergear: crear los labels release:patch, release:minor y release:major en el repo. Sin ellos, los PRs nunca van a publicar.
  • El lado de Compose (poner el label y llenar ## Release notes en sus PRs) lo ve Francisca.
  • El body y el título del PR son input no confiable: solo llegan a los scripts por env: o por archivo, nunca interpolados con ${{ }} en un run:. resolve tiene permisos mínimos (contents: read, pull-requests: read).
  • generate-notes corre justo después de prepare y antes de publicar en PyPI, así que si falla no queda nada publicado.
  • Para el PR template uso .github/pull_request_template.md, que es el que GitHub usa por defecto. PULL_REQUEST_TEMPLATE/release.md solo se aplica con ?template=release.md y es un template antiguo de descripción de versión, así que no lo toqué. El template está en inglés, así que la sección nueva también.
  • ## Release notes va justo después de Description y no al final. Así la sección siguiente la cierra y no se cuela en las notas públicas lo que venga después, como el footer de Compose (🤖🐙 Created with Compose · [View session](…)). Compose sigue el orden del template, así que esto le sirve si mantiene ese orden.
  • Releases encadenados (igual que fintoc-cli#62): el job release hace checkout de master y no de github.sha. Así un release que quedó en cola parte del commit de versión del anterior y no calcula un tag que ya existe. A cambio, en push verifica antes de publicar que master no tenga commits posteriores a github.sha aparte de commits release: .... Si los tiene, aborta sin publicar, para no sacar cambios de otro PR con el bump y las notas de este. El siguiente release los incluye, o se usa el dispatch si hace falta un bump mayor.
  • concurrency deja un solo run pendiente por grupo. Con tres merges con label seguidos, el del medio se cancela y su cambio sale en el siguiente release (o se rescata con el dispatch).
  • Riesgo que ya existía con el dispatch y ahora es más probable: si alguien mergea a master mientras corre el release, el push de finalize falla después de publicar en PyPI (el recovery está en RELEASING.md). La solución de raíz (rebase antes del push) va en release-action.
  • resolve-release.sh y su test son los mismos de fintoc-ruby ([DX-3324] Release automático al mergear PRs con label release:* fintoc-ruby#47), para mantener una sola implementación en los 4 SDKs.
  • Este PR no lleva label release:*, así que al mergearlo no publica.

¿Es seguro hacer rollback? Sí
¿Cuáles son los pasos para hacer rollback? Revert PR

@pibahamondesw pibahamondesw self-assigned this Nov 6, 2026
@pibahamondesw
pibahamondesw force-pushed the dx-3325-release-automatico-de-fintoc-python-al-mergear-prs-con-label branch from e78bfa4 to 1b07d98 Compare November 6, 2026 13:32
@pibahamondesw

Copy link
Copy Markdown
Contributor Author

fin review

Comment thread .github/workflows/release.yml Resolved
Comment thread .github/workflows/release.yml Resolved
Comment thread .github/scripts/resolve_release.py Resolved
@pibahamondesw
pibahamondesw force-pushed the dx-3325-release-automatico-de-fintoc-python-al-mergear-prs-con-label branch from 1b07d98 to 1316d8f Compare November 6, 2026 13:37
@pibahamondesw

Copy link
Copy Markdown
Contributor Author

fin review

@fin-review fin-review Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM ✅

@pibahamondesw
pibahamondesw force-pushed the dx-3325-release-automatico-de-fintoc-python-al-mergear-prs-con-label branch from 1316d8f to 9472e8c Compare November 6, 2026 13:49
@pibahamondesw

Copy link
Copy Markdown
Contributor Author

fin review

@fin-review fin-review Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM ✅

@pibahamondesw
pibahamondesw marked this pull request as ready for review November 6, 2026 21:24

@fin-review fin-review Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM ✅

@pibahamondesw
pibahamondesw merged commit 30b481e into master Nov 6, 2026
6 checks passed
@pibahamondesw
pibahamondesw deleted the dx-3325-release-automatico-de-fintoc-python-al-mergear-prs-con-label branch November 6, 2026 21:26
pibahamondesw added a commit that referenced this pull request Nov 7, 2026
…139)

## Description

**Contexto.** El release automático (#138) publica en PyPI y recién
después, en `release/finalize`, empuja el commit de versión y el tag. Si
alguien mergea a `master` mientras corre el release, ese push se rechaza
con el paquete ya publicado, sin tag ni GitHub Release.
fintoc-com/release-action#3 agregó `push: 'true'` a `prepare` para
empujar antes de publicar. Issue:
[DX-3387](https://linear.app/fintoc/issue/DX-3387/fintoc-python-empujar-commit-y-tag-antes-de-publicar).

**¿Qué hay de nuevo?**

- [x] `release/prepare` corre con `push: 'true'`: empuja el commit de
versión y el tag a `master` en un push atómico y sin force, antes de
`poetry build` y de publicar.
- Si `master` se movió durante el release, el push se rechaza y no se
publica nada.
- `release/finalize` ve el tag en el remote, se salta el push y solo
crea el GitHub Release.
- [x] El chequeo de commits posteriores al PR solo deja pasar commits
`release: ` cuyo autor es `fin-releases[bot]`. Antes bastaba el prefijo
del mensaje, así que un PR humano titulado `release: ...` se colaba. Es
el mismo filtro de fintoc-com/fintoc-cli#62.
- [x] `RELEASING.md` documenta el nuevo orden y sus modos de falla en la
tabla *Si falla*.

**Tests**

- [x] `actionlint` sobre `release.yml`: 8 hallazgos, los mismos que en
`origin/master` (actions `@v3`, label de Blacksmith, el typo
`steps.poetry-cache`, `$HOME` sin comillas). La línea nueva no agrega
ninguno.
- [x] El filtro nuevo de `compare`, probado contra la historia real del
repo: `31abd1b...d170905` lista `88c1ef6 d170905` y omite `d54ea49`
(`release: v2.29.0` de `fin-releases[bot]`); un rango con solo el commit
de versión y el mismo SHA no listan nada. Todos los commits `release: `
recientes los autorea `fin-releases[bot]`.
- [x] `shellcheck .github/scripts/*.sh` sin hallazgos.
- [x] `.github/scripts/resolve-release.test.sh` pasa (incluye "push sin
PR mergeado se salta", que cubre el run del commit de versión).

## Release notes

<!-- Sin release: cambio de CI. -->

## Requirements

None.

## Additional changes

None.

## Consideraciones

- El checkout del job `release` ya es por nombre de rama (`ref:
master`), así que `HEAD` no queda detached y el push de `prepare`
funciona sin más cambios.
- El chequeo de "commits posteriores al PR" queda igual: detecta lo que
se mergeó antes de que arrancara el job. El push sin force de `prepare`
cubre lo que se mergea durante el job.
- El commit de versión, ahora empujado antes de publicar, sigue
disparando un run de `release` que no hace nada: no tiene PR mergeado
asociado, así que `resolve` deja `bump` vacío y el job `release` queda
*skipped*.
- Cambio de trade-off: las notas de respaldo (`generate-notes`), `poetry
build` y la publicación en PyPI ahora corren después del push. Si
fallan, el tag queda en `master` sin paquete en PyPI. El recovery
(publicar desde el tag o saltarse la versión) está en `RELEASING.md`. Se
acepta porque es menos dañino que un paquete publicado sin tag, y porque
`generate-notes` ya funciona con el tag existente en el remote.
- Re-correr el job después de que el push entró publica la versión
siguiente, no la que falló. Quedó escrito en `RELEASING.md`.
- Este PR no lleva label `release:*`, así que al mergearlo no publica.

¿Es seguro hacer rollback? Sí
¿Cuáles son los pasos para hacer rollback? Revert PR
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant