cat swift/ci-base-package-swift.md

Lezione 46 45 min

CI di base per package Swift

Una CI minimale deve costruire, testare e controllare lo stile del package, rendendo riproducibile la qualità.

CI significa Continuous Integration. Nel nostro contesto: ogni modifica deve poter essere verificata automaticamente.

Per un package Swift, una CI base dovrebbe fare almeno:

  • checkout del codice;
  • installazione/selezione Swift;
  • swift build;
  • swift test;
  • controllo formattazione/lint;
  • eventualmente generazione documentazione.

Perché serve

Sul tuo computer tutto può sembrare a posto. In CI scopri:

  • file non committati;
  • dipendenze non risolte;
  • test che dipendono dall’ambiente;
  • differenze tra piattaforme;
  • comandi non documentati;
  • warning diventati errori.

La CI è memoria condivisa del progetto.

Comandi minimi

swift build
swift test

Se questi due comandi non funzionano da terminale, il package non è davvero sano.

GitHub Actions esempio

name: Swift

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

jobs:
  build:
    runs-on: macos-15

    steps:
      - uses: actions/checkout@v4

      - name: Build
        run: swift build

      - name: Test
        run: swift test

Questo è volutamente minimale.

Versione Swift e runner

La CI deve dichiarare chiaramente dove gira.

Per progetti Apple-oriented, macos-15 è una scelta pratica per avere toolchain e SDK Apple. Per package puri, ubuntu-latest può essere utile per verificare portabilità.

Non dare per scontato che “compila sul mio Mac” significhi “compila ovunque”. Se il package dichiara supporto Linux, testalo in CI.

Matrix

Per package cross-platform puoi testare su più ambienti:

strategy:
  matrix:
    os: [macos-15, ubuntu-latest]

runs-on: ${{ matrix.os }}

Non introdurre matrix troppo presto se rallenta il feedback senza bisogno. Ma per librerie pubbliche, testare più piattaforme è importante.

Esempio completo:

jobs:
  build:
    strategy:
      matrix:
        os: [macos-15, ubuntu-latest]

    runs-on: ${{ matrix.os }}

    steps:
      - uses: actions/checkout@v4
      - run: swift build
      - run: swift test

Se un target dipende da SwiftUI o SDK Apple, potrebbe non compilare su Linux. In quel caso separa i target portabili da quelli platform-specific.

Cache

La cache può velocizzare build, ma non partire da lì. Prima rendi la CI corretta. Poi ottimizza.

Una cache sbagliata può nascondere problemi o complicare la pipeline. Aggiungila quando:

  • build e test sono già stabili;
  • i tempi sono davvero un problema;
  • sai cosa stai cachando;
  • puoi invalidarla facilmente.

Lint e format

Aggiungi un passaggio:

- name: Lint
  run: swift format lint --recursive Sources Tests

Oppure il comando del linter scelto.

Il comando deve essere lo stesso documentato nel README.

Documentazione in CI

Per package pubblici, puoi aggiungere:

- name: Generate documentation
  run: swift package generate-documentation

Se la documentazione rompe, vuoi scoprirlo prima del rilascio.

Segreti

I test unitari non dovrebbero richiedere segreti.

Se una suite ha bisogno di token API, probabilmente è una suite di integrazione e va separata:

Unit tests
  sempre su PR, senza segreti

Integration tests
  manuali o schedulati, con ambiente controllato

Non bloccare ogni PR perché un servizio esterno è lento o non disponibile.

Test non deterministici

La CI espone test fragili:

  • dipendono dall’ordine;
  • dipendono dal tempo;
  • dipendono dalla rete reale;
  • dipendono dal locale;
  • falliscono sotto carico.

I test unitari dovrebbero evitare rete reale. Usa fake e fixture.

Checklist CI

Una CI base dovrebbe:

  • partire su PR;
  • partire su main;
  • eseguire swift build;
  • eseguire swift test;
  • controllare stile;
  • usare comandi documentati;
  • non dipendere da segreti per test unitari;
  • fallire in modo leggibile.

Output leggibile

Una CI fallita deve aiutare a correggere.

Evita script enormi in una sola riga. Meglio step separati:

- name: Build
  run: swift build

- name: Test
  run: swift test

Quando fallisce, sai subito dove guardare.

Esercizio

Crea .github/workflows/swift.yml per CouponKit con:

  • trigger su push e pull request;
  • build;
  • test;
  • lint opzionale;
  • generazione documentazione opzionale.

Poi aggiungi nel README una sezione “Development” con gli stessi comandi.