3do: cut v1.0.0 -- broker-based multi-device tester. #26
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Release | |
| # Triggered by tags shaped like <console>-v<semver>, e.g. gcn-v0.1.0, | |
| # pce-v0.2.3, etc. The console subdir comes from the prefix; only that | |
| # console's app is built and attached to a GitHub Release. | |
| on: | |
| push: | |
| tags: | |
| - '*-v[0-9]+.[0-9]+.[0-9]+' | |
| - '*-v[0-9]+.[0-9]+.[0-9]+-*' # pre-release suffixes (alpha, rc, etc.) | |
| permissions: | |
| contents: write # needed to create the release | |
| env: | |
| FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: 'true' | |
| jobs: | |
| parse: | |
| name: Parse tag | |
| runs-on: ubuntu-latest | |
| outputs: | |
| console: ${{ steps.split.outputs.console }} | |
| version: ${{ steps.split.outputs.version }} | |
| title: ${{ steps.split.outputs.title }} | |
| steps: | |
| - id: split | |
| run: | | |
| TAG="${GITHUB_REF_NAME}" | |
| CONSOLE="${TAG%%-v*}" | |
| VERSION="${TAG#*-v}" | |
| case "$CONSOLE" in | |
| gcn) PRETTY="GameCube" ;; | |
| wii) PRETTY="Wii" ;; | |
| n64) PRETTY="Nintendo 64" ;; | |
| snes) PRETTY="Super Nintendo" ;; | |
| gba) PRETTY="Game Boy Advance" ;; | |
| pce) PRETTY="PC Engine" ;; | |
| 3do) PRETTY="3DO" ;; | |
| *) PRETTY="$CONSOLE" ;; | |
| esac | |
| echo "console=$CONSOLE" >> "$GITHUB_OUTPUT" | |
| echo "version=$VERSION" >> "$GITHUB_OUTPUT" | |
| echo "title=Joypad Tester — $PRETTY v$VERSION" >> "$GITHUB_OUTPUT" | |
| build-and-release: | |
| name: Build + release ${{ needs.parse.outputs.console }} v${{ needs.parse.outputs.version }} | |
| needs: parse | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| submodules: recursive | |
| fetch-depth: 0 | |
| - name: Verify VERSION matches tag | |
| run: | | |
| FILE_VER="$(cat ${{ needs.parse.outputs.console }}/VERSION | tr -d '[:space:]')" | |
| if [ "$FILE_VER" != "${{ needs.parse.outputs.version }}" ]; then | |
| echo "::error::${{ needs.parse.outputs.console }}/VERSION ($FILE_VER) does not match tag (${{ needs.parse.outputs.version }})" | |
| exit 1 | |
| fi | |
| - name: Set up Python | |
| if: needs.parse.outputs.console == 'gcn' | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.12' | |
| - name: Install Pillow | |
| if: needs.parse.outputs.console == 'gcn' | |
| run: pip install --quiet Pillow | |
| - name: Generate banner | |
| if: needs.parse.outputs.console == 'gcn' | |
| working-directory: ${{ needs.parse.outputs.console }} | |
| run: python3 buildtools/make_banner.py opening.bnr | |
| - name: Generate screensaver logo header | |
| if: needs.parse.outputs.console == 'gcn' | |
| working-directory: ${{ needs.parse.outputs.console }} | |
| run: python3 buildtools/make_logo.py | |
| - name: Build (GameCube) | |
| if: needs.parse.outputs.console == 'gcn' | |
| run: | | |
| docker run --rm \ | |
| -v "${{ github.workspace }}":/workspace \ | |
| -w /workspace/${{ needs.parse.outputs.console }} \ | |
| -u "$(id -u):$(id -g)" \ | |
| ghcr.io/extremscorner/libogc2:latest \ | |
| bash -c "TARGET_CONSOLE=gamecube make && TARGET_CONSOLE=wii make" | |
| - name: Build (GBA — both variants) | |
| if: needs.parse.outputs.console == 'gba' | |
| run: | | |
| docker run --rm \ | |
| -v "${{ github.workspace }}":/workspace \ | |
| -w /workspace/gba \ | |
| -u "$(id -u):$(id -g)" \ | |
| devkitpro/devkitarm:latest \ | |
| make | |
| - name: Build (PC Engine) | |
| if: needs.parse.outputs.console == 'pce' | |
| run: | | |
| docker build -t joypad-tester-huc:release pce/buildtools/ | |
| docker run --rm \ | |
| -v "${{ github.workspace }}":/workspace \ | |
| -w /workspace/pce \ | |
| -u "$(id -u):$(id -g)" \ | |
| joypad-tester-huc:release \ | |
| make | |
| - name: Build (3DO) | |
| if: needs.parse.outputs.console == '3do' | |
| run: | | |
| cd 3do | |
| mkdir -p build .wine-home | |
| docker build --platform=linux/amd64 -t joypad-tester-3do:release buildtools/ | |
| docker run --rm \ | |
| --platform=linux/amd64 \ | |
| -v "$(pwd):/work" \ | |
| -u "$(id -u):$(id -g)" \ | |
| -e HOME=/work/.wine-home \ | |
| joypad-tester-3do:release \ | |
| bash -c " | |
| set -e | |
| cp /work/src/main.cpp /opt/3do-devkit/src/main.cpp | |
| cd /opt/3do-devkit | |
| make NAME=joypad-tester | |
| cp iso/joypad-tester.iso /work/build/joypad-tester.iso | |
| " | |
| - name: Stage release artifacts (GameCube) | |
| if: needs.parse.outputs.console == 'gcn' | |
| working-directory: ${{ needs.parse.outputs.console }} | |
| run: | | |
| # Three release artifacts: | |
| # joypad_tester_v<ver>_gcn.zip -- pre-built Swiss folder | |
| # layout for GC SD-card loaders (FlippyDrive, GC Loader, | |
| # SD2SP2, etc.). Contains Joypad Tester/{default.dol, | |
| # opening.bnr}, ready to drop on an SD root. | |
| # joypad_tester_v<ver>_gcn.iso -- bootable iso9660 + El | |
| # Torito disc image (homebrew apploader from | |
| # buildtools/apploader/gbi.hdr + the GC .dol renamed to | |
| # bootldr.dol + opening.bnr in the file tree). Suitable | |
| # for DVD-R burn / IPL-replacement modchips / Dolphin / | |
| # ODE flash carts that prefer ISO over folder layout. | |
| # joypad_tester_v<ver>_wii.dol -- bare Wii build for the | |
| # Homebrew Channel. | |
| sudo apt-get update -qq | |
| sudo apt-get install -y -qq --no-install-recommends genisoimage | |
| VERSION="${{ needs.parse.outputs.version }}" | |
| mkdir -p _release | |
| if [ -f joypad-tester-gamecube.dol ] && [ -f opening.bnr ]; then | |
| # Swiss-folder ZIP | |
| mkdir -p "_stage/Joypad Tester" | |
| cp joypad-tester-gamecube.dol "_stage/Joypad Tester/default.dol" | |
| cp opening.bnr "_stage/Joypad Tester/opening.bnr" | |
| (cd _stage && zip -r "../_release/joypad_tester_v${VERSION}_gcn.zip" "Joypad Tester") | |
| # Bootable ISO: bushing's open-source apploader (gbi.hdr, | |
| # vendored in buildtools/apploader/) wraps a bootldr.dol + | |
| # any extra disc-tree files. mkisofs composes the | |
| # iso9660 image with the El Torito boot extension. | |
| rm -rf _iso_stage | |
| mkdir -p _iso_stage | |
| cp joypad-tester-gamecube.dol _iso_stage/bootldr.dol | |
| cp opening.bnr _iso_stage/opening.bnr | |
| mkisofs -R -J -G buildtools/apploader/gbi.hdr \ | |
| -no-emul-boot -b bootldr.dol \ | |
| -o "_release/joypad_tester_v${VERSION}_gcn.iso" \ | |
| _iso_stage/ | |
| rm -rf _stage _iso_stage | |
| fi | |
| [ -f joypad-tester-wii.dol ] && cp joypad-tester-wii.dol "_release/joypad_tester_v${VERSION}_wii.dol" | |
| ls -la _release/ | |
| - name: Stage release artifacts (GBA) | |
| if: needs.parse.outputs.console == 'gba' | |
| working-directory: gba | |
| run: | | |
| # Public release ships only the user-facing tester ROM. | |
| # The eyes variant (joypad_mb.gba) is a firmware payload meant | |
| # to be multibooted by a separate host (joypad-os keeps its | |
| # own copy for that role), not run standalone -- end-users | |
| # downloading the release want a playable joypad tester. The | |
| # eyes build still lives in gba/build/ for source-tree | |
| # consumers but doesn't get a Release attachment. | |
| # Flash-cart-friendly name: joypad_tester_v<ver>.gba. | |
| VERSION="${{ needs.parse.outputs.version }}" | |
| mkdir -p _release | |
| cp build/tester/tester_mb.gba "_release/joypad_tester_v${VERSION}.gba" | |
| ls -la _release/ | |
| - name: Stage release artifacts (PC Engine) | |
| if: needs.parse.outputs.console == 'pce' | |
| working-directory: pce | |
| run: | | |
| # Flash-cart-friendly name: joypad_tester_v<ver>.pce. | |
| VERSION="${{ needs.parse.outputs.version }}" | |
| mkdir -p _release | |
| cp build/joypad-tester.pce "_release/joypad_tester_v${VERSION}.pce" | |
| ls -la _release/ | |
| - name: Stage release artifacts (3DO) | |
| if: needs.parse.outputs.console == '3do' | |
| working-directory: 3do | |
| run: | | |
| # Single .iso artifact; emulators + flash-friendly burn target. | |
| VERSION="${{ needs.parse.outputs.version }}" | |
| mkdir -p _release | |
| cp build/joypad-tester.iso "_release/joypad_tester_v${VERSION}_3do.iso" | |
| ls -la _release/ | |
| - name: Build release body | |
| id: notes | |
| working-directory: ${{ needs.parse.outputs.console }} | |
| run: | | |
| # Keep the release page tight: the CHANGELOG file is the | |
| # source of truth for the version-by-version highlights, | |
| # and the Assets section below auto-lists every attached | |
| # artifact. The body just points at the changelog. | |
| CONSOLE="${{ needs.parse.outputs.console }}" | |
| REPO="https://github.com/${{ github.repository }}" | |
| # Skip the anchor -- GitHub munges header text (drops dots, | |
| # collapses em-dashes) so #v1.0.0--2026-05-11 etc. doesn't | |
| # match deterministically. Top of the changelog is the | |
| # latest version anyway. | |
| cat > _notes.md <<EOF | |
| See [\`${CONSOLE}/CHANGELOG.md\`](${REPO}/blob/main/${CONSOLE}/CHANGELOG.md) for release details. | |
| EOF | |
| - name: Create GitHub Release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| name: ${{ needs.parse.outputs.title }} | |
| body_path: ${{ needs.parse.outputs.console }}/_notes.md | |
| draft: false | |
| prerelease: ${{ contains(github.ref_name, '-alpha') || contains(github.ref_name, '-beta') || contains(github.ref_name, '-rc') }} | |
| files: ${{ needs.parse.outputs.console }}/_release/* |