feat: attach the installer to each release

This commit is contained in:
Abdessamad Derraz committed 2026-10-23 18:48:02 +02:00
1 parent 34b3a9a9c6
commit 6e7047b3fc
2 files changed
+29 -5

No files matched your search

+20 -3
View File
@@ -7,7 +7,9 @@ SHA256SUMS.txt lists for it, as must each handheld launcher (RetroBIOS.zip
and the others build_port.py writes) the list names, the parts of a pack must add up to the download
size the README prints, and nothing else may be attached. The record holds
one pack for each platform the registry marks release_pack, and no other
pack. An upload that
pack. The installer (install.py, install.sh, install.ps1) and every file
list of install/ are listed and attached too, so a package can pin one
release. An upload that
failed in the loop, or a part re-uploaded from an older build, otherwise
publishes a release that `sha256sum --check` rejects for every user.
@@ -37,6 +39,12 @@ from release_record import RECORD, load_record
SUMS = "SHA256SUMS.txt"
SIGNATURE = SUMS + ".sig"
INSTALLER = ("install.py", "install.sh", "install.ps1")
def installer_files(install_dir: str | Path = "install") -> list[str]:
"""The release files a package pins: the installer and each file list."""
return [*INSTALLER, *sorted(p.name for p in Path(install_dir).glob("*.json"))]
@dataclass(frozen=True)
@@ -73,6 +81,7 @@ def compare_release(
tag: str,
local_files: dict[str, str] | None = None,
released: set[str] | None = None,
installer: list[str] | None = None,
) -> list[Finding]:
"""Every way the release can differ from what was built.
@@ -80,6 +89,7 @@ def compare_release(
signature) to its local sha256: the copy on the release must be that one.
*released* names the platforms the registry marks release_pack: each one
has a recorded pack, and no recorded pack serves only other platforms.
*installer* names the installer files each release lists and carries.
"""
findings: list[Finding] = []
if record.get("tag") != tag:
@@ -112,9 +122,11 @@ def compare_release(
findings.append(Finding("extra", name, "attached but neither recorded nor listed"))
for name in sorted(set(recorded) - set(sums)):
findings.append(Finding("unlisted", name, f"absent from {SUMS}"))
for name in sorted(set(installer or ()) - set(sums)):
findings.append(Finding("no-installer", name, f"absent from {SUMS}"))
# The handheld launchers are release files but no packs: release.json
# records packs, and the checksum list alone vouches for the launchers.
for name in sorted(set(sums) - set(recorded) - set(ARCHIVES)):
for name in sorted(set(sums) - set(recorded) - set(ARCHIVES) - set(installer or ())):
findings.append(Finding("unrecorded", name, f"listed in {SUMS}, absent from release.json"))
wanted = {**sums, **(local_files or {})}
@@ -190,6 +202,10 @@ def main() -> int:
"--platforms-dir", default="platforms",
help="registry whose release_pack platforms each need a pack (default: %(default)s)",
)
parser.add_argument(
"--install-dir", default="install",
help="file lists the release must carry beside the installer (default: %(default)s)",
)
parser.add_argument("--json", action="store_true", help="JSON output")
args = parser.parse_args()
@@ -223,7 +239,8 @@ def main() -> int:
return 2
released = set(list_release_pack_platforms(args.platforms_dir, include_archived=True))
findings = compare_release(record, sums, assets, tag, local_files, released)
findings = compare_release(record, sums, assets, tag, local_files, released,
installer_files(args.install_dir))
if args.json:
print(json.dumps(
{"tag": tag, "draft": draft, "assets": len(assets),
+9 -2
View File
@@ -227,11 +227,17 @@ python scripts/split_pack.py dist/
# check_release.py compares each asset with its line there.
python scripts/build_port.py
# 2c. The installer and the file lists step 1 wrote, so a package can pin
# one release (installer page, "For packagers"). check_release.py
# refuses a release that lacks one of them.
cp install.py install.sh install.ps1 install/*.json dist/
# 3. Checksums of the files as published, then sign the list. The checksums
# answer corruption, and the signature answers a rewritten release, which is
# the one thing a checksum published beside its own artifacts cannot
# answer.
(cd dist && sha256sum *.zip RetroBIOS.muxapp > SHA256SUMS.txt)
(cd dist && sha256sum *.zip RetroBIOS.muxapp install.py install.sh install.ps1 \
$(cd ../install && ls *.json) > SHA256SUMS.txt)
ssh-keygen -Y sign -f ~/.ssh/retrobios_signing -n file dist/SHA256SUMS.txt
# 4. Record what each pack holds, read from the archives just checked:
@@ -253,7 +259,8 @@ python scripts/release_notes.py --whats-new tmp/whats-new.md --output tmp/notes.
# A public release with half its assets is a broken download for everyone
# during the whole upload.
gh release create "v${DATE}" --draft --title "BIOS Pack v${DATE}" --notes-file tmp/notes.md
for f in dist/SHA256SUMS.txt dist/SHA256SUMS.txt.sig dist/*.zip dist/RetroBIOS.muxapp; do
for f in dist/SHA256SUMS.txt dist/SHA256SUMS.txt.sig dist/*.zip dist/RetroBIOS.muxapp \
dist/install.py dist/install.sh dist/install.ps1 $(ls install/*.json | sed 's|^install/|dist/|'); do
[ -f "$f" ] && gh release upload "v${DATE}" "$f#$(basename "$f")" --clobber
done
# A count does not see a failed upload beside a stray file, nor a part