ci(bundle): compose schema 2 for ServUO and Rust beside schema 1
All checks were successful
PR Checks / rust-gates (pull_request) Successful in 1m12s
All checks were successful
PR Checks / rust-gates (pull_request) Successful in 1m12s
Module-rust phase 18, step 2 of docs/modules/rust/PLAN.md §34.2.7 (D146, D147). The compose job now writes three streams on the bundles branch: current.json schema 1, ServUO, exactly as before v2/servuo/ schema 2, game "servuo" v2/rust/ schema 2, game "rust" (Rust-Link + Rust-Plugins) The gates move into .gitea/scripts/compose-bundles.sh, so they can be run by hand against the real release API or a mock without a runner. Each game composes independently: a Rust failure still lets a ServUO bundle publish, and the run goes red afterwards. A game whose repos have never released composes nothing and does not fail, which is where Rust is until its cutover. A ServUO matrix carries the same tag at both schemas, so the first run publishes v2/servuo/bundle-2026.09.15.json rather than a second name for the pair. Schema 1 stops being composed on 2027-01-01 and is left frozen. Tested in debian:12 against the real releases (v2/servuo published as 2026.09.15, schema 1 unchanged, Rust skipped; rerun is a no-op; past the retirement date schema 1 is frozen) and against a mock Gitea for Rust (document composed, protocol mismatch refused, missing manifest key refused, rerun a no-op, ServUO failing independently). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
This commit is contained in:
@@ -3,26 +3,45 @@
|
||||
**These files are generated. Do not edit them by hand.**
|
||||
|
||||
A *bundle* names one exact, protocol-checked combination of the two components the installer
|
||||
deploys — a `uo-link` sidecar release and a `servuo-plugins` overlay release. The installer does not
|
||||
deploys for one game: a sidecar release and a game-side payload release. For ServUO that is `link`
|
||||
and a `servuo-plugins` overlay; for Rust it is `Rust-Link` and a `Rust-Plugins` plugin. The installer does not
|
||||
hardcode versions and does not resolve "latest" at run time; it fetches one of these documents and
|
||||
installs what it names. **The bundle is the compat matrix.**
|
||||
|
||||
They are written by [`.gitea/workflows/bundle.yml`](../.gitea/workflows/bundle.yml), which composes
|
||||
They are written by [`.gitea/workflows/bundle.yml`](../.gitea/workflows/bundle.yml) (the logic is
|
||||
in [`.gitea/scripts/compose-bundles.sh`](../.gitea/scripts/compose-bundles.sh)), which composes
|
||||
one whenever a component publishes a release (dispatched by that release's own workflow) and
|
||||
nightly, so a missed dispatch self-heals. A run that finds nothing changed writes nothing.
|
||||
|
||||
See `docs/installer/PLAN.md` §7 for the design.
|
||||
See `docs/installer/PLAN.md` §7 for the design, and `docs/modules/rust/PLAN.md` §34.2.2 for
|
||||
schema 2.
|
||||
|
||||
## Where they live: the `bundles` branch
|
||||
|
||||
**The JSON documents are not in this directory.** They are published to a branch of their own,
|
||||
[`bundles`](https://gitea.whitlocktech.com/RunicGateway/installer/src/branch/bundles), at its root:
|
||||
[`bundles`](https://gitea.whitlocktech.com/RunicGateway/installer/src/branch/bundles). There is one
|
||||
stream per game and schema, each a directory holding the same two kinds of file:
|
||||
|
||||
| Directory | Stream |
|
||||
|---|---|
|
||||
| *(root)* | Schema 1, ServUO. What every installer up to v0.2.x reads. **Retires 2027-01-01** |
|
||||
| `v2/servuo/` | Schema 2, `"game": "servuo"` |
|
||||
| `v2/rust/` | Schema 2, `"game": "rust"` |
|
||||
|
||||
| File | What it is |
|
||||
|---|---|
|
||||
| `current.json` | The bundle the installer uses by default. Always a copy of the newest `bundle-*.json`. |
|
||||
| `bundle-<tag>.json` | Every bundle ever published, kept forever so `--bundle <tag>` stays reproducible. |
|
||||
|
||||
**Schema 1 retires on 2027-01-01.** Until then it is composed exactly as before, beside schema 2, so
|
||||
every installer already in the field keeps updating. After that date it stops being composed and is
|
||||
left **frozen at its last bundle, never deleted**: an old installer still resolves something, and
|
||||
every `bundle-<tag>.json` stays pinnable. A ServUO matrix carries the **same tag** at both schemas.
|
||||
|
||||
A schema-2 document names one game rather than both, because the games release on their own
|
||||
schedules: a document naming both would hand a ServUO host a new bundle every time a Rust plugin
|
||||
shipped. A game none of whose repos has released composes nothing, and that is not a failure.
|
||||
|
||||
Tags are UTC dates — `2026.08.04`. A second bundle on the same day (a sidecar release in the
|
||||
morning, an overlay release in the afternoon) becomes `2026.08.04.2`, so one tag always names
|
||||
exactly one matrix.
|
||||
@@ -45,6 +64,7 @@ Plain anonymous `GET`s against a public repo. The shard host gets no git and no
|
||||
```
|
||||
https://gitea.whitlocktech.com/RunicGateway/installer/raw/branch/bundles/current.json
|
||||
https://gitea.whitlocktech.com/RunicGateway/installer/raw/branch/bundles/bundle-2026.08.04.json
|
||||
https://gitea.whitlocktech.com/RunicGateway/installer/raw/branch/bundles/v2/rust/current.json
|
||||
```
|
||||
|
||||
Bundles are committed rather than published as Gitea releases because this repo's *own* releases are
|
||||
@@ -52,7 +72,7 @@ the installer binaries, and `/releases/latest` returns whichever release is newe
|
||||
kind — interleaving the two would make "latest" intermittently resolve to a release containing no
|
||||
installer binary.
|
||||
|
||||
## Schema
|
||||
## Schema 1 (ServUO, retiring)
|
||||
|
||||
`schema` is the version of *this document's* shape, and is unrelated to `protocol` (the uo-link wire
|
||||
protocol) or to either component's release version. All three move independently.
|
||||
@@ -104,3 +124,48 @@ rejects a protocol mismatch with `409` rather than mis-parsing, so a mismatched
|
||||
emitting into a void. CI refuses to publish one: it reads `PROTOCOL_VERSION` from the sidecar's
|
||||
source at its release tag and the declared `protocol` from the overlay tarball's `manifest.json`, and
|
||||
fails if they differ. The top-level `protocol` is that agreed value.
|
||||
|
||||
## Schema 2
|
||||
|
||||
The same document for either game: a `game` discriminant, a `sidecar`, and a `payload` whose `kind`
|
||||
says what it is. A reader switches on `game`, and refuses a `schema` it does not know.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"schema": 2,
|
||||
"game": "rust", // or "servuo"
|
||||
"bundle": "2026.09.27",
|
||||
"generated": "2026-09-27T…Z",
|
||||
"protocol": 12,
|
||||
|
||||
"sidecar": {
|
||||
"repo": "RunicGateway/Rust-Link", "tag": "v…", "version": "…", "protocol": 12,
|
||||
"assets": { // Rust: no linux-aarch64 — RustDedicated has no arm64 build
|
||||
"linux-x86_64": { "name": "…", "url": "…", "sha256": "…" },
|
||||
"windows-x86_64": { "name": "…", "url": "…", "sha256": "…" }
|
||||
},
|
||||
"launcher": { "name": "with-sidecar.sh", "url": "…", "sha256": "…" } // Rust only: the egg's startup
|
||||
},
|
||||
|
||||
"payload": {
|
||||
"kind": "plugin", // "overlay" for ServUO
|
||||
"repo": "RunicGateway/Rust-Plugins", "tag": "v…", "version": "…", "commit": "…",
|
||||
"protocol": 12,
|
||||
"compat": { // per game; for ServUO it is schema 1's `servuo` block
|
||||
"frameworks": { "oxide": { "min_version": "2.0.7585" },
|
||||
"carbon": { "min_version": "2.0.259" } },
|
||||
"requires_plugins": ["Kits", "ZoneManager"]
|
||||
},
|
||||
"asset": { "name": "runicgateway-rust-plugin-….tar.gz", "url": "…", "sha256": "…" }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
A ServUO schema-2 document is schema 1's content re-shaped: `link` becomes `sidecar` (no
|
||||
`launcher`), `overlay` becomes a `payload` of `"kind": "overlay"`, and its `servuo` block becomes
|
||||
`compat` (`min_version`, `patches_verified_against`).
|
||||
|
||||
The two gates hold for both games. For Rust, gate 1 reads `PROTOCOL_VERSION` from `Rust-Link`'s
|
||||
`sidecar/src/main.rs` at its release tag and `protocol` from the `manifest.json` inside the plugin
|
||||
tarball (`runicgateway-rust-plugin/manifest.json`). The stakes are higher there than for ServUO: the
|
||||
Rust game link has no `409`, so a mismatched plugin would mis-parse rather than be refused.
|
||||
|
||||
Reference in New Issue
Block a user