chore(deploy): containerize services + Forgejo release pipeline (#33) #98

Merged
marco merged 3 commits from chore/deploy-pipeline into main 2026-07-19 20:25:42 +02:00
Owner

Closes #33. Mirrors the aac-board pipeline for IsoMmo.

Stacked on #97 (protocol version) — includes it; merge #97 first.

Server images

  • src/IsoMmo.Auth/Dockerfile + src/IsoMmo.GameServer/Dockerfile: SDK 10 -> aspnet 10, built-in non-root app user, /app/data writable volume, curl healthcheck on /health.
  • .dockerignore excludes client/tools/tests.
  • Game:SavePath: world.sav moves to the mounted volume while the map stays read-only in the image (was coupled under ContentRoot).

Pipeline

  • ci.yaml gains workflow_call.
  • release.yaml (on tag): test -> publish (matrix isommo-auth/isommo-gameserver -> Forgejo registry) -> release (changelog via marco/forgejo-ci) -> deploy (Semaphore webhook), plus a client job that publishes self-contained win-x64/osx-arm64/linux-x64 zips (with a config.json pre-pointed at mmo.homelab.devncode.it) + the asset editor, attached to the release.

Verified locally (docker compose)

Both images build, run healthy; Auth issues a JWT (issuer/audience isommo); the GameServer accepts a WS across containers with the right protocol version and rejects the wrong one (426).

Deploy tail (Ansible roles/isommo in home-infra-ng + Semaphore integration) is separate infra work.

Definition of Done

  • A tag builds+pushes both images, creates the release with client zips, and deploys to mmo.homelab.devncode.it.
  • https://mmo.homelab.devncode.it/health responds; wss://…/ws accepts a valid client.
Closes #33. Mirrors the aac-board pipeline for IsoMmo. **Stacked on #97 (protocol version)** — includes it; merge #97 first. ### Server images - `src/IsoMmo.Auth/Dockerfile` + `src/IsoMmo.GameServer/Dockerfile`: SDK 10 -> aspnet 10, built-in non-root `app` user, `/app/data` writable volume, `curl` healthcheck on `/health`. - `.dockerignore` excludes client/tools/tests. - **`Game:SavePath`**: `world.sav` moves to the mounted volume while the map stays read-only in the image (was coupled under ContentRoot). ### Pipeline - `ci.yaml` gains `workflow_call`. - `release.yaml` (on tag): `test` -> `publish` (matrix `isommo-auth`/`isommo-gameserver` -> Forgejo registry) -> `release` (changelog via `marco/forgejo-ci`) -> `deploy` (Semaphore webhook), plus a `client` job that publishes self-contained **win-x64/osx-arm64/linux-x64** zips (with a `config.json` pre-pointed at `mmo.homelab.devncode.it`) + the asset editor, attached to the release. ### Verified locally (docker compose) Both images build, run **healthy**; Auth issues a JWT (issuer/audience `isommo`); the GameServer accepts a WS across containers with the right protocol version and **rejects the wrong one (426)**. Deploy tail (Ansible `roles/isommo` in home-infra-ng + Semaphore integration) is separate infra work. ## Definition of Done - [ ] A tag builds+pushes both images, creates the release with client zips, and deploys to `mmo.homelab.devncode.it`. - [ ] `https://mmo.homelab.devncode.it/health` responds; `wss://…/ws` accepts a valid client.
feat(protocol): version the wire contract, reject mismatched clients
All checks were successful
ci / Lint & Test (pull_request) Successful in 1m28s
603c2043d2
Add ProtocolVersion.Current (Shared/Protocol). The client sends it at connect
(/ws?...&v=); the server rejects a mismatched version with HTTP 426 before any
handshake, so a stale client can't talk a desynced protocol once client and
server ship as separate releases. Bump the const on any wire-contract change
(rule added to CLAUDE.md). Integration test: a wrong version is rejected.
chore(deploy): containerize Auth + GameServer, add Forgejo release pipeline (#33)
Some checks failed
ci / Lint & Test (pull_request) Successful in 1m54s
release / Lint & Test (push) Successful in 1m30s
release / test (push) Successful in 0s
release / Publish isommo-gameserver (push) Successful in 2m7s
release / Publish isommo-auth (push) Successful in 2m12s
release / Deploy via Semaphore (push) Failing after 4s
release / Create release (push) Successful in 7s
release / Client artifacts (push) Failing after 1m1s
801cc72059
Dockerfiles (SDK 10 -> aspnet 10, non-root app user, /app/data volume, curl
healthcheck on /health) for both services; .dockerignore excludes the client/tools/
tests. GameServer gains Game:SavePath so world.sav lives on a writable volume while
the map stays read-only in the image. ci.yaml gains workflow_call; release.yaml
mirrors aac-board — test -> publish (matrix isommo-auth/isommo-gameserver images to
the Forgejo registry) -> release (changelog) -> deploy (Semaphore webhook), plus a
client job that publishes self-contained win-x64/osx-arm64/linux-x64 zips (config.json
pre-pointed at mmo.homelab.devncode.it) + the asset editor and attaches them to the
release. Verified locally: both images build, run healthy, Auth issues a JWT and the
GameServer accepts a WS (protocol-gated) across containers.
fix(ci): zip client artifacts via python (no zip binary on the runner)
All checks were successful
ci / Lint & Test (pull_request) Successful in 1m53s
34ded01e2c
marco merged commit 59f04de775 into main 2026-07-19 20:25:42 +02:00
marco deleted branch chore/deploy-pipeline 2026-07-19 20:25:42 +02:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
marco/IsoMmo!98
No description provided.