From 3dd816184c492aea5ba62a2b495ee4800518b328 Mon Sep 17 00:00:00 2001 From: IPerception Date: Sun, 16 Aug 2026 20:13:36 -0400 Subject: [PATCH] chore: normalise line endings on the release asset v1.1.0 shipped as a 297,077-byte download of a 290,824-byte file: 6,253 carriage returns and nothing else. The asset is copied from the working tree, and a Windows checkout has CRLF there. LF is this repo's canonical form -- .gitattributes puts every text file on it via `* text=auto`, with only *.edi and *.txt exempt because there line endings are data. So the CRLF asset matched neither what git stores, nor what the Pages demo serves, nor what CI tested. Staging now normalises, and reports how many bytes it removed so a silent regression is visible in the release output. v1.1.0's published asset is left alone. Replacing it would mean a version number no longer identifies one set of bytes, which is the property step 2 of this script exists to protect. The fix applies from the next release. Co-Authored-By: Claude Opus 5 --- web/release.mjs | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/web/release.mjs b/web/release.mjs index 2893a4b..064f341 100644 --- a/web/release.mjs +++ b/web/release.mjs @@ -13,7 +13,7 @@ // Needs `gh` authenticated. Notes are read from the tag message if you pass // --notes-file, otherwise GitHub generates them from the commit log. import { execFileSync } from "node:child_process"; -import { copyFileSync, mkdtempSync, readFileSync } from "node:fs"; +import { mkdtempSync, readFileSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { APP, PROJECT, TESTS_DIR, appVersion } from "./tests/paths.mjs"; @@ -79,12 +79,25 @@ try { // Copied to a temp dir rather than renamed in place: the repo keeps one // unversioned EDIWorkbench.html, and only the download carries the version // in its name. +// +// Line endings are normalised to LF on the way out. .gitattributes puts every +// text file in this repo on LF (`* text=auto`, with only *.edi and *.txt +// exempt because there line endings are data), so LF is the canonical form -- +// it is what git stores and what the Pages demo serves. A Windows checkout has +// CRLF in the working tree, and copying that verbatim shipped v1.1.0 as a +// 297,077-byte download of a 290,824-byte file: same content, ~6 KB of carriage +// returns, and bytes that matched neither the repo nor the demo nor what CI +// tested. const staged = join(mkdtempSync(join(tmpdir(), "ediwb-")), asset); -copyFileSync(APP, staged); -if (!readFileSync(staged, "utf8").includes(`class="version">v${version}<`)) { +const working = readFileSync(APP, "utf8"); +const normalised = working.split("\r\n").join("\n"); +writeFileSync(staged, normalised, "utf8"); + +if (!normalised.includes(`class="version">v${version}<`)) { die("the staged asset does not state the version it is named for"); } -step(`staged ${asset} (${readFileSync(staged).length} bytes), version confirmed inside it`); +const saved = Buffer.byteLength(working, "utf8") - Buffer.byteLength(normalised, "utf8"); +step(`staged ${asset} (${Buffer.byteLength(normalised, "utf8")} bytes${saved ? `, ${saved} CRLF bytes normalised away` : ""}), version confirmed inside it`); if (!publish) { console.log(`\nDry run only. Re-run with --publish to create ${tag}.`);