Skip to content

Commit 3a57a75

Browse files
Fix cross-platform package E2E runner
Co-authored-by: devmap-agent <238585242+devmap-agent@users.noreply.github.com>
1 parent 46201e5 commit 3a57a75

2 files changed

Lines changed: 70 additions & 7 deletions

File tree

docs/for-me-personal/DEBUG.md

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Catatan Debugging DevMap
22

3-
Terakhir diperbarui: 2026-06-11
3+
Terakhir diperbarui: 2026-06-13
44

55
Dokumen ini menyimpan masalah teknis yang pernah ditemukan selama development
66
DevMap. Tujuannya supaya penyebab, solusi, dan cara verifikasinya tidak perlu
@@ -672,3 +672,39 @@ Gunakan format:
672672
### Verifikasi
673673
### Pelajaran
674674
```
675+
## 12. Packed E2E Mengasumsikan Layout Internal npm
676+
677+
**Tanggal:** 2026-06-13
678+
**Status:** Selesai
679+
680+
### Gejala
681+
682+
Package smoke test gagal pada GitHub Actions Ubuntu dengan `MODULE_NOT_FOUND`
683+
untuk path `node_modules/npm/bin/npm-cli.js`.
684+
685+
### Akar Masalah
686+
687+
Harness menyusun path internal npm relatif terhadap `process.execPath`.
688+
Layout tersebut tersedia pada instalasi Node lokal tertentu, tetapi bukan
689+
kontrak lintas platform dan tidak dipakai oleh image Node GitHub Actions.
690+
691+
### Solusi
692+
693+
Jalankan executable npm resmi yang berada di samping binary Node:
694+
695+
- `npm.cmd` pada Windows;
696+
- `npm` pada Linux dan macOS.
697+
698+
Windows menjalankan `npm.cmd` melalui shell, sedangkan Node, pnpm, dan binary
699+
Linux/macOS tetap dijalankan langsung. pnpm tetap memakai `npm_execpath` yang
700+
disediakan oleh pnpm.
701+
702+
### Verifikasi
703+
704+
- `pnpm test:package-e2e`
705+
- package smoke test GitHub Actions
706+
707+
### Pelajaran
708+
709+
Jangan bergantung pada struktur internal instalasi package manager. Gunakan
710+
executable publiknya ketika menguji perilaku CLI lintas platform.

packages/cli/test/package-e2e.mjs

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import assert from "node:assert/strict";
2-
import { execFile } from "node:child_process";
2+
import { exec, execFile } from "node:child_process";
33
import {
44
cp,
55
mkdtemp,
@@ -15,11 +15,15 @@ import { promisify } from "node:util";
1515
import { fileURLToPath } from "node:url";
1616

1717
const execute = promisify(execFile);
18+
const executeShell = promisify(exec);
1819
const testDirectory = dirname(fileURLToPath(import.meta.url));
1920
const packageRoot = resolve(testDirectory, "..");
2021
const workspaceRoot = resolve(packageRoot, "../..");
2122
const pnpmCli = process.env.npm_execpath;
22-
const npmCli = resolve(dirname(process.execPath), "node_modules/npm/bin/npm-cli.js");
23+
const npmExecutable = join(
24+
dirname(process.execPath),
25+
process.platform === "win32" ? "npm.cmd" : "npm"
26+
);
2327

2428
if (!pnpmCli) {
2529
throw new Error("Run this test through pnpm so npm_execpath is available.");
@@ -64,7 +68,7 @@ try {
6468
private: true
6569
}, null, 2), "utf8");
6670

67-
await runNodeCli(npmCli, [
71+
await runNpm([
6872
"install",
6973
"--no-package-lock",
7074
"--ignore-scripts",
@@ -106,11 +110,30 @@ try {
106110
}
107111

108112
async function runDevmap(cwd, args) {
109-
return runNodeCli(npmCli, ["exec", "--", "devmap", ...args], cwd);
113+
return runNpm(["exec", "--", "devmap", ...args], cwd);
110114
}
111115

112116
async function runNodeCli(cliPath, args, cwd) {
113-
return execute(process.execPath, [cliPath, ...args], {
117+
return runExecutable(process.execPath, [cliPath, ...args], cwd);
118+
}
119+
120+
async function runNpm(args, cwd) {
121+
if (process.platform !== "win32") {
122+
return runExecutable(npmExecutable, args, cwd);
123+
}
124+
125+
const command = [npmExecutable, ...args]
126+
.map(quoteWindowsArgument)
127+
.join(" ");
128+
return executeShell(command, commandOptions(cwd));
129+
}
130+
131+
async function runExecutable(executable, args, cwd) {
132+
return execute(executable, args, commandOptions(cwd));
133+
}
134+
135+
function commandOptions(cwd) {
136+
return {
114137
cwd,
115138
env: {
116139
...process.env,
@@ -120,7 +143,11 @@ async function runNodeCli(cliPath, args, cwd) {
120143
},
121144
maxBuffer: 10 * 1024 * 1024,
122145
windowsHide: true
123-
});
146+
};
147+
}
148+
149+
function quoteWindowsArgument(value) {
150+
return `"${value.replaceAll('"', '""')}"`;
124151
}
125152

126153
function stripAnsi(value) {

0 commit comments

Comments
 (0)