Commit 9ed1f35adf

9ed1f35adf36821efcda76cfb3dad14a6cb4d0ff

parent: 167e686a8e

Verified · cmc ci/build: failure ci/lint: success

cmc <hello@cleberg.net> · 2026-08-31 03:32 UTC

Rewrite the footer's orgo version at build time

build.py reads `orgo --version` after the build and substitutes it into
every page, so the note reports the orgo that actually ran instead of a
literal maintained by hand alongside the pin in .gitbay/ci.yml.

Runs over every page, not only the re-rendered ones: the build cache keys
on the cache format version, not orgo's release version, so pages carried
over from an older build would otherwise keep the old one. A build where
the note matches nothing fails rather than passing silently.

Layout: unified · split

README.md +7 −2
@@ -66,8 +66,9 @@ For users employing Doom Emacs, open any repository Org file using
6666
6767## Building and Publishing the Site
6868
69The `build.py` script wraps the build: it runs orgo, and then either
70deploys the result or serves it locally.
69The `build.py` script wraps the build: it runs orgo, rewrites the footer's
70orgo version to match the orgo that ran, and then either deploys the result
71or serves it locally.
7172
7273Environment variables control what it does, and all default to off:
7374
@@ -128,6 +129,10 @@ orgo can also build and preview on its own, without `build.py`:
128129orgo serve content -o /tmp/preview
129130```
130131
132Such a preview skips the footer rewrite, so it prints whatever version
133`content/templates/base.html` currently hardcodes rather than the one that
134built it.
135
131136## Deployment
132137
133138Production builds rewrite image URLs to root-relative ones
build.py +62
@@ -4,6 +4,7 @@ This script automates the process of building and deploying the website.
44It handles tasks such as:
55
66- Running orgo to generate site content.
7- Rewriting the footer's orgo version to match the orgo that built the site.
78- Rewriting image URLs for the onion service (production only).
89- Optionally deploying the built site to a remote server.
910- Starting a local development server for previewing changes.
@@ -77,6 +78,64 @@ def rewrite_img_urls(build_dir=".build"):
7778 print(f"Rewrote {count} img.cleberg.net references to /img/")
7879
7980
81# The footer's "Powered by orgo <version>" note. Anchored on the whole phrase rather
82# than on a placeholder token, so the template stays valid HTML on its own and a page
83# already carrying a version is rewritten the same way as a freshly rendered one — and
84# so prose that happens to end a paragraph with a link to orgo is left alone.
85ORGO_NOTE = re.compile(
86 r'(Powered by <a href="https://gitbay\.org/krz/orgo">orgo</a> )[^<]*(</p>)'
87)
88
89
90def orgo_version():
91 """The version reported by the orgo on PATH, e.g. "0.22.0"."""
92 result = subprocess.run(
93 ["orgo", "--version"], capture_output=True, text=True, check=False
94 )
95 if result.returncode != 0:
96 print("Could not read the orgo version:", file=sys.stderr)
97 print(result.stderr, file=sys.stderr)
98 sys.exit(1)
99 # `orgo --version` prints "orgo X.Y.Z". Anything else means the output format
100 # changed, and guessing at it would ship a wrong version to every page.
101 parts = result.stdout.split()
102 if len(parts) != 2 or parts[0] != "orgo":
103 print(f"Unexpected `orgo --version` output: {result.stdout!r}", file=sys.stderr)
104 sys.exit(1)
105 return parts[1]
106
107
108def rewrite_orgo_version(build_dir):
109 """Point the footer's orgo version at the orgo that just built the site.
110
111 Runs over every page rather than only the re-rendered ones, because the build cache
112 keys on a cache *format* version and not on orgo's release version: after a version
113 bump that leaves the format alone, the pages carried over from the previous build
114 would otherwise keep printing the old one.
115
116 The whole point of this is that the note cannot go stale, so a footer that no longer
117 matches is a failure and not a no-op — matching nothing anywhere means the note was
118 removed or its markup changed, and a silent pass would leave the site claiming
119 whatever the template last hardcoded.
120 """
121 version = orgo_version()
122 count = 0
123 for html in Path(build_dir).rglob("*.html"):
124 text = html.read_text(encoding="utf-8")
125 new_text, n = ORGO_NOTE.subn(rf"\g<1>{version}\g<2>", text)
126 if n and new_text != text:
127 html.write_text(new_text, encoding="utf-8")
128 count += n
129 if count == 0:
130 print(
131 "No 'Powered by orgo' note found in the build — the footer in "
132 "content/templates/base.html no longer matches ORGO_NOTE",
133 file=sys.stderr,
134 )
135 sys.exit(1)
136 print(f"Set the footer orgo version to {version} on {count} pages")
137
138
80139def run_orgo_build(build_dir):
81140 """
82141 Build the site with orgo.
@@ -164,6 +223,9 @@ def main():
164223
165224 if os.environ.get("BUILD", "").casefold() == "true":
166225 run_orgo_build(build_dir)
226 # Both environments: a dev preview showing a stale version is the same defect
227 # as a deployed page showing one.
228 rewrite_orgo_version(build_dir)
167229 # The onion needs same-origin images; dev previews keep the absolute URLs.
168230 # Runs over every page, not just the re-rendered ones, so a page carried over
169231 # from an earlier build is rewritten too.
content/templates/base.html +3 −1
@@ -93,7 +93,9 @@
9393<a href="{{ root }}tips/index.html">Tips</a> &middot;
9494<a href="https://iheartrss.com/">I &hearts; RSS</a>
9595<p>[ <a href="https://krz.sh">krz</a> &middot; <a href="https://audit-labs.dev">audit labs</a> ]</p>
96{#- The version is the one pinned in .gitbay/ci.yml; bump both together. #}
96{#- The version is rewritten in the built HTML by build.py, which reads it from the
97 orgo that just ran. What is written here is the seed and the fallback: a build
98 that bypasses build.py (`orgo serve`) prints it as-is. #}
9799<p>Powered by <a href="https://gitbay.org/krz/orgo">orgo</a> 0.22.0</p>
98100</footer>
99101</body>