name: Unit Tests on: # 指向 v3 的 PR 与推送都跑全量单测,作为合并门禁 pull_request: branches: - v3 push: branches: - v3 # 允许手动触发 workflow_dispatch: permissions: contents: read concurrency: group: unit-tests-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true jobs: architecture: runs-on: ubuntu-latest name: Architecture Contract Gate timeout-minutes: 10 steps: - name: Checkout code uses: actions/checkout@v5 - name: Set up uv uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1 with: version: '0.12.5' python-version: '3.14' enable-cache: true cache-dependency-glob: | pyproject.toml uv.lock - name: Install dependencies run: uv sync --locked - name: Check host architecture contracts run: | uv run --locked --no-sync pytest \ tests/test_architecture_dependencies.py \ tests/test_architecture_adapter_imports.py \ tests/test_architecture_contract_baseline.py \ tests/test_architecture_baseline_cli.py -q uv run --locked --no-sync python \ scripts/architecture/baseline.py --check-host - name: Check governed Python types run: uv run --locked --no-sync mypy --config-file mypy.ini - name: Check complexity ratchet run: uv run --locked --no-sync python scripts/architecture/complexity.py - name: Check async blocking ratchet run: uv run --locked --no-sync python scripts/architecture/async_blocking.py - name: Check background task ownership run: uv run --locked --no-sync python scripts/architecture/task_ownership.py - name: Check process runtime service locators run: uv run --locked --no-sync python scripts/architecture/service_locator.py - name: Check Ruff diagnostic ratchet run: uv run --locked --no-sync python scripts/architecture/ruff_ratchet.py - name: Check mypy error ratchet run: uv run --locked --no-sync python scripts/architecture/mypy_ratchet.py - name: Check startup performance contract run: >- uv run --locked --no-sync python scripts/startup/performance.py --check --repeat 3 pytest: runs-on: ubuntu-latest name: Unit Tests (${{ matrix.shard }}) timeout-minutes: 20 strategy: fail-fast: false matrix: include: - shard: '1/4' - shard: '2/4' - shard: '3/4' - shard: '4/4' steps: - name: Checkout code uses: actions/checkout@v5 - name: Set up uv uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1 with: version: '0.12.5' python-version: '3.14' enable-cache: true cache-dependency-glob: | pyproject.toml uv.lock - name: Install dependencies run: uv sync --locked - name: Run tests timeout-minutes: 10 run: uv run --locked --no-sync python tests/run.py --shard "${{ matrix.shard }}" coverage: runs-on: ubuntu-latest name: Coverage Report timeout-minutes: 20 steps: - name: Checkout code uses: actions/checkout@v5 - name: Set up uv uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1 with: version: '0.12.5' python-version: '3.14' enable-cache: true cache-dependency-glob: | pyproject.toml uv.lock - name: Install dependencies run: uv sync --locked - name: Generate coverage reports timeout-minutes: 10 run: | uv run --locked --no-sync python -m coverage erase uv run --locked --no-sync python -m coverage run tests/run.py --serial uv run --locked --no-sync python -m coverage report uv run --locked --no-sync python -m coverage json uv run --locked --no-sync python -m coverage xml - name: Upload coverage report uses: actions/upload-artifact@v7 with: name: coverage-report path: | coverage.xml coverage.json retention-days: 7 - name: Check coverage ratchet run: uv run --locked --no-sync python scripts/architecture/coverage_ratchet.py