Something went wrong. Try again.
All-in-one editor for Paper Mario (N64) mods diorama64.starhaven.dev
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125#!/usr/bin/env bash# SPDX-FileCopyrightText: 2026 Alexander Bates <alex@bates64.com>## SPDX-License-Identifier: 0BSD
# Builds every platform's release on Linux and, for a v* tag, publishes it to# the release bucket: an AppImage for Linux, an NSIS installer for Windows,# and a universal app for macOS, as a zip for updates and a disk image for# first installs. .tangled/workflows/release.yml runs it from the cross# devshell.## app/scripts/release.sh [TAG]## Publishing needs AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY. Signing the# macOS app needs what scripts/after-pack.mjs describes, and signing the# Windows installer what scripts/sign-windows.mjs does, which a release fails# without. Without a v* tag nothing is published, and the version stays# package.json's 0.0.0.
set -euo pipefail
tag=${1:-}cd "$(dirname "$0")/../.."
# puppeteer's Chrome is only for driving the app in development.PUPPETEER_SKIP_DOWNLOAD=1 yarn install --frozen-lockfilenode app/scripts/patch-electron-builder.mjsyarn buildcd app
publish=neverrelease=()name=if [[ $tag == v* ]]; then publish=always name=${tag#v} # Once a release is signed, the app only installs updates signed by the # same publisher, so a release mustn't go out unsigned. export DIORAMA64_REQUIRE_SIGNING=1 # A release's version is its tag's date with dots, and without the leading # zeros semver rejects, such as 2026.10.7 for v2026-10-07, and its files # are named for the tag as written, such as Diorama64-2026-10-07.dmg. release=(-c.extraMetadata.version="$(echo "$name" | tr - . | sed -E 's/(^|\.)0+([0-9])/\1\2/g')")fi
# The native modules were staged by the cross-compiling step for each# target, so electron-builder mustn't rebuild them for this machine.builder=(npx electron-builder --config electron-builder.yml --publish "$publish" -c.nativeModules.npmRebuild=false "${release[@]}")
# Each target's jj and ares go in resources/, which electron-builder.yml# bundles whole, so clear out the previous target's first.clean() { rm -rf resources/tools resources/ares; }
cleannode scripts/stage-natives.mjs --platform=linux --arch=x64yarn download:jj --platform=linux --arch=x64yarn download:ares --platform=linux --arch=x64"${builder[@]}" --linux --x64 ${name:+-c.appImage.artifactName="Diorama64-$name-\${arch}.\${ext}"}rm -rf dist/linux-unpacked
cleannode scripts/stage-natives.mjs --platform=win32 --arch=x64yarn download:jj --platform=win32 --arch=x64yarn download:ares --platform=win32 --arch=x64# Contributors on Windows download this build rather than building ares, under# a name that changes with its version and patches.if [[ $publish == always ]]; then ares_key=$(node scripts/download-ares.mjs --platform=win32 --arch=x64 --print-cache-key) mkdir -p dist/ares bsdtar -acf "dist/ares/ares-$ares_key.zip" --exclude .ares-version -C resources/ares/x64 . (cd dist/ares && sha256sum "ares-$ares_key.zip" > "ares-$ares_key.zip.sha256")fi"${builder[@]}" --win --x64 ${name:+-c.nsis.artifactName="Diorama64-$name.\${ext}"}rm -rf dist/win-unpacked
cleannode scripts/stage-natives.mjs --platform=darwinyarn download:jj --platform=darwinyarn download:ares --platform=darwin# The disk image is built below, from the app scripts/after-pack.mjs signed."${builder[@]}" --mac zip --universal ${name:+-c.mac.artifactName="Diorama64-$name.\${ext}"}rm -rf dist/mac-universal-*-temp
dmg="dist/Diorama64-${name:-0.0.0}.dmg"scripts/make-dmg.sh dist/mac-universal/Diorama64.app "$dmg"rm -rf dist/mac-universal
if [[ -n ${APPLE_DEVELOPER_ID_PEM:-} && -n ${APPLE_NOTARY_API_KEY:-} ]]; then secrets=$(mktemp -d) trap 'rm -rf "$secrets"' EXIT (umask 077 && echo "$APPLE_DEVELOPER_ID_PEM" | base64 -d > "$secrets/developer-id.pem") (umask 077 && echo "$APPLE_NOTARY_API_KEY" | base64 -d > "$secrets/notary-key.json") rcodesign sign --pem-source "$secrets/developer-id.pem" "$dmg" rcodesign notary-submit --api-key-file "$secrets/notary-key.json" --max-wait-seconds 3600 --staple "$dmg"fi
[[ $publish == always ]] || exit 0
# electron-builder.yml's publish settings, for rclone, which uploads the disk# image electron-builder didn't make and prunes old releases.export RCLONE_CONFIG_RELEASES_TYPE=s3export RCLONE_CONFIG_RELEASES_PROVIDER=Otherexport RCLONE_CONFIG_RELEASES_ENDPOINT=https://fsn1.your-objectstorage.comexport RCLONE_CONFIG_RELEASES_ACCESS_KEY_ID=$AWS_ACCESS_KEY_IDexport RCLONE_CONFIG_RELEASES_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEYexport RCLONE_CONFIG_RELEASES_ACL=public-readbucket=releases:starhaven/diorama64/releases
rclone copyto --s3-no-check-bucket "$dmg" "$bucket/$(basename "$dmg")"
# A build is named for what it was built from, so one that's uploaded stays.rclone copy --s3-no-check-bucket --ignore-existing dist/ares releases:starhaven/diorama64/ares
# Keep the newest 3 releases. Old ones are only kept for rollback:# electron-updater never reads them.keep=3stale=$(rclone lsf "$bucket" \ | sed -nE 's/^Diorama64-([0-9]{4}-[0-9]{2}-[0-9]{2})[-.].*/\1/p' \ | sort -u \ | head -n "-$keep")for version in $stale; do echo "Pruning $version" rclone delete "$bucket" --include "Diorama64-$version[-.]*"done