Da Anonimo (non verificato) , 29 Aprile 2026

Cosa otterrai

Costruirai una pipeline di release che trasforma un tag Git in un artefatto deployato — firmato, testato, versionato e pubblicato.

Il contratto

  • Pushare un tag che corrisponde a v*.*.*.
  • CI compila, testa, firma e pubblica.
  • Una release GitHub viene creata.
  • Il deployment e loggato e verificabile.

Passo 1: convenzioni tag

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

Passo 2: configurare il 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 }}

Passo 3: auto-generare release notes

      - 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

Passo 4: build matrix per release multi-platform

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*

Passo 5: artefatti firmati

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

Passo 6: release Docker image

      - 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

Passo 7: deploy dopo publish

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

Passo 8: notifica

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

Passo 9: canali 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 }}

Passo 10: integrare con release-please

Combinare bump versione automatizzato con questa pipeline.

Passo 11: taggare lo SHA negli artefatti

      - 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 }} .

Passo 12: protezione tag

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

Insidie comuni

  • La pipeline gira su ogni push.
  • Force-push di tag dopo release.
  • Segreti nei log CI.
  • Build da main su tag push.