Configura l'integrazione continua


Configurare l'integrazione continua (CI) per il tuo track è molto importante: aiuta a individuare gli errori.

GitHub Actions

I repository di Exercism (compresi quelli dei track) usano GitHub Actions per eseguire la loro CI. GitHub Actions si basa sui workflow, che definiscono gli script da eseguire automaticamente ogni volta che si verifica un evento specifico (ad esempio il push di un commit). Per ulteriori informazioni sui workflow di GitHub Actions, consulta la documentazione sui workflow.

Workflow preinstallati

I track arrivano con diversi workflow già installati, e la maggior parte di essi non va modificata (si chiamano workflow condivisi). C'è però un workflow che dovresti modificare: il workflow test.yml.

Il workflow dei test

L'obiettivo del workflow test.yml è verificare che gli esercizi del track siano in buono stato. Il workflow è configurato per essere eseguito automaticamente (nella terminologia di GitHub Actions: viene attivato) quando si fa push sul branch main o sul branch di una pull request.

Il workflow in sé non deve fare molto, se non:

  • Eseguire il checkout del codice (già implementato)
  • Installare le dipendenze (ad esempio installare i pacchetti, opzionale)
  • Installare gli strumenti (ad esempio installare un SDK, opzionale)
  • Eseguire lo script di verifica degli esercizi (già implementato)

Implementa lo script di verifica degli esercizi

Come accennato, gli esercizi vengono verificati tramite uno script, precisamente lo script bin/verify-exercises (bash). Questo script è quasi pronto e fa quanto segue:

  • Itera su tutte le directory degli esercizi
  • Per ogni directory di esercizio, poi:
    • Copia la soluzione di esempio/esemplare nei file della soluzione (stub) (già implementato)
    • Chiama la funzione unskip_tests, in cui puoi riattivare i test nei tuoi file di test (opzionale)
    • Chiama la funzione run_tests, in cui dovresti eseguire i test (obbligatorio)

Le funzioni run_tests e unskip_tests sono le uniche cose che devi implementare.

Riattivare i test

Se il tuo track prevede la possibilità di saltare i test, dobbiamo assicurarci che nessun test venga saltato durante la verifica della soluzione di esempio/esemplare di un esercizio. In generale, i track supportano la «riattivazione» dei test in due modi:

  1. Rimuovere annotazioni/codice/testo dai file di test. Ad esempio, cambiando test.skip in test.
  2. Fornire una variabile d'ambiente. Ad esempio, impostando SKIP_TESTS=false.

Rimuovere annotazioni/codice/testo dai file di test

Se saltare i test si basa sui file (la prima opzione menzionata sopra), modifica la funzione unskip_tests per modificare i file di test (il codice esistente gestisce già l'iterazione sui file di test).

Note

La funzione unskip_test viene eseguita su una copia della directory di un esercizio, quindi sentiti libero di modificare i file come preferisci.

Esempio

Il bin/verify-exercises file del track Arturo usa sed per riattivare i test all'interno dei file di test:

unskip_tests() {
    jq -r '.files.test[]' .meta/config.json | while read -r test_file; do
        sed -i 's/test.skip/test/g' "${test_file}"
    done
}

Fornire una variabile d'ambiente

Caution

Se la riattivazione dei test richiede che sia impostata una variabile d'ambiente, assicurati che venga impostata nella funzione run_tests.

Eseguire i test

La funzione run_tests si occupa di eseguire i test di un esercizio. Quando la funzione viene chiamata, i file di esempio/esemplare sono già stati copiati nei file della soluzione (stub), quindi devi solo chiamare il comando giusto per eseguire i test.

La funzione deve restituire zero come codice di uscita se tutti i test passano, altrimenti deve restituire un codice di uscita diverso da zero.

Note

La funzione run_tests viene eseguita su una copia della directory di un esercizio, quindi sentiti libero di modificare i file come preferisci.

Opzione 1: usare gli strumenti del linguaggio

L'opzione predefinita per lo script di verifica degli esercizi è usare gli strumenti del linguaggio (SDK/binario/ecc.), ed è quella che usa la maggior parte dei track. Ogni track avrà il proprio modo di eseguire i test, ma di solito si tratta di un solo comando.

Esempio

Il bin/verify-exercises file del track Arturo modifica la funzione run_tests per chiamare semplicemente il comando arturo sul file di test:

run_tests() {
    arturo tester.art
}

Opzione 2: usare l'immagine Docker del test runner

La seconda opzione consiste nel verificare gli esercizi eseguendo il test runner del track. Questo, naturalmente, richiede che il track abbia un test runner funzionante.

Se il tuo track non ha ancora un test runner, puoi:

  • creare un test runner funzionante, oppure
  • usare l'opzione 1 e utilizzare direttamente gli strumenti del linguaggio

Bisogna apportare le seguenti modifiche allo script bin/verify-exercises predefinito:

  1. Verificare che il comando docker sia disponibile
  2. Eseguire il pull (scaricare) dell'immagine Docker del test runner
  3. Usare docker run per eseguire l'immagine Docker del test runner su ogni esercizio
  4. Usare jq per verificare che il file results.json restituito dal container Docker indichi che tutti i test sono passati
  5. Rimuovere la funzione unskip_test e la chiamata a quella funzione
Note

Il vantaggio principale di questo approccio è che imita al meglio il modo in cui i test vengono eseguiti in produzione (sul sito web). Con questo approccio, è meno probabile che in produzione fallisca qualcosa che era passato nella CI. Lo svantaggio è che di solito è più lento, perché bisogna scaricare l'immagine Docker e c'è l'overhead di Docker.

Esempio

Il bin/verify-exercises file del track Unison aggiunge il controllo per verificare che sia installato anche il comando docker:

required_tool docker

Poi scarica l'immagine del test runner del track:

docker pull exercism/unison-test-runner

Poi modifica la funzione run_tests per usare docker run ed eseguire il test runner sull'esercizio corrente (che si trova nella directory di lavoro), seguito da un comando jq per controllare che lo stato sia quello giusto:

run_tests() {
    local slug

    slug="${1}"

    docker run \
        --rm \
        --network none \
        --mount type=bind,src="${PWD}",dst=/solution \
        --mount type=bind,src="${PWD}",dst=/output \
        --tmpfs /tmp:rw \
        exercism/unison-test-runner "${slug}" "/solution" "/output"
    jq -e '.status == "pass"' "${PWD}/results.json" >/dev/null 2>&1
}

Infine, dobbiamo modificare la chiamata al comando run_tests, perché ora richiede lo slug:

run_tests "${slug}"

Implementa il workflow dei test

Ora che lo script verify-exercises è pronto, è il momento di completare il workflow test.yml. Come farlo dipende dall'opzione scelta per l'implementazione dello script verify-exercises.

Opzione 1: usare gli strumenti del linguaggio

Se lo script verify-exercises usa direttamente gli strumenti del linguaggio, il workflow dei test dovrà installare:

  • Le dipendenze degli strumenti del linguaggio, come openssh o un compilatore C/C++.
  • Gli strumenti del linguaggio, come un SDK o un binario. Se l'installazione degli strumenti del linguaggio non aggiunge il binario o i binari installati al path, assicurati di aggiungerlo al percorso di sistema di GitHub Actions.

Una volta fatto questo, verify-exercises dovrebbe funzionare come previsto, e avrai configurato la CI con successo!

Per un esempio, guarda il workflow test.yml del track Arturo:

name: Test

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

jobs:
  ci:
    runs-on: ubuntu-22.04

    steps:
      - name: Checkout repository
        uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332

      - name: Install dependencies
        run: |
          sudo apt-get update
          sudo apt-get install libgtk-3-dev libwebkit2gtk-4.0-dev libmpfr-dev

      - name: Install Arturo
        run: bin/install-arturo
        env:
          GH_TOKEN: ${{ github.token }}

      - name: Verify all exercises
        run: bin/verify-exercises

Opzione 2: usare l'immagine Docker del test runner

La seconda opzione consiste nel verificare gli esercizi eseguendo il test runner del track. Questa opzione richiede due condizioni:

  1. Il track ha un test runner funzionante
  2. Lo script verify-exercises usa l'immagine Docker del test runner per eseguire i test di un esercizio

Se il tuo track non ha ancora un test runner, puoi:

  • creare un test runner funzionante, oppure
  • usare l'opzione 1 e utilizzare direttamente gli strumenti del linguaggio

Questo approccio ha un paio di vantaggi:

  1. Non devi installare dipendenze/strumenti nel workflow dei test (perché saranno già stati installati nell'immagine Docker)
  2. L'approccio imita al meglio il modo in cui i test vengono eseguiti in produzione (sul sito web), riducendo la probabilità di problemi in produzione.

Lo svantaggio principale è che probabilmente è più lento, perché bisogna scaricare l'immagine Docker e c'è l'overhead di Docker.

Ci sono un paio di modi per scaricare l'immagine Docker del test runner:

  1. Scaricare l'immagine all'interno del file verify-exercises. Questo è l'approccio usato dal track Unison.
  2. Scaricare l'immagine all'interno del workflow. Questo è l'approccio usato dal track Standard ML.
  3. Costruire l'immagine all'interno del workflow. Questo è l'approccio usato dal track 8th.

Allora quale approccio usare? Consigliamo di implementare almeno l'opzione numero 1, per rendere lo script verify-exercises autonomo. Se la tua immagine è particolarmente grande, potrebbe essere utile implementare anche l'opzione 3, che archivia l'immagine Docker costruita nella cache di GitHub Actions. Le esecuzioni successive potranno così leggere l'immagine Docker dalla cache invece di scaricarla, il che potrebbe essere meglio per le prestazioni (misura per averne la certezza).

Opzione 3: eseguire lo script di verifica degli esercizi dentro l'immagine Docker del test runner

Una terza opzione, alternativa, è un ibrido delle due precedenti. Anche qui usiamo l'immagine Docker del test runner, solo che stavolta eseguiamo lo script verify-exercises dentro quell'immagine Docker. Per abilitare questa opzione, dobbiamo impostare il container del workflow sul test runner:

container:
  image: exercism/vimscript-test-runner

Possiamo poi saltare i passaggi di installazione delle dipendenze e degli strumenti (perché saranno già stati installati nell'immagine Docker del test runner) e passare all'esecuzione dello script bin/verify-exercises.

Esempio

Il workflow test.yml del track vimscript usa questa opzione:

name: Verify Exercises

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

jobs:
  ci:
    runs-on: ubuntu-24.04
    container:
      image: exercism/vimscript-test-runner

    steps:
      - name: Checkout repository
        uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332

      - name: Verify all exercises
        run: bin/verify-exercises