release candidates: every push to main runs the full CI, the acceptance matrix and the Linux / Windows installer builds in parallel (ci.yml) and records the green result per commit as the draft rc-<sha> (green.json last); a version-only bump commit (proven file by file with the version writers) reuses its parent's CI and matrix and rebuilds only the installers; a v* tag only promotes the candidate (release.yml), fails fast on a red or missing commit; acceptance runs carry a CLI key; tools/release.ts does the whole release on the Mac (bump, CHANGELOG cut, fast gate, push, tag, Mac build + notarize in parallel with Forgejo, cached macOS acceptance, add, verify, publish with one upload of the Mac files, /Applications update, npm commands) and --rehearsal; DMG notarization runs while the app and updater bundle are checked; rehearsal channel on the VDS; docs

This commit is contained in:
CRTkafa 2026-10-15 00:42:39 +08:00
parent 89d94d6993
commit c3b1e8c370
14 changed files with 1438 additions and 526 deletions

View file

@ -5,6 +5,7 @@
# document root, because the site's publish rsync deletes everything that is not in the repository.
Alias /desktop/latest.json /var/www/storebound-desktop/latest.json
Alias /desktop/beta/latest.json /var/www/storebound-desktop/beta/latest.json
Alias /desktop/rehearsal/latest.json /var/www/storebound-desktop/rehearsal/latest.json
Alias /desktop/dl/ /var/www/storebound-desktop/dl/
<Directory /var/www/storebound-desktop>
Options -Indexes -FollowSymLinks
@ -15,7 +16,7 @@ Alias /desktop/dl/ /var/www/storebound-desktop/dl/
Header set Content-Disposition "attachment"
</FilesMatch>
</Directory>
<LocationMatch "^/desktop/(beta/)?latest\.json$">
<LocationMatch "^/desktop/((beta|rehearsal)/)?latest\.json$">
Header set Cache-Control "no-cache"
Header set Access-Control-Allow-Origin "*"
</LocationMatch>

View file

@ -1,7 +1,8 @@
#!/usr/bin/env bash
# Root-owned publish step for storebound desktop releases (install as /usr/local/sbin/storebound-desktop-publish,
# root:root 755; see docs/desktop-release.md). tools/desktop-release.ts publish uploads one version folder to
# /var/lib/storebound-desktop/incoming/<version>/ and then runs: storebound-desktop-publish <version> [stable|beta]
# /var/lib/storebound-desktop/incoming/<version>/ and then runs: storebound-desktop-publish <version> [stable|beta|rehearsal]
# (rehearsal: tools/release.ts --rehearsal, a throwaway prerelease at /desktop/rehearsal/latest.json that no app reads)
#
# It checks the upload (regular files with plain names only, SHA256SUMS, latest.json of that version whose every URL
# points at an uploaded file of /desktop/dl/<version>/), copies the files into /var/www/storebound-desktop/dl/<version>/
@ -20,8 +21,10 @@ ROOT=/var/www/storebound-desktop
SITE=https://storebound.dev/desktop
die() { echo "storebound-desktop-publish: $*" >&2; exit 1; }
[[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.]+)?$ ]] || die "usage: storebound-desktop-publish <version> [stable|beta]"
[[ "$CHANNEL" == stable || "$CHANNEL" == beta ]] || die "channel: stable or beta"
[[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.]+)?$ ]] || die "usage: storebound-desktop-publish <version> [stable|beta|rehearsal]"
[[ "$CHANNEL" == stable || "$CHANNEL" == beta || "$CHANNEL" == rehearsal ]] || die "channel: stable, beta or rehearsal"
# a stable or beta version is never a rehearsal, and a rehearsal never reaches stable or beta
if [[ "$VERSION" == *-rehearsal.* ]]; then [ "$CHANNEL" = rehearsal ] || die "a rehearsal version goes to the rehearsal channel only"; else [ "$CHANNEL" != rehearsal ] || die "the rehearsal channel takes rehearsal versions only"; fi
IN="$INCOMING/$VERSION"
DL="$ROOT/dl/$VERSION"
[ -d "$IN" ] && [ ! -L "$IN" ] || die "nothing uploaded at $IN"
@ -51,7 +54,7 @@ for e in entries:
assert e.get("signature"), url
PY
install -d -m 755 "$ROOT" "$ROOT/dl" "$ROOT/beta"
install -d -m 755 "$ROOT" "$ROOT/dl" "$ROOT/beta" "$ROOT/rehearsal"
if [ ! -e "$DL" ]; then
TMP="$(mktemp -d "$ROOT/dl/.tmp-$VERSION.XXXXXX")"
for f in "$IN"/*; do n="$(basename "$f")"; [ "$n" = latest.json ] || install -m 644 "$f" "$TMP/$n"; done
@ -76,7 +79,7 @@ fi
install -m 644 "$IN/latest.json" "$DL/.latest.json.tmp" && mv -f "$DL/.latest.json.tmp" "$DL/latest.json"
# latest.json last: installed apps see the new version only once every file it names is in place
if [ "$CHANNEL" = stable ]; then LJ="$ROOT/latest.json"; URL="$SITE/latest.json"; else LJ="$ROOT/beta/latest.json"; URL="$SITE/beta/latest.json"; fi
if [ "$CHANNEL" = stable ]; then LJ="$ROOT/latest.json"; URL="$SITE/latest.json"; else LJ="$ROOT/$CHANNEL/latest.json"; URL="$SITE/$CHANNEL/latest.json"; fi
install -m 644 "$IN/latest.json" "$LJ.tmp"
mv -f "$LJ.tmp" "$LJ"
rm -rf "$IN"