From 164d6ea90a19361dc8e6daea8b099b43d504b3ca Mon Sep 17 00:00:00 2001 From: 732642856 <732642856@qq.com> Date: Wed, 24 Jun 2026 14:43:33 +0800 Subject: [PATCH] Fix CI import path isolation --- progress.md | 3 +++ task_plan.md | 3 ++- tests/conftest.py | 31 +++++++++++++++++++++++++++ tests/test_ashtakavarga_invariants.py | 2 +- tests/test_cli_smoke.py | 16 ++++++++++++++ 5 files changed, 53 insertions(+), 2 deletions(-) create mode 100644 tests/conftest.py diff --git a/progress.md b/progress.md index 99a73dad..73504edd 100644 --- a/progress.md +++ b/progress.md @@ -294,3 +294,6 @@ - 云端同步完成:本地改动已提交为 `83cc859 Productize jyotish app release surface` 并推送到远端 `codex/release-hygiene-ci`;GitHub API 确认现有 PR #6 处于 open,head 已更新到 `83cc859`。 - 修复 PR CI 云端稳定性风险:`.github/workflows/ci.yml` 将质量门命令从默认 browser profile 改为 `python scripts/run_quality_gate.py --profile quick --skip-yoga-logic`,避免 GitHub Actions 在未安装 Playwright/真实浏览器依赖时误跑 browser click smoke;完整 browser/release profile 仍作为发布前本地/手动守门。 - 验证完成:`python3 -B -m pytest tests/test_frontend_productization.py::test_quality_gate_declares_fast_browser_release_profiles tests/test_frontend_productization.py::test_release_quality_gate_tracks_untracked_product_files -q` 通过;`.github/workflows/*.yml` 均可被 PyYAML 解析。 +- GitHub Actions 复查发现 PR #6 head `062dc86` 的 `validate` 与 `test` 均失败:`validate` 失败点为 Ruff lint,`test` 失败点为全量 `python -m pytest -q`;Actions 日志下载需要仓库 admin 权限,改为本地补齐 dev 依赖后复现。 +- 修复 CI 阻断:`tests/conftest.py` 统一保证当前仓库 `scripts` 在 `sys.path[0]`,并在每个测试前清理从 `~/.workbuddy/skills/jyotish-vedic-astrology/scripts` 载入的同名模块,避免历史测试收集期污染 `prashna`;`tests/test_ashtakavarga_invariants.py` 给需要先改 `sys.path` 的脚本导入加 Ruff E402 标注。 +- 验证完成:`python3 -m ruff check scripts/run_quality_gate.py tests/test_varga_bphs.py tests/test_ashtakavarga_invariants.py tests/test_cli_smoke.py tests/test_yoga_rules_integrity.py` 通过;`python3 -m pytest -q` 全量通过;`python3 scripts/run_quality_gate.py --profile quick --skip-yoga-logic` 通过,核心质量门 198 个 pytest、npm build 与 runtime smoke 通过。 diff --git a/task_plan.md b/task_plan.md index e629e30d..7565ff41 100644 --- a/task_plan.md +++ b/task_plan.md @@ -94,4 +94,5 @@ - [x] 发布/仓库卫生第一步:release profile 新增关键产品文件未跟踪守门,28 个产品关键 untracked 文件已纳入 Git 暂存,`audit_fragments.py --strict` 当前报告 untracked_count=0。 - [x] 完整 browser/release profile 与云端分支同步检查:browser/release profile 均通过,分支 `codex/release-hygiene-ci` 已推送到远端并更新现有 PR #6。 - [x] PR CI 云端稳定性修复:`.github/workflows/ci.yml` 显式使用 `--profile quick --skip-yoga-logic`,避免 PR 环境因未安装真实浏览器/Playwright 依赖而误触 browser click smoke。 -- [ ] 下一步:检查 GitHub Actions 运行结果与发布包链路,必要时补充 release-only workflow 的 browser/release 守门。 +- [x] GitHub Actions 失败根因修复:本地复现 PR `validate` 的 Ruff E402 与 `test` 全量 pytest 的 WorkBuddy 旧 skill 路径污染,新增 pytest import guard 并修复 Ashtakavarga lint。 +- [ ] 下一步:推送 CI 修复后复查 GitHub Actions 结果;继续检查发布包链路,必要时补充 release-only workflow 的 browser/release 守门。 diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 00000000..aa374ed5 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,31 @@ +"""Pytest import guardrails for local project modules.""" + +from __future__ import annotations + +import sys +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[1] +SCRIPTS = str(ROOT / "scripts") +WORKBUDDY_SKILL_SCRIPTS = ".workbuddy/skills/jyotish-vedic-astrology/scripts" + + +def ensure_project_scripts_first() -> None: + if SCRIPTS in sys.path: + sys.path.remove(SCRIPTS) + sys.path.insert(0, SCRIPTS) + + +def remove_workbuddy_shadow_modules() -> None: + for name, module in list(sys.modules.items()): + module_file = getattr(module, "__file__", "") or "" + if WORKBUDDY_SKILL_SCRIPTS in module_file: + del sys.modules[name] + + +def pytest_runtest_setup() -> None: + remove_workbuddy_shadow_modules() + ensure_project_scripts_first() + + +ensure_project_scripts_first() diff --git a/tests/test_ashtakavarga_invariants.py b/tests/test_ashtakavarga_invariants.py index 324400d5..8f7af9bd 100644 --- a/tests/test_ashtakavarga_invariants.py +++ b/tests/test_ashtakavarga_invariants.py @@ -11,7 +11,7 @@ SCRIPTS = ROOT / "scripts" if str(SCRIPTS) not in sys.path: sys.path.insert(0, str(SCRIPTS)) -from ashtakavarga import ( +from ashtakavarga import ( # noqa: E402 ALL_SOURCES, BAV_TOTALS, EXPECTED_SAV_TOTAL, diff --git a/tests/test_cli_smoke.py b/tests/test_cli_smoke.py index 01a3fe70..238794f8 100644 --- a/tests/test_cli_smoke.py +++ b/tests/test_cli_smoke.py @@ -3,6 +3,7 @@ from __future__ import annotations +import importlib import json import subprocess import sys @@ -92,3 +93,18 @@ def test_yoga_logic_validation_import_does_not_shadow_project_modules() -> None: assert not sys.path[0].endswith(".workbuddy/skills/jyotish-vedic-astrology/scripts") sys.path[:] = before + + +def test_pytest_import_guard_restores_project_scripts_first() -> None: + before = list(sys.path) + try: + sys.path.insert(0, str(ROOT / ".workbuddy" / "skills" / "jyotish-vedic-astrology" / "scripts")) + + import tests.conftest as conftest + + importlib.reload(conftest) + assert sys.path[0] == str(ROOT / "scripts") + assert str(ROOT / "scripts") == conftest.SCRIPTS + assert conftest.WORKBUDDY_SKILL_SCRIPTS == ".workbuddy/skills/jyotish-vedic-astrology/scripts" + finally: + sys.path[:] = before