Merge branch 'dev' into find-mods-release-stats

Resolve conflicts with the dev rewrite:

- LauncherView.lua / RomImporter.lua / ModUpdate.lua /
  docs/new-features.md: dev already carries the Find Mods stats &
  sort work (in evolved async form), so take dev's versions. The
  auto-merge's duplicate blocking _findStats is dropped.
- release.yml: keep dev's split version/love-payload/linux-arm64/
  xbox-uwp job structure and re-wire the Linux ARM SBC PortMaster
  step to needs.version.outputs.version (steps.ver no longer exists).

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Shane McGovern
2026-08-11 11:30:15 +01:00
605 changed files with 99665 additions and 38119 deletions
+193
View File
@@ -181,6 +181,196 @@ jobs:
if-no-files-found: error
retention-days: 7
xbox-uwp-changes:
name: detect Xbox UWP changes
runs-on: ubuntu-latest
outputs:
changed: ${{ steps.paths.outputs.changed }}
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- id: paths
env:
BASE_SHA: ${{ github.event.pull_request.base.sha || github.event.before }}
HEAD_SHA: ${{ github.sha }}
run: |
if [ -z "$BASE_SHA" ] || [ "$BASE_SHA" = "0000000000000000000000000000000000000000" ]; then
echo "changed=true" >> "$GITHUB_OUTPUT"
exit 0
fi
if git diff --name-only "$BASE_SHA" "$HEAD_SHA" | grep -Eq '^(ports/uwp/|scripts/build_xbox_uwp\.sh$|scripts/xbox-uwp/|scripts/pack_love\.sh$|\.github/workflows/(ci|release)\.yml$|src/core/Platform\.lua$|src/import/(CacheFs|LauncherView|RomImporter)\.lua$|src/update/Check\.lua$|tests/engine/(platform_nx|uwp_baseroms|uwp_native_picker)_test\.lua$|tests/rom_importer_double_pick_test\.lua$)'; then
echo "changed=true" >> "$GITHUB_OUTPUT"
else
echo "changed=false" >> "$GITHUB_OUTPUT"
fi
xbox-uwp-selftest:
name: Xbox UWP offline selftest
needs: xbox-uwp-changes
if: needs.xbox-uwp-changes.outputs.changed == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- name: Xbox UWP offline selftest
run: bash scripts/xbox-uwp/selftest_build_xbox_uwp.sh
- name: Build shared payload
run: |
scripts/pack_love.sh \
--output .bazinga/work/ci-game.love \
--listing .bazinga/work/ci-love-listing.txt \
--version 0.0.0
- name: Upload shared payload
uses: actions/upload-artifact@v7
with:
name: gen1recomp-xbox-uwp-payload
path: .bazinga/work/ci-game.love
if-no-files-found: error
retention-days: 1
xbox-uwp-build:
name: Xbox UWP build
needs: [xbox-uwp-changes, xbox-uwp-selftest]
if: |
always()
&& needs.xbox-uwp-changes.outputs.changed == 'true'
&& needs.xbox-uwp-selftest.result == 'success'
runs-on: windows-2022
steps:
- uses: actions/checkout@v7
- name: Download shared payload
uses: actions/download-artifact@v8
with:
name: gen1recomp-xbox-uwp-payload
path: .bazinga/work
- name: Build Xbox UWP package
shell: bash
run: |
bash scripts/build_xbox_uwp.sh \
--release \
--version 0.0.0 \
--game-love .bazinga/work/ci-game.love
- name: Upload Xbox UWP package
uses: actions/upload-artifact@v7
with:
name: gen1recomp-xbox-uwp
path: |
dist/xbox-uwp/gen1recomp-0.0.0-xbox-uwp.zip
dist/xbox-uwp/gen1recomp-0.0.0-xbox-uwp.zip.sha256
if-no-files-found: error
retention-days: 7
linux-arm64-changes:
name: detect Linux arm64 changes
runs-on: ubuntu-latest
outputs:
changed: ${{ steps.paths.outputs.changed }}
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- id: paths
env:
BASE_SHA: ${{ github.event.pull_request.base.sha || github.event.before }}
HEAD_SHA: ${{ github.sha }}
run: |
if [ -z "$BASE_SHA" ] || [ "$BASE_SHA" = "0000000000000000000000000000000000000000" ]; then
echo "changed=true" >> "$GITHUB_OUTPUT"
exit 0
fi
if git diff --name-only "$BASE_SHA" "$HEAD_SHA" | grep -Eq '^(scripts/build_linux_arm64\.sh$|scripts/linux-arm64/|scripts/pack_love\.sh$|docs/linux-arm64-build\.md$|\.github/workflows/(ci|release)\.yml$)'; then
echo "changed=true" >> "$GITHUB_OUTPUT"
else
echo "changed=false" >> "$GITHUB_OUTPUT"
fi
linux-arm64-selftest:
name: Linux arm64 offline selftest
needs: linux-arm64-changes
if: needs.linux-arm64-changes.outputs.changed == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
# Deliberately on x86_64: everything this gate checks (pins, the
# host-arch guard, the dependency exclude list, the AppRun fusion
# contract) is answerable without a container or an aarch64 machine,
# so the slow native job below only ever starts on a sane tree.
- name: Linux arm64 offline selftest
run: bash scripts/linux-arm64/selftest_build_linux_arm64.sh
linux-arm64-build:
name: Linux arm64 AppImage build
needs: [linux-arm64-changes, linux-arm64-selftest]
if: |
always()
&& needs.linux-arm64-changes.outputs.changed == 'true'
&& needs.linux-arm64-selftest.result == 'success'
# No fork restriction, unlike switch-build: this needs no secrets and no
# self-hosted hardware, just GitHub's free arm64 runner for public repos,
# so contributors get the same coverage on their own PRs.
runs-on: ubuntu-24.04-arm
steps:
- uses: actions/checkout@v7
- name: Build the aarch64 AppImage
run: |
set -euo pipefail
scripts/build_linux_arm64.sh --version 0.0.0
- name: Verify the AppImage is self-contained and bullseye-compatible
run: |
set -euo pipefail
image="dist/linux-arm64/gen1recomp-0.0.0-linux-arm64.AppImage"
# --appimage-extract needs no FUSE, so this works on a runner
# without /dev/fuse and still exercises the real payload.
"$image" --appimage-extract >/dev/null
for required in AppRun bin/love game.love lib/liblove-11.5.so; do
[ -e "squashfs-root/$required" ] \
|| { echo "::error::AppImage is missing $required"; exit 1; }
done
# Every bundled object must resolve once AppRun's LD_LIBRARY_PATH is
# applied; an unresolved soname here is a user-visible launch crash.
#
# This runs on a HEADLESS runner on purpose, and that is the point.
# The first version of this build bundled Debian's SDL2, which
# hard-links libpulse/libasound/libX11/libwayland, so it only ever
# started on a full desktop -- a bare runner is what exposed it.
missing="$(LD_LIBRARY_PATH="$PWD/squashfs-root/lib" \
ldd squashfs-root/bin/love squashfs-root/lib/*.so* 2>/dev/null \
| grep 'not found' || true)"
[ -z "$missing" ] || { echo "::error::unresolved deps:"; echo "$missing"; exit 1; }
# Nothing may hard-link a driver, session or audio-stack library:
# those must be reached through dlopen so the AppImage runs on a box
# with only ALSA, only Wayland, or only KMSDRM.
linked="$(for f in squashfs-root/bin/love squashfs-root/lib/*.so*; do
objdump -p "$f" 2>/dev/null | awk '/NEEDED/{print $2}'
done | sort -u | grep -E '^lib(pulse|asound|X11|wayland|GL|EGL|drm|gbm|xcb|cairo|sndio|dbus)' || true)"
[ -z "$linked" ] \
|| { echo "::error::these must be dlopened, not linked:"; echo "$linked"; exit 1; }
# The whole point of compiling on bullseye. If a future change moves
# the builder to a newer base, the glibc floor silently rises and
# every user on an older distro gets "GLIBC_2.xx not found" -- catch
# it here instead of in a release.
floor="$(objdump -T squashfs-root/bin/love squashfs-root/lib/*.so* 2>/dev/null \
| grep -o 'GLIBC_[0-9.]*' | sort -V | tail -1)"
echo "highest required glibc symbol version: $floor"
[ -n "$floor" ] \
|| { echo "::error::found no versioned glibc symbols -- objdump read nothing"; exit 1; }
highest="$(printf '%s\n' "$floor" "GLIBC_2.31" | sort -V | tail -1)"
[ "$highest" = "GLIBC_2.31" ] \
|| { echo "::error::AppImage requires $floor, above the bullseye 2.31 floor"; exit 1; }
- name: Upload the AppImage
uses: actions/upload-artifact@v7
with:
name: gen1recomp-linux-arm64
path: |
dist/linux-arm64/gen1recomp-0.0.0-linux-arm64.AppImage
dist/linux-arm64/gen1recomp-0.0.0-linux-arm64.AppImage.sha256
if-no-files-found: error
retention-days: 7
headless:
name: headless suites (no ROM)
runs-on: ubuntu-latest
@@ -193,6 +383,9 @@ jobs:
- name: install luajit
run: sudo apt-get update && sudo apt-get install -y luajit
- name: install Pillow
run: python3 -m pip install --upgrade pillow
- name: interpreter version
run: luajit -v
+198 -29
View File
@@ -1,8 +1,8 @@
name: Release
# Builds the macOS, Windows, and Linux desktop apps, an Android APK, an iOS
# IPA, a Nintendo Switch SD-ready zip (experimental), the Anbernic RG34XXSP
# (Stock OS 64-bit MOD / PortMaster) and Linux ARM SBC PortMaster
# IPA, a Nintendo Switch SD-ready zip (experimental), Xbox UWP, the Anbernic
# RG34XXSP (Stock OS 64-bit MOD / PortMaster) and Linux ARM SBC PortMaster
# handheld ports on the self-hosted Mac runner, and publishes them as a
# GitHub Release.
#
@@ -44,22 +44,17 @@ concurrency:
cancel-in-progress: false
jobs:
release:
runs-on: ${{ fromJSON(github.repository == 'bryanthaboi/gen1recomp' && '["self-hosted", "macOS"]' || '"macos-latest"') }}
version:
name: determine release version
runs-on: ubuntu-latest
outputs:
version: ${{ steps.ver.outputs.version }}
tag: ${{ steps.ver.outputs.tag }}
steps:
# The self-hosted runner lives under the machine owner's home
# directory; mask it first so absolute paths in every later step's
# output show up as *** in the public workflow logs.
- name: Mask runner paths
run: echo "::add-mask::$HOME"
- name: Checkout
uses: actions/checkout@v7
- uses: actions/checkout@v7
with:
fetch-depth: 0
fetch-tags: true
- name: Determine version
id: ver
env:
@@ -67,7 +62,6 @@ jobs:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
semver_re='^[0-9]+\.[0-9]+\.[0-9]+$'
# 1) Explicit override from a manual run.
@@ -97,7 +91,6 @@ jobs:
| grep -E "$semver_re" \
| sort -t. -k1,1n -k2,2n -k3,3n \
| tail -1 || true)"
if [ -z "$latest" ]; then
version="0.1.0"
echo "No existing release tag; starting at $version"
@@ -125,10 +118,157 @@ jobs:
echo "::error::Release $tag already exists. Pick a different version."
exit 1
fi
echo "version=$version" >> "$GITHUB_OUTPUT"
echo "tag=$tag" >> "$GITHUB_OUTPUT"
love-payload:
name: build release game.love
needs: version
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- name: Build shared payload
run: |
scripts/pack_love.sh \
--output dist/payload/game.love \
--listing dist/payload/love-listing.txt \
--version "${{ needs.version.outputs.version }}"
- name: Upload shared payload
uses: actions/upload-artifact@v7
with:
name: gen1recomp-release-love
path: dist/payload/game.love
if-no-files-found: error
retention-days: 1
linux-arm64:
name: build Linux arm64 AppImage
needs: [version, love-payload]
# GitHub's free arm64 runner for public repos. It has to be arm64: the
# AppImage compiles LÖVE natively inside a Debian bullseye arm64
# container, and the qemu-emulated alternative takes hours.
runs-on: ubuntu-24.04-arm
steps:
- uses: actions/checkout@v7
- name: Download shared payload
uses: actions/download-artifact@v8
with:
name: gen1recomp-release-love
path: .bazinga/work
- name: Build Linux arm64 AppImage
run: |
set -euo pipefail
scripts/build_linux_arm64.sh \
--version "${{ needs.version.outputs.version }}" \
--game-love .bazinga/work/game.love
- name: Upload Linux arm64 release
uses: actions/upload-artifact@v7
with:
name: gen1recomp-linux-arm64-release
path: |
dist/linux-arm64/gen1recomp-${{ needs.version.outputs.version }}-linux-arm64.AppImage
dist/linux-arm64/gen1recomp-${{ needs.version.outputs.version }}-linux-arm64.AppImage.sha256
if-no-files-found: error
retention-days: 1
xbox-uwp:
name: build Xbox UWP release
needs: [version, love-payload]
runs-on: windows-2022
steps:
- uses: actions/checkout@v7
- name: Download shared payload
uses: actions/download-artifact@v8
with:
name: gen1recomp-release-love
path: .bazinga/work
- name: Prepare signing certificate
shell: pwsh
env:
CERTIFICATE_BASE64: ${{ secrets.XBOX_UWP_SIGNING_CERTIFICATE }}
CERTIFICATE_PASSWORD: ${{ secrets.XBOX_UWP_SIGNING_PASSWORD }}
CANONICAL_REPOSITORY: ${{ github.repository == 'bryanthaboi/gen1recomp' }}
run: |
if ($env:CANONICAL_REPOSITORY -eq 'true' -and
[string]::IsNullOrWhiteSpace($env:CERTIFICATE_BASE64)) {
throw 'XBOX_UWP_SIGNING_CERTIFICATE is not configured.'
}
if ([string]::IsNullOrWhiteSpace($env:CERTIFICATE_BASE64)) {
"UWP_PUBLISHER=CN=Gen1Recomp" | Out-File $env:GITHUB_ENV -Append
exit 0
}
$pfx = Join-Path $env:RUNNER_TEMP 'gen1recomp-uwp.pfx'
[IO.File]::WriteAllBytes($pfx, [Convert]::FromBase64String($env:CERTIFICATE_BASE64))
$flags = [Security.Cryptography.X509Certificates.X509KeyStorageFlags]::EphemeralKeySet
$cert = [Security.Cryptography.X509Certificates.X509Certificate2]::new(
$pfx, $env:CERTIFICATE_PASSWORD, $flags)
$cer = Join-Path $env:RUNNER_TEMP 'gen1recomp-uwp.cer'
[IO.File]::WriteAllBytes(
$cer,
$cert.Export([Security.Cryptography.X509Certificates.X509ContentType]::Cert))
Import-Certificate -FilePath $cer -CertStoreLocation Cert:\LocalMachine\TrustedPeople | Out-Null
"UWP_PFX=$pfx" | Out-File $env:GITHUB_ENV -Append
"UWP_CERT_THUMBPRINT=$($cert.Thumbprint)" | Out-File $env:GITHUB_ENV -Append
"UWP_PUBLISHER=$($cert.Subject)" | Out-File $env:GITHUB_ENV -Append
- name: Build Xbox UWP package
shell: bash
run: |
bash scripts/build_xbox_uwp.sh \
--release \
--version "${{ needs.version.outputs.version }}" \
--publisher "$UWP_PUBLISHER" \
--game-love .bazinga/work/game.love
- name: Sign and stage Xbox UWP release
shell: pwsh
env:
CERTIFICATE_PASSWORD: ${{ secrets.XBOX_UWP_SIGNING_PASSWORD }}
run: |
if (-not $env:UWP_PFX) {
exit 0
}
scripts/xbox-uwp/stage_release.ps1 `
-Version '${{ needs.version.outputs.version }}' `
-Configuration Release `
-BuildInfo .bazinga/work/xbox-uwp-build-info.json `
-CertificatePath $env:UWP_PFX `
-CertificatePassword $env:CERTIFICATE_PASSWORD
- name: Upload Xbox UWP release
uses: actions/upload-artifact@v7
with:
name: gen1recomp-xbox-uwp-release
path: |
dist/xbox-uwp/gen1recomp-${{ needs.version.outputs.version }}-xbox-uwp.zip
dist/xbox-uwp/gen1recomp-${{ needs.version.outputs.version }}-xbox-uwp.zip.sha256
if-no-files-found: error
retention-days: 1
- name: Remove signing certificate
if: always()
shell: pwsh
run: |
if ($env:UWP_CERT_THUMBPRINT) {
Remove-Item "Cert:\LocalMachine\TrustedPeople\$env:UWP_CERT_THUMBPRINT" -ErrorAction SilentlyContinue
}
if ($env:UWP_PFX) {
Remove-Item $env:UWP_PFX -Force -ErrorAction SilentlyContinue
}
release:
needs: [version, xbox-uwp, linux-arm64]
runs-on: ${{ fromJSON(github.repository == 'bryanthaboi/gen1recomp' && '["self-hosted", "macOS"]' || '"macos-latest"') }}
steps:
# The self-hosted runner lives under the machine owner's home
# directory; mask it first so absolute paths in every later step's
# output show up as *** in the public workflow logs.
- name: Mask runner paths
run: echo "::add-mask::$HOME"
- name: Checkout
uses: actions/checkout@v7
with:
fetch-depth: 0
fetch-tags: true
- name: Import signing certificate into a temporary keychain
if: github.repository == 'bryanthaboi/gen1recomp'
run: |
@@ -173,12 +313,12 @@ jobs:
# notarize separately below so it uses secret credentials, not a
# login-keychain profile. "all" also builds the Linux AppImage,
# which needs no signing/notarization.
scripts/build.sh all --version "${{ steps.ver.outputs.version }}" --no-notarize
scripts/build.sh all --version "${{ needs.version.outputs.version }}" --no-notarize
- name: Build Android
run: |
set -euo pipefail
scripts/build_android.sh --version "${{ steps.ver.outputs.version }}"
scripts/build_android.sh --version "${{ needs.version.outputs.version }}"
- name: Install xcbeautify
run: |
@@ -192,10 +332,10 @@ jobs:
set -euo pipefail
if [ "$CANONICAL_REPOSITORY" = true ]; then
scripts/build_ios.sh --fetch --device --release \
--version "${{ steps.ver.outputs.version }}"
--version "${{ needs.version.outputs.version }}"
else
scripts/build_ios.sh --fetch --release \
--version "${{ steps.ver.outputs.version }}"
--version "${{ needs.version.outputs.version }}"
fi
- name: Build Switch
@@ -207,14 +347,14 @@ jobs:
# Needs native switch-tools (nacptool/elf2nro) and/or Docker on the
# Mac self-hosted runner; see docs/switch-build.md.
scripts/build_switch.sh --fetch --fused \
--version "${{ steps.ver.outputs.version }}"
--version "${{ needs.version.outputs.version }}"
- name: Build Anbernic RG34XXSP port
run: |
set -euo pipefail
# Self-contained aarch64 PortMaster-style pack; pulls the LÖVE 11.5
# runtime from PortMaster-GUI, so it needs no signing/notarization.
./build-rg34xxsp.sh --version "${{ steps.ver.outputs.version }}"
./build-rg34xxsp.sh --version "${{ needs.version.outputs.version }}"
- name: Build Linux ARM SBC PortMaster port
env:
@@ -222,13 +362,13 @@ jobs:
# script defaults to the latest published release for standalone
# builds, while this explicit local override keeps CI source-aligned.
GEN1RECOMP_SOURCE_DIR: ${{ github.workspace }}
GEN1RECOMP_RELEASE_TAG: v${{ steps.ver.outputs.version }}
GEN1RECOMP_RELEASE_TAG: v${{ needs.version.outputs.version }}
run: |
set -euo pipefail
# Same aarch64 PortMaster-style pack for Linux ARM SBC PortMaster. The build
# keeps its own cache because the two scripts use different staging
# layouts and runtime package paths.
./build-linux-arm-sbc.sh --version "${{ steps.ver.outputs.version }}"
./build-linux-arm-sbc.sh --version "${{ needs.version.outputs.version }}"
- name: Notarize & staple macOS app
if: github.repository == 'bryanthaboi/gen1recomp'
@@ -265,18 +405,41 @@ jobs:
ditto -c -k --sequesterRsrc --keepParent "$app" "$zip"
echo "Notarized + stapled ✓"
- name: Download Xbox UWP release
if: github.repository == 'bryanthaboi/gen1recomp'
uses: actions/download-artifact@v8
with:
name: gen1recomp-xbox-uwp-release
path: dist/xbox-uwp
- name: Download Linux arm64 release
if: github.repository == 'bryanthaboi/gen1recomp'
uses: actions/download-artifact@v8
with:
name: gen1recomp-linux-arm64-release
path: dist/linux-arm64
- name: Stage release assets
if: github.repository == 'bryanthaboi/gen1recomp'
id: assets
run: |
set -euo pipefail
v="${{ steps.ver.outputs.version }}"
v="${{ needs.version.outputs.version }}"
outdir="dist/release"
rm -rf "$outdir"
mkdir -p "$outdir"
cp "dist/mac/gen1recomp-macos.zip" "$outdir/gen1recomp-${v}-macos.zip"
cp "dist/win/gen1recomp-win64.zip" "$outdir/gen1recomp-${v}-windows.zip"
cp "dist/linux/gen1recomp-linux.zip" "$outdir/gen1recomp-${v}-linux.zip"
# arm64 desktop Linux (Raspberry Pi, Armbian, arm64 VMs). Built on
# its own runner because LÖVE publishes no aarch64 binary and the
# AppImage has to be compiled natively; ships as a runnable
# AppImage rather than a zip so `chmod +x && ./it` just works.
arm64_appimage="dist/linux-arm64/gen1recomp-${v}-linux-arm64.AppImage"
[ -f "$arm64_appimage" ] || { echo "::error::$arm64_appimage not found (expected from the linux-arm64 job)"; exit 1; }
cp "$arm64_appimage" "$outdir/gen1recomp-${v}-linux-arm64.AppImage"
chmod +x "$outdir/gen1recomp-${v}-linux-arm64.AppImage"
apk="$(find dist/android/debug -name '*.apk' | head -1)"
[ -n "$apk" ] || { echo "::error::no Android APK found under dist/android/debug"; exit 1; }
cp "$apk" "$outdir/gen1recomp-${v}-android.apk"
@@ -291,6 +454,10 @@ jobs:
# Local fused .nro stays under dist/switch/ for PR CI / debug; release
# publishes the SD-ready zip only.
uwp="dist/xbox-uwp/gen1recomp-${v}-xbox-uwp.zip"
[ -f "$uwp" ] || { echo "::error::$uwp not found (expected from the Xbox UWP job)"; exit 1; }
cp "$uwp" "$outdir/gen1recomp-${v}-xbox-uwp.zip"
# Anbernic handheld port (suffix names the CFW it targets, so a
# future RG35XX/other-CFW pack can ship alongside it).
rg34="dist/rg34xxsp/gen1recomp-rg34xxsp-stockos64-mod.zip"
@@ -322,8 +489,8 @@ jobs:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
v="${{ steps.ver.outputs.version }}"
tag="${{ steps.ver.outputs.tag }}"
v="${{ needs.version.outputs.version }}"
tag="${{ needs.version.outputs.tag }}"
# Issues this release closes. Three sources, deduped by number:
# 1. GitHub's own "closing issues" links on every PR whose
@@ -411,9 +578,11 @@ jobs:
"dist/release/gen1recomp-${v}-macos.zip"
"dist/release/gen1recomp-${v}-windows.zip"
"dist/release/gen1recomp-${v}-linux.zip"
"dist/release/gen1recomp-${v}-linux-arm64.AppImage"
"dist/release/gen1recomp-${v}-android.apk"
"dist/release/gen1recomp-${v}-ios.ipa"
"dist/release/gen1recomp-${v}-switch.zip"
"dist/release/gen1recomp-${v}-xbox-uwp.zip"
"dist/release/gen1recomp-${v}-rg34xxsp-stockos64-mod.zip"
"dist/release/gen1recomp-${v}-sbc-portmaster.zip"
"dist/release/gen1recomp-${v}.love"
@@ -432,7 +601,7 @@ jobs:
if: github.repository == 'bryanthaboi/gen1recomp'
run: |
set -euo pipefail
v="${{ steps.ver.outputs.version }}"
v="${{ needs.version.outputs.version }}"
ipa="dist/release/gen1recomp-${v}-ios.ipa"
app_repo="mobile/ios/app-repo.json"
[ -f "$ipa" ] || { echo "::error::$ipa not found"; exit 1; }