Skip to content

migrate: a default --map from the tier catalog - #160

Merged
linyiru merged 4 commits into
mainfrom
feat/migrate-replaces
Nov 5, 2026
Merged

linyiru merged 4 commits into
mainfrom
feat/migrate-replaces

Conversation

@linyiru

@linyiru linyiru commented Nov 5, 2026

Copy link
Copy Markdown
Contributor

Closes #158.

A new optional tier field, replaces. It lists the GitHub-hosted runs-on labels a tier takes over, e.g. ["ubuntu-latest", "ubuntu-24.04"]. firerunner migrate --catalog FILE maps each of these labels to the tier's name, so --map is no longer needed. When --map is given, it adds labels to that map or overrides them one by one, ignoring case.

Validation. It runs in the daemon's catalog validation, so config check applies it too. Labels are compared ignoring ASCII case, as GitHub compares them. Each entry:

  • must be a plain label;
  • is replaced by at most one tier;
  • is never self-hosted;
  • is never a name or label a tier itself answers to, since that would move an already-migrated job again.

Compatibility. The daemon ignores the field. Older daemons decode it as an unknown field, so a catalog that sets it still loads everywhere. config check lists each tier's replaces.

Docs. examples/tiers.json sets it on firerunner-ubuntu. The README and config.example.env describe it.

Tests

  • The validation rules, and that CheckCatalog applies them.
  • The map built from the catalog and its overrides.
  • Usage errors: no map at all, and a catalog that sets no replaces.
  • Issue migrate: a default --map from the tier catalog #158's acceptance check: --catalog alone gives the same report as the explicit --map it implies.
  • Mutation checks: all CAUGHT, including the wiring into CheckCatalog, every validation rule, case-insensitive overrides and the target check.

Live dry run on the e2e repository (2026-11-04). With --catalog examples/tiers.json alone, migrate maps both ubuntu-24.04 and ubuntu-latest to firerunner-ubuntu and writes nothing. Opening and updating the PR is unchanged from #157 and was tested live there.

"replaces": ["ubuntu-latest", "ubuntu-24.04"] records which runs-on
labels a tier takes over, for firerunner migrate to build its map from
(#158). The daemon ignores it, and older daemons decode it as an unknown
field, so a catalog that sets it still runs everywhere.

Validation, without regard to ASCII case as GitHub matches labels: a
plain label, replaced by one tier at most, never self-hosted, and never
a name or label a tier answers to, which would move a migrated job on
again. config check shows each tier's replaces.

Signed-off-by: Lawrence Lin <deduce@gmail.com>
With --catalog FILE and no --map, each label a tier replaces maps to
that tier's name; --map adds to that map or overrides it, label by
label, without regard to case. Every target must still be a tier's
name or label. A catalog that sets no replaces, with no --map, is a
usage error that says what to add.

Closes #158

Signed-off-by: Lawrence Lin <deduce@gmail.com>
From the review of #160:
- validateTiers checked replaces, so a mistake in data only migrate
  reads (self-hosted, a label listed twice) would stop the daemon at its
  next restart. CheckCatalog, which config check and migrate use, now
  checks it; the daemon neither uses nor checks it.
- Labels fold ASCII case only, as GitHub and internal/migrate do:
  strings.ToLower also folded the Kelvin sign into k.
- A tier that replaces labels must have a name migrate can write as a
  runs-on label (not "true", not "fr small"), so config check catches
  what migrate would refuse.
- A label listed twice in one tier gets its own message.

Signed-off-by: Lawrence Lin <deduce@gmail.com>
From the review of #160: catalogMap deleted every key matching an
explicit one, including another explicit key that differed only in
case, so `--map Ubuntu-22.04=a --map ubuntu-22.04=b` kept one at random
instead of being refused. It now drops only the catalog's own entries,
and Validate refuses the pair as without --catalog. `--map X=X` keeps
label X where it runs, the one way to leave a replaced label alone for
one repository. Usage spells out both forms.

Signed-off-by: Lawrence Lin <deduce@gmail.com>
@linyiru

linyiru commented Nov 5, 2026

Copy link
Copy Markdown
Contributor Author

Independent review (a fresh reviewer agent, given only the diff). It confirmed that no existing catalog is newly refused. Its findings are addressed in 51ccd5c and 9d24ad7:

  1. --catalog with --map Ubuntu-22.04=a --map ubuntu-22.04=b kept one of the two at random. Fixed. catalogMap deleted every key that matched an explicit one, including the other explicit key. It now drops only the catalog's own entries, and Validate refuses the pair, as it already did without --catalog.
  2. A replaces mistake could stop the daemon from starting. Fixed. The validation ran in validateTiers, so a bad entry (for example self-hosted, or a label listed twice) in data that only migrate reads would stop the daemon at its next restart. Now only CheckCatalog checks replaces; config check and migrate both use it, and the daemon ignores the field. A test pins this. The comment and the README now say so.
  3. config check accepted a tier name that migrate could not write. Fixed. A tier that replaces labels must have a plain-label name: not true, and no spaces.
  4. Case folding. Fixed. Labels now fold only ASCII case, as GitHub and internal/migrate do. strings.ToLower had also folded the Kelvin sign and the long s.

Lower-confidence notes:

  • No way to opt out of a single label. Done: --map X=X keeps label X where it runs. Verified live with a dry run on the e2e repo: --map ubuntu-latest=ubuntu-latest left private-image.yml untouched.
  • A label listed twice in one tier. It now has its own error message.
  • The usage line. Both forms are now spelled out.
  • The unlabelled replaces lines in the text output. Left as they are.

Every new rule is mutation-checked and CAUGHT.

@linyiru
linyiru merged commit 7ebf388 into main Nov 5, 2026
7 checks passed
@linyiru
linyiru deleted the feat/migrate-replaces branch November 5, 2026 00:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

migrate: a default --map from the tier catalog

1 participant