DevOps-bootcamp · Les

Shelltests uitvoeren in CI-pipelines

Integreer ShellCheck en Bats in GitHub Actions en laat elke wijziging aan de shell alleen door bij geslaagde controles.

Les 4 van 413 stappen

Shelltests uitvoeren in CI-pipelines is een gratis DevOps-bootcamp-les op CoddyKit. Dit is les 4 van 4. Je kunt 3 lessen uit dit leerpad gratis volledig lezen — daarna ontgrendelt CoddyKit PRO alle lessen, plus praktische oefeningen met een ingebouwde code-editor en een AI-tutor die 24/7 beschikbaar is. Deze les maakt deel uit van het leertraject DevOps-bootcamp. Je voortgang wordt gesynchroniseerd op het web en in de CoddyKit-app. De cursus DevOps-bootcamp bevat in totaal 4 lessen.

Waarom CI belangrijk is voor shellscripts

Shellscripts zijn code en verdienen, net als alle code, geautomatiseerde kwaliteitscontroles. Zonder CI kan een typefout in een implementatiescript ongemerkt productie bereiken en om drie uur 's nachts een storing veroorzaken.

Een degelijke CI-pijplijn voor Bash-projecten dwingt bij elke pull request twee zaken af:

  • Statische analyse via ShellCheck — detecteert syntaxisfouten, onveilige patronen en POSIX-portabiliteitsproblemen voordat het script ooit wordt uitgevoerd.
  • Eenheids- en integratietests via Bats (Bash Automated Testing System) — voert uw functies uit en controleert of ze zich correct gedragen.

Samen vormen ze een vangnet dat refactoren zonder zorgen en het inwerken van nieuwe teamleden sneller maakt. In deze les koppelt u beide hulpmiddelen aan GitHub Actions, het meestgebruikte gratis CI-platform voor opensource- en kleine teamprojecten.

Inleiding tot GitHub Actions voor shellprojecten

GitHub Actions is gebeurtenisgestuurde CI/CD die in GitHub is ingebouwd. Een werkstroom is een YAML-bestand dat onder .github/workflows/ is opgeslagen. De werkstroom wordt geactiveerd door gebeurtenissen (push, pull_request enzovoort) en voert taken uit op gehoste runners.

De belangrijkste concepten:

  • on: — de trigger (bijvoorbeeld push, pull_request)
  • jobs: — parallelle werkeenheden, elk op een nieuwe virtuele machine
  • steps: — opeenvolgende shellopdrachten of herbruikbare acties binnen een taak
  • runs-on: — de runnerimage (we gebruiken ubuntu-latest)

Werkstroombestanden moeten naar de repository worden gecommit. GitHub detecteert ze automatisch; externe configuratie is niet nodig.

# Minimal skeleton — .github/workflows/ci.yml
name: CI

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

jobs:
  shell-checks:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: echo "Steps go here"

ShellCheck installeren in een werkstroom

ShellCheck is vooraf geïnstalleerd op runners met ubuntu-latest, dus meestal hebt u helemaal geen installatiestappen nodig. De vooraf geïnstalleerde versie kan echter achterlopen op de nieuwste uitgave. Zet voor reproduceerbare builds een specifieke versie vast.

Twee installatiestrategieën:

  • Het vooraf geïnstalleerde binaire bestand gebruiken — het eenvoudigst en goed genoeg voor de meeste projecten.
  • Een vastgezette versie installeren via het officiële GitHub-release-tarball — garandeert lokaal en in CI dezelfde linterversie.

De onderstaande stap laat de vastgezette aanpak zien met een vaste versietekenreeks die als omgevingsvariabele is opgeslagen, zodat upgraden een wijziging van één regel wordt.

# .github/workflows/ci.yml  — ShellCheck install step
- name: Install ShellCheck
  env:
    SC_VERSION: v0.10.0
  run: |
    curl -sSfL \
      "https://github.com/koalaman/shellcheck/releases/download/${SC_VERSION}/shellcheck-${SC_VERSION}.linux.x86_64.tar.xz" \
      | tar -xJf - --strip-components=1 -C /usr/local/bin shellcheck-${SC_VERSION}/shellcheck
    shellcheck --version

ShellCheck op elk script uitvoeren

Na de installatie hebt u een stap nodig die alle shellscripts in de repository vindt en controleert. Gebruik find om bestanden te vinden en leid ze vervolgens door naar shellcheck.

Belangrijke opties:

  • -e SC2034 — sluit een specifieke regel uit (gebruik dit spaarzaam en met een opmerking).
  • --severity=warning — laat alleen waarschuwingen en ernstigere meldingen mislukken (suggesties over stijl worden genegeerd).
  • -x — volg source-instructies om ook ingelezen bestanden te controleren.

Als shellcheck een probleem vindt, wordt het afgesloten met een niet-nulstatus. Daardoor mislukt de CI-stap automatisch; extra logica is niet nodig.

# .github/workflows/ci.yml  — ShellCheck lint step
- name: Lint shell scripts
  run: |
    # Find all .sh files and files with a bash/sh shebang
    mapfile -t scripts < <(
      find . -type f -name '*.sh' -not -path './.git/*'
    )
    if [[ ${#scripts[@]} -eq 0 ]]; then
      echo 'No shell scripts found — skipping.'
      exit 0
    fi
    echo "Linting ${#scripts[@]} file(s)..."
    shellcheck --severity=warning -x "${scripts[@]}"

Wat is Bats en hoe werkt het?

Bats (Bash Automated Testing System) is een TAP-compatibel testframework voor Bash. Elk testbestand is een .bats-bestand met @test-blokken.

Een test slaagt als de hoofdtekst wordt afgesloten met 0 en mislukt als deze wordt afgesloten met een niet-nulstatus. Bats biedt helpervariabelen en -functies:

  • $status — de afsluitcode van de laatste opdracht met run.
  • $output — de gecombineerde stdout en stderr van de laatste opdracht met run.
  • $lines — array met uitvoerregels.
  • run <cmd> — voer een opdracht uit zonder de test te laten mislukken bij een niet-nulstatus.

De helper run is essentieel: zonder deze helper zou een mislukte opdracht de test afbreken voordat u $status kunt bekijken.

#!/usr/bin/env bats
# tests/greet.bats

setup() {
  # Runs before every @test block
  source "${BATS_TEST_DIRNAME}/../lib/greet.sh"
}

@test "greet outputs hello with the given name" {
  run greet "Alice"
  [ "$status" -eq 0 ]
  [ "$output" = "Hello, Alice!" ]
}

@test "greet fails when no argument is provided" {
  run greet
  [ "$status" -eq 1 ]
  [[ "$output" == *"Usage"* ]]
}

Bats-Core installeren via een Git-submodule

De gebruikelijke manier om Bats aan een project toe te voegen is als Git-submodule. Hiermee legt u een specifieke commit vast, blijft de versie van de runner gelijk aan die van de lokale ontwikkelomgeving en hoeft u niet op pakketbeheerders te vertrouwen.

Voer deze opdrachten eenmaal lokaal uit en commit vervolgens het resultaat:

  • git submodule add https://github.com/bats-core/bats-core test/bats
  • git submodule add https://github.com/bats-core/bats-support test/test_helper/bats-support
  • git submodule add https://github.com/bats-core/bats-assert test/test_helper/bats-assert

Herstel submodules in CI met actions/checkout@v4 en de optie submodules: recursive. De onderstaande stap toont de volledige checkoutconfiguratie.

# .github/workflows/ci.yml  — checkout with submodules
- name: Checkout repository
  uses: actions/checkout@v4
  with:
    submodules: recursive   # restores bats-core + helpers

Bats-tests uitvoeren in CI

Zodra Bats beschikbaar is (via een submodule of pakketinstallatie), voert u de tests uit met één opdracht. Geef een map op; Bats vindt vervolgens met de optie --recursive elk .bats-bestand recursief.

De optie --formatter tap produceert de TAP-indeling (Test Anything Protocol), die veel CI-systemen kunnen verwerken voor testrapportage. De standaardopmaak pretty is beter leesbaar voor mensen in onbewerkte logboeken.

Gebruik --timing om trage tests vroeg zichtbaar te maken: een test die langer dan 5 seconden duurt, wijst meestal op een ongewenste netwerkaanroep of een ontbrekende mock.

# .github/workflows/ci.yml  — Bats test step
- name: Run Bats tests
  run: |
    # If installed as a submodule:
    ./test/bats/bin/bats \
      --recursive \
      --timing \
      tests/

    # If installed via apt or brew (alternative):
    # bats --recursive --timing tests/

Een volledige werkstroom: ShellCheck + Bats

Voeg nu alles samen in één werkstroombestand dat geschikt is voor productie. Hier zijn de toegepaste best practices:

  • Twee afzonderlijke taken (lint en test) worden parallel uitgevoerd, zodat u sneller feedback krijgt.
  • De taak test declareert needs: lint, zodat tests pas worden uitgevoerd nadat de lintcontrole is geslaagd. Zo verspilt u geen runnerminuten aan duidelijk defecte code.
  • Vastgezette actieversies (@v4) voorkomen onverwachte problemen door updates van upstream.
  • Een blok permissions: beperkt het werkstroomtoken tot de minimaal vereiste rechten.
# .github/workflows/ci.yml
name: Shell CI

on:
  push:
    branches: [main]
  pull_request:

permissions:
  contents: read

jobs:
  lint:
    name: ShellCheck
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Run ShellCheck
        run: |
          mapfile -t scripts < <(find . -name '*.sh' -not -path './.git/*')
          [[ ${#scripts[@]} -gt 0 ]] && shellcheck --severity=warning -x "${scripts[@]}"

  test:
    name: Bats Tests
    runs-on: ubuntu-latest
    needs: lint
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: recursive
      - name: Run tests
        run: ./test/bats/bin/bats --recursive --timing tests/

Afhankelijkheden cachen voor snellere uitvoeringen

Wanneer Bats-helpers of andere hulpmiddelen in de werkstroom via een pakketbeheerder worden geïnstalleerd, versnelt caching volgende uitvoeringen aanzienlijk. GitHub Actions biedt hiervoor de actie actions/cache.

Belangrijke punten voor effectief cachen:

  • Gebruik een cachesleutel met daarin het besturingssysteem, de naam van het hulpmiddel en een hash van het lockbestand, zodat de cache automatisch ongeldig wordt wanneer afhankelijkheden veranderen.
  • Met een restore-keys-terugval kan de werkstroom een verouderde cache gebruiken in plaats van bij een cachemisser helemaal opnieuw te beginnen.
  • Voor Git-submodules is caching zelden nodig, omdat het ophalen van submodules snel gaat. Caching is vooral waardevol voor npm, pip of installaties van gecompileerde hulpmiddelen.
# .github/workflows/ci.yml  — cache step example
- name: Cache Bats npm helpers
  uses: actions/cache@v4
  with:
    path: ~/.npm
    key: ${{ runner.os }}-bats-${{ hashFiles('package-lock.json') }}
    restore-keys: |
      ${{ runner.os }}-bats-

- name: Install helpers
  run: npm ci  # uses cache when available

Branchbeveiliging: geslaagde controles afdwingen

Een CI-werkstroom die samenvoegingen niet blokkeert, is op zijn best adviserend. Met de regels voor branchbeveiliging van GitHub maakt u van uw controles harde poorten.

Configureer deze als volgt: ga naar Settings → Branches → Add rule voor main en schakel het volgende in:

  • Require status checks to pass before merging — selecteer ShellCheck en Bats Tests op naam.
  • Require branches to be up to date before merging — voorkomt dat een pull request die controles op een verouderde basis heeft doorstaan, defecte code toevoegt.
  • Do not allow bypassing the above settings — past de regels ook toe op repositorybeheerders.

Met deze regels is een pull request met alle groene CI-taken de enige route naar samenvoeging, precies het vangnet dat u nodig hebt.

Mislukte CI-stappen lokaal debuggen

Wanneer een CI-uitvoering mislukt, herstelt u dit het snelst door de fout lokaal te reproduceren voordat u nog een commit pusht. Twee technieken:

  • Voer de exacte opdrachten uit uit de mislukte stap in uw terminal. CI voert gewone shell uit, dus de opdrachten kunnen worden gekopieerd en opnieuw uitgevoerd.
  • Gebruik act — een hulpmiddel dat GitHub Actions-werkstromen lokaal in Docker uitvoert en daarmee de gehoste runneromgeving zo nauwkeurig mogelijk nabootst.

Een veelvoorkomende oorzaak van fouten die alleen in CI optreden, is een verschil in hulpmiddelversies tussen uw Mac (bijvoorbeeld BSD find op macOS versus GNU find op Ubuntu). Test altijd met opties van --posix of gebruik act om de Ubuntu-installatie lokaal uit te voeren.

#!/usr/bin/env bash
# run_ci_locally.sh  — mimic the CI lint step on your machine
set -euo pipefail

echo '=== ShellCheck ==='
mapfile -t scripts < <(find . -name '*.sh' -not -path './.git/*')
if [[ ${#scripts[@]} -eq 0 ]]; then
  echo 'No .sh files found.'
else
  shellcheck --severity=warning -x "${scripts[@]}"
  echo "Linted ${#scripts[@]} file(s) — OK"
fi

echo '=== Bats ==='
./test/bats/bin/bats --recursive --timing tests/

Kenniscontrole: concepten van CI-pijplijnen

Test uw begrip van het koppelen van ShellCheck en Bats aan GitHub Actions.

Samenvatting: shell-CI met ShellCheck en Bats

In deze les hebt u met GitHub Actions een volledige CI-pijplijn voor Bash-projecten gebouwd. Dit hebt u behandeld:

  • Basisprincipes van GitHub Actions — YAML voor werkstromen staat in .github/workflows/, wordt geactiveerd door push en pull_request en voert taken uit op runners met ubuntu-latest.
  • ShellCheck — vooraf geïnstalleerd op Ubuntu-runners; gebruik find om scripts te vinden en --severity=warning -x als praktische lintcontrole.
  • Bats via een submodule — zet bats-core en helpers vast als Git-submodules en herstel ze in CI met submodules: recursive bij de checkoutactie.
  • Volgorde van taken — gebruik needs: zodat tests pas worden uitgevoerd nadat de lintcontrole is geslaagd. Zo behoudt u snelle feedback en voorkomt u verspilde rekenkracht.
  • Branchbeveiliging — dwing statuscontroles af in de GitHub-instellingen, zodat geen pull request kan worden samengevoegd zonder groene CI.
  • Lokale reproductie — kopieer CI-opdrachten rechtstreeks naar uw terminal of gebruik act om fouten te debuggen zonder extra commits.

Met deze pijplijn wordt elke wijziging aan de shell automatisch gevalideerd voordat deze uw hoofdbranch raakt.

Gratis beginnen

Leer DevOps-bootcamp met een AI-tutor — gratis

Schrijf echte code en voer die uit in je browser, krijg direct hulp van een AI-tutor die 24/7 beschikbaar is en ga verder waar je gebleven bent op het web of in de app.

Cursussen
142
Lessen
568

Veelgestelde vragen

Is de les “Shelltests uitvoeren in CI-pipelines” gratis?

Ja — je kunt hier op het web alle 3 lessen van het leerpad DevOps-bootcamp, waaronder “Shelltests uitvoeren in CI-pipelines”, gratis volledig lezen. Daarna ontgrendelt CoddyKit PRO alle lessen, plus interactieve oefeningen met een ingebouwde code-editor en een AI-tutor die 24/7 beschikbaar is. De cursus DevOps-bootcamp bevat in totaal 4 lessen.

Wat leer ik in “Shelltests uitvoeren in CI-pipelines”?

Integreer ShellCheck en Bats in GitHub Actions en laat elke wijziging aan de shell alleen door bij geslaagde controles. Je oefent met DevOps-bootcamp door code rechtstreeks in de browser uit te voeren. Een AI-begeleider die 24/7 beschikbaar is beantwoordt je vragen terwijl je de les doorwerkt.

Heb ik ervaring nodig om met DevOps-bootcamp te beginnen?

Ervaring vooraf is niet nodig. DevOps-bootcamp op CoddyKit is opgebouwd voor beginners tot gevorderden, zodat je hier of bij het begin kunt starten en in je eigen tempo kunt leren. Dit is les 4 van 4.

Hoe lang duurt de les “Shelltests uitvoeren in CI-pipelines”?

De meeste lessen van CoddyKit duren ongeveer 5–10 minuten. Elke les is kort en interactief, zodat je gestaag vooruitgaat en op het web en in de app precies verdergaat waar je was gebleven.

Kan ik code schrijven en uitvoeren in deze les over DevOps-bootcamp?

Ja. Elke les over DevOps-bootcamp bevat een ingebouwde code-editor, zodat je rechtstreeks in je browser echte code kunt schrijven en uitvoeren en direct feedback van AI krijgt — lokale installatie is niet nodig.

Alle lessen in deze cursus

  1. Functies testen met Bats-core
  2. Commando's mocken en externe tools stubben
  3. Fixtures, tijdelijke omgevingen en coverage
  4. Shelltests uitvoeren in CI-pipelines
← Terug naar DevOps-bootcamp