Skip to content

[refactor] 버튼 추가 #42

[refactor] 버튼 추가

[refactor] 버튼 추가 #42

Workflow file for this run

name: Deploy Discord Bot to Oracle Cloud
on:
push:
branches:
- main # main 브랜치에 푸시하면 자동 배포
workflow_dispatch: # GitHub에서 수동 실행도 가능
jobs:
deploy:
name: Deploy to Oracle Cloud
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup SSH
run: |
mkdir -p ~/.ssh
echo "${{ secrets.ORACLE_SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
ssh-keyscan -H ${{ secrets.ORACLE_HOST }} >> ~/.ssh/known_hosts
- name: Deploy to Oracle Cloud
run: |
ssh -o StrictHostKeyChecking=no ${{ secrets.ORACLE_USER }}@${{ secrets.ORACLE_HOST }} << 'ENDSSH'
set -e # 에러 발생 시 중단
echo "🚀 배포 시작..."
# 프로젝트 디렉토리 확인 및 이동
PROJECT_DIR="$HOME/discord-bot"
if [ ! -d "$PROJECT_DIR" ]; then
echo "❌ 디렉토리가 없습니다: $PROJECT_DIR"
echo "초기 설정이 필요합니다. 다음 명령어를 실행하세요:"
echo " mkdir -p $PROJECT_DIR"
echo " cd $PROJECT_DIR"
echo " git clone <your-repo-url> ."
exit 1
fi
cd "$PROJECT_DIR"
# 데이터베이스 파일 백업 (덮어쓰기 방지) - Git reset 전에 필수!
DB_BACKUP_DIR="$PROJECT_DIR/db_backups"
mkdir -p "$DB_BACKUP_DIR"
if [ -f "bot_data.db" ]; then
BACKUP_FILE="$DB_BACKUP_DIR/bot_data.db.backup.$(date +%Y%m%d_%H%M%S)"
echo "💾 기존 데이터베이스 백업 중: $BACKUP_FILE"
cp bot_data.db "$BACKUP_FILE" || {
echo "⚠️ 데이터베이스 백업 실패, 배포 중단"
exit 1
}
echo "✅ 백업 완료: $(du -h "$BACKUP_FILE" | cut -f1)"
else
echo "ℹ️ 기존 데이터베이스 파일이 없습니다 (신규 설치)"
fi
# Git pull (stash를 사용하여 추적되지 않는 파일 보호)
echo "📥 코드 업데이트 중..."
git fetch origin main
# 추적되지 않는 파일들을 임시로 stash (bot_data.db 보호)
# git stash는 추적되지 않는 파일도 포함할 수 있지만, --include-untracked는 신중하게 사용
# 대신 bot_data.db를 임시 위치로 이동
TEMP_DB="/tmp/bot_data.db.$$"
if [ -f "bot_data.db" ]; then
echo "🛡️ 데이터베이스 파일 임시 보호 중..."
mv bot_data.db "$TEMP_DB" || {
echo "⚠️ 데이터베이스 파일 이동 실패, 배포 중단"
exit 1
}
fi
# Git reset 실행
git reset --hard origin/main || {
echo "⚠️ Git reset 실패, 데이터베이스 복원 시도..."
if [ -f "$TEMP_DB" ]; then
mv "$TEMP_DB" bot_data.db
fi
exit 1
}
# 데이터베이스 파일 복원
if [ -f "$TEMP_DB" ]; then
echo "🔄 데이터베이스 파일 복원 중..."
mv "$TEMP_DB" bot_data.db || {
echo "⚠️ 데이터베이스 복원 실패!"
echo "💾 백업에서 복원 시도..."
LATEST_BACKUP=$(ls -t "$DB_BACKUP_DIR"/bot_data.db.backup.* 2>/dev/null | head -1)
if [ -n "$LATEST_BACKUP" ]; then
cp "$LATEST_BACKUP" bot_data.db
echo "✅ 백업에서 복원 완료"
else
echo "❌ 백업 파일도 없습니다!"
exit 1
fi
}
echo "✅ 데이터베이스 파일 복원 완료"
fi
# 오래된 백업 파일 정리 (30일 이상 된 백업 삭제)
echo "🧹 오래된 백업 파일 정리 중..."
find "$DB_BACKUP_DIR" -name "bot_data.db.backup.*" -mtime +30 -delete 2>/dev/null || true
# 가상환경 확인 및 생성
if [ ! -d "venv" ]; then
echo "📦 가상환경 생성 중..."
python3 -m venv venv
fi
# 가상환경 활성화 및 의존성 설치
echo "📦 의존성 설치 중..."
source venv/bin/activate
pip install --upgrade pip --quiet
pip install -r requirements.txt --quiet
# 봇 재시작
echo "🔄 봇 재시작 중..."
# 기존 프로세스 모두 종료 (systemd든 직접 실행이든 상관없이)
echo "🛑 기존 봇 프로세스 종료 중..."
# systemd 서비스가 있으면 중지
if systemctl list-units --type=service --all | grep -q discord-bot; then
sudo systemctl stop discord-bot 2>/dev/null || true
echo " systemd 서비스 중지 완료"
fi
# 직접 실행된 프로세스 종료
PIDS=$(pgrep -f "python.*main.py" 2>/dev/null || true)
if [ -n "$PIDS" ]; then
echo " 직접 실행 프로세스 발견: $PIDS"
echo "$PIDS" | xargs kill -TERM 2>/dev/null || true
sleep 2
# 강제 종료가 필요한 경우
REMAINING=$(pgrep -f "python.*main.py" 2>/dev/null || true)
if [ -n "$REMAINING" ]; then
echo " 강제 종료 중..."
echo "$REMAINING" | xargs kill -9 2>/dev/null || true
sleep 1
fi
fi
# 프로세스가 완전히 종료되었는지 확인
sleep 2
REMAINING_PIDS=$(pgrep -f "python.*main.py" 2>/dev/null || true)
if [ -n "$REMAINING_PIDS" ]; then
echo "⚠️ 경고: 일부 프로세스가 여전히 실행 중입니다: $REMAINING_PIDS"
echo " 강제 종료 시도..."
echo "$REMAINING_PIDS" | xargs kill -9 2>/dev/null || true
sleep 1
fi
# systemd 사용하는 경우 (권장)
if systemctl list-units --type=service --all | grep -q discord-bot; then
echo "📦 systemd 서비스로 시작 중..."
sudo systemctl start discord-bot
sleep 3
if systemctl is-active --quiet discord-bot; then
echo "✅ systemd로 봇 재시작 완료"
# 프로세스 확인
PROC_COUNT=$(pgrep -f "python.*main.py" | wc -l)
if [ "$PROC_COUNT" -eq 1 ]; then
echo "✅ 단일 프로세스 실행 확인됨"
else
echo "⚠️ 경고: 프로세스가 $PROC_COUNT개 실행 중입니다"
fi
else
echo "❌ 봇 재시작 실패. 로그 확인: sudo journalctl -u discord-bot -n 50"
exit 1
fi
else
# 직접 실행하는 경우 (fallback)
echo "⚠️ systemd 서비스가 없습니다. 직접 실행 모드로 전환..."
# 프로세스가 완전히 종료되었는지 최종 확인
FINAL_CHECK=$(pgrep -f "python.*main.py" 2>/dev/null || true)
if [ -n "$FINAL_CHECK" ]; then
echo "❌ 오류: 기존 프로세스를 종료할 수 없습니다: $FINAL_CHECK"
echo " 수동으로 종료 후 다시 시도하세요: kill -9 $FINAL_CHECK"
exit 1
fi
# 새 프로세스 시작
cd "$PROJECT_DIR"
source venv/bin/activate
nohup python main.py > bot.log 2>&1 &
sleep 3
# 프로세스 확인
NEW_PIDS=$(pgrep -f "python.*main.py" 2>/dev/null || true)
if [ -z "$NEW_PIDS" ]; then
echo "❌ 봇 프로세스를 찾을 수 없습니다. 로그 확인: tail -f bot.log"
exit 1
fi
PROC_COUNT=$(echo "$NEW_PIDS" | wc -l)
if [ "$PROC_COUNT" -eq 1 ]; then
echo "✅ 봇 재시작 완료 (직접 실행, PID: $NEW_PIDS)"
else
echo "⚠️ 경고: 프로세스가 $PROC_COUNT개 실행 중입니다: $NEW_PIDS"
echo " 로그 확인: tail -f bot.log"
fi
fi
echo "✅ 배포 완료!"
ENDSSH
- name: Deployment Status
run: |
echo "✅ 배포가 완료되었습니다!"
echo "📋 로그 확인:"
echo " - systemd: ssh ${{ secrets.ORACLE_USER }}@${{ secrets.ORACLE_HOST }} 'sudo journalctl -u discord-bot -f'"
echo " - 직접 실행: ssh ${{ secrets.ORACLE_USER }}@${{ secrets.ORACLE_HOST }} 'tail -f ~/discord-bot/bot.log'"