ic-mops 2.3.0 → 2.3.2
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 +6 -0
- package/RELEASE.md +24 -65
- package/bundle/cli.tgz +0 -0
- package/commands/build.ts +8 -5
- package/commands/check-stable.ts +2 -2
- package/commands/check.ts +9 -8
- package/dist/bin/mops.js +1 -1
- package/dist/commands/build.js +8 -5
- package/dist/commands/check-stable.js +2 -2
- package/dist/commands/check.js +9 -8
- package/dist/fix-dist.js +5 -0
- package/dist/mops.d.ts +5 -0
- package/dist/mops.js +7 -0
- package/dist/package.json +1 -1
- package/dist/tests/build.test.js +18 -0
- package/dist/tests/check.test.js +7 -0
- package/dist/wasm/pkg/nodejs/wasm_bg.wasm +0 -0
- package/dist/wasm/pkg/nodejs/wasm_bg.wasm.d.ts +1 -1
- package/dist/wasm/pkg/web/wasm.d.ts +1 -1
- package/dist/wasm/pkg/web/wasm_bg.wasm +0 -0
- package/dist/wasm/pkg/web/wasm_bg.wasm.d.ts +1 -1
- package/fix-dist.ts +9 -0
- package/mops.ts +8 -0
- package/package.json +1 -1
- package/tests/build.test.ts +24 -0
- package/tests/check/canisters-subdir/mops.toml +8 -0
- package/tests/check/canisters-subdir/src/backend/main.mo +5 -0
- package/tests/check.test.ts +11 -0
- package/wasm/pkg/nodejs/wasm_bg.wasm +0 -0
- package/wasm/pkg/nodejs/wasm_bg.wasm.d.ts +1 -1
- package/wasm/pkg/web/wasm.d.ts +1 -1
- package/wasm/pkg/web/wasm_bg.wasm +0 -0
- package/wasm/pkg/web/wasm_bg.wasm.d.ts +1 -1
- package/wasm/Cargo.lock +0 -1522
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
## Next
|
|
4
4
|
|
|
5
|
+
## 2.3.2
|
|
6
|
+
- Fix `mops check`, `mops build`, and `mops check-stable` failing to find canister entrypoints when run from a subdirectory
|
|
7
|
+
|
|
8
|
+
## 2.3.1
|
|
9
|
+
- Fix `mops build` and `mops check-candid` failing with "Wasm bindings have not been set" when installed via `npm i -g ic-mops`
|
|
10
|
+
|
|
5
11
|
## 2.3.0
|
|
6
12
|
- Add `mops check-stable` command for stable variable compatibility checking
|
|
7
13
|
- `mops check` now falls back to canister entrypoints from `mops.toml` when no files are specified
|
package/RELEASE.md
CHANGED
|
@@ -2,20 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
## Prerequisites
|
|
4
4
|
|
|
5
|
-
### macOS: GNU tar
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
brew install gnu-tar
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
Add to `~/.zshrc` or `~/.bashrc`:
|
|
12
|
-
```bash
|
|
13
|
-
export PATH="$HOMEBREW_PREFIX/opt/gnu-tar/libexec/gnubin:$PATH"
|
|
14
|
-
```
|
|
15
|
-
|
|
16
5
|
### Docker
|
|
17
6
|
|
|
18
|
-
Docker (or OrbStack) must be installed and running. The
|
|
7
|
+
Docker (or OrbStack) must be installed and running. The on-chain release step builds the CLI inside a Docker container (`zenvoich/mops-builder:1.1.0`) for reproducibility.
|
|
19
8
|
|
|
20
9
|
### dfx
|
|
21
10
|
|
|
@@ -23,13 +12,7 @@ Docker (or OrbStack) must be installed and running. The CLI build happens inside
|
|
|
23
12
|
|
|
24
13
|
## Release Steps
|
|
25
14
|
|
|
26
|
-
### 1.
|
|
27
|
-
|
|
28
|
-
```bash
|
|
29
|
-
cd cli && bun install
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
### 2. Update changelog
|
|
15
|
+
### 1. Update changelog
|
|
33
16
|
|
|
34
17
|
Move items from the `## Next` section in `CHANGELOG.md` into a new version heading:
|
|
35
18
|
|
|
@@ -41,28 +24,19 @@ Move items from the `## Next` section in `CHANGELOG.md` into a new version headi
|
|
|
41
24
|
- Change 2
|
|
42
25
|
```
|
|
43
26
|
|
|
44
|
-
The heading must contain the exact version string —
|
|
45
|
-
|
|
46
|
-
### 3. Create a release branch and PR
|
|
47
|
-
|
|
48
|
-
Direct pushes to `main` are not allowed. Create a branch and PR:
|
|
49
|
-
|
|
50
|
-
```bash
|
|
51
|
-
git checkout -b <username>/release-X.Y.Z
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
### 4. Bump version
|
|
27
|
+
The heading must contain the exact version string — the release workflow parses it to extract release notes for the GitHub Release.
|
|
55
28
|
|
|
56
|
-
|
|
29
|
+
### 2. Bump version
|
|
57
30
|
|
|
58
31
|
```bash
|
|
59
32
|
cd cli
|
|
60
33
|
npm version minor --no-git-tag-version # or: patch / major
|
|
61
34
|
```
|
|
62
35
|
|
|
63
|
-
###
|
|
36
|
+
### 3. Create a release branch and PR
|
|
64
37
|
|
|
65
38
|
```bash
|
|
39
|
+
git checkout -b <username>/release-X.Y.Z
|
|
66
40
|
git add cli/CHANGELOG.md cli/package.json cli/package-lock.json
|
|
67
41
|
git commit -m "release: CLI vX.Y.Z"
|
|
68
42
|
git push -u origin <username>/release-X.Y.Z
|
|
@@ -71,41 +45,26 @@ gh pr create --title "release: CLI vX.Y.Z" --body "..."
|
|
|
71
45
|
|
|
72
46
|
Wait for CI to pass, then merge the PR.
|
|
73
47
|
|
|
74
|
-
###
|
|
75
|
-
|
|
76
|
-
After the PR is merged to `main`, check the SHA256 hash from the latest [build-hash workflow](https://github.com/caffeinelabs/mops/actions/workflows/build-hash.yml) run.
|
|
48
|
+
### 4. Tag and push
|
|
77
49
|
|
|
78
|
-
|
|
50
|
+
After the PR is merged to `main`:
|
|
79
51
|
|
|
80
|
-
Build the same version locally:
|
|
81
52
|
```bash
|
|
82
|
-
|
|
83
|
-
|
|
53
|
+
git checkout main && git pull
|
|
54
|
+
git tag cli-vX.Y.Z
|
|
55
|
+
git push origin cli-vX.Y.Z
|
|
84
56
|
```
|
|
85
57
|
|
|
86
|
-
`
|
|
87
|
-
1.
|
|
88
|
-
2.
|
|
89
|
-
3.
|
|
90
|
-
4.
|
|
91
|
-
5.
|
|
58
|
+
This triggers the [`release.yml`](../.github/workflows/release.yml) workflow which automatically:
|
|
59
|
+
1. Validates the tag is on `main` and version matches `package.json`
|
|
60
|
+
2. Builds the CLI tarball in Docker (reproducible build)
|
|
61
|
+
3. Computes and reports the SHA256 hash (visible in the workflow Step Summary)
|
|
62
|
+
4. Publishes to npm via OIDC trusted publishing
|
|
63
|
+
5. Creates a GitHub Release with the tarball attached and changelog as release notes
|
|
92
64
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
**Notes on the local build output:**
|
|
96
|
-
- The "Verification failed" message at the end is **expected** — it happens because no `SHASUM` env var is passed for comparison. The important output is the `Actual shasum: <hash>` line.
|
|
97
|
-
|
|
98
|
-
### 7. Publish to npm
|
|
99
|
-
|
|
100
|
-
After the PR is merged and the build hash is verified:
|
|
101
|
-
|
|
102
|
-
```bash
|
|
103
|
-
git checkout main && git pull
|
|
104
|
-
cd cli
|
|
105
|
-
npm publish
|
|
106
|
-
```
|
|
65
|
+
Monitor the workflow run at [Actions → Release CLI](https://github.com/caffeinelabs/mops/actions/workflows/release.yml).
|
|
107
66
|
|
|
108
|
-
###
|
|
67
|
+
### 5. Prepare on-chain release
|
|
109
68
|
|
|
110
69
|
Run from the **repo root** (not `cli/`), with Docker running:
|
|
111
70
|
|
|
@@ -122,7 +81,7 @@ This runs `cli/release-cli.ts`, which:
|
|
|
122
81
|
6. Updates `cli-releases/tags/latest` to the new version
|
|
123
82
|
7. Updates `cli-releases/releases.json` with metadata (timestamp, size, hash, commit hash, download URL, release notes)
|
|
124
83
|
|
|
125
|
-
###
|
|
84
|
+
### 6. Deploy the canister
|
|
126
85
|
|
|
127
86
|
```bash
|
|
128
87
|
dfx deploy --network ic --no-wallet cli --identity mops
|
|
@@ -130,7 +89,7 @@ dfx deploy --network ic --no-wallet cli --identity mops
|
|
|
130
89
|
|
|
131
90
|
This deploys the `cli-releases` canister (serving `cli.mops.one`) to the Internet Computer mainnet.
|
|
132
91
|
|
|
133
|
-
###
|
|
92
|
+
### 7. Deploy the docs canister
|
|
134
93
|
|
|
135
94
|
```bash
|
|
136
95
|
dfx deploy --network ic --no-wallet docs --identity mops
|
|
@@ -138,9 +97,9 @@ dfx deploy --network ic --no-wallet docs --identity mops
|
|
|
138
97
|
|
|
139
98
|
This builds the Docusaurus site (`docs/`) and deploys the `docs` assets canister (serving `docs.mops.one`). Docs are not auto-deployed, so this step ensures any documentation changes from the release are published.
|
|
140
99
|
|
|
141
|
-
###
|
|
100
|
+
### 8. Commit and push release artifacts
|
|
142
101
|
|
|
143
|
-
Step
|
|
102
|
+
Step 5 generates files in `cli-releases/` that must be committed and pushed:
|
|
144
103
|
|
|
145
104
|
```bash
|
|
146
105
|
git add cli-releases/
|
|
@@ -159,7 +118,7 @@ Merge this PR after approval.
|
|
|
159
118
|
|
|
160
119
|
## Verify build
|
|
161
120
|
|
|
162
|
-
Anyone can verify a released version by rebuilding from source
|
|
121
|
+
Anyone can verify a released version by rebuilding from source. The SHA256 hash and verification instructions are included in each [GitHub Release](https://github.com/caffeinelabs/mops/releases).
|
|
163
122
|
|
|
164
123
|
```bash
|
|
165
124
|
cd cli
|
package/bundle/cli.tgz
CHANGED
|
Binary file
|
package/commands/build.ts
CHANGED
|
@@ -7,7 +7,7 @@ import { cliError } from "../error.js";
|
|
|
7
7
|
import { isCandidCompatible } from "../helpers/is-candid-compatible.js";
|
|
8
8
|
import { resolveCanisterConfigs } from "../helpers/resolve-canisters.js";
|
|
9
9
|
import { CustomSection, getWasmBindings } from "../wasm.js";
|
|
10
|
-
import { getGlobalMocArgs, readConfig } from "../mops.js";
|
|
10
|
+
import { getGlobalMocArgs, readConfig, resolveConfigPath } from "../mops.js";
|
|
11
11
|
import { sourcesArgs } from "./sources.js";
|
|
12
12
|
import { toolchain } from "./toolchain/index.js";
|
|
13
13
|
|
|
@@ -67,6 +67,7 @@ export async function build(
|
|
|
67
67
|
if (!motokoPath) {
|
|
68
68
|
cliError(`No main file is specified for canister ${canisterName}`);
|
|
69
69
|
}
|
|
70
|
+
motokoPath = resolveConfigPath(motokoPath);
|
|
70
71
|
const wasmPath = join(outputDir, `${canisterName}.wasm`);
|
|
71
72
|
let args = [
|
|
72
73
|
"-c",
|
|
@@ -129,13 +130,15 @@ export async function build(
|
|
|
129
130
|
}
|
|
130
131
|
|
|
131
132
|
const generatedDidPath = join(outputDir, `${canisterName}.did`);
|
|
132
|
-
|
|
133
|
-
|
|
133
|
+
const resolvedCandidPath = canister.candid
|
|
134
|
+
? resolveConfigPath(canister.candid)
|
|
135
|
+
: null;
|
|
134
136
|
|
|
137
|
+
if (resolvedCandidPath) {
|
|
135
138
|
try {
|
|
136
139
|
const compatible = await isCandidCompatible(
|
|
137
140
|
generatedDidPath,
|
|
138
|
-
|
|
141
|
+
resolvedCandidPath,
|
|
139
142
|
);
|
|
140
143
|
|
|
141
144
|
if (!compatible) {
|
|
@@ -160,7 +163,7 @@ export async function build(
|
|
|
160
163
|
|
|
161
164
|
options.verbose &&
|
|
162
165
|
console.log(chalk.gray(`Adding metadata to ${wasmPath}`));
|
|
163
|
-
const candidPath =
|
|
166
|
+
const candidPath = resolvedCandidPath ?? generatedDidPath;
|
|
164
167
|
const candidText = await readFile(candidPath, "utf-8");
|
|
165
168
|
const customSections: CustomSection[] = [
|
|
166
169
|
{ name: `${candidVisibility} candid:service`, data: candidText },
|
package/commands/check-stable.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { rename, 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 { getGlobalMocArgs, readConfig } from "../mops.js";
|
|
7
|
+
import { getGlobalMocArgs, readConfig, resolveConfigPath } from "../mops.js";
|
|
8
8
|
import { resolveSingleCanister } from "../helpers/resolve-canisters.js";
|
|
9
9
|
import { sourcesArgs } from "./sources.js";
|
|
10
10
|
import { toolchain } from "./toolchain/index.js";
|
|
@@ -33,7 +33,7 @@ export async function checkStable(
|
|
|
33
33
|
|
|
34
34
|
await runStableCheck({
|
|
35
35
|
oldFile,
|
|
36
|
-
canisterMain: canister.main,
|
|
36
|
+
canisterMain: resolveConfigPath(canister.main),
|
|
37
37
|
canisterName: name,
|
|
38
38
|
mocPath,
|
|
39
39
|
globalMocArgs,
|
package/commands/check.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import
|
|
1
|
+
import path from "node:path";
|
|
2
2
|
import { existsSync } from "node:fs";
|
|
3
3
|
import chalk from "chalk";
|
|
4
4
|
import { execa } from "execa";
|
|
5
5
|
import { cliError } from "../error.js";
|
|
6
|
-
import { getGlobalMocArgs, readConfig } from "../mops.js";
|
|
6
|
+
import { getGlobalMocArgs, readConfig, resolveConfigPath } from "../mops.js";
|
|
7
7
|
import { autofixMotoko } from "../helpers/autofix-motoko.js";
|
|
8
8
|
import { getMocSemVer } from "../helpers/get-moc-version.js";
|
|
9
9
|
import {
|
|
@@ -36,7 +36,7 @@ export async function check(
|
|
|
36
36
|
const config = readConfig();
|
|
37
37
|
|
|
38
38
|
if (fileList.length === 0) {
|
|
39
|
-
fileList = resolveCanisterEntrypoints(config);
|
|
39
|
+
fileList = resolveCanisterEntrypoints(config).map(resolveConfigPath);
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
if (fileList.length === 0) {
|
|
@@ -86,7 +86,7 @@ export async function check(
|
|
|
86
86
|
for (const [file, codes] of fixResult.fixedFiles) {
|
|
87
87
|
const unique = [...new Set(codes)].sort();
|
|
88
88
|
const n = codes.length;
|
|
89
|
-
const rel = relative(process.cwd(), file);
|
|
89
|
+
const rel = path.relative(process.cwd(), file);
|
|
90
90
|
console.log(
|
|
91
91
|
chalk.green(
|
|
92
92
|
`Fixed ${rel} (${n} ${n === 1 ? "fix" : "fixes"}: ${unique.join(", ")})`,
|
|
@@ -144,12 +144,13 @@ export async function check(
|
|
|
144
144
|
cliError(`No main file specified for canister '${name}' in mops.toml`);
|
|
145
145
|
}
|
|
146
146
|
|
|
147
|
-
|
|
147
|
+
const stablePath = resolveConfigPath(stableConfig.path);
|
|
148
|
+
if (!existsSync(stablePath)) {
|
|
148
149
|
if (stableConfig.skipIfMissing) {
|
|
149
150
|
continue;
|
|
150
151
|
}
|
|
151
152
|
cliError(
|
|
152
|
-
`Deployed file not found: ${
|
|
153
|
+
`Deployed file not found: ${stablePath} (canister '${name}')\n` +
|
|
153
154
|
"Set skipIfMissing = true in [canisters." +
|
|
154
155
|
name +
|
|
155
156
|
".check-stable] to skip this check when the file is missing.",
|
|
@@ -157,8 +158,8 @@ export async function check(
|
|
|
157
158
|
}
|
|
158
159
|
|
|
159
160
|
await runStableCheck({
|
|
160
|
-
oldFile:
|
|
161
|
-
canisterMain: canister.main,
|
|
161
|
+
oldFile: stablePath,
|
|
162
|
+
canisterMain: resolveConfigPath(canister.main),
|
|
162
163
|
canisterName: name,
|
|
163
164
|
mocPath,
|
|
164
165
|
globalMocArgs,
|
package/dist/bin/mops.js
CHANGED
package/dist/commands/build.js
CHANGED
|
@@ -7,7 +7,7 @@ import { cliError } from "../error.js";
|
|
|
7
7
|
import { isCandidCompatible } from "../helpers/is-candid-compatible.js";
|
|
8
8
|
import { resolveCanisterConfigs } from "../helpers/resolve-canisters.js";
|
|
9
9
|
import { getWasmBindings } from "../wasm.js";
|
|
10
|
-
import { getGlobalMocArgs, readConfig } from "../mops.js";
|
|
10
|
+
import { getGlobalMocArgs, readConfig, resolveConfigPath } from "../mops.js";
|
|
11
11
|
import { sourcesArgs } from "./sources.js";
|
|
12
12
|
import { toolchain } from "./toolchain/index.js";
|
|
13
13
|
export const DEFAULT_BUILD_OUTPUT_DIR = ".mops/.build";
|
|
@@ -45,6 +45,7 @@ export async function build(canisterNames, options) {
|
|
|
45
45
|
if (!motokoPath) {
|
|
46
46
|
cliError(`No main file is specified for canister ${canisterName}`);
|
|
47
47
|
}
|
|
48
|
+
motokoPath = resolveConfigPath(motokoPath);
|
|
48
49
|
const wasmPath = join(outputDir, `${canisterName}.wasm`);
|
|
49
50
|
let args = [
|
|
50
51
|
"-c",
|
|
@@ -98,10 +99,12 @@ export async function build(canisterNames, options) {
|
|
|
98
99
|
console.log(result.stdout);
|
|
99
100
|
}
|
|
100
101
|
const generatedDidPath = join(outputDir, `${canisterName}.did`);
|
|
101
|
-
|
|
102
|
-
|
|
102
|
+
const resolvedCandidPath = canister.candid
|
|
103
|
+
? resolveConfigPath(canister.candid)
|
|
104
|
+
: null;
|
|
105
|
+
if (resolvedCandidPath) {
|
|
103
106
|
try {
|
|
104
|
-
const compatible = await isCandidCompatible(generatedDidPath,
|
|
107
|
+
const compatible = await isCandidCompatible(generatedDidPath, resolvedCandidPath);
|
|
105
108
|
if (!compatible) {
|
|
106
109
|
cliError(`Candid compatibility check failed for canister ${canisterName}`);
|
|
107
110
|
}
|
|
@@ -115,7 +118,7 @@ export async function build(canisterNames, options) {
|
|
|
115
118
|
}
|
|
116
119
|
options.verbose &&
|
|
117
120
|
console.log(chalk.gray(`Adding metadata to ${wasmPath}`));
|
|
118
|
-
const candidPath =
|
|
121
|
+
const candidPath = resolvedCandidPath ?? generatedDidPath;
|
|
119
122
|
const candidText = await readFile(candidPath, "utf-8");
|
|
120
123
|
const customSections = [
|
|
121
124
|
{ name: `${candidVisibility} candid:service`, data: candidText },
|
|
@@ -4,7 +4,7 @@ import { rename, 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 { getGlobalMocArgs, readConfig } from "../mops.js";
|
|
7
|
+
import { getGlobalMocArgs, readConfig, resolveConfigPath } from "../mops.js";
|
|
8
8
|
import { resolveSingleCanister } from "../helpers/resolve-canisters.js";
|
|
9
9
|
import { sourcesArgs } from "./sources.js";
|
|
10
10
|
import { toolchain } from "./toolchain/index.js";
|
|
@@ -19,7 +19,7 @@ export async function checkStable(oldFile, canisterName, options = {}) {
|
|
|
19
19
|
const globalMocArgs = getGlobalMocArgs(config);
|
|
20
20
|
await runStableCheck({
|
|
21
21
|
oldFile,
|
|
22
|
-
canisterMain: canister.main,
|
|
22
|
+
canisterMain: resolveConfigPath(canister.main),
|
|
23
23
|
canisterName: name,
|
|
24
24
|
mocPath,
|
|
25
25
|
globalMocArgs,
|
package/dist/commands/check.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import
|
|
1
|
+
import path from "node:path";
|
|
2
2
|
import { existsSync } from "node:fs";
|
|
3
3
|
import chalk from "chalk";
|
|
4
4
|
import { execa } from "execa";
|
|
5
5
|
import { cliError } from "../error.js";
|
|
6
|
-
import { getGlobalMocArgs, readConfig } from "../mops.js";
|
|
6
|
+
import { getGlobalMocArgs, readConfig, resolveConfigPath } from "../mops.js";
|
|
7
7
|
import { autofixMotoko } from "../helpers/autofix-motoko.js";
|
|
8
8
|
import { getMocSemVer } from "../helpers/get-moc-version.js";
|
|
9
9
|
import { resolveCanisterConfigs, resolveCanisterEntrypoints, } from "../helpers/resolve-canisters.js";
|
|
@@ -19,7 +19,7 @@ export async function check(files, options = {}) {
|
|
|
19
19
|
let fileList = Array.isArray(files) ? files : files ? [files] : [];
|
|
20
20
|
const config = readConfig();
|
|
21
21
|
if (fileList.length === 0) {
|
|
22
|
-
fileList = resolveCanisterEntrypoints(config);
|
|
22
|
+
fileList = resolveCanisterEntrypoints(config).map(resolveConfigPath);
|
|
23
23
|
}
|
|
24
24
|
if (fileList.length === 0) {
|
|
25
25
|
cliError("No Motoko files specified and no canisters defined in mops.toml.\n" +
|
|
@@ -55,7 +55,7 @@ export async function check(files, options = {}) {
|
|
|
55
55
|
for (const [file, codes] of fixResult.fixedFiles) {
|
|
56
56
|
const unique = [...new Set(codes)].sort();
|
|
57
57
|
const n = codes.length;
|
|
58
|
-
const rel = relative(process.cwd(), file);
|
|
58
|
+
const rel = path.relative(process.cwd(), file);
|
|
59
59
|
console.log(chalk.green(`Fixed ${rel} (${n} ${n === 1 ? "fix" : "fixes"}: ${unique.join(", ")})`));
|
|
60
60
|
}
|
|
61
61
|
const fileCount = fixResult.fixedFiles.size;
|
|
@@ -96,18 +96,19 @@ export async function check(files, options = {}) {
|
|
|
96
96
|
if (!canister.main) {
|
|
97
97
|
cliError(`No main file specified for canister '${name}' in mops.toml`);
|
|
98
98
|
}
|
|
99
|
-
|
|
99
|
+
const stablePath = resolveConfigPath(stableConfig.path);
|
|
100
|
+
if (!existsSync(stablePath)) {
|
|
100
101
|
if (stableConfig.skipIfMissing) {
|
|
101
102
|
continue;
|
|
102
103
|
}
|
|
103
|
-
cliError(`Deployed file not found: ${
|
|
104
|
+
cliError(`Deployed file not found: ${stablePath} (canister '${name}')\n` +
|
|
104
105
|
"Set skipIfMissing = true in [canisters." +
|
|
105
106
|
name +
|
|
106
107
|
".check-stable] to skip this check when the file is missing.");
|
|
107
108
|
}
|
|
108
109
|
await runStableCheck({
|
|
109
|
-
oldFile:
|
|
110
|
-
canisterMain: canister.main,
|
|
110
|
+
oldFile: stablePath,
|
|
111
|
+
canisterMain: resolveConfigPath(canister.main),
|
|
111
112
|
canisterName: name,
|
|
112
113
|
mocPath,
|
|
113
114
|
globalMocArgs,
|
package/dist/fix-dist.js
CHANGED
|
@@ -7,3 +7,8 @@ delete json.scripts;
|
|
|
7
7
|
json.bin.mops = "bin/mops.js";
|
|
8
8
|
json.bin["ic-mops"] = "bin/mops.js";
|
|
9
9
|
writeFileSync("dist/package.json", JSON.stringify(json, null, 2));
|
|
10
|
+
// Route the npm entry point through the Node.js environment wrapper
|
|
11
|
+
// so setWasmBindings() is called before the CLI runs.
|
|
12
|
+
// The source bin/mops.js imports ../cli.js (needed for the single-file bundle),
|
|
13
|
+
// but dist/ has the full directory structure with environments/nodejs/cli.js.
|
|
14
|
+
writeFileSync("dist/bin/mops.js", '#!/usr/bin/env node\n\nimport "../environments/nodejs/cli.js";\n');
|
package/dist/mops.d.ts
CHANGED
|
@@ -11,6 +11,11 @@ export declare function setNetwork(network: string): void;
|
|
|
11
11
|
export declare let getIdentity: () => Promise<Identity | undefined>;
|
|
12
12
|
export declare function getClosestConfigFile(dir?: string): string;
|
|
13
13
|
export declare function getRootDir(): string;
|
|
14
|
+
/**
|
|
15
|
+
* Resolve a path from mops.toml config (relative to project root)
|
|
16
|
+
* into a path relative to the current working directory.
|
|
17
|
+
*/
|
|
18
|
+
export declare function resolveConfigPath(configPath: string): string;
|
|
14
19
|
export declare function checkConfigFile(exit?: boolean): boolean;
|
|
15
20
|
export declare function progressBar(step: number, total: number): string;
|
|
16
21
|
export declare function parseGithubURL(href: string): {
|
package/dist/mops.js
CHANGED
|
@@ -87,6 +87,13 @@ export function getRootDir() {
|
|
|
87
87
|
}
|
|
88
88
|
return path.dirname(configFile);
|
|
89
89
|
}
|
|
90
|
+
/**
|
|
91
|
+
* Resolve a path from mops.toml config (relative to project root)
|
|
92
|
+
* into a path relative to the current working directory.
|
|
93
|
+
*/
|
|
94
|
+
export function resolveConfigPath(configPath) {
|
|
95
|
+
return path.relative(process.cwd(), path.resolve(getRootDir(), configPath));
|
|
96
|
+
}
|
|
90
97
|
export function checkConfigFile(exit = false) {
|
|
91
98
|
let configFile = getClosestConfigFile();
|
|
92
99
|
if (!configFile) {
|
package/dist/package.json
CHANGED
package/dist/tests/build.test.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { describe, expect, test } from "@jest/globals";
|
|
2
|
+
import { execa } from "execa";
|
|
3
|
+
import { existsSync } from "node:fs";
|
|
2
4
|
import path from "path";
|
|
3
5
|
import { cliSnapshot } from "./helpers";
|
|
6
|
+
const distBin = path.resolve(import.meta.dirname, "../dist/bin/mops.js");
|
|
4
7
|
describe("build", () => {
|
|
5
8
|
test("ok", async () => {
|
|
6
9
|
const cwd = path.join(import.meta.dirname, "build/success");
|
|
@@ -15,4 +18,19 @@ describe("build", () => {
|
|
|
15
18
|
expect((await cliSnapshot(["build", "bar"], { cwd }, 1)).stderr).toMatch("Candid compatibility check failed for canister bar");
|
|
16
19
|
expect((await cliSnapshot(["build", "foo", "bar"], { cwd }, 1)).stderr).toMatch("Candid compatibility check failed for canister bar");
|
|
17
20
|
});
|
|
21
|
+
// Regression: bin/mops.js must route through environments/nodejs/cli.js
|
|
22
|
+
// so that setWasmBindings() is called before any command runs.
|
|
23
|
+
// The dev entry point (npm run mops) uses tsx and always worked;
|
|
24
|
+
// this test exercises the compiled dist binary (same path as npm i -g ic-mops).
|
|
25
|
+
const hasDistBin = existsSync(distBin);
|
|
26
|
+
(hasDistBin ? test : test.skip)("wasm bindings initialized via dist entry point", async () => {
|
|
27
|
+
const cwd = path.join(import.meta.dirname, "build/success");
|
|
28
|
+
const result = await execa("node", [distBin, "build", "foo"], {
|
|
29
|
+
cwd,
|
|
30
|
+
stdio: "pipe",
|
|
31
|
+
reject: false,
|
|
32
|
+
});
|
|
33
|
+
expect(result.stderr).not.toContain("Wasm bindings have not been set");
|
|
34
|
+
expect(result.exitCode).toBe(0);
|
|
35
|
+
});
|
|
18
36
|
});
|
package/dist/tests/check.test.js
CHANGED
|
@@ -38,6 +38,13 @@ describe("check", () => {
|
|
|
38
38
|
const cwd = path.join(import.meta.dirname, "check/canisters");
|
|
39
39
|
await cliSnapshot(["check"], { cwd }, 0);
|
|
40
40
|
});
|
|
41
|
+
test("canister entrypoint resolved relative to config root when run from subdirectory", async () => {
|
|
42
|
+
const fixtureRoot = path.join(import.meta.dirname, "check/canisters-subdir");
|
|
43
|
+
const subdir = path.join(fixtureRoot, "src/backend");
|
|
44
|
+
const result = await cli(["check"], { cwd: subdir });
|
|
45
|
+
expect(result.exitCode).toBe(0);
|
|
46
|
+
expect(result.stdout).toMatch(/✓/);
|
|
47
|
+
});
|
|
41
48
|
test("[moc] args applied when using canister fallback", async () => {
|
|
42
49
|
const cwd = path.join(import.meta.dirname, "check/canisters-moc-args");
|
|
43
50
|
const result = await cli(["check"], { cwd });
|
|
Binary file
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/* tslint:disable */
|
|
2
2
|
/* eslint-disable */
|
|
3
3
|
export const memory: WebAssembly.Memory;
|
|
4
|
-
export const is_candid_compatible: (a: number, b: number, c: number, d: number) => number;
|
|
5
4
|
export const add_custom_sections: (a: number, b: number, c: any) => [number, number, number, number];
|
|
5
|
+
export const is_candid_compatible: (a: number, b: number, c: number, d: number) => number;
|
|
6
6
|
export const __wbindgen_malloc: (a: number, b: number) => number;
|
|
7
7
|
export const __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
|
|
8
8
|
export const __wbindgen_exn_store: (a: number) => void;
|
|
@@ -9,8 +9,8 @@ export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembl
|
|
|
9
9
|
|
|
10
10
|
export interface InitOutput {
|
|
11
11
|
readonly memory: WebAssembly.Memory;
|
|
12
|
-
readonly is_candid_compatible: (a: number, b: number, c: number, d: number) => number;
|
|
13
12
|
readonly add_custom_sections: (a: number, b: number, c: any) => [number, number, number, number];
|
|
13
|
+
readonly is_candid_compatible: (a: number, b: number, c: number, d: number) => number;
|
|
14
14
|
readonly __wbindgen_malloc: (a: number, b: number) => number;
|
|
15
15
|
readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
|
|
16
16
|
readonly __wbindgen_exn_store: (a: number) => void;
|
|
Binary file
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/* tslint:disable */
|
|
2
2
|
/* eslint-disable */
|
|
3
3
|
export const memory: WebAssembly.Memory;
|
|
4
|
-
export const is_candid_compatible: (a: number, b: number, c: number, d: number) => number;
|
|
5
4
|
export const add_custom_sections: (a: number, b: number, c: any) => [number, number, number, number];
|
|
5
|
+
export const is_candid_compatible: (a: number, b: number, c: number, d: number) => number;
|
|
6
6
|
export const __wbindgen_malloc: (a: number, b: number) => number;
|
|
7
7
|
export const __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
|
|
8
8
|
export const __wbindgen_exn_store: (a: number) => void;
|
package/fix-dist.ts
CHANGED
|
@@ -10,3 +10,12 @@ json.bin.mops = "bin/mops.js";
|
|
|
10
10
|
json.bin["ic-mops"] = "bin/mops.js";
|
|
11
11
|
|
|
12
12
|
writeFileSync("dist/package.json", JSON.stringify(json, null, 2));
|
|
13
|
+
|
|
14
|
+
// Route the npm entry point through the Node.js environment wrapper
|
|
15
|
+
// so setWasmBindings() is called before the CLI runs.
|
|
16
|
+
// The source bin/mops.js imports ../cli.js (needed for the single-file bundle),
|
|
17
|
+
// but dist/ has the full directory structure with environments/nodejs/cli.js.
|
|
18
|
+
writeFileSync(
|
|
19
|
+
"dist/bin/mops.js",
|
|
20
|
+
'#!/usr/bin/env node\n\nimport "../environments/nodejs/cli.js";\n',
|
|
21
|
+
);
|
package/mops.ts
CHANGED
|
@@ -100,6 +100,14 @@ export function getRootDir() {
|
|
|
100
100
|
return path.dirname(configFile);
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
+
/**
|
|
104
|
+
* Resolve a path from mops.toml config (relative to project root)
|
|
105
|
+
* into a path relative to the current working directory.
|
|
106
|
+
*/
|
|
107
|
+
export function resolveConfigPath(configPath: string): string {
|
|
108
|
+
return path.relative(process.cwd(), path.resolve(getRootDir(), configPath));
|
|
109
|
+
}
|
|
110
|
+
|
|
103
111
|
export function checkConfigFile(exit = false) {
|
|
104
112
|
let configFile = getClosestConfigFile();
|
|
105
113
|
if (!configFile) {
|
package/package.json
CHANGED
package/tests/build.test.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { describe, expect, test } from "@jest/globals";
|
|
2
|
+
import { execa } from "execa";
|
|
3
|
+
import { existsSync } from "node:fs";
|
|
2
4
|
import path from "path";
|
|
3
5
|
import { cliSnapshot } from "./helpers";
|
|
4
6
|
|
|
7
|
+
const distBin = path.resolve(import.meta.dirname, "../dist/bin/mops.js");
|
|
8
|
+
|
|
5
9
|
describe("build", () => {
|
|
6
10
|
test("ok", async () => {
|
|
7
11
|
const cwd = path.join(import.meta.dirname, "build/success");
|
|
@@ -21,4 +25,24 @@ describe("build", () => {
|
|
|
21
25
|
(await cliSnapshot(["build", "foo", "bar"], { cwd }, 1)).stderr,
|
|
22
26
|
).toMatch("Candid compatibility check failed for canister bar");
|
|
23
27
|
});
|
|
28
|
+
|
|
29
|
+
// Regression: bin/mops.js must route through environments/nodejs/cli.js
|
|
30
|
+
// so that setWasmBindings() is called before any command runs.
|
|
31
|
+
// The dev entry point (npm run mops) uses tsx and always worked;
|
|
32
|
+
// this test exercises the compiled dist binary (same path as npm i -g ic-mops).
|
|
33
|
+
const hasDistBin = existsSync(distBin);
|
|
34
|
+
(hasDistBin ? test : test.skip)(
|
|
35
|
+
"wasm bindings initialized via dist entry point",
|
|
36
|
+
async () => {
|
|
37
|
+
const cwd = path.join(import.meta.dirname, "build/success");
|
|
38
|
+
const result = await execa("node", [distBin, "build", "foo"], {
|
|
39
|
+
cwd,
|
|
40
|
+
stdio: "pipe",
|
|
41
|
+
reject: false,
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
expect(result.stderr).not.toContain("Wasm bindings have not been set");
|
|
45
|
+
expect(result.exitCode).toBe(0);
|
|
46
|
+
},
|
|
47
|
+
);
|
|
24
48
|
});
|