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
2 changes: 2 additions & 0 deletions cli/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## Next

- `mops build`, `mops check`, `mops generate`, and `mops check-stable` now tunnel `moc`'s exit code instead of always exiting `1`. moc exits `2` on a compiler crash (uncaught internal error) versus `1` for normal user errors (type/compile errors, stable-compat mismatch, bad args), so CI and scripts can now distinguish "file a Motoko bug" from "fix your code" via `$?`. `mops test` likewise exits `2` when a `moc` process crashes during a test run, instead of reporting it as an ordinary test failure.

## 2.16.0

- `mops bench` now compiles benchmark canisters under **enhanced orthogonal persistence** (moc's default) instead of forcing `--legacy-persistence` — measuring the persistence mode real canisters run. Pass `--legacy-persistence` to opt back into legacy persistence.
Expand Down
5 changes: 3 additions & 2 deletions cli/commands/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { exists } from "fs-extra";
import { mkdir, readFile, writeFile } from "node:fs/promises";
import { join } from "node:path";
import { lock, unlockSync } from "proper-lockfile";
import { cliError } from "../error.js";
import { cliError, cliExit } from "../error.js";
import { isCandidCompatible } from "../helpers/is-candid-compatible.js";
import {
filterCanisters,
Expand Down Expand Up @@ -136,7 +136,8 @@ export async function build(
console.error(result.stdout);
}
}
cliError(
cliExit(
result.exitCode ?? 1,
`Build failed for canister ${canisterName} (exit code: ${result.exitCode})`,
);
}
Expand Down
8 changes: 5 additions & 3 deletions cli/commands/check-stable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { existsSync, mkdirSync, mkdtempSync } from "node:fs";
import { rm } from "node:fs/promises";
import chalk from "chalk";
import { execa } from "execa";
import { cliError } from "../error.js";
import { cliError, cliExit } from "../error.js";
import {
getCheckLimitPendingIssue,
prepareMigrationArgs,
Expand Down Expand Up @@ -261,7 +261,8 @@ export async function runStableCheck(
if (result.stderr) {
console.error(result.stderr);
}
cliError(
cliExit(
result.exitCode ?? 1,
`✗ Stable compatibility check failed for canister '${canisterName}'`,
);
}
Expand Down Expand Up @@ -314,7 +315,8 @@ async function generateStableTypes(
if (result.stderr) {
console.error(result.stderr);
}
cliError(
cliExit(
result.exitCode ?? 1,
`Failed to generate stable types for ${moFile} (exit code: ${result.exitCode})`,
);
}
Expand Down
8 changes: 5 additions & 3 deletions cli/commands/check.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import path from "node:path";
import chalk from "chalk";
import { execa } from "execa";
import { cliError } from "../error.js";
import { cliError, cliExit } from "../error.js";
import {
getGlobalMocArgs,
getRootDir,
Expand Down Expand Up @@ -208,7 +208,8 @@ async function checkCanisters(
});

if (result.exitCode !== 0) {
cliError(
cliExit(
result.exitCode ?? 1,
`✗ Check failed for canister ${canisterName} (exit code: ${result.exitCode})`,
);
}
Expand Down Expand Up @@ -285,7 +286,8 @@ async function checkFiles(
});

if (result.exitCode !== 0) {
cliError(
cliExit(
result.exitCode ?? 1,
`✗ Check failed for file ${file} (exit code: ${result.exitCode})`,
);
}
Expand Down
5 changes: 3 additions & 2 deletions cli/commands/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import chalk from "chalk";
import { execa } from "execa";
import { mkdir } from "node:fs/promises";
import path from "node:path";
import { cliError } from "../error.js";
import { cliError, cliExit } from "../error.js";
import {
filterCanisters,
resolveCanisterConfigs,
Expand Down Expand Up @@ -104,7 +104,8 @@ export async function generateCandid(
console.error(result.stdout);
}
}
cliError(
cliExit(
result.exitCode ?? 1,
`Failed to generate Candid for canister ${canisterName} (exit code: ${result.exitCode})`,
);
}
Expand Down
16 changes: 12 additions & 4 deletions cli/commands/test/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,14 +159,21 @@ export async function test(filter = "", options: Partial<TestOptions> = {}) {
explicitReplica,
);
if (!passed) {
process.exit(1);
process.exit(maxMocExit >= 2 ? 2 : 1);
}
}
}

let mocPath = "";
let wasmtimePath = "";

let maxMocExit = 0;
const trackMocExit = (code: number | null) => {
if (code && code >= 2) {
maxMocExit = Math.max(maxMocExit, code);
}
};

async function runAll(
reporterName: ReporterName | undefined,
filter = "",
Expand Down Expand Up @@ -197,6 +204,7 @@ export async function testWithReporter(
signal?: AbortSignal,
explicitReplica = false,
): Promise<boolean> {
maxMocExit = 0;
let rootDir = getRootDir();
let files: string[] = [];
let libFiles = globSync("**/test?(s)/lib.mo", MOTOKO_GLOB_CONFIG);
Expand Down Expand Up @@ -328,7 +336,7 @@ export async function testWithReporter(
}
throw error;
});
pipeMMF(proc, mmf).then(resolve);
pipeMMF(proc, mmf, trackMocExit).then(resolve);
}
// build and run wasm
else if (mode === "wasi") {
Expand All @@ -346,7 +354,7 @@ export async function testWithReporter(
}
throw error;
});
pipeMMF(buildProc, mmf)
pipeMMF(buildProc, mmf, trackMocExit)
.then(async () => {
if (mmf.failed > 0) {
return;
Expand Down Expand Up @@ -413,7 +421,7 @@ export async function testWithReporter(
throw error;
});

pipeMMF(buildProc, mmf)
pipeMMF(buildProc, mmf, trackMocExit)
.then(async () => {
if (mmf.failed > 0) {
return;
Expand Down
8 changes: 6 additions & 2 deletions cli/commands/test/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,18 +68,22 @@ export function pipeStderrToMMF(stderr: Readable, mmf: MMF1, dir = "") {
});
}

export function pipeMMF(proc: ChildProcessWithoutNullStreams, mmf: MMF1) {
export function pipeMMF(
proc: ChildProcessWithoutNullStreams,
mmf: MMF1,
onClose?: (code: number | null) => void,
) {
return new Promise<void>((resolve) => {
pipeStdoutToMMF(proc.stdout, mmf);
pipeStderrToMMF(proc.stderr, mmf);

// exit
proc.on("close", (code) => {
if (code === 0) {
mmf.strategy !== "print" && mmf.pass();
} else if (code !== 1) {
mmf.fail(`unknown exit code: ${code}`);
}
onClose?.(code ?? null);
resolve();
});
});
Expand Down
5 changes: 5 additions & 0 deletions cli/error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,8 @@ export function cliError(...args: unknown[]): never {
console.error(chalk.red(...args));
process.exit(1);
}

export function cliExit(code: number, ...args: unknown[]): never {
console.error(chalk.red(...args));
process.exit(code || 1);
}
Loading