Mengotomasi release CatatanKu dengan GitHub Actions: build matrix untuk Windows/macOS/Linux, code signing di pipeline, caching dependensi, dan release automation yang menghasilkan installer siap distribusi

CatatanKu sekarang punya test (episode 15) dan metrik performa (episode 16) — keduanya tidak berguna jika tidak dijalankan otomatis setiap perubahan. CI/CD desktop menjawab kebutuhan khusus aplikasi desktop yang tidak dimiliki web: harus build di OS yang sama dengan target (Linux tidak bisa build DMG macOS secara native), menandatangani biner dengan sertifikat, dan menghasilkan installer untuk banyak platform dari satu commit.
Episode ini membangun pipeline GitHub Actions CatatanKu: build matrix (tiga OS), testing, code signing dengan secrets, caching yang mempercepat build, dan release automation yang menghasilkan installer siap distribusi. Ini menyambungkan episode 12 (packaging), 13 (update), dan 15 (testing) menjadi satu alur otomatis.
Aplikasi desktop hanya bisa dibuild dan ditandatangani untuk suatu platform di platform tersebut: macOS build hanya jalan di macOS, Windows di Windows. Matrix menjalankan job yang sama di beberapa runner sekaligus:
name: Release CatatanKu
on:
push:
tags: ["v*"]
jobs:
build:
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
include:
- os: ubuntu-latest
target: [AppImage, deb]
- os: windows-latest
target: [nsis]
- os: macos-latest
target: [dmg]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
if: runner.os == 'Linux' || runner.os == 'macOS'
- name: Install Linux dependencies
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y libwebkit2gtk-4.1-dev libgtk-3-devBuild desktop mahal — toolchain Rust, dependensi npm, engine Flutter. Tanpa cache, setiap rilis membayar penuh. Caching memotong waktu build secara drastis:
- name: Cache cargo registry
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
src-tauri/target
key: cargo-${{ runner.os }}-${{ hashFiles('**/Cargo.lock') }}
- name: Cache npm
uses: actions/cache@v4
with:
path: ~/.npm
key: npm-${{ runner.os }}-${{ hashFiles('package-lock.json') }}actions/setup-node dan dtolnay/rust-toolchain juga punya caching bawaan — pakai keduanya. Aturan cache: key harus berubah saat lockfile berubah, atau cache rusak.
Pipeline build sebaiknya tidak dijalankan untuk kode yang gagal test. Pisahkan job testing (cepat, bisa di matrix parsial) dari job build:
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 22, cache: npm }
- run: npm ci
- name: Unit & integration tests
run: npm test
- name: Lint & typecheck
run: npm run lint && npm run typecheck
- name: E2E tests
run: npx playwright testAturan praktis: unit/integration wajib lulus untuk setiap PR; E2E jalan di PR dan wajib lulus sebelum rilis; build installer hanya saat tag v*. Ini membagi kecepatan: feedback cepat untuk kesalahan umum, gate penuh untuk rilis.
Signing (episode 12) memakai rahasia: sertifikat Authenticode/Developer ID dan password-nya. Semua itu hidup di GitHub Secrets, di-inject ke step yang membutuhkan, dan tidak pernah muncul di log:
- name: Import Developer ID certificate
env:
CERTIFICATE_OSX: ${{ secrets.CERTIFICATE_OSX }} # base64
CERTIFICATE_PASSWORD_OSX: ${{ secrets.CERT_PASSWORD_OSX }}
KEYCHAIN: build.keychain
run: |
echo "$CERTIFICATE_OSX" | base64 --decode > cert.p12
security create-keychain -p "$KEYCHAIN" "$KEYCHAIN"
security default-keychain -s "$KEYCHAIN"
security import cert.p12 -k "$KEYCHAIN" \
-P "$CERTIFICATE_PASSWORD_OSX" -T /usr/bin/codesign
security set-key-partition-list -S apple-tool:,apple: \
-s -k "$KEYCHAIN" "$KEYCHAIN"- name: Sign Windows installer
env:
PFX_BASE64: ${{ secrets.WINDOWS_CERT_PFX }}
PFX_PASSWORD: ${{ secrets.WINDOWS_CERT_PASSWORD }}
shell: pwsh
run: |
$bytes = [Convert]::FromBase64String($env:PFX_BASE64)
[IO.File]::WriteAllBytes("catatanku.pfx", $bytes)
signtool sign /f catatanku.pfx /p $env:PFX_PASSWORD `
/tr http://timestamp.digicert.com /td sha256 /fd sha256 `
"dist/CatatanKu Setup.exe"Langkah sign bisa berjalan dalam pipeline build itu sendiri (electron-builder/tauri bundler mendukung config signing via env) atau sebagai step tambahan setelah build. Prinsipnya: kredensial hanya di inject environment step yang membutuhkannya.
Warning
Aturan ketat secret di CI: jangan pernah echo nilai secret ke log, jangan simpan di artifact, dan jangan izinkan job PR yang tidak tepercaya mengaksesnya. Pemicu rilis hanya dari tag — bukan dari fork/PR sembarangan. Sekali secret bocor di log, asumsikan kompromi: rotasi segera.
Semua bagian menyatu dalam satu alur saat tag versi didorong:
git tag v2.1.0 && git push --tags
↓ GitHub Actions (matrix 3 OS)
build + test + signing di tiap OS
↓ kumpulkan artifact installer
upload artifact ke GitHub Release
↓
update server (episode 13) membaca release
↓
pengguna menerima auto-update- name: Upload installer artifacts
uses: actions/upload-artifact@v4
with:
name: installer-${{ runner.os }}
path: |
dist/**/*.exe
dist/**/*.dmg
dist/**/*.AppImage
dist/**/*.deb
- name: Create GitHub Release
uses: softprops/action-gh-release@v2
if: startsWith(github.ref, 'refs/tags/')
with:
files: |
dist/**/*.exe
dist/**/*.dmg
dist/**/*.AppImage
dist/**/*.deb
generate_release_notes: trueDari sini, electron-updater/Tauri updater bisa memakai GitHub Releases sebagai update server, atau pipeline menyalin artifact ke CDN yang dikonfigurasi di episode 13.
Inti yang harus dibawa pulang:
Di episode 18 selanjutnya kita mengamankan jalur jaringan aplikasi: network security & WebView — konfigurasi webview yang aman, CORS, dan penanganan link eksternal. Sampai jumpa di episode 18!