34. CI/CD Pipeline & Local Validation

Proses pengembangan software sekarang dituntut serba cepat, tapi kodenya harus tetap stabil dan berkualitas. Makanya, kita menerapkan prinsip Shift-Left Validation. Konsepnya sederhana: kita memindahkan proses testing dan validasi sedini mungkin ke lingkungan lokal (komputer developer) sebelum kodenya masuk ke repositori utama.

Dengan melakukan validasi secara lokal, feedback loop jadi lebih cepat, kita bisa menghemat waktu build di server CI/CD, menghemat resource runner, dan memastikan branch utama (main/master) selalu aman dan siap deploy kapan saja (always deployable).


A. Alur Validasi Kode (Validation Workflow)

Berikut adalah diagram alur verifikasi kode dari komputer lokal sampai dideploy lewat server CI/CD:

graph TD
    A[Developer Menulis Kode] --> B[Simpan File / Git Commit]
    B --> C{Git Hook: Husky & lint-staged}
    C -- Ada Error Lint/Type/Test --> D[Commit Ditolak & Perbaiki di Lokal]
    C -- Sukses --> E[Push ke Repositori Remote]
    E --> F[Picu Pipeline CI/CD di Server]
    F --> G{Pemeriksaan CI/CD Pipeline}
    G -- Gagal --> H[Kirim Notifikasi Gagal & Blok Merge]
    H --> A
    G -- Sukses --> I[Merge ke Branch Utama & Deploy]

B. Validasi Lokal (Local Validation Checklist)

Sebelum melakukan push atau membuat commit, developer sebaiknya menjalankan checklist validasi berikut secara mandiri di komputer masing-masing:

1. Code Formatting (Prettier)

Memastikan semua file rapi sesuai standar penulisan kode. Langkah ini membantu menghindari perdebatan seputar format kode (seperti koma, spasi, dll.) saat code review.

# Memeriksa apakah ada file yang melanggar format
npm run format:check

# Memperbaiki format kode secara otomatis di semua file
npm run format:write

2. Static Analysis & Linting (ESLint)

Mendeteksi pola kode yang kurang baik (anti-patterns), variabel yang tidak terpakai, dan potensi bug sebelum kode dijalankan.

# Menjalankan linter untuk mencari masalah kode
npm run lint

# Memperbaiki masalah linting ringan secara otomatis
npm run lint -- --fix

3. Type Checking (TypeScript Compiler)

Memastikan keamanan tipe data (type safety) di seluruh project. Proses build biasa kadang mengabaikan error tipe data jika tidak dikonfigurasi dengan ketat.

# Menjalankan type-check tanpa menghasilkan file build
npm run type-check
# atau secara langsung:
npx tsc --noEmit

4. Automated Testing (Unit & Integration)

Memastikan perubahan kode baru tidak merusak fitur lama yang sudah berjalan (regression testing).

# Menjalankan semua test
npm run test

# Menjalankan test untuk file yang berubah saja (Watch Mode)
npm run test:watch

5. Local Production Build Simulation

Kadang kode berjalan lancar di mode development (npm run dev), tapi gagal saat di-build untuk production karena masalah optimasi compiler, circular dependencies, atau file yang hilang. Selalu jalankan build lokal sebelum membuat Pull Request (PR).

# Simulasi membuat production build secara lokal
npm run build

C. Otomatisasi Validasi Lokal Menggunakan Git Hooks

Menjalankan lima langkah di atas secara manual setiap kali akan commit tentu kurang efisien dan rentan terlewat. Untuk memudahkan, kita bisa mengotomatisasikannya menggunakan Husky dan lint-staged.

[!IMPORTANT] lint-staged sangat membantu memastikan pemeriksaan hanya berjalan pada file yang sedang diubah (staged files), bukan seluruh project. Hal ini menjaga proses git commit tetap berjalan cepat (di bawah 10 detik).

1. Instalasi Dependensi

npm install -D husky lint-staged

2. Inisialisasi Husky

npx husky-init
npm install

Perintah ini akan membuat folder .husky/ di direktori utama dan menambahkan script prepare di package.json.

3. Konfigurasi lint-staged di package.json

Tambahkan konfigurasi berikut di package.json untuk menentukan file mana saja yang perlu diperiksa:

{
  "scripts": {
    "prepare": "husky install"
  },
  "lint-staged": {
    "*.{js,jsx,ts,tsx}": [
      "eslint --fix",
      "prettier --write"
    ],
    "*.{json,md,css,scss}": [
      "prettier --write"
    ]
  }
}

4. Konfigurasi Git Pre-commit Hook (.husky/pre-commit)

Ubah isi file .husky/pre-commit menjadi seperti di bawah ini. File ini akan berjalan otomatis setiap kali melakukan git commit.

#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

echo "=== Memulai Validasi Pre-Commit ==="

# 1. Jalankan Type-Check pada file TypeScript (memerlukan konteks seluruh proyek)
echo "🔍 Menjalankan TypeScript Type-Check..."
npx tsc --noEmit || {
  echo "❌ TypeScript Type-Check gagal! Silakan perbaiki error tipe data sebelum commit."
  exit 1
}

# 2. Jalankan lint-staged untuk memformat dan memeriksa file yang diubah
echo "🧹 Menjalankan ESLint & Prettier pada staged files..."
npx lint-staged || {
  echo "❌ Linting atau formatting gagal!"
  exit 1
}

# 3. Jalankan unit test untuk file yang berubah (sangat direkomendasikan)
echo "🧪 Menjalankan Unit Test..."
npm run test:related || npm run test -- --watchAll=false --findRelatedTests $(git diff --staged --name-only) || {
  echo "❌ Unit test gagal!"
  exit 1
}

echo "✅ Validasi berhasil! Melanjutkan commit."

D. Standardisasi CI/CD Pipeline Server

Meskipun validasi lokal sudah berjalan, server CI/CD tetap bertindak sebagai Gatekeeper Utama. Server CI/CD menjamin pengujian berjalan di lingkungan yang bersih (clean slate) dan terisolasi dari cache komputer developer.

1. Aturan Penggunaan npm ci vs npm install

Di server CI/CD, sebaiknya gunakan npm ci (Clean Install) alih-alih npm install. Keuntungannya:

  • Menghapus folder node_modules yang ada untuk memastikan dependensi bersih.
  • Mengunduh dependensi sesuai dengan package-lock.json untuk menjamin versi yang sama dengan komputer lokal.
  • Tidak memperbarui package-lock.json secara otomatis, menghindari efek samping perubahan versi.
  • Proses instalasi lebih cepat dibanding npm install biasa.

2. Contoh Konfigurasi GitLab CI/CD (.gitlab-ci.yml)

Berikut contoh konfigurasi multi-stage untuk GitLab CI/CD (.gitlab-ci.yml):

# Menggunakan image node versi LTS
image: node:20-alpine

# Aktifkan cache node_modules untuk mempercepat build berikutnya
cache:
  key:
    files:
      - package-lock.json
  paths:
    - .npm/
    - node_modules/

stages:
  - install
  - test
  - build
  - deploy

# Stage 1: Instalasi dependensi
install_dependencies:
  stage: install
  script:
    - npm ci --cache .npm --prefer-offline
  artifacts:
    paths:
      - node_modules/
    expire_in: 1 hour

# Stage 2: Pemeriksaan kualitas kode & test
code_quality_and_test:
  stage: test
  dependencies:
    - install_dependencies
  script:
    - npm run lint
    - npx tsc --noEmit
    - npm run test -- --coverage --watchAll=false
  coverage: '/All files[^|]*\|[^|]*\s+([\d\.]+)/'
  artifacts:
    reports:
      junit: junit.xml

# Stage 3: Proses build
build_project:
  stage: build
  dependencies:
    - install_dependencies
  script:
    - npm run build
  artifacts:
    paths:
      - dist/
      - .next/
    expire_in: 1 week
  only:
    - main
    - merge_requests

# Stage 4: Deployment (Contoh ke Staging/Production)
deploy_to_staging:
  stage: deploy
  dependencies:
    - build_project
  script:
    - echo "Deploying to Staging Server..."
    - # Jalankan script deployment di sini (AWS S3, Vercel CLI, Docker, dll)
  environment:
    name: staging
    url: https://staging.company.com
  only:
    - main

3. Contoh Konfigurasi GitHub Actions (.github/workflows/ci.yml)

Berikut contoh konfigurasi untuk GitHub Actions (.github/workflows/ci.yml):

name: Frontend CI/CD Pipeline

on:
  push:
    branches: [ main, staging ]
  pull_request:
    branches: [ main, staging ]

jobs:
  validate-and-build:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout Repository
        uses: actions/checkout@v4

      - name: Setup Node.js Environment
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm' # Caching otomatis untuk dependensi npm

      - name: Install Dependencies
        run: npm ci

      - name: Run ESLint
        run: npm run lint

      - name: Run TypeScript Type-Check
        run: npx tsc --noEmit

      - name: Run Unit Tests
        run: npm run test -- --watchAll=false

      - name: Build Application
        run: npm run build

      - name: Upload Build Artifacts
        if: github.ref == 'refs/heads/main' && github.event_name == 'push'
        uses: actions/upload-artifact@v4
        with:
          name: production-build
          path: |
            .next/
            dist/
            public/
            package.json
          retention-days: 7

E. Best Practices dalam CI/CD

Untuk menjaga pipeline berjalan efisien dan aman, ikuti prinsip-prinsip berikut:

  1. Dependency Caching: Selalu konfigurasikan caching untuk folder node_modules atau cache NPM (.npm). Ini dapat mempersingkat waktu build hingga 50% - 70%.
  2. Secrets & Environment Variables:
    • [!WARNING] Jangan menyimpan file .env atau secret keys di dalam repositori Git.

    • Simpan kredensial sensitif di menu Variables (GitLab CI/CD) atau Secrets (GitHub Settings).
    • Panggil nilai tersebut di dalam pipeline menggunakan environment variable (contoh: process.env.API_KEY).
  3. Pipeline Fail-Fast: Tempatkan pengujian yang paling cepat (seperti linting) di tahap awal. Jika tahap awal ini gagal, hentikan pipeline segera untuk menghemat waktu dan resource komputasi.

F. Panduan Pemecahan Masalah (Troubleshooting)

Kasus 1: "Lokal sukses berjalan, tetapi CI/CD gagal build"

  • Kemungkinan Penyebab A: Perbedaan sensitivitas huruf besar/kecil (case-sensitivity) pada nama file. Komputer macOS/Windows secara default bersifat case-insensitive, sedangkan server Linux CI/CD bersifat case-sensitive.
    • Solusi: Pastikan impor file sesuai persis dengan nama file fisik (misal: import Card from './Card' bukan import Card from './card').
  • Kemungkinan Penyebab B: Dependensi yang terpasang di lokal tidak tercatat di package.json atau terpasang sebagai package global.
    • Solusi: Jalankan npm ci di folder baru secara lokal untuk mensimulasikan lingkungan server.

Kasus 2: "Proses Type-Checking lambat di CI/CD"

  • Solusi: Pastikan Anda menyertakan opsi skipLibCheck: true di dalam berkas tsconfig.json proyek untuk menghindari pemeriksaan tipe data pada berkas pihak ketiga di node_modules.

G. Matriks Perbandingan Validasi

Dimensi ValidasiLingkungan Lokal (Local)Lingkungan CI/CD (Server)Frekuensi Eksekusi
FormattingMenggunakan Prettier otomatis saat menyimpan berkas atau git commit.prettier --check memastikan tidak ada bypass kode yang tidak rapi.Setiap commit & PR check.
LintingIntegrasi IDE memberikan info error langsung saat mengetik.ESLint memeriksa secara mutlak sebelum penggabungan kode (merge).Instan di IDE & saat PR check.
Type CheckingEvaluasi incremental di latar belakang oleh IDE atau tsc --noEmit manual.Pemeriksaan penuh dari awal untuk menghindari kesalahan tipe data.Setiap commit & PR check.
TestingMenjalankan test-suite spesifik yang terkait dengan file yang diubah.Menjalankan seluruh pengujian dari awal beserta perhitungan coverage.Setiap commit & PR check.
BuildingOpsional dijalankan mandiri sebelum membuat Pull Request.Wajib dijalankan untuk memvalidasi output bundler sebelum proses deploy.Setiap PR & deploy branch.

© 2026. Technical Excellence Standard.

© 2026 Bit Group Asia. All rights reserved.

ArchitectureSecurityGuidelines