Pipeline CI Supabase CLI yang baik tidak sekadar memeriksa apakah file SQL ada di repository. Pipeline harus membuktikan bahwa database dapat dibangun ulang dari nol menggunakan migration yang dikomit, seed dapat dijalankan, dan kontrak skema penting masih tersedia. Untuk tim yang memakai Git sebagai source of truth, pemeriksaan ini mencegah migration yang urutannya salah, dependensi objek yang hilang, serta perubahan skema manual yang tidak pernah masuk ke repository.
Prinsip utamanya adalah: jangan menguji database bersama yang statusnya tidak pasti untuk validasi pull request. Buat database Supabase lokal atau terisolasi di runner CI, reset database tersebut, terapkan seluruh migration, jalankan seed dan smoke test. Audit terhadap database Supabase remote dapat ditambahkan sebagai pemeriksaan terpisah, karena membutuhkan kredensial dan memiliki risiko berbeda.
Struktur repository: migration adalah sumber kebenaran
Proyek yang diinisialisasi dengan Supabase CLI umumnya menyimpan artefak database di direktori supabase/. Struktur yang praktis adalah sebagai berikut.
.
├── supabase/
│ ├── config.toml
│ ├── migrations/
│ │ ├── 20250110090000_create_profiles.sql
│ │ ├── 20250111113000_add_profile_policies.sql
│ │ └── 20250112101500_add_profile_trigger.sql
│ └── seed.sql
├── ci/
│ └── smoke.sql
└── .github/
└── workflows/
└── database-ci.yml
supabase/migrations/berisi migration SQL berurutan. Nama file biasanya diawali timestamp agar urutan penerapan deterministik.supabase/seed.sqlmenyimpan data minimum untuk pengujian lokal, misalnya data referensi atau akun uji yang tidak sensitif.supabase/config.tomlmenyimpan konfigurasi proyek lokal. File ini boleh dikomit selama tidak berisi secret.ci/smoke.sqlberisi assertion SQL terhadap objek dan perilaku database yang penting bagi aplikasi.
Jangan mengedit migration yang telah diterapkan di lingkungan bersama. Buat migration baru untuk setiap perubahan berikutnya. Mengubah file lama dapat membuat isi Git, histori migration, dan database remote tidak lagi konsisten.
Desain Pipeline CI Supabase CLI
Urutan validasi yang efektif bersifat fail-fast: kegagalan murah seperti nama file atau SQL yang tidak dapat diterapkan harus menghentikan pipeline sebelum runner menghabiskan waktu untuk test lain.
- Checkout commit pull request.
- Pasang Supabase CLI dan jalankan stack Supabase lokal menggunakan Docker.
- Reset database lokal agar semua migration diterapkan dari keadaan kosong.
- Jalankan seed yang dikonfigurasi untuk reset lokal.
- Jalankan
supabase db diff --localsebagai diagnosis perbedaan antara target lokal dan state yang direpresentasikan oleh migration. - Jalankan smoke test SQL dengan koneksi database lokal.
- Hentikan stack Supabase, termasuk saat langkah sebelumnya gagal.
supabase db reset merupakan inti validasi ini. Perintah tersebut menghapus state database lokal lalu membangun kembali database berdasarkan migration proyek. Jika migration membutuhkan tabel yang dibuat belakangan, ekstensi yang tidak tersedia, policy yang merujuk kolom salah, atau urutan DDL yang tidak benar, proses reset akan gagal.
Makna pemeriksaan diff pada CI lokal
supabase db diff --local berguna untuk melihat SQL yang diperlukan agar state target lokal dan state yang direpresentasikan migration menjadi sama. Setelah database baru saja di-reset dari seluruh migration, hasil yang diharapkan adalah tidak ada perubahan bermakna.
Namun, ada batasan penting: CI hanya melihat file yang dikirim ke Git. CI tidak dapat menemukan perubahan yang dibuat seorang developer secara manual di Supabase Studio pada laptopnya tetapi tidak diekspor menjadi migration. Oleh karena itu, reset dari nol memvalidasi reproduksibilitas migration yang dikomit, sedangkan audit terhadap database remote diperlukan untuk mendeteksi drift di lingkungan bersama.
Smoke test SQL dan seed yang aman
Smoke test bukan pengganti test aplikasi atau test integrasi penuh. Tujuannya adalah memastikan kontrak database paling kritis tersedia setelah migration diterapkan: tabel utama ada, RLS aktif bila diwajibkan, fungsi atau trigger penting dapat dibuat, dan data referensi dari seed tersedia.
Contoh berikut mengasumsikan aplikasi memiliki tabel public.profiles dan data referensi member pada tabel public.roles. Sesuaikan nama objek dengan proyek Anda.
-- ci/smoke.sql
DO $$
BEGIN
IF to_regclass('public.profiles') IS NULL THEN
RAISE EXCEPTION 'Tabel public.profiles tidak ditemukan';
END IF;
IF NOT EXISTS (
SELECT 1
FROM pg_class
WHERE oid = 'public.profiles'::regclass
AND relrowsecurity
) THEN
RAISE EXCEPTION 'RLS belum aktif pada public.profiles';
END IF;
IF NOT EXISTS (
SELECT 1
FROM public.roles
WHERE code = 'member'
) THEN
RAISE EXCEPTION 'Seed role member tidak ditemukan';
END IF;
END
$$;
Gunakan psql dengan ON_ERROR_STOP agar satu assertion yang gagal langsung menghasilkan exit code gagal. Hindari memasukkan data produksi, email pelanggan, token, atau password nyata ke seed.sql. Seed CI harus deterministik, minimal, dan aman dipublikasikan di repository.
Contoh workflow GitHub Actions
Workflow berikut menjalankan pemeriksaan untuk pull request yang mengubah aplikasi atau artefak database. Runner GitHub-hosted Linux menyediakan Docker, yang diperlukan oleh supabase start. Versi CLI dipin pada workflow nyata agar perubahan perilaku CLI tidak diam-diam mengubah hasil CI.
name: Database CI
on:
pull_request:
paths:
- 'supabase/**'
- 'ci/smoke.sql'
- '.github/workflows/database-ci.yml'
permissions:
contents: read
concurrency:
group: database-ci-${{ github.event.pull_request.number }}
cancel-in-progress: true
jobs:
validate-database:
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Supabase CLI
uses: supabase/setup-cli@v1
with:
version: latest
- name: Validate migration filenames
shell: bash
run: |
set -euo pipefail
find supabase/migrations -maxdepth 1 -type f -name '*.sql' -print0 |
while IFS= read -r -d '' file; do
base=$(basename "$file")
if [[ ! "$base" =~ ^[0-9]{14}_.+\.sql$ ]]; then
echo "Nama migration tidak valid: $base"
exit 1
fi
done
- name: Start isolated Supabase stack
run: supabase start
- name: Rebuild database from migrations and seed
run: supabase db reset --local
- name: Inspect local schema diff
shell: bash
run: |
set -euo pipefail
supabase db diff --local --schema public | tee /tmp/local-schema-diff.sql
if [ -s /tmp/local-schema-diff.sql ]; then
echo 'Ada diff skema setelah reset lokal. Periksa output di atas.'
exit 1
fi
- name: Install PostgreSQL client
run: |
sudo apt-get update
sudo apt-get install -y postgresql-client
- name: Run SQL smoke test
shell: bash
run: |
set -euo pipefail
source <(supabase status -o env)
psql "$DB_URL" -v ON_ERROR_STOP=1 -f ci/smoke.sql
- name: Stop local Supabase stack
if: always()
run: supabase stop
Perhatikan dua detail implementasi berikut.
source <(supabase status -o env)mengambil URL database lokal yang dilaporkan CLI, bukan mengandalkan port atau password yang ditulis tetap di workflow.- Output
db diffperlu diuji pada versi CLI yang tim gunakan. Jika versi tertentu menulis pesan informasional ke standard output, filter atau simpan hanya SQL diff-nya sebelum melakukan pemeriksaan file kosong. Jangan menganggap setiap teks output selalu berarti drift tanpa memverifikasi perilaku versi CLI yang dipin.
Jika repository juga menjalankan test Node.js, cache paket seperti cache npm boleh digunakan berdasarkan file lock. Jangan cache direktori temporary Supabase, volume Docker, file environment, kredensial CLI, atau artefak yang mungkin mengandung URL database dan token. Untuk validasi database ini, tidak menggunakan cache state database adalah pilihan yang lebih aman karena setiap job memang harus memulai dari keadaan kosong.
Audit schema drift pada database Supabase remote
Database remote dapat drift ketika seseorang menjalankan DDL langsung di dashboard, memakai koneksi SQL administratif, atau menjalankan deploy dari branch yang tidak semestinya. Pemeriksaan lokal tidak akan melihat keadaan tersebut. Tambahkan audit remote sebagai job terpisah yang berjalan pada branch terlindungi, jadwal teratur, atau workflow manual.
Secara umum, langkah auditnya adalah:
- Autentikasi CLI menggunakan
SUPABASE_ACCESS_TOKENdari GitHub Secrets. - Link ke project yang dituju menggunakan project reference dan password database dari Secrets.
- Periksa keselarasan histori dengan
supabase migration list --linked. - Gunakan
supabase db diff --linked --schema publicuntuk menghasilkan dan meninjau perbedaan skema terhadap database linked. - Gagalkan audit bila perbedaan bukan perubahan yang sengaja dikecualikan dan telah didokumentasikan.
env:
SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }}
SUPABASE_DB_PASSWORD: ${{ secrets.SUPABASE_DB_PASSWORD }}
# Jalankan hanya pada branch terlindungi atau workflow_dispatch.
supabase link --project-ref "$SUPABASE_PROJECT_REF" --password "$SUPABASE_DB_PASSWORD"
supabase migration list --linked
supabase db diff --linked --schema public
Jangan menjalankan job yang memakai secret pada event pull request dari fork. Jangan memakai pull_request_target untuk menjalankan kode SQL atau skrip dari pull request tidak tepercaya. Job audit remote sebaiknya memakai environment GitHub yang dilindungi dan kredensial dengan akses minimum.
Diff remote harus ditinjau secara semantik. Perbedaan dapat berasal dari extension, objek yang dikelola platform, atau skema di luar cakupan aplikasi. Batasi pemeriksaan pada skema yang memang dikelola tim, misalnya
public, dan dokumentasikan pengecualian yang sah.
Investigasi saat CI gagal
Migration gagal saat reset
- Baca nama migration terakhir pada log. Kesalahan PostgreSQL biasanya menunjuk statement, objek, atau dependensi yang gagal.
- Jalankan ulang secara lokal dengan
supabase startlalusupabase db reset --local. Reproduksi dari database kosong, bukan dari database pengembangan yang sudah berisi state lama. - Periksa urutan file timestamp. Tabel, tipe, extension, fungsi, dan kolom harus dibuat sebelum dirujuk oleh foreign key, policy, trigger, atau view.
- Pastikan migration aman dijalankan pada database baru. Hindari ketergantungan pada data atau objek manual yang tidak dibuat oleh migration sebelumnya.
- Untuk perubahan data besar atau operasi yang berpotensi mengunci tabel, pisahkan strategi deploy produksi dari validasi CI. Reset lokal tidak mensimulasikan ukuran data maupun lock produksi.
CI melaporkan schema drift
- Bandingkan SQL diff dengan migration pada branch yang diuji. Tentukan apakah perubahan berasal dari migration yang belum dikomit, perubahan manual di remote, atau objek platform yang seharusnya dikecualikan.
- Jika perubahan skema memang diinginkan, buat migration baru yang eksplisit. Jangan memperbaiki drift hanya dengan mengubah database remote agar tampak hijau.
- Jika perubahan remote tidak diinginkan, rencanakan migration korektif dan telaah dampaknya. Hindari menjalankan DDL destruktif otomatis hanya karena audit mendeteksi perbedaan.
- Jika histori migration lokal dan remote berbeda, hentikan deploy sampai penyebabnya dipahami. Memaksa histori tanpa prosedur yang disetujui dapat membuat recovery lebih sulit.
CI bukan deploy atau rollback produksi
CI pull request menjawab pertanyaan: apakah perubahan yang dikomit dapat membangun database secara deterministik dan memenuhi assertion dasar? CI tidak seharusnya mendorong migration ke produksi, menghapus data remote, atau menjadi mekanisme rollback otomatis.
Deploy produksi perlu pipeline terpisah dengan approval, target environment yang jelas, backup, observabilitas, dan strategi perubahan kompatibel. Untuk PostgreSQL, rollback tidak selalu aman: migration yang menghapus kolom, mengubah tipe data, atau memigrasikan data dapat kehilangan informasi. Praktik yang lebih aman adalah membuat migration maju (forward fix), menerapkan pola expand-contract untuk perubahan inkompatibel, dan menyimpan prosedur pemulihan yang telah diuji.
Dengan pemisahan tersebut, Git tetap menjadi sumber kebenaran untuk skema, CI menjaga kualitas migration sebelum merge, dan proses deploy produksi tetap memiliki kontrol operasional yang sesuai.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!