From 9fff01a27207940c5799321cf7c5d7478e60caf7 Mon Sep 17 00:00:00 2001 From: mac Date: Tue, 28 Jul 2026 20:24:09 +0800 Subject: [PATCH] =?UTF-8?q?v2.2.1=20=E2=80=94=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=81=A5=E5=BA=B7=E6=A3=80=E6=9F=A5=20+=20Gitea=20Actions=20CI?= =?UTF-8?q?/CD=20=E8=87=AA=E5=8A=A8=E9=83=A8=E7=BD=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitea/workflows/deploy.yml | 132 ++++++++++++++++++++++++++++++++++++ app.py | 7 ++ 2 files changed, 139 insertions(+) create mode 100644 .gitea/workflows/deploy.yml diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml new file mode 100644 index 0000000..bf17ab5 --- /dev/null +++ b/.gitea/workflows/deploy.yml @@ -0,0 +1,132 @@ +name: Deploy + +on: + push: + branches: [main] + +jobs: + deploy: + runs-on: prod-deploy + env: + DEPLOY_BASE: /opt/ziwei-power + REPO_URL: https://qiukai:${{ secrets.DEPLOY_TOKEN }}@git.qiukai.me/qiukai/ziwei-power.git + SERVICE_NAME: ziwei-power + steps: + - name: Clone and deploy + run: | + set -e + RELEASE_ID="${{ github.sha }}" + RELEASE_DIR="${DEPLOY_BASE}/releases/${RELEASE_ID}" + CLONE_DIR="/tmp/zw-deploy-${RELEASE_ID}" + + echo "=== 1. Clone repository ===" + rm -rf "${CLONE_DIR}" + git clone --depth 1 --branch main "${REPO_URL}" "${CLONE_DIR}" + + echo "=== 2. Prepare release directory ===" + rm -rf "${RELEASE_DIR}" + mkdir -p "${RELEASE_DIR}" + + # Copy repo content to release dir (exclude .git, .env, venv, data) + rsync -a --exclude='.git' \ + --exclude='.env' \ + --exclude='.env.local' \ + --exclude='.venv' \ + --exclude='data/' \ + --exclude='__pycache__' \ + --exclude='.gitea' \ + "${CLONE_DIR}/" "${RELEASE_DIR}/" + + echo "=== 2.5 Ensure .env secrets ===" + mkdir -p "${DEPLOY_BASE}/shared" + SHARED_ENV="${DEPLOY_BASE}/shared/.env" + touch "${SHARED_ENV}" + ensure_env_var() { + key="$1"; val="$2" + if [ -z "$val" ]; then + echo " ! ${key} 未提供(CI secret 为空),跳过写入" + return + fi + if ! grep -q "^${key}=" "${SHARED_ENV}"; then + echo "${key}=${val}" >> "${SHARED_ENV}" + echo " + 已写入 ${key}" + else + echo " = ${key} 已存在,保留原值" + fi + } + ensure_env_var "SECRET_KEY" "${{ secrets.ZW_SECRET_KEY }}" + + echo "=== 3. Link shared resources ===" + mkdir -p "${RELEASE_DIR}/data" + # .env from shared dir (not in git) + ln -sfn "${DEPLOY_BASE}/shared/.env" "${RELEASE_DIR}/.env" + + # Database dir symlink to persist across releases + DB_DIR="$HOME/.workbuddy/data/ziwei-power" + mkdir -p "${DB_DIR}" + ln -sfn "${DB_DIR}" "${RELEASE_DIR}/data" + + echo "=== 4. Setup Python venv ===" + cd "${RELEASE_DIR}" + python3 -m venv .venv + . .venv/bin/activate + pip install --no-cache-dir -r requirements.txt + + echo "=== 5. Setup systemd service ===" + if ! systemctl is-enabled "${SERVICE_NAME}" >/dev/null 2>&1; then + cat > "/etc/systemd/system/${SERVICE_NAME}.service" </dev/null 2>&1; then + echo "Health check passed" + break + fi + echo "Attempt $i: waiting for service..." + sleep 2 + done + + # Final verify + if ! curl -fsS http://127.0.0.1:5058/api/health >/dev/null 2>&1; then + echo "ERROR: Health check failed after 5 attempts" + echo "Rolling back to previous release..." + PREV=$(ls -t "${DEPLOY_BASE}/releases" | sed -n '2p') + if [ -n "${PREV}" ]; then + ln -sfn "${DEPLOY_BASE}/releases/${PREV}" "${DEPLOY_BASE}/current" + systemctl restart "${SERVICE_NAME}" + echo "Rolled back to ${PREV}" + fi + exit 1 + fi + + echo "=== 8. Cleanup old releases ===" + ls -dt "${DEPLOY_BASE}"/releases/*/ | tail -n +6 | xargs -r rm -rf + + echo "=== 9. Cleanup temp ===" + rm -rf "${CLONE_DIR}" + + echo "=== Deploy complete: ${RELEASE_ID} ===" diff --git a/app.py b/app.py index e27d31a..c9782f4 100644 --- a/app.py +++ b/app.py @@ -406,6 +406,13 @@ def api_calendar_sync_all(): return jsonify({'ok': True, 'data': results, 'saved_days': saved_weeks}) +# ── 健康检查 ────────────────────────────────────────── + +@app.route('/api/health') +def api_health(): + return jsonify({'ok': True, 'service': 'ziwei-power'}) + + # ── 启动 ────────────────────────────────────────────── if __name__ == '__main__':