A folyamatos integráció beállítása


Nagyon fontos, hogy a kurzusodhoz beállítsd a folyamatos integrációt (CI), mert segít kiszűrni a hibákat.

GitHub Actions

Az Exercism tárolói (köztük a kurzusok tárolói is) a GitHub Actions segítségével futtatják a CI-jukat. A GitHub Actions workflow-kon alapul, amelyek meghatározzák, milyen szkriptek fussanak automatikusan, valahányszor egy adott esemény bekövetkezik (például egy commit pusholása). A GitHub Actions workflow-król további információt a workflow-k dokumentációjában találsz.

Előre telepített workflow-k

A kurzusokhoz számos workflow előre telepítve van, amelyek többségét nem szabad módosítanod (ezeket megosztott workflow-knak nevezik). Van azonban egy workflow, amelyet módosítanod kell: a test.yml workflow.

A teszt workflow

A test.yml workflow célja, hogy ellenőrizze, rendben vannak-e a kurzus feladatai. A workflow úgy van beállítva, hogy automatikusan lefusson (a GitHub Actions terminológiája szerint: kiváltódik), amikor push történik a main ágra vagy egy pull request ágára.

Magának a workflow-nak nem sok mindent kell tennie, csak a következőket:

  • A kód checkoutolása (már implementálva)
  • A függőségek telepítése (például csomagok telepítése, opcionális)
  • A tooling telepítése (például egy SDK telepítése, opcionális)
  • A feladatokat ellenőrző szkript futtatása (már implementálva)

A feladatokat ellenőrző szkript implementálása

Ahogy már említettük, a feladatokat egy szkript ellenőrzi, mégpedig a bin/verify-exercises (bash) szkript. Ez a szkript majdnem kész, és a következőket teszi:

  • Végigmegy az összes feladatkönyvtáron
  • Minden feladatkönyvtárnál ezután:
    • Átmásolja az example/exemplar megoldást a (stub) megoldásfájlokba (már implementálva)
    • Meghívja az unskip_tests függvényt, amelyben megszüntetheted a tesztek kihagyását a tesztfájljaidban (opcionális)
    • Meghívja a run_tests függvényt, amelyben futtatnod kell a teszteket (kötelező)

A run_tests és az unskip_tests függvény az egyetlen, amit implementálnod kell.

A tesztek kihagyásának megszüntetése

Ha a kurzusod támogatja a tesztek kihagyását, biztosítanunk kell, hogy egy feladat example/exemplar megoldásának ellenőrzésekor egyetlen teszt se legyen kihagyva. Általánosságban kétféleképpen támogatják a kurzusok a tesztek »kihagyásának megszüntetését«:

  1. Eltávolítják a megjegyzéseket/kódot/szöveget a tesztfájlokból. Például a test.skip szót test-re cserélik.
  2. Beállítanak egy környezeti változót. Például a SKIP_TESTS=false értéket adják meg.

Megjegyzések/kód/szöveg eltávolítása a tesztfájlokból

Ha a tesztek kihagyása fájlalapú (a fent említett első lehetőség), szerkeszd az unskip_tests függvényt úgy, hogy módosítsa a tesztfájlokat (a meglévő kód már kezeli a tesztfájlokon való végigiterálást).

Note

Az unskip_test függvény egy feladatkönyvtár másolatán fut, így nyugodtan módosítsd a fájlokat, ahogy jónak látod.

Példa

Az Arturo kurzus bin/verify-exercises file a sed segítségével szünteti meg a tesztek kihagyását a tesztfájlokban:

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
}

Környezeti változó megadása

Caution

Ha a tesztek kihagyásának megszüntetéséhez környezeti változót kell beállítani, győződj meg róla, hogy az a run_tests függvényben be van állítva.

Tesztek futtatása

A run_tests függvény felelős egy feladat tesztjeinek futtatásáért. Amikor a függvény meghívódik, az example/exemplar fájlok már át lettek másolva a (stub) megoldásfájlokba, így csak a megfelelő parancsot kell meghívnod a tesztek futtatásához.

A függvénynek nullát kell visszaadnia kilépési kódként, ha minden teszt sikeres, ellenkező esetben nullától eltérő kilépési kódot kell visszaadnia.

Note

A run_tests függvény egy feladatkönyvtár másolatán fut, így nyugodtan módosítsd a fájlokat, ahogy jónak látod.

1. lehetőség: a nyelvhez tartozó tooling használata

A feladatokat ellenőrző szkript alapértelmezett lehetősége a nyelvhez tartozó tooling (SDK/bináris fájl/stb.) használata, és a legtöbb kurzus ezt választja. Minden kurzusnak megvan a maga módja a tesztek futtatására, de általában ez csak egyetlen parancs.

Példa

Az Arturo kurzus bin/verify-exercises file úgy módosítja a run_tests függvényt, hogy egyszerűen meghívja az arturo parancsot a tesztfájlon:

run_tests() {
    arturo tester.art
}

2. lehetőség: a tesztfuttató Docker-image használata

A második lehetőség, hogy a feladatokat a kurzus tesztfuttatójának futtatásával ellenőrizzük. Ez persze attól függ, hogy a kurzusnak van-e működő tesztfuttatója.

Ha a kurzusodnak még nincs tesztfuttatója, választhatsz:

  • építesz egy működő tesztfuttatót, vagy
  • az 1. lehetőséget választod, és közvetlenül a nyelvhez tartozó toolingot használod

A következő módosításokat kell elvégezni az alapértelmezett bin/verify-exercises szkripten:

  1. Ellenőrizd, hogy a docker parancs elérhető-e
  2. Töltsd le (pull) a tesztfuttató Docker-image-et
  3. A docker run segítségével futtasd a tesztfuttató Docker-image-et minden feladaton
  4. A jq segítségével ellenőrizd, hogy a Docker-konténer által visszaadott results.json fájl minden teszt sikerességét jelzi-e
  5. Távolítsd el az unskip_test függvényt és annak meghívását
Note

Ennek a megközelítésnek a fő előnye, hogy ez utánozza legjobban, ahogy a tesztek élesben (a weboldalon) futnak. Ezzel a megközelítéssel kevésbé valószínű, hogy olyan dolgok hibáznak élesben, amelyek a CI-ben átmentek. A hátránya, hogy általában lassabb, mert le kell tölteni a Docker-image-et, és a Dockernek is van többletterhelése.

Példa

Az Unison kurzus bin/verify-exercises file hozzáadja az ellenőrzést, amellyel meggyőződhet arról, hogy a docker parancs is telepítve van:

required_tool docker

Ezután lehúzza a kurzus tesztfuttató image-ét:

docker pull exercism/unison-test-runner

Ezután módosítja a run_tests függvényt, hogy a docker run segítségével futtassa a tesztfuttatót az aktuális feladaton (amely a munkakönyvtárban van), majd egy jq paranccsal ellenőrzi a megfelelő státuszt:

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
}

Végül módosítanunk kell a run_tests parancs hívását, mert az most már megköveteli a slugot:

run_tests "${slug}"

A teszt workflow implementálása

Most, hogy a verify-exercises szkript elkészült, ideje véglegesíteni a test.yml workflow-t. Az, hogy ezt hogyan tegyük, attól függ, melyik lehetőséget választottad a verify-exercises szkript implementálásához.

1. lehetőség: a nyelvhez tartozó tooling használata

Ha a verify-exercises szkript közvetlenül a nyelvhez tartozó toolingot használja, a teszt workflow-nak telepítenie kell:

  • A nyelvhez tartozó tooling függőségeit, például az openssh-t vagy egy C/C++ fordítót.
  • A nyelvhez tartozó toolingot, például egy SDK-t vagy bináris fájlt. Ha a nyelvhez tartozó tooling telepítése nem adja hozzá a telepített bináris fájlt/fájlokat a path-hoz, mindenképp add hozzá a GitHub Actions rendszerútvonalához.

Ha ez megvan, a verify-exercises a várt módon fog működni, és sikeresen beállítottad a CI-t!

Példáért nézd meg az Arturo kurzus test.yml workflow-ját:

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

2. lehetőség: a tesztfuttató Docker-image használata

A második lehetőség, hogy a feladatokat a kurzus tesztfuttatójának futtatásával ellenőrizzük. Ez a lehetőség két dolgot feltételez:

  1. A kurzusnak van működő tesztfuttatója
  2. A verify-exercises szkript a tesztfuttató Docker-image-et használja egy feladat tesztjeinek futtatásához

Ha a kurzusodnak még nincs tesztfuttatója, választhatsz:

  • építesz egy működő tesztfuttatót, vagy
  • az 1. lehetőséget választod, és közvetlenül a nyelvhez tartozó toolingot használod

Ennek a megközelítésnek néhány előnye van:

  1. A teszt workflow-ban nem kell semmilyen függőséget/toolingot telepítened (azok ugyanis már telepítve lesznek a Docker-image-ben)
  2. Ez a megközelítés utánozza legjobban, ahogy a tesztek élesben (a weboldalon) futnak, csökkentve az éles hibák valószínűségét.

A fő hátránya, hogy valószínűleg lassabb, mert le kell tölteni a Docker-image-et, és a Dockernek is van többletterhelése.

Néhány módon húzhatod le a tesztfuttató Docker-image-et:

  1. Töltsd le az image-et a verify-exercises fájlból. Ezt a megközelítést választja az Unison kurzus.
  2. Töltsd le az image-et a workflow-n belül. Ezt a megközelítést választja a Standard ML kurzus.
  3. Építsd fel az image-et a workflow-n belül. Ezt a megközelítést választja a 8th kurzus.

Szóval melyik megközelítést érdemes választani? Azt javasoljuk, hogy legalább az 1. lehetőséget valósítsd meg, hogy a verify-exercises szkript önálló legyen. Ha az image különösen nagy, hasznos lehet a 3. lehetőséget is megvalósítani, amely a felépített Docker-image-et a GitHub Actions gyorsítótárában tárolja. A későbbi futások ezután egyszerűen beolvassák a Docker-image-et a gyorsítótárból a letöltés helyett, ami jobb lehet a teljesítmény szempontjából (mindenképp mérd meg, hogy biztos legyél benne).

3. lehetőség: a feladatokat ellenőrző szkript futtatása a tesztfuttató Docker-image-en belül

Egy harmadik, alternatív lehetőség az előző kettő hibridje. Itt szintén a tesztfuttató Docker-image-et használjuk, csak ezúttal a verify-exercises szkriptet azon a Docker-image-en belül futtatjuk. Ennek a lehetőségnek az engedélyezéséhez a workflow konténerét a tesztfuttatóra kell állítanunk:

container:
  image: exercism/vimscript-test-runner

Ezután kihagyhatjuk a függőségek és a tooling telepítésének lépéseit (azok ugyanis már telepítve lesznek a tesztfuttató Docker-image-ben), és nekiláthatunk a bin/verify-exercises szkript futtatásának.

Példa

A vimscript kurzus test.yml workflow-ja ezt a lehetőséget használja:

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