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.shlangsung 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:
- Tambahkan notifikasi. Kalau deploy selesai, kirim pesan ke Telegram atau Slack pakai
curlke webhook. - Buat script backup database yang jalan otomatis sebelum migration.
- 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.