aad5a6b317
根因:deploy.yml notify-deploy-success job 中 python3 -c 使用多行字符串, Python 代码零缩进(column 0)破坏了 YAML literal block scalar (run: |), 导致 Gitea YAML 解析器报错 'line 114: could not find expected :', 在 DetectWorkflows 阶段被静默丢弃,push 事件无法触发 deploy。 Gitea 日志证据: ignore invalid workflow "deploy.yml": yaml: line 114: could not find expected ':' 修复:将多行 python3 -c 改为单行,避免零缩进代码行破坏 YAML 块结构。 影响范围:仅 deploy.yml,不影响 ci.yml 和 e2e.yml 验证方式:YAML 解析已通过,合并后观察 push 事件是否触发 Actions
141 lines
5.5 KiB
YAML
141 lines
5.5 KiB
YAML
# 部署管道 — moziplus v2.0
|
||
#
|
||
# 触发条件:
|
||
# - push 到 main 分支
|
||
#
|
||
# Gitea v1.23.4 限制注意:
|
||
# - 不支持 failure() 表达式
|
||
# - 不支持 concurrency / permissions
|
||
# - 部署脚本 scripts/deploy.sh,支持 --version/--rollback/--health-check
|
||
|
||
name: Deploy
|
||
|
||
on:
|
||
push:
|
||
branches: [main]
|
||
|
||
jobs:
|
||
# ── Job 1: CI(main 分支跑完整测试)─────────────────
|
||
ci:
|
||
runs-on: macos-arm64
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- name: Setup Python
|
||
run: |
|
||
python3 -m venv /tmp/ci-venv-deploy
|
||
/tmp/ci-venv-deploy/bin/pip install --quiet flake8 fastapi pydantic pyyaml uvicorn requests pytest pytest-asyncio httpx
|
||
|
||
- name: Lint
|
||
run: |
|
||
/tmp/ci-venv-deploy/bin/flake8 src/ --max-line-length=120 --extend-ignore=E501
|
||
|
||
- name: Unit & Integration Tests
|
||
run: |
|
||
/tmp/ci-venv-deploy/bin/pytest tests/ -m "not e2e" -x -q
|
||
|
||
# ── Job 2: 部署 ─────────────────────────────────────
|
||
deploy:
|
||
runs-on: macos-arm64
|
||
needs: ci
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- name: Record current version
|
||
run: |
|
||
bash scripts/deploy.sh --version || echo "No deploy history yet"
|
||
|
||
- name: Deploy
|
||
run: |
|
||
bash scripts/deploy.sh --source="$GITHUB_WORKSPACE" --target="$HOME/.sanguo_projects/sanguo_moziplus_v2" --health-check
|
||
|
||
# 回滚由 notify-deploy-failure job 检测失败后通知人工介入
|
||
|
||
# ── Job 3: 部署失败通知 ──────────────────────────────
|
||
notify-deploy-failure:
|
||
runs-on: macos-arm64
|
||
needs: [ci, deploy]
|
||
if: always()
|
||
steps:
|
||
- name: Check deploy result and notify
|
||
env:
|
||
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||
run: |
|
||
STATUS=$(curl -sf \
|
||
-H "Authorization: token $GITEA_TOKEN" \
|
||
"${{ gitea.api_url }}/repos/${{ gitea.repository }}/commits/${{ gitea.sha }}/status" \
|
||
| python3 -c "import sys,json; print(json.load(sys.stdin).get('state',''))" 2>/dev/null || echo "")
|
||
|
||
echo "Deploy status: $STATUS"
|
||
|
||
if [ "$STATUS" != "success" ]; then
|
||
echo "Deploy failed, creating Issue for manual intervention..."
|
||
|
||
# 创建 Issue 通知人工介入
|
||
curl -sf -X POST \
|
||
-H "Authorization: token $GITEA_TOKEN" \
|
||
-H "Content-Type: application/json" \
|
||
"${{ gitea.api_url }}/repos/${{ gitea.repository }}/issues" \
|
||
-d "{\"title\": \"🔴 部署失败: commit ${{ gitea.sha }}\", \"body\": \"部署失败,需人工介入排查。\\n\\n触发 commit: \`${{ gitea.sha }}\`\\n分支: main\\n\\n请检查 deploy 日志并手动处理。\", \"labels\": [\"bug\", \"priority:high\"]}" \
|
||
|| echo "Failed to create issue"
|
||
|
||
echo "Issue created for deploy failure."
|
||
else
|
||
echo "Deploy succeeded."
|
||
fi
|
||
|
||
# ── Job 4: 部署成功通知 ──────────────────────────────
|
||
notify-deploy-success:
|
||
runs-on: macos-arm64
|
||
needs: [ci, deploy]
|
||
if: always()
|
||
steps:
|
||
- name: Notify deploy success
|
||
env:
|
||
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||
DEPLOY_RESULT: ${{ needs.deploy.result }}
|
||
run: |
|
||
if [ "$DEPLOY_RESULT" != "success" ]; then
|
||
echo "Deploy did not succeed (result: $DEPLOY_RESULT), skipping success notification."
|
||
exit 0
|
||
fi
|
||
|
||
echo "Deploy succeeded, sending notification..."
|
||
|
||
API_URL="${{ gitea.api_url }}"
|
||
REPO="${{ gitea.repository }}"
|
||
COMMIT_SHA="${{ gitea.sha }}"
|
||
|
||
# 查询关联的 merged PR 作者
|
||
PR_AUTHOR=$(curl --max-time 5 -sf \
|
||
-H "Authorization: token $GITEA_TOKEN" \
|
||
"$API_URL/repos/$REPO/pulls?state=closed&sort=updated&order=desc&limit=10" | \
|
||
python3 -c "import json,sys; sha='$COMMIT_SHA'; matches=[pr['user']['login'] for pr in json.load(sys.stdin) if (pr.get('merge_commit_sha','') or '').startswith(sha) or sha.startswith(pr.get('merge_commit_sha','') or '')]; print(matches[0] if matches else '')" 2>/dev/null || echo "")
|
||
|
||
# 确定通知对象
|
||
if [ -n "$PR_AUTHOR" ]; then
|
||
NOTIFY_TO="$PR_AUTHOR"
|
||
else
|
||
# direct push 场景通知 jiangwei-infra
|
||
NOTIFY_TO="jiangwei-infra"
|
||
fi
|
||
|
||
# 发送 Mail 通知
|
||
MAIL_TITLE="[CD] 部署成功: $(echo $COMMIT_SHA | cut -c1-8)"
|
||
MAIL_TEXT="部署成功。Commit: ${COMMIT_SHA}"
|
||
|
||
curl --max-time 5 -s -X POST http://localhost:8083/api/mail \
|
||
-H "Content-Type: application/json" \
|
||
-d "{\"from\":\"system\",\"to\":\"$NOTIFY_TO\",\"title\":\"$MAIL_TITLE\",\"text\":\"$MAIL_TEXT\",\"type\":\"inform\"}" \
|
||
|| echo "Mail notification failed (non-blocking)"
|
||
|
||
# 同时通知 pangtong-fujunshi(如果 PR 作者不是 pangtong)
|
||
if [ "$NOTIFY_TO" != "pangtong-fujunshi" ]; then
|
||
curl --max-time 5 -s -X POST http://localhost:8083/api/mail \
|
||
-H "Content-Type: application/json" \
|
||
-d "{\"from\":\"system\",\"to\":\"pangtong-fujunshi\",\"title\":\"$MAIL_TITLE\",\"text\":\"$MAIL_TEXT\",\"type\":\"inform\"}" \
|
||
|| echo "Mail notification failed (non-blocking)"
|
||
fi
|
||
|
||
echo "Deploy success notification sent to: $NOTIFY_TO"
|