Jika Anda ingin mencegah kode bermasalah masuk ke repository, Git hook di proyek CodeIgniter 4 adalah cara praktis untuk menahan commit atau push sebelum perubahan lolos pemeriksaan dasar. Pendekatan ini cocok untuk validasi cepat di lokal: formatter/linter, static analysis, dan test penting yang relatif ringan.
Tujuan utamanya bukan menggantikan CI, tetapi memindahkan umpan balik lebih dekat ke developer. Dengan begitu, error sederhana seperti style yang tidak konsisten, type issue yang mudah dideteksi, atau test dasar yang gagal bisa berhenti sebelum masuk ke branch bersama.
Mengapa Git hook relevan untuk CodeIgniter 4
Pada proyek CodeIgniter 4, perubahan sering menyentuh kombinasi controller, service, model, validation, dan konfigurasi. Masalah kecil seperti import yang salah, pemanggilan method yang keliru, atau perubahan perilaku di layer service sering baru terlihat saat test atau review. Git hook membantu menutup celah ini dengan validasi otomatis di mesin developer.
Manfaat yang paling terasa:
- Feedback cepat: developer tahu masalah sebelum commit atau push.
- DX lebih baik: aturan kualitas berjalan otomatis, bukan mengandalkan ingatan manual.
- Branch lebih bersih: mengurangi commit yang jelas rusak.
- Review lebih fokus: reviewer tidak sibuk mengomentari hal mekanis seperti formatting.
Prinsip penting: hook lokal harus cepat dan dapat diprediksi. Jika terlalu lambat, developer akan frustrasi, mencari cara bypass, atau menonaktifkannya.
Target workflow: apa yang dijalankan di pre-commit dan pre-push
Untuk menjaga hook tetap ringan, pisahkan validasi berdasarkan biaya eksekusi:
Pre-commit
- Format/lint pada file yang di-stage
- Static analysis ringan atau terbatas jika memungkinkan
- Pemeriksaan cepat yang hampir selalu selesai dalam hitungan singkat
Pre-push
- Static analysis penuh
- Subset test penting, atau seluruh test suite jika masih cukup cepat
Pemisahan ini bekerja karena commit terjadi jauh lebih sering daripada push. Jadi, pre-commit sebaiknya hanya memuat pemeriksaan yang ringan dan sangat sering berguna.
Struktur dasar proyek dan composer script
Agar hook tidak berisi command yang panjang dan sulit dirawat, simpan semua workflow di composer.json. Hook cukup memanggil script Composer. Keuntungannya:
- Satu sumber definisi command untuk lokal dan CI
- Lebih mudah diubah tanpa mengedit banyak file hook
- Dokumentasi tim lebih sederhana
Contoh struktur yang umum:
project-root/
├── app/
├── public/
├── tests/
├── vendor/
├── tools/
│ └── git-hooks/
├── composer.json
├── phpunit.xml
├── phpstan.neon
└── .php-cs-fixer.phpContoh composer.json yang memusatkan command quality check:
{
"scripts": {
"lint": "php-cs-fixer fix --dry-run --diff --verbose",
"lint:fix": "php-cs-fixer fix --verbose",
"stan": "phpstan analyse",
"test": "phpunit",
"qa": [
"@lint",
"@stan",
"@test"
],
"hook:pre-commit": "bash tools/git-hooks/run-pre-commit.sh",
"hook:pre-push": "bash tools/git-hooks/run-pre-push.sh"
}
}Jika tim Anda lebih memilih Laravel Pint untuk style fixer karena sintaks yang lebih sederhana, itu juga bisa dipakai pada proyek PHP secara umum selama dependensi dan ruleset sesuai kebutuhan tim. Namun untuk proyek CodeIgniter 4, PHP CS Fixer sering dipilih karena lebih fleksibel dan netral terhadap framework.
Menambahkan tool inti: formatter, static analysis, dan test
1. Formatter/linter: PHP CS Fixer atau Pint
Untuk workflow tim, formatter sebaiknya punya dua mode:
- Mode cek untuk hook dan CI
- Mode perbaikan otomatis untuk dijalankan manual oleh developer
Contoh konfigurasi minimal .php-cs-fixer.php:
<?php
$finder = PhpCsFixer\Finder::create()
->in([
__DIR__ . '/app',
__DIR__ . '/tests'
])
->name('*.php');
return (new PhpCsFixer\Config())
->setRiskyAllowed(false)
->setRules([
'@PSR12' => true,
'array_syntax' => ['syntax' => 'short'],
'no_unused_imports' => true,
'single_quote' => true,
'trailing_comma_in_multiline' => true,
])
->setFinder($finder);Untuk hook, gunakan mode --dry-run agar commit gagal jika format belum benar, tetapi file tidak diam-diam diubah oleh hook. Ini lebih aman dan lebih mudah dipahami developer.
2. Static analysis dengan PHPStan
PHPStan berguna untuk menangkap error yang tidak selalu terlihat dari lint syntax biasa, seperti pemanggilan method yang tidak ada, nullability issue, atau tipe data yang tidak konsisten.
Contoh phpstan.neon yang sederhana:
parameters:
paths:
- app
- tests
level: 5
tmpDir: writable/cache/phpstanCatatan penting: level PHPStan tidak perlu langsung agresif. Pada repository yang sudah berjalan lama, menaikkan level terlalu cepat justru menghambat adopsi. Mulailah dari level yang realistis, lalu tingkatkan bertahap.
3. PHPUnit untuk test dasar
Hook lokal sebaiknya tidak selalu menjalankan semua test jika suite Anda besar. Mulai dari:
- test unit/service yang cepat
- test untuk komponen inti yang sering berubah
- smoke test sederhana untuk memastikan aplikasi tidak rusak secara dasar
Jika Anda sudah punya grouping test, pre-push bisa menjalankan subset yang penting dulu, sedangkan suite penuh dipindahkan ke CI.
Contoh implementasi Git hook yang ringan
Pre-commit: fokus pada file yang di-stage
Masalah paling umum pada hook adalah terlalu lambat karena memeriksa seluruh repository. Untuk pre-commit, lebih efisien memproses file PHP yang sedang di-stage saja.
Contoh tools/git-hooks/run-pre-commit.sh:
#!/usr/bin/env bash
set -e
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\.php$' || true)
if [ -z "$STAGED_FILES" ]; then
echo "Tidak ada file PHP yang di-stage. Lewati pre-commit."
exit 0
fi
echo "Menjalankan formatter check pada file yang di-stage..."
php vendor/bin/php-cs-fixer fix --dry-run --diff --path-mode=intersection $STAGED_FILES
echo "Pre-commit selesai."Mengapa pendekatan ini efektif:
- Hanya file relevan yang diperiksa
- Waktu eksekusi jauh lebih singkat
- Developer tidak dihukum untuk file lama yang belum dirapikan
Jika ingin menambah pemeriksaan syntax dasar, Anda bisa menambahkan loop php -l untuk file yang di-stage. Namun jangan menumpuk terlalu banyak command di pre-commit jika hasilnya lambat.
Pre-push: static analysis dan test dasar
Contoh tools/git-hooks/run-pre-push.sh:
#!/usr/bin/env bash
set -e
echo "Menjalankan PHPStan..."
php vendor/bin/phpstan analyse
echo "Menjalankan PHPUnit..."
php vendor/bin/phpunit
echo "Pre-push selesai."Jika test suite Anda mulai berat, ubah strategi menjadi:
- pre-push menjalankan subset test yang cepat
- CI menjalankan suite penuh, termasuk integrasi dan regresi
Cara memasang hook tanpa setup manual per developer
Masalah klasik Git hook adalah file hook berada di .git/hooks, yang tidak ikut version control. Jika mengandalkan copy manual, cepat atau lambat akan ada anggota tim yang lupa memasang atau menggunakan versi lama.
Pendekatan yang lebih stabil adalah menyimpan hook di repository, lalu mengarahkan Git ke direktori hook tersebut melalui core.hooksPath.
Simpan hook di dalam repo
tools/
└── git-hooks/
├── pre-commit
├── pre-push
├── run-pre-commit.sh
└── run-pre-push.shContoh file wrapper tools/git-hooks/pre-commit:
#!/usr/bin/env bash
composer hook:pre-commitContoh file wrapper tools/git-hooks/pre-push:
#!/usr/bin/env bash
composer hook:pre-pushLalu arahkan Git ke path tersebut:
git config core.hooksPath tools/git-hooks
chmod +x tools/git-hooks/pre-commit tools/git-hooks/pre-push
chmod +x tools/git-hooks/run-pre-commit.sh tools/git-hooks/run-pre-push.shOtomasi pemasangan hook
Supaya tidak manual, sediakan script bootstrap, misalnya tools/setup-hooks.sh:
#!/usr/bin/env bash
set -e
git config core.hooksPath tools/git-hooks
chmod +x tools/git-hooks/pre-commit tools/git-hooks/pre-push
chmod +x tools/git-hooks/run-pre-commit.sh tools/git-hooks/run-pre-push.sh
echo "Git hooks berhasil dipasang."Lalu expose lewat Composer:
{
"scripts": {
"setup-hooks": "bash tools/setup-hooks.sh"
}
}Developer cukup menjalankan:
composer setup-hooksJika ingin lebih jauh, Anda bisa memasukkan langkah ini ke proses onboarding lokal tim atau script setup project. Intinya, jangan menjadikan dokumentasi sebagai satu-satunya mekanisme sinkronisasi.
Alur eksekusi yang disarankan
- Developer mengubah file di
app/atautests/. - Developer menjalankan formatter lokal bila perlu, misalnya
composer lint:fix. - Saat
git commit, hook pre-commit memeriksa file PHP yang di-stage. - Jika gagal, commit dibatalkan dan developer memperbaiki masalah.
- Saat
git push, hook pre-push menjalankan PHPStan dan PHPUnit. - Setelah lolos, perubahan dikirim ke remote dan tetap diverifikasi lagi oleh CI.
Model ini memberi dua lapis perlindungan:
- Lokal untuk feedback cepat
- CI untuk validasi final yang lebih lengkap dan konsisten
Menghindari hook yang terlalu lambat
Keberhasilan Git hook lebih ditentukan oleh pengalaman pengguna daripada banyaknya rule. Berikut strategi paling efektif agar workflow tetap dipakai tim:
1. Batasi pre-commit ke file yang di-stage
Ini langkah paling berdampak. Jangan scan seluruh project jika kebutuhan Anda hanya mencegah commit rusak yang baru saja dibuat.
2. Pisahkan formatter check dan auto-fix
Hook sebaiknya mengecek, bukan diam-diam mengubah file. Auto-fix tetap tersedia lewat command manual seperti composer lint:fix.
3. Simpan static analysis berat di pre-push atau CI
PHPStan pada codebase besar bisa cukup mahal. Jika pre-push terasa lambat, pertimbangkan:
- jalankan hanya pada branch utama sebelum push
- jalankan subset path tertentu
- jadikan CI sebagai sumber validasi penuh
4. Gunakan cache tool jika tersedia
Beberapa tool memiliki mekanisme cache atau direktori temporary untuk mempercepat eksekusi berikutnya. Pastikan direktori cache tidak bentrok dengan hak akses lokal tim.
5. Jangan jalankan test integrasi berat di hook lokal
Test yang membutuhkan service eksternal, database kompleks, atau environment khusus lebih cocok ditempatkan di CI. Hook lokal idealnya independen dan mudah dijalankan di semua mesin developer.
Kapan validasi dipindah ke CI
Git hook lokal bukan tempat untuk semua jenis pemeriksaan. Pindahkan validasi ke CI jika memenuhi salah satu kondisi berikut:
- Waktu eksekusinya terlalu lama untuk workflow harian
- Membutuhkan dependency eksternal seperti database, Redis, atau service lain
- Butuh environment yang konsisten dan terisolasi
- Hasilnya harus menjadi source of truth resmi sebelum merge
Contoh yang cocok di CI:
- seluruh PHPUnit suite
- integration test
- coverage gate
- security scanning
- matrix build untuk beberapa versi runtime
Aturan praktis: jika sebuah pemeriksaan membuat
git committerasa berat, kemungkinan besar pemeriksaan itu terlalu mahal untuk pre-commit.
Trade-off dan keterbatasan
Kelebihan
- Mencegah error umum masuk terlalu jauh
- Mengurangi noise saat code review
- Memaksa standar kualitas minimum secara konsisten
Kekurangan
- Hook lokal bisa dibypass dengan
--no-verify - Performa tergantung mesin developer
- Tooling yang terlalu agresif bisa mengganggu produktivitas
- Repository lama sering butuh strategi adopsi bertahap
Karena hook bisa dibypass, CI tetap wajib sebagai pengaman final. Hook lokal berfungsi sebagai lapisan pencegahan awal, bukan pengganti pipeline validasi terpusat.
Kesalahan umum dan tips debugging
Hook tidak berjalan
- Periksa apakah
core.hooksPathsudah diarahkan dengan benar - Pastikan file hook executable dengan
chmod +x - Pastikan shell script menggunakan line ending yang benar
Command gagal hanya di satu mesin
- Periksa versi PHP lokal dan extension yang terpasang
- Pastikan dependency sudah di-install melalui Composer
- Gunakan path executable dari
vendor/binagar konsisten
Formatter memeriksa terlalu banyak file
- Periksa penggunaan
--path-mode=intersectionatau logika daftar file staged - Pastikan finder/config tidak memasukkan direktori yang tidak relevan
PHPStan terlalu berisik pada codebase lama
- Turunkan level awal
- Batasi path yang dianalisis lebih dulu
- Naikkan standar secara bertahap, bukan sekaligus
Checklist adopsi bertahap untuk repository yang sudah berjalan
Jika project CodeIgniter 4 Anda sudah aktif dan memiliki banyak legacy code, jangan langsung menyalakan semua validasi sekaligus. Gunakan pendekatan bertahap berikut:
- Langkah 1: tambahkan formatter check di pre-commit untuk file yang di-stage.
- Langkah 2: sediakan command auto-fix agar developer mudah menyesuaikan style.
- Langkah 3: tambahkan PHPStan dengan level moderat pada path utama.
- Langkah 4: tambahkan PHPUnit subset yang cepat di pre-push.
- Langkah 5: pindahkan suite penuh dan validasi berat ke CI.
- Langkah 6: setelah tim stabil, tingkatkan rule atau level analysis secara bertahap.
Checklist implementasi praktis:
- Composer script untuk
lint,lint:fix,stan,test, dan setup hook - Direktori hook yang disimpan di repository
- Pre-commit ringan, fokus ke file staged
- Pre-push untuk analysis dan test dasar
- Dokumentasi onboarding satu perintah
- CI tetap aktif sebagai validasi final
Penutup
Git hook untuk CodeIgniter 4 paling efektif jika dirancang sederhana: formatter di pre-commit, static analysis dan test dasar di pre-push, lalu validasi penuh di CI. Dengan composer script yang rapi dan sinkronisasi melalui core.hooksPath, tim bisa mendapatkan automasi lokal yang konsisten tanpa bergantung pada setup manual yang mudah terlewat.
Mulailah dari workflow yang ringan dan benar-benar membantu. Jika hook terasa cepat, jelas, dan jarang memberi false positive, peluang besar seluruh tim akan memakainya secara konsisten.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!