mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-10-30 20:05:42 +08:00
ci: split architecture gate into parallel jobs and drop duplicate event policy run
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
committed by
InfinityPacer
parent
ec1c1ddcb4
commit
5d6e4b38b2
30
.github/workflows/test.yml
vendored
30
.github/workflows/test.yml
vendored
@@ -73,8 +73,6 @@ jobs:
|
||||
tests/test_architecture_egress.py \
|
||||
tests/test_architecture_event_facts.py \
|
||||
tests/test_architecture_event_policy.py -q
|
||||
uv run --locked --no-sync python \
|
||||
scripts/architecture/event_policy.py
|
||||
|
||||
- name: Check host architecture snapshot
|
||||
run: |
|
||||
@@ -84,6 +82,30 @@ jobs:
|
||||
uv run --locked --no-sync python \
|
||||
scripts/architecture/baseline.py --check-host
|
||||
|
||||
# 与 architecture job 并行执行,两者合计即完整的宿主架构门禁
|
||||
architecture-ratchets:
|
||||
needs: reuse
|
||||
if: needs.reuse.outputs.reused != 'true'
|
||||
runs-on: ubuntu-latest
|
||||
name: Architecture Ratchet Gate
|
||||
timeout-minutes: 10
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v7
|
||||
|
||||
- name: Set up uv
|
||||
uses: astral-sh/setup-uv@v10.0.1
|
||||
with:
|
||||
python-version: '3.14'
|
||||
enable-cache: true
|
||||
cache-dependency-glob: |
|
||||
pyproject.toml
|
||||
uv.lock
|
||||
|
||||
- name: Install dependencies
|
||||
run: uv sync --locked
|
||||
|
||||
- name: Check governed Python types
|
||||
run: uv run --locked --no-sync mypy --config-file mypy.ini
|
||||
|
||||
@@ -215,8 +237,8 @@ jobs:
|
||||
|
||||
proof:
|
||||
name: CI proof (${{ github.sha }})
|
||||
needs: [architecture, coverage-shard, coverage-report]
|
||||
if: github.event_name == 'pull_request' && needs.architecture.result == 'success' && needs.coverage-shard.result == 'success' && needs.coverage-report.result == 'success'
|
||||
needs: [architecture, architecture-ratchets, coverage-shard, coverage-report]
|
||||
if: github.event_name == 'pull_request' && needs.architecture.result == 'success' && needs.architecture-ratchets.result == 'success' && needs.coverage-shard.result == 'success' && needs.coverage-report.result == 'success'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 1
|
||||
steps:
|
||||
|
||||
@@ -155,7 +155,6 @@ uv run --locked --no-sync pytest \
|
||||
tests/test_architecture_egress.py \
|
||||
tests/test_architecture_event_facts.py \
|
||||
tests/test_architecture_event_policy.py -q
|
||||
uv run --locked --no-sync python scripts/architecture/event_policy.py
|
||||
uv run --locked --no-sync pytest \
|
||||
tests/test_architecture_contract_baseline.py \
|
||||
tests/test_architecture_baseline_cli.py -q
|
||||
|
||||
@@ -186,7 +186,7 @@ def test_recognize_prefers_explicit_identity(sample_meta, monkeypatch):
|
||||
- **合并检查复用**:单测/架构与 Pylint 工作流各自保留 PR、push 和手动入口。PR 完整通过全部门禁后,末尾 `CI proof (<github.sha>)` job 记录实际验证的模拟合并提交。合并 push 只在同一工作流的最新 PR 运行完整成功、证明成功、代码树完全相同、模拟合并父提交分别等于 push 前的目标分支和 PR head 时跳过重复门禁。直接 push、强制 push、基线变化、旧工作流缺少证明、失败/未完成运行或 API 异常都执行全量;不依赖提交消息,也不把 PR 的 head SHA 当作测试的合并 SHA。标准 merge/squash/rebase 仅在上述证据一致时复用。GitHub 构建与发布工作流保持独立。
|
||||
- **去重脚本验证**:`node --test .github/scripts/reuse.test.mjs` 离线覆盖成功复用及保守回退,两个检查工作流均在判定前执行。复用 job 仅持有 contents/actions/pull-requests 读取权限;没有修改分支保护设置。
|
||||
|
||||
- **门禁**:`.github/workflows/test.yml` 在指向 `v3` 的 `pull_request` / `push` 及手动触发时,从 `uv.lock` 同步环境。独立 `architecture` job 先运行宿主依赖、运行契约和基线 CLI 快速门禁;其余测试通过 `coverage run --parallel-mode tests/run.py --exclude-architecture-gate --shard N/6` 分到 6 个 job,一次执行同时验证单测并采集覆盖率;门禁已运行的架构测试不在分片中重复执行。每个分片都有独立进程和临时 `CONFIG_DIR`,不共用 SQLite 或进程级状态,由单一报告 job 合并后检查 Application 与 Domain 的固定 80% 基线。
|
||||
- **门禁**:`.github/workflows/test.yml` 在指向 `v3` 的 `pull_request` / `push` 及手动触发时,从 `uv.lock` 同步环境。宿主架构门禁分为两个并行 job,`architecture` 运行宿主依赖、运行契约、事件政策测试和基线快照,`architecture-ratchets` 运行类型、复杂度、并发、Ruff/mypy ratchet 与启动性能检查;其余测试通过 `coverage run --parallel-mode tests/run.py --exclude-architecture-gate --shard N/6` 分到 6 个 job,一次执行同时验证单测并采集覆盖率;门禁已运行的架构测试不在分片中重复执行。每个分片都有独立进程和临时 `CONFIG_DIR`,不共用 SQLite 或进程级状态,由单一报告 job 合并后检查 Application 与 Domain 的固定 80% 基线。
|
||||
- **跨仓观察**:`.github/workflows/architecture-observe.yml` 每周或手工检出官方插件仓最新 `main`,使用 `--check-plugins` 比较公开导入、Hook 和动态 API 契约。它只上传 `official-plugin-architecture-report.json`,不会自动刷新 fixture;语义变化必须人工审查后显式执行 `--write-plugins`。
|
||||
- **静态检查**:`.github/workflows/pylint.yml` 对指向 `v3` 的 PR、推送和手工触发运行 Pylint。PR/推送改动到的 Python 文件是硬门禁;`app/` 全量扫描保留为建议性 JSON 构建工件,存量告警不会掩盖或阻塞本次增量治理。
|
||||
- **PR 本地验证**:按上文「验证范围与维护者安排」选择 contributor 默认检查或已记录的维护者安排,统一处理证据复用与失败归属;需要断点、输出顺序或测试污染诊断时使用 `--serial`。确认受影响路径与零真实出站,准确标注验证范围;本地执行安排不改变 CI 的全量验证与复用合同。
|
||||
|
||||
@@ -28,7 +28,9 @@ def _step_commands(workflow: dict, job_name: str) -> str:
|
||||
def test_unit_test_workflow_has_independent_host_architecture_gate():
|
||||
"""主仓 PR 与推送必须在全量分片外快速执行宿主架构门禁。"""
|
||||
workflow = _load_workflow("test.yml")
|
||||
commands = _step_commands(workflow, "architecture")
|
||||
commands = "\n".join(
|
||||
_step_commands(workflow, job_name) for job_name in ("architecture", "architecture-ratchets")
|
||||
)
|
||||
steps = workflow["jobs"]["architecture"]["steps"]
|
||||
semantic_step = next(
|
||||
step for step in steps if step.get("name") == "Check event semantic policy"
|
||||
@@ -47,7 +49,6 @@ def test_unit_test_workflow_has_independent_host_architecture_gate():
|
||||
assert "tests/test_architecture_dependencies.py" in semantic_step["run"]
|
||||
assert "tests/test_architecture_adapter_imports.py" in semantic_step["run"]
|
||||
assert "tests/test_architecture_egress.py" in semantic_step["run"]
|
||||
assert "scripts/architecture/event_policy.py" in semantic_step["run"]
|
||||
assert "scripts/architecture/baseline.py" not in semantic_step["run"]
|
||||
assert not {
|
||||
"tests/test_architecture_dependencies.py",
|
||||
@@ -178,7 +179,7 @@ def test_coverage_jobs_parallelize_data_and_keep_one_global_ratchet() -> None:
|
||||
def test_ci_reuse_requires_successful_proof_for_every_gate() -> None:
|
||||
"""证明必须依赖全部硬门禁,推送只能通过保守判定跳过昂贵任务。"""
|
||||
for filename, gates in {
|
||||
"test.yml": ["architecture", "coverage-shard", "coverage-report"],
|
||||
"test.yml": ["architecture", "architecture-ratchets", "coverage-shard", "coverage-report"],
|
||||
"pylint.yml": ["pylint"],
|
||||
}.items():
|
||||
jobs = _load_workflow(filename)["jobs"]
|
||||
|
||||
Reference in New Issue
Block a user