Linux Command Line & Bash Scripting Mastery · Lekcja

Uruchamianie testów powłoki w potokach CI

Połącz ShellCheck i Bats z GitHub Actions, aby każda zmiana w skryptach powłoki przechodziła dopiero po pomyślnym sprawdzeniu.

Lekcja 4 z 413 kroki

Uruchamianie testów powłoki w potokach CI to bezpłatna lekcja Linux Command Line & Bash Scripting Mastery na CoddyKit. To lekcja 4 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Linux Command Line & Bash Scripting Mastery, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Linux Command Line & Bash Scripting Mastery zawiera 4 lekcji w sumie.

Dlaczego CI ma znaczenie w przypadku skryptów powłoki

Skrypty powłoki to kod — i podobnie jak każdy kod zasługują na automatyczne kontrole jakości. Bez CI literówka w skrypcie wdrożeniowym może niezauważenie trafić na produkcję i spowodować awarię o 3 w nocy.

Solidny potok CI dla projektów Bash wymusza dwie rzeczy przy każdym pull requeście:

  • Analizę statyczną za pomocą ShellCheck — wykrywa błędy składni, niebezpieczne wzorce i problemy z przenośnością POSIX, zanim skrypt zostanie uruchomiony.
  • Testy jednostkowe/integracyjne za pomocą Bats (Bash Automated Testing System) — wykonuje funkcje i sprawdza ich prawidłowe działanie.

Razem tworzą one siatkę bezpieczeństwa, która pozwala bez obaw refaktoryzować kod i szybciej wdrażać nowe osoby. W tej lekcji oba narzędzia zostaną zintegrowane z GitHub Actions, najpopularniejszą bezpłatną platformą CI dla projektów open source i projektów małych zespołów.

Wprowadzenie do GitHub Actions dla projektów skryptów powłoki

GitHub Actions to sterowane zdarzeniami CI/CD wbudowane w GitHub. Workflow to plik YAML przechowywany w katalogu .github/workflows/. Jest uruchamiany przez zdarzenia (push, pull_request itd.) i wykonuje zadania na hostowanych runnerach.

Najważniejsze pojęcia:

  • on: — wyzwalacz, na przykład push lub pull_request
  • jobs: — równoległe jednostki pracy, z których każda działa na nowej maszynie wirtualnej
  • steps: — sekwencyjne polecenia powłoki lub wielokrotnego użytku akcje wykonywane w ramach zadania
  • runs-on: — obraz runnera (w tym przypadku używamy ubuntu-latest)

Pliki workflow muszą zostać zatwierdzone w repozytorium. GitHub wykrywa je automatycznie — nie jest wymagana żadna zewnętrzna konfiguracja.

# 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"

Instalowanie ShellCheck w workflow

ShellCheck jest preinstalowany na runnerach ubuntu-latest, więc w większości przypadków nie trzeba wykonywać żadnych kroków instalacji. Jednak preinstalowana wersja może być starsza od najnowszego wydania. Aby zapewnić powtarzalność kompilacji, należy przypiąć konkretną wersję.

Dwie strategie instalacji:

  • Użycie preinstalowanego pliku binarnego — najprostsze rozwiązanie, wystarczające w większości projektów.
  • Instalacja przypiętej wersji za pomocą archiwum TAR z oficjalnego wydania GitHub — gwarantuje używanie tej samej wersji lintera lokalnie i w CI.

Poniższy krok pokazuje podejście z przypiętą wersją, w którym stały ciąg wersji jest przechowywany jako zmienna środowiskowa, dzięki czemu aktualizacja wymaga zmiany tylko jednej linii.

# .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

Uruchamianie ShellCheck dla każdego skryptu

Po instalacji należy dodać krok, który znajdzie i sprawdzi wszystkie skrypty powłoki w repozytorium. Należy użyć find do zlokalizowania plików, a następnie przekazać je potokiem do shellcheck.

Ważne opcje:

  • -e SC2034 — wyklucza określoną regułę (należy korzystać z tego oszczędnie i dodać komentarz).
  • --severity=warning — powoduje niepowodzenie tylko w przypadku ostrzeżeń lub poważniejszych problemów, ignorując sugestie dotyczące stylu.
  • -x — podąża za dyrektywami source, aby sprawdzać również dołączane pliki.

Jeśli shellcheck znajdzie dowolny problem, kończy działanie kodem różnym od zera, co automatycznie powoduje niepowodzenie kroku CI — nie jest potrzebna dodatkowa logika.

# .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[@]}"

Czym jest Bats i jak działa

Bats (Bash Automated Testing System) to zgodny z TAP framework testowy dla Bash. Każdy plik testowy ma rozszerzenie .bats i zawiera bloki @test.

Test kończy się powodzeniem, gdy jego ciało kończy działanie ze statusem 0, a niepowodzeniem, gdy kończy działanie ze statusem różnym od zera. Bats udostępnia zmienne i funkcje pomocnicze:

  • $status — kod zakończenia ostatniego polecenia run.
  • $output — połączone standardowe wyjście i standardowe wyjście błędów ostatniego polecenia run.
  • $lines — tablica wierszy wyjścia.
  • run <cmd> — wykonuje polecenie bez powodowania niepowodzenia testu przy zakończeniu kodem różnym od zera.

Pomocnik run jest niezbędny — bez niego nieudane polecenie przerwałoby test, zanim można byłoby sprawdzić $status.

#!/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"* ]]
}

Instalowanie Bats-Core za pomocą podmodułu Git

Standardowym sposobem dodania Bats do projektu jest użycie podmodułu Git. Przypina on konkretny commit, zapewnia identyczną wersję runnera lokalnie i w CI oraz pozwala uniknąć zależności od menedżerów pakietów.

Proszę wykonać te polecenia raz lokalnie, a następnie zatwierdzić wynik:

  • 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

W CI podmoduły należy pobrać za pomocą actions/checkout@v4 i opcji submodules: recursive. Poniższy krok przedstawia pełną konfigurację pobierania repozytorium.

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

Uruchamianie testów Bats w CI

Gdy Bats jest już dostępny (za pośrednictwem podmodułu lub instalacji pakietu), uruchomienie testów wymaga jednego polecenia. Należy wskazać katalog, a Bats znajdzie w nim rekurencyjnie każdy plik .bats dzięki opcji --recursive.

Opcja --formatter tap generuje dane w formacie TAP (Test Anything Protocol), który wiele systemów CI potrafi analizować na potrzeby raportowania testów. Domyślny formatter pretty lepiej sprawdza się przy ręcznym czytaniu surowych logów.

Opcja --timing pozwala wcześnie wykrywać wolne testy — test trwający ponad 5 sekund zwykle wskazuje na niepożądane wywołanie sieci lub brak mocka.

# .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/

Kompletny workflow: ShellCheck + Bats

Teraz połączmy wszystko w jeden gotowy do użycia produkcyjnego plik workflow. Zastosowano tu następujące dobre praktyki:

  • Dwa oddzielne zadania (lint i test) działają równolegle, zapewniając szybsze informacje zwrotne.
  • Zadanie test deklaruje needs: lint, więc testy są uruchamiane dopiero po pomyślnym lintowaniu — pozwala to uniknąć marnowania minut pracy runnera na oczywiście wadliwy kod.
  • Przypięte wersje akcji (@v4) zapobiegają nieoczekiwanym problemom spowodowanym aktualizacjami po stronie projektu źródłowego.
  • Blok permissions: ogranicza token workflow do minimalnego niezbędnego zakresu uprawnień.
# .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/

Buforowanie zależności w celu przyspieszenia uruchomień

Gdy pomocniki Bats lub inne narzędzia są instalowane za pomocą menedżera pakietów w ramach workflow, buforowanie znacznie przyspiesza kolejne uruchomienia. GitHub Actions udostępnia w tym celu akcję actions/cache.

Najważniejsze zasady skutecznego buforowania:

  • Należy używać klucza pamięci podręcznej zawierającego system operacyjny, nazwę narzędzia i skrót pliku blokady — dzięki temu pamięć podręczna jest automatycznie unieważniana po zmianie zależności.
  • Zapasowe klucze w restore-keys pozwalają workflow użyć nieaktualnej pamięci podręcznej zamiast rozpoczynać pracę od zera po braku trafienia.
  • W przypadku podmodułów Git buforowanie rzadko jest potrzebne, ponieważ ich pobieranie jest szybkie. Pamięć podręczna jest najbardziej przydatna w przypadku instalacji narzędzi npm, pip lub narzędzi kompilowanych.
# .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

Ochrona gałęzi: wymuszanie pomyślnych kontroli

Workflow CI, który nie blokuje scalania, ma najwyżej charakter doradczy. Reguły ochrony gałęzi GitHub zamieniają kontrole w rzeczywiste bramki.

Aby je skonfigurować, należy przejść do: Ustawienia → Gałęzie → Dodaj regułę dla main, a następnie włączyć:

  • Wymagaj pomyślnego przejścia kontroli przed scaleniem — wybierz kontrole ShellCheck i Bats Tests według nazw.
  • Wymagaj aktualności gałęzi przed scaleniem — zapobiega wprowadzeniu wadliwego kodu przez pull request, który przeszedł kontrole na nieaktualnej gałęzi bazowej.
  • Nie zezwalaj na omijanie powyższych ustawień — reguły obowiązują również administratorów repozytorium.

Po skonfigurowaniu tych reguł jedyną drogą do scalenia jest pull request, w którym wszystkie zadania CI zakończyły się pomyślnie — dokładnie takiej siatki bezpieczeństwa Państwo potrzebują.

Lokalne debugowanie nieudanych kroków CI

Gdy uruchomienie CI zakończy się niepowodzeniem, najszybszy cykl naprawy polega na odtworzeniu problemu lokalnie przed wysłaniem kolejnego commita. Można zastosować dwie techniki:

  • Uruchomienie dokładnych poleceń z nieudanego kroku w terminalu — CI uruchamia zwykłą powłokę, więc polecenia można odtworzyć metodą kopiuj-wklej.
  • Użycie act — narzędzia, które uruchamia workflow GitHub Actions lokalnie w Dockerze, zapewniając możliwie najwierniejsze odwzorowanie środowiska hostowanego runnera.

Częstym źródłem problemów występujących tylko w CI jest niezgodność wersji narzędzi między Makiem (na przykład BSD find w systemie macOS a GNU find w Ubuntu). Należy zawsze testować z opcjami --posix albo użyć act do lokalnego uruchomienia obrazu Ubuntu.

#!/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/

Sprawdzenie wiedzy: pojęcia związane z potokiem CI

Proszę sprawdzić swoje rozumienie integracji ShellCheck i Bats z GitHub Actions.

Podsumowanie: CI dla skryptów powłoki z ShellCheck i Bats

W tej lekcji utworzyli Państwo kompletny potok CI dla projektów Bash z użyciem GitHub Actions. Oto omówione zagadnienia:

  • Podstawy GitHub Actions — plik YAML workflow znajduje się w katalogu .github/workflows/, jest uruchamiany przez zdarzenia push i pull_request oraz wykonuje zadania na runnerach ubuntu-latest.
  • ShellCheck — jest preinstalowany na runnerach Ubuntu; należy użyć find do znalezienia skryptów oraz --severity=warning -x jako praktycznej bramki lintowania.
  • Bats za pośrednictwem podmodułu — należy przypiąć bats-core i narzędzia pomocnicze jako podmoduły Git oraz pobierać je w CI za pomocą submodules: recursive w akcji checkout.
  • Kolejność zadań — należy użyć needs:, aby testy uruchamiały się dopiero po pomyślnym lintowaniu, zapewniając szybkie informacje zwrotne i unikając marnowania zasobów obliczeniowych.
  • Ochrona gałęzi — należy wymusić kontrole statusu w ustawieniach GitHub, aby żaden pull request nie został scalony bez pomyślnego CI.
  • Lokalne odtwarzanie problemów — można kopiować polecenia CI bezpośrednio do terminalu lub użyć act do debugowania problemów bez tworzenia dodatkowych commitów.

Dzięki temu potokowi każda zmiana w skryptach powłoki jest automatycznie sprawdzana, zanim trafi do głównej gałęzi main.

Bezpłatny start

Ucz się Bash dzięki korepetycjom AI — za darmo

Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.

Kursy
22
Lekcje
88

Często zadawane pytania

Czy lekcja „Uruchamianie testów powłoki w potokach CI” jest bezpłatna?

Tak — pełny tekst „Uruchamianie testów powłoki w potokach CI” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Linux Command Line & Bash Scripting Mastery, przejdź na CoddyKit PRO. Kurs Linux Command Line & Bash Scripting Mastery zawiera 4 lekcji w sumie.

Co nauczysz się w „Uruchamianie testów powłoki w potokach CI”?

Połącz ShellCheck i Bats z GitHub Actions, aby każda zmiana w skryptach powłoki przechodziła dopiero po pomyślnym sprawdzeniu. Ćwiczysz Linux Command Line & Bash Scripting Mastery z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Linux Command Line & Bash Scripting Mastery?

Nie wymagamy żadnego doświadczenia. Linux Command Line & Bash Scripting Mastery w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 4 z 4.

Ile czasu zajmuje lekcja „Uruchamianie testów powłoki w potokach CI”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Linux Command Line & Bash Scripting Mastery?

Tak. Każda lekcja Linux Command Line & Bash Scripting Mastery zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Testowanie jednostkowe funkcji za pomocą Bats-core
  2. Mockowanie poleceń i zastępowanie narzędzi zewnętrznych
  3. Fixtures, środowiska tymczasowe i pokrycie kodu
  4. Uruchamianie testów powłoki w potokach CI
← Powrót do Linux Command Line & Bash Scripting Mastery