ci: 测试类job去重——同head_sha有push流水线时PR侧跳过测试 #1551
@@ -24,6 +24,54 @@ concurrency:
|
||||
group: ci-pipeline-${{ gitea.ref }}
|
||||
cancel-in-progress: true
|
||||
jobs:
|
||||
dedupe-check:
|
||||
name: Dedup Check - skip PR tests when covered by push pipeline
|
||||
runs-on: ci-l1
|
||||
timeout-minutes: 3
|
||||
outputs:
|
||||
skip_tests: ${{ steps.dedupe.outputs.skip_tests }}
|
||||
reason: ${{ steps.dedupe.outputs.reason }}
|
||||
steps:
|
||||
- name: Decide test dedup
|
||||
id: dedupe
|
||||
shell: bash
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||
HEAD_SHA: ${{ github.sha }}
|
||||
EVENT_NAME: ${{ github.event_name }}
|
||||
run: |
|
||||
set -eu
|
||||
if [ "$EVENT_NAME" != "pull_request" ]; then
|
||||
echo "skip_tests=false" >> $GITHUB_OUTPUT
|
||||
echo "reason=push-event-tests-required" >> $GITHUB_OUTPUT
|
||||
echo "push 事件:测试照跑(部署链路门禁必需)"
|
||||
exit 0
|
||||
fi
|
||||
# 情形1:PR 已合并(合并瞬间/合并后触发的 PR run)-> 全量测试由 push 流水线承接
|
||||
MERGED=$(curl -sfH "Authorization: token $GITHUB_TOKEN" \
|
||||
"${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/pulls/${PR_NUMBER}" \
|
||||
| python3 -c "import json,sys; d=json.load(sys.stdin); print('true' if d.get('merged') else 'false')" || echo false)
|
||||
if [ "$MERGED" = "true" ]; then
|
||||
echo "skip_tests=true" >> $GITHUB_OUTPUT
|
||||
echo "reason=pr-merged-push-pipeline-covers" >> $GITHUB_OUTPUT
|
||||
echo "::warning::PR #${PR_NUMBER} 已合并,测试由合并后 push 流水线承接,PR 侧测试类 job 跳过"
|
||||
exit 0
|
||||
fi
|
||||
# 情形2:同一 head_sha 已有在跑/排队的 push 流水线(rebase/ff 合并竞态)
|
||||
DUP=$(curl -sfH "Authorization: token $GITHUB_TOKEN" \
|
||||
"${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/actions/runs?head_sha=${HEAD_SHA}&per_page=30" \
|
||||
| python3 -c "import json,sys; d=json.load(sys.stdin); runs=d if isinstance(d,list) else d.get('workflow_runs',d.get('runs',[])); hit=[r for r in runs if r.get('event')=='push' and r.get('status') in ('in_progress','queued','waiting','pending')]; print('true' if hit else 'false')" || echo false)
|
||||
if [ "$DUP" = "true" ]; then
|
||||
echo "skip_tests=true" >> $GITHUB_OUTPUT
|
||||
echo "reason=duplicate-push-run-active" >> $GITHUB_OUTPUT
|
||||
echo "::warning::同一 head_sha ${HEAD_SHA:0:8} 已有 push 流水线在跑,PR 侧测试类 job 跳过"
|
||||
exit 0
|
||||
fi
|
||||
echo "skip_tests=false" >> $GITHUB_OUTPUT
|
||||
echo "reason=no-duplicate" >> $GITHUB_OUTPUT
|
||||
echo "无重复 push 流水线,PR 侧测试照跑"
|
||||
|
||||
check-frontend-only:
|
||||
name: Check if frontend-only change
|
||||
runs-on: ci-l2
|
||||
@@ -79,6 +127,8 @@ jobs:
|
||||
python3 scripts/ci/ci_trace_report.py --service xiaoxia-saas-ci --status $STATUS --start-time "$START_TIME" || true
|
||||
|
||||
validate-code-quality:
|
||||
needs: dedupe-check
|
||||
if: always() && needs.dedupe-check.outputs.skip_tests != 'true'
|
||||
name: Validate - Code Quality
|
||||
runs-on: ci-l2
|
||||
timeout-minutes: 8
|
||||
@@ -180,6 +230,8 @@ jobs:
|
||||
python3 scripts/ci/ci_trace_report.py --service xiaoxia-saas-ci --status $STATUS --start-time "$START_TIME" || true
|
||||
|
||||
validate-type-check:
|
||||
needs: dedupe-check
|
||||
if: always() && needs.dedupe-check.outputs.skip_tests != 'true'
|
||||
name: Validate - Type Check (mypy)
|
||||
runs-on: ci-l2
|
||||
timeout-minutes: 8
|
||||
@@ -255,6 +307,8 @@ jobs:
|
||||
python3 scripts/ci/ci_trace_report.py --service xiaoxia-saas-ci --status $STATUS --start-time "$START_TIME" || true
|
||||
|
||||
validate-migration:
|
||||
needs: dedupe-check
|
||||
if: always() && needs.dedupe-check.outputs.skip_tests != 'true'
|
||||
name: Validate - Migration (alembic)
|
||||
runs-on: ci-l2
|
||||
timeout-minutes: 8
|
||||
@@ -334,8 +388,8 @@ jobs:
|
||||
python3 scripts/ci/ci_trace_report.py --service xiaoxia-saas-ci --status $STATUS --start-time "$START_TIME" || true
|
||||
|
||||
unit-tests:
|
||||
needs: check-frontend-only
|
||||
if: always() && needs.check-frontend-only.outputs.skip_backend != 'true'
|
||||
needs: [check-frontend-only, dedupe-check]
|
||||
if: always() && needs.dedupe-check.outputs.skip_tests != 'true' && needs.check-frontend-only.outputs.skip_backend != 'true'
|
||||
name: Unit Tests
|
||||
runs-on: ci-l2
|
||||
timeout-minutes: 8
|
||||
@@ -412,9 +466,10 @@ jobs:
|
||||
name: Integration Tests
|
||||
runs-on: ci-l2
|
||||
timeout-minutes: 30
|
||||
if: always() && needs.check-frontend-only.outputs.skip_backend != 'true'
|
||||
if: always() && needs.dedupe-check.outputs.skip_tests != 'true' && needs.check-frontend-only.outputs.skip_backend != 'true'
|
||||
needs:
|
||||
- check-frontend-only
|
||||
- dedupe-check
|
||||
- validate-code-quality
|
||||
- validate-type-check
|
||||
- validate-migration
|
||||
@@ -478,8 +533,8 @@ jobs:
|
||||
name: Frontend Lint
|
||||
runs-on: ci-l2
|
||||
timeout-minutes: 10
|
||||
needs: check-frontend-only
|
||||
if: needs.check-frontend-only.outputs.skip_frontend != 'true'
|
||||
needs: [check-frontend-only, dedupe-check]
|
||||
if: needs.dedupe-check.outputs.skip_tests != 'true' && needs.check-frontend-only.outputs.skip_frontend != 'true'
|
||||
steps:
|
||||
- name: Checkout code
|
||||
shell: sh
|
||||
@@ -540,8 +595,8 @@ jobs:
|
||||
name: Frontend Unit Tests
|
||||
runs-on: ci-l2
|
||||
timeout-minutes: 15
|
||||
needs: check-frontend-only
|
||||
if: always() && needs.check-frontend-only.outputs.skip_frontend != 'true'
|
||||
needs: [check-frontend-only, dedupe-check]
|
||||
if: always() && needs.dedupe-check.outputs.skip_tests != 'true' && needs.check-frontend-only.outputs.skip_frontend != 'true'
|
||||
steps:
|
||||
- name: Checkout code
|
||||
shell: sh
|
||||
|
||||
Reference in New Issue
Block a user