Checklists in the body, colour from tags, and commit-derived CalVer #4
@@ -39,6 +39,25 @@
|
||||
# field, never in the version — note 3127 §7, and rule 149.
|
||||
set -eu
|
||||
|
||||
# ANCHOR AT THE REPO ROOT BEFORE ANYTHING ELSE.
|
||||
#
|
||||
# `git log -- <paths>` resolves pathspecs relative to the CURRENT DIRECTORY, not to
|
||||
# the repo root. Callers run from wherever suits them — the desktop build from
|
||||
# `desktop/src-tauri`, the Android build from `android`, the manifest job from the
|
||||
# root — so without this the same request answers differently per caller.
|
||||
#
|
||||
# It is not a tidy failure. Measured on run 4796, one push produced THREE versions:
|
||||
# the desktop build (cwd `desktop/src-tauri`) said 1.0.3494522, while the pacman
|
||||
# packager and the manifest job both said 1.0.3502131. The build's pathspec had
|
||||
# matched `desktop/src-tauri/Cargo.toml` — a real file — so git returned the newest
|
||||
# commit touching THAT, six days stale. Non-empty, so the guard below could not fire;
|
||||
# the manifest then found no bundle matching its own answer and the lane went red for
|
||||
# a reason two steps removed from the cause.
|
||||
#
|
||||
# The Android job failed loudly in the same run only because its pathspec happened to
|
||||
# match nothing from `android/`. Same bug, louder symptom, pure luck.
|
||||
cd "$(git rev-parse --show-toplevel)"
|
||||
|
||||
# 2020-01-01T00:00:00Z. The counter epoch, and it must NEVER move: shifting it
|
||||
# renumbers every artifact downwards, which is the one direction you cannot recover
|
||||
# from (note 3127 §6.4).
|
||||
@@ -115,6 +134,28 @@ minutes_since_epoch() { echo $(( ($1 - EPOCH) / 60 )); }
|
||||
what="${1:?usage: version.sh <display|key|paths> <desktop|android|server>}"
|
||||
artifact="${2:?usage: version.sh <display|key|paths> <desktop|android|server>}"
|
||||
|
||||
# VALIDATED HERE, in the parent shell, and not left to `paths_for`'s default arm.
|
||||
#
|
||||
# Third instance of one trap in this script, so it is worth stating plainly: `exit`
|
||||
# inside a function called as `$(...)` ends the SUBSHELL, not the script. `paths_for`
|
||||
# is reached through `$(paths_for "$1")`, so its `exit 2` printed the error and
|
||||
# returned an EMPTY pathspec — and an empty pathspec matches everything, so
|
||||
# `version.sh display nope` answered `2026.08.28.0900` and exited 0. A confident
|
||||
# version for an artifact that does not exist.
|
||||
#
|
||||
# The other two were the shallow-clone guard on the `key` path (emitted
|
||||
# `1.0.-26297280`, exit 0) and the same guard on `display` (which failed only because
|
||||
# `date` then choked on an empty string — luck, not design). Each was found by a
|
||||
# different mechanism; none by reading the code. If you add a guard to this file,
|
||||
# make sure it runs where the script does.
|
||||
case "$artifact" in
|
||||
desktop|android|server) : ;;
|
||||
*)
|
||||
echo "version.sh: unknown artifact '$artifact' (want desktop, android or server)" >&2
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
|
||||
case "$what" in
|
||||
paths)
|
||||
paths_for "$artifact"
|
||||
|
||||
@@ -59,10 +59,11 @@ def commit(repo: Path, path: str, when: int) -> None:
|
||||
)
|
||||
|
||||
|
||||
def version(repo: Path, what: str, artifact: str) -> str:
|
||||
def version(repo: Path, what: str, artifact: str, *, subdir: str = "") -> str:
|
||||
return subprocess.run(
|
||||
["sh", str(SCRIPT), what, artifact],
|
||||
cwd=repo, check=True, capture_output=True, text=True,
|
||||
cwd=repo / subdir if subdir else repo,
|
||||
check=True, capture_output=True, text=True,
|
||||
).stdout.strip()
|
||||
|
||||
|
||||
@@ -134,6 +135,37 @@ def test_the_build_recipe_is_in_the_set(repo: Path) -> None:
|
||||
assert version(repo, "display", "desktop") == "2026.08.28.1000"
|
||||
|
||||
|
||||
# --- where it is called from -------------------------------------------------
|
||||
|
||||
@pytest.mark.parametrize("subdir", ["", "desktop/src-tauri", "android", "core"])
|
||||
def test_the_answer_does_not_depend_on_the_caller_s_directory(repo: Path, subdir: str) -> None:
|
||||
"""`git log -- <paths>` resolves pathspecs relative to the CURRENT DIRECTORY.
|
||||
Every caller runs from somewhere different — the desktop build from
|
||||
`desktop/src-tauri`, the Android build from `android`, the manifest from the root
|
||||
— so without an anchor the same request answers differently per caller.
|
||||
|
||||
This is not hypothetical and it is not a loud failure. Run 4796 produced THREE
|
||||
versions from one push: the desktop build said 1.0.3494522 while the manifest and
|
||||
the pacman packager said 1.0.3502131, because the build's pathspec matched
|
||||
`desktop/src-tauri/Cargo.toml` — a real file, six days stale. Non-empty, so the
|
||||
shallow-clone guard could not fire. The Android job failed loudly in the same run
|
||||
only because ITS pathspec happened to match nothing; same bug, luckier symptom."""
|
||||
(repo / "desktop/src-tauri").mkdir(parents=True, exist_ok=True)
|
||||
(repo / "core").mkdir(parents=True, exist_ok=True)
|
||||
assert version(repo, "display", "desktop", subdir=subdir) == "2026.08.28.0900"
|
||||
assert version(repo, "key", "desktop", subdir=subdir) == version(repo, "key", "desktop")
|
||||
|
||||
|
||||
def test_every_artifact_agrees_across_directories(repo: Path) -> None:
|
||||
"""The property the manifest job actually depends on: the value the bundle was
|
||||
built with and the value the manifest looks for must be the same string, and they
|
||||
are computed by different jobs in different directories."""
|
||||
for artifact in ("desktop", "android", "server"):
|
||||
root = version(repo, "display", artifact)
|
||||
assert version(repo, "display", artifact, subdir="desktop/src-tauri") == root
|
||||
assert version(repo, "display", artifact, subdir="android") == root
|
||||
|
||||
|
||||
# --- the ordering keys -------------------------------------------------------
|
||||
|
||||
def test_the_desktop_key_is_valid_semver(repo: Path) -> None:
|
||||
@@ -182,10 +214,19 @@ def test_the_server_has_no_ordering_key(repo: Path) -> None:
|
||||
|
||||
# --- failing loudly ----------------------------------------------------------
|
||||
|
||||
def test_an_unknown_artifact_is_rejected(repo: Path) -> None:
|
||||
r = subprocess.run(["sh", str(SCRIPT), "display", "nope"],
|
||||
@pytest.mark.parametrize("what", ["display", "key", "paths"])
|
||||
def test_an_unknown_artifact_is_rejected(repo: Path, what: str) -> None:
|
||||
"""It was not. `paths_for`'s `exit 2` ran inside `$(paths_for ...)`, so it printed
|
||||
the error, returned an EMPTY pathspec — which matches everything — and answered
|
||||
`2026.08.28.0900` with exit 0. A confident version for an artifact that does not
|
||||
exist, which is the worst kind of wrong for a value nothing else can contradict.
|
||||
|
||||
Asserting on stdout as well as the exit code, because the exit code alone passed
|
||||
for `display` in the first version of this file while stdout carried a lie."""
|
||||
r = subprocess.run(["sh", str(SCRIPT), what, "nope"],
|
||||
cwd=repo, capture_output=True, text=True)
|
||||
assert r.returncode != 0
|
||||
assert r.returncode != 0, f"{what} exited 0 with stdout={r.stdout!r}"
|
||||
assert r.stdout.strip() == "", f"{what} emitted a value for a bogus artifact: {r.stdout!r}"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("what", ["display", "key"])
|
||||
|
||||
Reference in New Issue
Block a user