diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 98c045960..a12b19c16 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -197,10 +197,8 @@ jobs: enable-cache: false - name: Check lockfile run: uv lock --check - - name: Install dependencies - run: | - python -m pip install --upgrade pip - python -m pip install -e ".[dev,youtube]" + - name: Install locked dependencies + run: uv sync --locked --python "${{ matrix.python-version }}" --extra dev --extra youtube - name: Run tests # This is a fast unit-only sanity job. It measures coverage but must NOT # enforce the 84.2153% baseline: that figure (6,525 / 7,748 statements) @@ -210,8 +208,8 @@ jobs: # against the same package-wide denominator, so a full-suite floor here # would fail every run. See coverage.yml for the enforced baseline. run: >- - PYTHONPATH=src python -m pytest tests/unit/ -v --timeout=120 + PYTHONPATH=src .venv/bin/python -m pytest tests/unit/ -v --timeout=120 --cov=src/youtube_extension --cov-fail-under=0 --ignore=tests/unit/test_transcript_action_workflow.py -k "not integration" - name: Offline MCP inventory and approval regressions - run: python -m pytest tests/security/test_local_mcp_config.py tests/security/test_mcp_catalog_approval.py -q -o addopts='' + run: .venv/bin/python -m pytest tests/security/test_local_mcp_config.py tests/security/test_mcp_catalog_approval.py -q -o addopts='' diff --git a/tests/unit/test_gh_aw_workflow_governance.py b/tests/unit/test_gh_aw_workflow_governance.py index 6a34a4588..ed1cf175f 100644 --- a/tests/unit/test_gh_aw_workflow_governance.py +++ b/tests/unit/test_gh_aw_workflow_governance.py @@ -69,12 +69,27 @@ def test_coverage_workflow_is_authoritative() -> None: def test_ci_installs_the_authoritative_python_environment() -> None: workflow = _load_yaml(ROOT / ".github/workflows/ci.yml") steps = workflow["jobs"]["test"]["steps"] - install_script = next( - step for step in steps if step.get("name") == "Install dependencies" - )["run"] - test_script = next(step for step in steps if step.get("name") == "Run tests")["run"] + lock_check = next(step for step in steps if step.get("name") == "Check lockfile") + install = next( + step for step in steps if step.get("name") == "Install locked dependencies" + ) + run_tests = next(step for step in steps if step.get("name") == "Run tests") + offline_tests = next( + step for step in steps + if step.get("name") == "Offline MCP inventory and approval regressions" + ) + install_script = install["run"] + test_script = run_tests["run"] - assert 'python -m pip install -e ".[dev,youtube]"' in install_script + assert steps.index(lock_check) < steps.index(install) < steps.index(run_tests) + assert steps.index(install) < steps.index(offline_tests) + assert install_script == ( + 'uv sync --locked --python "${{ matrix.python-version }}" ' + "--extra dev --extra youtube" + ) + assert not install.get("continue-on-error", False) + assert test_script.startswith("PYTHONPATH=src .venv/bin/python -m pytest ") + assert offline_tests["run"].startswith(".venv/bin/python -m pytest ") assert "--timeout=120" in test_script assert "--cov=src/youtube_extension" in test_script # The unit-only CI job must NOT enforce the full-suite baseline: 84.2% @@ -129,7 +144,7 @@ def test_ci_runs_supported_python_matrix_with_immutable_actions() -> None: assert run_tests.get("if") is None test_script = run_tests["run"] assert test_script == ( - "PYTHONPATH=src python -m pytest tests/unit/ -v --timeout=120 " + "PYTHONPATH=src .venv/bin/python -m pytest tests/unit/ -v --timeout=120 " "--cov=src/youtube_extension --cov-fail-under=0 " '--ignore=tests/unit/test_transcript_action_workflow.py -k "not integration"' )