exclude docs from wheel; harden bundle item handling; single-source version

This commit is contained in:
ykcheungab
2026-09-12 16:19:34 +08:00
parent 57bef85e32
commit 35af74f639
24 changed files with 508 additions and 157 deletions
+115 -47
View File
@@ -30,7 +30,7 @@ version = {attr = "orisys.__version__"}
""".lstrip()
def _make_repo(tmp_path: Path, *, version: str = "0.5.2", with_git: bool = False) -> Path:
def _make_repo(tmp_path: Path, *, version: str = "1.2.3", with_git: bool = False) -> Path:
(tmp_path / "pyproject.toml").write_text(PYPROJECT, encoding="utf-8")
package = tmp_path / "src" / "orisys"
package.mkdir(parents=True)
@@ -63,16 +63,16 @@ class _FakeResponse:
def test_wheel_version_parsing():
assert version_mod.wheel_version(Path("orisys-0.5.2-cp310-cp310-win_amd64.whl")) == "0.5.2"
assert version_mod.wheel_version(Path("orisys-1.2.3-cp310-cp310-win_amd64.whl")) == "1.2.3"
assert version_mod.wheel_version(Path("orisys-1.0.0-1-cp312-abi3-manylinux_2_28_x86_64.whl")) == "1.0.0"
assert version_mod.wheel_version(Path("something-else.whl")) is None
def test_sdk_versions_are_numerically_sorted(tmp_path):
for name in ("0.9.0", "0.4.10", "0.5.2"):
for name in ("0.9.0", "0.4.10", "1.2.3"):
(tmp_path / "SDK" / name).mkdir(parents=True)
(tmp_path / "SDK" / "not-a-version").mkdir()
assert version_mod.sdk_versions(tmp_path)[:3] == ["0.4.10", "0.5.2", "0.9.0"]
assert version_mod.sdk_versions(tmp_path)[:3] == ["0.4.10", "0.9.0", "1.2.3"]
def test_sdk_versions_empty_without_sdk_dir(tmp_path):
@@ -81,10 +81,10 @@ def test_sdk_versions_empty_without_sdk_dir(tmp_path):
def test_sdk_wheels_lists_only_that_version(tmp_path):
repo = _make_repo(tmp_path)
_stage_wheel(repo, "0.5.2")
_stage_wheel(repo, "1.2.3")
_stage_wheel(repo, "0.4.3")
wheels = version_mod.sdk_wheels(repo, "0.5.2")
assert [w.name for w in wheels] == ["orisys-0.5.2-cp310-cp310-win_amd64.whl"]
wheels = version_mod.sdk_wheels(repo, "1.2.3")
assert [w.name for w in wheels] == ["orisys-1.2.3-cp310-cp310-win_amd64.whl"]
def test_dynamic_version_attr_read_from_pyproject(tmp_path):
@@ -98,12 +98,12 @@ def test_dynamic_version_attr_none_when_absent(tmp_path):
def test_pypi_released_versions_parses_response(tmp_path, monkeypatch):
fake = _FakeResponse({"releases": {"0.4.2": [{"filename": "a"}], "0.5.2": [{"filename": "b"}], "0.0.0": []}})
fake = _FakeResponse({"releases": {"0.4.2": [{"filename": "a"}], "1.2.3": [{"filename": "b"}], "0.0.0": []}})
monkeypatch.setattr(version_mod.urllib.request, "urlopen", lambda *a, **k: fake)
versions, error = version_mod.pypi_released_versions()
assert error is None
# An empty file list means nothing was ever uploaded for that version.
assert versions == ["0.4.2", "0.5.2"]
assert versions == ["0.4.2", "1.2.3"]
def test_pypi_released_versions_reports_http_404_as_empty(monkeypatch):
@@ -137,7 +137,7 @@ def test_python_for_tag_uses_envs_root(tmp_path):
def test_write_report_round_trips(tmp_path):
payload = {
"version": "0.5.2",
"version": "1.2.3",
"ok": False,
"git": {"commit": "abc", "branch": "dev", "dirty": True},
"interpreter": {"version": "3.10.19", "executable": "python"},
@@ -182,43 +182,43 @@ def test_repo_state_fails_outside_git(tmp_path, capsys):
def test_version_consistency_detects_mismatch(tmp_path):
repo = _make_repo(tmp_path, version="0.5.2")
repo = _make_repo(tmp_path, version="1.2.3")
step = Preflight(PreflightOptions(version="9.9.9"), repo_root=repo)._version_consistency()
assert not step.ok
assert "0.5.2" in step.detail and "9.9.9" in step.detail
assert "1.2.3" in step.detail and "9.9.9" in step.detail
def test_version_consistency_passes_on_match(tmp_path):
repo = _make_repo(tmp_path, version="0.5.2")
step = Preflight(PreflightOptions(version="0.5.2"), repo_root=repo)._version_consistency()
repo = _make_repo(tmp_path, version="1.2.3")
step = Preflight(PreflightOptions(version="1.2.3"), repo_root=repo)._version_consistency()
assert step.ok, step.detail
def test_duplicate_guard_allows_staged_sdk_dir(tmp_path, monkeypatch):
"""A populated SDK/<version>/ is the normal preflight input, not a hazard."""
repo = _make_repo(tmp_path, version="0.5.2")
_stage_wheel(repo, "0.5.2")
repo = _make_repo(tmp_path, version="1.2.3")
_stage_wheel(repo, "1.2.3")
monkeypatch.setattr(version_mod, "git_tags", lambda root: [])
step = Preflight(PreflightOptions(version="0.5.2"), repo_root=repo)._duplicate_guard()
step = Preflight(PreflightOptions(version="1.2.3"), repo_root=repo)._duplicate_guard()
assert step.ok, step.detail
assert "staged wheel(s) to verify" in step.detail
def test_duplicate_guard_blocks_released_tag(tmp_path, monkeypatch):
repo = _make_repo(tmp_path, version="0.5.2")
_stage_wheel(repo, "0.5.2")
monkeypatch.setattr(version_mod, "git_tags", lambda root: ["v0.5.2", "v0.5.1"])
step = Preflight(PreflightOptions(version="0.5.2"), repo_root=repo)._duplicate_guard()
repo = _make_repo(tmp_path, version="1.2.3")
_stage_wheel(repo, "1.2.3")
monkeypatch.setattr(version_mod, "git_tags", lambda root: ["v1.2.3", "v0.5.1"])
step = Preflight(PreflightOptions(version="1.2.3"), repo_root=repo)._duplicate_guard()
assert not step.ok
assert "already mark 0.5.2 as released" in step.detail
assert "already mark 1.2.3 as released" in step.detail
assert "--force" in step.detail
def test_duplicate_guard_force_accepts_released_tag(tmp_path, monkeypatch):
repo = _make_repo(tmp_path, version="0.5.2")
monkeypatch.setattr(version_mod, "git_tags", lambda root: ["0.5.2"])
repo = _make_repo(tmp_path, version="1.2.3")
monkeypatch.setattr(version_mod, "git_tags", lambda root: ["1.2.3"])
step = Preflight(
PreflightOptions(version="0.5.2", force=True), repo_root=repo
PreflightOptions(version="1.2.3", force=True), repo_root=repo
)._duplicate_guard()
assert step.ok, step.detail
assert "accepted via --force" in step.detail
@@ -226,18 +226,18 @@ def test_duplicate_guard_force_accepts_released_tag(tmp_path, monkeypatch):
def test_duplicate_guard_reports_unreleased_version(tmp_path, monkeypatch):
repo = _make_repo(tmp_path, version="0.5.3")
monkeypatch.setattr(version_mod, "git_tags", lambda root: ["v0.5.2"])
monkeypatch.setattr(version_mod, "git_tags", lambda root: ["v1.2.3"])
step = Preflight(PreflightOptions(version="0.5.3"), repo_root=repo)._duplicate_guard()
assert step.ok, step.detail
assert "no local git tag marks 0.5.3" in step.detail
def test_duplicate_guard_flags_published_version(tmp_path, monkeypatch):
repo = _make_repo(tmp_path, version="0.5.2")
repo = _make_repo(tmp_path, version="1.2.3")
monkeypatch.setattr(version_mod, "git_tags", lambda root: [])
monkeypatch.setattr(version_mod, "pypi_released_versions", lambda *a, **k: (["0.5.2"], None))
monkeypatch.setattr(version_mod, "pypi_released_versions", lambda *a, **k: (["1.2.3"], None))
step = Preflight(
PreflightOptions(version="0.5.2", check_pypi=True), repo_root=repo
PreflightOptions(version="1.2.3", check_pypi=True), repo_root=repo
)._duplicate_guard()
assert not step.ok
assert "already published on PyPI" in step.detail
@@ -246,7 +246,7 @@ def test_duplicate_guard_flags_published_version(tmp_path, monkeypatch):
def test_released_tags_for_matches_version_spellings():
tags = ["v0.5.1", "0.5.1", "v0.4.3", "0.50"]
assert version_mod.released_tags_for("0.5.1", tags) == ["0.5.1", "v0.5.1"]
assert version_mod.released_tags_for("0.5.2", tags) == []
assert version_mod.released_tags_for("1.2.3", tags) == []
def test_git_tags_reads_repo_tags(tmp_path):
@@ -261,13 +261,81 @@ def test_git_tags_reads_repo_tags(tmp_path):
(repo / "f.txt").write_text("x", encoding="utf-8")
subprocess.run(["git", "add", "f.txt"], cwd=repo, check=True, capture_output=True)
subprocess.run(["git", "commit", "-qm", "init"], cwd=repo, check=True, capture_output=True)
subprocess.run(["git", "tag", "v0.5.2"], cwd=repo, check=True, capture_output=True)
subprocess.run(["git", "tag", "v1.2.3"], cwd=repo, check=True, capture_output=True)
assert "v0.5.2" in version_mod.git_tags(repo)
assert "v1.2.3" in version_mod.git_tags(repo)
def test_version_string_scan_flags_stale_literal(tmp_path):
repo = tmp_path / "repo"
(repo / "docs").mkdir(parents=True)
(repo / "docs" / "a.md").write_text("版本:0.4.0\n", encoding="utf-8")
(repo / "README.md").write_text("release 1.2.3\n", encoding="utf-8")
hits = version_mod.find_version_literals(repo, "1.2.3")
assert [(path, line) for path, line, _ in hits] == [("docs/a.md", 1)]
def test_version_string_scan_ignores_dependency_constraints(tmp_path):
repo = tmp_path / "repo"
repo.mkdir()
(repo / "docs.md").write_text(
"pip install numpy>=1.24.4 scipy==1.13 opencv-python>=4.10.0.84\n",
encoding="utf-8",
)
assert version_mod.find_version_literals(repo, "1.2.3") == []
def test_version_string_scan_honours_allowlist(tmp_path, monkeypatch):
monkeypatch.setitem(
version_mod.VERSION_STRING_ALLOWLIST, "docs.md", frozenset({"0.4.0"})
)
repo = tmp_path / "repo"
repo.mkdir()
(repo / "docs.md").write_text("历史版本:0.4.0\n", encoding="utf-8")
assert version_mod.find_version_literals(repo, "1.2.3") == []
def test_version_string_scan_skips_tests_directory(tmp_path):
repo = tmp_path / "repo"
(repo / "tests").mkdir(parents=True)
(repo / "tests" / "test_x.py").write_text('v = "0.1.2"\n', encoding="utf-8")
assert version_mod.find_version_literals(repo, "1.2.3") == []
def test_version_string_scan_accepts_current_version_and_v_prefix(tmp_path):
repo = tmp_path / "repo"
repo.mkdir()
(repo / "README.md").write_text("current 1.2.3 and tag v1.2.3\n", encoding="utf-8")
assert version_mod.find_version_literals(repo, "1.2.3") == []
def test_preflight_version_strings_step_fails_on_leftover(tmp_path):
repo = _make_repo(tmp_path, version="1.2.3")
(repo / "docs").mkdir()
(repo / "docs" / "guide.md").write_text("版本:0.4.0\n", encoding="utf-8")
step = Preflight(PreflightOptions(version="1.2.3"), repo_root=repo)._version_strings()
assert not step.ok
assert "0.4.0" in step.detail
assert "VERSION_STRING_ALLOWLIST" in step.detail
def test_preflight_version_strings_step_passes_on_clean_tree(tmp_path):
repo = _make_repo(tmp_path, version="1.2.3")
(repo / "README.md").write_text("no version literal here\n", encoding="utf-8")
step = Preflight(PreflightOptions(version="1.2.3"), repo_root=repo)._version_strings()
assert step.ok, step.detail
def test_repo_has_no_stale_version_literals():
"""The real repository must satisfy its own version-string gate."""
from common.pyproject_utils import get_version
version = get_version(REPO_ROOT)
assert version_mod.find_version_literals(REPO_ROOT, version) == []
def test_bundle_precheck_fails_when_pattern_resolves_nothing(tmp_path):
repo = _make_repo(tmp_path, version="0.5.2")
repo = _make_repo(tmp_path, version="1.2.3")
(repo / "pyproject.toml").write_text(
PYPROJECT
+ """
@@ -279,23 +347,23 @@ patterns = ["*.json"]
""",
encoding="utf-8",
)
step = Preflight(PreflightOptions(version="0.5.2"), repo_root=repo)._bundle_precheck()
step = Preflight(PreflightOptions(version="1.2.3"), repo_root=repo)._bundle_precheck()
assert not step.ok
assert "resolved 0 files" in step.detail
def test_wheel_inspection_fails_without_wheels(tmp_path):
repo = _make_repo(tmp_path, version="0.5.2")
step = Preflight(PreflightOptions(version="0.5.2"), repo_root=repo)._wheel_inspection()
repo = _make_repo(tmp_path, version="1.2.3")
step = Preflight(PreflightOptions(version="1.2.3"), repo_root=repo)._wheel_inspection()
assert not step.ok
assert "does not exist" in step.detail
def test_wheel_runtime_fails_without_video(tmp_path, monkeypatch):
repo = _make_repo(tmp_path, version="0.5.2")
_stage_wheel(repo, "0.5.2")
repo = _make_repo(tmp_path, version="1.2.3")
_stage_wheel(repo, "1.2.3")
monkeypatch.setattr("release.preflight.default_verification_video", lambda root: None)
preflight = Preflight(PreflightOptions(version="0.5.2"), repo_root=repo)
preflight = Preflight(PreflightOptions(version="1.2.3"), repo_root=repo)
preflight._discover_wheels()
step = preflight._wheel_runtime()
assert not step.ok
@@ -303,18 +371,18 @@ def test_wheel_runtime_fails_without_video(tmp_path, monkeypatch):
def test_wheel_runtime_skip_is_recorded(tmp_path):
repo = _make_repo(tmp_path, version="0.5.2")
repo = _make_repo(tmp_path, version="1.2.3")
step = Preflight(
PreflightOptions(version="0.5.2", no_runtime=True), repo_root=repo
PreflightOptions(version="1.2.3", no_runtime=True), repo_root=repo
)._wheel_runtime()
assert step.ok
assert "SKIPPED" in step.detail
def test_tests_skip_is_loud_and_recorded(tmp_path):
repo = _make_repo(tmp_path, version="0.5.2")
repo = _make_repo(tmp_path, version="1.2.3")
step = Preflight(
PreflightOptions(version="0.5.2", skip_tests=True), repo_root=repo
PreflightOptions(version="1.2.3", skip_tests=True), repo_root=repo
)._tests()
assert step.ok
assert "SKIPPED" in step.detail
@@ -322,8 +390,8 @@ def test_tests_skip_is_loud_and_recorded(tmp_path):
def test_execute_marks_failure_and_aborts(tmp_path, capsys):
repo = _make_repo(tmp_path, version="0.5.2")
preflight = Preflight(PreflightOptions(version="0.5.2"), repo_root=repo)
repo = _make_repo(tmp_path, version="1.2.3")
preflight = Preflight(PreflightOptions(version="1.2.3"), repo_root=repo)
preflight._execute(preflight._repo_state)
assert preflight.aborted
assert preflight.steps[-1].name == "repo-state"
@@ -331,7 +399,7 @@ def test_execute_marks_failure_and_aborts(tmp_path, capsys):
def test_execute_keep_going_does_not_abort(tmp_path):
repo = _make_repo(tmp_path, version="0.5.2")
preflight = Preflight(PreflightOptions(version="0.5.2", keep_going=True), repo_root=repo)
repo = _make_repo(tmp_path, version="1.2.3")
preflight = Preflight(PreflightOptions(version="1.2.3", keep_going=True), repo_root=repo)
preflight._execute(preflight._repo_state)
assert not preflight.aborted