Checki w PR, które mają sens — shift-left bez szumu
Szybki feedback na pull requestach przyspiesza delivery. Naucz się projektować checki PR, które łapią prawdziwe problemy wcześnie, używać filtrów ścieżek do pomijania nieistotnych checków i.
Ten post to część 5 serii Jakość w CI/CD. Część 4 omawiała raporty i triage niepowodzeń — czynienie niepowodzeń CI możliwymi do działania.
Wprowadzenie — shift-left dotyczy szybkości, nie objętości
“Shift-left” oznacza łapanie problemów wcześniej w cyklu developmentu. Im wcześniej znajdziesz defekt, tym taniej jest go naprawić.
Ale shift-left to nie “uruchom każdy check na każdym PR”. Tak dostajesz:
- 20-minutowe uruchomienia CI, które blokują merge’e
- Developerów czekających na przejście niezwiązanych checków
- Fałszywe pozytywne z checków, które nie dotyczą zmienionego kodu
Mądre checki PR są szybkie, istotne i blokujące tylko gdy konieczne.
Ten post omawia, jak projektować checki PR, które dostarczają szybki feedback bez tworzenia wąskich gardeł, używać filtrów ścieżek do pomijania nieistotnych checków i równoważyć wymagane vs. opcjonalne checki.
Szybki feedback vs. wolne suity
Cel checków PR to szybki feedback. Jeśli developer czeka 20 minut na CI, przełącza kontekst na inne zadanie. Gdy CI się kończy, już się przełączył.
Docelowe czasy CI
| Typ checku | Docelowy czas | Cel |
|---|---|---|
| Lint | < 30 sekund | Łap naruszenia stylu |
| Build | < 2 minuty | Upewnij się, że kod się kompiluje |
| Testy jednostkowe | < 3 minuty | Waliduj logikę biznesową |
| Testy smoke | < 5 minut | Łap krytyczne regresje |
| Pełna suita E2E | 10–20 minut | Kompleksowa walidacja (uruchom post-merge) |
Zasada: Blokuj merge’e na szybkich checkach (< 5 minut). Uruchamiaj wolne suity post-merge lub według harmonogramu.
:::warning[Reguła 5 minut] Jeśli Twoje wymagane checki PR trwają dłużej niż 5 minut, developerzy zaczną je omijać. Szybki feedback utrzymuje CI zaufanym. :::
Filtry ścieżek — uruchamiaj tylko istotne checki
Nie każdy PR potrzebuje każdego checku. Jeśli zmieniasz dokumentację, nie musisz uruchamiać testów E2E.
GitHub Actions wspiera filtry ścieżek do wyzwalania workflow tylko gdy konkretne pliki się zmieniają.
Przykład: pomiń testy E2E dla zmian w docs
name: E2E Tests
on:
pull_request:
paths:
- 'src/**'
- 'tests/**'
- 'package.json'
- 'playwright.config.ts'
jobs:
e2e:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npx playwright install --with-deps chromium
- run: npm run test:e2e
Rezultat: Testy E2E uruchamiają się tylko gdy zmienia się src/, tests/ lub config testowy. PR-y z docsami całkowicie pomijają ten workflow.
Przykład: oddzielne workflow dla frontendu i backendu
# .github/workflows/frontend-ci.yml
name: Frontend CI
on:
pull_request:
paths:
- 'frontend/**'
- 'package.json'
jobs:
frontend-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm test
# .github/workflows/backend-ci.yml
name: Backend CI
on:
pull_request:
paths:
- 'backend/**'
- 'requirements.txt'
jobs:
backend-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: pip install -r requirements.txt
- run: pytest
Rezultat: Zmiany frontendu uruchamiają tylko testy frontendowe. Zmiany backendu uruchamiają tylko testy backendowe. Żadnych zmarnowanych minut CI.
:::tip[Łączenie filtrów ścieżek]
Użyj paths-ignore do wykluczenia konkretnych plików. Przykład: paths-ignore: ['docs/**', '*.md'] pomija workflow dla zmian w dokumentacji.
:::
Wymagane vs. opcjonalne checki
GitHub pozwala oznaczyć konkretne checki jako wymagane przed merge’em PR.
Repository Settings → Branches → Branch protection rules → Require status checks to pass before merging
Rekomendowane wymagane checki
✅ Build — kod musi się kompilować
✅ Lint — styl kodu musi przejść
✅ Testy jednostkowe — logika biznesowa musi być poprawna
✅ Testy smoke — krytyczne ścieżki muszą działać
Rekomendowane opcjonalne checki
ℹ️ Pełna suita E2E — informacyjne; niepowodzenia badane post-merge
ℹ️ Raport coverage — trendy śledzone; brak twardego progu
ℹ️ Benchmarki wydajności — regresje flagowane, ale nie blokowane
Uzasadnienie: Wymagane checki są szybkie, deterministyczne i blokują oczywiste defekty. Opcjonalne checki dostarczają kontekst bez blokowania delivery.
Checki warunkowe bazujące na labelach
Użyj labeli GitHub do wyzwalania opcjonalnych checków na żądanie.
Przykład: uruchom pełną suitę E2E gdy oznaczona
name: Full E2E (On-Demand)
on:
pull_request:
types: [labeled]
jobs:
e2e-full:
if: contains(github.event.pull_request.labels.*.name, 'run-e2e-full')
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npx playwright install --with-deps
- run: npm run test:e2e
Użycie: Dodaj label run-e2e-full do PR, aby wywołać pełną suitę E2E. Usuń label, aby ją pominąć.
Dlaczego to działa: Pełne suity E2E są wolne. Uruchamiaj je tylko gdy potrzebne — zmiany wysokiego ryzyka, walidacja przed release lub badanie regresji.
Failowanie szybko — zatrzymaj przy pierwszym niepowodzeniu
Jeśli build failuje, nie ma sensu uruchamiać testów. Jeśli lint failuje, nie ma sensu uruchamiać E2E.
Użyj zależności jobów do szybkiego failowania.
Przykład: sekwencyjne checki z zależnościami
name: CI
on: [pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm run build
lint:
runs-on: ubuntu-latest
needs: build
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm run lint
unit-tests:
runs-on: ubuntu-latest
needs: build
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm test
smoke-tests:
runs-on: ubuntu-latest
needs: [build, lint, unit-tests]
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npx playwright install --with-deps chromium
- run: npm run test:e2e:smoke
Przepływ:
builduruchamia się pierwszy- Jeśli
buildsię powiedzie,lintiunit-testsuruchamiają się równolegle - Jeśli wszystkie się powiodą,
smoke-testssię uruchamia - Jeśli jakikolwiek job failuje, zależne joby są pomijane
Rezultat: Szybkie niepowodzenie. Jeśli build failuje w 1 minutę, CI zatrzymuje się natychmiast. Brak zmarnowanego czasu na uruchamianie testów przeciwko zepsutemu kodowi.
Praktyczny przykład — zoptymalizowane checki PR
Połącz filtry ścieżek, wymagane checki, opcjonalne checki i szybkie failowanie.
name: PR Checks
on:
pull_request:
paths:
- 'src/**'
- 'tests/**'
- 'package.json'
- 'playwright.config.ts'
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- run: npm ci
- run: npm run build
lint:
runs-on: ubuntu-latest
needs: build
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- run: npm ci
- run: npm run lint
unit-tests:
runs-on: ubuntu-latest
needs: build
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- run: npm ci
- run: npm test
smoke-tests:
runs-on: ubuntu-latest
needs: [build, lint, unit-tests]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- run: npm ci
- run: npx playwright install --with-deps chromium
- run: npm run test:e2e:smoke
- name: Upload report
if: always()
uses: actions/upload-artifact@v4
with:
name: smoke-test-report
path: playwright-report/
e2e-full:
if: contains(github.event.pull_request.labels.*.name, 'run-e2e-full')
runs-on: ubuntu-latest
needs: [build, lint, unit-tests]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- run: npm ci
- run: npx playwright install --with-deps
- run: npm run test:e2e
- name: Upload report
if: always()
uses: actions/upload-artifact@v4
with:
name: e2e-full-report
path: playwright-report/
Funkcje:
- Filtry ścieżek pomijają workflow dla zmian w docs
builduruchamia się pierwszy; inne joby od niego zależąsmoke-testsjest wymagany i wykonuje się w < 5 minute2e-fulljest opcjonalny i uruchamia się tylko gdy oznaczony- Wszystkie raporty uploadowane jako artefakty
Typowy PR: 3–4 minuty do zakończenia wymaganych checków. Pełne E2E uruchamia się tylko gdy jawnie zażądane.
Auto-merge dla zaufanych PR-ów
Dla PR-ów niskiego ryzyka (aktualizacje zależności, automatyczne refactory) włącz auto-merge, gdy wszystkie checki przejdą.
Auto-merge Dependabota
name: Auto-Merge Dependabot
on:
pull_request_target:
jobs:
auto-merge:
if: github.actor == 'dependabot[bot]'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Enable auto-merge
run: gh pr merge --auto --squash "${{ github.event.pull_request.html_url }}"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Rezultat: PR-y Dependabota auto-merge’ują się, gdy wszystkie checki przejdą. Brak manualnej akceptacji wymaganej dla aktualizacji zależności niskiego ryzyka.
:::warning[Kwestia bezpieczeństwa] Auto-merge’uj PR-y tylko ze zaufanych źródeł (Dependabot, renovate). Nigdy nie auto-merge’uj PR-ów zewnętrznych kontrybutorów bez review. :::
Podsumowanie — szybkie, istotne, zaufane
Checki PR są pierwszą linią jakości. Łapią problemy przed merge, dostarczają szybki feedback i utrzymują stabilność głównego brancha.
Zasady:
- Uruchamiaj szybkie checki (< 5 minut) jako wymagane checki
- Używaj filtrów ścieżek do pomijania nieistotnych workflow
- Failuj szybko z zależnościami jobów
- Rób wolne suity opcjonalnymi lub wyzwalanymi labelem
- Auto-merge’uj zaufane PR-y aby zmniejszyć manualne obciążenie
Gdy checki PR są szybkie i istotne, developerzy im ufają. Gdy developerzy ufają CI, wysyłają szybciej.
Zadanie na ten tydzień: Zmierz P50 i P95 czasów dla swoich checków PR. Jeśli P95 > 10 minut, zidentyfikuj najwolniejszy job i albo go zoptymalizuj, przenieś do post-merge, albo zrób opcjonalnym.
Dalej w tej serii: Część 6 — Continuous testing w continuous delivery