ic-mops 2.15.1 → 2.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/bundle/cli.tgz +0 -0
- package/check-requirements.ts +53 -31
- package/cli.ts +37 -10
- package/commands/bench.ts +23 -5
- package/commands/check-stable.ts +20 -3
- package/commands/check.ts +6 -1
- package/commands/toolchain/index.ts +1 -3
- package/dist/check-requirements.js +31 -24
- package/dist/cli.js +19 -9
- package/dist/commands/bench.d.ts +2 -0
- package/dist/commands/bench.js +16 -3
- package/dist/commands/check-stable.d.ts +2 -1
- package/dist/commands/check-stable.js +8 -2
- package/dist/commands/check.js +6 -1
- package/dist/commands/toolchain/index.js +1 -3
- package/dist/helpers/get-lintoko-version.d.ts +3 -0
- package/dist/helpers/get-lintoko-version.js +30 -0
- package/dist/helpers/migrations.d.ts +16 -0
- package/dist/helpers/migrations.js +71 -1
- package/dist/helpers/parse-most.d.ts +5 -0
- package/dist/helpers/parse-most.js +28 -0
- package/dist/mops.js +2 -2
- package/dist/package.json +1 -1
- package/dist/tests/check-stable.test.js +15 -0
- package/dist/tests/check.test.js +5 -0
- package/dist/tests/lint.test.js +1 -1
- package/dist/tests/migrations-most.test.d.ts +1 -0
- package/dist/tests/migrations-most.test.js +47 -0
- package/dist/tests/requirements.test.d.ts +1 -0
- package/dist/tests/requirements.test.js +46 -0
- package/dist/types.d.ts +1 -0
- package/helpers/get-lintoko-version.ts +32 -0
- package/helpers/migrations.ts +117 -0
- package/helpers/parse-most.ts +32 -0
- package/mops.ts +2 -2
- package/package.json +1 -1
- package/tests/__snapshots__/check-stable.test.ts.snap +11 -0
- package/tests/__snapshots__/lint.test.ts.snap +29 -1
- package/tests/check-stable/check-limit-warning/deployed.most +8 -0
- package/tests/check-stable/check-limit-warning/migrations/20250101_000000_Init.mo +5 -0
- package/tests/check-stable/check-limit-warning/migrations/20250201_000000_AddField.mo +9 -0
- package/tests/check-stable/check-limit-warning/migrations/20250301_000000_AddD.mo +10 -0
- package/tests/check-stable/check-limit-warning/mops.toml +15 -0
- package/tests/check-stable/check-limit-warning/src/main.mo +12 -0
- package/tests/check-stable.test.ts +24 -0
- package/tests/check.test.ts +9 -0
- package/tests/lint-extra-example-rules/lint/migration-self-contained/migration-self-contained.toml +7 -0
- package/tests/lint-extra-example-rules/migrations/20250101_000000_Init.mo +11 -0
- package/tests/lint-extra-example-rules/mops.toml +1 -0
- package/tests/lint.test.ts +1 -1
- package/tests/migrations-most.test.ts +64 -0
- package/tests/requirements-lintoko/mops.toml +5 -0
- package/tests/requirements.test.ts +66 -0
- package/types.ts +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
## Next
|
|
4
4
|
|
|
5
|
+
## 2.16.0
|
|
6
|
+
|
|
7
|
+
- `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.
|
|
8
|
+
- `mops bench --query` measures each cell in a **query** call instead of an update call. Queries run no GC on the IC, so the instruction counts exclude GC work an update would incur — for benchmarking `query`/read-only workloads realistically. Only for synchronous benchmark runners (no inter-canister `await`).
|
|
9
|
+
- `[requirements].lintoko` declares a minimum lintoko version for package consumers. `mops install` (and `mops add`, `mops toolchain use`) warn when the project's lintoko is below a dependency's requirement, same as `moc` (#597).
|
|
10
|
+
|
|
11
|
+
## 2.15.2
|
|
12
|
+
|
|
13
|
+
- `mops check-stable` (and the stable check inside `mops check`) reports when `[canisters.<name>.migrations].check-limit` is set but more migrations are pending than the limit allows. If the compatibility check failed, the check-limit diagnostic replaces the misleading `moc` error; if it passed anyway, a warning is shown. Compares the deployed `.most` baseline against the local chain; use `--no-check-limit` to suppress.
|
|
14
|
+
|
|
5
15
|
## 2.15.1
|
|
6
16
|
|
|
7
17
|
- `mops check --fix` no longer aborts when a fixable file is read-only (e.g. a frozen migration chain file deliberately `chmod`'d to remove write access). The autofixer now skips such files with a warning and continues fixing the rest, instead of crashing the whole run on `EACCES`/`EPERM`.
|
package/bundle/cli.tgz
CHANGED
|
Binary file
|
package/check-requirements.ts
CHANGED
|
@@ -5,47 +5,69 @@ import chalk from "chalk";
|
|
|
5
5
|
import { getDependencyType, getRootDir, readConfig } from "./mops.js";
|
|
6
6
|
import { resolvePackages } from "./resolve-packages.js";
|
|
7
7
|
import { getMocSemVer } from "./helpers/get-moc-version.js";
|
|
8
|
+
import { getLintokoSemVer } from "./helpers/get-lintoko-version.js";
|
|
8
9
|
import { getPackageId } from "./helpers/get-package-id.js";
|
|
10
|
+
import type { Requirements } from "./types.js";
|
|
11
|
+
|
|
12
|
+
type ToolRequirement = keyof Requirements;
|
|
13
|
+
|
|
14
|
+
const TOOL_REQUIREMENTS: {
|
|
15
|
+
tool: ToolRequirement;
|
|
16
|
+
getInstalled: () => SemVer | null;
|
|
17
|
+
}[] = [
|
|
18
|
+
{ tool: "moc", getInstalled: getMocSemVer },
|
|
19
|
+
{ tool: "lintoko", getInstalled: getLintokoSemVer },
|
|
20
|
+
];
|
|
9
21
|
|
|
10
22
|
export async function checkRequirements({ verbose = false } = {}) {
|
|
11
|
-
let installedMoc = getMocSemVer();
|
|
12
|
-
if (!installedMoc) {
|
|
13
|
-
return;
|
|
14
|
-
}
|
|
15
|
-
let highestRequiredMoc = new SemVer("0.0.0");
|
|
16
|
-
let highestRequiredMocPkgId = "";
|
|
17
23
|
let rootDir = getRootDir();
|
|
18
|
-
|
|
19
24
|
let resolvedPackages = await resolvePackages();
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
25
|
+
|
|
26
|
+
for (let { tool, getInstalled } of TOOL_REQUIREMENTS) {
|
|
27
|
+
let installed = getInstalled();
|
|
28
|
+
if (!installed) {
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
let highestRequired = new SemVer("0.0.0");
|
|
33
|
+
let highestRequiredPkgId = "";
|
|
34
|
+
|
|
35
|
+
for (let [name, version] of Object.entries(resolvedPackages)) {
|
|
36
|
+
if (getDependencyType(version) === "mops") {
|
|
37
|
+
let pkgId = getPackageId(name, version);
|
|
38
|
+
let depConfig = readConfig(
|
|
39
|
+
path.join(rootDir, ".mops", pkgId, "mops.toml"),
|
|
40
|
+
);
|
|
41
|
+
let required = depConfig.requirements?.[tool];
|
|
42
|
+
|
|
43
|
+
if (required) {
|
|
44
|
+
let requiredVersion = new SemVer(required);
|
|
45
|
+
if (highestRequired.compare(requiredVersion) < 0) {
|
|
46
|
+
highestRequired = requiredVersion;
|
|
47
|
+
highestRequiredPkgId = pkgId;
|
|
48
|
+
}
|
|
49
|
+
verbose && _check(tool, pkgId, installed, requiredVersion);
|
|
33
50
|
}
|
|
34
|
-
verbose && _check(pkgId, installedMoc, requiredMoc);
|
|
35
51
|
}
|
|
36
52
|
}
|
|
37
|
-
}
|
|
38
53
|
|
|
39
|
-
|
|
54
|
+
verbose || _check(tool, highestRequiredPkgId, installed, highestRequired);
|
|
55
|
+
}
|
|
40
56
|
}
|
|
41
57
|
|
|
42
|
-
function _check(
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
58
|
+
function _check(
|
|
59
|
+
tool: ToolRequirement,
|
|
60
|
+
pkgId: string,
|
|
61
|
+
installed: SemVer,
|
|
62
|
+
required: SemVer,
|
|
63
|
+
) {
|
|
64
|
+
if (!pkgId || installed.compare(required) >= 0) {
|
|
65
|
+
return;
|
|
50
66
|
}
|
|
67
|
+
|
|
68
|
+
console.log(
|
|
69
|
+
chalk.yellow(`${tool} version does not meet the requirements of ${pkgId}`),
|
|
70
|
+
);
|
|
71
|
+
console.log(chalk.yellow(` Required: >= ${required.format()}`));
|
|
72
|
+
console.log(chalk.yellow(` Installed: ${installed.format()}`));
|
|
51
73
|
}
|
package/cli.ts
CHANGED
|
@@ -102,14 +102,26 @@ function parseExtraArgs(variadicArgs?: string[]): {
|
|
|
102
102
|
// Shared `--help` section describing the enhanced migration `check-limit`
|
|
103
103
|
// trimming and its override flag, so the limit behaviour is discoverable
|
|
104
104
|
// from `--help`. `withFix` appends the `--fix` hint for commands that support it.
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
105
|
+
// `withPendingWarning` adds the stable-check pending-migration warning (check / check-stable only).
|
|
106
|
+
function enhancedMigrationHelp(
|
|
107
|
+
options: {
|
|
108
|
+
withFix?: boolean;
|
|
109
|
+
withPendingWarning?: boolean;
|
|
110
|
+
} = {},
|
|
111
|
+
): string {
|
|
112
|
+
const example = options.withFix ? " (e.g. to --fix older migrations)" : "";
|
|
113
|
+
let text =
|
|
108
114
|
"\nEnhanced migration ([canisters.<name>.migrations]):\n" +
|
|
109
115
|
" The canister is checked against its migration chain. [migrations].check-limit\n" +
|
|
110
116
|
" trims it to the last N migrations (older ones are skipped). Pass --no-check-limit\n" +
|
|
111
|
-
` to use the full chain${example}
|
|
112
|
-
)
|
|
117
|
+
` to use the full chain${example}.`;
|
|
118
|
+
if (options.withPendingWarning) {
|
|
119
|
+
text +=
|
|
120
|
+
"\n When check-limit is set, the stable check reports if more migrations are pending\n" +
|
|
121
|
+
" (relative to the deployed .most baseline) than the limit allows — as an error if\n" +
|
|
122
|
+
" compat failed, otherwise a warning.";
|
|
123
|
+
}
|
|
124
|
+
return text;
|
|
113
125
|
}
|
|
114
126
|
|
|
115
127
|
program.name("mops");
|
|
@@ -372,14 +384,17 @@ program
|
|
|
372
384
|
.addOption(
|
|
373
385
|
new Option(
|
|
374
386
|
"--no-check-limit",
|
|
375
|
-
"
|
|
387
|
+
"Use the full migration chain, ignoring [migrations].check-limit; also suppresses the pending-migration warning",
|
|
376
388
|
),
|
|
377
389
|
)
|
|
378
390
|
.addHelpText(
|
|
379
391
|
"after",
|
|
380
392
|
"\nArguments after -- are forwarded directly to moc, e.g.:\n $ mops check -- -Werror",
|
|
381
393
|
)
|
|
382
|
-
.addHelpText(
|
|
394
|
+
.addHelpText(
|
|
395
|
+
"after",
|
|
396
|
+
enhancedMigrationHelp({ withFix: true, withPendingWarning: true }),
|
|
397
|
+
)
|
|
383
398
|
.allowUnknownOption(true)
|
|
384
399
|
.action(async (args, options) => {
|
|
385
400
|
checkConfigFile(true);
|
|
@@ -419,14 +434,14 @@ program
|
|
|
419
434
|
.addOption(
|
|
420
435
|
new Option(
|
|
421
436
|
"--no-check-limit",
|
|
422
|
-
"
|
|
437
|
+
"Use the full migration chain, ignoring [migrations].check-limit; also suppresses the pending-migration warning",
|
|
423
438
|
),
|
|
424
439
|
)
|
|
425
440
|
.addHelpText(
|
|
426
441
|
"after",
|
|
427
442
|
"\nArguments after -- are forwarded directly to moc, e.g.:\n $ mops check-stable -- -Werror",
|
|
428
443
|
)
|
|
429
|
-
.addHelpText("after", enhancedMigrationHelp(
|
|
444
|
+
.addHelpText("after", enhancedMigrationHelp({ withPendingWarning: true }))
|
|
430
445
|
.allowUnknownOption(true)
|
|
431
446
|
.action(async (args, options) => {
|
|
432
447
|
checkConfigFile(true);
|
|
@@ -543,6 +558,18 @@ program
|
|
|
543
558
|
),
|
|
544
559
|
)
|
|
545
560
|
// .addOption(new Option('--force-gc', 'Force GC'))
|
|
561
|
+
.addOption(
|
|
562
|
+
new Option(
|
|
563
|
+
"--query",
|
|
564
|
+
"Measure each cell in a query call (how `query` methods run on the IC: no GC). Only for benchmarks whose runner is synchronous (no inter-canister calls)",
|
|
565
|
+
),
|
|
566
|
+
)
|
|
567
|
+
.addOption(
|
|
568
|
+
new Option(
|
|
569
|
+
"--legacy-persistence",
|
|
570
|
+
"Compile benchmark canisters under legacy persistence instead of enhanced orthogonal persistence (the default)",
|
|
571
|
+
),
|
|
572
|
+
)
|
|
546
573
|
.addOption(
|
|
547
574
|
new Option(
|
|
548
575
|
"--verbose",
|
|
@@ -979,7 +1006,7 @@ program
|
|
|
979
1006
|
"after",
|
|
980
1007
|
"\nArguments after -- are forwarded directly to lintoko, e.g.:\n $ mops lint -- --severity warning",
|
|
981
1008
|
)
|
|
982
|
-
.addHelpText("after", enhancedMigrationHelp(true))
|
|
1009
|
+
.addHelpText("after", enhancedMigrationHelp({ withFix: true }))
|
|
983
1010
|
.allowUnknownOption(true)
|
|
984
1011
|
.action(async (filter, options) => {
|
|
985
1012
|
checkConfigFile(true);
|
package/commands/bench.ts
CHANGED
|
@@ -40,6 +40,8 @@ type BenchOptions = {
|
|
|
40
40
|
compilerVersion: string;
|
|
41
41
|
gc: "copying" | "compacting" | "generational" | "incremental";
|
|
42
42
|
forceGc: boolean;
|
|
43
|
+
query: boolean;
|
|
44
|
+
legacyPersistence: boolean;
|
|
43
45
|
save: boolean;
|
|
44
46
|
compare: boolean;
|
|
45
47
|
verbose: boolean;
|
|
@@ -61,6 +63,8 @@ export async function bench(
|
|
|
61
63
|
compilerVersion: getMocVersion(true),
|
|
62
64
|
gc: "copying",
|
|
63
65
|
forceGc: true,
|
|
66
|
+
query: false,
|
|
67
|
+
legacyPersistence: false,
|
|
64
68
|
save: false,
|
|
65
69
|
compare: false,
|
|
66
70
|
verbose: false,
|
|
@@ -120,6 +124,14 @@ export async function bench(
|
|
|
120
124
|
` gc: ${options.gc}${options.forceGc ? " (forced)" : ""}`,
|
|
121
125
|
),
|
|
122
126
|
);
|
|
127
|
+
console.log(
|
|
128
|
+
chalk.gray(` context: ${options.query ? "query" : "update"}`),
|
|
129
|
+
);
|
|
130
|
+
console.log(
|
|
131
|
+
chalk.gray(
|
|
132
|
+
` persistence: ${options.legacyPersistence ? "legacy" : "enhanced"}`,
|
|
133
|
+
),
|
|
134
|
+
);
|
|
123
135
|
console.log(chalk.gray(` profile: ${options.profile}`));
|
|
124
136
|
console.log(chalk.gray(` optimize: ${optimize}`));
|
|
125
137
|
}
|
|
@@ -270,7 +282,12 @@ function computeDiffAll(
|
|
|
270
282
|
function getMocArgs(options: BenchOptions): string {
|
|
271
283
|
let args = "";
|
|
272
284
|
|
|
285
|
+
// Benchmarks compile under enhanced orthogonal persistence (moc's default
|
|
286
|
+
// since 0.15) — the mode real canisters run. Pass `--legacy-persistence`
|
|
287
|
+
// only when the user opts in, and only where moc supports the flag (>= 0.15;
|
|
288
|
+
// legacy is already the default below it).
|
|
273
289
|
if (
|
|
290
|
+
options.legacyPersistence &&
|
|
274
291
|
options.compilerVersion &&
|
|
275
292
|
new SemVer(options.compilerVersion).compare("0.15.0") >= 0
|
|
276
293
|
) {
|
|
@@ -533,13 +550,14 @@ async function runBenchFile(
|
|
|
533
550
|
log();
|
|
534
551
|
}
|
|
535
552
|
|
|
536
|
-
// run all cells
|
|
553
|
+
// run all cells. `--query` measures in query context (how `query` methods
|
|
554
|
+
// actually run on the IC: no GC), at the cost of not supporting benches whose
|
|
555
|
+
// runner performs async calls. Otherwise use the update path.
|
|
537
556
|
for (let [rowIndex, row] of schema.rows.entries()) {
|
|
538
557
|
for (let [colIndex, col] of schema.cols.entries()) {
|
|
539
|
-
let res =
|
|
540
|
-
BigInt(rowIndex),
|
|
541
|
-
BigInt(colIndex)
|
|
542
|
-
);
|
|
558
|
+
let res = options.query
|
|
559
|
+
? await actor.runCellQuery(BigInt(rowIndex), BigInt(colIndex))
|
|
560
|
+
: await actor.runCellUpdateAwait(BigInt(rowIndex), BigInt(colIndex));
|
|
543
561
|
results.set(`${row}:${col}`, res);
|
|
544
562
|
|
|
545
563
|
// @ts-ignore
|
package/commands/check-stable.ts
CHANGED
|
@@ -4,9 +4,13 @@ import { rm } from "node:fs/promises";
|
|
|
4
4
|
import chalk from "chalk";
|
|
5
5
|
import { execa } from "execa";
|
|
6
6
|
import { cliError } from "../error.js";
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
getCheckLimitPendingIssue,
|
|
9
|
+
prepareMigrationArgs,
|
|
10
|
+
reportCheckLimitPendingIssue,
|
|
11
|
+
} from "../helpers/migrations.js";
|
|
8
12
|
import { getGlobalMocArgs, readConfig, resolveConfigPath } from "../mops.js";
|
|
9
|
-
import { CanisterConfig } from "../types.js";
|
|
13
|
+
import { CanisterConfig, MigrationsConfig } from "../types.js";
|
|
10
14
|
import {
|
|
11
15
|
filterCanisters,
|
|
12
16
|
looksLikeFile,
|
|
@@ -103,6 +107,7 @@ export async function checkStable(
|
|
|
103
107
|
mocPath,
|
|
104
108
|
globalMocArgs,
|
|
105
109
|
canisterArgs: [...migration.migrationArgs, ...(canister.args ?? [])],
|
|
110
|
+
migrations: canister.migrations,
|
|
106
111
|
options,
|
|
107
112
|
});
|
|
108
113
|
} finally {
|
|
@@ -146,6 +151,7 @@ export async function checkStable(
|
|
|
146
151
|
globalMocArgs,
|
|
147
152
|
canisterArgs: [...migration.migrationArgs, ...(canister.args ?? [])],
|
|
148
153
|
sources,
|
|
154
|
+
migrations: canister.migrations,
|
|
149
155
|
options,
|
|
150
156
|
});
|
|
151
157
|
} finally {
|
|
@@ -173,6 +179,7 @@ export interface RunStableCheckParams {
|
|
|
173
179
|
globalMocArgs: string[];
|
|
174
180
|
canisterArgs: string[];
|
|
175
181
|
sources?: string[];
|
|
182
|
+
migrations?: MigrationsConfig;
|
|
176
183
|
options?: Partial<CheckStableOptions>;
|
|
177
184
|
}
|
|
178
185
|
|
|
@@ -240,7 +247,17 @@ export async function runStableCheck(
|
|
|
240
247
|
reject: false,
|
|
241
248
|
});
|
|
242
249
|
|
|
243
|
-
|
|
250
|
+
const issue = getCheckLimitPendingIssue(
|
|
251
|
+
params.migrations,
|
|
252
|
+
canisterName,
|
|
253
|
+
oldMostPath,
|
|
254
|
+
options.checkLimit === false,
|
|
255
|
+
isOldMostFile,
|
|
256
|
+
);
|
|
257
|
+
|
|
258
|
+
if (issue) {
|
|
259
|
+
reportCheckLimitPendingIssue(issue, result.exitCode !== 0);
|
|
260
|
+
} else if (result.exitCode !== 0) {
|
|
244
261
|
if (result.stderr) {
|
|
245
262
|
console.error(result.stderr);
|
|
246
263
|
}
|
package/commands/check.ts
CHANGED
|
@@ -230,7 +230,12 @@ async function checkCanisters(
|
|
|
230
230
|
globalMocArgs,
|
|
231
231
|
canisterArgs: [...migration.migrationArgs, ...(canister.args ?? [])],
|
|
232
232
|
sources,
|
|
233
|
-
|
|
233
|
+
migrations: canister.migrations,
|
|
234
|
+
options: {
|
|
235
|
+
verbose: options.verbose,
|
|
236
|
+
extraArgs: options.extraArgs,
|
|
237
|
+
checkLimit: options.checkLimit,
|
|
238
|
+
},
|
|
234
239
|
});
|
|
235
240
|
}
|
|
236
241
|
} finally {
|
|
@@ -337,9 +337,7 @@ async function update(tool?: Tool) {
|
|
|
337
337
|
config.toolchain[tool] = version;
|
|
338
338
|
writeConfig(config);
|
|
339
339
|
|
|
340
|
-
|
|
341
|
-
await checkRequirements();
|
|
342
|
-
}
|
|
340
|
+
await checkRequirements();
|
|
343
341
|
|
|
344
342
|
if (oldVersion === version) {
|
|
345
343
|
console.log(`Latest ${tool} ${version} is already installed`);
|
|
@@ -4,38 +4,45 @@ import chalk from "chalk";
|
|
|
4
4
|
import { getDependencyType, getRootDir, readConfig } from "./mops.js";
|
|
5
5
|
import { resolvePackages } from "./resolve-packages.js";
|
|
6
6
|
import { getMocSemVer } from "./helpers/get-moc-version.js";
|
|
7
|
+
import { getLintokoSemVer } from "./helpers/get-lintoko-version.js";
|
|
7
8
|
import { getPackageId } from "./helpers/get-package-id.js";
|
|
9
|
+
const TOOL_REQUIREMENTS = [
|
|
10
|
+
{ tool: "moc", getInstalled: getMocSemVer },
|
|
11
|
+
{ tool: "lintoko", getInstalled: getLintokoSemVer },
|
|
12
|
+
];
|
|
8
13
|
export async function checkRequirements({ verbose = false } = {}) {
|
|
9
|
-
let installedMoc = getMocSemVer();
|
|
10
|
-
if (!installedMoc) {
|
|
11
|
-
return;
|
|
12
|
-
}
|
|
13
|
-
let highestRequiredMoc = new SemVer("0.0.0");
|
|
14
|
-
let highestRequiredMocPkgId = "";
|
|
15
14
|
let rootDir = getRootDir();
|
|
16
15
|
let resolvedPackages = await resolvePackages();
|
|
17
|
-
for (let
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
16
|
+
for (let { tool, getInstalled } of TOOL_REQUIREMENTS) {
|
|
17
|
+
let installed = getInstalled();
|
|
18
|
+
if (!installed) {
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
let highestRequired = new SemVer("0.0.0");
|
|
22
|
+
let highestRequiredPkgId = "";
|
|
23
|
+
for (let [name, version] of Object.entries(resolvedPackages)) {
|
|
24
|
+
if (getDependencyType(version) === "mops") {
|
|
25
|
+
let pkgId = getPackageId(name, version);
|
|
26
|
+
let depConfig = readConfig(path.join(rootDir, ".mops", pkgId, "mops.toml"));
|
|
27
|
+
let required = depConfig.requirements?.[tool];
|
|
28
|
+
if (required) {
|
|
29
|
+
let requiredVersion = new SemVer(required);
|
|
30
|
+
if (highestRequired.compare(requiredVersion) < 0) {
|
|
31
|
+
highestRequired = requiredVersion;
|
|
32
|
+
highestRequiredPkgId = pkgId;
|
|
33
|
+
}
|
|
34
|
+
verbose && _check(tool, pkgId, installed, requiredVersion);
|
|
27
35
|
}
|
|
28
|
-
verbose && _check(pkgId, installedMoc, requiredMoc);
|
|
29
36
|
}
|
|
30
37
|
}
|
|
38
|
+
verbose || _check(tool, highestRequiredPkgId, installed, highestRequired);
|
|
31
39
|
}
|
|
32
|
-
verbose || _check(highestRequiredMocPkgId, installedMoc, highestRequiredMoc);
|
|
33
40
|
}
|
|
34
|
-
function _check(pkgId,
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
console.log(chalk.yellow(`moc version does not meet the requirements of ${pkgId}`));
|
|
38
|
-
console.log(chalk.yellow(` Required: >= ${requiredMoc.format()}`));
|
|
39
|
-
console.log(chalk.yellow(` Installed: ${installedMoc.format()}`));
|
|
41
|
+
function _check(tool, pkgId, installed, required) {
|
|
42
|
+
if (!pkgId || installed.compare(required) >= 0) {
|
|
43
|
+
return;
|
|
40
44
|
}
|
|
45
|
+
console.log(chalk.yellow(`${tool} version does not meet the requirements of ${pkgId}`));
|
|
46
|
+
console.log(chalk.yellow(` Required: >= ${required.format()}`));
|
|
47
|
+
console.log(chalk.yellow(` Installed: ${installed.format()}`));
|
|
41
48
|
}
|
package/dist/cli.js
CHANGED
|
@@ -65,12 +65,20 @@ function parseExtraArgs(variadicArgs) {
|
|
|
65
65
|
// Shared `--help` section describing the enhanced migration `check-limit`
|
|
66
66
|
// trimming and its override flag, so the limit behaviour is discoverable
|
|
67
67
|
// from `--help`. `withFix` appends the `--fix` hint for commands that support it.
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
68
|
+
// `withPendingWarning` adds the stable-check pending-migration warning (check / check-stable only).
|
|
69
|
+
function enhancedMigrationHelp(options = {}) {
|
|
70
|
+
const example = options.withFix ? " (e.g. to --fix older migrations)" : "";
|
|
71
|
+
let text = "\nEnhanced migration ([canisters.<name>.migrations]):\n" +
|
|
71
72
|
" The canister is checked against its migration chain. [migrations].check-limit\n" +
|
|
72
73
|
" trims it to the last N migrations (older ones are skipped). Pass --no-check-limit\n" +
|
|
73
|
-
` to use the full chain${example}
|
|
74
|
+
` to use the full chain${example}.`;
|
|
75
|
+
if (options.withPendingWarning) {
|
|
76
|
+
text +=
|
|
77
|
+
"\n When check-limit is set, the stable check reports if more migrations are pending\n" +
|
|
78
|
+
" (relative to the deployed .most baseline) than the limit allows — as an error if\n" +
|
|
79
|
+
" compat failed, otherwise a warning.";
|
|
80
|
+
}
|
|
81
|
+
return text;
|
|
74
82
|
}
|
|
75
83
|
program.name("mops");
|
|
76
84
|
// --version
|
|
@@ -286,9 +294,9 @@ program
|
|
|
286
294
|
.description("Check Motoko canisters or files for syntax errors and type issues. Arguments can be canister names or file paths. If no arguments are given, checks all canisters from mops.toml. Also runs stable compatibility checks for canisters with [check-stable] configured, and runs linting if lintoko is configured in [toolchain]")
|
|
287
295
|
.option("--verbose", "Verbose console output")
|
|
288
296
|
.addOption(new Option("--fix", "Apply autofixes to all files, including transitively imported ones"))
|
|
289
|
-
.addOption(new Option("--no-check-limit", "
|
|
297
|
+
.addOption(new Option("--no-check-limit", "Use the full migration chain, ignoring [migrations].check-limit; also suppresses the pending-migration warning"))
|
|
290
298
|
.addHelpText("after", "\nArguments after -- are forwarded directly to moc, e.g.:\n $ mops check -- -Werror")
|
|
291
|
-
.addHelpText("after", enhancedMigrationHelp(true))
|
|
299
|
+
.addHelpText("after", enhancedMigrationHelp({ withFix: true, withPendingWarning: true }))
|
|
292
300
|
.allowUnknownOption(true)
|
|
293
301
|
.action(async (args, options) => {
|
|
294
302
|
checkConfigFile(true);
|
|
@@ -321,9 +329,9 @@ program
|
|
|
321
329
|
.command("check-stable [args...]")
|
|
322
330
|
.description("Check stable variable compatibility. With no arguments, checks all canisters with [check-stable] configured. Arguments can be canister names or an old file path followed by an optional canister name")
|
|
323
331
|
.option("--verbose", "Verbose console output")
|
|
324
|
-
.addOption(new Option("--no-check-limit", "
|
|
332
|
+
.addOption(new Option("--no-check-limit", "Use the full migration chain, ignoring [migrations].check-limit; also suppresses the pending-migration warning"))
|
|
325
333
|
.addHelpText("after", "\nArguments after -- are forwarded directly to moc, e.g.:\n $ mops check-stable -- -Werror")
|
|
326
|
-
.addHelpText("after", enhancedMigrationHelp(
|
|
334
|
+
.addHelpText("after", enhancedMigrationHelp({ withPendingWarning: true }))
|
|
327
335
|
.allowUnknownOption(true)
|
|
328
336
|
.action(async (args, options) => {
|
|
329
337
|
checkConfigFile(true);
|
|
@@ -393,6 +401,8 @@ program
|
|
|
393
401
|
.addOption(new Option("--save", "Save benchmark results to .bench/<filename>.json"))
|
|
394
402
|
.addOption(new Option("--compare", "Run benchmark and compare results with .bench/<filename>.json"))
|
|
395
403
|
// .addOption(new Option('--force-gc', 'Force GC'))
|
|
404
|
+
.addOption(new Option("--query", "Measure each cell in a query call (how `query` methods run on the IC: no GC). Only for benchmarks whose runner is synchronous (no inter-canister calls)"))
|
|
405
|
+
.addOption(new Option("--legacy-persistence", "Compile benchmark canisters under legacy persistence instead of enhanced orthogonal persistence (the default)"))
|
|
396
406
|
.addOption(new Option("--verbose", "Print the benchmark pipeline (compiler, replica, GC, optimization) and stream compiler/replica output, including dfx optimization warnings"))
|
|
397
407
|
.action(async (filter, options) => {
|
|
398
408
|
checkConfigFile(true);
|
|
@@ -693,7 +703,7 @@ program
|
|
|
693
703
|
.addOption(new Option("-r, --rules <directory...>", "Directories containing rules (can be used multiple times)"))
|
|
694
704
|
.addOption(new Option("--no-check-limit", "Lint the full migration chain, ignoring [migrations].check-limit"))
|
|
695
705
|
.addHelpText("after", "\nArguments after -- are forwarded directly to lintoko, e.g.:\n $ mops lint -- --severity warning")
|
|
696
|
-
.addHelpText("after", enhancedMigrationHelp(true))
|
|
706
|
+
.addHelpText("after", enhancedMigrationHelp({ withFix: true }))
|
|
697
707
|
.allowUnknownOption(true)
|
|
698
708
|
.action(async (filter, options) => {
|
|
699
709
|
checkConfigFile(true);
|
package/dist/commands/bench.d.ts
CHANGED
package/dist/commands/bench.js
CHANGED
|
@@ -31,6 +31,8 @@ export async function bench(filter = "", optionsArg = {}) {
|
|
|
31
31
|
compilerVersion: getMocVersion(true),
|
|
32
32
|
gc: "copying",
|
|
33
33
|
forceGc: true,
|
|
34
|
+
query: false,
|
|
35
|
+
legacyPersistence: false,
|
|
34
36
|
save: false,
|
|
35
37
|
compare: false,
|
|
36
38
|
verbose: false,
|
|
@@ -71,6 +73,8 @@ export async function bench(filter = "", optionsArg = {}) {
|
|
|
71
73
|
console.log(chalk.gray(` compiler: moc ${options.compilerVersion}`));
|
|
72
74
|
console.log(chalk.gray(` replica: ${replicaType}${options.replicaVersion ? ` ${options.replicaVersion}` : ""}`));
|
|
73
75
|
console.log(chalk.gray(` gc: ${options.gc}${options.forceGc ? " (forced)" : ""}`));
|
|
76
|
+
console.log(chalk.gray(` context: ${options.query ? "query" : "update"}`));
|
|
77
|
+
console.log(chalk.gray(` persistence: ${options.legacyPersistence ? "legacy" : "enhanced"}`));
|
|
74
78
|
console.log(chalk.gray(` profile: ${options.profile}`));
|
|
75
79
|
console.log(chalk.gray(` optimize: ${optimize}`));
|
|
76
80
|
}
|
|
@@ -188,7 +192,12 @@ function computeDiffAll(currentResults, prevResults, rows, cols) {
|
|
|
188
192
|
}
|
|
189
193
|
function getMocArgs(options) {
|
|
190
194
|
let args = "";
|
|
191
|
-
|
|
195
|
+
// Benchmarks compile under enhanced orthogonal persistence (moc's default
|
|
196
|
+
// since 0.15) — the mode real canisters run. Pass `--legacy-persistence`
|
|
197
|
+
// only when the user opts in, and only where moc supports the flag (>= 0.15;
|
|
198
|
+
// legacy is already the default below it).
|
|
199
|
+
if (options.legacyPersistence &&
|
|
200
|
+
options.compilerVersion &&
|
|
192
201
|
new SemVer(options.compilerVersion).compare("0.15.0") >= 0) {
|
|
193
202
|
args += " --legacy-persistence";
|
|
194
203
|
}
|
|
@@ -386,10 +395,14 @@ async function runBenchFile(file, options, replica) {
|
|
|
386
395
|
if (canUpdateLog) {
|
|
387
396
|
log();
|
|
388
397
|
}
|
|
389
|
-
// run all cells
|
|
398
|
+
// run all cells. `--query` measures in query context (how `query` methods
|
|
399
|
+
// actually run on the IC: no GC), at the cost of not supporting benches whose
|
|
400
|
+
// runner performs async calls. Otherwise use the update path.
|
|
390
401
|
for (let [rowIndex, row] of schema.rows.entries()) {
|
|
391
402
|
for (let [colIndex, col] of schema.cols.entries()) {
|
|
392
|
-
let res =
|
|
403
|
+
let res = options.query
|
|
404
|
+
? await actor.runCellQuery(BigInt(rowIndex), BigInt(colIndex))
|
|
405
|
+
: await actor.runCellUpdateAwait(BigInt(rowIndex), BigInt(colIndex));
|
|
393
406
|
results.set(`${row}:${col}`, res);
|
|
394
407
|
// @ts-ignore
|
|
395
408
|
instructionsCells[rowIndex][colIndex] = res.instructions;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CanisterConfig } from "../types.js";
|
|
1
|
+
import { CanisterConfig, MigrationsConfig } from "../types.js";
|
|
2
2
|
export interface CheckStableOptions {
|
|
3
3
|
verbose: boolean;
|
|
4
4
|
extraArgs: string[];
|
|
@@ -17,6 +17,7 @@ export interface RunStableCheckParams {
|
|
|
17
17
|
globalMocArgs: string[];
|
|
18
18
|
canisterArgs: string[];
|
|
19
19
|
sources?: string[];
|
|
20
|
+
migrations?: MigrationsConfig;
|
|
20
21
|
options?: Partial<CheckStableOptions>;
|
|
21
22
|
}
|
|
22
23
|
export declare function runStableCheck(params: RunStableCheckParams): Promise<void>;
|
|
@@ -4,7 +4,7 @@ import { rm } from "node:fs/promises";
|
|
|
4
4
|
import chalk from "chalk";
|
|
5
5
|
import { execa } from "execa";
|
|
6
6
|
import { cliError } from "../error.js";
|
|
7
|
-
import { prepareMigrationArgs } from "../helpers/migrations.js";
|
|
7
|
+
import { getCheckLimitPendingIssue, prepareMigrationArgs, reportCheckLimitPendingIssue, } from "../helpers/migrations.js";
|
|
8
8
|
import { getGlobalMocArgs, readConfig, resolveConfigPath } from "../mops.js";
|
|
9
9
|
import { filterCanisters, looksLikeFile, resolveCanisterConfigs, resolveSingleCanister, validateCanisterArgs, } from "../helpers/resolve-canisters.js";
|
|
10
10
|
import { sourcesArgs } from "./sources.js";
|
|
@@ -61,6 +61,7 @@ export async function checkStable(args, options = {}) {
|
|
|
61
61
|
mocPath,
|
|
62
62
|
globalMocArgs,
|
|
63
63
|
canisterArgs: [...migration.migrationArgs, ...(canister.args ?? [])],
|
|
64
|
+
migrations: canister.migrations,
|
|
64
65
|
options,
|
|
65
66
|
});
|
|
66
67
|
}
|
|
@@ -95,6 +96,7 @@ export async function checkStable(args, options = {}) {
|
|
|
95
96
|
globalMocArgs,
|
|
96
97
|
canisterArgs: [...migration.migrationArgs, ...(canister.args ?? [])],
|
|
97
98
|
sources,
|
|
99
|
+
migrations: canister.migrations,
|
|
98
100
|
options,
|
|
99
101
|
});
|
|
100
102
|
}
|
|
@@ -136,7 +138,11 @@ export async function runStableCheck(params) {
|
|
|
136
138
|
stdio: "pipe",
|
|
137
139
|
reject: false,
|
|
138
140
|
});
|
|
139
|
-
|
|
141
|
+
const issue = getCheckLimitPendingIssue(params.migrations, canisterName, oldMostPath, options.checkLimit === false, isOldMostFile);
|
|
142
|
+
if (issue) {
|
|
143
|
+
reportCheckLimitPendingIssue(issue, result.exitCode !== 0);
|
|
144
|
+
}
|
|
145
|
+
else if (result.exitCode !== 0) {
|
|
140
146
|
if (result.stderr) {
|
|
141
147
|
console.error(result.stderr);
|
|
142
148
|
}
|
package/dist/commands/check.js
CHANGED
|
@@ -144,7 +144,12 @@ async function checkCanisters(config, canisters, options) {
|
|
|
144
144
|
globalMocArgs,
|
|
145
145
|
canisterArgs: [...migration.migrationArgs, ...(canister.args ?? [])],
|
|
146
146
|
sources,
|
|
147
|
-
|
|
147
|
+
migrations: canister.migrations,
|
|
148
|
+
options: {
|
|
149
|
+
verbose: options.verbose,
|
|
150
|
+
extraArgs: options.extraArgs,
|
|
151
|
+
checkLimit: options.checkLimit,
|
|
152
|
+
},
|
|
148
153
|
});
|
|
149
154
|
}
|
|
150
155
|
}
|
|
@@ -259,9 +259,7 @@ async function update(tool) {
|
|
|
259
259
|
let oldVersion = config.toolchain[tool];
|
|
260
260
|
config.toolchain[tool] = version;
|
|
261
261
|
writeConfig(config);
|
|
262
|
-
|
|
263
|
-
await checkRequirements();
|
|
264
|
-
}
|
|
262
|
+
await checkRequirements();
|
|
265
263
|
if (oldVersion === version) {
|
|
266
264
|
console.log(`Latest ${tool} ${version} is already installed`);
|
|
267
265
|
}
|