# Getting Started
Releaser funciona con tres tipos de proyecto Elixir:
1. **Poncho project** (multi-app con grupos, como cfdi-elixir)
2. **Umbrella project** (multi-app estándar de Elixir)
3. **Proyecto single** (un solo mix.exs sin apps/)
## Instalación
Agrega `releaser` a tu **root** `mix.exs`:
```elixir
defp deps do
[
{:releaser, "~> 0.1", only: :dev, runtime: false}
]
end
```
```bash
mix deps.get
```
## Configuración por tipo de proyecto
### Poncho project (apps agrupados)
```
mi_proyecto/
├── mix.exs ← root
├── apps/
│ ├── cfdi/ ← grupo
│ │ ├── xml/mix.exs ← app
│ │ ├── csd/mix.exs ← app
│ │ └── complementos/mix.exs ← app
│ ├── sat/ ← grupo
│ │ ├── auth/mix.exs ← app
│ │ └── pacs/mix.exs ← app
│ └── clir/
│ └── openssl/mix.exs ← app
```
Configuración en el root `mix.exs`:
```elixir
def project do
[
app: :mi_proyecto,
version: "0.1.0",
deps: deps(),
releaser: [
apps_root: "apps" # default, busca mix.exs recursivamente
]
]
end
```
En cada app que quieras publicar a Hex:
```elixir
# apps/cfdi/xml/mix.exs
def project do
[
app: :cfdi_xml,
version: "4.0.18",
deps: deps(),
description: "XML builder para CFDI",
releaser: [publish: true] # ← marcado como publicable
]
end
```
### Umbrella project (estándar de Elixir)
```
mi_umbrella/
├── mix.exs ← root umbrella
├── apps/
│ ├── core/mix.exs ← app
│ ├── api/mix.exs ← app
│ └── worker/mix.exs ← app
```
Configuración idéntica. Releaser detecta ambos layouts automáticamente:
```elixir
# mix.exs (root)
def project do
[
app: :mi_umbrella,
version: "0.1.0",
apps_path: "apps", # esto es de umbrella
deps: deps(),
releaser: [
apps_root: "apps"
]
]
end
```
En cada app:
```elixir
# apps/core/mix.exs
def project do
[
app: :core,
version: "1.0.0",
build_path: "../../_build",
deps_path: "../../deps",
lockfile: "../../mix.lock",
deps: deps(),
description: "Core business logic",
releaser: [publish: true]
]
end
```
### Proyecto single (sin apps/)
Para un proyecto con un solo `mix.exs`:
```
mi_libreria/
├── mix.exs
├── lib/
└── test/
```
```elixir
# mix.exs
def project do
[
app: :mi_libreria,
version: "1.0.0",
deps: deps(),
description: "Mi librería",
releaser: [
apps_root: ".", # ← apunta al directorio actual
publish: true
]
]
end
```
En este caso Releaser detecta un solo app y funciona para bump + changelog + publish (sin cascade porque no hay dependientes).
## Dos caminos: manual o automatizado
Releaser soporta **dos flujos de trabajo** igualmente válidos. Elige según
tu equipo y proyecto — puedes empezar con uno y migrar al otro sin
romper nada.
### Camino A — Releases manuales (default)
**No requiere configuración adicional**. Tú decides cada bump:
```bash
mix releaser.bump patch # 1.0.0 → 1.0.1
mix releaser.bump minor # 1.0.1 → 1.1.0
mix releaser.bump major # 1.1.0 → 2.0.0
```
Formato de commits libre, sin hooks, sin CI obligatorio. Ver
[Manual releases](./manual-releases.md).
### Camino B — Conventional Commits (opt-in)
Si adoptas [Conventional Commits](https://www.conventionalcommits.org/)
(`feat:`, `fix:`, `feat!:`), Releaser puede leer tu historial de git y
decidir el bump automáticamente:
```elixir
releaser: [
commits: [enabled: true]
]
```
```bash
# Analiza sin aplicar
mix releaser.bump --suggest
# Aplica automáticamente
mix releaser.bump --from-commits --mode prerelease --tag dev
```
Incluye hook de git para rechazar commits mal formateados, GitHub
Actions template, y flujo gitflow automatizado. Ver
[Conventional Commits](./conventional-commits.md).
### Comparación rápida
| | Camino A (manual) | Camino B (commits) |
|------------------------------|-----------------------|------------------------|
| Config extra | Ninguna | `commits: [enabled: true]` |
| Quién decide el bump | Tú | El parser de git log |
| Pre-commit hook | — | Opcional (strict) |
| GitHub Actions | Opcional | Opcional (template incluido) |
Todo el resto del releaser (cascade, publish, pre-releases, changelog)
funciona igual en ambos caminos.
## Publish policy
### Qué es `publish: true`
El flag `releaser: [publish: true]` en el `mix.exs` de cada app controla:
| Con `publish: true` | Sin `publish: true` |
|---|---|
| Se publica a Hex con `mix releaser.publish` | NO se publica |
| Recibe cascade bump cuando sus deps cambian | NO recibe cascade bump |
| Aparece en `mix releaser.publish --dry-run` | No aparece en el plan de publish |
| Aparece en `mix releaser.status` con su estado | Aparece como "private" |
| Se incluye en `mix releaser.bump --list` | Se incluye en `--list` |
| Se incluye en `mix releaser.graph` | Se incluye en el grafo |
### Reglas de publicación
```
┌───────────────────────────────────────────────────────────────────────┐
│ Reglas de publish │
├───────────────────────────────────────────────────────────────────────┤
│ │
│ 1. Solo apps con publish: true se publican │
│ │
│ 2. Al publicar un app, también se publican sus DEPENDIENTES │
│ (quienes dependen de él), no sus dependencias │
│ │
│ 3. Las dependencias que no son publicables (publish: false) │
│ se resuelven contra la versión que ya está en Hex │
│ │
│ 4. El cascade de bump solo aplica a apps publicables │
│ │
└───────────────────────────────────────────────────────────────────────┘
```
### Ejemplo: ¿qué pasa cuando modifico un app?
#### Caso 1: Modifico `cfdi_xml` (nadie depende de él)
```bash
$ mix releaser.bump cfdi_xml patch --dry-run
Version changes:
cfdi_xml 4.0.18 → 4.0.19 (direct)
# Solo cfdi_xml — nadie más depende de él
$ mix releaser.publish --only cfdi_xml --dry-run
# Solo publica cfdi_xml
# Sus deps (cfdi_csd, saxon_he, etc.) ya están en Hex
```
#### Caso 2: Modifico `cfdi_csd` (cfdi_xml depende de él)
```bash
$ mix releaser.bump cfdi_csd patch --dry-run
Version changes:
cfdi_csd 4.0.16 → 4.0.17 (direct)
cfdi_xml 4.0.18 → 4.0.19 (cascade) ← depende de csd, publish: true
# sat_auth NO aparece — tiene publish: false
$ mix releaser.publish --only cfdi_csd --dry-run
# Publica: cfdi_csd (nivel 1), luego cfdi_xml (nivel 2)
# sat_auth NO se publica — no tiene publish: true
```
#### Caso 3: Modifico `clir_openssl` (toda la cadena depende)
```bash
$ mix releaser.bump clir_openssl patch --dry-run
Version changes:
clir_openssl 0.0.17 → 0.0.18 (direct)
cfdi_csd 4.0.16 → 4.0.17 (cascade)
cfdi_xml 4.0.18 → 4.0.19 (cascade)
# Solo los publicables cascadean
```
### Escenarios de policy
#### App interno que nunca se publica
```elixir
# apps/sat/scraper/mix.exs — herramienta interna de scraping
def project do
[
app: :sat_scraper,
version: "0.0.1",
deps: deps()
# Sin releaser: [publish: true] → privado, no se publica nunca
]
end
```
#### App que YA estaba en Hex pero ya no se publicará más
Si `cfdi_transform` ya está en Hex como `4.0.14` y decides no publicar más versiones:
1. Quita `releaser: [publish: true]` de su `mix.exs` (o simplemente no lo pongas)
2. La versión `4.0.14` sigue disponible en Hex
3. Los apps que dependen de él usan `{:cfdi_transform, "~> 4.0"}` — resuelve a `4.0.14`
4. No recibe cascade bumps
5. No se intenta publicar
#### App nuevo que se publicará por primera vez
```elixir
# apps/cfdi/nuevo/mix.exs
def project do
[
app: :cfdi_nuevo,
version: "0.1.0",
deps: deps(),
description: "Nuevo paquete", # requerido por Hex
releaser: [publish: true]
]
end
```
Al ejecutar `mix releaser.publish`, se publica por primera vez.
`mix releaser.status` lo mostrará como "unpublished".
## Primeros pasos después de configurar
```bash
# 1. Ver todos los apps descubiertos
$ mix releaser.bump --list
# 2. Ver el grafo de dependencias
$ mix releaser.graph
# 3. Ver qué está pendiente de publicar
$ mix releaser.status
# 4. Probar un bump (sin aplicar cambios)
$ mix releaser.bump mi_app patch --tag dev --dry-run
# 5. Probar el plan de publicación
$ mix releaser.publish --dry-run
```
## Siguiente lectura
- [Pre-release Tags](pre-release-tags.html) — ciclo dev → beta → rc → release
- [Publishing to Hex](publishing-to-hex.html) — cómo funciona la publicación topológica
- [Changelog and Hooks](changelog-and-hooks.html) — automatizar git tags y changelogs
- [Monorepo Patterns](monorepo-patterns.html) — estructuras de proyecto y patrones avanzados