Ogni workflow GitHub Actions che hai scritto è un file YAML. Tutto — i trigger, i job, gli step, le variabili d'ambiente, la matrix strategy — è espresso in YAML. Il che significa che capire YAML in profondità non è solo accademico: è la differenza tra una CI che funziona in modo affidabile e una CI che si rompe misteriosamente alle 16:00 di venerdì quando stai cercando di rilasciare una release.

GitHub Actions ha un'eccellente documentazione sulla sintassi dei workflow, ma si concentra sulle funzionalità di Actions piuttosto che sui meccanismi YAML sottostanti. Questo articolo copre entrambi — la struttura del workflow e i pattern YAML specifici (e le insidie) che determinano il successo o il fallimento delle configurazioni CI.

Struttura del workflow: le chiavi di primo livello

Un file workflow GitHub Actions si trova in .github/workflows/ e ha tre chiavi obbligatorie di primo livello. La panoramica ufficiale dei workflow spiega dove si trova il file nel repository e come GitHub lo scopre:

yaml
name: CI Pipeline          # optional but shown in the Actions UI

on:                        # triggers
  push:
    branches: [main]
  pull_request:

jobs:                      # the actual work
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci && npm test
Attenzione a on come booleano YAML: In YAML 1.1, la parola nuda on viene interpretata come booleano true. Il parser di GitHub gestisce correttamente questo, ma se mai vedi il tuo file workflow segnalato da un linter YAML generico, è per questo motivo. La forma sicura è quotarlo: "on": — anche se GitHub Actions stesso non richiede le virgolette.

Trigger: la chiave on:

La chiave on: controlla quando viene eseguito il workflow. La lista completa degli eventi trigger copre tutto, dalle revisioni delle pull request ai repository dispatch. Ecco i pattern più comuni:

yaml
on:
  # Push to specific branches
  push:
    branches:
      - main
      - "release/**"       # glob pattern — quotes needed for /**
    paths-ignore:
      - "docs/**"
      - "*.md"

  # PRs targeting main
  pull_request:
    branches: [main]
    types: [opened, synchronize, reopened]

  # Scheduled (cron syntax)
  schedule:
    - cron: "0 2 * * 1"   # every Monday at 2am UTC

  # Manual trigger with input
  workflow_dispatch:
    inputs:
      environment:
        description: "Target environment"
        required: true
        default: staging
        type: choice
        options: [staging, production]

Comandi run: multiriga e blocchi scalari YAML

La chiave run: è dove il blocco scalare letterale YAML (|) si dimostra indispensabile — vedi il riferimento yaml-multiline.info per ogni variante di blocchi e scalari ripiegati. Senza di esso, dovresti concatenare comandi con && su una singola riga, che è illeggibile:

yaml
steps:
  # Single line — works but hard to read
  - name: Build
    run: npm ci && npm run lint && npm run test && npm run build

  # Multi-line with literal block scalar — much better
  - name: Build
    run: |
      npm ci
      npm run lint
      npm run test -- --coverage
      npm run build

  # Folded scalar (>) joins lines with spaces — NOT what you want for shell
  # This would run as a single command with spaces where the newlines are:
  - name: Wrong for shell
    run: >
      npm ci
      npm test
Usa sempre | per gli script shell multiriga, mai >. Lo scalare ripiegato converte i newline in spazi, il che significa che i tuoi comandi shell vengono uniti in una lunga stringa. Questo causa errori criptici. Il blocco scalare letterale | preserva i newline esattamente, quindi ogni riga viene eseguita come un comando shell separato.

Variabili d'ambiente e segreti

Le variabili d'ambiente in GitHub Actions usano YAML in combinazione con la sintassi di contesto ed espressione di Actions. Ecco come si incastrano insieme:

yaml
env:
  NODE_ENV: production         # workflow-level env var
  API_VERSION: "2.1"          # quoted to force string type

jobs:
  deploy:
    runs-on: ubuntu-latest
    env:
      DEPLOY_ENV: staging      # job-level env var (overrides workflow-level)

    steps:
      - name: Deploy to staging
        env:
          API_KEY: ${{ secrets.STAGING_API_KEY }}     # step-level, from secret
          DATABASE_URL: ${{ vars.STAGING_DB_URL }}    # step-level, from variable
        run: |
          echo "Deploying to $DEPLOY_ENV"
          ./scripts/deploy.sh

La sintassi delle espressioni ${{ }} è il linguaggio template di GitHub Actions sovrapposto a YAML. Viene valutato prima del parsing YAML in alcuni contesti, il che può interagire inaspettatamente con le proprie regole di quotazione di YAML. In caso di dubbio, racchiudi i valori che iniziano con ${{ tra virgolette doppie.

Matrix strategy: build su più configurazioni

La matrix strategy è una delle funzionalità più potenti di GitHub Actions — ed è espressa interamente in YAML. Esegue il job una volta per ogni combinazione di valori della matrix:

yaml
jobs:
  test:
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false         # don't cancel other matrix jobs on failure
      matrix:
        os: [ubuntu-latest, windows-latest, macos-latest]
        node: ["18", "20", "22"]
        exclude:
          - os: windows-latest
            node: "18"         # skip this combination

    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node }}
      - run: npm ci && npm test

Questa singola definizione di job produce fino a 9 esecuzioni parallele (3 OS × 3 versioni Node, meno 1 esclusa). I valori della matrix YAML sono semplici array — l'unica cosa a cui prestare attenzione è che i numeri di versione come 18 dovrebbero essere quotati come "18" per tenerli come stringhe. Senza virgolette, YAML li analizza come interi e alcune Actions potrebbero lamentarsi.

Step condizionali con if:

La chiave if: ti permette di saltare step in base a condizioni. Usa il linguaggio delle espressioni di GitHub, non i valori YAML normali:

yaml
steps:
  - name: Run tests
    run: npm test

  - name: Upload coverage
    if: success() && github.ref == 'refs/heads/main'
    uses: codecov/codecov-action@v4

  - name: Notify on failure
    if: failure()
    uses: slackapi/slack-github-action@v1
    with:
      slack-message: "Build failed on ${{ github.ref }}"
      channel-id: "C12345ABC"
    env:
      SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}

  - name: Deploy (only on tag push)
    if: startsWith(github.ref, 'refs/tags/v')
    run: ./scripts/deploy.sh production

Workflow riutilizzabili

Per eliminare la duplicazione tra repository (non solo all'interno di un file), GitHub Actions supporta i workflow riutilizzabili. Il workflow chiamato usa on: workflow_call: e il chiamante usa uses: a livello di job — non a livello di step:

yaml
# .github/workflows/reusable-test.yml (the reusable workflow)
on:
  workflow_call:
    inputs:
      node-version:
        required: false
        type: string
        default: "20"
    secrets:
      NPM_TOKEN:
        required: true

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ inputs.node-version }}
      - run: npm ci && npm test
        env:
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
yaml
# .github/workflows/ci.yml (the caller)
on: [push, pull_request]

jobs:
  run-tests:
    uses: my-org/shared-workflows/.github/workflows/reusable-test.yml@main
    with:
      node-version: "22"
    secrets:
      NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

Gli errori YAML più comuni in GitHub Actions

  • Indentazione errata negli step. Gli step devono essere indentati sotto steps: con spazi coerenti. Un singolo spazio in più o in meno sposta uno step fuori dal suo job.
  • Numeri di versione non quotati. node-version: 20 passa un intero; alcune actions si aspettano una stringa. Usa node-version: "20" per sicurezza.
  • Uso di > invece di | per gli script shell. Gli scalari ripiegati collassano i newline. Il tuo script multiriga diventa una lunga stringa e fallisce.
  • Virgolette mancanti sui pattern glob. Pattern come release/** contengono * che YAML potrebbe interpretare come alias. Cita sempre i pattern glob.
  • Segreti usati nelle condizioni if:. GitHub maschera i segreti nei log ma non permette loro di essere usati nelle espressioni if:. Usa invece una variabile d'ambiente.
  • Dimenticare fail-fast: false nei job matrix. Per impostazione predefinita, se un job matrix fallisce, tutti gli altri vengono annullati. Di solito non è quello che vuoi durante il debug.

Conclusione

I workflow GitHub Actions sono fondamentalmente file YAML — capire i blocchi scalari letterali di YAML, le regole di quotazione e la coercizione dei tipi si traduce direttamente nella scrittura di una CI più affidabile. I fallimenti più comuni derivano da errori di indentazione, valori non quotati che vengono coerciti al tipo sbagliato e dall'uso dell'operatore sbagliato per le stringhe multiriga negli script shell. Fai quelle tre cose bene e la maggior parte del debug dei workflow diventa semplice. Usa il YAML Validator per individuare gli errori di sintassi prima del push, e il YAML Formatter per applicare un'indentazione coerente nei tuoi file workflow.