- deployment.md: 구체적 IP/VMID/LXC ID 제거 → 일반화 - stack.md: DB 호스트 정보 제거 - SPRINT-004: LXC 참조 제거 - migration: LXC ID 제거 → 역할 기반 - install.sh: 하드코딩 repo URL 제거 → RAILS_REPO_URL 또는 --repo 필수 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
240 lines
9.6 KiB
Bash
Executable File
240 lines
9.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# ═══════════════════════════════════════════════════════
|
|
# hanarang-rails installer
|
|
# 범용: 어떤 서버에서든 실행 가능
|
|
# 사용법: curl -fsSL <raw-url>/install.sh | bash
|
|
# 또는: bash install.sh [--dev]
|
|
# ═══════════════════════════════════════════════════════
|
|
set -euo pipefail
|
|
|
|
# ──────────────────────────────────────────────
|
|
# 색상 + 로그
|
|
# ──────────────────────────────────────────────
|
|
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; BLUE='\033[0;34m'; NC='\033[0m'
|
|
log() { printf "${BLUE}[rails]${NC} %s\n" "$*"; }
|
|
ok() { printf "${GREEN}[ OK ]${NC} %s\n" "$*"; }
|
|
warn() { printf "${YELLOW}[WARN ]${NC} %s\n" "$*"; }
|
|
err() { printf "${RED}[ERROR]${NC} %s\n" "$*" >&2; }
|
|
die() { err "$*"; exit 1; }
|
|
|
|
# ──────────────────────────────────────────────
|
|
# 설정
|
|
# ──────────────────────────────────────────────
|
|
REPO_URL="${RAILS_REPO_URL:-}"
|
|
INSTALL_DIR="${RAILS_INSTALL_DIR:-$(pwd)/hanarang-rails}"
|
|
DEV_MODE=false
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--dev) DEV_MODE=true; shift ;;
|
|
--dir) INSTALL_DIR="$2"; shift 2 ;;
|
|
--repo) REPO_URL="$2"; shift 2 ;;
|
|
-h|--help)
|
|
echo "hanarang-rails installer"
|
|
echo ""
|
|
echo "Usage: bash install.sh [options]"
|
|
echo ""
|
|
echo "Options:"
|
|
echo " --dev Dev 모드 (소스 clone + 개발 의존성)"
|
|
echo " --dir <path> 설치 경로 (기본: ./hanarang-rails)"
|
|
echo " --repo <url> Git repo URL"
|
|
echo " -h, --help 도움말"
|
|
echo ""
|
|
echo "Environment:"
|
|
echo " RAILS_REPO_URL Git repo URL override"
|
|
echo " RAILS_INSTALL_DIR 설치 경로 override"
|
|
echo " DATABASE_URL MariaDB 연결 문자열"
|
|
echo " DISCORD_TOKEN Discord bot token"
|
|
echo " DISCORD_GUILD_ID Discord guild ID"
|
|
exit 0
|
|
;;
|
|
*) die "알 수 없는 옵션: $1" ;;
|
|
esac
|
|
done
|
|
|
|
# ──────────────────────────────────────────────
|
|
# 1. 사전 조건 확인
|
|
# ──────────────────────────────────────────────
|
|
log "사전 조건 확인..."
|
|
|
|
check_cmd() {
|
|
if command -v "$1" &>/dev/null; then
|
|
ok "$1 $(command -v "$1")"
|
|
return 0
|
|
else
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Node.js ≥ 22
|
|
if check_cmd node; then
|
|
NODE_VER=$(node --version | sed 's/v//' | cut -d. -f1)
|
|
if [[ "$NODE_VER" -lt 22 ]]; then
|
|
die "Node.js 22 이상 필요 (현재: $(node --version))"
|
|
fi
|
|
else
|
|
die "Node.js 가 설치되지 않음. https://nodejs.org 에서 v22+ 설치"
|
|
fi
|
|
|
|
# pnpm
|
|
if ! check_cmd pnpm; then
|
|
log "pnpm 미설치. 자동 설치..."
|
|
npm install -g pnpm || die "pnpm 설치 실패"
|
|
ok "pnpm 설치 완료 ($(pnpm --version))"
|
|
fi
|
|
|
|
# git
|
|
check_cmd git || die "git 이 설치되지 않음"
|
|
|
|
# ──────────────────────────────────────────────
|
|
# 2. 소스 코드 받기
|
|
# ──────────────────────────────────────────────
|
|
if [[ -d "$INSTALL_DIR/.git" ]]; then
|
|
log "기존 설치 감지: $INSTALL_DIR"
|
|
log "git pull 로 업데이트..."
|
|
git -C "$INSTALL_DIR" pull --ff-only || warn "git pull 실패 — 수동 확인 필요"
|
|
else
|
|
if [[ -z "$REPO_URL" ]]; then
|
|
die "RAILS_REPO_URL 환경변수 또는 --repo <url> 을 지정하세요"
|
|
fi
|
|
log "repo clone: $REPO_URL → $INSTALL_DIR"
|
|
git clone "$REPO_URL" "$INSTALL_DIR" || die "git clone 실패"
|
|
fi
|
|
|
|
cd "$INSTALL_DIR"
|
|
ok "소스: $(pwd) ($(git log --oneline -1))"
|
|
|
|
# ──────────────────────────────────────────────
|
|
# 3. 의존성 설치
|
|
# ──────────────────────────────────────────────
|
|
log "의존성 설치 (pnpm install)..."
|
|
if [[ "$DEV_MODE" == true ]]; then
|
|
pnpm install || die "pnpm install 실패"
|
|
else
|
|
pnpm install --prod || die "pnpm install --prod 실패"
|
|
fi
|
|
ok "의존성 설치 완료"
|
|
|
|
# ──────────────────────────────────────────────
|
|
# 4. .env 생성 (없을 때만)
|
|
# ──────────────────────────────────────────────
|
|
if [[ ! -f .env ]]; then
|
|
if [[ -f .env.example ]]; then
|
|
cp .env.example .env
|
|
warn ".env.example → .env 복사됨. 값을 채워주세요:"
|
|
else
|
|
cat > .env << 'ENVEOF'
|
|
# hanarang-rails 환경변수
|
|
# 아래 값을 채워주세요.
|
|
|
|
# ── Database (MariaDB) ──
|
|
DATABASE_URL="mysql://rails:CHANGE_ME@localhost:3306/hanarang_rails"
|
|
|
|
# ── Discord ──
|
|
DISCORD_TOKEN=""
|
|
DISCORD_GUILD_ID=""
|
|
|
|
# ── Gitea Webhook ──
|
|
GITEA_WEBHOOK_SECRET=""
|
|
|
|
# ── Rails ──
|
|
RAILS_PORT=18800
|
|
RAILS_LOG_LEVEL=info
|
|
NODE_ENV=production
|
|
ENVEOF
|
|
warn ".env 파일 생성됨. 값을 채워주세요:"
|
|
fi
|
|
echo ""
|
|
echo " 필수:"
|
|
echo " DATABASE_URL — MariaDB 연결 문자열"
|
|
echo " DISCORD_TOKEN — Discord bot token"
|
|
echo " DISCORD_GUILD_ID — Discord 서버 ID"
|
|
echo ""
|
|
echo " 선택:"
|
|
echo " GITEA_WEBHOOK_SECRET — Gitea webhook HMAC secret"
|
|
echo " RAILS_PORT — webhook + API 포트 (기본: 18800)"
|
|
echo ""
|
|
fi
|
|
|
|
# ──────────────────────────────────────────────
|
|
# 5. 빌드 (TypeScript → dist/)
|
|
# ──────────────────────────────────────────────
|
|
if [[ -f tsconfig.json ]]; then
|
|
log "TypeScript 빌드..."
|
|
pnpm build || die "빌드 실패"
|
|
ok "빌드 완료 (dist/)"
|
|
else
|
|
warn "tsconfig.json 없음 — 빌드 스킵 (아직 Sprint 001 미완?)"
|
|
fi
|
|
|
|
# ──────────────────────────────────────────────
|
|
# 6. DB 마이그레이션 (Prisma)
|
|
# ──────────────────────────────────────────────
|
|
if [[ -f prisma/schema.prisma ]]; then
|
|
if [[ -n "${DATABASE_URL:-}" ]] || grep -q "DATABASE_URL" .env 2>/dev/null; then
|
|
log "Prisma 마이그레이션..."
|
|
pnpm prisma migrate deploy 2>/dev/null || warn "DB 마이그레이션 실패 — DATABASE_URL 을 확인하세요"
|
|
pnpm prisma generate || warn "Prisma generate 실패"
|
|
else
|
|
warn "DATABASE_URL 미설정 — DB 마이그레이션 스킵"
|
|
fi
|
|
else
|
|
warn "prisma/schema.prisma 없음 — DB 마이그레이션 스킵"
|
|
fi
|
|
|
|
# ──────────────────────────────────────────────
|
|
# 7. PM2 설정 (선택)
|
|
# ──────────────────────────────────────────────
|
|
if command -v pm2 &>/dev/null; then
|
|
if [[ ! -f ecosystem.config.js ]] && [[ ! -f ecosystem.config.cjs ]]; then
|
|
log "PM2 ecosystem 설정 생성..."
|
|
cat > ecosystem.config.cjs << 'PM2EOF'
|
|
module.exports = {
|
|
apps: [{
|
|
name: 'hanarang-rails',
|
|
script: 'dist/cli/index.js',
|
|
args: 'serve',
|
|
cwd: __dirname,
|
|
env: {
|
|
NODE_ENV: 'production',
|
|
},
|
|
max_restarts: 10,
|
|
restart_delay: 5000,
|
|
error_file: './logs/error.log',
|
|
out_file: './logs/out.log',
|
|
merge_logs: true,
|
|
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
|
|
}]
|
|
}
|
|
PM2EOF
|
|
ok "ecosystem.config.cjs 생성"
|
|
fi
|
|
echo ""
|
|
echo " PM2 로 시작하려면:"
|
|
echo " pm2 start ecosystem.config.cjs"
|
|
echo " pm2 save"
|
|
echo ""
|
|
else
|
|
warn "PM2 미설치. 수동 실행: node dist/cli/index.js serve"
|
|
fi
|
|
|
|
# ──────────────────────────────────────────────
|
|
# 8. 완료
|
|
# ──────────────────────────────────────────────
|
|
echo ""
|
|
echo "═══════════════════════════════════════════════"
|
|
printf " ${GREEN}hanarang-rails 설치 완료${NC}\n"
|
|
echo "═══════════════════════════════════════════════"
|
|
echo ""
|
|
echo " 경로: $(pwd)"
|
|
echo " 버전: $(git describe --tags --always 2>/dev/null || git log --oneline -1)"
|
|
echo ""
|
|
echo " 다음 단계:"
|
|
echo " 1. .env 파일의 값을 채우세요 (DATABASE_URL, DISCORD_TOKEN 등)"
|
|
echo " 2. DB 마이그레이션: pnpm prisma migrate deploy"
|
|
echo " 3. 시작: pm2 start ecosystem.config.cjs (또는 pnpm rails serve)"
|
|
echo " 4. 확인: pnpm rails status"
|
|
echo ""
|
|
echo " 문서: https://git.nabomhalang.co.kr/hanarang/hanarang-rails"
|
|
echo ""
|