Testy przechodzą u Ciebie. U kolegi nie - bo ma inną wersję Node'a. Na serwerze też nie, bo ktoś zapomniał przebudować obrazu. Każda z tych trzech sytuacji kosztuje pół dnia, a wszystkie mają wspólną przyczynę: sprawdzenie zależy od tego, kto i gdzie je uruchomił.
Continuous Integration usuwa tę zależność: to automatyczne budowanie i testowanie kodu po każdym push. Nie ręczne wdrażanie raz w tygodniu, nie monitorowanie pamięci i nie kopie zapasowe bazy - tylko jedno sprawdzenie, zawsze tak samo, na maszynie, której nikt nie skonfigurował po swojemu.
Workflow zaczyna się od wskazania zdarzeń, które go budzą:
1name: CI
2
3on:
4 push:
5 branches: [main]
6 pull_request:
uruchamia workflow przy tworzeniu pull requesta - i to jest ten moment, o który chodzi najbardziej, bo sprawdzenie odbywa się przed wejściem zmiany do gałęzi głównej.on: pull_request
on: push reaguje na wypchnięcie kodu; oba stosuje się zwykle razem. Istnieją też inne wyzwalacze, ale robią co innego: on: schedule uruchamia workflow o wyznaczonej porze, a on: deployment - przy zdarzeniu wdrożenia. Żaden z nich nie zadziała, gdy ktoś otworzy pull request.Pipeline dzieli się na joby, a ich kolejność nie jest dowolna:
Reguła porządkująca brzmi: najtańsze i najszybsze najpierw. Lint kończy się w kilka sekund, więc nie ma sensu czekać pięciu minut na testy, żeby dowiedzieć się o brakującym średniku. Kompilacja poprzedza testy, bo test nieskompilowanego kodu i tak nie ruszy. Obraz Dockera budujemy na końcu - to najdroższy krok i nie ma po co go zaczynać, jeśli cokolwiek wcześniej padło.
Każdy job składa się z kroków, a pierwszym jest zawsze pobranie kodu:
1jobs:
2 test:
3 runs-on: ubuntu-latest
4 steps:
5 - name: Checkout kodu
6 uses: actions/checkout@v4
7
8 - name: Setup Node
9 uses: actions/setup-node@v4
10 with:
11 node-version: 20
12
13 - name: Instalacja zaleznosci
14 run: yarn install --frozen-lockfile
15
16 - name: Testy
17 run: yarn test --coverageBudowa kroku jest stała:
, potem - name: Checkout kodu
, dalej uses:
. actions/checkout@v4
name to opis widoczny w interfejsie, uses wskazuje gotową akcję, a run - polecenie do wykonania w powłoce.Kolejność w jobie testowym też jest niezmienna:
pobiera kod, actions/checkout@v4
instaluje Node'a, actions/setup-node@v4
wciąga zależności, a na końcu yarn install --frozen-lockfile
uruchamia testy.yarn test --coverage
Flaga
--frozen-lockfile zasługuje na uwagę: każe zainstalować dokładnie wersje z pliku blokady i przerwać, gdyby się nie zgadzały. Bez niej pipeline mógłby cicho zainstalować nowszą wersję zależności i przetestować coś innego, niż uruchomisz na produkcji.Pipeline potrzebuje haseł - do rejestru obrazów, do serwera, do bazy testowej. Przechowujemy je w Settings > Secrets and variables > Actions, w ustawieniach repozytorium.
Nie w pliku
.env w repozytorium, nie w komentarzu do commita, nie w README.md - wszystkie te miejsca są publiczne dla każdego, kto ma dostęp do kodu, a historii Gita nie da się tak po prostu wyczyścić.Zapisany sekret wstawiasz do workflow przez odwołanie, nigdy wprost:
1 - name: Logowanie do rejestru
2 run: docker login -u ${{ secrets.REGISTRY_USER }} -p ${{ secrets.REGISTRY_TOKEN }}Wartość zostanie podstawiona przy uruchomieniu, a w logach pojawi się w postaci zamaskowanej.
Na koniec trzy rzeczy, które odróżniają pipeline działający od pipeline'u, na który da się czekać.
Matrix uruchamia ten sam job na kilku konfiguracjach naraz:
1 strategy:
2 matrix:
3 node-version: [18, 20, 22]Trzy wersje Node'a, trzy równoległe przebiegi, jeden opis. To odpowiedź na problem z początku lekcji - „u kolegi nie działa" wychodzi teraz przy pull requeście, a nie po tygodniu.
Cache zapamiętuje pobrane zależności między przebiegami. Bez niego każdy przebieg ściąga te same paczki od nowa; z nim instalacja skraca się z minut do sekund.
Artifacts to pliki, które job zostawia po sobie - raport pokrycia, zbudowana paczka, zrzuty ekranu z testów. Przeżywają zakończenie przebiegu i można je pobrać z interfejsu, co bywa jedynym sposobem, by zrozumieć, dlaczego coś padło tylko na maszynie CI, @name.
Sprawdzenie przestało zależeć od tego, kto je uruchamia:
on: pull_request uruchamia workflow przy tworzeniu pull requesta; on: schedule działa o wyznaczonej porze, on: deployment przy wdrożeniu,- name:, potem uses:, potem nazwa akcji; run: wykonuje polecenie powłoki,actions/checkout@v4, actions/setup-node@v4, yarn install --frozen-lockfile, yarn test --coverage,--frozen-lockfile instaluje dokładnie wersje z pliku blokady i przerywa przy niezgodności,.env, nie w komentarzu, nie w README.md,W następnej lekcji zejdziemy z poziomu liczb do pojedynczego żądania - poznasz distributed tracing. A na razie zapamiętaj: pipeline to jedno sprawdzenie, wykonywane zawsze tak samo - a matrix sprawia, że „u mnie działa" przestaje być argumentem.