Releaser puede leer tu historial de git y decidir automáticamente qué apps bumpear y con qué tipo (major/minor/patch).
Feature opt-in. Esta integración con Conventional Commits está desactivada por default. Si no activas
commits: [enabled: true]en tumix.exs, todo lo descrito aquí se ignora y Releaser funciona como una herramienta de releases manual (ver Manual releases).Ambos caminos son soportados de primera clase.
Activar la feature
En tu mix.exs:
releaser: [
apps_root: ".",
commits: [enabled: true]
]Con eso basta — los defaults sensatos se aplican. Si quieres personalizar:
releaser: [
commits: [
enabled: true,
bump_rules: %{
"feat" => :minor,
"fix" => :patch,
"perf" => :patch,
"refactor" => :patch,
"revert" => :patch
},
breaking_bump: :major,
breaking_markers: [:bang, :body],
scope_aliases: %{"autenticacion" => "auth"},
no_scope: :warn
]
]La tabla: tipo de commit → bump
| Tipo | Ejemplo | Bump |
|---|---|---|
feat | feat(xml): add carta_porte 3.1 | minor |
fix | fix(csd): handle empty key | patch |
perf | perf(xml): faster parsing | patch |
refactor | refactor(csd): extract Signer | patch |
revert | revert(xml): revert X | patch |
docs | docs(xml): update README | (ninguno) |
chore | chore: bump deps | (ninguno) |
test | test(xml): add cases | (ninguno) |
style / build / ci | ci: add coverage | (ninguno) |
BREAKING CHANGE
Dos formas de marcar un breaking change (ambas se activan por default):
1. El ! inline
feat(xml)!: rename CFDI.sign to CFDI.sign_with_csd
fix(csd)!: remove deprecated load_key/1Va después del tipo o el scope, antes de los dos puntos.
2. BREAKING CHANGE: en el body
feat(xml): add new signer
BREAKING CHANGE: CFDI.sign/2 was renamed to CFDI.sign_with_csd/2.También acepta BREAKING-CHANGE: (con guion).
Cualquier commit con alguno de estos markers se bumpea a major —
incluso tipos que normalmente no bumpean (docs, chore).
Agregación: muchos commits → un solo bump
Si tienes 10 commits desde el último tag, no son 10 bumps. Es UN bump del tipo más agresivo presente.
feat(xml): X1
feat(xml): X2
fix(xml): Y
refactor(xml): Z→ minor (un solo bump). Si entre esos hay feat(xml)!: → major.
Jerarquía: major > minor > patch > ninguno.
Scopes y apps
El scope del commit determina a qué app se aplica:
feat(xml): ... → app llamado "xml" (o "cfdi_xml" con prefix-stripping)
fix(csd): ... → app "csd" o "cfdi_csd" o "sat_csd"Scope aliases
Si el scope no coincide con el nombre del app, configura:
commits: [
enabled: true,
scope_aliases: %{
"autenticacion" => "sat_auth",
"certificados" => "cfdi_csd"
}
]Prefix stripping automático
Si tu app se llama cfdi_xml y el commit es feat(xml): ..., Releaser
reconoce la relación automáticamente quitando prefijos comunes (cfdi_,
sat_, clir_, renapo_).
Commits sin scope
Por defecto (no_scope: :warn), se ignoran con un warning. Opciones:
:ignore— silencioso:warn— warning en stdout (default)
Comandos
Sugerir (análisis sin aplicar)
mix releaser.bump --suggest
Output:
Analyzing commits since v4.0.18...
Apps to bump:
xml 4.0.18 → 4.1.0 (minor — 3 commit(s))
csd 4.0.16 → 4.0.17 (patch — 1 commit(s))
auth 1.0.1 → 2.0.0 (major — 1 commit(s))
Apps with no relevant changes:
renapo
Run with --from-commits to apply.Aplicar
# Todos los apps que tengan commits relevantes
mix releaser.bump --from-commits
# Solo un app
mix releaser.bump xml --from-commits
# En canal pre-release
mix releaser.bump --from-commits --mode prerelease --tag dev
# Desde un tag específico (no el último)
mix releaser.bump --from-commits --since v4.0.0
No-op (sin commits relevantes)
Si no hay commits que disparen bump, el comando termina exitosamente sin modificar nada:
$ mix releaser.bump --from-commits
No relevant commits since v4.0.18. No bump.
Esto es importante para CI: si nadie hizo un feat/fix desde el último
release, el workflow no bumpea ni publica. Idempotente.
Gitflow: dev / beta / main
Con Conventional Commits activo + el workflow de GitHub Actions incluido, el flujo es:
Dev trabaja en una feature branch:
git checkout -b feature/carta-porte-31 # ... código ... git commit -m "feat(xml): add carta_porte 3.1 support" git push -u origin feature/carta-porte-31 # abre PR a devMerge a
dev→ GitHub Actions detecta el push, lee el commitfeat(xml), y automáticamente:- Bumpea
xmla4.1.0-dev.1 - Commitea
chore(release): auto-bump on dev - Crea tag
v4.1.0-dev.1 - Pushea
- Bumpea
Merge dev → beta → Actions bumpea a
4.1.0-beta.1.Merge beta → main → Actions bumpea a
4.1.0estable y, siPUBLISH_TO_HEX=true, publica a Hex + crea GitHub Release.
Pre-commit hooks
Para evitar que commits mal formateados entren al repo, Releaser incluye un hook de git que valida cada mensaje.
Instalación
mix releaser.install_hooks
Eso ejecuta git config core.hooksPath .githooks — todos los hooks del
repo se activan en una sola línea. Cada dev del proyecto tiene que correrlo
una vez después de clonar.
Qué valida
Sigue estrictamente Conventional Commits v1.0.0:
- Formato:
<type>(<scope>)?(!)?: <subject> BREAKING CHANGE:/BREAKING-CHANGE:en mayúsculas (la spec lo exige)- Línea en blanco obligatoria entre header y body cuando hay body
- Subject no puede estar vacío
- Subject no puede exceder
max_subject_length(default 100)
Configuración
En tu mix.exs:
releaser: [
commits: [
enabled: true,
validation: [
# Si true, solo tipos declarados en bump_rules + allowed_types son válidos.
strict_types: false,
# Tipos adicionales válidos (que NO bumpean pero son aceptados).
allowed_types: ~w[docs chore test style build ci],
# Si true, solo scopes declarados son válidos.
strict_scopes: false,
# Lista explícita de scopes. Si omites, se auto-infiere de app names
# + scope_aliases.
allowed_scopes: nil,
# Permitir commits sin scope (`feat: ...` sin paréntesis).
allow_no_scope: true,
# Longitud máxima del subject.
max_subject_length: 100
]
]
]Modos
| Modo | strict_types | strict_scopes | Para qué |
|---|---|---|---|
| Permisivo (default) | false | false | Solo valida formato. Bueno para empezar. |
| Strict | true | true | Solo tipos/scopes declarados. Para proyectos maduros. |
Ejemplos de errores
$ git commit -m "fix stuff"
✗ Commit message invalid
fix stuff
Commit message does not match Conventional Commits format.
Expected: <type>(<scope>)?(!)?: <subject>
$ git commit -m "feat(xmll): ..." # en modo strict
✗ Commit message invalid
feat(xmll): ...
Unknown scope "xmll".
Allowed scopes: releaser, rel, release
Bypass (no recomendado)
git commit --no-verify -m "emergency fix"
Desinstalar
git config --unset core.hooksPath
Variables del workflow
Configura en Settings → Actions → Variables:
| Nombre | Valores | Qué hace |
|---|---|---|
PUBLISH_TO_HEX | true / false | Publica a Hex en push a main. Default false. |
CREATE_GH_RELEASE | true / false | Crea GitHub Release en push a main. Default false. |
Secret requerido si PUBLISH_TO_HEX=true:
HEX_API_KEY— Obtén una conmix hex.user whoami/mix hex.user key generate.