Files
sanguo_moziplus_v2/.gitea/workflows/ci.yml
T
claude_dev 96d6926272
CI / lint (pull_request) Successful in 19s
CI / test (pull_request) Successful in 27s
CI / frontend (pull_request) Successful in 27s
CI / notify-on-failure (pull_request) Successful in 1s
[moz] ci: venv 解释器钉 /usr/bin/python3(3.9.6)——真因是 3.14 tokenize 行为变化
修正 19a76e2 的错误归因:flake8/pycodestyle 版本无漂移(CI venv 与
本地用户站完全同版 7.3.0/2.14.0,已对拍排除)。真正差异是解释器:
- runner PATH 首位 /opt/homebrew/bin(7-5 起 python3→3.14.6)
- Python 3.12+ 重写 tokenize,pycodestyle E122 判定翻转
- 同一 toolchain_routes.py:1217:3.9 零报错 / 3.14 报 E122(实证)
- 6-25 绿色基线的 CI venv 是 python3.9(6月任务日志实证)
- 另:pydantic<2 无 3.14 wheel,test job 在 3.14 下必挂

本地预验证(/usr/bin/python3 3.9.6,CI 同款命令):
- lint: flake8 7.3.0 全量 src/ exit=0 零报错(两轮)
- test: 同款依赖 503 passed / 9 skipped / 0 failed

交付检查:docs/design 无需更新(环境策略写入 ci.yml 注释);tests
无需更新(本提交含全量预验证)。
2026-09-11 05:32:14 +08:00

135 lines
5.6 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# CI 管道 — moziplus v2.0
#
# 触发条件:
# - pull_requestopened, synchronize
# - 所有 PR 均触发 CI,确保 status check 始终产出
# (移除 paths-ignore:与分支保护 enable_status_check 冲突,
# 纯文档 PR 无 CI status 导致无法合并)
#
# 注意:只保留 pull_request 触发,避免 push + pull_request 双倍触发
#
# Gitea v1.23.4 限制注意:
# - 不支持 failure() 表达式,用 always() + shell 条件判断替代
# - 不支持 concurrency / continue-on-error / timeout-minutes / permissions
# - 无内置 GITEA_TOKEN,需手动配置 PAT 为 secret
# - runs-on 只支持单个 label
name: CI
on:
pull_request:
types: [opened, synchronize]
jobs:
# ── Job 1: Lint ──────────────────────────────────────
lint:
runs-on: macos-arm64
steps:
- uses: actions/checkout@v4
- name: Setup Python
env:
no_proxy: "*"
run: |
rm -rf /tmp/ci-venv-lint
/usr/bin/python3 -m venv /tmp/ci-venv-lint # 钉解释器:runner PATH 首位 homebrew python3=3.14tokenize 行为变化致 E122 误报);3.9.6=6月绿基线
/tmp/ci-venv-lint/bin/pip install --quiet --upgrade pip
/tmp/ci-venv-lint/bin/pip install --quiet 'flake8==7.3.0' # 锁版本(防漂移)。注:首版归因 pycodestyle 有误,真因是解释器 3.14 tokenize 变化,见本 PR 后续 commit
- name: Lint with flake8
run: |
/tmp/ci-venv-lint/bin/flake8 src/ --max-line-length=120 --extend-ignore=E501
# ── Job 2: Test ──────────────────────────────────────
test:
runs-on: macos-arm64
needs: lint
steps:
- uses: actions/checkout@v4
- name: Setup Python
env:
no_proxy: "*"
run: |
rm -rf /tmp/ci-venv-test
/usr/bin/python3 -m venv /tmp/ci-venv-test # 同钉 3.9.6pydantic<2 无 3.14 wheel;全量 503 用例本地实证绿
/tmp/ci-venv-test/bin/pip install --quiet --upgrade pip
/tmp/ci-venv-test/bin/pip install --quiet 'fastapi' 'pydantic<2' pyyaml uvicorn requests pytest pytest-asyncio httpx
- name: Debug environment
run: |
echo "PWD=$(pwd)"
echo "PYTHONPATH=$PYTHONPATH"
python3 -c "import sys; [print(p) for p in sys.path if 'sanguo' in p.lower() or 'openclaw' in p.lower()]"
grep -c "assignee = agent_id" src/daemon/toolchain_handler.py || true
grep -c "_BUSINESS_FAIL_THRESHOLD" src/daemon/toolchain_handler.py || true
- name: Run tests (exclude E2E)
run: |
PYTHONPATH=$(pwd) /tmp/ci-venv-test/bin/pytest tests/ -m "not e2e" -x -q || \
(echo '=== RETRY WITH VERBOSE ===' && \
PYTHONPATH=$(pwd) /tmp/ci-venv-test/bin/pytest tests/ -m "not e2e" -x -v 2>&1 | tail -30)
# ── Job 3: Frontend Build ───────────────────────────
frontend:
runs-on: macos-arm64
needs: lint
steps:
- uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 20
- name: Install & Build
run: |
cd src/frontend
npm ci || npm install
npm run build
# ── Job 4: CI 失败通知 ───────────────────────────────
# 使用 needs.<job>.result 直接判断,不查询 commit status API
# 根因:notify 自身的 pending status 会污染 commit status 查询结果(竞态条件)
notify-on-failure:
runs-on: macos-arm64
needs: [lint, test, frontend]
if: always()
steps:
- name: Check results and notify
env:
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
LINT_RESULT: ${{ needs.lint.result }}
TEST_RESULT: ${{ needs.test.result }}
FRONTEND_RESULT: ${{ needs.frontend.result }}
run: |
echo "Lint result: $LINT_RESULT"
echo "Test result: $TEST_RESULT"
# 只有 lint 或 test 明确失败时才发通知
if [ "$LINT_RESULT" = "failure" ] || [ "$TEST_RESULT" = "failure" ] || [ "$FRONTEND_RESULT" = "failure" ]; then
echo "CI has failures, sending notification..."
# 如果是 PR 事件,写评论通知
PR_NUMBER="${{ gitea.event.pull_request.number }}"
if [ -n "$PR_NUMBER" ]; then
# 构建失败摘要
FAILED_JOBS=""
[ "$LINT_RESULT" = "failure" ] && FAILED_JOBS="${FAILED_JOBS}lint "
[ "$TEST_RESULT" = "failure" ] && FAILED_JOBS="${FAILED_JOBS}test "
[ "$FRONTEND_RESULT" = "failure" ] && FAILED_JOBS="${FAILED_JOBS}frontend "
curl -sf -X POST \
-H "Authorization: token $GITEA_TOKEN" \
-H "Content-Type: application/json" \
"${{ gitea.api_url }}/repos/${{ gitea.repository }}/issues/${PR_NUMBER}/comments" \
-d "{\"body\": \"[CI] 失败\\n\\n分支: ${{ gitea.ref_name }}\\n触发 commit: \`${{ gitea.sha }}\`\\n失败 Job: ${FAILED_JOBS}\\n请检查 CI 日志并修复。\"}" \
|| echo "Failed to post PR comment"
echo "PR comment posted."
else
echo "Not a PR event, skipping PR comment."
fi
else
echo "No explicit failures (results: lint=$LINT_RESULT, test=$TEST_RESULT), no notification needed."
fi