Proses rilis manual rentan terhadap inkonsistensi penomoran versi (SemVer), catatan rilis (changelog) yang terlewat, dan kesalahan pembuatan Git tag. Mengotomatisasi siklus ini menghilangkan friksi operasional dan menjaga integritas repositori. Semantic-release mengotomatiskan seluruh alur kerja rilis: menentukan nomor versi berikutnya, membuat catatan rilis, mempublikasikan artefak, dan membuat tag Git secara deterministik berdasarkan pesan commit.

Prinsip Semantic Versioning dan Conventional Commits

Semantic-release bekerja dengan menganalisis riwayat Git commit sejak tag rilis terakhir. Standar yang digunakan mengacu pada Conventional Commits untuk memetakan pesan commit secara langsung ke aturan Semantic Versioning (SemVer):

  • fix: Memperbaiki bug dalam kode (menghasilkan kenaikan versi PATCH, misal: 1.0.0 ke 1.0.1).
  • feat: Menambahkan fitur baru yang backwards-compatible (menghasilkan kenaikan versi MINOR, misal: 1.0.0 ke 1.1.0).
  • BREAKING CHANGE: Perubahan yang merusak kompatibilitas ke belakang, dinyatakan melalui footer commit BREAKING CHANGE: atau tanda seru setelah tipe/scope seperti feat!: (menghasilkan kenaikan versi MAJOR, misal: 1.0.0 ke 2.0.0).
  • Tipe lain seperti docs:, chore:, refactor:, style:, atau test: secara default diabaikan dari penentuan rilis versi baru.

Instalasi Dependensi dan Konfigurasi Plugin

Semantic-release menggunakan arsitektur berbasis plugin. Untuk alur kerja rilis standar pada proyek Node.js atau repositori generik, instal paket-paket berikut sebagai devDependencies:

npm install --save-dev semantic-release \
  @semantic-release/commit-analyzer \
  @semantic-release/release-notes-generator \
  @semantic-release/changelog \
  @semantic-release/git \
  @semantic-release/github

Konfigurasi urutan plugin sangat penting karena output dari satu plugin menjadi input bagi plugin berikutnya. Buat file konfigurasi .releaserc.json pada root repositori:

{
  "branches": [
    "main"
  ],
  "plugins": [
    "@semantic-release/commit-analyzer",
    "@semantic-release/release-notes-generator",
    [
      "@semantic-release/changelog",
      {
        "changelogFile": "CHANGELOG.md"
      }
    ],
    [
      "@semantic-release/npm",
      {
        "npmPublish": false
      }
    ],
    [
      "@semantic-release/git",
      {
        "assets": [
          "CHANGELOG.md",
          "package.json",
          "package-lock.json"
        ],
        "message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
      }
    ],
    "@semantic-release/github"
  ]
}

Jika repositori bukan paket npm publik, set npmPublish: false pada @semantic-release/npm agar plugin hanya memperbarui field versi pada package.json tanpa mencoba mengunggah artefak ke npm registry. Plugin @semantic-release/git bertugas melakukan commit kembali file changelog dan manifes ke branch utama dengan penanda [skip ci] untuk menghindari loop eksekusi tak terbatas.

Konfigurasi Workflow GitHub Actions

Semantic-release memerlukan akses tulis ke repositori untuk membuat commit, membuat tag, dan merilis GitHub Release. Gunakan GITHUB_TOKEN bawaan GitHub Actions dengan mengatur izin (permissions) secara eksplisit.

Buat file workflow pada .github/workflows/release.yml:

name: Release

on:
  push:
    branches:
      - main

permissions:
  contents: write
  issues: write
  pull-requests: write

jobs:
  release:
    name: Run Semantic Release
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
          persist-credentials: false

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'npm'

      - name: Install Dependencies
        run: npm ci

      - name: Execute Semantic Release
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: npx semantic-release

Penting: Parameter fetch-depth: 0 pada actions/checkout wajib disertakan. Semantic-release memerlukan riwayat commit dan Git tag lengkap untuk menghitung perbedaan commit sejak rilis sebelumnya. Jika diatur ke nilai default (1), semantic-release gagal mendeteksi tag lama dan berisiko salah menentukan versi rilis berikutnya.

Strategi Validasi Melalui Dry-Run

Sebelum menggabungkan (merge) Pull Request ke branch main, pipeline pengujian sebaiknya memverifikasi apakah format commit valid dan perubahan versi yang dihasilkan sesuai ekspektasi tanpa memicu rilis nyata.

Tambahkan job atau workflow terpisah untuk Pull Request dengan flag --dry-run:

name: Release Dry Run

on:
  pull_request:
    branches:
      - main

jobs:
  dry-run:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'npm'

      - name: Install Dependencies
        run: npm ci

      - name: Dry Run Semantic Release
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: npx semantic-release --dry-run

Flag --dry-run mencetak kalkulasi versi dan changelog ke stdout GitHub Actions runner tanpa memodifikasi Git history, membuat tag, atau mempublikasikan rilis.

Troubleshooting dan Masalah Umum

  • Branch Protection Rule Block: Jika branch main diproteksi dan memerlukan signed commit atau pull request review sebelum push, commit rilis dari @semantic-release/git yang menggunakan GITHUB_TOKEN standar akan ditolak (HTTP 403). Solusinya: gunakan GitHub App token dengan izin tulis bypass branch protection, atau hindari commit balik ke Git dengan hanya mempublikasikan release assets langsung ke GitHub Releases.
  • Squash Merge Title Mismatch: Saat menggunakan strategi Squash and Merge di GitHub, commit individual di PR digabung menjadi satu commit. Pastikan judul PR mengikuti format Conventional Commits (misal: feat: add user authentication), karena judul tersebut yang akan menjadi commit message di branch main.
  • Trigger Ganda dari Tag: Jangan pernah memicu workflow semantic-release pada event on: push: tags:. Workflow hanya boleh berjalan pada perubahan branch utama untuk mencegah rekursi eksekusi workflow saat tag baru dibuat oleh semantic-release.