Skip to content

Rename commands per #116: geocoder, static, tilesets - #8

Merged
zmofei merged 2 commits into
mainfrom
rename-commands
Sep 14, 2026
Merged

zmofei merged 2 commits into
mainfrom
rename-commands

Conversation

@zmofei

@zmofei zmofei commented Sep 14, 2026

Copy link
Copy Markdown
Member

Regenerates openapi/ from mapbox-cli-private's internal/openapi-command-config/command-config.yaml (the #116 open-source review's decision record):

  • geocoder forward-geocode/reverse-geocode/batch-geocode -> forward/reverse/batch
  • static-images and static-tiles merge into one static command group: get-static-image -> get-image, get-static-tile -> get-tile
  • tilequery, and one operation each from rastertiles, rasterarrays and vectortiles, merge into tilesets: get-rastertile -> get-tile, get-mrt-tile -> get-mrt, get-vectortile -> get-mvt, tilequery get -> query

No hidden alias for any of these — nothing answers to the old spellings.

Also updates docs/commands.md, tests/fixtures/api_command_surface.txt, and every test that referenced an old command spelling. Full cargo test is green.

Companion to mapbox-cli-private PR #143.

Regenerated openapi/ from internal/openapi-command-config/command-config.yaml
(#116's decision record in mapbox-cli-private):

- geocoder forward-geocode/reverse-geocode/batch-geocode ->
  forward/reverse/batch
- static-images and static-tiles merge into one `static` command group:
  get-static-image -> get-image, get-static-tile -> get-tile
- tilequery, and one operation each from rastertiles, rasterarrays and
  vectortiles, merge into `tilesets`: get-rastertile -> get-tile,
  get-mrt-tile -> get-mrt, get-vectortile -> get-mvt, tilequery get -> query

Updated docs/commands.md, tests/fixtures/api_command_surface.txt and every
test referencing an old command spelling to match.

@mattpodwysocki mattpodwysocki left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving. Reviewed together with mapbox-cli-private#143, since neither half
means much alone.

I verified the thing that would otherwise break quietly

sync-openapi-specs.sh's own rule is that neither spec directory is
hand-edited
: "A change made to raw/ is one the next sync silently reverts,
and one made to oss/openapi/ is one the next --regenerate does." This PR
commits 8 changed files under openapi/, so the question that matters is
whether those edits are derived from #143's command-config.yaml or merely
consistent with it — because if it's the latter, the next --regenerate
throws all nine renames away.

So I ran it. With #143's command-config.yaml, internal/openapi-raw/ at
44fff1f, and this branch checked out as oss/:

$ sh scripts/sync-openapi-specs.sh --regenerate
sync-openapi-specs: derived 10 spec(s) into oss/openapi/ from 44fff1f

$ diff -rq <this PR's openapi/> oss/openapi
(no output)

Byte-identical, all 10 specs. The renames are genuinely encoded in the
config, so a regenerate reproduces them rather than reverting them. That is
the property the two-step design exists to guarantee, and it holds.

(Worth noting for anyone else running it: strip.py needs PyYAML, and
without it the script fails loudly — "command-config.yaml has no enabled
operations for it, but oss/src/spec.rs still wires it" — rather than
emitting empty specs. Good failure mode.)

The missing CHANGELOG here is correct, and that took checking

This PR touches no CHANGELOG.md, which for nine breaking renames looks
alarming. It isn't: check-release-ready.sh:45 says "The crate is under
oss/; CHANGELOG.md stayed at the root beside this script", and that is
the file release.yml checks against oss/Cargo.toml's version. So the
canonical entry belongs in #143, where it is — marked Breaking, with the
full was/is table and the reasoning for dropping rasterarrays, tilequery,
static-images and static-tiles as groups. Nothing to add.

It does mean this repo's CHANGELOG.md is a second file that nothing reads
at release time
, which is worth deciding about separately — I put my five
ported PRs' entries into it, which was the wrong file, and I'm fixing that on
the private side. Not this PR's problem, but this PR is what made me look.

One thing I'd like changed, and it is small

A renamed command's JSON error drops the migration hint that text mode
shows.
There are no aliases — deliberately, per the body — so a script
pinned to an old name breaks. In text mode the reader is fine:

$ mapbox geocoder forward-geocode -o text
error: unrecognized subcommand 'forward-geocode'

  tip: a similar subcommand exists: 'forward'

Under -o json — which is what scripts and agents get, and exactly the
consumers a rename breaks — that becomes:

{"code":"usage","message":"unrecognized subcommand 'forward-geocode'"}

The tip is gone. Same for static-images → static, and for every rename I
tried where clap's suggester fires.

The cause is narrow and already understood by the code around it.
report_parse_result takes clap's first paragraph:

let paragraph: Vec<&str> = rendered
    .lines()
    .skip_while(|line| line.trim().is_empty())
    .take_while(|line| !line.trim().is_empty())

and clap puts the tip in a second paragraph, past a blank line:

error: unrecognized subcommand 'forward-geocode'⏎
⏎
  tip: a similar subcommand exists: 'forward'⏎

So take_while stops one line short of the only part that tells a broken
caller what to do. The comment above that code explains why it takes the whole
paragraph rather than the first line — a missing-argument error lists the
arguments on later lines — and the same reasoning extends one paragraph
further here.

Carrying a tip: line into fix would fit what fix already means ("why it
failed, and what would make it work") and would cost a few lines. It matters
most in exactly this release: nine renames, no aliases, and the machine-
readable rendering is the one that stays silent.

I'd take that over hand-written aliases or a rename table — clap already
computed the answer, we're just discarding it.

Checked and fine

  • tests/fixtures/api_command_surface.txt moves with the renames, so the
    pinned surface is honest.
  • remedy.rs updated — its advice names commands, so it had to be.
  • New names are discoverable: mapbox geocoder --help lists
    forward/reverse/batch.
  • No stray old spellings: docs/commands.md and the four contract tests all
    move together, and cargo test is green on the branch.
  • Version: the pre-1.0 rule makes this a minor bump, and 0.1.8's entry
    already records "The next release is 0.2.0", so nothing is owed here.

report_parse_result's message only ever took clap's first paragraph, and
clap renders a 'did you mean' tip as its second — so -o text showed it
and -o json silently dropped it. That's backwards for a rename with no
alias: the caller a tip would save is a script or an agent, and that's
exactly who's on -o json.

Per @mattpodwysocki's review on this PR.
@zmofei

zmofei commented Sep 14, 2026

Copy link
Copy Markdown
Member Author

Fixed in 37afc38 — report_parse_result now carries clap's tip: paragraph into the error's fix field when there is one, so -o json shows the same suggestion -o text always did:

$ mapbox geocoder forward-geocode -o json
{"code":"usage","fix":"a similar subcommand exists: 'forward'","message":"unrecognized subcommand 'forward-geocode'"}

Added an_unrecognized_subcommand_carries_claps_suggestion_into_json in tests/output_contract.rs to pin it. Verified the no-tip case (a genuine usage error clap has no suggestion for) still gets no fix, and MissingSubcommand's own remedy is untouched. Full cargo test, fmt and clippy are clean.

mattpodwysocki added a commit that referenced this pull request Sep 14, 2026
Clap works out what was probably meant and renders it as its own paragraph:

    error: unrecognized subcommand 'forward-geocode'

      tip: a similar subcommand exists: 'forward'

`message` is built from clap's *first* paragraph — deliberately, so a
missing-argument error names the arguments on its later lines — and the tip
sits in the next one, so `take_while` stopped one line short of it. Under
`text` that cost nothing, because clap prints its whole rendering there. Under
`json` only `message` survived:

    {"code":"usage","message":"unrecognized subcommand 'forward-geocode'"}

The one part that says what to do instead was gone, in the rendering scripts
and agents read — so the consumers least able to guess a new name were the
ones told least.

That is worth fixing before 0.2.0 rather than after it. #8 renames nine
commands with no aliases, so 0.2.0 is the release where a pinned script
breaks, and a hint that arrives in 0.2.1 arrives after the moment it was for.
Verified against that branch:

    mapbox geocoder forward-geocode  -> fix: A similar subcommand exists: 'forward'
    mapbox static-images …           -> fix: A similar subcommand exists: 'static'
    mapbox tilequery get             -> fix: A similar subcommand exists: 'tilesets'

It helps misspelled flags too, which is the other thing clap suggests about:
`--usernam` now answers `A similar argument exists: '--username'`.

Goes in `fix`, which already means "why it failed, and what would make it
work", rather than inventing a key. Capitalised, because every other `fix` in
this crate reads as a sentence and clap's wording starts lowercase. Absent
when clap had no suggestion, the rule the other optional keys follow.

`text` is untouched: that path still hands the error to clap to print.

Four tests, and I checked they fail for the right reason — reverting the
change reddens the two that assert the new behaviour and leaves the two
asserting the old behaviour green.

588 tests, fmt and clippy clean. Raised while reviewing #8.
@zmofei
zmofei merged commit 3a818d2 into main Sep 14, 2026
7 of 8 checks passed
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.

2 participants