Shell Script Automation untuk Development Workflow

by Marcus Chen
Shell Script Automation untuk Development Workflow

Masalah yang Bikin Frustrasi Tiap Pagi

Kamu buka laptop, buka terminal, terus mulai ngetik:

cd ~/projects/myapp
git pull origin main
npm install
npm run migrate
npm run dev

Besoknya, sama lagi. Lusa, sama lagi. Seminggu penuh, sama lagi.

Belum lagi kalau kamu kerja di beberapa project sekaligus — satu backend, satu frontend, satu service tambahan. Tiap kali switch context, kamu harus ingat port berapa, environment variable apa yang perlu di-set, dan service mana yang harus jalan duluan.

Ini bukan masalah kecil. Ini cognitive load yang nyata. Dan solusinya bukan beli tool baru — cukup shell script.

Shell script automation untuk development workflow bukan hal yang cuma dipakai SRE atau DevOps senior. Kamu bisa mulai hari ini, dari script 10 baris, dan langsung rasain bedanya.


Kenapa Shell Script, Bukan Tool Lain?

Ada banyak tool automation — Makefile, Task, Just, bahkan Taskfile.yml. Semuanya valid. Tapi shell script punya keunggulan yang susah ditandingi:

  • Ada di mana-mana. Bash ada di Linux, macOS, WSL. Kamu nggak perlu install apa-apa.
  • Composable. Script bisa panggil script lain, pipe output, redirect error.
  • Debuggable. bash -x script.sh langsung kasih trace tiap perintah yang jalan.
  • Version-controllable. Simpan di repo, semua tim pakai versi yang sama.

Gotcha pertama yang gue temuin: jangan pakai #!/bin/sh kalau kamu mau fitur Bash modern kayak array atau [[ ]]. Selalu mulai dengan #!/usr/bin/env bash dan tambahkan:

set -euo pipefail

-e = exit kalau ada perintah yang gagal. -u = error kalau variabel belum di-set. -o pipefail = pipe gagal kalau salah satu bagiannya gagal. Tiga flag ini menyelamatkan kamu dari bug yang susah dideteksi.


Script Pertama: Dev Environment Starter

Ini script yang gue pakai tiap pagi. Satu perintah, semua service jalan.

#!/usr/bin/env bash
set -euo pipefail

# dev-start.sh — jalanin semua yang dibutuhin buat development

PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
LOG_DIR="$PROJECT_ROOT/.logs"

mkdir -p "$LOG_DIR"

echo "[dev] Starting development environment..."

# 1. Pastiin dependencies up to date
echo "[dev] Checking dependencies..."
npm install --silent

# 2. Jalanin database migration kalau ada yang pending
echo "[dev] Running migrations..."
npm run migrate 2>&1 | tee "$LOG_DIR/migrate.log"

# 3. Start backend di background
echo "[dev] Starting backend on port 3001..."
npm run dev:backend > "$LOG_DIR/backend.log" 2>&1 &
BACKEND_PID=$!
echo $BACKEND_PID > "$LOG_DIR/backend.pid"

# 4. Tunggu backend siap (health check sederhana)
echo "[dev] Waiting for backend..."
for i in {1..10}; do
  if curl -sf http://localhost:3001/health > /dev/null 2>&1; then
    echo "[dev] Backend ready!"
    break
  fi
  sleep 1
done

# 5. Start frontend
echo "[dev] Starting frontend on port 3000..."
npm run dev:frontend > "$LOG_DIR/frontend.log" 2>&1 &
FRONTEND_PID=$!
echo $FRONTEND_PID > "$LOG_DIR/frontend.pid"

echo ""
echo "✓ Dev environment running"
echo "  Backend:  http://localhost:3001"
echo "  Frontend: http://localhost:3000"
echo "  Logs:     $LOG_DIR/"
echo ""
echo "Run './dev-stop.sh' to stop all services."

Dan pasangannya, dev-stop.sh:

#!/usr/bin/env bash
set -euo pipefail

PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
LOG_DIR="$PROJECT_ROOT/.logs"

for service in backend frontend; do
  PID_FILE="$LOG_DIR/$service.pid"
  if [[ -f "$PID_FILE" ]]; then
    PID=$(cat "$PID_FILE")
    if kill -0 "$PID" 2>/dev/null; then
      echo "[dev] Stopping $service (PID $PID)..."
      kill "$PID"
    fi
    rm -f "$PID_FILE"
  fi
done

echo "[dev] All services stopped."

Simpan dua file ini di root project, chmod +x dev-start.sh dev-stop.sh, dan kamu udah punya dev environment yang bisa jalan satu perintah.


Script Kedua: Git Workflow Automation

Berapa kali kamu lupa pull sebelum push? Atau lupa switch branch yang bener? Script ini handle workflow git yang repetitif.

#!/usr/bin/env bash
set -euo pipefail

# new-feature.sh — buat feature branch baru dari main yang fresh

if [[ $# -eq 0 ]]; then
  echo "Usage: $0 <feature-name>"
  echo "Example: $0 user-authentication"
  exit 1
fi

FEATURE_NAME="$1"
BRANCH_NAME="feature/$FEATURE_NAME"
MAIN_BRANCH="main"

# Cek ada uncommitted changes nggak
if ! git diff --quiet || ! git diff --cached --quiet; then
  echo "Error: Kamu punya uncommitted changes. Commit atau stash dulu."
  git status --short
  exit 1
fi

# Update main
echo "[git] Updating $MAIN_BRANCH..."
git checkout "$MAIN_BRANCH"
git pull origin "$MAIN_BRANCH"

# Buat dan switch ke branch baru
echo "[git] Creating branch $BRANCH_NAME..."
git checkout -b "$BRANCH_NAME"

echo ""
echo "✓ Branch '$BRANCH_NAME' siap."
echo "  Mulai coding, terus commit seperti biasa."

Gotcha yang gue temuin di sini: kalau nama feature mengandung spasi, branch name-nya bakal rusak. Makanya script ini pakai $1 bukan $*, dan kamu perlu kasih nama pakai tanda hubung: ./new-feature.sh user-authentication, bukan ./new-feature.sh user authentication.

Kalau mau lebih aman, tambahkan validasi:

# Validasi: hanya huruf, angka, dan tanda hubung
if [[ ! "$FEATURE_NAME" =~ ^[a-z0-9-]+$ ]]; then
  echo "Error: Nama feature hanya boleh huruf kecil, angka, dan tanda hubung."
  exit 1
fi

Script Ketiga: Pre-Deploy Checklist

Ini yang paling sering diselamatin orang dari insiden production. Sebelum deploy, ada beberapa hal yang harus dicek — dan kalau kamu lakuin manual, pasti ada yang kelewat.

#!/usr/bin/env bash
set -euo pipefail

# pre-deploy.sh — validasi sebelum deploy ke production

ERRORS=0

check() {
  local description="$1"
  local command="$2"
  
  echo -n "Checking: $description... "
  if eval "$command" > /dev/null 2>&1; then
    echo "✓"
  else
    echo "✗ FAILED"
    ERRORS=$((ERRORS + 1))
  fi
}

echo "=== Pre-Deploy Checklist ==="
echo ""

# 1. Cek branch yang aktif
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
check "On main/production branch" "[[ '$CURRENT_BRANCH' == 'main' || '$CURRENT_BRANCH' == 'production' ]]"

# 2. Cek nggak ada uncommitted changes
check "No uncommitted changes" "git diff --quiet && git diff --cached --quiet"

# 3. Cek branch sudah up to date dengan remote
git fetch origin --quiet
LOCAL=$(git rev-parse HEAD)
REMOTE=$(git rev-parse origin/"$CURRENT_BRANCH")
check "Branch up to date with remote" "[[ '$LOCAL' == '$REMOTE' ]]"

# 4. Jalanin test suite
check "All tests passing" "npm test -- --passWithNoTests"

# 5. Cek environment variables yang wajib ada
REQUIRED_VARS=("DATABASE_URL" "API_SECRET" "NODE_ENV")
for var in "${REQUIRED_VARS[@]}"; do
  check "Env var $var is set" "[[ -n '${!var:-}' ]]"
done

# 6. Build production bundle
check "Production build succeeds" "npm run build"

echo ""
if [[ $ERRORS -eq 0 ]]; then
  echo "✓ Semua check passed. Aman untuk deploy."
  exit 0
else
  echo "✗ $ERRORS check gagal. Perbaiki dulu sebelum deploy."
  exit 1
fi

Script ini return exit code 1 kalau ada yang gagal — artinya kamu bisa integrate ke CI/CD pipeline dan pipeline-nya otomatis stop kalau pre-deploy check gagal.


Organisasi Script yang Nggak Bikin Pusing

Kalau kamu udah punya lebih dari 3-4 script, taruh semua di folder scripts/ di root project:

project/
├── scripts/
│   ├── dev-start.sh
│   ├── dev-stop.sh
│   ├── new-feature.sh
│   └── pre-deploy.sh
├── src/
├── package.json
└── README.md

Terus di package.json, expose script-script ini lewat npm scripts supaya tim yang nggak familiar dengan shell tetap bisa pakai:

{
  "scripts": {
    "dev": "./scripts/dev-start.sh",
    "dev:stop": "./scripts/dev-stop.sh",
    "feature": "./scripts/new-feature.sh",
    "predeploy": "./scripts/pre-deploy.sh"
  }
}

Sekarang npm run dev dan npm run predeploy bisa dipakai semua orang di tim.

Gotcha penting: kalau kamu pakai predeploy sebagai nama npm script, npm akan otomatis jalanin script itu sebelum npm run deploy. Ini fitur bawaan npm — manfaatin.


Debugging Script yang Error

Script kamu error tapi nggak tahu di mana? Dua cara paling cepat:

1. Mode verbose dengan -x:

bash -x scripts/dev-start.sh

Ini print tiap perintah sebelum dieksekusi, lengkap dengan nilai variabelnya. Sangat berguna buat trace logic yang salah.

2. Tambah set -x di bagian yang dicurigai:

set -x  # mulai trace
npm run migrate
set +x  # stop trace

Jangan lupa hapus atau comment set -x sebelum commit — output-nya verbose banget dan bikin log jadi noise.


Yang Gue Lakuin Sekarang

Semua script di atas udah gue pakai di project aktif. Setup-nya makan waktu sekitar 2 jam pertama kali, tapi setelah itu:

  • Morning setup yang biasanya 5-7 menit manual jadi 30 detik.
  • Deploy yang biasanya ada step yang kelewat sekarang selalu konsisten.
  • Onboarding developer baru lebih gampang — cukup npm run dev.

Langkah lanjutan yang bisa kamu coba:

  1. Tambahkan notifikasi. Kalau deploy selesai, kirim pesan ke Telegram atau Slack pakai curl ke webhook.
  2. Buat script backup database yang jalan otomatis sebelum migration.
  3. Integrate dengan cron untuk task yang perlu jalan terjadwal — misalnya cleanup log tiap malam.

Mulai dari satu script dulu. Script yang paling sering kamu jalanin manual — itu kandidat pertama untuk diotomasi. Shell script automation untuk development workflow bukan soal bikin sistem yang kompleks; ini soal ngapus friction kecil yang tiap hari nguras energi kamu.

Script pertama kamu nggak harus sempurna. Yang penting jalan.