@astra-kit/rp 0.0.0-stage → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +196 -0
- package/LICENSE.md +21 -0
- package/README.md +352 -2
- package/bin/astra-rp.js +51 -0
- package/package.json +93 -4
- package/src/build-gate.js +157 -0
- package/src/changelog-blocks.js +53 -0
- package/src/changelog.js +108 -0
- package/src/constants/build-gate.js +30 -0
- package/src/constants/changelog-draft.js +180 -0
- package/src/constants/changelog.js +74 -0
- package/src/constants/ci-release.js +346 -0
- package/src/constants/cli.js +12 -0
- package/src/constants/create-version.js +523 -0
- package/src/constants/guard-publish.js +29 -0
- package/src/constants/index.js +18 -0
- package/src/constants/monorepo.js +57 -0
- package/src/constants/package-manager.js +56 -0
- package/src/constants/registry.js +72 -0
- package/src/constants/terminal-ui.js +93 -0
- package/src/constants/version-files.js +63 -0
- package/src/constants/versions.js +60 -0
- package/src/create-version/artifact.js +343 -0
- package/src/create-version/changelog-draft-workspace.js +124 -0
- package/src/create-version/changelog-draft.js +380 -0
- package/src/create-version/changelog.js +264 -0
- package/src/create-version/ci-config.js +54 -0
- package/src/create-version/ci-publication-history.js +113 -0
- package/src/create-version/ci-release-identity-step.js +58 -0
- package/src/create-version/ci-setup.js +794 -0
- package/src/create-version/ci.js +555 -0
- package/src/create-version/committed-tree.js +75 -0
- package/src/create-version/config.js +489 -0
- package/src/create-version/errors.js +46 -0
- package/src/create-version/github-workflow.js +199 -0
- package/src/create-version/index.js +54 -0
- package/src/create-version/json.js +32 -0
- package/src/create-version/jsonc.js +76 -0
- package/src/create-version/jsr.js +96 -0
- package/src/create-version/local-changes.js +178 -0
- package/src/create-version/npm-auth.js +142 -0
- package/src/create-version/npm.js +812 -0
- package/src/create-version/plan.js +1200 -0
- package/src/create-version/process.js +334 -0
- package/src/create-version/registry-config.js +121 -0
- package/src/create-version/registry-http.js +62 -0
- package/src/create-version/registry.js +220 -0
- package/src/create-version/release-execution.js +45 -0
- package/src/create-version/release-tag-config.js +76 -0
- package/src/create-version/run.js +2087 -0
- package/src/create-version/state.js +461 -0
- package/src/create-version/strict-utf8.js +11 -0
- package/src/create-version/templates/release.yml +52 -0
- package/src/create-version/templates/vercel-ignore-build.mjs +66 -0
- package/src/guard-publish.js +77 -0
- package/src/index.js +42 -0
- package/src/monorepo/plan.js +475 -0
- package/src/monorepo/release-commit.js +46 -0
- package/src/monorepo/run.js +927 -0
- package/src/monorepo/state.js +206 -0
- package/src/monorepo/workspaces.js +327 -0
- package/src/package-manager.js +107 -0
- package/src/terminal-ui.js +548 -0
- package/src/testing.js +70 -0
- package/src/version-files.js +142 -0
- package/src/versions.js +303 -0
- package/types/build-gate.d.ts +43 -0
- package/types/changelog-blocks.d.ts +33 -0
- package/types/changelog.d.ts +61 -0
- package/types/constants/build-gate.d.ts +23 -0
- package/types/constants/changelog-draft.d.ts +138 -0
- package/types/constants/changelog.d.ts +56 -0
- package/types/constants/ci-release.d.ts +284 -0
- package/types/constants/cli.d.ts +11 -0
- package/types/constants/create-version.d.ts +397 -0
- package/types/constants/guard-publish.d.ts +25 -0
- package/types/constants/index.d.ts +17 -0
- package/types/constants/monorepo.d.ts +45 -0
- package/types/constants/package-manager.d.ts +40 -0
- package/types/constants/registry.d.ts +79 -0
- package/types/constants/terminal-ui.d.ts +73 -0
- package/types/constants/version-files.d.ts +51 -0
- package/types/constants/versions.d.ts +47 -0
- package/types/create-version/artifact.d.ts +113 -0
- package/types/create-version/changelog-draft-workspace.d.ts +33 -0
- package/types/create-version/changelog-draft.d.ts +127 -0
- package/types/create-version/changelog.d.ts +141 -0
- package/types/create-version/ci-config.d.ts +33 -0
- package/types/create-version/ci-publication-history.d.ts +51 -0
- package/types/create-version/ci-release-identity-step.d.ts +12 -0
- package/types/create-version/ci-setup.d.ts +148 -0
- package/types/create-version/ci.d.ts +145 -0
- package/types/create-version/committed-tree.d.ts +55 -0
- package/types/create-version/config.d.ts +128 -0
- package/types/create-version/errors.d.ts +39 -0
- package/types/create-version/github-workflow.d.ts +41 -0
- package/types/create-version/index.d.ts +28 -0
- package/types/create-version/json.d.ts +21 -0
- package/types/create-version/jsonc.d.ts +21 -0
- package/types/create-version/jsr.d.ts +52 -0
- package/types/create-version/local-changes.d.ts +52 -0
- package/types/create-version/npm-auth.d.ts +60 -0
- package/types/create-version/npm.d.ts +331 -0
- package/types/create-version/plan.d.ts +369 -0
- package/types/create-version/process.d.ts +151 -0
- package/types/create-version/registry-config.d.ts +56 -0
- package/types/create-version/registry-http.d.ts +22 -0
- package/types/create-version/registry.d.ts +86 -0
- package/types/create-version/release-execution.d.ts +22 -0
- package/types/create-version/release-tag-config.d.ts +18 -0
- package/types/create-version/run.d.ts +407 -0
- package/types/create-version/state.d.ts +204 -0
- package/types/create-version/strict-utf8.d.ts +10 -0
- package/types/guard-publish.d.ts +49 -0
- package/types/index.d.ts +23 -0
- package/types/monorepo/plan.d.ts +68 -0
- package/types/monorepo/release-commit.d.ts +29 -0
- package/types/monorepo/run.d.ts +68 -0
- package/types/monorepo/state.d.ts +96 -0
- package/types/monorepo/workspaces.d.ts +86 -0
- package/types/package-manager.d.ts +58 -0
- package/types/terminal-ui.d.ts +196 -0
- package/types/testing.d.ts +31 -0
- package/types/version-files.d.ts +59 -0
- package/types/versions.d.ts +158 -0
package/README.md
CHANGED
|
@@ -1,3 +1,353 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @astra-kit/rp
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Proceso de release compartido por los proyectos Beez (beez-ui, TuTribu, Control Mensual). No tiene dependencias de runtime: solo usa módulos `node:*`, así que `npx` lo descarga y ejecuta en segundos, incluso antes de instalar las dependencias del proyecto.
|
|
4
|
+
|
|
5
|
+
## Regla de versiones
|
|
6
|
+
|
|
7
|
+
- Solo existen versiones estables `X.Y.Z`: nunca `-alpha.X`, `-beta.X`, `-rc.X`, metadata `+build`, prefijos (`v1.2.3`) ni ceros a la izquierda.
|
|
8
|
+
- Después de una versión solo se permite la siguiente patch, minor o major. De `1.2.3` valen `1.2.4`, `1.3.0` o `2.0.0`.
|
|
9
|
+
- No se puede repetir, bajar ni saltear versiones (`1.0.0` → `3.0.0`, `1.2.3` → `1.4.0`), ni subir la minor o la major sin reiniciar las partes menores (`1.2.3` → `1.3.3`).
|
|
10
|
+
|
|
11
|
+
## Módulos
|
|
12
|
+
|
|
13
|
+
| Import | Contenido |
|
|
14
|
+
| --- | --- |
|
|
15
|
+
| `@astra-kit/rp/versions` | `isStableReleaseVersion`, `parseReleaseVersion`, `bumpReleaseVersion`, `listNextVersions`, `listAllowedVersionsAfter`, `resolveRequestedVersion` (`--bump` / `--set-version`), `toReleaseTag`, `isReleaseCommitSubject`, `suggestReleaseType`, `suggestNextReleaseType` e `isPreMajorShiftActive` (con `preMajorShift`). |
|
|
16
|
+
| `@astra-kit/rp/build-gate` | `decideBuild(previousVersion, currentVersion)` y `decideBuildForCheckout(repositoryRoot)` para el `ignoreCommand` de Vercel. |
|
|
17
|
+
| `@astra-kit/rp/changelog` | Helpers puros de lectura y transformación de texto de changelog; no escriben archivos. `create-version` verifica el CHANGELOG manual y, en el commit de versión, cierra su sección `## [Unreleased]`. |
|
|
18
|
+
| `@astra-kit/rp/guard-publish` | `decidePublishGuard(userAgent)` del `prepublishOnly` que bloquea publicaciones con pnpm, yarn o bun. |
|
|
19
|
+
| `@astra-kit/rp/version-files` | `updateVersionMarkers(content, version)`: reescribe las versiones de las líneas marcadas de `versionFiles`. |
|
|
20
|
+
| `@astra-kit/rp/package-manager` | `detectPackageManager(root)` (pnpm, bun, npm o yarn) y `describeProjectCommands(packageManager)`: los comandos que astra-rp corre y muestra en ese proyecto. |
|
|
21
|
+
| `@astra-kit/rp/terminal-ui` | Cajas, filas, banner, spinner y selector interactivo sin dependencias. |
|
|
22
|
+
| `@astra-kit/rp/create-version` | Comando compartido de release: `runCreateVersion`, el planificador puro `buildReleasePlan`, el lector de estado y los tipos de `astra-rp.config.js`. |
|
|
23
|
+
| `@astra-kit/rp/testing` | Fixtures de versiones permitidas y rechazadas para los tests de cada proyecto. |
|
|
24
|
+
| `@astra-kit/rp/constants` | Todas las constantes, agrupadas por dominio. |
|
|
25
|
+
|
|
26
|
+
## Gate de Vercel
|
|
27
|
+
|
|
28
|
+
`astra-rp ignore-build` compara la versión de `package.json` del commit desplegado con la de `HEAD^`. Imprime el motivo y, como última línea, `BUILD` o `SKIP`, y sale con `0`. Si no puede decidir, sale con `2`.
|
|
29
|
+
|
|
30
|
+
El `ignoreCommand` de Vercel corre antes de instalar dependencias. Por eso cada proyecto usa un wrapper que buildea solo cuando la última línea es `BUILD`: cualquier otra salida, incluido un fallo de `npx` o de red, saltea el build.
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
#!/bin/bash
|
|
34
|
+
# scripts/ignore-build.sh — Vercel: exit 0 saltea el build, exit 1 buildea.
|
|
35
|
+
set -u
|
|
36
|
+
GATE_OUTPUT=$(npx --yes --package @astra-kit/rp@X.Y.Z astra-rp ignore-build)
|
|
37
|
+
GATE_EXIT_CODE=$?
|
|
38
|
+
echo "$GATE_OUTPUT"
|
|
39
|
+
if [ "$GATE_EXIT_CODE" -eq 0 ] && [ "$(printf '%s\n' "$GATE_OUTPUT" | tail -n 1)" = "BUILD" ]; then
|
|
40
|
+
exit 1
|
|
41
|
+
fi
|
|
42
|
+
exit 0
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
```json
|
|
46
|
+
{ "ignoreCommand": "bash scripts/ignore-build.sh" }
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Tests en los proyectos
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
import { REJECTED_VERSION_BUMP_CASES, CURRENT_STABLE_VERSION } from "@astra-kit/rp/testing";
|
|
53
|
+
import { resolveRequestedVersion } from "@astra-kit/rp/versions";
|
|
54
|
+
|
|
55
|
+
it.each(REJECTED_VERSION_BUMP_CASES)("rechaza %s (%j)", (_reason, version) => {
|
|
56
|
+
expect(() => resolveRequestedVersion(CURRENT_STABLE_VERSION, { bump: null, setVersion: version })).toThrow();
|
|
57
|
+
});
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## create-version
|
|
61
|
+
|
|
62
|
+
Cada proyecto versiona con el mismo comando y describe sus diferencias en `astra-rp.config.js` (o `astra-rp.config.mjs`, que tiene prioridad y conviene en proyectos sin `"type": "module"`).
|
|
63
|
+
|
|
64
|
+
### Elegir local o CI
|
|
65
|
+
|
|
66
|
+
En una terminal interactiva, `pnpm cv` pregunta dónde ejecutar el release. Si el repo configura `ci.workflow`, **CI queda seleccionado por defecto** y se puede elegir **Local**. Sin configuración, ofrece **Configurar CI automáticamente**, **Continuar en local** o **Cancelar**. Sin terminal conserva el modo local cuando no hay `ci`; con `ci` usa CI. Dentro de un runtime CI nunca despacha otro workflow.
|
|
67
|
+
|
|
68
|
+
```js
|
|
69
|
+
export default {
|
|
70
|
+
checks: ["pnpm run ci"],
|
|
71
|
+
ci: {
|
|
72
|
+
workflow: "release.yml", // archivo dentro de .github/workflows
|
|
73
|
+
secrets: ["DATABASE_MIGRATION_URL"], // nombres; los valores van en Actions
|
|
74
|
+
variables: [],
|
|
75
|
+
deployment: "vercel", // opcional: deploy después de los checks
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
En **CI**, el proceso local verifica el CHANGELOG manual, el estado de Git, `gh` y las credenciales del worker; elige la versión, hace el bump, cierra `## [Unreleased]` del CHANGELOG, crea commit + tag, hace push y dispara el workflow. Omite checks, migraciones, preparación, publicación y hooks de Git locales: esas validaciones se ejecutan en el worker. La terminal informa **enviado a CI**, no publicado.
|
|
81
|
+
|
|
82
|
+
El worker hace checkout del tag exacto y, antes de configurar herramientas o instalar dependencias (es decir, antes de ejecutar código del proyecto con los secrets y el permiso OIDC del job), un paso que solo usa Git rechaza el release si `tag` no es `v<version>` estable, si no apunta exactamente al `sha` enviado o si ese commit no está en `origin/main`. Después vuelve a comprobar su versión y SHA antes de ejecutar checks, migraciones, preparación y publicación. Usa `--ci-release vX.Y.Z`; nunca vuelve a hacer bump ni push, ni modifica el CHANGELOG del commit de versión. Un check fallido corta el release. Una versión que el registry ya confirma publicada no se vuelve a publicar. Tampoco se ejecuta un tag anterior a la versión vigente en `origin/main`.
|
|
83
|
+
|
|
84
|
+
En **Local**, se conserva el flujo completo en la máquina actual, incluidos sus hooks. Se puede elegir por flag:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
pnpm cv --local --bump patch
|
|
88
|
+
pnpm cv --ci --bump minor
|
|
89
|
+
pnpm cv --setup-ci --bump patch
|
|
90
|
+
pnpm cv --ci --dry-run
|
|
91
|
+
pnpm cv --retry-ci v1.2.4
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Cada commit de release de un proyecto con `ci` registra dónde se preparó en el trailer `Astra-Rp-Execution` (`local` o `ci`), sin agregar archivos al repo. Si el push falla, el release se retoma solo en ese modo: `--local` no puede retomar un release preparado para CI (que omitió checks y migraciones), ni a la inversa. Los commits de release anteriores, sin trailer, se retoman como antes.
|
|
95
|
+
|
|
96
|
+
`--setup-ci` prepara el workflow y agrega `export const ci = ...` al config existente, sin reemplazar sus hooks. Se aceptan tanto un objeto `ci` dentro de `export default` como ese export nombrado; el objeto del default tiene prioridad y un campo ausente o `null` permite usar el export nombrado. Los archivos se incluyen en el mismo commit del bump y se restauran si el commit falla. Los workflows existentes no se sobrescriben: si `ci` ya estaba configurado y el workflow commiteado difiere del que generaría la configuración actual (por ejemplo, un secret o token de publicación nuevo), `--setup-ci` se detiene antes de crear el commit, el tag o el dispatch; regeneralo borrándolo en un commit propio, actualizalo a mano o, si está personalizado a propósito, usá `--ci`. Los archivos que modifica el setup, como `.gitignore`, deben estar commiteados y limpios incluso con `--ignore-local-changes`. El comando detecta el package manager y el `.nvmrc` commiteado en HEAD; usa instalación con lockfile congelado (`npm ci`, `pnpm install --frozen-lockfile`, `yarn install --frozen-lockfile`/`--immutable` o `bun install --frozen-lockfile`) y una versión predeterminada de pnpm si solo hay lockfile. Por eso `--setup-ci` se detiene antes del bump si HEAD no contiene commiteado un lockfile del package manager detectado (`package-lock.json` o `npm-shrinkwrap.json`, `pnpm-lock.yaml`, `yarn.lock`, `bun.lock` o `bun.lockb`); tenerlo solo en disco no alcanza. Lo mismo vale para `.nvmrc`: el workflow solo lo usa si HEAD lo contiene como archivo regular, y `--setup-ci` se detiene antes del bump si existe en disco sin estar commiteado (sin trackear, ignorado o apartado por `--ignore-local-changes`); commitealo o borralo para usar el major local. Ambos chequeos también corren en un release `--ci` ordinario mientras el workflow commiteado sea exactamente el que generaría `--setup-ci`; un workflow personalizado queda a cargo del proyecto. Para proyectos con `vercel.json` y sin publisher propio, configura el deploy de Vercel; los nombres de variables explícitos en `migrations.targetHint` se incluyen como secrets del worker.
|
|
97
|
+
|
|
98
|
+
El workflow recibe tres inputs `string`: `version`, `tag` y `sha`. Debe declarar `workflow_dispatch`, tener un `run-name` como `astra-rp release ${{ inputs.tag }} ${{ inputs.sha }}` y llamar al script `create-version` con `--ci-release`. La configuración automática genera ese contrato. Ejemplo del despacho que hace astra-rp ([GitHub CLI](https://cli.github.com/manual/gh_workflow_run)):
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
gh workflow run release.yml --ref v1.2.4 \
|
|
102
|
+
-f version=1.2.4 -f tag=v1.2.4 -f sha=<commit-del-tag>
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
El despacho usa `--ref <tag>`: GitHub ejecuta la versión del workflow guardada en el tag del release, no la de `main`, así que un `--retry-ci` posterior a cambios del workflow en `main` repite el release con su workflow original; si el tag no contiene el workflow, no se envía nada. Por eso `--retry-ci` toma `ci.workflow` y los bindings requeridos (`ci.secrets`, `ci.variables` y credenciales de publicación) de la configuración guardada en el tag, no del working tree: renombrar el workflow o cambiar sus bindings en `main` sin cambiar la versión no altera el reintento. Se requiere `origin` de GitHub, `main` como rama por defecto y `gh auth login` con acceso al repo. Las credenciales de publicación y los nombres de `ci.secrets` / `ci.variables` se comprueban antes del bump, aceptando tanto los del repo como los secrets/variables de organización compartidos con él; si no se pueden listar los de organización, el preflight bloquea indicando los nombres sin verificar. Se configuran con `gh secret set NPM_TOKEN`, por ejemplo. El entorno configurado también está disponible durante la instalación de dependencias privadas. OIDC usa `id-token: write`; GitHub Packages con `GITHUB_TOKEN` usa el token del workflow y `packages: write`; como ese token solo lo acepta GitHub Packages, `publication.tokenEnv: "GITHUB_TOKEN"` con otro registry efectivo (npm, GitLab, JSR u otro endpoint) se rechaza antes del bump: guardá ese token con otro nombre, como `NPM_TOKEN`. Para instalar dependencias privadas de GitHub Packages, el workflow generado agrega `packages: read` y el paso `Autenticar GitHub Packages`, que guarda en `~/.npmrc` del runner, antes de instalar, el token que expande el `.npmrc` (el secret de `ci.secrets` cuando `NOMBRE` es uno propio y, si no, el token del workflow) (lo leen npm, pnpm y el build de Vercel). Esta autenticación solo se soporta cuando el package manager detectado es npm o pnpm: con Yarn (cualquier versión) o Bun, cualquier señal de GitHub Packages (las de abajo o una línea no comentada de `.yarnrc`, `.yarnrc.yml` o `bunfig.toml` que mencione `npm.pkg.github.com`) se rechaza antes del bump, porque esos package managers leen registries y credenciales de su propia configuración y variables de entorno; para ellos usá un workflow propio en `ci.workflow`. Con npm o pnpm esos archivos de Yarn y Bun no se inspeccionan. Se activa cuando el `.npmrc` commiteado en HEAD resuelve un scope o el registry por defecto desde `npm.pkg.github.com`, cuando define una credencial para ese host o cuando `ci.secrets` declara `GITHUB_TOKEN`; un `.npmrc` sin commitear o ignorado no cuenta, porque el worker no lo recibe. El `.npmrc` se lee como en npm: claves y valores entre comillas (las dobles se decodifican como JSON, y las simples se quitan antes de ese decodificado), el sufijo de array `[]` de una clave (salvo en claves de `npm.pkg.github.com`, que se rechazan siempre), líneas terminadas en CRLF, LF o CR, la última asignación de cada clave y solo las claves fuera de secciones `[nombre]` (un encabezado cuenta solo si `[` abre la línea, como en npm; una línea con sangría como ` [nombre]` es una clave más). Las credenciales de GitHub Packages siguen una lista cerrada: la única aceptada es `//npm.pkg.github.com/:_authToken=${NOMBRE}` (clave del host, sin ruta de owner, y un valor que es solo `${NOMBRE}`), y `NOMBRE` solo puede ser `GITHUB_TOKEN` (el workflow lo expone con el token del workflow a nivel job, salvo que `ci.variables` lo declare) o un secret declarado en `ci.secrets` que no sea de Vercel ni `publication.tokenEnv` (lo provee ese secret). Antes del bump se rechaza cualquier otra clave que empiece con `//npm.pkg.github.com` (con ruta de owner, `_auth`, `username`, `_password`, `certfile`, `keyfile`, la forma de pnpm `:@org:_authToken` o con `[]`) y cualquier otro valor (literales, vacíos, sin `=`, `true`, `false`, `undefined` o compuestos como `${NOMBRE}-x`): usá `//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}` o quitá la línea; cualquier otro `NOMBRE` (por ejemplo `PATH` o `HOME`) se rechaza: usá `${GITHUB_TOKEN}` o declará el secret en `ci.secrets`. También se rechazan siempre una clave con `${...}` y un registry con `${...}`, porque no se puede saber a qué host apuntan (escribí la clave o la URL literal); un registry de GitHub Packages que no use `https:`; un `.npmrc` commiteado que no es un archivo regular, como un enlace simbólico; y, cuando el workflow agrega el paso de autenticación, `HOME`, `XDG_CONFIG_HOME` o cualquier variable cuyo nombre empiece con `NPM_CONFIG_` o `PNPM_CONFIG_` (sin distinguir mayúsculas) en `ci.secrets` o `ci.variables`, porque mueven la configuración de usuario o reemplazan registries, archivos de configuración o credenciales con valores que no se pueden comprobar. Estas validaciones aplican al workflow generado: con un workflow personalizado, que autentica por su cuenta, `--ci` no las exige. Con el paso de autenticación también se validan los demás archivos commiteados en HEAD (cualquiera que no sea un archivo regular se rechaza): con pnpm, un `pnpm-workspace.yaml` que define, en una línea no comentada, `registry`, `registries`, `strictSsl`/`strict-ssl`, `ca`, `cafile`, `cert`, `key`, `proxy`, `httpsProxy`/`https-proxy` o `noProxy` se rechaza, porque pnpm los usaría sin validar (mové el registry al `.npmrc` con una URL literal `https://` y no desactives TLS); un lockfile (`package-lock.json`, `npm-shrinkwrap.json`, `pnpm-lock.yaml`, `yarn.lock`, `bun.lock` o `bun.lockb`) con una URL `http://npm.pkg.github.com` cuyo host termina ahí (seguido de `/`, `:`, comillas, espacio o fin; `http://npm.pkg.github.com.corp.example/` es otro host) se rechaza porque enviaría el token sin cifrar (regeneralo con `https://`); y, para no desactivar TLS, se rechazan un `.npmrc` cuyo `strict-ssl` efectivo es `false` y `NODE_TLS_REJECT_UNAUTHORIZED` en `ci.secrets` o `ci.variables`. Solo se consideran de `npm.pkg.github.com` las claves cuyo host termina ahí (seguido de `/`, `:` o nada): `//npm.pkg.github.com.corp.example/` es otro host. Un texto entre comillas dobles que no es JSON válido conserva sus comillas, igual que en npm. Un workflow generado antes de este cambio no tiene ese paso: `--setup-ci` lo reporta como desactualizado y `--ci` lo rechaza antes del bump cuando solo le faltan las líneas de autenticación de GitHub Packages; borralo en un commit propio y regeneralo con `--setup-ci`. Si JSR selecciona `jsrClient: "deno"`, el workflow instala Deno. Con npm y OIDC, el Node.js que fija el `.nvmrc` commiteado en HEAD (o el major local si HEAD no lo contiene) debe alcanzar Node >= 22.14.0 antes del bump; con pnpm, Yarn o Bun el workflow instala además npm 11.5.1 solo para publicar; con npm se valida el pin de `packageManager` y, sin pin, el workflow instala npm 11.5.1 después de `npm ci`; además, el registry efectivo (`publication.registryUrl`, `publishConfig` o el `.npmrc` del proyecto) debe ser el público de npm. Otros secretos usados por hooks deben declararse explícitamente. Un estado de migraciones desconocido, antes o después de aplicar, corta el worker. Este protocolo de tag `vX.Y.Z` corresponde al modo de una única versión; los monorepos conservan el modo local.
|
|
106
|
+
|
|
107
|
+
Si el despacho falla después del push, el tag queda en origin y el error indica `--retry-ci vX.Y.Z`: conserva la misma versión y no repite el push. Antes de despachar, consulta las ejecuciones con el mismo tag y SHA; reutiliza una activa o exitosa. Si una respuesta fallida no permite confirmar la aceptación, pide revisar Actions antes de reenviar y nunca reintenta automáticamente.
|
|
108
|
+
|
|
109
|
+
Si `publish` es una función propia, con o sin deploy, el registry no puede probar que ya se publicó: el workflow generado recibe `actions: read` y `GITHUB_TOKEN`, y el worker consulta las otras ejecuciones del mismo tag y SHA (también los re-runs), excluyendo la ejecución e intento actuales. Si alguna terminó con éxito el paso `Checks y publicación del release`, el worker no repite el publisher. Esto también cubre dos `--retry-ci` concurrentes: el concurrency group del workflow encola el segundo despacho en vez de cancelarlo, y cuando arranca ya ve el éxito del primero. Si no puede leer ese historial, corta sin publicar. Los workflows generados antes de este cambio con un publisher propio y sin Vercel no tienen esos permisos: el worker corta sin publicar y `--setup-ci` los reporta como desactualizados; borralos en un commit propio y regeneralos con `--setup-ci`.
|
|
110
|
+
|
|
111
|
+
Con `deployment: "vercel"`, se necesitan `VERCEL_TOKEN`, `VERCEL_ORG_ID` y `VERCEL_PROJECT_ID` como secrets de Actions. La configuración automática conserva el `ignoreCommand` anterior detrás de un gate sin dependencias, que evita el deploy por Git del release delegado a CI. `.astra-rp/release.json` registra la versión y el destino de ese release; un release local vuelve a usar el gate original. Después de los checks, migraciones y hooks, el workflow obtiene el entorno de producción y recién entonces construye y despliega con `vercel deploy --prebuilt --prod` ([flujo oficial de Vercel](https://vercel.com/kb/guide/how-can-i-use-github-actions-with-vercel)). Un workflow configurado manualmente debe incluir ese gate o desactivar el deploy automático por Git para que producción espere a CI. astra-rp no configura cuentas ni sube secretos desde `.env`. Con un publisher propio, un reintento por un deploy fallido vuelve a correr los checks y `prepare` pero no repite el publisher (ver el párrafo siguiente).
|
|
112
|
+
|
|
113
|
+
Funciona con pnpm, bun, npm o yarn: astra-rp detecta el package manager por el campo `packageManager` del `package.json` (por ejemplo `"bun@1.3.11"`), si no por el lockfile (`bun.lock`, `pnpm-lock.yaml`, `yarn.lock`, `package-lock.json`) y, sin ninguno, asume pnpm. Con eso arma los checks por defecto (`bun run ci`) y cada "volvé a correr" de los mensajes (`bun run create-version`; `npm run create-version`; `pnpm` y `yarn` corren el script directo). Los ejemplos de abajo usan pnpm. Con npm, las opciones van después de `--` (`npm run create-version -- -b M`, `npm run cv -- -sv=1.3.0`): sin el separador npm toma los flags como opciones propias y no le llegan a `create-version`; `--help` y los avisos ya lo muestran así. npm, GitHub Packages y GitLab se publican con el CLI de npm; JSR usa su cliente oficial o Deno.
|
|
114
|
+
|
|
115
|
+
```json
|
|
116
|
+
{ "scripts": { "create-version": "astra-rp create-version", "cv": "astra-rp create-version" } }
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
pnpm create-version # o pnpm cv
|
|
121
|
+
pnpm cv --bump patch # o --bump minor / --bump major
|
|
122
|
+
pnpm cv -b m # -b acepta también p, m y M: -b m es minor, -b M major
|
|
123
|
+
pnpm cv -p # atajo de --patch
|
|
124
|
+
pnpm cv -m # atajo de --minor (m minúscula)
|
|
125
|
+
pnpm cv -M # atajo de --major (M mayúscula)
|
|
126
|
+
pnpm cv --set-version X.Y.Z # o -sv X.Y.Z / -sv=X.Y.Z; solo la siguiente patch, minor o major
|
|
127
|
+
pnpm cv -l # igual que --local: todo el release en esta máquina, sin preguntar
|
|
128
|
+
pnpm cv --dry-run # diagnóstico y plan, sin cambiar nada
|
|
129
|
+
pnpm cv --skip-unpublished # release nuevo aunque el último no esté en npm (lo saltea)
|
|
130
|
+
pnpm cv --ignore-local-changes # publica aunque haya cambios sin commitear (se apartan y se restauran)
|
|
131
|
+
pnpm cv --accept-suggested # toma la versión sugerida por los commits sin preguntar
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Los flags cortos (`-b`, `-p`, `-m`, `-M`, `-sv`, `-l`, `-h`) distinguen mayúsculas y van de a uno: `-lm` no se agrupa y corta con un error, igual que un flag corto desconocido; usá `-l -m`. Los que llevan valor lo aceptan en el token siguiente o con `=` (`-b m`, `-b=m`, `-sv=1.3.0`). Pedir dos tipos de versión distintos (`-m -M`, `--minor --bump major`, `-b p -b M`), repetir `--set-version`, `--ci-release` o `--retry-ci` con otro valor, combinar un tipo con `--set-version` o `--ci` con `--local` corta con un error antes de cualquier cambio. `--ci` sin `ci.workflow` configurado también corta, sin preguntar, y sugiere `--setup-ci` o `--local`.
|
|
135
|
+
|
|
136
|
+
Sin `--bump` ni `--set-version`, el comando pregunta la versión sin ninguna opción preseleccionada: se elige con su número, o con `↑`/`k` y `↓`/`j`/`Tab` más Enter (Enter no hace nada hasta marcar una). La opción que sugieren los commits lleva una estrella, pero no se elige sola. Sin terminal interactiva (CI) hay que pasar `--bump` o `--set-version`.
|
|
137
|
+
|
|
138
|
+
Si hay cambios sin commitear y son lo único que frena el release, el comando los lista y pregunta si ignorarlos (sin opción preseleccionada); responder que sí equivale a `--ignore-local-changes`. Con `--dry-run` o sin terminal interactiva no pregunta: muestra el bloqueo.
|
|
139
|
+
|
|
140
|
+
Con `--ignore-local-changes`, los cambios sin commitear (staged, sin stagear y archivos nuevos) se apartan con `git stash` antes del primer paso y se restauran al terminar, también si un paso falla: ni los checks, ni la preparación, ni la publicación los ven, y el commit de versión solo lleva `package.json`, `CHANGELOG.md` y `versionFiles`. En un release nuevo, `CHANGELOG.md` queda en el working tree porque el bump lo commitea. La restauración es exacta o no toca nada: lo que estaba staged vuelve staged, lo que estaba solo en el working tree vuelve sin stagear y los archivos nuevos vuelven sin trackear. Si alguna parte choca con el commit de versión (por ejemplo, un cambio en la línea `version` de `package.json`), no se escribe nada, la entrada queda en `git stash` y el comando lo avisa; igual que si el proceso se corta, se recuperan con `git stash pop --index`.
|
|
141
|
+
|
|
142
|
+
`--ignore-local-changes` no aparta cambios en archivos `.js`, `.mjs`, `.cjs`, `.ts` ni `.json`, ni en ningún `.npmrc`: la configuración ya se cargó desde el working tree y puede depender de ellos, y el diagnóstico ya resolvió el registry y las credenciales desde el `.npmrc`. El plan, también con `--dry-run`, se bloquea y pide commitearlos o guardarlos con `git stash`. En la preparación de un release en CI tampoco aparta cambios en los archivos que definen el worker (`astra-rp.config.*`, `package.json`, `.npmrc`, `.nvmrc`, cualquier lockfile y el workflow configurado): el preflight los leería del working tree y el worker usaría los commiteados en el tag, así que el plan se bloquea antes del bump.
|
|
143
|
+
|
|
144
|
+
El comando sale solo desde `main`, limpio y al día con origin (solo `CHANGELOG.md` puede quedar sin commitear en un release nuevo, porque el bump lo commitea; para retomar un release ya commiteado, también tiene que estar limpio). En una rama feature explica qué falta: pushear, abrir o mergear el PR (con `gh`). La única excepción es publicar un release que falta en npm desde su tag (ver [Versiones sin publicar](#versiones-sin-publicar)).
|
|
145
|
+
|
|
146
|
+
1. Si `main` está atrás de origin, lo actualiza en fast-forward y termina (código de salida 0) sin tocar la versión ni los tags: hay que volver a correr `pnpm create-version`, que en un proceso nuevo carga `astra-rp.config.(m)js`, sus módulos y el diagnóstico desde el código actualizado.
|
|
147
|
+
2. Verifica que `CHANGELOG.md` exista, haya cambiado desde el último release y tenga un bloque `## [Unreleased]` con al menos una entrada (`- …`). Si falta, no fue actualizado o `[Unreleased]` no tiene entradas, corta con código de salida `1` y lo reporta antes de aplicar migraciones o cambiar la versión, también con `--dry-run` y sin que otros flags salteen la verificación. Se aceptan actualizaciones manuales ya commiteadas, staged o sin stagear. Para el primer release no se compara con un release anterior. Con `changelogDraft`, antes de cortar intenta redactar las entradas con un agente (ver [Redacción del CHANGELOG con un agente](#redacción-del-changelog-con-un-agente)).
|
|
148
|
+
3. Aplica migraciones pendientes, si el proyecto tiene adaptador, después de pedir confirmación.
|
|
149
|
+
4. Corre los `checks` (por defecto `pnpm run ci`; ver abajo).
|
|
150
|
+
5. Pide la versión y crea el commit `X.Y.Z` con el tag anotado `vX.Y.Z`. En ese commit cierra la sección del CHANGELOG: el encabezado `## [Unreleased]` pasa a `## [X.Y.Z] - AAAA-MM-DD` (el día en la zona horaria IANA de `releaseTimeZone` si el proyecto la configura; si no, el día local de la máquina que crea el commit, también al preparar un release en CI) con su contenido intacto, y arriba se agrega un `## [Unreleased]` nuevo y vacío. Nunca genera entradas ni reescribe el resto del archivo. Si un check modificó el CHANGELOG antes del bump, corta sin tocar la versión; si falla la escritura o el commit, o un hook lo cambia, devuelve el CHANGELOG a su contenido y staging anteriores y no crea el tag. Al retomar un release ya commiteado no lo vuelve a cerrar.
|
|
151
|
+
6. Corre `prepare`, sube `main` y el tag con `git push --atomic` y corre `publish`.
|
|
152
|
+
|
|
153
|
+
El último release es el último commit de `origin/main` que cambió el `version` de `package.json`, así que sirve con commits `X.Y.Z`, con otros asuntos de release y con versiones subidas a mano. Si algo falla después del commit, volver a correr el comando retoma solo lo que falta: el push de un commit de versión local o, con `registry: "npm"`, la preparación y publicación de una versión que npm todavía no tiene. Las versiones publicadas se consultan con `npm view --registry` en el mismo registry donde se publica (ver abajo), porque `npm view` no aplica el `publishConfig` del `package.json`.
|
|
154
|
+
|
|
155
|
+
Si un paso falla cuando `main` y el tag ya están en origin (recién pusheados o de antes), el recuadro de error lo dice explícitamente, por ejemplo: "`v1.9.1` ya está en GitHub (main + tag); falta publicar en npm. Corré `pnpm create-version` para reintentar solo la publicación."
|
|
156
|
+
|
|
157
|
+
### astra-rp.config.js
|
|
158
|
+
|
|
159
|
+
```js
|
|
160
|
+
/** @type {import("@astra-kit/rp/create-version").CreateVersionConfig} */
|
|
161
|
+
export default {
|
|
162
|
+
projectName: "TuTribu", // banner; por defecto el name de package.json
|
|
163
|
+
releaseTypeDescriptions: { patch: "…", minor: "…", major: "…" },
|
|
164
|
+
preMajorShift: true, // en 0.x la sugerida baja un nivel (breaking → minor, feat → patch)
|
|
165
|
+
publishedLabel: "en producción", // banner: vX.Y.Z en producción
|
|
166
|
+
registry: "npm", // retoma y banner según las versiones en npm
|
|
167
|
+
checks: ["pnpm check"], // antes de tocar la versión; false para no validar
|
|
168
|
+
migrations: { check, apply, targetHint }, // adaptador de base de datos
|
|
169
|
+
prepare: ["pnpm release:prepare"], // comandos o función, sobre el commit de versión
|
|
170
|
+
publish: "npm", // npm publish con NPM_TOKEN, o una función
|
|
171
|
+
artifact: "releases/{version}-{sha256}/{name}-{version}.tgz", // con "npm": publica ese tarball verificado
|
|
172
|
+
summary: ["Vercel buildea {version}."], // líneas extra del resumen final
|
|
173
|
+
versionFiles: ["src/cli.ts"], // otros archivos con la versión, en el commit de release
|
|
174
|
+
releaseTimeZone: "America/Argentina/Buenos_Aires", // zona IANA de la fecha de ## [X.Y.Z] - AAAA-MM-DD; por defecto el día local
|
|
175
|
+
changelogDraft: true, // redacta [Unreleased] con Claude Code o Codex si falta; o ["codex", "claude"]
|
|
176
|
+
};
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Redacción del CHANGELOG con un agente
|
|
180
|
+
|
|
181
|
+
`changelogDraft` es opcional y está apagado por defecto. Cuando un release nuevo local se cortaría solo porque `CHANGELOG.md` no tiene entradas en `## [Unreleased]` (o el archivo no existe), astra-rp las redacta con un agente CLI antes de cortar:
|
|
182
|
+
|
|
183
|
+
- `true` prueba primero Claude Code (`claude`) y, si falla, Codex (`codex`). Una lista como `["codex"]` o `["codex", "claude"]` elige cuáles se prueban y en qué orden.
|
|
184
|
+
- Los agentes no corren en el repositorio sino en una copia aislada, en un directorio temporal que se borra al terminar: `repository/` con los archivos versionados en `HEAD`, incluidos los marcados con `export-ignore` (sin `.git` ni archivos sin trackear, así credenciales locales como un `.env` o `.npmrc` sin versionar quedan afuera) y `release-context/` con el diff del rango desde el último release (sin `CHANGELOG.md`), su `git log --stat` y el `CHANGELOG.md` actual del working tree, que arma astra-rp. El prompt incluye ese rango y sus commits, y pide respetar las reglas del proyecto sobre el CHANGELOG (`AGENTS.md`, `CLAUDE.md`, `CONTRIBUTING.md`). Si la copia no se puede armar, se informa el motivo y el release se corta como sin `changelogDraft`.
|
|
185
|
+
- Claude Code solo tiene sus herramientas de lectura (`Read`, `Grep`, `Glob`), sin Bash ni servidores MCP, con `--permission-mode dontAsk`, `permissions.blockReadsOutsideWorkingDirectories` y `--restricted` (requiere Claude Code v2.1.248 o posterior), que no carga tus settings de usuario ni de proyecto: las lecturas fuera de la copia se rechazan. Corre con `--no-session-persistence`, así no queda una sesión reanudable con el prompt. Codex usa `--sandbox read-only`, que impide escribir pero no limita qué lee: Codex no ofrece una opción para restringir las lecturas a un directorio ni para desactivar su shell, así que, aunque la copia ya no expone las credenciales sin versionar del repositorio, podría leer otros archivos de la máquina (por ejemplo `~/.npmrc` o claves SSH). Si ese riesgo no es aceptable, configurá `changelogDraft: ["claude"]`.
|
|
186
|
+
- Se pasa al siguiente agente si el actual no está instalado, no tiene cuota o sesión, falla, tarda más de 10 minutos o responde algo que no sean secciones de Keep a Changelog con entradas `- …`: cada entrada debe estar dentro de una sección, y las secciones (`### Added`, `### Changed`, `### Deprecated`, `### Removed`, `### Fixed`, `### Security`) deben aparecer una sola vez, en ese orden y con al menos una entrada.
|
|
187
|
+
- La primera respuesta válida se escribe en `## [Unreleased]` sin pedir confirmación, se muestra en la terminal y el release sigue: el commit de versión la cierra como cualquier entrada manual. Si todos los agentes fallan, se muestra por qué falló cada uno y el release se corta como sin `changelogDraft`.
|
|
188
|
+
- No corre con `--dry-run` (solo avisa que lo haría), en el worker de CI, en `--retry-ci` ni en modo monorepo. Tampoco reemplaza entradas que ya existen.
|
|
189
|
+
- No redacta si `CHANGELOG.md` no es un archivo regular (por ejemplo, un symlink que podría apuntar fuera del repositorio): avisa y el release se corta como sin `changelogDraft`. Tampoco redacta, ni llama a ningún agente, si `## [Unreleased]` tiene algo más que líneas en blanco y encabezados `### <tipo>` vacíos (por ejemplo, un comentario `<!-- … -->` o texto de plantilla), para no borrarlo: avisa y el release se corta igual. Si el archivo cambia, aparece o desaparece mientras el agente redacta, no se escribe nada: se avisa y hay que volver a correr el comando.
|
|
190
|
+
|
|
191
|
+
### Un registry por proyecto
|
|
192
|
+
|
|
193
|
+
`publish` elige un único destino: `"npm"`, `"github"`, `"gitlab"` o `"jsr"`. `registry` toma ese mismo valor por defecto; consulta las versiones en ese destino para decidir qué falta publicar. `publish: "npm"` conserva su comportamiento y sus defaults anteriores. Una función de `publish` sigue siendo válida para un flujo propio.
|
|
194
|
+
|
|
195
|
+
```js
|
|
196
|
+
export default {
|
|
197
|
+
checks: ["pnpm check"],
|
|
198
|
+
publish: "gitlab",
|
|
199
|
+
publication: {
|
|
200
|
+
registryUrl: "https://gitlab.com/api/v4/projects/123/packages/npm/",
|
|
201
|
+
authentication: "token",
|
|
202
|
+
tokenEnv: "CI_JOB_TOKEN",
|
|
203
|
+
access: "restricted",
|
|
204
|
+
tag: "latest",
|
|
205
|
+
},
|
|
206
|
+
};
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
GitHub Packages requiere un `name` con scope en `package.json` (`@owner/package`). Su URL por defecto es `https://npm.pkg.github.com/` y su variable de token por defecto es `GITHUB_TOKEN`; en ejecución local puede contener un PAT classic con permisos de paquetes. La visibilidad del paquete también depende de la configuración de GitHub: `access` no reemplaza esos permisos. GitLab requiere el endpoint del **proyecto** para publicar, también en instalaciones propias. Su variable por defecto es `GITLAB_TOKEN`, configurable como `CI_JOB_TOKEN` o cualquier otra variable mediante `tokenEnv`. Un redirect de GitLab hacia npmjs.com se interpreta como paquete ausente en GitLab; nunca confirma una publicación local.
|
|
210
|
+
|
|
211
|
+
Los tokens se buscan en el entorno, `.env` del repo y `~/.config/astra-rp/.env`, en ese orden. `tokenEnv` selecciona qué variable leer. Las verificaciones de permisos que el proveedor no expone se muestran como **no verificables**; GitHub y GitLab no necesitan implementar `npm whoami` ni `npm owner ls` para publicar. Si una publicación falla, se consulta el registry elegido antes de declararla pendiente; una versión confirmada no se vuelve a subir.
|
|
212
|
+
|
|
213
|
+
Para npm con trusted publishing, configurá `publication: { authentication: "oidc" }`. Se verifica el entorno de GitHub Actions o GitLab CI, npm >= 11.5.1 y Node >= 22.14.0; no exige `NPM_TOKEN` para publicar. El paquete debe tener el trusted publisher configurado en npm. La consulta de un paquete privado puede usar una credencial de lectura mediante `tokenEnv`.
|
|
214
|
+
|
|
215
|
+
```js
|
|
216
|
+
export default {
|
|
217
|
+
checks: ["pnpm check"],
|
|
218
|
+
publish: "jsr",
|
|
219
|
+
publication: {
|
|
220
|
+
authentication: "oidc", // GitHub Actions; local: "browser", otro CI: "token"
|
|
221
|
+
configFile: "jsr.json", // también jsr.jsonc, deno.json o deno.jsonc
|
|
222
|
+
jsrClient: "npx", // cliente oficial fijado a jsr@0.14.3; alternativa: "deno"
|
|
223
|
+
},
|
|
224
|
+
};
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
JSR requiere un manifest propio trackeado, con `name` con scope, `version`, `exports` y los demás requisitos del cliente oficial (ESM y licencia). astra-rp sincroniza su versión con `package.json` en el mismo commit, conservando comentarios y formato de JSONC. En monorepos cada paquete publicado tiene su propio manifest dentro de su carpeta. No agregues ese archivo a `versionFiles`: su versión se gestiona automáticamente. Los tarballs y la comprobación contra `npm pack` aplican a los tres destinos compatibles con npm; JSR publica fuentes y confirma la versión en su API nativa. No admite paquetes privados ni dist-tags de npm. El cliente oficial puede descargarse en su caché con `npx`; `jsrClient: "deno"` usa Deno instalado. Los errores del cliente se muestran ocultando el token. Las entradas del CHANGELOG siguen siendo manuales.
|
|
228
|
+
|
|
229
|
+
Las entradas del CHANGELOG se escriben a mano dentro de `## [Unreleased]`, con las secciones que elija el proyecto (se recomienda [Keep a Changelog](https://keepachangelog.com/es-ES/1.1.0/)); nunca se escriben la versión ni la fecha. Un release nuevo exige que el archivo cambie desde el último release y que `[Unreleased]` tenga al menos una entrada; el commit de versión renombra ese bloque a `## [X.Y.Z] - AAAA-MM-DD`, deja arriba un `## [Unreleased]` vacío y conserva el resto del archivo byte a byte. La fecha es el día de la máquina que crea el commit de versión; un runner de CI suele estar en UTC, así que un release de la noche en Argentina quedaría fechado al día siguiente. `releaseTimeZone` fija esa fecha en una zona horaria IANA (por ejemplo `"America/Argentina/Buenos_Aires"`), en modo simple y monorepo, en local y en CI, y el mensaje `[Unreleased] cerrado como ## [X.Y.Z] - AAAA-MM-DD (zona horaria …)` la nombra. Una zona que `Intl.DateTimeFormat` no reconoce, o un valor que no es string, corta el comando al leer el config, antes de cualquier cambio. Para retomar un release ya commiteado, el CHANGELOG debe estar limpio incluso con --ignore-local-changes, porque el comando no lo aparta ni restaura. Sin `checks`, un release nuevo corre `<package manager> run ci` (`pnpm run ci`, `bun run ci`…) si el `package.json` declara el script `ci`; si no lo declara, el plan se bloquea para no publicar sin validar. `checks: false` saltea la validación a propósito (por ejemplo, cuando `prepare` ya corre lint, typecheck, tests y build) y una lista vacía no es válida. Los hooks (`migrations.check`, `migrations.apply`, `prepare`, `publish`) reciben `{ repositoryRoot, version, git, run, print, fail }`: `git` lee Git, `run("pnpm x")` corre un comando visible y devuelve su exit code, y `fail(mensaje, qué hacer)` corta el paso con una explicación. El config no necesita importar `@astra-kit/rp`.
|
|
230
|
+
|
|
231
|
+
La versión sugerida sale de los commits: un breaking change (`feat!:` o `BREAKING CHANGE:`) sugiere major, un `feat` (o un asunto como "Add …") minor, y solo arreglos y mantenimiento patch. Con `preMajorShift: true`, mientras la versión es `0.x` la sugerida baja un nivel (breaking → minor, `feat` → patch), la convención de `0.x` que release-please aplica con `bump-minor-pre-major` y `bump-patch-for-minor-pre-major`: así un breaking change en `0.x` no sugiere saltar a `1.0.0`. Las descripciones por defecto de cada opción bajan con ella (patch: arreglos o funcionalidades nuevas compatibles; minor: cambio incompatible; major: salir de `0.x` a `1.0.0`); las que el proyecto definió en `releaseTypeDescriptions` se muestran tal cual. Es solo la sugerida (la estrella y `--accept-suggested`); se puede elegir cualquiera de las tres.
|
|
232
|
+
|
|
233
|
+
`versionFiles` lista archivos que también llevan la versión, como el `--version` de una CLI o una constante: rutas relativas a la raíz, con `/` o `\` (`.\src\cli.ts` es `src/cli.ts`), sin rutas absolutas, `..`, `package.json` ni `CHANGELOG.md` (el commit de release los incluye y es el que cierra la sección `[Unreleased]` del CHANGELOG). En el commit de release solo cambian sus líneas marcadas: una línea con el comentario `astra-rp-version`, o todas las líneas entre `astra-rp-start-version` y `astra-rp-end`. También se aceptan los marcadores de release-please (`x-release-please-version`, `x-release-please-start-version` … `x-release-please-end`), así que un proyecto que viene de release-please no toca sus archivos. Una versión seguida de un punto final (`1.2.3.`) se reescribe; `1.2.3.4` no. Un bloque sin cierre, un cierre sin bloque, un bloque dentro de otro o cerrado con el marcador de la otra herramienta cortan el release con el archivo, la línea y el marcador. Antes de escribir nada, cada archivo tiene que existir como archivo regular (no un symlink), estar trackeado en Git, ser UTF-8 válido y tener al menos una versión marcada; si no, el release se corta sin tocar la versión (release-please lo ignoraría en silencio). Si un paso anterior (por ejemplo, un check con `--fix`) modificó `package.json` o un `versionFiles`, el release también se corta sin tocar la versión, para no llevar ese cambio al commit de release. Si falla una escritura, `git add` o el commit, astra-rp devuelve `package.json`, `versionFiles` y el CHANGELOG a su contenido y staging anteriores; si un hook cambia o agrega algo al commit de versión, lo deshace y restaura esos archivos sin crear el tag ni subir nada. Al retomar un release ya commiteado, verifica que los `versionFiles` del commit tengan la versión pendiente antes de subir o publicar, y no retoma mientras `astra-rp.config.(m)js` tenga cambios sin commitear.
|
|
234
|
+
|
|
235
|
+
```ts
|
|
236
|
+
program.version("1.4.0"); // astra-rp-version
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
`migrations.check` devuelve `{ status: "up-to-date" | "pending" | "unknown", pending, target, reason }`; después de `apply`, el comando vuelve a llamar a `check` y falla si siguen pendientes. `publish: "npm"` toma `NPM_TOKEN` de una sola búsqueda, compartida por el diagnóstico, `npm view` y la publicación (ver [Token de npm](#token-de-npm)). No hace falta `.npmrc`: el comando escribe una config de npm temporal fuera del repo que asocia `${NPM_TOKEN}` al registry donde realmente se publica, resuelto como npm: `publishConfig["@scope:registry"]` si el paquete tiene ese scope, si no `publishConfig.registry` y, si el `package.json` no declara ninguno, lo que devuelve `npm config get @scope:registry` (paquete con scope) o `npm config get registry` en la raíz del repo, que incluye el `.npmrc` del proyecto, las variables `npm_config_*` y la config global (como la publicación, no lee `~/.npmrc`, que se reemplaza por la config temporal); tiene que ser una URL http(s) válida o no se publica. Con `NPM_TOKEN` disponible, el diagnóstico también consulta `npm view` con esa config temporal, así que funciona con paquetes privados; sin token consulta sin autenticar. El resumen final enlaza a npmjs.com solo si el registry es `https://registry.npmjs.org/`; si no, muestra `Registro: <url>` con el paquete y la versión. Solo guarda esa referencia: npm la expande, el token nunca queda en disco ni en la línea de comandos, y la config se borra al terminar. npm hereda la terminal, así que la confirmación 2FA (navegador o código) funciona igual.
|
|
240
|
+
|
|
241
|
+
Sin `artifact`, `publish: "npm"` publica el working tree. Con `artifact` publica exactamente el tarball que dejó `prepare`. Los proyectos empaquetan siempre con npm: `prepare` construye (con pnpm o lo que use el proyecto) y después corre `npm pack --ignore-scripts`. `npm pack` es reproducible (el mismo commit da siempre los mismos bytes), así que la verificación es una comparación de hash. Después de `prepare` y antes de `npm publish`:
|
|
242
|
+
|
|
243
|
+
- Working tree: `git status --porcelain --untracked-files=no` tiene que estar vacío. `prepare` puede generar archivos ignorados o no versionados (`dist/`, `releases/`), pero no modificar archivos versionados como `package.json`; así lo que lee npm es exactamente el commit de release.
|
|
244
|
+
- Publicable con npm: si el `package.json` depende de algo que solo pnpm reescribe al empaquetar (especificadores `workspace:`, `catalog:` o `jsr:` en `dependencies`, `peerDependencies` u `optionalDependencies`, o campos del manifest dentro de `publishConfig` que pnpm sube a la raíz del `package.json` empaquetado), no se publica. Para npm, `publishConfig` es solo [configuración de npm](https://docs.npmjs.com/cli/v11/configuring-npm/package-json#publishconfig), así que se acepta cualquier clave (`registry`, `access`, `tag`, `provenance`, `@scope:registry`, `otp`...) salvo las que pnpm aplica al manifest: `name`, `bin`, `engines`, `type`, `imports`, `main`, `module`, `typings`, `types`, `exports`, `browser`, `esnext`, `es2015`, `unpkg`, `umd:main`, `os`, `cpu`, `libc` y `typesVersions` (lista de `PUBLISH_CONFIG_WHITELIST` en pnpm). Declaralos en la raíz del `package.json`.
|
|
245
|
+
- Ubicación: el patrón es relativo a la raíz, reemplaza `{version}` (obligatorio) y `{name}` (el nombre de archivo que usa `npm pack`: `@scope/pkg` pasa a `scope-pkg`), y dentro de un segmento acepta `*` y `{sha256}`. Si hay varios, toma el más reciente. La ruta solo puede tener letras, números, `.`, `-`, `_`, `@`, `+`, `~` y `/`.
|
|
246
|
+
- `{sha256}`: el SHA-256 del archivo tiene que coincidir con el de su ruta. Puede repetirse en un segmento o en varios; todas las apariciones tienen que declarar el mismo digest.
|
|
247
|
+
- Hash: astra-rp corre `npm pack --dry-run --json --ignore-scripts` en la raíz y compara su `integrity` (`sha512-<base64>`) con el SHA-512 del tarball. Durante ese dry run el tarball se mueve a un directorio temporal fuera del paquete y siempre vuelve a su ruta, aunque npm falle: sin una lista `files` ni una regla de `.npmignore`/`.gitignore` que excluya su carpeta, npm lo contaría como parte del paquete y la integrity nunca coincidiría. Después se publica desde su ruta original. Si difieren, el tarball no es lo que npm empaquetaría de este commit (por ejemplo, se armó con otra herramienta o antes de construir) y no se publica. Si npm falla o su salida no se puede leer, tampoco.
|
|
248
|
+
|
|
249
|
+
Ejemplo de `prepare` que deja `releases/{version}-{sha256}/{name}-{version}.tgz`: `pnpm build`, `npm pack --ignore-scripts --pack-destination releases/<version>-tmp/` y renombrar la carpeta con el SHA-256 del tarball.
|
|
250
|
+
|
|
251
|
+
Si no hay tarball o la verificación falla, no se publica nada y volver a correr el comando retoma preparación y publicación.
|
|
252
|
+
|
|
253
|
+
### Monorepo
|
|
254
|
+
|
|
255
|
+
Con `packages` en el config, cada paquete publicable del monorepo tiene su propia versión, su `CHANGELOG.md`, su tag y su publicación:
|
|
256
|
+
|
|
257
|
+
```js
|
|
258
|
+
export default {
|
|
259
|
+
packages: "workspaces", // los workspaces del package.json raíz, o ["packages/*", "!packages/internal"]
|
|
260
|
+
tagFormat: "{component}-v{version}", // por defecto: widget-v1.2.0 ({component} es la carpeta; también {name})
|
|
261
|
+
checks: ["bun run ci"],
|
|
262
|
+
prepare: ["bun install --frozen-lockfile", "bun run build"], // una vez para todos los paquetes
|
|
263
|
+
publish: "npm",
|
|
264
|
+
};
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
- Paquetes: los workspaces con `name` que no son `private`. Un paquete tiene cambios cuando un commit toca su carpeta, o la de un paquete `private` del que depende (directa o transitivamente, en cualquier campo de dependencias): los paquetes internos suelen ir bundleados en quien los usa, así que un cambio ahí sale con un release de cada consumidor. Los patrones son rutas relativas a la raíz: uno con `..` o absoluto corta el comando, igual que un `package.json` inválido en una carpeta que coincide con un patrón, o uno que no es `private` sin `name` o sin un `version` estable `X.Y.Z` (se indica la ruta y el motivo).
|
|
268
|
+
- Último release de cada paquete: el último commit de `origin/main` que cambió el `version` de su `package.json`. Un paquete en `0.0.0` (el placeholder de release-please) nunca salió, salvo que su propio tag apunte a ese commit o que un commit `release: …` lo liste en `0.0.0`: todos sus commits van en su primer release, cuya sugerida no baja con `preMajorShift` (un `feat` da `0.1.0`).
|
|
269
|
+
- Versión: por cada paquete con cambios pregunta patch, minor o major (la sugerida por sus commits lleva una estrella) o "No publicar ahora". `--bump` aplica el mismo tipo a todos y `--accept-suggested` toma la sugerida de cada uno; `--set-version` no aplica. Si una versión elegida no es mayor que la más alta publicada en npm (ya está publicada o movería `latest` hacia atrás), si dos paquetes elegidos darían el mismo tag (por ejemplo, dos carpetas `server` con `{component}`), si un tag no es un nombre válido para Git o ya existe en local, se corta sin escribir nada. El CHANGELOG conserva el formato y las secciones elegidas manualmente; solo se cierra su bloque `[Unreleased]`.
|
|
270
|
+
- CHANGELOG: cada paquete elegido debe tener su archivo actualizado manualmente respecto de su último release y un `## [Unreleased]` con al menos una entrada. Si falta, no cambió o `[Unreleased]` no tiene entradas, el comando corta y reporta el archivo antes de aplicar migraciones o cambiar versiones. El plan avisa qué paquetes necesitan actualización; un paquete que no se elige no exige notas nuevas ni se modifica. El commit de release cierra el `[Unreleased]` de cada paquete que sale como `## [X.Y.Z] - AAAA-MM-DD` con la versión de ese paquete, y lo restaura si el commit falla.
|
|
271
|
+
- Las versiones se eligen antes de aplicar migraciones: si no sale ningún paquete, no se toca la base de datos.
|
|
272
|
+
- Los `CHANGELOG.md` de los paquetes pueden quedar sin commitear durante el plan, pero antes de escribir el commit de release el comando se corta sin tocar nada si hay algo staged que no es de los paquetes elegidos, o si el `CHANGELOG.md` de un paquete que no sale tiene cambios. Como en un solo paquete, `--ignore-local-changes` no aparta cambios en `.js`, `.mjs`, `.cjs`, `.ts`, `.json` (incluidos los `package.json` de los workspaces) ni `.npmrc`.
|
|
273
|
+
- `summary`: una línea con `{version}` o `{name}` se muestra una vez por paquete publicado, con su versión y su nombre; las demás, una sola vez.
|
|
274
|
+
- Un solo commit de release (`release: @scope/a@1.2.0, @scope/b@0.3.1`) con un tag anotado por paquete; `main` y los tags suben con `git push --atomic`.
|
|
275
|
+
- `versionFiles` sigue siendo relativo a la raíz: cada archivo toma la versión del paquete que lo contiene y solo cambia cuando ese paquete sale (no puede ser el `package.json` ni el `CHANGELOG.md` de un paquete: el commit de release ya los escribe y cierra el `[Unreleased]` del CHANGELOG), con las mismas validaciones, el mismo rollback y la misma verificación del commit de release. Al retomar un release no se verifica la versión de esos archivos.
|
|
276
|
+
- `prepare` corre una vez (su contexto trae `releases` con nombre, versión y carpeta); `publish: "npm"` publica cada paquete desde su carpeta, en orden de dependencias (primero los que otros instalan). `artifact`, si se usa, es relativo a la carpeta de cada paquete. Con o sin `artifact`, npm no publica si `prepare` modificó archivos versionados o si el `package.json` del paquete usa `workspace:`, `catalog:` o `jsr:` en `dependencies`, `peerDependencies` u `optionalDependencies`. Un `publish` propio corre una vez por paquete.
|
|
277
|
+
- Retoma: si el commit de release quedó solo en local, retoma el push y la publicación. Si un release ya está en origin con su tag y falta en npm, lo publica antes de cualquier release nuevo, preparándolo desde su propio commit en un worktree temporal (no hace falta desacoplar HEAD) aunque `main` haya avanzado. Se publica en el registry que resolvió el diagnóstico en el repositorio (también el de un `.npmrc` sin trackear). Si un tag local ya existe y apunta a otro commit que el de release, no se sube nada. Si el paquete cambió de `name` desde su commit de release, ese release no se publica. Una versión menor que la más alta de npm no se publica (movería `latest` hacia atrás) y se avisa. `--skip-unpublished` saltea esos releases pendientes (lo advierte el plan) y planifica el release nuevo.
|
|
278
|
+
- No aplican `ignore-build` ni la publicación desde HEAD desacoplado.
|
|
279
|
+
|
|
280
|
+
### Token de npm
|
|
281
|
+
|
|
282
|
+
`NPM_TOKEN` se busca en este orden y se usa el primero que esté definido (no vacío):
|
|
283
|
+
|
|
284
|
+
1. La variable de entorno `NPM_TOKEN`.
|
|
285
|
+
2. El `.env` del repo (ignorado por Git).
|
|
286
|
+
3. `~/.config/astra-rp/.env` (en Windows, `%USERPROFILE%\.config\astra-rp\.env`), compartido por todos los proyectos.
|
|
287
|
+
|
|
288
|
+
Para tener un solo token en todos los proyectos, guardalo solo en el archivo compartido y sacá `NPM_TOKEN` de los `.env` de cada repo (que tienen prioridad):
|
|
289
|
+
|
|
290
|
+
```bash
|
|
291
|
+
mkdir -p ~/.config/astra-rp
|
|
292
|
+
printf 'NPM_TOKEN=%s\n' "<token>" > ~/.config/astra-rp/.env
|
|
293
|
+
chmod 600 ~/.config/astra-rp/.env
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
El token nunca se escribe en disco ni en la línea de comandos, ni se carga en el `process.env` del comando: solo lo recibe el proceso de npm por su entorno, y la config temporal lo referencia como `${NPM_TOKEN}`. Los mensajes dicen de qué fuente salió, nunca el valor.
|
|
297
|
+
|
|
298
|
+
### Credenciales antes de publicar
|
|
299
|
+
|
|
300
|
+
Cuando el plan incluiría la publicación con `publish: "npm"` (release nuevo o retomado), el diagnóstico verifica las credenciales antes de tocar nada, con la misma config temporal y el mismo registry que `npm publish`, y las muestra en la fila `npm auth` (por ejemplo `guidomodarelli (.env del repo), dueño de <paquete>; permiso de escritura del token no verificable antes de publicar`):
|
|
301
|
+
|
|
302
|
+
- Sin token: bloquea y explica dónde definir `NPM_TOKEN`.
|
|
303
|
+
- `.npmrc` del proyecto con credenciales para ese registry (`//host/path/:_authToken`, `_auth`, `_password`, etc.): bloquea, porque npm las prioriza sobre la config temporal y autenticaría con ellas en vez de `NPM_TOKEN`. Solo se leen las claves, nunca los valores.
|
|
304
|
+
- `npm whoami --registry <registry>` responde 401/403: bloquea porque el token (de la fuente que corresponda) es inválido o venció.
|
|
305
|
+
- `npm owner ls <paquete> --registry <registry>`: si el paquete no existe (E404) es la primera publicación y sigue; si existe y el usuario no está entre los dueños, bloquea con el usuario y los dueños. En un paquete con scope de organización solo advierte, porque el acceso puede venir de un equipo.
|
|
306
|
+
- Si la verificación no puede decidir (red, registry sin `npm owner ls`, un `.env` o `.npmrc` que existe pero no se puede leer), advierte y publica igual. Un `.env` ilegible también hace fallar la consulta de `npm view`, que bloquea el diagnóstico nombrando el archivo.
|
|
307
|
+
|
|
308
|
+
`npm whoami` y `npm owner ls` corren con `--json=false`, así que su salida sigue siendo texto aunque el proyecto active `json=true` (o `npm_config_json=true`).
|
|
309
|
+
|
|
310
|
+
Límite: que el usuario sea dueño del paquete no prueba que el token pueda escribir. Un token read-only o granular sin permiso de escritura sobre el paquete pasa `npm whoami` y `npm owner ls`, y npm no ofrece una forma sin efectos de verificarlo antes de publicar (`npm publish --dry-run` no autentica). Por eso la fila lo aclara sin bloquear, y ese caso recién falla en `npm publish`, después de pushear el commit y el tag.
|
|
311
|
+
|
|
312
|
+
`npm publish` hereda la terminal (para el 2FA), así que su salida no se puede leer. Si termina con error, el comando vuelve a verificar las credenciales y explica el motivo: token inválido, usuario sin permisos sobre el paquete o, si el usuario es dueño, el error genérico, que menciona que el token puede ser read-only o granular sin permiso de escritura. Un `404 Not Found` de npm en el PUT suele significar falta de permisos.
|
|
313
|
+
|
|
314
|
+
### Versiones sin publicar
|
|
315
|
+
|
|
316
|
+
Con `registry: "npm"`, si la versión del último release (`package.json` en `origin/main`) es estable, no está en npm y es mayor que la última publicada, el comando no crea un release nuevo ni retoma un commit de versión local de otra versión, porque la saltearía. Si npm no tiene ninguna versión, solo bloquea cuando ese release tiene su tag `vX.Y.Z` (una versión inicial sin tag no es un release). El bloqueo explica cómo publicarla:
|
|
317
|
+
|
|
318
|
+
```bash
|
|
319
|
+
git switch --detach vX.Y.Z
|
|
320
|
+
pnpm create-version # prepara (si corresponde) y publica X.Y.Z; no sincroniza ni pushea main
|
|
321
|
+
git switch main
|
|
322
|
+
pnpm create-version # ahora sí, el release nuevo
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
Con HEAD desacoplado el comando solo corre cuando HEAD es exactamente el commit del tag `vX.Y.Z`, su asunto es `X.Y.Z` y esa versión falta en npm. Además bloquea si el tag no está en origin o apunta ahí a otro commit (volvé a `main` y corré `pnpm create-version`, que retoma el push) y si la versión no es mayor que la versión estable más alta de npm, porque publicarla con `--tag latest` movería `latest` hacia atrás. Si el release no se puede retomar así (otro asunto o sin tag), hay que publicarlo a mano. `--skip-unpublished` crea el release nuevo igual, a propósito, y lo advierte en el plan.
|
|
326
|
+
|
|
327
|
+
## Bloquear publicaciones con pnpm
|
|
328
|
+
|
|
329
|
+
`create-version` publica siempre con npm y verifica el tarball contra `npm pack --dry-run`, así que un `pnpm publish` manual saltearía esas garantías. Cada proyecto lo bloquea con:
|
|
330
|
+
|
|
331
|
+
```json
|
|
332
|
+
{ "scripts": { "prepublishOnly": "astra-rp guard-publish" } }
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
`astra-rp guard-publish` lee `npm_config_user_agent`: si empieza con `pnpm/`, `yarn/` o `bun/`, explica por stderr que se publica con el create-version de ese package manager (`pnpm create-version`, `yarn create-version` o `bun run create-version`) y sale con `1`; con `npm/`, sin la variable o con un valor desconocido sale con `0` sin imprimir nada. npm toma un `npm_config_user_agent` heredado como su config `user-agent`, por eso `create-version` lo quita del entorno de `npm publish`: así `pnpm create-version` no se bloquea a sí mismo.
|
|
336
|
+
|
|
337
|
+
Es una protección contra errores, no un candado: `--ignore-scripts` la esquiva a propósito. Aun así, un tarball empaquetado con pnpm no pasa la verificación de hash de `create-version`.
|
|
338
|
+
|
|
339
|
+
## Publicar @astra-kit/rp
|
|
340
|
+
|
|
341
|
+
astra-rp se publica con su propio comando (`astra-rp.config.js`: `checks: ["pnpm check"]`, `publish: "npm"`). Su `prepublishOnly` es `node bin/astra-rp.js guard-publish`, porque no se instala a sí mismo:
|
|
342
|
+
|
|
343
|
+
```bash
|
|
344
|
+
pnpm cv
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
## Desarrollo
|
|
348
|
+
|
|
349
|
+
```bash
|
|
350
|
+
pnpm install
|
|
351
|
+
pnpm check # oxlint (.oxlintrc.json) + typecheck (JSDoc con checkJs) + tests
|
|
352
|
+
pnpm build:types # genera types/*.d.ts (también corre en prepack)
|
|
353
|
+
```
|
package/bin/astra-rp.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* `astra-rp` command line.
|
|
4
|
+
*
|
|
5
|
+
* - `astra-rp ignore-build` prints why the current checkout is built or skipped
|
|
6
|
+
* and, as its last line, the decision (`BUILD` or `SKIP`), exiting with `0`.
|
|
7
|
+
* It exits with `2` when it cannot decide. Vercel wrappers must build only
|
|
8
|
+
* when the last line is `BUILD`, so any failure (including `npx` itself)
|
|
9
|
+
* skips the build.
|
|
10
|
+
* - `astra-rp create-version [--bump patch|minor|major | --set-version X.Y.Z] [--dry-run]`
|
|
11
|
+
* diagnoses the repository in the current directory and ships its release
|
|
12
|
+
* from `main`, following its `astra-rp.config.js`.
|
|
13
|
+
* - `astra-rp guard-publish` is the `prepublishOnly` guard: it exits with `1`
|
|
14
|
+
* and explains why when pnpm, yarn or bun publishes, and with `0` otherwise.
|
|
15
|
+
*
|
|
16
|
+
* @module astra-rp-cli
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { decideBuildForCheckout } from "../src/build-gate.js";
|
|
20
|
+
import { BUILD_DECISION, DECISION_EXIT_CODE, GATE_FAILURE_EXIT_CODE } from "../src/constants/build-gate.js";
|
|
21
|
+
import { CLI_COMMAND } from "../src/constants/cli.js";
|
|
22
|
+
import { runCreateVersion } from "../src/create-version/run.js";
|
|
23
|
+
import { decidePublishGuardForEnvironment } from "../src/guard-publish.js";
|
|
24
|
+
|
|
25
|
+
/** Usage printed for unknown commands. */
|
|
26
|
+
const USAGE = `Usage: astra-rp ${CLI_COMMAND.ignoreBuild} | astra-rp ${CLI_COMMAND.createVersion} [options] | astra-rp ${CLI_COMMAND.guardPublish}`;
|
|
27
|
+
|
|
28
|
+
const [command, ...commandArguments] = process.argv.slice(2);
|
|
29
|
+
|
|
30
|
+
if (command === CLI_COMMAND.createVersion) {
|
|
31
|
+
process.exitCode = await runCreateVersion({ repositoryRoot: process.cwd(), argv: commandArguments });
|
|
32
|
+
} else if (command === CLI_COMMAND.guardPublish) {
|
|
33
|
+
const decision = decidePublishGuardForEnvironment();
|
|
34
|
+
if (decision.message) {
|
|
35
|
+
console.error(decision.message);
|
|
36
|
+
}
|
|
37
|
+
process.exitCode = decision.exitCode;
|
|
38
|
+
} else if (command === CLI_COMMAND.ignoreBuild) {
|
|
39
|
+
try {
|
|
40
|
+
const decision = decideBuildForCheckout(process.cwd());
|
|
41
|
+
console.log(decision.reason);
|
|
42
|
+
console.log(decision.shouldBuild ? BUILD_DECISION.build : BUILD_DECISION.skip);
|
|
43
|
+
process.exitCode = DECISION_EXIT_CODE;
|
|
44
|
+
} catch (error) {
|
|
45
|
+
console.error("astra-rp ignore-build: could not decide; the build must be skipped.", error);
|
|
46
|
+
process.exitCode = GATE_FAILURE_EXIT_CODE;
|
|
47
|
+
}
|
|
48
|
+
} else {
|
|
49
|
+
console.error(`astra-rp: unknown command "${command ?? ""}". ${USAGE}`);
|
|
50
|
+
process.exitCode = GATE_FAILURE_EXIT_CODE;
|
|
51
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,95 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astra-kit/rp",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.10.0",
|
|
4
|
+
"description": "Dependency-free release process: stable version rules, Vercel build gate, manual changelog checks with automatic closing of [Unreleased], and terminal UI.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Guido Modarelli",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/guidomodarelli/astra-rp.git"
|
|
10
|
+
},
|
|
11
|
+
"type": "module",
|
|
12
|
+
"sideEffects": false,
|
|
13
|
+
"engines": {
|
|
14
|
+
"node": ">=22"
|
|
15
|
+
},
|
|
16
|
+
"packageManager": "pnpm@12.6.0",
|
|
17
|
+
"bin": {
|
|
18
|
+
"astra-rp": "./bin/astra-rp.js"
|
|
19
|
+
},
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"types": "./types/index.d.ts",
|
|
23
|
+
"default": "./src/index.js"
|
|
24
|
+
},
|
|
25
|
+
"./versions": {
|
|
26
|
+
"types": "./types/versions.d.ts",
|
|
27
|
+
"default": "./src/versions.js"
|
|
28
|
+
},
|
|
29
|
+
"./build-gate": {
|
|
30
|
+
"types": "./types/build-gate.d.ts",
|
|
31
|
+
"default": "./src/build-gate.js"
|
|
32
|
+
},
|
|
33
|
+
"./changelog": {
|
|
34
|
+
"types": "./types/changelog.d.ts",
|
|
35
|
+
"default": "./src/changelog.js"
|
|
36
|
+
},
|
|
37
|
+
"./terminal-ui": {
|
|
38
|
+
"types": "./types/terminal-ui.d.ts",
|
|
39
|
+
"default": "./src/terminal-ui.js"
|
|
40
|
+
},
|
|
41
|
+
"./testing": {
|
|
42
|
+
"types": "./types/testing.d.ts",
|
|
43
|
+
"default": "./src/testing.js"
|
|
44
|
+
},
|
|
45
|
+
"./guard-publish": {
|
|
46
|
+
"types": "./types/guard-publish.d.ts",
|
|
47
|
+
"default": "./src/guard-publish.js"
|
|
48
|
+
},
|
|
49
|
+
"./package-manager": {
|
|
50
|
+
"types": "./types/package-manager.d.ts",
|
|
51
|
+
"default": "./src/package-manager.js"
|
|
52
|
+
},
|
|
53
|
+
"./version-files": {
|
|
54
|
+
"types": "./types/version-files.d.ts",
|
|
55
|
+
"default": "./src/version-files.js"
|
|
56
|
+
},
|
|
57
|
+
"./create-version": {
|
|
58
|
+
"types": "./types/create-version/index.d.ts",
|
|
59
|
+
"default": "./src/create-version/index.js"
|
|
60
|
+
},
|
|
61
|
+
"./constants": {
|
|
62
|
+
"types": "./types/constants/index.d.ts",
|
|
63
|
+
"default": "./src/constants/index.js"
|
|
64
|
+
},
|
|
65
|
+
"./package.json": "./package.json"
|
|
66
|
+
},
|
|
67
|
+
"files": [
|
|
68
|
+
"bin",
|
|
69
|
+
"src",
|
|
70
|
+
"types",
|
|
71
|
+
"CHANGELOG.md",
|
|
72
|
+
"README.md",
|
|
73
|
+
"LICENSE.md"
|
|
74
|
+
],
|
|
75
|
+
"scripts": {
|
|
76
|
+
"build:types": "tsc -p tsconfig.types.json",
|
|
77
|
+
"lint": "oxlint",
|
|
78
|
+
"typecheck": "tsc -p tsconfig.json",
|
|
79
|
+
"test": "vitest run --dir tests",
|
|
80
|
+
"check": "pnpm lint && pnpm typecheck && pnpm test",
|
|
81
|
+
"create-version": "node bin/astra-rp.js create-version",
|
|
82
|
+
"cv": "node bin/astra-rp.js create-version",
|
|
83
|
+
"prepack": "pnpm build:types",
|
|
84
|
+
"prepublishOnly": "node bin/astra-rp.js guard-publish"
|
|
85
|
+
},
|
|
86
|
+
"publishConfig": {
|
|
87
|
+
"access": "public"
|
|
88
|
+
},
|
|
89
|
+
"devDependencies": {
|
|
90
|
+
"@types/node": "^24.13.4",
|
|
91
|
+
"oxlint": "^1.85.0",
|
|
92
|
+
"typescript": "^7.0.2",
|
|
93
|
+
"vitest": "^5.0.0"
|
|
94
|
+
}
|
|
95
|
+
}
|