mirror of
https://github.com/kuhyx/utils.git
synced 2026-11-10 20:27:15 +01:00
See git-tag pins in Python requirements; cut crdt-sync 0.9.1, gatelock 0.7.2
Some checks are pending
crdt-sync pre-commit / pre-commit (push) Waiting to run
crdt-sync tests / test (3.10) (push) Waiting to run
crdt-sync tests / test (3.11) (push) Waiting to run
crdt-sync tests / test (3.12) (push) Waiting to run
dependency freshness / dependencies on newest stable (push) Waiting to run
file length / file-length (push) Waiting to run
gatelock pre-commit / pre-commit (push) Waiting to run
gatelock tests / test (3.10) (push) Waiting to run
gatelock tests / test (3.11) (push) Waiting to run
gatelock tests / test (3.12) (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
palette drift / palette (push) Waiting to run
shared gate tests / gate unit tests (push) Waiting to run
Some checks are pending
crdt-sync pre-commit / pre-commit (push) Waiting to run
crdt-sync tests / test (3.10) (push) Waiting to run
crdt-sync tests / test (3.11) (push) Waiting to run
crdt-sync tests / test (3.12) (push) Waiting to run
dependency freshness / dependencies on newest stable (push) Waiting to run
file length / file-length (push) Waiting to run
gatelock pre-commit / pre-commit (push) Waiting to run
gatelock tests / test (3.10) (push) Waiting to run
gatelock tests / test (3.11) (push) Waiting to run
gatelock tests / test (3.12) (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
palette drift / palette (push) Waiting to run
shared gate tests / gate unit tests (push) Waiting to run
**The gate could not see the shared Python libraries at all.** They are
consumed as PEP 508 direct references --
`crdt-sync @ git+https://github.com/kuhyx/utils@crdt-sync-v0.5.1#subdirectory=crdt-sync`
-- which parsed as an unpinned PyPI package that does not exist on PyPI. That
answer is undeterminable, not stale, so wake-alarm sat on gatelock-v0.4.1
against v0.7.1 and crdt-sync-v0.5.1 against v0.9.0 with a green gate. They are
git-tag dependencies now, judged the same way the Dart libraries are.
A ref that is a branch or a SHA still parses as before: there is no version
in it to compare.
The line is found textually when the key indexer cannot help. A TOML
dependency array holds bare strings with no `key =`, so these findings would
otherwise report line 0 and make the fix a search.
Both libraries also had their dependency upgrades land after their newest tag
(81d2493), so anything moving to "latest tag" would have taken the pre-upgrade
constraints. Cut 0.9.1 and 0.7.2; version bump only.
315 tests, 100% branch coverage.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CRykabMwPgDzFHcARoqpaK
This commit is contained in:
parent
2e1f3da6cf
commit
7a682a46f3
@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "crdt-sync"
|
||||
version = "0.9.0"
|
||||
version = "0.9.1"
|
||||
description = "Shared CRDT merge scheme + GitHub-Contents-API sync transport for cross-device apps"
|
||||
requires-python = ">=3.10"
|
||||
dependencies = ["requests==2.34.2"]
|
||||
|
||||
@ -12,7 +12,7 @@ from pathlib import Path
|
||||
import re
|
||||
import tomllib
|
||||
|
||||
from dep_freshness._tables import PYPI, TOOLCHAIN
|
||||
from dep_freshness._tables import GITTAG, PYPI, TOOLCHAIN
|
||||
from dep_freshness.models import Dep
|
||||
from dep_freshness.parsers._lines import index
|
||||
from dep_freshness.versions import exact_pin
|
||||
@ -24,6 +24,49 @@ _REQ = re.compile(
|
||||
)
|
||||
_SKIP_PREFIXES = ("-", "#", "git+", "http://", "https://", ".", "/")
|
||||
|
||||
# PEP 508 direct reference: `crdt-sync @ git+https://.../utils@crdt-sync-v0.9.0`
|
||||
# The shared Python libraries are consumed this way, so "latest" for them is a
|
||||
# git tag, exactly as for the Dart libraries. Without this the requirement
|
||||
# parses as an unpinned PyPI package that does not exist on PyPI, the answer
|
||||
# comes back undeterminable, and four minor versions of drift stay invisible --
|
||||
# which is how wake-alarm sat on gatelock-v0.4.1 against v0.7.1 and
|
||||
# crdt-sync-v0.5.1 against v0.9.0 with a green gate.
|
||||
_DIRECT = re.compile(
|
||||
r"^\s*(?P<name>[A-Za-z0-9][A-Za-z0-9._-]*)"
|
||||
r"(?:\[[^\]]*\])?"
|
||||
r"\s*@\s*git\+\S+?@(?P<ref>[A-Za-z0-9_.-]+-v[0-9][^\s#]*)"
|
||||
)
|
||||
|
||||
|
||||
def _direct_reference(requirement: str, path: Path, line: int) -> Dep | None:
|
||||
"""A `<name> @ git+<url>@<pkg>-vX.Y.Z` requirement as a git-tag dep."""
|
||||
match = _DIRECT.match(requirement.split(";", 1)[0].strip())
|
||||
if not match:
|
||||
return None
|
||||
ref = match.group("ref")
|
||||
package, _, version = ref.rpartition("-v")
|
||||
return Dep(
|
||||
ecosystem=GITTAG, name=package or match.group("name"), constraint=ref,
|
||||
path=path, line=line or _ref_line(path, ref), pinned=version or None,
|
||||
)
|
||||
|
||||
|
||||
def _ref_line(path: Path, ref: str) -> int:
|
||||
"""Locate `ref` textually. A TOML dependency list has no `key =` to index.
|
||||
|
||||
`"gatelock @ git+...@gatelock-v0.7.1"` is a bare string inside an array,
|
||||
so the shared key indexer finds nothing and the finding would report
|
||||
line 0 -- a fix the reader has to go looking for.
|
||||
"""
|
||||
try:
|
||||
text = path.read_text(encoding="utf-8", errors="replace")
|
||||
except OSError:
|
||||
return 0
|
||||
for number, line in enumerate(text.splitlines(), start=1):
|
||||
if ref in line:
|
||||
return number
|
||||
return 0
|
||||
|
||||
|
||||
def _split(requirement: str) -> tuple[str, str] | None:
|
||||
"""`('ruff', '==0.16.5')` from a PEP 508 requirement string."""
|
||||
@ -51,6 +94,10 @@ def parse_requirements(path: Path) -> list[Dep]:
|
||||
return []
|
||||
deps: list[Dep] = []
|
||||
for number, raw in enumerate(text.splitlines(), start=1):
|
||||
direct = _direct_reference(raw, path, number)
|
||||
if direct is not None:
|
||||
deps.append(direct)
|
||||
continue
|
||||
split = _split(raw)
|
||||
if split:
|
||||
deps.append(_dep(split[0], split[1], path, number))
|
||||
@ -81,7 +128,14 @@ def parse_pyproject(path: Path) -> list[Dep]:
|
||||
|
||||
for group in groups:
|
||||
for requirement in group:
|
||||
split = _split(str(requirement))
|
||||
text = str(requirement)
|
||||
name = _REQ.match(text.strip())
|
||||
line = lines.get(name.group("name"), 0) if name else 0
|
||||
direct = _direct_reference(text, path, line)
|
||||
if direct is not None:
|
||||
deps.append(direct)
|
||||
continue
|
||||
split = _split(text)
|
||||
if split:
|
||||
deps.append(_dep(split[0], split[1], path, lines.get(split[0], 0)))
|
||||
return deps
|
||||
|
||||
@ -140,3 +140,68 @@ dependencies:
|
||||
for d in pubspec.parse(write(tmp_path, "pubspec.yaml", body))
|
||||
}
|
||||
assert deps["dart"].line == 3
|
||||
|
||||
|
||||
DIRECT_REQ = """\
|
||||
ruff==0.16.5
|
||||
crdt-sync @ git+https://github.com/kuhyx/utils@crdt-sync-v0.9.0#subdirectory=crdt-sync
|
||||
gatelock @ git+https://github.com/kuhyx/utils@gatelock-v0.7.1#subdirectory=gatelock
|
||||
"""
|
||||
|
||||
|
||||
def test_a_git_direct_reference_is_a_git_tag_dependency(tmp_path):
|
||||
"""The shared Python libs are consumed by git tag, like the Dart ones.
|
||||
|
||||
Parsed as an ordinary requirement this is an unpinned PyPI package that
|
||||
does not exist on PyPI, so the answer is undeterminable and the drift is
|
||||
invisible -- wake-alarm sat four minor versions behind on both with a
|
||||
green gate.
|
||||
"""
|
||||
deps = {
|
||||
d.name: d
|
||||
for d in python.parse_requirements(
|
||||
write(tmp_path, "requirements.txt", DIRECT_REQ)
|
||||
)
|
||||
}
|
||||
assert deps["crdt-sync"].ecosystem == "gittag"
|
||||
assert deps["crdt-sync"].pinned == "0.9.0"
|
||||
assert deps["crdt-sync"].line == 2
|
||||
assert deps["gatelock"].pinned == "0.7.1"
|
||||
assert deps["ruff"].ecosystem == "pypi"
|
||||
|
||||
|
||||
def test_a_pyproject_git_direct_reference_is_a_git_tag_dependency(tmp_path):
|
||||
body = """\
|
||||
[project]
|
||||
name = "demo"
|
||||
requires-python = ">=3.13"
|
||||
dependencies = [
|
||||
"gatelock @ git+https://github.com/kuhyx/utils@gatelock-v0.7.1#subdirectory=gatelock",
|
||||
]
|
||||
"""
|
||||
deps = {
|
||||
d.name: d
|
||||
for d in python.parse_pyproject(write(tmp_path, "pyproject.toml", body))
|
||||
}
|
||||
assert deps["gatelock"].ecosystem == "gittag"
|
||||
assert deps["gatelock"].pinned == "0.7.1"
|
||||
assert deps["gatelock"].line == 5
|
||||
|
||||
|
||||
def test_a_plain_git_url_without_a_version_tag_is_still_skipped(tmp_path):
|
||||
"""A branch or SHA ref has no version to compare, so it stays unparsed."""
|
||||
body = "thing @ git+https://github.com/kuhyx/utils@main#subdirectory=thing\n"
|
||||
assert python.parse_requirements(
|
||||
write(tmp_path, "requirements.txt", body)
|
||||
)[0].ecosystem == "pypi"
|
||||
|
||||
|
||||
def test_an_unreadable_manifest_gives_the_direct_reference_no_line(tmp_path):
|
||||
"""`_ref_line` degrades to 0 rather than raising, like the key indexer."""
|
||||
missing = tmp_path / "gone.txt"
|
||||
assert python._ref_line(missing, "gatelock-v0.7.1") == 0
|
||||
|
||||
|
||||
def test_a_direct_reference_the_file_does_not_contain_has_no_line(tmp_path):
|
||||
path = write(tmp_path, "requirements.txt", "ruff==0.16.5\n")
|
||||
assert python._ref_line(path, "gatelock-v0.7.1") == 0
|
||||
|
||||
@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "gatelock"
|
||||
version = "0.7.1"
|
||||
version = "0.7.2"
|
||||
description = "Shared per-output lock-window + HMAC log-integrity backend for blocking-overlay apps"
|
||||
requires-python = ">=3.10"
|
||||
dependencies = [] # pure stdlib — tkinter is bundled with Python
|
||||
|
||||
Loading…
Reference in New Issue
Block a user