Langsung ke Solusi: Bagaimana lint incremental dan cache berlapis mempercepat pipeline CI
Lint incremental memproses hanya berkas atau paket yang berubah, sedangkan cache artefak berlapis menjaga dependensi dan build output siap pakai. Gabungan keduanya memangkas waktu pipeline CI secara signifikan tanpa meninggalkan jaminan kualitas. Dalam artikel ini, kita akan menggabungkan skrip deteksi target berubah, cache Node/monorepo berlapis, dan cara memantau metrik terkait.
Pembanding: lint penuh vs lint incremental
Lint penuh
Lint penuh menjalankan seluruh set aturan terhadap seluruh kode, cocok untuk pengecekan awal atau release candidate. Simpel tetapi memakan waktu; setiap push harus memeriksa ribuan file bahkan jika hanya satu file yang berubah.
Lint incremental
Lint incremental mendeteksi berkas, paket, atau modul yang diubah dan menjalankan lint hanya pada area tersebut. Ini menekan durasi build karena sebagian besar pekerjaan tidak dilakukan kembali, tetapi memerlukan logika tambahan untuk menentukan target dan menghindari penerapan cache yang tidak sinkron.
Perbandingan dan trade-off
- Durasi: lint incremental biasanya 30–70% lebih cepat karena menghindari pemeriksaan redundan.
- Keandalan: lint penuh lebih aman terhadap konfigurasi lint yang berubah, sedangkan lint incremental rawan jika deteksi target berubah tidak akurat.
- Kompleksitas: lint incremental membutuhkan skrip/konfigurasi tambahan, sementara lint penuh tetap sederhana.
Menerapkan lint incremental di pipeline CI
Langkah pertama adalah menentukan target lint. Dalam monorepo atau proyek dengan beberapa paket, gunakan daftar paket yang berubah berdasarkan diff terhadap cabang utama:
CHANGED=( $(git diff --name-only origin/main...HEAD | grep -E '^packages/[^/]+/' | cut -d/ -f2 | sort -u) )Jika daftar kosong, lewati langkah lint. Jika ada, jalankan lint per paket dengan skrip seperti:
for pkg in "${CHANGED[@]}"; do
cd packages/$pkg
npm run lint
cd -
doneDalam GitHub Actions, job lint bisa terlihat seperti berikut:
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
run: npm install
- name: Deteksi paket berubah
id: targets
run: |
CHANGED=$(git diff --name-only origin/main...HEAD | grep -E '^packages/[^/]+/' | cut -d/ -f2 | sort -u)
echo "changed=$CHANGED" >> $GITHUB_OUTPUT
- name: Lint only changed packages
if: steps.targets.outputs.changed != ''
run: |
for pkg in ${{ steps.targets.outputs.changed }}; do
npm --workspace=packages/$pkg run lint
done
Langkah di atas menghindari lint jika tidak ada target berubah, sehingga lint incremental hanya berjalan saat diperlukan.
Cache artefak berlapis untuk Node atau monorepo
Cache berlapis mencakup level seperti cache package manager (npm/pnpm), node_modules per paket, dan output lint/build. Contoh cache di GitHub Actions:
- name: Cache pnpm store
uses: actions/cache@v4
with:
path: ~/.pnpm-store
key: pnpm-store-${{ hashFiles('pnpm-lock.yaml') }}
- name: Cache node_modules per paket
uses: actions/cache@v4
with:
path: |
packages/*/node_modules
key: node-modules-${{ matrix.package }}-${{ hashFiles('packages/${{ matrix.package }}/package-lock.json') }}
restore-keys: |
node-modules-${{ matrix.package }}-
node-modules-
Jika menggunakan matrix lint, pastikan setiap kombinasi paket punya key unik agar cache tidak tertukar. Cache berlapis juga berarti Anda bisa memanfaatkan restore-keys untuk mengambil artefak generik saat kunci spesifik belum ada.
Untuk GitLab CI, definisinya serupa:
cache:
key: "${CI_JOB_NAME}-${CI_COMMIT_REF_SLUG}"
paths:
- .pnpm-store/
- packages/*/node_modules/
Pastikan setiap job lint punya level cache sendiri agar tidak saling menginjeksi dependencies paketik. Cache berlapis membantu memperkecil waktu instalasi dan lint, terutama pada monorepo besar.
Memicu lint hanya pada target berubah di CI
Selain deteksi paket, penting juga memastikan CI hanya menjalankan lint jika target berubah. Ini bisa digabungkan dengan aturan file path di workflow:
- Gunakan opsi
pathspada trigger GitHub Actions untuk memicu job lint hanya saat file dalampackages/**berubah. - Tambahkan logika di job lint untuk memeriksa daftar paket yang berubah dan hentikan job jika kosong (mengembalikan status 0).
- Untuk monorepo berbasis pnpm, npm workspaces, atau lerna, gunakan CLI seperti
pnpm -r execdengan filter--filter"..."untuk mengejar paket yang terpengaruh.
Ada juga pendekatan hybrid: lint penuh dijalankan setiap malam atau di branch utama, sementara lint incremental cukup untuk merge request. Ini memastikan linting secara end-to-end tetap dijaga tanpa membebani setiap push.
Metrik dan risiko cache basi
Untuk mengevaluasi efektivitas optimasi, pantau metrik seperti:
- Durasi lint per job (sebisa mungkin bandingkan lint incremental vs lint penuh).
- Cache hit ratio dari tool CI (hit/miss), termasuk cache paket dan node_modules.
- Frekuensi job skipped karena tidak ada target berubah.
Perhatikan bahwa cache artefak bisa menjadi basi ketika dependensi berubah tanpa penggantian key. Risiko lint gagal akibat cache basi muncul ketika lint memakai rule set atau plugin yang sudah diperbarui tapi cache masih memuat versi lama. Solusinya:
- Gunakan cache key yang menggabungkan file lock (pnpm-lock.yaml/npm-shrinkwrap).
- Terapkan cache invalidation manual setelah upgrade lint tool.
- Bagikan log lint yang menunjukkan versi plugin agar mudah membandingkan ketika lint tiba-tiba gagal.
Dengan memasang warning di pipeline saat cache miss tinggi atau lint duration tak wajar, tim bisa mengidentifikasi kapan cache perlu di-refresh atau skrip lint deteksi perlu disesuaikan.
Kesimpulan
Lint incremental dan cache artefak berlapis adalah kombinasi yang efektif untuk mempercepat pipeline CI tanpa mengorbankan kualitas. Dengan mendeteksi target berubah, menjaga cache per paket, dan memantau metrik seperti durasi serta cache hit, Anda bisa menciptakan linting yang responsif dan dapat diandalkan. Selalu siapkan mekanisme invalidasi cache untuk menghindari lint gagal karena dependensi atau rule lama.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!