Lompat ke konten
dokumentasi.id
Commit 9a47d33
v2
Star3,4 rb

11

Otomasi Repository: Husky, Commitlint, dan CI

Template ini menahan kesalahan masuk lewat dua lapis. Lapis pertama berjalan di mesin pengembang: tiga hook Husky memeriksa berkas dan pesan commit sebelum commit itu tercatat .husky/pre-commit:1-4. Lapis kedua berjalan di server: workflow GitHub Actions mengulang pemeriksaan yang sama setelah kode di-push ke main atau dijadikan pull request .github/workflows/lint.yml:1-6. Keduanya memakai script yang sama dari package.json, sehingga kegagalan lokal hampir selalu berarti kegagalan CI juga.

Tiga hook lokal

Setiap berkas hook memakai pola identik: memuat _/husky.sh pada baris kedua, lalu menjalankan tepat satu perintah.

HookPerintahCakupan
pre-commitnpx lint-stagedhanya berkas yang sudah di-stage .husky/pre-commit:1-4
commit-msgnpx --no-install commitlint --edit "$1"pesan commit hasil penyuntingan .husky/commit-msg:1-4
post-mergepnpm installmenyamakan node_modules dengan pnpm-lock.yaml setelah merge .husky/post-merge:1-4

Berkas _/husky.sh tidak disimpan di repository; direktori .husky/ hanya memuat tiga berkas hook di atas. Hook baru aktif setelah husky install dijalankan oleh script prepare package.json:18.

⚠️ Clone tanpa pnpm install membuat ketiga hook tidak pernah terpasang, dan tidak ada peringatan apa pun saat commit dibuat. README menegaskan pemakaian pnpm justru supaya hook Husky bekerja sebagaimana mestinya README.md:79.

Opsi --no-install pada commit-msg melarang npx mengunduh paket, sehingga commitlint wajib sudah ada di node_modules. Ketiga alat itu masuk devDependencies: @commitlint/cli dan @commitlint/config-conventional package.json:31-32, sedangkan husky dan lint-staged package.json:48-50.

Alur commit dari hook lokal sampai CI

Diagram berikut menelusuri satu commit dari git commit sampai status check di GitHub. Perhatikan bahwa pemeriksaan yang sama dijalankan dua kali: sekali oleh hook, sekali oleh CI.

sequenceDiagram
    autonumber
    actor Dev as Developer
    participant PC as pre-commit
    participant LS as lint-staged
    participant CM as commit-msg
    participant CL as commitlint
    participant CI as Code Check
    Dev->>PC: git commit
    PC->>LS: npx lint-staged
    LS->>LS: eslint --max-warnings=0 pada berkas staged
    LS->>LS: prettier -w
    alt ada berkas yang gagal
        LS-->>Dev: commit dibatalkan
    else semua lolos
        PC->>CM: pesan commit tersedia
        CM->>CL: npx --no-install commitlint --edit
        alt type di luar type-enum
            CL-->>Dev: commit ditolak
        else type valid
            Dev->>CI: push ke main atau pull request
            CI->>CI: lint:strict dan typecheck
            CI->>CI: format:check dan test
            CI-->>Dev: status check selesai
        end
    end
%% fig: Alur commit dari hook lokal sampai Code Check
%% desc: pre-commit menjalankan lint-staged lalu commit-msg menjalankan commitlint; setelah push atau pull request workflow Code Check mengulang seluruh pemeriksaan.
Fig. 1: Alur commit dari hook lokal sampai Code Checkpre-commit menjalankan lint-staged lalu commit-msg menjalankan commitlint; setelah push atau pull request workflow Code Check mengulang seluruh pemeriksaan.

lint-staged dan aturan commitlint

lint-staged dipilih berdasarkan pola berkas, bukan seluruh proyek, sehingga hanya berkas yang berubah yang diperiksa package.json:59-67.

Pola berkasPerintah berurutan
**/*.{js,jsx,ts,tsx}eslint --max-warnings=0, lalu prettier -w
**/*.{json,css,scss,md,webmanifest}prettier -w

Perhatikan bahwa prettier -w menulis ulang berkas, bukan sekadar memeriksanya. Pemeriksaan tanpa menulis hanya terjadi di CI lewat format:check package.json:9-16.

commitlint.config.js mewarisi @commitlint/config-conventional lalu mempersempit daftar type commitlint.config.js:1-3. Ada sebelas nilai yang diterima commitlint.config.js:6-22.

typeDipakai untuk
featfitur baru
fixperbaikan bug
docsdokumentasi
chorepekerjaan pemeliharaan
styleformat tanpa mengubah perilaku
refactorpenyusunan ulang kode tanpa mengubah perilaku
ciperubahan konfigurasi CI
testperubahan test
perfpeningkatan performa
revertpembatalan commit sebelumnya
vercelpenyesuaian deploy Vercel, lihat SEO, Sitemap, dan Deploy

Aturan scope-enum sengaja masih dikomentari, jadi scope bebas dipakai selama formatnya type(scope): subject commitlint.config.js:4-5. Pesan seperti update atau fix bug tidak punya type yang sah dan ditolak sebelum commit tercatat.

Empat workflow GitHub Actions

Setiap workflow dipicu event yang berbeda, seperti terlihat pada peta berikut.

graph LR
    PUSH["push ke main"] --> CODE["Code Check<br/>lint.yml"]
    PR["pull_request"] --> CODE
    PR --> LINK["Issue Autolink<br/>issue-autolink.yml"]
    ASSIGN["issues assigned"] --> BRANCH["Create Branch<br/>create-branch.yml"]
    DISPATCH["workflow_dispatch"] --> REL["release-please<br/>release-please.yml"]
    BRANCH --> NAME["branchName i nomor issue"]
    LINK --> PREFIX["branch-prefix i"]
    CODE --> FAIL["check gagal"]
    style CODE fill:#2d7d46,color:#fff
    style FAIL fill:#dc2626,color:#fff
    style BRANCH fill:#8b5cf6,color:#fff
    style LINK fill:#8b5cf6,color:#fff
    style NAME fill:#8b5cf6,color:#fff
    style PREFIX fill:#8b5cf6,color:#fff
    style REL fill:#f59e0b,color:#000
%% fig: Peta trigger workflow GitHub Actions
%% desc: Setiap workflow dipicu event berbeda; hanya Code Check yang menjaga push ke main dan pull request, sedangkan release-please masih manual.
Fig. 2: Peta trigger workflow GitHub ActionsSetiap workflow dipicu event berbeda; hanya Code Check yang menjaga push ke main dan pull request, sedangkan release-please masih manual.
WorkflowBerkasTriggerLangkah kunci
Code Checklint.ymlpush ke main, pull_request .github/workflows/lint.yml:2-6pnpm 9 dan Node 20 dengan cache pnpm, pnpm install --frozen-lockfile, lalu lint:strict, typecheck, format:check, test .github/workflows/lint.yml:16-44
release-pleaserelease-please.ymlworkflow_dispatch .github/workflows/release-please.yml:1-9google-github-actions/release-please-action@v3 dengan release-type: node .github/workflows/release-please.yml:10-17
Create Branch from Issuecreate-branch.ymlissues tipe assigned .github/workflows/create-branch.yml:1-5robvanderleek/create-issue-branch@main .github/workflows/create-branch.yml:7-13
Issue Autolinkissue-autolink.ymlpull_request tipe opened .github/workflows/issue-autolink.yml:1-4tkt-actions/[email protected] dengan branch-prefix: 'i' dan resolve: 'true' .github/workflows/issue-autolink.yml:6-16

Workflow Code Check juga memasang concurrency dengan group ${{ github.job }}-${{ github.ref }} dan cancel-in-progress: true, jadi push baru pada ref yang sama membatalkan run yang masih berjalan .github/workflows/lint.yml:8-10.

Langkah CI memanggil script yang sudah ada di package.json, bukan perintah baru package.json:9-16. Karena itu kegagalan test di CI bisa ditelusuri lewat Pengujian dengan Jest, dan aturan lint serta TypeScript-nya dibahas di Konfigurasi Build dan Alat Pengembangan.

Saat sebuah issue di-assign, create-issue-branch membuat branch dengan nama dari .github/issue-branch.yml. Pola namanya i${issue.number}-${issue.title,}, dan issue berlabel epic atau debt dilewati .github/issue-branch.yml:1-9. Di sisi lain, add-issue-links memakai branch-prefix: 'i', sehingga prefix huruf i yang sama menghubungkan branch hasil otomasi dengan pull request yang dibuka .github/workflows/issue-autolink.yml:12-16.

⚠️ Label epic dan debt tidak akan menghasilkan branch otomatis. Kalau branch tetap dibuat manual dengan nama di luar pola i<nomor>, autolink tidak menemukan issue pasangannya.

release-please dan changelog

Workflow release-please sengaja hanya bisa dijalankan manual. Trigger otomatis push ke main tersedia di berkas itu, tetapi masih dikomentari .github/workflows/release-please.yml:3-9. Nilai package-name diisi release-please-action, bukan nama paket repository ini yang tertulis di package.json ts-nextjs-tailwind-starter package.json:2, jadi ganti nilai itu sebelum workflow dipakai sungguhan .github/workflows/release-please.yml:14-17.

⚠️ Selama trigger hanya workflow_dispatch, CHANGELOG.md tidak bertambah sendiri setelah merge ke main. Riwayat rilis baru bergerak ketika seseorang menjalankan workflow ini dari tab Actions.