gabriel / muse public
derive-semver-tag-from-pep440-version.md markdown
70 lines 2.9 KB
Raw
sha256:61100cca63d948098d334e1b600d8fea514568a1c26ef357bf8b6380fbd8a217 chore(timeline): remove unused RationalRate import in entity.py Human minor ⚠ breaking 8 days ago

Derive the SemVer release tag from pyproject.toml automatically

Background

pyproject.toml's version field must stay in canonical PEP 440 form (0.2.0rc15, no hyphen) because that's the literal string hatchling embeds in the built sdist's filename — publish_muse_release.sh and smoke_muse.sh both derive the tarball URL directly from it. A hyphenated form (0.2.0-rc15) was tried during the rc15 release and broke the publish script's tarball-filename lookup (hatchling normalizes it away regardless of what's written in the file), so it was reverted back to 0.2.0rc15.

Separately, muse tag add enforces strict SemVer 2.0, which requires the hyphen before a pre-release identifier (v0.2.0-rc15 is valid, v0.2.0rc15 is rejected with "Version tag must start with 'v' ... is not valid semver").

These two canonical forms are incompatible at the string level — there is no single literal that satisfies both PEP 440's canonical form and SemVer 2.0's required hyphen. pyproject.toml stays the single source of truth in PEP 440 form (see decision above); the SemVer tag needs to be derived from it, not hand-typed as a second, independently-maintained version string.

Goal

Whenever a release is tagged with muse tag add, the SemVer-hyphenated tag string is computed from pyproject.toml's PEP 440 version automatically — no one hand-types v0.2.0-rc15 and risks a typo or drift from the actual shipped version.

Suggested approach

A small helper (Python, using the already-available packaging library) that takes a PEP 440 version string and emits the SemVer-compatible tag:

from packaging.version import Version

def pep440_to_semver_tag(version_str: str) -> str:
    v = Version(version_str)
    pre = f"-{v.pre[0]}{v.pre[1]}" if v.pre else ""
    return f"v{v.major}.{v.minor}.{v.micro}{pre}"

# pep440_to_semver_tag("0.2.0rc15") -> "v0.2.0-rc15"

Wire this into the standard release flow (documented in musehub/.muse/agent.md's "Standard release flow" section) as a step after publish_muse_release.sh succeeds:

TAG=$(python3 -c "from packaging.version import Version; v=Version('$MUSE_VERSION'); pre=f'-{v.pre[0]}{v.pre[1]}' if v.pre else ''; print(f'v{v.major}.{v.minor}.{v.micro}{pre}')")
muse tag add "$TAG" --message "release $MUSE_VERSION"

Deliverables

  • [ ] Helper function (or inline one-liner, whichever fits the existing script style better) added to the release flow, not hand-typed.
  • [ ] musehub/.muse/agent.md's "Standard release flow" section updated with the new tagging step.
  • [ ] Manually QA'd once against a real release before considering this done (tag the current 0.2.0rc15 release once MWP verb QA — muse#63 — is fully signed off, per gabriel's explicit sequencing: manual QA first, then tag).

Out of scope

  • Changing pyproject.toml's format — settled as PEP 440, no hyphen, per the incident above.
  • Retroactively tagging any release prior to this ticket.
File History 1 commit
sha256:61100cca63d948098d334e1b600d8fea514568a1c26ef357bf8b6380fbd8a217 chore(timeline): remove unused RationalRate import in entity.py Human minor 8 days ago