GitHub Actions menjalankan otomatisasi langsung dari repository, tanpa perlu menyiapkan server CI terpisah. Untuk proyek yang sudah ada di GitHub, ini jalur paling pendek dari βkode masukβ ke βkode terpasang di productionβ.
Apa itu CI/CD?
Continuous Integration berarti setiap perubahan yang masuk otomatis dibangun dan diuji. Tujuannya menemukan kesalahan dalam hitungan menit, bukan saat rilis. Nilai CI datang dari disiplin: kalau test-nya tidak dipercaya atau sering gagal tanpa sebab jelas, orang akan mulai mengabaikannya dan CI jadi sekadar hiasan.
Continuous Deployment berarti perubahan yang lolos pengujian otomatis dipasang ke production. Ada juga istilah Continuous Delivery, yang berhenti satu langkah sebelumnya: artefak siap dipasang, tapi penekanan tombol terakhir tetap manual.
Anatomi Workflow
Workflow adalah file YAML di .github/workflows/. Strukturnya bertingkat:
- Trigger menentukan kapan workflow jalan
- Job adalah unit yang berjalan di satu mesin virtual, dan antar job bisa paralel
- Step adalah perintah berurutan di dalam satu job
- Action adalah langkah siap pakai yang dibuat orang lain
Contoh pipeline untuk membangun dan memasang situs statis ke GitHub Pages:
name: Deploy
on:
push:
branches: [main]
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: pages
cancel-in-progress: true
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
- name: Build
run: npm run build
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: ./dist
deploy:
needs: build
runs-on: ubuntu-latest
environment:
name: github-pages
steps:
- uses: actions/deploy-pages@v4
Ada beberapa hal di file itu yang layak dibahas satu per satu.
Batasi Izin Token
Setiap workflow menerima GITHUB_TOKEN otomatis. Secara bawaan token ini bisa punya izin tulis ke banyak hal di repository. Kalau ada dependensi yang disusupi, token itu jadi celah yang nyaman.
Blok permissions di atas menurunkan izin ke tingkat paling minim yang dibutuhkan. Kebiasaan yang baik adalah menuliskan permissions secara eksplisit di setiap workflow, dan memberi izin tulis hanya pada job yang benar-benar membutuhkannya.
Caching Dependensi
Baris cache: 'npm' pada setup-node menyimpan cache npm antar jalannya workflow. Untuk proyek dengan dependensi banyak, ini memangkas waktu install dari menit menjadi detik.
Kalau butuh cache untuk hal lain, actions/cache bisa dipakai langsung:
- uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: playwright-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
Kunci cache sebaiknya mengandung hash dari file lock. Dengan begitu cache otomatis kedaluwarsa saat dependensi berubah, dan Anda tidak akan tertipu cache basi.
Concurrency
Tanpa pengaturan concurrency, dorongan berturut-turut ke main akan menjalankan beberapa deploy sekaligus, dan urutan selesainya tidak dijamin. Deploy lama bisa menimpa deploy baru.
Blok concurrency dengan cancel-in-progress: true membatalkan workflow lama begitu ada yang baru. Untuk pipeline deploy, ini hampir selalu yang Anda inginkan.
Matrix untuk Menguji Banyak Versi
Kalau library Anda harus jalan di beberapa versi Node, matrix menjalankan job yang sama untuk tiap kombinasi:
jobs:
test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
node: [18, 20, 22]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
cache: 'npm'
- run: npm ci
- run: npm test
fail-fast: false membuat kegagalan di satu versi tidak langsung membatalkan yang lain. Tanpa itu, Anda hanya tahu satu versi yang bermasalah padahal mungkin ada tiga.
Secret dan Variable
Secret disimpan di pengaturan repository dan nilainya tersamarkan di log. Variable dipakai untuk nilai yang tidak rahasia, misalnya nama environment.
- name: Deploy
env:
API_TOKEN: ${{ secrets.API_TOKEN }}
REGION: ${{ vars.DEPLOY_REGION }}
run: ./deploy.sh
Dua hal yang perlu diingat. Pertama, penyamaran log tidak sempurna. Kalau secret Anda olah, misalnya di-encode base64 lalu dicetak, nilainya bisa bocor utuh. Kedua, workflow yang dipicu pull_request dari fork tidak mendapat akses ke secret, dan itu memang disengaja demi keamanan.
Pisahkan Pipeline Test dan Deploy
Satu pola yang membuat pipeline terasa jauh lebih tenang adalah memisahkan dua workflow. Workflow test berjalan pada setiap pull request dan setiap dorongan. Workflow deploy hanya berjalan pada main, dan mensyaratkan test sudah lulus.
Dengan pemisahan ini, kontributor mendapat umpan balik cepat tanpa pernah menyentuh kredensial production.
Jebakan yang Sering Ditemui
Menyematkan action tanpa versi. Menulis uses: some/action@main berarti Anda menjalankan apa pun yang ada di branch itu hari ini. Untuk action pihak ketiga, sematkan ke tag rilis, atau kalau ingin lebih ketat, ke commit SHA.
Memakai npm install alih-alih npm ci. Yang pertama bisa memutakhirkan dependensi secara diam-diam, sehingga CI menguji sesuatu yang berbeda dari isi lock file.
Test yang bergantung pada urutan atau waktu. Runner CI lebih lambat dan lebih paralel daripada laptop. Test yang mengandalkan sleep atau urutan file akan gagal secara acak, dan test yang gagal secara acak lebih buruk daripada tidak ada test, karena melatih tim untuk mengabaikan lampu merah.
Pipeline yang terlalu lama. Kalau butuh dua puluh menit untuk tahu sebuah perubahan aman, orang akan berhenti menunggu. Paralelkan job, cache yang bisa di-cache, dan pindahkan pengujian berat ke jadwal malam.
Tidak pernah menguji jalur rollback. Pipeline yang hanya bisa maju akan terasa menakutkan saat ada yang salah. Pastikan Anda tahu persis cara kembali ke versi sebelumnya sebelum benar-benar membutuhkannya.
Menjalankan Terjadwal
Selain saat ada perubahan kode, workflow bisa dijalankan berkala. Berguna untuk pemeriksaan dependensi atau pembaruan data:
on:
schedule:
- cron: '0 2 * * 1' # Setiap Senin pukul 02:00 UTC
workflow_dispatch: # Sekaligus bisa dipicu manual
workflow_dispatch sebaiknya selalu ditambahkan pada workflow terjadwal. Saat ada yang perlu diperiksa, Anda tidak ingin menunggu sampai Senin berikutnya.