Semua pemeriksaan yang kita bangun sepanjang section ini — gofmt, goimports, go vet, staticcheck, golangci-lint, make test — hanya bermanfaat jika benar-benar dijalankan, dan manusia adalah pemrakarsa paling tidak andal: ada yang lupa, ada yang sengaja melewati saat terburu-buru. Continuous Integration (CI) memindahkan pemicunya dari ingatan ke peristiwa: setiap push dan setiap pull request otomatis memicu server menjalankan test dan lint pada salinan kode yang bersih. Pada chapter ini kita akan menyusun workflow GitHub Actions untuk proyek Go, memahami cache dan matriks sistem operasinya, lalu memasang gerbang perlindungan cabang agar kode yang gagal tidak bisa masuk ke main. Seluruh konfigurasi pada chapter ini adalah contoh: eksekusinya memerlukan repositori GitHub sehingga tidak dijalankan di lingkungan penulisan.

Dari Ingatan ke Otomasi #

Alur CI proyek Go umumnya berbunyi: checkout kode, pasang toolchain Go versi yang dipin, unduh dependency, lalu jalankan go vet ./..., go test ./..., dan golangci-lint. Kekuatannya bukan pada teknologi server, melainkan pada dua sifat yang tidak dimiliki pemeriksaan manual: pemicunya pasti terjadi pada setiap push, dan lingkungannya seragam untuk semua orang. Bug yang hanya muncul di Windows atau di versi Go lama tertangkap sebelum merge.

Workflow GitHub Actions #

GitHub Actions membaca berkas YAML di direktori .github/workflows/ repositori. Berikut contoh lengkap go.yml dengan dua job — test dan lint:

yaml
name: CI

on:
  push:
    branches: [main]
  pull_request:

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-go@v5
        with:
          go-version: "1.27"
          cache: true
      - name: go vet
        run: go vet ./...
      - name: go test
        run: go test -race ./...

  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-go@v5
        with:
          go-version: "1.27"
      - name: golangci-lint
        uses: golangci/golangci-lint-action@v7
        with:
          version: latest

Mari kita bedah isi workflow di atas:

  1. Blok on:: workflow dipicu oleh push ke cabang main dan oleh setiap pull request — dua momen ketika kode akan bergabung dengan orang lain.
  2. actions/checkout@v4: menyalin kode repositori ke runner.
  3. actions/setup-go@v5 dengan go-version: "1.27": memasang toolchain Go versi tetap. Nomor versi yang dipin menjaga hasil CI stabil — build tidak berubah perilaku hanya karena Go merilis versi baru.
  4. cache: true: setup-go menyimpan cache module go mod download antar eksekusi sehingga dependency tidak diunduh dari nol setiap kali.
  5. Langkah go test -race ./...: flag -race menyalakan race detector bawaan toolchain, yang mendeteksi akses data bersamaan secara nyata saat test berjalan — pemeriksaan yang mustahil dilakukan analyzer statis.
  6. Job lint terpisah: golangci-lint berjalan paralel dengan test lewat action resminya, sehingga kegagalan lint dan kegagalan test terbaca berdampingan tanpa saling menunggu.

Matriks Sistem Operasi #

Go mengompilasi lintas platform dengan mudah, tetapi perilaku runtime tetap bisa berbeda antar sistem operasi — path berkas, akhiran baris, hingga batas jaringan. Pemicuan matriks menjalankan job yang sama di beberapa runner:

yaml
  test:
    strategy:
      matrix:
        os: [ubuntu-latest, macos-latest, windows-latest]
    runs-on: ${{ matrix.os }}

Dengan konfigurasi tersebut, satu langkah go test dijalankan tiga kali — sekali per sistem operasi — dan pull request hanya lulus bila ketiganya hijau.

Lencana Status dan Gerbang Cabang #

Setelah workflow aktif, GitHub menyediakan lencana status yang lazim ditempel di README:

markdown
![CI](https://github.com/USER/REPO/actions/workflows/go.yml/badge.svg)

Lencana hijau menandakan cabang main sehat. Gerbang sesungguhnya dipasang lewat branch protection pada pengaturan repositori: cabang main dilindungi agar pull request tidak bisa di-merge sebelum status check test dan lint lulus. Kombinasi keduanya mengubah rantai kualitas dari saran menjadi syarat.

pre-commit versus CI #

Pemeriksaan tercepat tetap yang terjadi sebelum commit, karena umpan baliknya datang dalam hitungan detik. Hook git pre-commit menjalankan pemeriksaan ringan setiap kali git commit dipanggil:

bash
#!/bin/sh
gofmt -d . > /dev/null || { echo "ada berkas belum terformat gofmt"; exit 1; }
go vet ./... || exit 1

Skrip ini memanfaatkan kode keluar gofmt -d: perintah tersebut berstatus 1 ketika ada berkas yang berbeda dari format standar, sehingga commit ditolak lebih awal. Simpan skripnya sebagai .git/hooks/pre-commit dan beri hak eksekusi. Karena hook tidak ikut tersalin saat repositori di-clone, hook berlaku hanya untuk mesin yang memasangnya sendiri — itulah sebabnya CI tetap wajib: server tidak percaya keberadaan hook di mesin developer, server memeriksa kodenya langsung. Pre-commit menjaga kenyamanan lokal; CI menjaga kebenaran bersama.

Rantai perkakas kini tersambung: gofmt menjaga bentuk, vet dan linter menjaga kualitas, Makefile menjalankan semuanya satu pintu, dan CI memastikan pintu itu terbuka pada setiap perubahan. Seluruh bekal belajar sudah lengkap — saatnya menyusun program yang utuh di Section Proyek .

Referensi #