mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-11-11 12:33:53 -06:00
chore: keep the launchers off the release
check_release reports a launcher in the checksum list as unrecorded and one attached as extra, as it does for install.py. The release steps no longer run build_port, and the checksum and upload globs name the packs (*_BIOS_Pack*.zip) so a launcher left in dist/ is never caught.
This commit is contained in:
1 parent
d7bd89d42b
commit
962f18ac3f
6 files changed
+63
-43
No files matched your search
@@ -3,13 +3,13 @@
|
||||
|
||||
Run on the draft before publishing it, and on the published release at any
|
||||
time. Every pack asset release.json names must be on the release at the sha256
|
||||
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
|
||||
SHA256SUMS.txt lists for it, 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. The installer and the file lists are not release files: a package pins
|
||||
them from the tag, so a reader of the release page sees the packs and nothing
|
||||
to puzzle over. An upload that
|
||||
pack. The installer, the file lists and the handheld launchers are not
|
||||
release files: a package pins the first two from the tag, and the site
|
||||
serves the launchers built from its own commit (sitehandheld.py), so a
|
||||
reader of the release page sees the packs and nothing to puzzle over. 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.
|
||||
|
||||
@@ -31,7 +31,6 @@ from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, os.path.dirname(__file__))
|
||||
from build_port import ARCHIVES
|
||||
from check_release_assets import digests_of
|
||||
from common import list_release_pack_platforms, require_directory
|
||||
from largefiles import LARGE_FILES_REPO
|
||||
@@ -112,9 +111,7 @@ 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}"))
|
||||
# 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)):
|
||||
findings.append(Finding("unrecorded", name, f"listed in {SUMS}, absent from release.json"))
|
||||
|
||||
wanted = {**sums, **(local_files or {})}
|
||||
|
||||
+16
-14
@@ -15,6 +15,7 @@ from pathlib import Path
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent.parent / "scripts"))
|
||||
|
||||
import build_port # noqa: E402
|
||||
from check_release import SIGNATURE, SUMS, Asset, compare_release, parse_sums
|
||||
|
||||
A = "a" * 64
|
||||
@@ -97,20 +98,21 @@ class ReleaseMatchesWhatWasBuilt(unittest.TestCase):
|
||||
self.assertIn(("unrecorded", "Other_BIOS_Pack.zip"), kinds)
|
||||
self.assertIn(("missing", "Other_BIOS_Pack.zip"), kinds)
|
||||
|
||||
def test_the_handheld_port_is_vouched_for_by_the_checksum_list(self):
|
||||
sums = {**SUMS_LIST, "RetroBIOS.zip": A}
|
||||
assets = _assets()
|
||||
self.assertEqual(
|
||||
_kinds(compare_release(RECORD, sums, assets, "v2026.10.10")),
|
||||
{("missing", "RetroBIOS.zip")},
|
||||
)
|
||||
assets["RetroBIOS.zip"] = Asset(70, A)
|
||||
self.assertEqual(compare_release(RECORD, sums, assets, "v2026.10.10"), [])
|
||||
assets["RetroBIOS.zip"] = Asset(70, B)
|
||||
self.assertEqual(
|
||||
_kinds(compare_release(RECORD, sums, assets, "v2026.10.10")),
|
||||
{("content", "RetroBIOS.zip")},
|
||||
)
|
||||
def test_a_handheld_launcher_is_no_release_file(self):
|
||||
"""The site serves the launchers built from its own commit: one in
|
||||
the checksum list or among the assets is refused."""
|
||||
for name in build_port.ARCHIVES:
|
||||
with self.subTest(name=name):
|
||||
sums = {**SUMS_LIST, name: A}
|
||||
assets = _assets()
|
||||
assets[name] = Asset(70, A)
|
||||
self.assertEqual(_kinds(compare_release(RECORD, sums, assets, "v2026.10.10")),
|
||||
{("unrecorded", name)})
|
||||
assets = _assets()
|
||||
assets[name] = Asset(70, A)
|
||||
self.assertEqual(
|
||||
_kinds(compare_release(RECORD, SUMS_LIST, assets, "v2026.10.10")),
|
||||
{("extra", name)})
|
||||
|
||||
def test_parts_must_add_up_to_the_printed_download_size(self):
|
||||
assets = _assets()
|
||||
|
||||
@@ -374,10 +374,16 @@ class TheArchives(unittest.TestCase):
|
||||
with self.subTest(archive=name), self.assertRaises(ValueError):
|
||||
build_port.build_archive(name, self.out / name, root)
|
||||
|
||||
def test_the_release_process_attaches_each(self):
|
||||
def test_the_site_serves_each_and_the_release_none(self):
|
||||
"""Each archive carries install.py: the site serves it from its own
|
||||
commit (sitehandheld.py), and the release steps never build one."""
|
||||
text = (REPO_ROOT / "wiki" / "release-process.md").read_text(encoding="utf-8")
|
||||
self.assertNotIn("scripts/build_port.py", text)
|
||||
installer = (REPO_ROOT / "wiki" / "installer.md").read_text(encoding="utf-8")
|
||||
for name in build_port.ARCHIVES:
|
||||
self.assertIn(name, text)
|
||||
with self.subTest(archive=name):
|
||||
self.assertNotIn(name, text)
|
||||
self.assertIn(f"](../get/handheld/{name})", installer)
|
||||
|
||||
|
||||
FAKE_INSTALL = r'''
|
||||
|
||||
+21
-1
@@ -33,6 +33,7 @@ from __future__ import annotations
|
||||
|
||||
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
|
||||
|
||||
import fnmatch
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
@@ -48,6 +49,7 @@ sys.path.insert(0, str(REPO_ROOT))
|
||||
import sitediagrams # noqa: E402
|
||||
from siteguides import INSTALL_SH # noqa: E402
|
||||
from tests import sitepages # noqa: E402
|
||||
import build_port # noqa: E402
|
||||
from check_release import SUMS, Asset, compare_release # noqa: E402
|
||||
|
||||
|
||||
@@ -870,15 +872,33 @@ class PinnedInstaller(unittest.TestCase):
|
||||
kinds = {(f.kind, f.name) for f in compare_release(record, sums, assets, "v1")}
|
||||
self.assertEqual(kinds, {("unrecorded", "install.py"), ("unrecorded", "retroarch.json")})
|
||||
|
||||
def test_a_launcher_attached_to_the_release_is_refused(self):
|
||||
"""The handheld launchers carry install.py: the site serves them
|
||||
from its own commit, the release never does."""
|
||||
record = {"tag": "v1", "packs": {"P.zip": {"download_size": 5, "assets": ["P.zip"]}}}
|
||||
sums = _sums_with(["P.zip", *build_port.ARCHIVES])
|
||||
assets = {name: Asset(5, digest) for name, digest in sums.items()}
|
||||
assets[SUMS] = Asset(1, None)
|
||||
kinds = {(f.kind, f.name) for f in compare_release(record, sums, assets, "v1")}
|
||||
self.assertEqual(kinds, {("unrecorded", name) for name in build_port.ARCHIVES})
|
||||
|
||||
def test_the_release_steps_ship_none(self):
|
||||
text = _wiki("release-process.md")
|
||||
self.assertNotIn("cp install.py", text)
|
||||
sums = re.search(r"sha256sum [^>]+> SHA256SUMS.txt", text, re.S).group(0)
|
||||
upload = re.search(r"for f in dist/SHA256SUMS.txt.*?; do", text, re.S).group(0)
|
||||
for name in ("install.py", "install.sh", "install.ps1", ".json"):
|
||||
for name in ("install.py", "install.sh", "install.ps1", ".json", "RetroBIOS",
|
||||
".muxapp", "build_port", " *.zip", "/*.zip"):
|
||||
with self.subTest(name=name):
|
||||
self.assertNotIn(name, sums)
|
||||
self.assertNotIn(name, upload)
|
||||
# A launcher built into dist/ is never caught by the glob either.
|
||||
for archive in build_port.ARCHIVES:
|
||||
with self.subTest(archive=archive):
|
||||
self.assertFalse(fnmatch.fnmatch(archive, "*_BIOS_Pack*.zip"))
|
||||
self.assertIn("*_BIOS_Pack*.zip", sums)
|
||||
self.assertIn("*_BIOS_Pack*.zip", upload)
|
||||
self.assertNotIn("scripts/build_port.py", text)
|
||||
|
||||
def test_the_installer_page_pins_one_commit(self):
|
||||
# v2026.10.10 carries no install.py: until a release does, the
|
||||
|
||||
@@ -278,7 +278,7 @@ class ReleaseProcessPublishesArchives(unittest.TestCase):
|
||||
def test_the_checksums_are_those_of_the_published_files(self):
|
||||
self.assertLess(
|
||||
self.text.index("scripts/split_pack.py"),
|
||||
self.text.index("sha256sum *.zip"),
|
||||
self.text.index("sha256sum *_BIOS_Pack*.zip"),
|
||||
)
|
||||
|
||||
|
||||
|
||||
+11
-16
@@ -248,25 +248,18 @@ python scripts/pipeline.py
|
||||
# which install.py --check reads to name a part missing from a folder.
|
||||
python scripts/split_pack.py dist/
|
||||
|
||||
# 2b. The handheld launchers, each carrying the installer the bootstraps pin:
|
||||
# RetroBIOS.zip (the PortMaster port), RetroBIOS-batocera.zip (Batocera
|
||||
# and Knulli Ports), RetroBIOS.muxapp (muOS Applications) and
|
||||
# RetroBIOS-tools.zip (the Tools menu of ArkOS, dArkOS, ROCKNIX, JELOS,
|
||||
# AmberELEC). They are release files, listed in the checksums below, and
|
||||
# check_release.py compares each asset with its line there.
|
||||
python scripts/build_port.py
|
||||
|
||||
# 2c. The release carries the packs, the handheld launchers and the signed
|
||||
# checksum list, and nothing else: a beginner reads that page to pick one
|
||||
# file. A package pins install.py and its file list from the tag
|
||||
# (installer page, "For packagers"), and check_release.py refuses an
|
||||
# installer or a file list attached to the release.
|
||||
# 2b. The release carries the packs and the signed checksum list, and
|
||||
# nothing else: a beginner reads that page to pick one file. A package
|
||||
# pins install.py and its file list from the tag (installer page, "For
|
||||
# packagers"). The handheld launchers carry install.py too, so the site
|
||||
# builds and serves them from its own commit. check_release.py refuses an
|
||||
# installer, a file list or a launcher attached to the release.
|
||||
|
||||
# 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 *_BIOS_Pack*.zip > 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:
|
||||
@@ -284,14 +277,16 @@ python scripts/generate_site.py
|
||||
# maintainer's own text in tmp/whats-new.md, appended as written. The
|
||||
# script refuses a text that judges another project ("forum list") or
|
||||
# promises what the gap analysis contradicts ("never stops"): it says
|
||||
# what changed and how it was checked.
|
||||
# what changed and how it was checked. The notes end with everyone who
|
||||
# helped since the start, read with gh (--thanks FILE passes a checked
|
||||
# list), and the full changelog from the previous release's record.
|
||||
python scripts/release_notes.py --whats-new tmp/whats-new.md --output tmp/notes.md
|
||||
|
||||
# Create the release as a DRAFT, upload every asset, and only then publish it.
|
||||
# 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/*_BIOS_Pack*.zip; 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
|
||||
|
||||
Reference in new issue
Block a user