Skip to content
Pages
On this page

Documentation

Publishing from GitHub Actions

El objetivo es que lanzar una versión sea esto y nada más:

bash
git tag -a v1.2.0 -m "Pegado con formato y atajo configurable."
git push origin v1.2.0

Y que compilar, sacar las notas, crear la versión, subir los binarios y publicar lo haga el CI.

Abajo tienes el workflow completo, trozo a trozo y con el porqué de cada pieza. Pégalo en .github/workflows/publicar.yml, cambia APP por el slug de tu ficha y guarda tu clave como secreto.

Antes: el secreto

Crea la clave en claves de API con ámbito publish y nada más, atada a esta aplicación y con caducidad — 365 días está bien para un CI. Guárdala en Settings → Secrets and variables → Actions → New repository secret con el nombre FULGEON_TOKEN.

Sólo publish porque es lo único que hace este workflow. Y atada a la app porque limita el destrozo: si el token se escapa —un registro, un fork, un runner ajeno— quien lo tenga puede publicar en esta ficha y en ninguna otra de tu cuenta.

Cuándo se dispara

yaml
on:
  push:
    tags:
      - 'v*'

  workflow_dispatch:
    inputs:
      version:
        description: 'Versión a publicar (por ejemplo 1.2.0)'
        required: true
      ensayo:
        description: 'Ensayo: no publica nada'
        type: boolean
        default: true

Con los tags v* para lo normal, y con ejecución manual para probarlo sin crear un tag. En la manual, la casilla ensayo viene marcada por defecto: enseña lo que haría y no publica nada.

Permisos y concurrencia

yaml
permissions:
  contents: read

concurrency:
  group: fulgeon-publicar
  cancel-in-progress: false

El workflow no escribe en el repositorio —sólo lee el código y el tag—, así que pide el permiso mínimo. Y una publicación empezada no se cancela: si entran dos tags seguidos, el segundo espera. Cancelar a mitad dejaría un borrador incompleto.

Descargar el código

yaml
- name: Descargar el código
  uses: actions/checkout@v4
  with:
    fetch-depth: 0

fetch-depth: 0 no es capricho: sin el historial completo no se puede leer el cuerpo del tag anotado ni buscar el tag anterior, y de ahí salen las notas.

Compilar

Aquí va tu build. Lo único que importa es que deje los binarios en dist/ y que el nombre diga en qué plataforma corren: el CLI deduce el destino de la extensión (.dmg → macOS, .msi → Windows, .AppImage → Linux) y del nombre (…-arm64…, …-x86_64…). Un .zip no lo deduce nadie: renómbralo o dile el destino a mano.

Compilar los tres sistemas en un solo runner casi nunca sale. Lo normal es un job por plataforma (strategy.matrix) que suba sus binarios con actions/upload-artifact, y que este job los recoja con actions/download-artifact antes de publicar. Publicar se hace una vez y con todo junto: una versión son todos sus archivos.

Versión, canal y notas

El paso Preparar versión y notas saca tres cosas del tag:

  • La versión: el nombre del tag sin la v inicial.
  • El canal, del propio tag: *-alpha* es alpha; *-beta* y *-rc* son beta; el resto, stable. Una v1.3.0-beta.1 no es una estable.
  • Las notas, de tres fuentes en orden de preferencia:
    1. El cuerpo del tag anotado. La fuente buena: las notas se escriben al etiquetar, cuando aún te acuerdas de qué cambió.
    2. La sección de CHANGELOG.md cuyo título mencione esa versión. Entra en el primer encabezado que la nombre y sale en el siguiente del mismo nivel o superior, así que los «### Añadido» y «### Corregido» de dentro se conservan.
    3. Último recurso: los commits desde el tag anterior. Feo, pero mejor que publicar sin decir qué cambia.

Si ninguna de las tres llega a diez caracteres, el CLI se planta antes de subir nada. Las notas quedan en NOTAS-VERSION.md, que es lo que se le pasa después con --changelog @NOTAS-VERSION.md.

Ensayo

yaml
- name: Ensayo
  env:
    FULGEON_TOKEN: ${{ secrets.FULGEON_TOKEN }}
  run: |
    npx --yes @fulgeon/cli@1 publish \
      --app "$APP" \
      --version "${{ steps.datos.outputs.version }}" \
      --channel "${{ steps.datos.outputs.canal }}" \
      --changelog @NOTAS-VERSION.md \
      --file 'dist/*.dmg' \
      --file 'dist/*.exe' \
      --file 'dist/*.AppImage' \
      --dry-run

Comprueba clave, ámbitos, app, canal, notas, archivos y destinos, y enseña la tabla de lo que subiría. No crea nada. Cuesta segundos y evita descubrir un error después de subir 400 MB.

El paso empieza mirando que el secreto exista y falla con un mensaje claro si falta, en vez de dejar que el error salga cinco líneas más abajo disfrazado de otra cosa.

Publicar

El mismo comando sin --dry-run, y sólo cuando no era un ensayo. Crea la versión en borrador, sube los binarios y la publica.

Si algo falla a mitad, la versión se queda en borrador —invisible— y el CLI te dice cuántos archivos llegaron: se termina desde el panel, o se borra el borrador y se relanza. Nada queda publicado a medias.

Añade --draft si prefieres revisarla en el panel antes de que se vea.

El resumen del job

El último paso escribe en $GITHUB_STEP_SUMMARY la versión, el canal, el enlace a la ficha y las notas. Así el resultado se lee desde la propia pestaña de Actions sin abrir el registro entero.

Sobre los forks

Los secretos no viajan a los forks, y eso es a propósito. Este workflow sólo se dispara con tags del repositorio: un pull request de fuera no puede publicar nada.

La acción compuesta

Si prefieres un solo paso a llamar a npx, existe como acción pública: JaviHG/fulgeon-publish-action, con las etiquetas v1 y v1.0.0. Instala el CLI, crea la versión, sube los archivos con sus hashes y publica:

yaml
- uses: JaviHG/fulgeon-publish-action@v1
  with:
    token: ${{ secrets.FULGEON_TOKEN }}
    app: clipio
    version: ${{ github.ref_name }}
    changelog: |
      Arranque más rápido en frío.
      Arreglado el icono de la bandeja en Windows 11.
    files: |
      dist/*.dmg
      dist/*.exe
    channel: stable

Entradas: token, app, version, changelog (multilínea, o @ruta para leer un fichero del repositorio), files (un patrón por línea), channel, targets, draft, dry-run, api y cli-version. Salidas: url y version-id.