Menamai versi rilis secara manual rawan inkonsistensi dan kesalahan. Di episode ini kita mengotomasi semantic versioning dari commit message Conventional Commits, lalu membuat GitHub Release dengan changelog dan artifact setiap kali kode masuk ke main.

Di episode 17 kita memasang environment protection rules dan approval gateway. Semua pengamanan itu akhirnya bermuara pada satu momen penting: rilis. Menentukan versi manual seperti v1.2.3 lalu v1.2.4 sering salah hitung, tidak konsisten antar developer, dan membuat changelog menumpuk tak terkontrol. Di episode ini kita menyerahkan penomoran versi, changelog, dan pembuatan GitHub Release sepenuhnya kepada otomasi.
Di episode ini kita membahas:
SemVer memakai format MAJOR.MINOR.PATCH. Analoginya: MAJOR seperti generasi mobil — naik dari generasi 1 ke 2 bisa jadi mesinnya berubah total; MINOR seperti tambahan fitur pada generasi yang sama; PATCH seperti perbaikan kecil pada fitur yang sudah ada. Nomor ini bukan hiasan; ia memberi tahu konsumen seberapa "berbahaya" update tersebut bagi mereka.
| Komponen | Naik ketika | Contoh |
|---|---|---|
| MAJOR | Ada perubahan yang memecah API lama | 1.0.0 ke 2.0.0 |
| MINOR | Fitur baru yang backward-compatible | 1.0.0 ke 1.1.0 |
| PATCH | Perbaikan bug yang backward-compatible | 1.0.0 ke 1.0.1 |
Kalau versi salah naik, konsumen bisa kecewa. Menaikkan MAJOR tanpa alasan memaksa mereka meninjau ulang seluruh API; melewatkannya membuat upgrade diam-diam merusak aplikasi mereka.
Otomasi butuh "umpan" yang bisa dibaca mesin. Conventional Commits adalah konvensi format commit message yang mengekspos jenis perubahan lewat prefix:
| Prefix | Jenis perubahan | Dampak versi |
|---|---|---|
| feat: | Fitur baru | MINOR |
| fix: | Perbaikan bug | PATCH |
breaking change atau feat!: | Perubahan API | MAJOR |
| chore:, docs:, refactor: | Tidak mengubah perilaku | Tidak ada rilis |
Contohnya feat: tambah endpoint healthcheck, fix: perbaiki memory leak pada worker, dan feat!: ganti format response API. Karena prefix inilah yang dibaca tool versioner, disiplin commit message menjadi prasyarat mutlak. Tanpa itu pipeline akan "tuli" terhadap perubahan kode dan versi tidak pernah naik.
Tip
Pasang commit linting (misalnya commitlint) sebagai status check di pull request. Commit message yang tidak mengikuti konvensi tertahan lebih awal, sehingga otomasi versi tidak pernah menerima input yang kacau.
Dua tool yang dominan di ekosistem: release-please (dari Google) dan semantic-release (komunitas). Keduanya membaca Conventional Commits, menghitung versi berikutnya, dan menulis changelog. Perbedaannya pada gaya kerja:
| Aspek | release-please | semantic-release |
|---|---|---|
| Gaya rilis | Release PR yang menunggu review | Langsung rilis saat push main |
| Changelog | Otomatis dari commit history | Otomatis dari commit history |
| Kompleksitas | Sederhana | Fleksibel dengan banyak plugin |
| Action resmi | google-github-actions/release-please-action@v4 | Via npm semantic-release |
release-please membuka pull request berisi perubahan file CHANGELOG.md dan kenaikan versi di manifest. Setelah PR itu di-merge, ia membuat tag dan GitHub Release — manusia tetap memegang kendali kapan rilis terjadi. semantic-release sebaliknya: begitu kode masuk main, ia langsung menandai versi dan merilis. Cocok untuk tim yang ingin otomasi penuh tanpa review tambahan.
Workflow berikut dijalankan setiap push ke main. Pada push commit fitur, ia membuat atau memperbarui Release PR; pada push hasil merge Release PR, ia menerbitkan tag dan GitHub Release:
name: Release Automation
on:
push:
branches: [main]
permissions:
contents: write
pull-requests: write
jobs:
release-please:
runs-on: ubuntu-latest
steps:
- name: Jalankan release-please
uses: google-github-actions/release-please-action@v4
with:
release-type: node
token: ${{ secrets.GITHUB_TOKEN }}Yang perlu diperhatikan:
permissions: contents: write dan pull-requests: write dibutuhkan untuk membuat tag, release, dan Release PR.release-type: node menyesuaikan perilaku untuk project Node.js; tersedia juga python, go, java, dan simple.secrets.GITHUB_TOKEN, sehingga semua perubahannya teraudit sebagai bagian dari repositori.Siklus kerjanya: developer merge fitur → action membuat "chore(main): release v1.1.0" PR → tim review → PR di-merge → action mendeteksi PR rilisnya tergabung → membuat tag v1.1.0 dan GitHub Release. Hasilnya, rilis selalu didokumentasikan dan mudah ditelusuri.
Untuk binary, paket instalasi, atau aset lain, softprops/action-gh-release@v2 menempelkan file ke release. Workflow ini dipicu oleh tag berprefix v dan mengunggah hasil build:
name: Attach Release Assets
on:
push:
tags: ['v*']
permissions:
contents: write
jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Checkout kode
uses: actions/checkout@v4
- name: Build artifact
run: npm ci && npm run build
- name: Buat/update GitHub Release
uses: softprops/action-gh-release@v2
with:
files: dist/*.zip
generate_release_notes: truePenjelasan:
generate_release_notes: true membuat GitHub menyusun release notes dari commit yang digabung sejak rilis sebelumnya.files: dist/*.zip melampirkan semua file zip di folder dist; bisa juga berupa array glob.tags: ['v*'] membuat workflow ini hanya berjalan saat tag v dibuat, sehingga tidak pernah memicu rilis ganda.Pola produksi yang umum: release-please membuat tag dan release, lalu workflow bertrigger tag menempelkan artifact ke release yang sudah ada. Keduanya berjalan berurutan tanpa saling menimpa.
Warning
Jangan biarkan release dalam status draft tanpa pengawas. Workflow yang mengunggah artifact ke release yang belum dipublish akan gagal. Pastikan tahap publish eksplisit, atau set draft: true hanya pada langkah yang memang dijadwalkan untuk diselesaikan manual.
Di episode ini kita mengotomasi release management & semantic versioning:
MAJOR.MINOR.PATCH) memberi bahasa versi yang dipahami mesin dan manusia.Pipeline produksi yang baik bukan hanya berjalan mulus — ia juga harus mudah ditelusuri saat gagal. Di episode 19 kita membahas troubleshooting, debugging, dan pengembangan custom action, termasuk membuka debug logging dan masuk ke runner lewat SSH. Sampai jumpa!