移除: 单元测试、current-integration、backward-compat 三个 Job 保留: build (npm ci + prisma + build) → deploy (迁移 + rsync + systemctl) Co-Authored-By: Claude <noreply@anthropic.com>
129 lines
5.2 KiB
YAML
129 lines
5.2 KiB
YAML
name: Deploy API Server
|
|
|
|
on:
|
|
push:
|
|
branches: [main]
|
|
workflow_dispatch:
|
|
|
|
env:
|
|
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
|
WORKDIR: /tmp/api-server
|
|
ARTIFACT_DIR: /tmp/api-server-artifacts
|
|
|
|
jobs:
|
|
# ═══════════════════════════════════════════════════════════
|
|
# Job 1: Build
|
|
# ═══════════════════════════════════════════════════════════
|
|
build:
|
|
runs-on: prod
|
|
steps:
|
|
- name: Checkout
|
|
run: |
|
|
if [ -d $WORKDIR ]; then
|
|
cd $WORKDIR
|
|
git fetch origin && git reset --hard origin/main
|
|
else
|
|
git clone http://10.2.0.7:3000/wangdl/api-server.git $WORKDIR
|
|
fi
|
|
|
|
- name: Install dependencies
|
|
run: cd $WORKDIR && npm ci
|
|
timeout-minutes: 5
|
|
|
|
- name: Prisma generate & validate
|
|
run: |
|
|
cd $WORKDIR
|
|
npx prisma generate
|
|
npx prisma validate
|
|
|
|
- name: Build
|
|
run: cd $WORKDIR && npm run build
|
|
|
|
- name: Save build artifacts
|
|
run: |
|
|
rm -rf $ARTIFACT_DIR
|
|
mkdir -p $ARTIFACT_DIR
|
|
cp -a $WORKDIR/dist $ARTIFACT_DIR/dist
|
|
cp -a $WORKDIR/node_modules $ARTIFACT_DIR/node_modules
|
|
cp -a $WORKDIR/prisma $ARTIFACT_DIR/prisma
|
|
cp $WORKDIR/package.json $ARTIFACT_DIR/package.json
|
|
cp $WORKDIR/package-lock.json $ARTIFACT_DIR/package-lock.json
|
|
|
|
# ═══════════════════════════════════════════════════════════
|
|
# Job 2: Deploy
|
|
# ═══════════════════════════════════════════════════════════
|
|
deploy:
|
|
needs: build
|
|
runs-on: prod
|
|
steps:
|
|
- name: Restore build artifacts
|
|
run: |
|
|
cp -a $ARTIFACT_DIR/dist $WORKDIR/dist
|
|
cp -a $ARTIFACT_DIR/node_modules $WORKDIR/node_modules
|
|
cp -a $ARTIFACT_DIR/prisma $WORKDIR/prisma
|
|
|
|
- name: Ensure infrastructure
|
|
run: |
|
|
docker start mysql redis qdrant 2>/dev/null || true
|
|
sleep 2
|
|
|
|
- name: Resolve failed migrations
|
|
run: |
|
|
cd $WORKDIR
|
|
MYSQL_CMD="docker exec mysql mysql -u ${{ secrets.DB_USER }} -p${{ secrets.DB_PASSWORD }} ${{ secrets.DB_NAME }}"
|
|
FAILED=$($MYSQL_CMD -N -e "SELECT migration_name FROM _prisma_migrations WHERE logs LIKE '%failed%' LIMIT 1;" 2>/dev/null || true)
|
|
if [ -n "$FAILED" ]; then
|
|
echo "[deploy] Found failed migration: $FAILED, cleaning up..."
|
|
$MYSQL_CMD -e "DELETE FROM _prisma_migrations WHERE migration_name = '$FAILED';"
|
|
echo "[deploy] Cleaned up failed migration $FAILED"
|
|
else
|
|
echo "[deploy] No failed migrations found"
|
|
fi
|
|
|
|
- name: Apply database migrations
|
|
run: |
|
|
cd $WORKDIR
|
|
HAS_MIGS=$(npx prisma db execute --stdin <<< "SELECT COUNT(*) as cnt FROM _prisma_migrations" 2>/dev/null | grep -o '[0-9]*' | head -1 || echo "0")
|
|
if [ "$HAS_MIGS" = "0" ] || [ -z "$HAS_MIGS" ]; then
|
|
echo "[deploy] Baselining existing migrations..."
|
|
for m in prisma/migrations/*/; do
|
|
m_name=$(basename "$m")
|
|
if [ "$m_name" != "backfill_chat_scope.sql" ] && [ "$m_name" != "migration_lock.toml" ]; then
|
|
DATABASE_URL="${{ secrets.DATABASE_URL }}" npx prisma migrate resolve --applied "$m_name" 2>/dev/null || true
|
|
fi
|
|
done
|
|
echo "[deploy] Baseline complete."
|
|
fi
|
|
DATABASE_URL="${{ secrets.DATABASE_URL }}" npx prisma migrate deploy
|
|
env:
|
|
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
|
|
|
- name: Deploy API
|
|
run: |
|
|
sudo rsync -av --delete $WORKDIR/dist/ /opt/zhixi/backend/dist/
|
|
sudo rsync -av --delete $WORKDIR/node_modules/ /opt/zhixi/backend/node_modules/
|
|
sudo rsync -av $WORKDIR/prisma/ /opt/zhixi/backend/prisma/
|
|
sudo rsync -av $WORKDIR/package.json /opt/zhixi/backend/package.json
|
|
cd /opt/zhixi/backend && npx prisma generate
|
|
sudo systemctl reset-failed zhixi-api 2>/dev/null || true
|
|
sudo systemctl restart zhixi-api
|
|
sleep 3
|
|
if curl -sf http://localhost:3000/api > /dev/null 2>&1; then
|
|
echo "[deploy] API health OK"
|
|
else
|
|
echo "[deploy] Health check failed"
|
|
sudo journalctl -u zhixi-api --no-pager -n 20
|
|
exit 1
|
|
fi
|
|
|
|
- name: Deploy Worker
|
|
run: |
|
|
cd /opt/zhixi/backend
|
|
sudo cp deploy/zhixi-nest-worker.service /etc/systemd/system/
|
|
sudo systemctl daemon-reload
|
|
sudo systemctl reset-failed zhixi-nest-worker 2>/dev/null || true
|
|
sudo systemctl restart zhixi-nest-worker
|
|
sleep 5
|
|
echo "[deploy] Worker: $(sudo systemctl is-active zhixi-nest-worker)"
|
|
sudo journalctl -u zhixi-nest-worker --no-pager -n 10
|