fix(update): refresh release tags before stamping source versions

This commit is contained in:
ethernet
2026-09-24 23:29:55 -04:00
parent 7b11c1bcac
commit 97c4fa022c
3 changed files with 50 additions and 14 deletions

View File

@@ -391,19 +391,18 @@ def prune_stale_shallow_grafts(repo_root: Path) -> int:
def fetch_full_commit_graph(repo_root: Path, **run_kwargs) -> bool:
"""Turn a shallow checkout into a treeless partial clone of ``origin``.
"""Refresh release tags and fill shallow history before publishing identity.
Version identity is the nearest reachable release tag plus the commit count since
it, and a shallow boundary hides both. Only commits (and the tags that follow
them) are fetched; trees and blobs stay on demand, so this costs a fraction of a
full unshallow. Returns False when the checkout was not shallow; raises
``subprocess.CalledProcessError`` / ``TimeoutExpired`` when the fetch fails.
A full commit graph does not imply current tags, especially after a --no-tags
clone. Fetch version tags explicitly without fetching every remote branch or
replacing existing tags. Trees and blobs stay on demand. Returns whether the
checkout was unshallowed; fetch failures raise subprocess errors.
"""
if _shallow_file_path(repo_root) is None:
return False
shallow = _shallow_file_path(repo_root) is not None
subprocess.run(
["git", "fetch", "--quiet", "--unshallow", "--filter=tree:0", "origin"],
["git", "fetch", "--quiet", *(["--unshallow"] if shallow else []),
"--filter=tree:0", "--no-tags", "origin", "refs/tags/v*:refs/tags/v*"],
cwd=str(repo_root), check=True, capture_output=True, text=True,
encoding="utf-8", errors="replace", timeout=900, **run_kwargs,
)
return True
return shallow

View File

@@ -990,9 +990,8 @@ def _run_post_update_maintenance(
with _best_effort('Post-update state.db integrity check failed: %s'):
_verify_and_restore_state_dbs_post_update()
# Pre-PM installers cloned --depth 1, which hides the release tag identity is
# derived from. Fetch the commit graph before the completion line and the
# install stamp read that identity.
# Both shallow history and missing tags can hide the release identity.
# Refresh them before the completion line and install stamp read it.
try:
from hermes_cli.gitlock import fetch_full_commit_graph
from hermes_cli.update_cmd import _no_prompt_git_kwargs
@@ -1000,7 +999,7 @@ def _run_post_update_maintenance(
print(" ✓ Fetched release history (commits only) for version identity")
except (OSError, subprocess.SubprocessError) as exc:
detail = (getattr(exc, "stderr", None) or str(exc)).strip().splitlines()[-1:] or [type(exc).__name__]
print(f" ⚠ Could not fetch release history ({detail[0]}); the version shows as git.<sha> until the next update")
print(f" ⚠ Could not refresh release history ({detail[0]}); the version label may be stale or unknown until the next update")
# Seed the model-catalog cache from the checkout instead of a bot-gated, flaky fetch.
with _best_effort('Model catalog seed during update failed: %s'):

View File

@@ -108,3 +108,41 @@ def test_shallow_checkout_publishes_its_release_after_fetching_the_commit_graph(
assert stamp is not None
assert (stamp["baseVersion"], stamp["distance"]) == ("0.21.4", 3)
assert not fetch_full_commit_graph(checkout)
def test_full_checkout_refreshes_release_tags_before_publishing_identity(tmp_path):
from hermes_cli.gitlock import fetch_full_commit_graph
server = _repo(tmp_path)
env = {"HOME": str(tmp_path), "PATH": os.environ["PATH"]}
def git(root: Path, *args: str) -> str:
return subprocess.run(
["git", *args], cwd=root, env=env, check=True, capture_output=True, text=True,
).stdout.strip()
git(server, "config", "uploadpack.allowFilter", "true")
git(server, "tag", "-d", "v0.21.4")
versions = (("v2026.9.7", "0.21.1"), ("v2026.9.24", "0.21.5"))
for tag, version in versions:
(server / "pyproject.toml").write_text(f'[project]\nversion = "{version}"\n', encoding="utf-8")
git(server, "add", "pyproject.toml")
git(server, "commit", "-qm", "release")
git(server, "tag", tag)
git(server, "commit", "-q", "--allow-empty", "-m", "after release")
checkout = tmp_path / "checkout"
git(server, "clone", "-q", "--no-tags", server.as_uri(), str(checkout))
old_tag, old_version = versions[0]
git(checkout, "fetch", "-q", "origin", f"refs/tags/{old_tag}:refs/tags/{old_tag}")
commit = git(checkout, "rev-parse", "HEAD")
assert git(checkout, "rev-parse", "--is-shallow-repository") == "false"
before = write_source_stamp(checkout)
assert before is not None
assert before["baseVersion"] == old_version
fetch_full_commit_graph(checkout)
stamp = write_source_stamp(checkout)
assert stamp is not None
assert (stamp["baseVersion"], stamp["distance"]) == (versions[1][1], 1)
assert stamp["commit"] == commit == git(checkout, "rev-parse", "HEAD")