Skip to content

Commit 85196fc

Browse files
gba: set up release/versioning + add top-level CLAUDE.md
Mirror the gamecube/ subdir's release pattern for gba/: VERSION (0.1.0), CHANGELOG.md, and LICENSE.md (renamed from LICENSE for consistency). Wire the GBA into both CI workflows: - verify-build: new matrix entry using devkitpro/devkitarm:latest, uploading both joypad_* and tester_* artifacts. - release: gate gamecube-only steps (Python/Pillow/banner/logo) behind needs.parse.outputs.console == 'gamecube', add GBA build step, and split staging into per-console variants. Add CLAUDE.md documenting the per-console subdir pattern (VERSION / CHANGELOG / LICENSE / Makefile), the tag-driven release convention (<console>-v<semver>), the workflow extension model, and embedding conventions (payload symbol-name stability across variants), so adding N64/SNES/etc. doesn't require relearning the structure.
1 parent ccb0dea commit 85196fc

6 files changed

Lines changed: 215 additions & 2 deletions

File tree

.github/workflows/release.yml

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,14 +61,17 @@ jobs:
6161
fi
6262
6363
- name: Set up Python
64+
if: needs.parse.outputs.console == 'gamecube'
6465
uses: actions/setup-python@v5
6566
with:
6667
python-version: '3.12'
6768

6869
- name: Install Pillow
70+
if: needs.parse.outputs.console == 'gamecube'
6971
run: pip install --quiet Pillow
7072

7173
- name: Generate banner
74+
if: needs.parse.outputs.console == 'gamecube'
7275
working-directory: ${{ needs.parse.outputs.console }}
7376
run: python3 buildtools/make_banner.py opening.bnr
7477

@@ -87,16 +90,37 @@ jobs:
8790
ghcr.io/extremscorner/libogc2:latest \
8891
bash -c "apt-get install -y -qq --no-install-recommends -t bookworm-backports xorriso 2>/dev/null; TARGET_CONSOLE=gamecube make && TARGET_CONSOLE=wii make"
8992
90-
- name: Stage release artifacts
93+
- name: Build (GBA — both variants)
94+
if: needs.parse.outputs.console == 'gba'
95+
run: |
96+
docker run --rm \
97+
-v "${{ github.workspace }}":/workspace \
98+
-w /workspace/gba \
99+
-u "$(id -u):$(id -g)" \
100+
devkitpro/devkitarm:latest \
101+
make
102+
103+
- name: Stage release artifacts (GameCube)
104+
if: needs.parse.outputs.console == 'gamecube'
91105
working-directory: ${{ needs.parse.outputs.console }}
92106
run: |
93107
mkdir -p _release
94-
# Copy whatever .dol files the build produced + the banner.
95108
for f in *.dol opening.bnr; do
96109
[ -f "$f" ] && cp "$f" _release/
97110
done
98111
ls -la _release/
99112
113+
- name: Stage release artifacts (GBA)
114+
if: needs.parse.outputs.console == 'gba'
115+
working-directory: gba
116+
run: |
117+
mkdir -p _release
118+
cp build/joypad/joypad_mb.gba _release/
119+
cp build/joypad/joypad_payload.c _release/
120+
cp build/tester/tester_mb.gba _release/
121+
cp build/tester/tester_payload.c _release/
122+
ls -la _release/
123+
100124
- name: Extract changelog section for this version
101125
id: notes
102126
working-directory: ${{ needs.parse.outputs.console }}

.github/workflows/verify-build.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@ jobs:
2424
gamecube/joypad-tester-gamecube.dol
2525
gamecube/joypad-tester-wii.dol
2626
gamecube/opening.bnr
27+
- console: gba
28+
image: devkitpro/devkitarm:latest
29+
artifacts: |
30+
gba/build/joypad/joypad_mb.gba
31+
gba/build/joypad/joypad_payload.c
32+
gba/build/tester/tester_mb.gba
33+
gba/build/tester/tester_payload.c
2734
steps:
2835
- name: Checkout
2936
uses: actions/checkout@v4
@@ -37,9 +44,11 @@ jobs:
3744
python-version: '3.12'
3845

3946
- name: Install Pillow (for banner generation)
47+
if: matrix.console == 'gamecube'
4048
run: pip install --quiet Pillow
4149

4250
- name: Generate banner
51+
if: matrix.console == 'gamecube'
4352
working-directory: ${{ matrix.console }}
4453
run: python3 buildtools/make_banner.py opening.bnr
4554

@@ -68,6 +77,16 @@ jobs:
6877
${{ matrix.image }} \
6978
bash -c "TARGET_CONSOLE=wii make"
7079
80+
- name: Build (GBA — both variants)
81+
if: matrix.console == 'gba'
82+
run: |
83+
docker run --rm \
84+
-v "${{ github.workspace }}":/workspace \
85+
-w /workspace/gba \
86+
-u "$(id -u):$(id -g)" \
87+
${{ matrix.image }} \
88+
make
89+
7190
- name: Upload artifacts
7291
uses: actions/upload-artifact@v4
7392
with:

CLAUDE.md

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
# CLAUDE.md — joypad-tester
2+
3+
This repo holds one test app per console, each in its own subdirectory.
4+
The patterns below describe how each console subdir is structured so
5+
that new consoles can be added without churning the top-level scaffolding
6+
or the CI/release wiring.
7+
8+
## Repository shape
9+
10+
```
11+
.
12+
├── CLAUDE.md # this file
13+
├── LICENSE.md # MIT, covers repo scaffolding + any future common/
14+
├── README.md # top-level overview
15+
├── .github/
16+
│ ├── FUNDING.yml # Sponsor button → RobertDaleSmith
17+
│ └── workflows/
18+
│ ├── verify-build.yml # matrix CI for every push/PR
19+
│ └── release.yml # tag-driven per-console releases
20+
├── <console>/ # one subdir per supported console
21+
│ ├── VERSION # bare semver string, e.g. "0.1.0"
22+
│ ├── CHANGELOG.md # console-scoped, header style: "## v0.1.0 — YYYY-MM-DD"
23+
│ ├── LICENSE.md # whatever the upstream code's licence is
24+
│ ├── README.md # console-scoped overview
25+
│ ├── Makefile # console-specific build
26+
│ ├── source/ (or ppc/, etc.)
27+
│ ├── build*/ # build outputs; intermediate files gitignored,
28+
│ │ # final artifacts (.dol/.gba/_payload.c) committed
29+
│ │ # if downstream consumers need them prebuilt
30+
│ └── ...
31+
└── common/ # (future) cross-console shared helpers
32+
```
33+
34+
Existing console subdirs at time of writing:
35+
36+
- `gamecube/` — GameCube + Wii test app (libogc2-based, builds .dol;
37+
also surfaces N64 controllers via the passive adapter on GC ports).
38+
Origin: zlib (corenting GC-Controller-Test); `gamecube/LICENSE.md`.
39+
- `gba/` — GBA multiboot payload, two variants from one source tree
40+
(eyes for joypad-os consumers, tester for the GameCube host or
41+
flashcart use). Origin: MIT (Doridian Joybus-PIO); `gba/LICENSE.md`.
42+
43+
## Console subdir conventions
44+
45+
Each console subdir is a self-contained product. Adding a new one
46+
should not require touching anything outside its own directory, with
47+
the exception of the two CI workflows and CLAUDE.md's "Existing console
48+
subdirs" list.
49+
50+
### Files every console subdir must have
51+
52+
| File | Purpose |
53+
|---------------|---------------------------------------------------------------|
54+
| `VERSION` | Bare semver string. Must match the release tag (see below). |
55+
| `CHANGELOG.md`| Per-console changelog. First section header `## v<semver> — <date>`. |
56+
| `LICENSE.md` | Whatever the upstream code's licence is (zlib, MIT, …). |
57+
| `README.md` | Audience-facing overview: what the app is, how to build, how to embed. |
58+
| `Makefile` | Build entrypoint. Use a Docker-based toolchain if it eases CI. |
59+
60+
### Build outputs
61+
62+
Intermediates (`*.o`, `*.d`, `*.elf`, `*.map`) should be `.gitignore`d.
63+
Final artifacts (`*.dol`, `*.gba`, `*_payload.c`) get committed **only
64+
when downstream consumers need them prebuilt** (e.g., joypad-os
65+
submodules `gba/` and consumes `build/joypad/joypad_payload.c` without
66+
running devkitARM). For consoles whose artifacts are end-user
67+
downloads only, leave them out of git and let the release workflow
68+
build them.
69+
70+
## CI: build verification (`.github/workflows/verify-build.yml`)
71+
72+
Runs on every push to `main` and every PR. Strategy is a matrix:
73+
74+
```yaml
75+
matrix:
76+
include:
77+
- console: <name>
78+
image: <docker image with the toolchain>
79+
artifacts: |
80+
<path/to/output1>
81+
<path/to/output2>
82+
```
83+
84+
Per-console steps are gated with `if: matrix.console == '<name>'` so a
85+
matrix entry only runs the build commands it needs. Adding a console
86+
means adding a matrix entry + the corresponding build step(s).
87+
88+
## CI: releases (`.github/workflows/release.yml`)
89+
90+
Tag-driven. Tag format: `<console>-v<semver>` (e.g. `gamecube-v0.1.0`,
91+
`gba-v0.2.3`). Pre-release suffixes allowed (`-alpha.1`, `-rc.2`, …).
92+
93+
The workflow:
94+
95+
1. Parses the tag to extract `<console>` and `<semver>`.
96+
2. Verifies `<console>/VERSION` matches the tag's version. (Mismatch
97+
fails the build — there's no auto-bump.)
98+
3. Builds the requested console (gated by `if:` on each build step,
99+
same pattern as verify-build).
100+
4. Stages release artifacts into `<console>/_release/` (also gated).
101+
5. Extracts the relevant section of `<console>/CHANGELOG.md` as the
102+
release body (`## v<semver> — <date>` to the next `## ` header).
103+
6. Creates a GitHub Release with the artifacts attached.
104+
105+
Adding a console = adding a build step + a stage-artifacts step (both
106+
gated on `if: needs.parse.outputs.console == '<name>'`), and a case for
107+
the pretty name in the `parse` job.
108+
109+
## Release flow for a console
110+
111+
To cut, e.g., `gba-v0.2.0`:
112+
113+
1. Bump `<console>/VERSION` to `0.2.0`.
114+
2. Prepend a new section to `<console>/CHANGELOG.md`:
115+
`## v0.2.0 — YYYY-MM-DD` followed by bullet-point release notes.
116+
3. Commit + push to `main`.
117+
4. Tag `<console>-v0.2.0` and push the tag.
118+
5. CI parses the tag, verifies VERSION, builds, and publishes the
119+
GitHub Release with artifacts + the changelog section as the body.
120+
121+
If `VERSION` doesn't match the tag, the release fails (intentional —
122+
forces the changelog and version-bump commits to land before the tag).
123+
124+
## When extending or refactoring
125+
126+
- Top-level scaffolding (workflows, CLAUDE.md, repo-wide README, top-
127+
level LICENSE.md) is shared and should stay generic. If a new
128+
console needs something fundamentally different that doesn't fit
129+
the conventions above, prefer extending the conventions (and
130+
documenting here) over per-console drift.
131+
- A `common/` dir for cross-console helpers is reserved and should
132+
inherit the top-level MIT licence.
133+
- Submodule consumers (joypad-os pulls in `gba/`) rely on the
134+
committed prebuilt artifacts in `build/`. Don't break that path
135+
without coordinating the consumer side.

gba/CHANGELOG.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Joypad Tester — GBA — Changelog
2+
3+
## v0.1.0 — 2026-05-11
4+
5+
Initial release. Two multiboot ROM variants built from one source tree.
6+
7+
### Eyes (`joypad_mb.gba`)
8+
- Doridian-style joybus controller + animated cartoon eyes overlay
9+
rendered to a Mode-4 framebuffer.
10+
- Per-emotion FG/pupil palette, dpad-as-self-centering-analog gaze,
11+
ACTIVE → wander → sleep cycle.
12+
- Intended for embedding into [joypad-os](https://github.com/joypad-ai/joypad-os)
13+
as the GBA-as-controller payload (RP2040 host).
14+
15+
### Tester (`tester_mb.gba`)
16+
- Doridian-style joybus controller + on-GBA text console with live
17+
button state in a 2-column layout.
18+
- Mode-4 page-flipped idle screensaver: 64×54 logo bounces with 7-colour
19+
cycle (red/green/yellow/blue/magenta/cyan/white) on every wall hit,
20+
matching the joypad-tester GameCube variant.
21+
- Intended for embedding into joypad-tester's GameCube/Wii host (so
22+
testers see visual feedback on the GBA itself) and for standalone use
23+
via flash cart as a pure button tester.
24+
25+
### Shared
26+
- Doridian joybus handshake taken verbatim from Joybus-PIO; modifying it
27+
breaks the cable's level-shifter MCU.
28+
- Robust joybus reset handling: `REG_JOYCNT.RST` polled inside the
29+
VBlank busy-wait so a host `cmd 0xFF` triggers `SystemCall(0x26)`
30+
within microseconds — enables clean hot-swap and host-reboot
31+
re-multiboot.
32+
- `bin2c.py` emits `joypad_payload[]` / `joypad_payload_len` from
33+
either variant, so the host's externs don't change when switching
34+
ROMs.
File renamed without changes.

gba/VERSION

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
0.1.0

0 commit comments

Comments
 (0)