Por Anónimo (no verificado) , 29 Abril 2026

Lo que lograrás

Construirás un pipeline de release que convierte un tag Git en un artefacto desplegado — firmado, probado, versionado y publicado.

El contrato

  • Push de un tag que coincida con v*.*.*.
  • CI construye, prueba, firma y publica.
  • Se crea un release de GitHub con notas auto-generadas.
  • El deployment se registra y verifica.

Paso 1: convenciones de tag

git tag -a v1.4.0 -m "Release 1.4.0"
git tag -s v1.4.0 -m "Release 1.4.0"

Paso 2: configurar el workflow

# .github/workflows/release.yml
name: release
on:
  push:
    tags: ['v*.*.*']

permissions:
  contents: write
  packages: write
  id-token: write

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          registry-url: 'https://registry.npmjs.org'
      - run: npm ci
      - run: npm run lint
      - run: npm test
      - run: npm run build
      - run: npm publish --provenance --access public
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

Paso 3: auto-generar notas de release

      - name: Generate notes
    id: notes
    uses: orhun/git-cliff-action@v2
    with:
      config: cliff.toml
      args: --latest --strip header
  - name: Create release
    uses: softprops/action-gh-release@v2
    with:
      body: ${{ steps.notes.outputs.content }}
      generate_release_notes: true

Paso 4: matriz de build para releases multi-plataforma

jobs:
  build:
    strategy:
      matrix:
        os: [ubuntu-latest, macos-latest, windows-latest]
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v4
      - run: cargo build --release
      - uses: actions/upload-artifact@v4
        with:
          name: bin-${{ matrix.os }}
          path: target/release/myapp*

Paso 5: artefactos firmados

      - uses: sigstore/cosign-installer@v3
  - run: |
      cosign sign-blob --yes \
        --output-certificate cert.pem \
        --output-signature sig.bin \
        dist/myapp-1.4.0.tgz

Paso 6: release de imagen Docker

      - uses: docker/setup-buildx-action@v3
  - uses: docker/login-action@v3
    with:
      registry: ghcr.io
      username: ${{ github.actor }}
      password: ${{ secrets.GITHUB_TOKEN }}
  - uses: docker/build-push-action@v5
    with:
      push: true
      tags: |
        ghcr.io/${{ github.repository }}:${{ github.ref_name }}
        ghcr.io/${{ github.repository }}:latest

Paso 7: deploy tras publish

      - name: Deploy to production
    run: ./scripts/deploy.sh
    env:
      DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}

Paso 8: notificación

      - name: Slack notify
    uses: slackapi/slack-github-action@v1
    with:
      payload: |
        {
          "text": "Released ${{ github.ref_name }} :rocket:"
        }
    env:
      SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}

Paso 9: canales de pre-release

jobs:
  release:
    steps:
      - id: classify
        run: |
          if [[ "${{ github.ref_name }}" =~ -(alpha|beta|rc) ]]; then
            echo "tag=next" >> $GITHUB_OUTPUT
          else
            echo "tag=latest" >> $GITHUB_OUTPUT
          fi
      - run: npm publish --tag ${{ steps.classify.outputs.tag }}

Paso 10: integrar con release-please

Paso 11: tagear el SHA en artefactos

      - name: Get short SHA
    id: vars
    run: echo "sha=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
  - run: docker build -t myapp:${{ github.ref_name }} -t myapp:${{ steps.vars.outputs.sha }} .

Paso 12: protección de tags

gh api -X POST repos/owner/repo/tags/protection \
  -F pattern='v*.*.*'

Trampas comunes

  • El pipeline corre en cada push.
  • Force-push de tags tras release.
  • Secretos en logs CI.
  • Build desde main en push de tag.