Rantai npm run ci yang kita rangkai pada Chapter Konsistensi Gaya Kode hanya bermanfaat bila dijalankan — dan mengandalkan setiap orang untuk menjalankannya secara sukarela adalah keandalan semu. Continuous Integration (CI) memindahkan rantai itu ke server: setiap usulan perubahan diperiksa otomatis, jauh sebelum menyentuh cabang utama, dan setiap hasil tercatat untuk semua orang. Continuous Delivery (CD) menambahkan langkah berikutnya — mengemas dan menyebar versi yang lolos. Chapter penutup section ini membangun workflow GitHub Actions untuk proyek Node.js: memicu pemeriksaan, menjalankan rantai yang sama dengan yang kita jalankan lokal, dan memperluasnya menuju penyebaran.
Pipeline sebagai Penjaga Gerbang #
Mekanisme dasarnya sejajar dengan yang sudah kita kenal. Rantai lokal memakai exit code: npm run lint && npm test berhenti di kegagalan pertama, dan exit code 1 memberi tahu terminal bahwa sesuatu gagal. Pipeline memakai bahasa yang sama persis — sebuah langkah dikatakan gagal bila perintahnya keluar dengan kode selain nol — hanya saja konsekuensinya lebih tegas: usulan perubahan ditandai merah dan penggabungan tertahan sampai hijau. Karena itu aturan emasnya sederhana: perintah yang dijalankan pipeline harus identik dengan perintah yang kita jalankan sendiri, agar “hijau di laptop” dan “hijau di pipeline” bermakna sama.
Berkas Workflow #
GitHub Actions membaca konfigurasi dari folder .github/workflows/ di dalam repo. Satu berkas YAML adalah satu workflow; inilah versi terkecil yang bermakna untuk proyek kita:
name: CI
on:
push:
branches: [main]
pull_request:
jobs:
uji:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with:
node-version: 24
- run: npm ci
- run: npm run lint
- run: npm testAnatomi berkasnya — panduan lengkapnya ada di dokumentasi tentang workflow :
name: CI: nama yang tampil di halaman status dan pada tiap eksekusi; bebas kita pilih.on:: pemicu workflow.pushkemainmemeriksa setiap perubahan yang mendarat,pull_requestmemeriksa setiap usulan sebelum digabungkan — dua arah yang sama pentingnya.jobs:: kumpulan pekerjaan; setiap job berjalan di mesin virtual segar yang saling terpisah. Jobujikita hanya satu.runs-on: ubuntu-latest: sistem operasi mesin virtual — untuk aplikasi Node.js pilihan ini nyaris selalu cukup.steps:dengan dua jenis langkah:usesmemakai action siap pakai,runmenjalankan perintah shell apa adanya.
Tiga langkah pertama adalah persiapan standar: actions/checkout
menyalin isi repo ke mesin virtual, actions/setup-node
memasang Node.js versi yang kita minta, dan npm ci memasang dependencies persis seperti package-lock.json — bukan versi yang “kira-kiras cocok”, melainkan salinan bit per bit dari yang kita uji lokal. Tiga langkah terakhir adalah rantai gerbang yang sudah akrab: lint, lalu test, masing-masing satu langkah agar kegagalan terbaca jelas di mana letaknya.
Langkah Uji di Mata Pipeline #
Apa yang dilihat pipeline saat langkah npm test berjalan? Persis keluaran yang kita lihat lokal — runner tidak melakukan trick khusus, ia hanya menjalankan perintah di mesin bersih. Kita bisa meniru pengalamannya dengan modul kecil beserta test-nya:
export function susunCatatanRilis(versi, daftarPerubahan) {
if (daftarPerubahan.length === 0) {
return `## ${versi}\n\n- perbaikan internal tanpa perubahan perilaku`;
}
const butir = daftarPerubahan.map((p) => `- ${p}`).join('\n');
return `## ${versi}\n\n${butir}`;
}import { test } from 'node:test';
import assert from 'node:assert';
import { susunCatatanRilis } from './pelacak-rilis.mjs';
test('menyusun catatan rilis dari daftar perubahan', () => {
const hasil = susunCatatanRilis('v1.2.0', ['menambah rute /kesehatan']);
assert.strictEqual(hasil, '## v1.2.0\n\n- menambah rute /kesehatan');
});
test('daftar kosong menghasilkan catatan bawaan', () => {
const hasil = susunCatatanRilis('v1.2.1', []);
assert.match(hasil, /perbaikan internal/);
});Inilah perintah yang ditulis pipeline pada langkah npm test, dijalankan dari folder proyek yang sama:
node --test
echo "kode keluar: $?"Output yang Dihasilkan:
✔ menyusun catatan rilis dari daftar perubahan
✔ daftar kosong menghasilkan catatan bawaan
ℹ tests 2
ℹ suites 0
ℹ pass 2
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
kode keluar: 0Dua tanda centang, ringkasan pass 2 fail 0, dan exit code 0 — bahasa yang oleh pipeline diterjemahkan menjadi tanda hijau pada langkah tersebut. Runner juga menyimpan seluruh keluaran ini sebagai log yang bisa dibuka kapan saja, sehingga kegagalan yang terjadi di mesin virtual bisa diselidiki tanpa memasang ulang apa pun di laptop kita.
Matriks: Menguji Beberapa Versi Sekaligus #
Kekuatan pipeline mulai terasa ketika satu pekerjaan dikalikan. Dengan strategy.matrix, pemeriksaan yang sama berjalan untuk setiap kombinasi yang kita daftarkan — misalnya dua versi Node.js:
jobs:
uji:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [22, 24]
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm run lint
- run: npm testEkspresi ${{ matrix.node-version }} mengambil nilai dari matriks untuk eksekusi yang sedang berjalan — dua eksekusi, dua versi, dua laporan terpisah di halaman yang sama. Pola ini menjawab pertanyaan yang sulit dijawab lokal: “apakah kode kita tetap sehat pada versi LTS sebelumnya?” — pertanyaan penting bagi package yang dipakai orang lain, dan murah untuk dijawab begitu matriksnya tertulis.
Dari CI ke CD #
Continuous delivery menambahkan job kedua yang hanya berjalan setelah yang pertama hijau:
terbitkan:
needs: uji
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with:
node-version: 24
- run: npm ci
- run: npm publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}Dua hal baru di sini. Kunci needs: uji menyatakan ketergantungan antar job — terbitkan menunggu uji tuntas dengan sukses; syarat if memastikannya hanya terjadi pada cabang utama, bukan pada setiap pull request. Lalu ${{ secrets.NPM_TOKEN }}: token penerbitan dibaca dari penyimpanan rahasia repo, bukan ditulis di berkas — penerapan langsung prinsip Chapter Manajemen Secret. Rahasia yang tersimpan begitu tidak pernah muncul di log maupun pada salinan repo milik siapa pun. Untuk penyebaran ke server, polanya sama — hanya langkah terakhirnya yang berbeda: membangun image Docker seperti chapter sebelumnya, atau menjalankan git pull dan memuat ulang process manager melalui SSH.
Dengan ini rangkaian operasional kita tertutup penuh: aplikasi yang siap ditempatkan, dikonfigurasi, dimatikan dengan teratur, dipantau lewat log dan metrik — dan kini dijaga oleh pipeline yang memastikan setiap perubahan melewati gerbang yang sama. Section berikutnya mengangkat topik yang membuat semua kode tersebut lebih kokoh sejak ditulis: TypeScript, dimulai dari alasan memakainya.