CI pipeline adalah rangkaian pemeriksaan yang dijalankan otomatis tiap ada push atau pull request: lint, test, lalu E2E. Gak ada lagi "lupa jalanin test sebelum merge". Bayangin pabrik roti dengan tiga pos pemeriksaan berurutan: timbang adonan, cek kematangan, cek kemasan. Roti yang gagal di pos pertama gak perlu dibawa ke pos berikutnya, dan gak ada roti yang boleh keluar pabrik sebelum lulus semuanya.
🧪 Tebakan cepat: workflow-nya punya tiga job berurutan:
lint,test, lalue2e. Joblintgagal. Jobe2etetap jalan atau gak? Tebak dulu, jawabannya ada di bagian "Urutan job dengan needs".
Workflow GitHub Actions
GitHub Actions membaca file YAML di folder .github/workflows/. Satu file adalah satu workflow.
# .github/workflows/ci.yml
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 24
cache: npm
- run: npm ci
- run: npm run lint
test:
needs: lint
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
node-version: [22, 24]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: npm
- run: npm ci
- run: npx vitest run --coverage
e2e:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 24
cache: npm
- run: npm ci
- run: npx playwright install --with-deps
- run: npx playwright test
jobsberisi job: kumpulan langkah yang jalan di satu mesin baru (runs-on: ubuntu-latest). Tiap job mulai dari mesin kosong, jadi tiap job mengambil kode dan memasang dependency sendiri.stepsadalah langkahnya, berurutan.usesmemakai action buatan orang lain:actions/checkoutmengambil kode repo-mu,actions/setup-nodememasang Node.runmenjalankan perintah terminal.cache: npmmenyimpan cache unduhan npm antar-run, jadinpm ciberikutnya lebih cepat.- Satu step gagal (perintahnya keluar dengan exit code selain 0), job-nya berhenti dan ditandai gagal.
Kapan workflow jalan
Bagian on menentukan event yang memicu workflow:
pushdenganbranches: [main]: jalan tiap ada commit yang di-push kemain.pull_requestdenganbranches: [main]: jalan tiap ada PR kemaindibuka, dan tiap kali PR itu dapat commit baru.- Push ke branch
fitur-xyang belum punya PR gak memicu apa pun, karenafitur-xbukanmain. Begitu PR darifitur-xkemaindibuka, push berikutnya kefitur-xmemicupull_request.
Urutan job dengan needs
Tanpa needs, semua job jalan bersamaan. needs: lint artinya test menunggu lint lulus dulu, dan needs: test artinya e2e menunggu semua job test.
| Yang rusak | lint | test (22) | test (24) | e2e |
|---|---|---|---|---|
| gak ada | lulus | lulus | lulus | lulus |
| variabel gak terpakai | gagal | skipped | skipped | skipped |
| test ongkir gagal | lulus | gagal | gagal | skipped |
RegExp.escape dipakai |
lulus | gagal | lulus | skipped |
Kalau lint gagal, job yang bergantung padanya gak jalan sama sekali, statusnya skipped. Jadi e2e gak jalan. Itu jawaban tebakannya. Inilah fail fast: pemeriksaan yang murah dan cepat ditaruh di depan, supaya E2E yang lama gak membuang waktu untuk kode yang jelas-jelas rusak.
Ini log job lint saat ada variabel yang gak terpakai:
Run npm run lint
> [email protected] lint
> eslint .
/home/runner/work/toko/toko/src/ongkir.js
3:9 error 'diskon' is assigned a value but never used no-unused-vars
✖ 1 problem (1 error, 0 warnings)
Error: Process completed with exit code 1.
Baca dari bawah ke atas: exit code 1 artinya perintahnya gagal, dan di atasnya ada alasannya, lengkap dengan file, baris 3, dan kolom 9.
Matrix: satu job, beberapa versi
strategy.matrix menjalankan job yang sama untuk tiap kombinasi nilai, paralel. node-version: [22, 24] menghasilkan dua job, test (22) dan test (24). Dua daftar, misalnya 3 OS dan 2 versi Node, menghasilkan 3 × 2 = 6 job.
Gunanya terlihat waktu kodemu memakai fitur baru. RegExp.escape baru ada di Node 24, jadi job di Node 22 gagal:
FAIL src/cari.test.js > sorot kata yang dicari
TypeError: RegExp.escape is not a function
Di laptopmu yang memakai Node 24 semuanya hijau. Tanpa matrix, server yang masih Node 22 baru ketahuan rusak setelah deploy. fail-fast: false membuat semua kombinasi tetap jalan sampai selesai. Defaultnya true, dan GitHub membatalkan job matrix lain begitu satu gagal.
Branch protection: PR gak bisa di-merge sebelum hijau
Workflow cuma memberi tanda merah atau hijau. Supaya PR yang merah benar-benar gak bisa di-merge, pasang branch protection rule untuk main: buka Settings, lalu Branches (atau Rules, lalu Rulesets), aktifkan Require status checks to pass before merging, lalu pilih check yang wajib, misalnya lint, test (22), test (24), dan e2e. Setelah itu tombol merge terkunci sampai semuanya lulus.
⚠️ Jebakan yang sering ketemu
- Workflow tanpa branch protection. Check-nya merah, tapi tombol merge tetap bisa diklik. CI baru jadi penjaga kalau check-nya diwajibkan.
- Semua job jalan bersamaan. Tanpa
needs, E2E yang lama tetap jalan walau lint sudah gagal. Taruh yang murah di depan. - Cuma tes di satu versi. "Di laptopku jalan" gak berarti jalan di Node yang dipakai server. Pakai matrix untuk versi yang benar-benar kamu dukung.
- Push ke branch yang gak ada di
on. Workflow-nya gak jalan sama sekali, dan gak ada yang memperingatkan.
TL;DR: CI pipeline menjalankan pemeriksaan otomatis tiap push atau PR. Di GitHub Actions, workflow ditulis di .github/workflows/*.yml: on menentukan kapan jalan (push dan pull_request ke main), jobs berisi job dengan steps (uses untuk action, run untuk perintah). needs mengurutkan job, dan job yang bergantung pada job gagal jadi skipped (fail fast). strategy.matrix menjalankan job yang sama di beberapa versi atau OS secara paralel, misalnya Node 22 dan 24. Pasang branch protection rule dengan "Require status checks to pass before merging" supaya PR gak bisa di-merge sebelum check-nya hijau.