build(COMPASS-28): move to @oclif/core 4 - #2730
Conversation
Automated review —
|
Five deprecated packages out — `@oclif/command`, `@oclif/config`,
`@oclif/errors`, `@oclif/help` and `@oclif/dev-cli` — for `@oclif/core` 4,
`@oclif/plugin-help` 6 and the maintained `oclif` CLI. `prepack` calls
`oclif manifest` and `oclif readme` in place of the `oclif-dev` forms; both
were verified by hand, since nothing in CI runs the pack lifecycle.
`@oclif/core` is held at 4.13.3 rather than 4.14.0, which does not clear
`minimumReleaseAge`.
Across the nine commands: `flags` becomes `Flags`, `static args` becomes an
object of `Args.string(...)` rather than an array of descriptors, and
`this.parse` is awaited. The `flags.Input<flags.Output>` annotations are
dropped — v4 has no equivalent and infers more than they did. `bin/run`
moves to `@oclif/core`'s own `run`, `flush` and `handle`.
Two v4 changes reach `spot lint`, and neither shows up in a type check.
`Command.warn` reads `this.jsonEnabled()`, where v1's touched no state. The
logger handed to `findLintViolations` passed the method by reference, so
calling it off a plain object threw before it could warn — and
`no-trailing-forward-slash` is `warn` in the default config, so a plain
`spot lint` on a contract with one hit it. Wrapped in an arrow now.
`lint.spec.ts` covers the warning path, which had no spec at all; the parity
script lints a clean contract and escalates the rule to `error`, so both of
its cases stepped around the branch.
`flags.enum` is gone. `Flags.option` is its successor but returns a factory
rather than a flag, and assigning that where a flag belongs throws at
startup. The v1 shape maps to `Flags.string({ options })`, and
`finalFlags` is typed `Interfaces.FlagInput` rather than
`Record<string, any>`: that rejects a factory, so the same mistake is a
compile error rather than a crash.
`@oclif/core` reads `$SHELL` and falls back to `os.userInfo().shell`, which
throws for a uid absent from /etc/passwd — the uid `docker run --user`
supplies, and equally a Kubernetes `runAsUser` or `npx` inside another
image. `bin/run` defaults it, which covers every entrypoint; the Dockerfile
sets it too, and an image built without that line now works regardless.
`checksum` ships in the image and the parity script never ran it. It does
now.
The image drops `mock`, `docs` and `init` by deleting their compiled files
and shipping no manifest. That still works under v4's loader, and v4 still
says "command ... not found", which is what the parity script greps for.
Neither was safe to assume: the check fails open if the wording changes.
`this.log` reaches the terminal through `console.log` in v4 rather than
`process.stdout.write`, so two specs captured nothing — jest substitutes its
own `console`, which never reaches the stream they were spying on. They spy
on `console.log` now.
The README's command reference is regenerated rather than left for the next
publish to rewrite: v4's help prints FLAGS instead of OPTIONS and adds a
DESCRIPTION section. Every changed line falls inside the `<!-- commands -->`
and `<!-- toc -->` blocks.
Generated output does not change: the 318-artifact comparison is identical,
and parity compares all seven generator and language combinations byte for
byte, along with the exit codes for validate, checksum, lint, ts-lint and
the oclif error path, which is still 2.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
932ec16 to
7955588
Compare
|
Addressed in Blocker — One thing that spec deliberately does not cover: an error-severity violation. The command answers that with
Left the remaining five uncovered commands to a ticket, as discussed: a table-driven spec across nine commands is a larger change than this migration should carry. |
Automated review, round 2 —
|
Ticket
COMPASS-28 — Bump
spot's NodeJS minimum from 18 to 22What
Five deprecated packages out, three in:
@oclif/command^1.8.0@oclif/core^4.13.3@oclif/config^1.17.0@oclif/errors^1.3.6@oclif/help^1.0.15@oclif/plugin-help^3.2.3@oclif/plugin-help^6.2.58@oclif/dev-cli^1.26.0 (dev)oclif^4.23.30 (dev)@oclif/coreis held at 4.13.3, not 4.14.0 — that was published today and does not clearminimumReleaseAge. Supersedes Dependabot #2699.Across the nine commands:
flags→Flags,static argsfrom an array of descriptors to an object ofArgs.string(...),this.parseawaited, and theflags.Input<flags.Output>annotations dropped (v4 has no equivalent and infers the same).bin/runmoves to core's ownrun/flush/handle.prepackcallsoclif manifestandoclif readme.flags.enumis gone, and its successor is a trapFlags.optionlooks like the replacement but returns a factory, not a flag. Assigning it where a flag belongs throws at startup:That is how
spot lintfailed first — the build was clean and the suite was green. The v1 shape maps toFlags.string({ options }), which restricts values the same way. Checked all three cases:lint <contract>lint --no-trailing-forward-slash=errorlint --no-trailing-forward-slash=bogusExpected ... to be one of: error, warn, offTwo things only the image showed
1. Every command failed before doing anything.
@oclif/corereads$SHELLand falls back toos.userInfo().shell(lib/util/os.js:37). That throws for a uid with no/etc/passwdentry — exactly the uid--user "$(id -u):$(id -g)"supplies, which is how the Dockerfile header documents running the image. It worked without--userand failed with it, which is the wrong way round for the supported usage.ENV SHELL=/bin/shnow sits besideENV HOME=/tmp, which exists for the same class of reason and carries a comment saying so.2. The two parity assertions I expected to fail actually hold — but only because I checked.
Both fail open, so a changed message would have passed silently:
mock,docsandinitby deleting their compiled files and shipping no manifest. That still works under v4's loader.Error: command <x> not found, which is whatcheck-image-paritygreps for withgrep -qi "not found".this.logno longer goes throughprocess.stdoutIn v4 it goes through
console.log, and jest substitutes its ownconsolethat never reaches the real stream — so two specs captured an empty string while the command was printing correctly.ts-lint.spec.tsandgenerate.spec.tsspy onconsole.lognow. Notably these passed in isolation and failed in the full run, which is a good argument for not trusting a single-file run.The README is regenerated, not left for the next publish
v4's help prints
FLAGSinstead ofOPTIONS, adds aDESCRIPTIONsection, and shows flags in the usage line.prepackrunsoclif readme, so leaving this out would mean the committed reference silently disagreeing with--helpuntil a release rewrote it.All 284 changed lines fall inside the
<!-- commands -->and<!-- toc -->blocks — verified programmatically that zero changes land outside them, so no hand-written content moved.Generated output does not change
The 318-artifact run matters here beyond generation: it drives
generate318 times through the rewrittenArgs/Flagsparsing.How this was verified
pnpm buildpnpm testpnpm lint:checkpnpm build-docsdocker build+check-image-parityoclif manifestvalidateargs["spot_contract"], flags["help"]oclif readme--useron a clean workspaceContract is valid,Generated .../api.yml--prodinstall +--help/validate/lint/ts-lintThe
prepacksteps are hand-verified because nothing in CI runs the pack lifecycle — the publish job would have been the first thing to execute them.