skate3recomp-multiplayer/tools/release/release.sh
MiTHRAL 7173d7e88d releases: local build+upload script, optional Forgejo Actions workflow, docs
Clarifies that releases ship ONLY the recompiled binaries (skate3 +
librexruntime + ghost_relay + README) - never the game files; the game dump
(default.xex + EAWebkit.xex) is required at BUILD TIME for codegen only.

- tools/release/release.sh: builds + packages a per-platform release zip
  (configure -> codegen -> build -> zip), prints a sha256sum, and with
  --upload creates/updates a Forgejo Release and attaches the zip via the
  API (GITEA_TOKEN). Supports linux/windows/macos presets on their native
  hosts.
- .forgejo/workflows/release.yml: optional automation - builds on a
  self-hosted Docker runner (ubuntu-24.04 label), self-heals the broken
  nested submodule pins via tools/ci/init-submodules.sh, and publishes a
  Linux release on v* tags. Needs the game dump mounted on the runner
  (codegen only, never uploaded), SUBMODULE_KEY + RELEASE_TOKEN secrets.
- tools/ci/init-submodules.sh: recursive submodule init that self-heals
  upstream pins a fresh clone can no longer fetch (the rexglue fork pins
  thirdparty/imgui to a commit ocornut/imgui dropped; the script checks out
  the upstream default tip for any nested submodule left empty).
- docs/releases.md: what's in a release, the local path, and the optional
  CI path.
- .gitignore: keep tools/ci + tools/release, ignore local release zips.
2026-08-26 23:32:13 -04:00

144 lines
No EOL
5.7 KiB
Bash
Executable file

#!/usr/bin/env bash
# Build a Skate 3 recomp release from this checkout and optionally publish it
# to a Forgejo/Gitea Release.
#
# IMPORTANT: the release zip contains ONLY the recompiled binaries
# (skate3 + librexruntime.so + ghost_relay + README) - NO game files. Players
# bring their own ISO and the in-app installer extracts it. The game dump
# (default.xex + data/webkit/EAWebkit.xex) is required at BUILD TIME only,
# because codegen translates the actual Xbox 360 binary into C++ source; it
# is never included in, or uploaded with, the release.
#
# Usage:
# ./tools/release/release.sh # build this platform, no upload
# ./tools/release/release.sh --tag v1.0.0 --upload # build + publish
# ./tools/release/release.sh --game-root /path/to/game --tu /path/to/TU_12K2276_...
#
# Options:
# --tag TAG release tag/version (default: last git tag or 'dev')
# --game-root DIR extracted game dump (default: $REPO/game)
# --tu FILE optional Title Update STFS package for codegen
# --os linux|windows|macos override platform (default: host OS)
# --upload publish the zip to a Forgejo Release
#
# Env for --upload:
# GITEA_TOKEN Forgejo token with write:repository (release) scope
# FORGEJO_REPO default "ad3laid3/skate3recomp-multiplayer"
# FORGEJO_INSTANCE default "https://git.mithraic.cloud"
set -euo pipefail
REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
cd "$REPO"
UPLOAD=0
TAG=""
GAME_ROOT="${SKATE3_GAME_DATA_ROOT:-$REPO/game}"
TU="${SKATE3_TITLE_UPDATE_PACKAGE:-}"
OS_ARG=""
while [ $# -gt 0 ]; do
case "$1" in
--tag) TAG="${2:?--tag needs a value}"; shift 2;;
--game-root) GAME_ROOT="$2"; shift 2;;
--tu) TU="$2"; shift 2;;
--os) OS_ARG="$2"; shift 2;;
--upload) UPLOAD=1; shift;;
-h|--help)
sed -n '2,30p' "$0"; exit 0;;
*) echo "unknown argument: $1"; exit 2;;
esac
done
# ---- platform ---------------------------------------------------------------
UNAME_S="$(uname -s 2>/dev/null || echo Windows)"
case "${OS_ARG:-$UNAME_S}" in
linux|Linux) PRESET="linux-relwithdebinfo"; BIN="skate3"; LIB="librexruntime.so"; EXT="Linux";;
windows|Windows|MINGW*|MSYS*|CYGWIN*)
PRESET="relwithdebinfo"; BIN="skate3.exe"; LIB="librexruntime.dll"; EXT="Windows";;
macos|macOS|Darwin) PRESET="macos-relwithdebinfo"; BIN="skate3"; LIB="librexruntime.dylib"; EXT="macOS";;
*) echo "unsupported platform: ${OS_ARG:-$UNAME_S} (set --os linux|windows|macos)"; exit 2;;
esac
if [ -z "$TAG" ]; then
TAG="$(git describe --tags --always 2>/dev/null || echo dev)"
fi
VER="${TAG#v}"
NAME="Skate3Recomp-$EXT-$VER"
if [ ! -f "$GAME_ROOT/default.xex" ]; then
echo "ERROR: game dump not found at $GAME_ROOT (need default.xex + data/webkit/EAWebkit.xex)"
echo " It is required for codegen; it is NOT shipped in the release."
exit 1
fi
TU_ARGS=""
if [ -n "$TU" ]; then
if [ ! -f "$TU" ]; then echo "ERROR: title update package not found: $TU"; exit 1; fi
TU_ARGS="-DSKATE3_TITLE_UPDATE_PACKAGE=$TU"
fi
echo "==> Release $TAG ($EXT) preset=$PRESET game=$GAME_ROOT"
echo "==> Configure"
cmake --preset "$PRESET" -DSKATE3_GAME_DATA_ROOT="$GAME_ROOT" $TU_ARGS
echo "==> Generate recompiled code"
cmake --build --preset "$PRESET" --target generate-all --parallel
echo "==> Reconfigure (generated sources)"
cmake --preset "$PRESET" -DSKATE3_GAME_DATA_ROOT="$GAME_ROOT" $TU_ARGS
echo "==> Build"
cmake --build --preset "$PRESET" --parallel
# ---- package ---------------------------------------------------------------
OUT="out/build/$PRESET"
STAGE="$NAME"
rm -rf "$STAGE"; mkdir -p "$STAGE"
cp "$OUT/$BIN" "$STAGE/"
cp "$OUT/$LIB" "$STAGE/" 2>/dev/null || true
cp "$OUT/ghost_relay" "$STAGE/" 2>/dev/null || true
cp "$OUT/ghost_relay.exe" "$STAGE/" 2>/dev/null || true
# Title-update patches staged next to the binary when the build used the TU
if [ -f "$OUT/game/default.xexp" ]; then
mkdir -p "$STAGE/game/data/webkit"
cp "$OUT/game/default.xexp" "$STAGE/game/"
cp "$OUT/game/data/webkit/EAWebkit.xexp" "$STAGE/game/data/webkit/" 2>/dev/null || true
fi
cp README.md "$STAGE/"
rm -f "$NAME.zip"
zip -r "$NAME.zip" "$STAGE"
rm -rf "$STAGE"
echo "==> Packaged: $NAME.zip ($(du -h "$NAME.zip" | cut -f1))"
sha256sum "$NAME.zip"
# ---- publish ----------------------------------------------------------------
if [ "$UPLOAD" = 1 ]; then
: "${GITEA_TOKEN:?--upload needs GITEA_TOKEN}"
REPO_FULL="${FORGEJO_REPO:-ad3laid3/skate3recomp-multiplayer}"
INSTANCE="${FORGEJO_INSTANCE:-https://git.mithraic.cloud}"
AUTH="Authorization: token $GITEA_TOKEN"
echo "==> Publishing $NAME.zip to $INSTANCE/$REPO_FULL release '$TAG'"
RELEASE_ID="$(curl -s -X POST "$INSTANCE/api/v1/repos/$REPO_FULL/releases" \
-H "$AUTH" -H "Content-Type: application/json" \
-d "{\"tag_name\":\"$TAG\",\"name\":\"Skate 3 Recomp $TAG\",\"target_commitish\":\"main\"}" \
| python3 -c "import sys,json
try: print(json.load(sys.stdin).get('id',''))
except Exception: print('')")"
if [ -z "$RELEASE_ID" ]; then
RELEASE_ID="$(curl -s "$INSTANCE/api/v1/repos/$REPO_FULL/releases/tags/$TAG" -H "$AUTH" \
| python3 -c "import sys,json
try: print(json.load(sys.stdin).get('id',''))
except Exception: print('')")"
fi
if [ -z "$RELEASE_ID" ]; then
echo "ERROR: could not create/find release '$TAG'"; exit 1
fi
curl -s -X POST "$INSTANCE/api/v1/repos/$REPO_FULL/releases/$RELEASE_ID/assets" \
-H "$AUTH" -F "attachment=@$NAME.zip" -F "name=$NAME.zip" \
| python3 -c "import sys,json
try:
a=json.load(sys.stdin); print('Uploaded asset', a.get('name'), a.get('size'), 'bytes')
except Exception as e: print('upload response parse failed:', e)"
echo "==> Done: https://git.mithraic.cloud/$REPO_FULL/releases/tag/$TAG"
fi