Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9e8a0cee7a | |||
| 2ffe1c466c |
+105
-2
@@ -165,7 +165,8 @@ jobs:
|
||||
run: |
|
||||
set -eu
|
||||
PYTHONPATH="$PWD/apps/api:$PWD" python3 -m pytest tests/unit -q \
|
||||
--cov=apps --cov-report=term --cov-report=xml --cov-fail-under=50
|
||||
--cov=apps --cov-report=term --cov-report=term-missing --cov-report=xml \
|
||||
--cov-fail-under=60
|
||||
|
||||
- name: Start PostgreSQL for integration tests
|
||||
shell: sh
|
||||
@@ -211,7 +212,7 @@ jobs:
|
||||
set -eu
|
||||
pip install -q pytest-rerunfailures
|
||||
PYTHONPATH="$PWD/apps/api:$PWD" python3 -m pytest tests/integration -q --timeout=60 -x --reruns 2 --reruns-delay 1 -m "not performance" \
|
||||
--cov=apps --cov-append --cov-report=term --cov-report=xml --cov-fail-under=50
|
||||
--cov=apps --cov-append --cov-report=term --cov-report=term-missing --cov-report=xml --cov-fail-under=65
|
||||
|
||||
- name: Run API performance baseline tests
|
||||
shell: sh
|
||||
@@ -262,6 +263,98 @@ jobs:
|
||||
docker rm -f "${PG_CONTAINER:-ci-pg-validate}" 2>/dev/null || true
|
||||
echo "PostgreSQL container cleaned up"
|
||||
|
||||
- name: Coverage summary
|
||||
if: always()
|
||||
shell: sh
|
||||
run: |
|
||||
set +e
|
||||
echo "=== 覆盖率汇总 ==="
|
||||
if [ -f coverage.xml ]; then
|
||||
python3 -c "
|
||||
import xml.etree.ElementTree as ET
|
||||
tree = ET.parse('coverage.xml')
|
||||
root = tree.getroot()
|
||||
line_rate = float(root.get('line-rate', 0)) * 100
|
||||
branch_rate = float(root.get('branch-rate', 0)) * 100
|
||||
lines_covered = int(root.get('lines-covered', 0))
|
||||
lines_valid = int(root.get('lines-valid', 0))
|
||||
print(f'行覆盖率: {line_rate:.2f}% ({lines_covered}/{lines_valid})')
|
||||
print(f'分支覆盖率: {branch_rate:.2f}%')
|
||||
print(f'门槛: 65%')
|
||||
print(f'状态: {"PASS ✅" if line_rate >= 65 else "FAIL ❌"}')
|
||||
"
|
||||
else
|
||||
echo "coverage.xml 不存在,跳过汇总"
|
||||
fi
|
||||
|
||||
- name: Notify CI failure
|
||||
if: failure()
|
||||
shell: sh
|
||||
run: |
|
||||
set +e
|
||||
echo "=== CI 失败通知 ==="
|
||||
|
||||
# 收集失败信息
|
||||
FAILED_JOB="Validate Code Quality And Tests"
|
||||
BRANCH="${GITHUB_REF_NAME:-unknown}"
|
||||
COMMIT="${GITHUB_SHA:0:8}"
|
||||
ACTOR="${GITHUB_ACTOR:-unknown}"
|
||||
RUN_ID="${GITHUB_RUN_ID:-unknown}"
|
||||
REPO="${GITHUB_REPOSITORY:-unknown}"
|
||||
RUN_URL="https://git.xiaoxiajianji.com/${REPO}/actions/runs/${RUN_ID}"
|
||||
|
||||
# 构造通知消息
|
||||
PAYLOAD=$(cat <<EOF
|
||||
{
|
||||
"msg_type": "interactive",
|
||||
"card": {
|
||||
"header": {
|
||||
"title": {
|
||||
"tag": "plain_text",
|
||||
"content": "❌ CI 构建失败"
|
||||
},
|
||||
"status": "red"
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"tag": "div",
|
||||
"text": {
|
||||
"tag": "lark_md",
|
||||
"content": "**任务**: ${FAILED_JOB}
|
||||
**分支**: ${BRANCH}
|
||||
**提交**: ${COMMIT}
|
||||
**提交者**: ${ACTOR}
|
||||
**Run ID**: ${RUN_ID}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "action",
|
||||
"actions": [
|
||||
{
|
||||
"tag": "button",
|
||||
"text": {
|
||||
"tag": "plain_text",
|
||||
"content": "查看失败日志"
|
||||
},
|
||||
"url": "${RUN_URL}",
|
||||
"type": "danger"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
EOF
|
||||
)
|
||||
|
||||
# 如果配置了通知 webhook 就发送
|
||||
if [ -n "${CI_NOTIFY_WEBHOOK:-}" ]; then
|
||||
curl -s -X POST -H "Content-Type: application/json" "${CI_NOTIFY_WEBHOOK}" -d "$PAYLOAD" > /dev/null 2>&1 && echo "通知已发送" || echo "通知发送失败"
|
||||
else
|
||||
echo "未配置 CI_NOTIFY_WEBHOOK,跳过通知"
|
||||
echo "如需启用,请在仓库 Settings -> Secrets and variables -> Actions 中添加 CI_NOTIFY_WEBHOOK"
|
||||
fi
|
||||
|
||||
- name: Build summary
|
||||
if: github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/main'
|
||||
shell: sh
|
||||
@@ -270,6 +363,16 @@ jobs:
|
||||
echo "Build completed successfully!"
|
||||
echo "Branch: ${GITHUB_REF_NAME}"
|
||||
echo "Commit: ${GITHUB_SHA}"
|
||||
# 输出最终覆盖率
|
||||
if [ -f coverage.xml ]; then
|
||||
python3 -c "
|
||||
import xml.etree.ElementTree as ET
|
||||
tree = ET.parse('coverage.xml')
|
||||
root = tree.getroot()
|
||||
line_rate = float(root.get('line-rate', 0)) * 100
|
||||
print(f'Total coverage: {line_rate:.2f}%')
|
||||
"
|
||||
fi
|
||||
|
||||
frontend-lint:
|
||||
name: Frontend Lint
|
||||
|
||||
@@ -37,3 +37,35 @@ extend_skip_glob = [
|
||||
"out/**",
|
||||
"coverage/**",
|
||||
]
|
||||
|
||||
[tool.coverage.run]
|
||||
source = ["apps", "packages"]
|
||||
omit = [
|
||||
"*/migrations/*",
|
||||
"*/tests/*",
|
||||
"*/test_*.py",
|
||||
"*/site-packages/*",
|
||||
"*/.cache/*",
|
||||
]
|
||||
branch = true
|
||||
|
||||
[tool.coverage.report]
|
||||
exclude_lines = [
|
||||
"pragma: no cover",
|
||||
"def __repr__",
|
||||
"if __name__ == .__main__.:",
|
||||
"raise NotImplementedError",
|
||||
"pass",
|
||||
"if TYPE_CHECKING:",
|
||||
"class .*Protocol",
|
||||
"@abstractmethod",
|
||||
"raise AssertionError",
|
||||
"raise RuntimeError",
|
||||
"if 0:",
|
||||
"if __debug__:",
|
||||
]
|
||||
show_missing = true
|
||||
skip_covered = false
|
||||
|
||||
[tool.coverage.xml]
|
||||
output = "coverage.xml"
|
||||
|
||||
Reference in New Issue
Block a user