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.
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ładpushlubpull_requestjobs:— równoległe jednostki pracy, z których każda działa na nowej maszynie wirtualnejsteps:— sekwencyjne polecenia powłoki lub wielokrotnego użytku akcje wykonywane w ramach zadaniaruns-on:— obraz runnera (w tym przypadku używamyubuntu-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 --versionUruchamianie 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 dyrektywamisource, 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 poleceniarun.$output— połączone standardowe wyjście i standardowe wyjście błędów ostatniego poleceniarun.$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/batsgit submodule add https://github.com/bats-core/bats-support test/test_helper/bats-supportgit 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 + helpersUruchamianie 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 (
lintitest) działają równolegle, zapewniając szybsze informacje zwrotne. - Zadanie
testdeklarujeneeds: 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-keyspozwalają 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,piplub 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 availableOchrona 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 runnerachubuntu-latest. - ShellCheck — jest preinstalowany na runnerach Ubuntu; należy użyć
finddo znalezienia skryptów oraz--severity=warning -xjako 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: recursivew 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ć
actdo 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.
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
- Testowanie jednostkowe funkcji za pomocą Bats-core
- Mockowanie poleceń i zastępowanie narzędzi zewnętrznych
- Fixtures, środowiska tymczasowe i pokrycie kodu
- Uruchamianie testów powłoki w potokach CI