Some checks failed
CD Pipeline / deploy (push) Failing after 59s
- 建立 Gitea Actions CD pipeline (.gitea/workflows/cd.yaml) - 部署模式: rsync Python 檔案至 188 → docker restart (volume mount) - Dockerfile/requirements 變動時自動重建 Docker image - 部署通知: Telegram (開始/成功/失敗) - 健康檢查: https://mo.wooo.work/health (最多 5 次重試) - 同步最新 CLAUDE.md / ADR-008 / memory (2026-04-19) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
362 lines
12 KiB
Bash
Executable File
362 lines
12 KiB
Bash
Executable File
#!/bin/bash
|
|
# ============================================================================
|
|
# MOMO Pro System - 多環境同步腳本
|
|
# 支援開發 (DEV)、UAT、正式 (PROD) 三環境同步
|
|
# ============================================================================
|
|
|
|
set -e
|
|
|
|
# 顏色定義
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
CYAN='\033[0;36m'
|
|
NC='\033[0m'
|
|
|
|
# 環境配置
|
|
DEV_PATH="/Users/ogt/momo_pro_system"
|
|
UAT_HOST="wooo@192.168.0.110"
|
|
UAT_PATH="/home/wooo/momo_pro_system"
|
|
PROD_HOST="momo-server"
|
|
PROD_ZONE="asia-east1-a"
|
|
PROD_PATH="/home/ogt/momo_pro_system"
|
|
|
|
# 密碼檔案(避免硬編碼)
|
|
UAT_PASS_FILE="$HOME/.momo_uat_pass"
|
|
|
|
# 排除的檔案和目錄
|
|
EXCLUDES="--exclude='venv' --exclude='__pycache__' --exclude='*.pyc' --exclude='.git' --exclude='logs/*.log' --exclude='backups' --exclude='.DS_Store'"
|
|
|
|
# ============================================================================
|
|
# 工具函式
|
|
# ============================================================================
|
|
|
|
print_header() {
|
|
echo -e "\n${CYAN}========================================${NC}"
|
|
echo -e "${CYAN} $1${NC}"
|
|
echo -e "${CYAN}========================================${NC}\n"
|
|
}
|
|
|
|
print_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
|
|
print_success() { echo -e "${GREEN}[OK]${NC} $1"; }
|
|
print_warning() { echo -e "${YELLOW}[WARN]${NC} $1"; }
|
|
print_error() { echo -e "${RED}[ERROR]${NC} $1"; }
|
|
|
|
get_uat_pass() {
|
|
if [ -f "$UAT_PASS_FILE" ]; then
|
|
# V-Fix: 使用 xargs 去除可能存在的換行符號,避免 SSH 失敗
|
|
cat "$UAT_PASS_FILE" | xargs
|
|
else
|
|
read -sp "請輸入 UAT 密碼: " pass
|
|
echo "$pass"
|
|
fi
|
|
}
|
|
|
|
ssh_uat() {
|
|
local pass=$(get_uat_pass)
|
|
sshpass -p "$pass" ssh -o StrictHostKeyChecking=accept-new $UAT_HOST "$1"
|
|
}
|
|
|
|
|
|
scp_to_uat() {
|
|
local pass=$(get_uat_pass)
|
|
sshpass -p "$pass" scp -r "$1" "$UAT_HOST:$2"
|
|
}
|
|
|
|
scp_to_uat_2() {
|
|
local pass=$(get_uat_pass)
|
|
sshpass -p "$pass" scp -r "$1" "$UAT_HOST_2:$2"
|
|
}
|
|
|
|
# ============================================================================
|
|
# 環境狀態檢查
|
|
# ============================================================================
|
|
|
|
check_all_status() {
|
|
print_header "檢查所有環境狀態"
|
|
|
|
echo -e "${YELLOW}📍 開發環境 (DEV) - 本機 Mac${NC}"
|
|
echo " 路徑: $DEV_PATH"
|
|
local dev_app_mtime=$(stat -f "%Sm" -t "%Y-%m-%d %H:%M" "$DEV_PATH/app.py" 2>/dev/null || echo "N/A")
|
|
local dev_db_size=$(ls -lh "$DEV_PATH/data/momo_database.db" 2>/dev/null | awk '{print $5}' || echo "N/A")
|
|
echo " app.py 修改時間: $dev_app_mtime"
|
|
echo " 資料庫大小: $dev_db_size"
|
|
echo ""
|
|
|
|
echo -e "${YELLOW}📍 UAT 環境 - VMWare VM${NC}"
|
|
echo " 主機: $UAT_HOST"
|
|
echo " 網址: https://mo.wooo.work"
|
|
local uat_status=$(ssh_uat "systemctl is-active momo 2>/dev/null" 2>/dev/null || echo "N/A")
|
|
local uat_app_mtime=$(ssh_uat "stat -c '%y' $UAT_PATH/app.py 2>/dev/null | cut -d'.' -f1" 2>/dev/null || echo "N/A")
|
|
local uat_db_size=$(ssh_uat "ls -lh $UAT_PATH/data/momo_database.db 2>/dev/null | awk '{print \$5}'" 2>/dev/null || echo "N/A")
|
|
echo " 服務狀態: $uat_status"
|
|
echo " app.py 修改時間: $uat_app_mtime"
|
|
echo " 資料庫大小: $uat_db_size"
|
|
echo ""
|
|
|
|
echo -e "${YELLOW}📍 正式環境 (PROD) - GCP VM${NC}"
|
|
echo " 主機: $PROD_HOST ($PROD_ZONE)"
|
|
echo " 網址: https://mo.wooo.work"
|
|
local prod_status=$(gcloud compute ssh $PROD_HOST --zone=$PROD_ZONE --command="systemctl is-active momo 2>/dev/null" 2>/dev/null || echo "N/A")
|
|
local prod_app_mtime=$(gcloud compute ssh $PROD_HOST --zone=$PROD_ZONE --command="stat -c '%y' $PROD_PATH/app.py 2>/dev/null | cut -d'.' -f1" 2>/dev/null || echo "N/A")
|
|
local prod_db_size=$(gcloud compute ssh $PROD_HOST --zone=$PROD_ZONE --command="ls -lh $PROD_PATH/data/momo_database.db 2>/dev/null | awk '{print \$5}'" 2>/dev/null || echo "N/A")
|
|
echo " 服務狀態: $prod_status"
|
|
echo " app.py 修改時間: $prod_app_mtime"
|
|
echo " 資料庫大小: $prod_db_size"
|
|
}
|
|
|
|
# ============================================================================
|
|
# 同步程式碼
|
|
# ============================================================================
|
|
|
|
sync_code_to_uat() {
|
|
print_header "同步程式碼: DEV → UAT"
|
|
|
|
print_info "打包程式碼..."
|
|
cd "$DEV_PATH"
|
|
tar czf /tmp/momo_code_sync.tar.gz \
|
|
--exclude='venv' --exclude='__pycache__' --exclude='*.pyc' \
|
|
--exclude='.git' --exclude='logs/*.log' --exclude='backups' \
|
|
--exclude='.DS_Store' --exclude='data/*.db' \
|
|
*.py *.html *.md database/ static/ services/ config/ 2>/dev/null || true
|
|
|
|
print_info "上傳到 UAT..."
|
|
scp_to_uat /tmp/momo_code_sync.tar.gz "$UAT_PATH/"
|
|
|
|
print_info "在 UAT 解壓並重啟服務..."
|
|
local pass=$(get_uat_pass)
|
|
ssh_uat "cd $UAT_PATH && tar xzf momo_code_sync.tar.gz && rm momo_code_sync.tar.gz && echo \"$pass\" | sudo -S systemctl restart momo"
|
|
|
|
print_success "程式碼同步到 UAT 完成!"
|
|
}
|
|
|
|
|
|
sync_code_to_prod() {
|
|
print_header "同步程式碼: DEV → PROD"
|
|
|
|
print_info "打包程式碼..."
|
|
cd "$DEV_PATH"
|
|
tar czf /tmp/momo_code_sync.tar.gz \
|
|
--exclude='venv' --exclude='__pycache__' --exclude='*.pyc' \
|
|
--exclude='.git' --exclude='logs/*.log' --exclude='backups' \
|
|
--exclude='.DS_Store' --exclude='data/*.db' \
|
|
*.py *.html *.md database/ static/ services/ config/ 2>/dev/null || true
|
|
|
|
print_info "上傳到 PROD..."
|
|
gcloud compute scp /tmp/momo_code_sync.tar.gz $PROD_HOST:$PROD_PATH/ --zone=$PROD_ZONE
|
|
|
|
print_info "在 PROD 解壓並重啟服務..."
|
|
gcloud compute ssh $PROD_HOST --zone=$PROD_ZONE --command="cd $PROD_PATH && tar xzf momo_code_sync.tar.gz && rm momo_code_sync.tar.gz && sudo systemctl restart momo"
|
|
|
|
print_success "程式碼同步到 PROD 完成!"
|
|
}
|
|
|
|
sync_code_uat_to_prod() {
|
|
print_header "同步程式碼: UAT → PROD"
|
|
|
|
print_info "從 UAT 打包程式碼..."
|
|
ssh_uat "cd $UAT_PATH && tar czf /tmp/momo_uat_code.tar.gz --exclude='venv' --exclude='__pycache__' --exclude='*.pyc' --exclude='data/*.db' *.py *.html *.md database/ static/ services/ config/ 2>/dev/null || true"
|
|
|
|
print_info "下載到本機..."
|
|
local pass=$(get_uat_pass)
|
|
sshpass -p "$pass" scp "$UAT_HOST:/tmp/momo_uat_code.tar.gz" /tmp/
|
|
|
|
print_info "上傳到 PROD..."
|
|
gcloud compute scp /tmp/momo_uat_code.tar.gz $PROD_HOST:$PROD_PATH/ --zone=$PROD_ZONE
|
|
|
|
print_info "在 PROD 解壓並重啟服務..."
|
|
gcloud compute ssh $PROD_HOST --zone=$PROD_ZONE --command="cd $PROD_PATH && tar xzf momo_uat_code.tar.gz && rm momo_uat_code.tar.gz && sudo systemctl restart momo"
|
|
|
|
print_success "UAT 程式碼同步到 PROD 完成!"
|
|
}
|
|
|
|
# ============================================================================
|
|
# 同步資料庫
|
|
# ============================================================================
|
|
|
|
sync_db_to_uat() {
|
|
print_header "同步資料庫: DEV → UAT"
|
|
|
|
print_info "上傳資料庫到 UAT..."
|
|
scp_to_uat "$DEV_PATH/data/momo_database.db" "$UAT_PATH/data/"
|
|
|
|
print_info "重啟 UAT 服務..."
|
|
local pass=$(get_uat_pass)
|
|
ssh_uat "echo \"$pass\" | sudo -S systemctl restart momo"
|
|
|
|
print_success "資料庫同步到 UAT 完成!"
|
|
}
|
|
|
|
sync_db_to_prod() {
|
|
print_header "同步資料庫: DEV → PROD"
|
|
|
|
print_info "上傳資料庫到 PROD..."
|
|
gcloud compute scp "$DEV_PATH/data/momo_database.db" $PROD_HOST:$PROD_PATH/data/ --zone=$PROD_ZONE
|
|
|
|
print_info "重啟 PROD 服務..."
|
|
gcloud compute ssh $PROD_HOST --zone=$PROD_ZONE --command="sudo systemctl restart momo"
|
|
|
|
print_success "資料庫同步到 PROD 完成!"
|
|
}
|
|
|
|
sync_db_prod_to_dev() {
|
|
print_header "同步資料庫: PROD → DEV"
|
|
|
|
print_info "備份本機資料庫..."
|
|
cp "$DEV_PATH/data/momo_database.db" "$DEV_PATH/data/momo_database_backup_$(date +%Y%m%d_%H%M%S).db"
|
|
|
|
print_info "從 PROD 下載資料庫..."
|
|
gcloud compute scp $PROD_HOST:$PROD_PATH/data/momo_database.db "$DEV_PATH/data/" --zone=$PROD_ZONE
|
|
|
|
print_success "PROD 資料庫同步到 DEV 完成!"
|
|
}
|
|
|
|
sync_db_prod_to_uat() {
|
|
print_header "同步資料庫: PROD → UAT"
|
|
|
|
print_info "從 PROD 下載資料庫..."
|
|
gcloud compute scp $PROD_HOST:$PROD_PATH/data/momo_database.db /tmp/ --zone=$PROD_ZONE
|
|
|
|
print_info "上傳到 UAT..."
|
|
scp_to_uat /tmp/momo_database.db "$UAT_PATH/data/"
|
|
|
|
print_info "重啟 UAT 服務..."
|
|
local pass=$(get_uat_pass)
|
|
ssh_uat "echo \"$pass\" | sudo -S systemctl restart momo"
|
|
|
|
print_success "PROD 資料庫同步到 UAT 完成!"
|
|
}
|
|
|
|
# ============================================================================
|
|
# 完整同步
|
|
# ============================================================================
|
|
|
|
sync_all_to_uat() {
|
|
print_header "完整同步: DEV → UAT (程式碼 + 資料庫)"
|
|
sync_code_to_uat
|
|
sync_db_to_uat
|
|
print_success "完整同步到 UAT 完成!"
|
|
}
|
|
|
|
sync_all_to_prod() {
|
|
print_header "完整同步: DEV → PROD (程式碼 + 資料庫)"
|
|
sync_code_to_prod
|
|
sync_db_to_prod
|
|
print_success "完整同步到 PROD 完成!"
|
|
}
|
|
|
|
sync_all_environments() {
|
|
print_header "同步所有環境 (DEV → UAT → PROD)"
|
|
sync_all_to_uat
|
|
sync_code_uat_to_prod
|
|
sync_db_to_prod
|
|
print_success "所有環境同步完成!"
|
|
}
|
|
|
|
# ============================================================================
|
|
# 主選單
|
|
# ============================================================================
|
|
|
|
show_menu() {
|
|
print_header "MOMO Pro System - 多環境同步工具"
|
|
echo "請選擇操作:"
|
|
echo ""
|
|
echo -e "${CYAN}狀態檢查${NC}"
|
|
echo " 1) 檢查所有環境狀態"
|
|
echo ""
|
|
echo -e "${CYAN}程式碼同步${NC}"
|
|
echo " 2) DEV → UAT (程式碼)"
|
|
echo " 3) DEV → PROD (程式碼)"
|
|
echo " 4) UAT → PROD (程式碼)"
|
|
echo ""
|
|
echo -e "${CYAN}資料庫同步${NC}"
|
|
echo " 5) DEV → UAT (資料庫)"
|
|
echo " 6) DEV → PROD (資料庫)"
|
|
echo " 7) PROD → DEV (資料庫)"
|
|
echo " 8) PROD → UAT (資料庫)"
|
|
echo ""
|
|
echo -e "${CYAN}完整同步${NC}"
|
|
echo " 9) DEV → UAT (完整)"
|
|
echo " 10) DEV → PROD (完整)"
|
|
echo " 11) 同步所有環境"
|
|
echo ""
|
|
echo " 0) 離開"
|
|
echo ""
|
|
read -p "請輸入選項 [0-11]: " choice
|
|
|
|
case $choice in
|
|
1) check_all_status ;;
|
|
2) sync_code_to_uat ;;
|
|
3) sync_code_to_prod ;;
|
|
4) sync_code_uat_to_prod ;;
|
|
5) sync_db_to_uat ;;
|
|
6) sync_db_to_prod ;;
|
|
7) sync_db_prod_to_dev ;;
|
|
8) sync_db_prod_to_uat ;;
|
|
9) sync_all_to_uat ;;
|
|
10) sync_all_to_prod ;;
|
|
11) sync_all_environments ;;
|
|
0) echo "再見!"; exit 0 ;;
|
|
*) print_error "無效選項"; show_menu ;;
|
|
esac
|
|
|
|
echo ""
|
|
read -p "按 Enter 返回選單..."
|
|
show_menu
|
|
}
|
|
|
|
# ============================================================================
|
|
# 命令列參數處理
|
|
# ============================================================================
|
|
|
|
case "$1" in
|
|
--status)
|
|
check_all_status
|
|
;;
|
|
--code-to-uat)
|
|
sync_code_to_uat
|
|
;;
|
|
--code-to-prod)
|
|
sync_code_to_prod
|
|
;;
|
|
--db-to-uat)
|
|
sync_db_to_uat
|
|
;;
|
|
--db-to-prod)
|
|
sync_db_to_prod
|
|
;;
|
|
--db-from-prod)
|
|
sync_db_prod_to_dev
|
|
;;
|
|
--full-uat)
|
|
sync_all_to_uat
|
|
;;
|
|
--full-prod)
|
|
sync_all_to_prod
|
|
;;
|
|
--sync-all)
|
|
sync_all_environments
|
|
;;
|
|
--help|-h)
|
|
echo "使用方式: $0 [選項]"
|
|
echo ""
|
|
echo "選項:"
|
|
echo " --status 檢查所有環境狀態"
|
|
echo " --code-to-uat 同步程式碼到 UAT"
|
|
echo " --code-to-prod 同步程式碼到 PROD"
|
|
echo " --db-to-uat 同步資料庫到 UAT"
|
|
echo " --db-to-prod 同步資料庫到 PROD"
|
|
echo " --db-from-prod 從 PROD 下載資料庫到 DEV"
|
|
echo " --full-uat 完整同步到 UAT"
|
|
echo " --full-prod 完整同步到 PROD"
|
|
echo " --sync-all 同步所有環境"
|
|
echo " --help, -h 顯示此說明"
|
|
echo ""
|
|
echo "不帶參數執行會顯示互動式選單"
|
|
;;
|
|
*)
|
|
show_menu
|
|
;;
|
|
esac
|