feat(cli): add checks list/get commands with typed formatters#1233
feat(cli): add checks list/get commands with typed formatters#1233MichaelHogers wants to merge 10 commits intomainfrom
Conversation
Add `checkly checks list` and `checkly checks get` commands with REST clients, formatters, and e2e tests. Formatters use typed field definitions (DetailField, ColumnDef) with generic renderDetailFields/renderTable primitives, defining fields once and rendering them for both terminal and markdown output formats.
- Extract appendErrors/appendAssets helpers in check-result-detail - Collapse duplicated formatBody try/catch branches - De-duplicate Tags column definition in checks table - Simplify formatCheckType to pass-through - Use stripAnsi/formatDate in get.ts instead of inline regex/formatting
78aeeb3 to
482d32e
Compare
…tive checks - Replace this.exit(1) with process.exitCode = 1 to avoid oclif's global handler printing the error a second time - Exclude inactive checks from --status filter results - Extract filterByStatus() and add unit tests
Add .catch() fallbacks for check-statuses and check-groups API calls so accounts with no checks don't crash with a 404.
Test checks list and get commands against an account with no checks to verify graceful handling of empty responses and 404 fallbacks.
…nfig - Add markdown output branch to showErrorGroupDetail (was rendering terminal/chalk output regardless of --output flag) - Switch empty account e2e tests to use node-config pattern with describe.skipIf for graceful skipping when creds aren't set - Add emptyApiKey/emptyAccountId to e2e config default.js - Document optional empty account test setup in e2e README
|
checking something with totals not adding up as expected, monitors causing some funniness in the counting |
Show per-type counts (e.g. BROWSER: 140 API: 77 ...) on a dim line below the status summary. Filters by activeCheckIds so the subcounts sum to the displayed total.
|
@sorccu could you give this an initial review please? 🙇 |
|
@sorccu what do you typically do with CLI releases? do we best first dogfood these type of changes? |
thebiglabasky
left a comment
There was a problem hiding this comment.
I think it's fine, though also believe there could be a case for already centralizing some elements that'll be common across most commands like pagination, command output parameter, or formatting.
The second point is regarding the contract, though I think we could go with this first and refactor later to move the definitions you have there into the contract package.
This made me wonder if by "contract" we wouldn't actually mean a TS SDK that we'd import both from the CLI and webapp and would act as the actual contract against the openapi spec from the BE API.
| }) | ||
| expect(result.status).toBe(0) | ||
| expect(result.stdout).toContain('#') | ||
| expect(result.stdout).toContain('| Field |') |
There was a problem hiding this comment.
I guess it's fine but is that the most relevant keyword to be looking for? That felt surprising at first glance
| }) | ||
| expect(result.status).toBe(0) | ||
| expect(result.stdout).toContain('| Name |') | ||
| expect(result.stdout).toContain('| --- |') |
There was a problem hiding this comment.
That line feels superfluous
| import type { CheckGroup } from '../../../rest/check-groups' | ||
| import type { CheckWithStatus } from '../../../formatters/checks' | ||
|
|
||
| function makeCheck (overrides: Partial<Check> = {}): Check { |
There was a problem hiding this comment.
Looks like fixtures we could reuse and worth having centralized for future use on other commands? Or do we want to limit the scope of these to make the tests more self-contained/less dependent?
| expect(result.has('c2')).toBe(false) | ||
| }) | ||
|
|
||
| it('includes heartbeat checks', () => { |
There was a problem hiding this comment.
It's kinda strange to test 'includes activated non-heartbeat checks' and another 'includes hearbeat checks': I don't really see the expected difference between both tests so might as well drop one?
Note: I haven't checked what buildActiveCheckIds is currently doing so there might be a good reason for that, though it's unclear at surface level.
| 'results-cursor': Flags.string({ | ||
| description: 'Cursor for results pagination (from previous output).', | ||
| }), | ||
| 'output': Flags.string({ |
There was a problem hiding this comment.
Could be good to generalize to all commands so we don't need to repeat this and risk drifts going forward. I'd take it that every command will need to be able to customize the output, so worth centralizing imo
There was a problem hiding this comment.
That file mixes a lot of concerns in one, I'd likely split between helpers, and per-check-type formatting
| return [ | ||
| { | ||
| header: 'Error', | ||
| width: 60, |
There was a problem hiding this comment.
Feels a bit arbitrary but I guess why not? 😅
There was a problem hiding this comment.
Same, skimmed through since secondary
|
|
||
| // --- API check result --- | ||
|
|
||
| export interface ApiCheckAssertion { |
There was a problem hiding this comment.
So these should ideally come from the contract package, correct?
| return this.api.get<Check[]>('/v1/checks', { params }) | ||
| } | ||
|
|
||
| async getAllPaginated (params: ListChecksParams = {}): Promise<PaginatedChecks> { |
There was a problem hiding this comment.
Looks like something we could centralize for all paginated endpoints
|
thanks @thebiglabasky going through the comments now (on the formatting side i didn't feel super strongly about the code, because it is bound to change and nothing depends directly on that for a while) |
@thebiglabasky the way i've done this before is:
*: we need to also build some tooling to check that older contracts still work against latest backend, this could be by validating the contracts directly or simply e2e suits between the range of versions of clients and latest backend, probably former is easiest |
I was thinking this but then wondered why we'd actually bother to separate all these things since it's all TypeScript in the end, so having all the openapi, types and even handy wrapping call methods in a single package suddenly looked appealing to me: so you don't even bother with the API endpoint and structure, it's all typed through the SDK. The openapi part becomes the elements used by the backend and for docs. |
|
Note for self: came back from the SDK idea, and now sold on sticking to only zod so we can generate the openapi spec, and get runtime validation all in a single place |
Summary
Add
checkly checks listandcheckly checks getCLI commands for viewing checks, results, and error groups from the terminal.DetailField<T>,ColumnDef<T>) — fields defined once, rendered for both terminal and markdownAlso adds a new e2e testing account with no checks, representing a new user, to cover any potential edge cases we may miss in our own e2e prod account.
Test plan
vitest --run src/formatters/__tests__/ src/commands/checks/__tests__/— 115 tests passchecks-list.spec.ts,checks-get.spec.ts(require prod env)