diff --git a/.github/scripts/check-release-notes.py b/.github/scripts/check-release-notes.py new file mode 100755 index 0000000..c7333ef --- /dev/null +++ b/.github/scripts/check-release-notes.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python3 +"""Render the release notes header the way the workflow does, and check it. + +The v0.1.0 notes shipped with an empty ```bash block in them. It came from +editing the heredoc by string substitution — inserting a closing fence, some +prose and an opening fence directly above a closing fence that was already +there. Nothing rendered the result before it was published. + +Markdown has no compiler, so this is the compiler: unbalanced fences and empty +code blocks are the two failures that survive review by looking fine in a diff. +""" + +import pathlib +import sys + +WORKFLOW = pathlib.Path(".github/workflows/release.yml") +START = "cat > header.md <<'EOF'\n" +END = "\n EOF\n" + + +def main() -> int: + text = WORKFLOW.read_text() + if START not in text or END not in text: + print(f"{WORKFLOW}: no release-notes heredoc to check") + return 1 + + body = text.split(START, 1)[1].split(END, 1)[0] + # The heredoc is indented ten spaces inside the YAML. + header = "\n".join( + line[10:] if line.startswith(" " * 10) else line for line in body.split("\n") + ) + header = header.replace("OWNER", "example").replace("TAG", "v0.0.0") + + lines = header.split("\n") + fences = [n for n, line in enumerate(lines) if line.strip().startswith("```")] + + problems = [] + if len(fences) % 2: + problems.append(f"{len(fences)} code fences — unbalanced, so one block never closes") + + for opened, closed in zip(fences[0::2], fences[1::2]): + if not [line for line in lines[opened + 1 : closed] if line.strip()]: + problems.append(f"empty code block at lines {opened + 1}-{closed + 1}") + + if problems: + print("release notes would render wrong:") + for problem in problems: + print(f" {problem}") + return 1 + + print(f"release notes: {len(fences) // 2} code blocks, all balanced and non-empty") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2a02e1b..8ade4f3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -68,6 +68,12 @@ jobs: fi echo "README and CI agree on $WANT" + # The v0.1.0 notes shipped with an empty ```bash block, from editing the + # heredoc by string substitution and never rendering the result. + # Markdown has no compiler; this is the compiler. + - name: The release notes would render + run: python3 .github/scripts/check-release-notes.py + - name: Host tests run: cargo test -p oxinit-unit -p oxinit-graph -p oxinit-service -p oxinit-cgroup -p oxinit-user -p oxinit-ipc -p oxinit-log -p oxinit-timer diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f3a8106..e9d1893 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -130,9 +130,6 @@ jobs: `ghcr.io/OWNER/oxinit:demo` tracks `main` if you would rather have the latest. - ```bash - ``` - ### Install Download the tarball for your architecture below, check it, and put diff --git a/ROADMAP.md b/ROADMAP.md index e570fc7..ccdd6ce 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1000,6 +1000,31 @@ and runs. The lesson is the same one the bug taught, applied to the fix: the reason to run the command is that reasoning about what it will do is not the same thing. +### v0.1.0, and an empty code block in its notes + +The release workflow worked on its first run: both architectures' tarballs with +checksums, the versioned image, and notes generated from the merged pull +requests. Verified by downloading what was published rather than trusting what +was built — both checksums match, and the binaries out of both tarballs report +`0.1.0` under emulation. + +The notes shipped with an empty ```` ```bash ```` block in them, reported by +the first person to read them. + +It came from editing the heredoc that writes those notes by string +substitution: the insertion ended with an opening fence directly above a +closing fence that was already there. The diff looked fine. Nothing rendered +the result, and Markdown has no compiler to complain. + +So CI has one now. `.github/scripts/check-release-notes.py` renders the header +the way the workflow does and fails on unbalanced fences or empty blocks — +which are exactly the two mistakes that survive review by looking correct in a +diff. The published v0.1.0 notes were edited in place. + +Third time in this project that the failure was *editing text without looking +at the output*, and the second time it reached somebody. It is worth naming as +a pattern rather than as three separate slips. + ## Not doing, and why These were on the list. They are coming off it with a reason rather than