Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ The reference implementation runs on a Mac Studio M1 in our living room at Lake
<br>

> [!NOTE]
> [**v0.3.0-beta.1**](https://github.com/famstack-dev/famstack/releases/tag/v0.3.0-beta.1) is the current Beta.
> [**v0.3.0-beta.2**](https://github.com/famstack-dev/famstack/releases/tag/v0.3.0-beta.2) is the current Beta.
>
> The state of this project is: **It works on my machine.™**
> I gave my best it works on yours too. If it doesn't, come back and report it
Expand Down
20 changes: 19 additions & 1 deletion tests/framework/test_check_versions.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

import pytest

from tests.integration._check_versions import _normalise
from tests.integration._check_versions import _normalise, _readme_version


@pytest.mark.parametrize(
Expand Down Expand Up @@ -53,3 +53,21 @@ def test_prerelease_markers_map_to_canonical_letters():
def test_bare_marker_implies_zero():
# `1.2.0b` and `1.2.0b0` are the same release under PEP 440.
assert _normalise("1.2.0b") == "1.2.0b0"


class TestReadmeIsCheckedToo:
"""README is the first file anyone reads and was the last one nothing
verified, which is how v0.3.0-beta.2 shipped announcing beta.1 as
current. These pin that the claim is now machine-checked."""

def test_the_current_release_claim_is_found_and_parses(self):
# Reads the real README, so a reworded sentence fails here rather
# than silently disabling the check at release time.
assert _readme_version(), "README must state which release is current"

def test_it_agrees_with_the_shipped_version(self):
from tests.integration._check_versions import (
_cli_version, _pyproject_version,
)
assert _normalise(_readme_version()) == _normalise(_cli_version())
assert _normalise(_readme_version()) == _normalise(_pyproject_version())
41 changes: 38 additions & 3 deletions tests/integration/_check_versions.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,14 @@
with the tag, because the pre-tag checklist was manual and a human skipped a
line. This is that line, made mechanical.

Two sources must agree: `lib/stack/cli.py`'s VERSION constant and
`pyproject.toml`'s `project.version`. When run inside a tag build,
`GITHUB_REF_NAME` is a third — the tag itself, minus its leading `v`.
Three sources must agree: `lib/stack/cli.py`'s VERSION constant,
`pyproject.toml`'s `project.version`, and the release README.md announces as
current. When run inside a tag build, `GITHUB_REF_NAME` is a fourth — the tag
itself, minus its leading `v`.

README joined the list after v0.3.0-beta.2 shipped with a README still telling
every visitor that beta.1 was current. It is the first file anyone reads and
was the only version-bearing one nothing checked.

Exits non-zero with the mismatch spelled out. Import-free beyond stdlib so it
runs anywhere `stacktests preflight` runs.
Expand All @@ -27,6 +32,14 @@
# CLI banner read `0.3.0-beta.2`, while pyproject stores PEP 440's canonical
# `0.3.0b2`. Comparing raw strings would fail every beta release, so normalise
# to the canonical form before comparing.
# The one README sentence that makes a claim about *which* release is
# current. Other version mentions there are historical ("first tagged as
# v0.3.0-beta.1") and stay put across releases, so this deliberately matches
# the claim rather than every version-shaped string.
_README_RE = re.compile(
r"\[\*\*v(?P<label>[^\]]+)\*\*\]\((?P<url>[^)]+)\)\s+is the current Beta",
)

_PRE_RE = re.compile(
r"[-_.]?(?:(?P<a>alpha|a)|(?P<b>beta|b)|(?P<rc>rc|c|pre|preview))[-_.]?(?P<n>\d*)$",
re.IGNORECASE,
Expand Down Expand Up @@ -58,6 +71,27 @@ def _cli_version() -> str:
return match.group(1)


def _readme_version() -> str:
"""The release README tells a visitor is the current one.

Fails loudly rather than silently passing when the sentence is reworded:
a check that quietly stops checking is worse than no check.
"""
text = (REPO_ROOT / "README.md").read_text(encoding="utf-8")
match = _README_RE.search(text)
if not match:
raise SystemExit(
"README.md: no '[**vX.Y.Z**](...) is the current Beta' line found.\n"
" If the wording changed, update _README_RE in this script to match."
)
label, url = match.group("label"), match.group("url")
if not url.rstrip("/").endswith(f"v{label}"):
raise SystemExit(
f"README.md: link says v{label} but its URL points at {url}"
)
return label


def _pyproject_version() -> str:
with (REPO_ROOT / "pyproject.toml").open("rb") as fh:
return tomllib.load(fh)["project"]["version"]
Expand All @@ -67,6 +101,7 @@ def main() -> int:
sources = {
"lib/stack/cli.py": _cli_version(),
"pyproject.toml": _pyproject_version(),
"README.md": _readme_version(),
}

# Only present in a tag build; locally there is no tag to agree with.
Expand Down
Loading