Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/cli-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ jobs:
working-directory: ./cli
run: pnpm lint

- name: Type check (strict, src + tests)
working-directory: ./cli
run: pnpm typecheck

- name: Run CLI tests
working-directory: ./cli
env:
Expand Down
3 changes: 2 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co

- `pnpm dcd <args>` — run the CLI from source via `tsx`.
- `pnpm build` — clean, compile TypeScript to `dist/`, and `chmod +x dist/index.js` so the published binary is directly executable.
- `pnpm lint` — ESLint over `src/`.
- `pnpm lint` — ESLint over `src/` and `test/`.
- `pnpm typecheck` — `tsc --noEmit` over `src/` and `test/` (strict mode; `pnpm build` only compiles `src/`).
- `pnpm test` — runs `scripts/test-runner.mjs`: builds the CLI, boots a mock API, then runs all `test/**/*.test.ts` via mocha + ts-node. The mock API lives in the **sibling `dcd/` repo** (`../dcd/mock-api`). Override its location with `MOCK_API_DIR=/path/to/mock-api`.
- Run a single test: `pnpm mocha test/integration/cloud.integration.test.ts --timeout 60000` (picks up `.mocharc.json` which wires tsx; requires the mock API already running on its expected port).

Expand Down
8 changes: 8 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,4 +74,12 @@ module.exports = tseslint.config(
'@typescript-eslint/no-require-imports': 'off',
},
},
{
// Chai's property-style assertions (`expect(x).to.be.true`) are
// expression statements by design.
files: ['test/**/*.ts'],
rules: {
'@typescript-eslint/no-unused-expressions': 'off',
},
},
);
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,10 @@
"dcd": "tsx src/index.ts",
"build": "shx rm -rf dist && tsc -b && shx chmod +x dist/index.js",
"build:binaries": "node scripts/build-binaries.mjs",
"lint": "eslint src --ext .ts",
"lint": "eslint src test --ext .ts",
"prepare": "pnpm build",
"test": "node scripts/test-runner.mjs"
"test": "node scripts/test-runner.mjs",
"typecheck": "tsc --noEmit -p tsconfig.test.json"
},
"version": "5.0.0",
"bugs": {
Expand Down
5 changes: 4 additions & 1 deletion src/commands/upgrade.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,10 @@ async function downloadToFile(url: string, dest: string): Promise<void> {
throw new Error(`HTTP ${res.status} fetching ${url}`);
}
// Node 22 exposes Readable.fromWeb for piping a WHATWG ReadableStream.
await pipeline(Readable.fromWeb(res.body), createWriteStream(dest));
await pipeline(
Readable.fromWeb(res.body as Parameters<typeof Readable.fromWeb>[0]),
createWriteStream(dest),
);
}

async function fetchExpectedChecksum(
Expand Down
7 changes: 4 additions & 3 deletions src/services/results-polling.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ import { checkInternetConnectivity } from '../utils/connectivity';
import { ux } from '../utils/progress';
import { colors, formatTestSummary, table } from '../utils/styling';

type TestResult =
paths['/results/{uploadId}']['get']['responses']['200']['content']['application/json']['results'][number];
type TestResult = NonNullable<
paths['/results/{uploadId}']['get']['responses']['200']['content']['application/json']['results']
>[number];

/**
* Custom error for run failures that includes the polling result
Expand Down Expand Up @@ -177,7 +178,7 @@ export class ResultsPollingService {
? 'PASSED'
: 'FAILED',
tests: resultsWithoutEarlierTries.map((r) => ({
durationSeconds: r.duration_seconds,
durationSeconds: r.duration_seconds ?? null,
failReason:
r.status === 'FAILED' ? r.fail_reason || 'No reason provided' : undefined,
fileName: r.test_file_name,
Expand Down
6 changes: 6 additions & 0 deletions src/services/version.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,12 @@ export class VersionService {
}
}

if (!resolvedVersion) {
throw new Error(
'Unable to resolve a Maestro version: compatibility data did not provide a default.',
);
}

// Validate Maestro version
if (!supportedVersions.includes(resolvedVersion)) {
throw new Error(
Expand Down
5 changes: 3 additions & 2 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@
"module": "commonjs",
"outDir": "dist",
"rootDir": "src",
"strict": false,
"strict": true,
"target": "es2022",
"skipLibCheck": true,
"resolveJsonModule": true
"resolveJsonModule": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*"]
}
10 changes: 10 additions & 0 deletions tsconfig.test.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"noEmit": true,
"declaration": false,
"rootDir": ".",
"types": ["node", "mocha", "chai"]
},
"include": ["src/**/*", "test/**/*"]
}
Loading