@pipelab/test-utils 1.0.0-beta.32 → 1.0.0-beta.35
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 +24 -0
- package/dist/index.cjs +10 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +14 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
- package/src/index.ts +19 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# @pipelab/test-utils
|
|
2
2
|
|
|
3
|
+
## 1.0.0-beta.35
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- sd
|
|
8
|
+
- Updated dependencies
|
|
9
|
+
- @pipelab/plugin-core@1.0.0-beta.35
|
|
10
|
+
|
|
11
|
+
## 1.0.0-beta.34
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- sd
|
|
16
|
+
- Updated dependencies
|
|
17
|
+
- @pipelab/plugin-core@1.0.0-beta.34
|
|
18
|
+
|
|
19
|
+
## 1.0.0-beta.33
|
|
20
|
+
|
|
21
|
+
### Patch Changes
|
|
22
|
+
|
|
23
|
+
- sd
|
|
24
|
+
- Updated dependencies
|
|
25
|
+
- @pipelab/plugin-core@1.0.0-beta.33
|
|
26
|
+
|
|
3
27
|
## 1.0.0-beta.32
|
|
4
28
|
|
|
5
29
|
### Patch Changes
|
package/dist/index.cjs
CHANGED
|
@@ -84,9 +84,18 @@ const runCLI = async (args, options = {}) => {
|
|
|
84
84
|
*/
|
|
85
85
|
const runAction = async (runner, options) => {
|
|
86
86
|
const outputs = {};
|
|
87
|
+
let realPnpm = "pnpm";
|
|
88
|
+
try {
|
|
89
|
+
const { execSync } = require("child_process");
|
|
90
|
+
const isWindows = process.platform === "win32";
|
|
91
|
+
const lines = execSync(isWindows ? "where pnpm" : "which pnpm", { encoding: "utf8" }).split(/\r?\n/).map((l) => l.trim()).filter(Boolean);
|
|
92
|
+
if (isWindows) realPnpm = lines.find((l) => l.endsWith(".cmd") || l.endsWith(".exe")) || lines[0] || "pnpm";
|
|
93
|
+
else realPnpm = lines[0] || "pnpm";
|
|
94
|
+
realPnpm = realPnpm.replace(/\\/g, "\\\\");
|
|
95
|
+
} catch (e) {}
|
|
87
96
|
const pnpmShimPath = (0, node_path.join)(options.sandboxPath, "pnpm-shim.cjs");
|
|
88
97
|
await (0, node_fs_promises.writeFile)(pnpmShimPath, `const { spawnSync } = require('child_process');
|
|
89
|
-
const result = spawnSync('
|
|
98
|
+
const result = spawnSync('${realPnpm}', process.argv.slice(2), { stdio: 'inherit', shell: true });
|
|
90
99
|
process.exit(result.status ?? 0);`);
|
|
91
100
|
const context = {
|
|
92
101
|
inputs: options.inputs,
|
package/dist/index.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;;;iBAmBgB,eAAA,CAAgB,QAAA;AAAA,cAWnB,SAAA;AAAA,cACA,KAAA;AAAA,cACA,OAAA;;AAFb;;;cAQa,aAAA,GAAuB,MAAA,aAAc,OAAA;;;;;;;;;;;;qCAyBxB,OAAA,WACJ,OAAA;IACL,SAAA;EAAA,MAA4B,OAAA;;;;;;cAyChC,MAAA,GACX,IAAA,YACA,OAAA;EACE,GAAA;EACA,GAAA,GAAM,MAAA;AAAA,MACF,OAAA,CADQ,KAAA,CACR,MAAA;;;;;;;;;cAkBK,SAAA,aAA6B,MAAA,EACxC,MAAA,EAAQ,YAAA,CAAa,CAAA,GACrB,OAAA;EACE,MAAA,EAAQ,gBAAA,CAAiB,CAAA;EACzB,WAAA;EACA,QAAA,GAAW,MAAA;AAAA,MAEZ,OAAA;EAAU,OAAA,EAAS,MAAA;AAAA;AA9BtB;;;AAAA,
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;;;iBAmBgB,eAAA,CAAgB,QAAA;AAAA,cAWnB,SAAA;AAAA,cACA,KAAA;AAAA,cACA,OAAA;;AAFb;;;cAQa,aAAA,GAAuB,MAAA,aAAc,OAAA;;;;;;;;;;;;qCAyBxB,OAAA,WACJ,OAAA;IACL,SAAA;EAAA,MAA4B,OAAA;;;;;;cAyChC,MAAA,GACX,IAAA,YACA,OAAA;EACE,GAAA;EACA,GAAA,GAAM,MAAA;AAAA,MACF,OAAA,CADQ,KAAA,CACR,MAAA;;;;;;;;;cAkBK,SAAA,aAA6B,MAAA,EACxC,MAAA,EAAQ,YAAA,CAAa,CAAA,GACrB,OAAA;EACE,MAAA,EAAQ,gBAAA,CAAiB,CAAA;EACzB,WAAA;EACA,QAAA,GAAW,MAAA;AAAA,MAEZ,OAAA;EAAU,OAAA,EAAS,MAAA;AAAA;AA9BtB;;;AAAA,cAqIa,cAAA,GAAwB,QAAA,UAAkB,OAAA;EAAW,SAAA;AAAA,MAAyB,OAAA,CAM1F,KAAA,CAN0F,MAAA"}
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;;;iBAmBgB,eAAA,CAAgB,QAAA;AAAA,cAWnB,SAAA;AAAA,cACA,KAAA;AAAA,cACA,OAAA;;AAFb;;;cAQa,aAAA,GAAuB,MAAA,aAAc,OAAA;;;;;;;;;;;;qCAyBxB,OAAA,WACJ,OAAA;IACL,SAAA;EAAA,MAA4B,OAAA;;;;;;cAyChC,MAAA,GACX,IAAA,YACA,OAAA;EACE,GAAA;EACA,GAAA,GAAM,MAAA;AAAA,MACF,OAAA,CADQ,OAAA,CACR,MAAA;;;;;;;;;cAkBK,SAAA,aAA6B,MAAA,EACxC,MAAA,EAAQ,YAAA,CAAa,CAAA,GACrB,OAAA;EACE,MAAA,EAAQ,gBAAA,CAAiB,CAAA;EACzB,WAAA;EACA,QAAA,GAAW,MAAA;AAAA,MAEZ,OAAA;EAAU,OAAA,EAAS,MAAA;AAAA;AA9BtB;;;AAAA,
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;;;iBAmBgB,eAAA,CAAgB,QAAA;AAAA,cAWnB,SAAA;AAAA,cACA,KAAA;AAAA,cACA,OAAA;;AAFb;;;cAQa,aAAA,GAAuB,MAAA,aAAc,OAAA;;;;;;;;;;;;qCAyBxB,OAAA,WACJ,OAAA;IACL,SAAA;EAAA,MAA4B,OAAA;;;;;;cAyChC,MAAA,GACX,IAAA,YACA,OAAA;EACE,GAAA;EACA,GAAA,GAAM,MAAA;AAAA,MACF,OAAA,CADQ,OAAA,CACR,MAAA;;;;;;;;;cAkBK,SAAA,aAA6B,MAAA,EACxC,MAAA,EAAQ,YAAA,CAAa,CAAA,GACrB,OAAA;EACE,MAAA,EAAQ,gBAAA,CAAiB,CAAA;EACzB,WAAA;EACA,QAAA,GAAW,MAAA;AAAA,MAEZ,OAAA;EAAU,OAAA,EAAS,MAAA;AAAA;AA9BtB;;;AAAA,cAqIa,cAAA,GAAwB,QAAA,UAAkB,OAAA;EAAW,SAAA;AAAA,MAAyB,OAAA,CAM1F,OAAA,CAN0F,MAAA"}
|
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
1
2
|
import { dirname, join, resolve } from "node:path";
|
|
2
3
|
import { fileURLToPath } from "node:url";
|
|
3
4
|
import { chmod, mkdir, rm, writeFile } from "node:fs/promises";
|
|
@@ -5,6 +6,9 @@ import { existsSync } from "node:fs";
|
|
|
5
6
|
import { tmpdir } from "node:os";
|
|
6
7
|
import { PipelabContext } from "@pipelab/plugin-core";
|
|
7
8
|
import { execa } from "execa";
|
|
9
|
+
//#region \0rolldown/runtime.js
|
|
10
|
+
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
11
|
+
//#endregion
|
|
8
12
|
//#region src/index.ts
|
|
9
13
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
10
14
|
/**
|
|
@@ -83,9 +87,18 @@ const runCLI = async (args, options = {}) => {
|
|
|
83
87
|
*/
|
|
84
88
|
const runAction = async (runner, options) => {
|
|
85
89
|
const outputs = {};
|
|
90
|
+
let realPnpm = "pnpm";
|
|
91
|
+
try {
|
|
92
|
+
const { execSync } = __require("child_process");
|
|
93
|
+
const isWindows = process.platform === "win32";
|
|
94
|
+
const lines = execSync(isWindows ? "where pnpm" : "which pnpm", { encoding: "utf8" }).split(/\r?\n/).map((l) => l.trim()).filter(Boolean);
|
|
95
|
+
if (isWindows) realPnpm = lines.find((l) => l.endsWith(".cmd") || l.endsWith(".exe")) || lines[0] || "pnpm";
|
|
96
|
+
else realPnpm = lines[0] || "pnpm";
|
|
97
|
+
realPnpm = realPnpm.replace(/\\/g, "\\\\");
|
|
98
|
+
} catch (e) {}
|
|
86
99
|
const pnpmShimPath = join(options.sandboxPath, "pnpm-shim.cjs");
|
|
87
100
|
await writeFile(pnpmShimPath, `const { spawnSync } = require('child_process');
|
|
88
|
-
const result = spawnSync('
|
|
101
|
+
const result = spawnSync('${realPnpm}', process.argv.slice(2), { stdio: 'inherit', shell: true });
|
|
89
102
|
process.exit(result.status ?? 0);`);
|
|
90
103
|
const context = {
|
|
91
104
|
inputs: options.inputs,
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["existsSyncSync"],"sources":["../src/index.ts"],"sourcesContent":["import { resolve, dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { mkdir, writeFile, chmod, rm } from \"node:fs/promises\";\nimport { existsSync as existsSyncSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport {\n type ActionRunner,\n type ActionRunnerData,\n type Action,\n PipelabContext,\n} from \"@pipelab/plugin-core\";\nimport { execa } from \"execa\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\n/**\n * Finds the monorepo root by looking for pnpm-workspace.yaml.\n */\nexport function findProjectRoot(startDir: string): string {\n let curr = startDir;\n while (curr !== dirname(curr)) {\n if (existsSyncSync(join(curr, \"pnpm-workspace.yaml\"))) {\n return curr;\n }\n curr = dirname(curr);\n }\n throw new Error(\"Could not find project root (pnpm-workspace.yaml)\");\n}\n\nexport const isWindows = process.platform === \"win32\";\nexport const isMac = process.platform === \"darwin\";\nexport const isLinux = process.platform === \"linux\";\n\n/**\n * Creates a unique sandbox directory and returns a bundle containing its path\n * and a pre-filled remove utility.\n */\nexport const createSandbox = async (prefix: string) => {\n const sandboxPath = join(tmpdir(), `${prefix}-${Math.random().toString(36).substring(7)}`);\n\n const paths = {\n input: join(sandboxPath, \"input\"),\n output: join(sandboxPath, \"output\"),\n userData: join(sandboxPath, \"user-data\"),\n project: join(sandboxPath, \"project\"),\n thirdparty: join(sandboxPath, \"thirdparty\"),\n };\n\n await mkdir(sandboxPath, { recursive: true });\n await Promise.all([\n mkdir(paths.input, { recursive: true }),\n mkdir(paths.output, { recursive: true }),\n mkdir(paths.userData, { recursive: true }),\n ]);\n\n return {\n path: sandboxPath,\n paths,\n /**\n * Creates a mock binary/script in the sandbox.\n */\n mockBinary: async (\n relativePath: string,\n content?: string,\n options: { extension?: string | false } = {},\n ) => {\n const fullPath = join(sandboxPath, relativePath);\n let platformPath = fullPath;\n\n if (options.extension === false) {\n // Use exactly the path provided\n } else if (options.extension) {\n platformPath = `${fullPath}.${options.extension}`;\n } else {\n const hasExtension = /\\.[a-z0-9]+$/i.test(relativePath);\n platformPath = hasExtension ? fullPath : isWindows ? `${fullPath}.cmd` : `${fullPath}.sh`;\n }\n\n const defaultContent = isWindows\n ? `@echo off\\necho Mock Binary Execution: %*\\nexit /b 0`\n : `#!/bin/bash\\necho \"Mock Binary Execution: $@\"\\nexit 0`;\n\n await mkdir(dirname(platformPath), { recursive: true });\n await writeFile(platformPath, content || defaultContent);\n\n if (!isWindows) {\n await chmod(platformPath, 0o755);\n }\n\n return platformPath;\n },\n remove: async () => {\n await rm(sandboxPath, {\n recursive: true,\n force: true,\n maxRetries: 20,\n retryDelay: 500,\n });\n },\n };\n};\n\n/**\n * Runs the Pipelab CLI out-of-process.\n */\nexport const runCLI = async (\n args: string[],\n options: {\n cwd?: string;\n env?: Record<string, string>;\n } = {},\n) => {\n const projectRoot = findProjectRoot(__dirname);\n const cliPath = resolve(projectRoot, \"apps/cli/src/index.ts\");\n\n return execa(\"tsx\", [cliPath, ...args], {\n cwd: options.cwd || projectRoot,\n env: {\n ...process.env,\n PIPELAB_DISABLE_HISTORY: \"true\",\n ...options.env,\n },\n });\n};\n\n/**\n * Runs a Pipelab action runner directly in-process for focused testing.\n */\nexport const runAction = async <A extends Action>(\n runner: ActionRunner<A>,\n options: {\n inputs: ActionRunnerData<A>[\"inputs\"];\n sandboxPath: string;\n extraEnv?: Record<string, string>;\n },\n): Promise<{ outputs: Record<string, unknown> }> => {\n const outputs: Record<string, unknown> = {};\n\n // Create a pnpm shim because ensureNPMPackage expects a JS file runnable by node\n const pnpmShimPath = join(options.sandboxPath, \"pnpm-shim.cjs\");\n await writeFile(\n pnpmShimPath,\n `const { spawnSync } = require('child_process');\nconst result = spawnSync('pnpm', process.argv.slice(2), { stdio: 'inherit', shell: true });\nprocess.exit(result.status ?? 0);`,\n );\n\n const context: ActionRunnerData<A> = {\n inputs: options.inputs,\n log: (...args: any[]) => {\n console.log(\"[Runner Log]\", ...args);\n },\n setOutput: (key: any, value: any) => {\n console.log(`[Runner Output] ${key} = ${value}`);\n outputs[key] = value;\n },\n cwd: options.sandboxPath,\n paths: {\n cache: join(options.sandboxPath, \"cache\"),\n pnpm: pnpmShimPath,\n node: process.execPath,\n userData: join(options.sandboxPath, \"user-data\"),\n modules: join(options.sandboxPath, \"modules\"),\n thirdparty: join(options.sandboxPath, \"thirdparty\"),\n },\n api: {\n fetchAsset: async (packageName: string) => {\n const sandboxAssetPath = join(options.sandboxPath, \"assets\", packageName);\n if (existsSyncSync(sandboxAssetPath)) {\n return sandboxAssetPath;\n }\n // Fallback to real monorepo assets\n // Normalize: remove @pipelab/ prefix if present\n const folderName = packageName.startsWith(\"@pipelab/\")\n ? packageName.replace(\"@pipelab/\", \"\")\n : packageName;\n\n const projectRoot = findProjectRoot(__dirname);\n return join(projectRoot, \"assets\", folderName);\n },\n },\n // @ts-ignore - Mocking BrowserWindow\n browserWindow: undefined,\n abortSignal: new AbortController().signal,\n context: new PipelabContext({\n userDataPath: join(options.sandboxPath, \"user-data\"),\n }),\n // @ts-ignore - Mocking setMeta\n setMeta: () => {},\n meta: {} as any,\n };\n\n // Set environment variables for the test if provided\n const originalEnv = { ...process.env };\n if (options.extraEnv) {\n Object.assign(process.env, options.extraEnv);\n }\n\n try {\n await runner(context);\n } finally {\n // Restore original environment\n if (options.extraEnv) {\n // Remove keys that were added\n for (const key in options.extraEnv) {\n if (!(key in originalEnv)) {\n delete process.env[key];\n }\n }\n // Restore original values\n Object.assign(process.env, originalEnv);\n }\n }\n\n return { outputs };\n};\n\n/**\n * Runs the packaged electron app (smoke test)\n */\nexport const runElectronApp = async (app_path: string, options: { timeoutMs?: number } = {}) => {\n const child = execa(app_path, [], {\n cleanup: true,\n timeout: options.timeoutMs || 120000,\n });\n return child;\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["existsSyncSync"],"sources":["../src/index.ts"],"sourcesContent":["import { resolve, dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { mkdir, writeFile, chmod, rm } from \"node:fs/promises\";\nimport { existsSync as existsSyncSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport {\n type ActionRunner,\n type ActionRunnerData,\n type Action,\n PipelabContext,\n} from \"@pipelab/plugin-core\";\nimport { execa } from \"execa\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\n/**\n * Finds the monorepo root by looking for pnpm-workspace.yaml.\n */\nexport function findProjectRoot(startDir: string): string {\n let curr = startDir;\n while (curr !== dirname(curr)) {\n if (existsSyncSync(join(curr, \"pnpm-workspace.yaml\"))) {\n return curr;\n }\n curr = dirname(curr);\n }\n throw new Error(\"Could not find project root (pnpm-workspace.yaml)\");\n}\n\nexport const isWindows = process.platform === \"win32\";\nexport const isMac = process.platform === \"darwin\";\nexport const isLinux = process.platform === \"linux\";\n\n/**\n * Creates a unique sandbox directory and returns a bundle containing its path\n * and a pre-filled remove utility.\n */\nexport const createSandbox = async (prefix: string) => {\n const sandboxPath = join(tmpdir(), `${prefix}-${Math.random().toString(36).substring(7)}`);\n\n const paths = {\n input: join(sandboxPath, \"input\"),\n output: join(sandboxPath, \"output\"),\n userData: join(sandboxPath, \"user-data\"),\n project: join(sandboxPath, \"project\"),\n thirdparty: join(sandboxPath, \"thirdparty\"),\n };\n\n await mkdir(sandboxPath, { recursive: true });\n await Promise.all([\n mkdir(paths.input, { recursive: true }),\n mkdir(paths.output, { recursive: true }),\n mkdir(paths.userData, { recursive: true }),\n ]);\n\n return {\n path: sandboxPath,\n paths,\n /**\n * Creates a mock binary/script in the sandbox.\n */\n mockBinary: async (\n relativePath: string,\n content?: string,\n options: { extension?: string | false } = {},\n ) => {\n const fullPath = join(sandboxPath, relativePath);\n let platformPath = fullPath;\n\n if (options.extension === false) {\n // Use exactly the path provided\n } else if (options.extension) {\n platformPath = `${fullPath}.${options.extension}`;\n } else {\n const hasExtension = /\\.[a-z0-9]+$/i.test(relativePath);\n platformPath = hasExtension ? fullPath : isWindows ? `${fullPath}.cmd` : `${fullPath}.sh`;\n }\n\n const defaultContent = isWindows\n ? `@echo off\\necho Mock Binary Execution: %*\\nexit /b 0`\n : `#!/bin/bash\\necho \"Mock Binary Execution: $@\"\\nexit 0`;\n\n await mkdir(dirname(platformPath), { recursive: true });\n await writeFile(platformPath, content || defaultContent);\n\n if (!isWindows) {\n await chmod(platformPath, 0o755);\n }\n\n return platformPath;\n },\n remove: async () => {\n await rm(sandboxPath, {\n recursive: true,\n force: true,\n maxRetries: 20,\n retryDelay: 500,\n });\n },\n };\n};\n\n/**\n * Runs the Pipelab CLI out-of-process.\n */\nexport const runCLI = async (\n args: string[],\n options: {\n cwd?: string;\n env?: Record<string, string>;\n } = {},\n) => {\n const projectRoot = findProjectRoot(__dirname);\n const cliPath = resolve(projectRoot, \"apps/cli/src/index.ts\");\n\n return execa(\"tsx\", [cliPath, ...args], {\n cwd: options.cwd || projectRoot,\n env: {\n ...process.env,\n PIPELAB_DISABLE_HISTORY: \"true\",\n ...options.env,\n },\n });\n};\n\n/**\n * Runs a Pipelab action runner directly in-process for focused testing.\n */\nexport const runAction = async <A extends Action>(\n runner: ActionRunner<A>,\n options: {\n inputs: ActionRunnerData<A>[\"inputs\"];\n sandboxPath: string;\n extraEnv?: Record<string, string>;\n },\n): Promise<{ outputs: Record<string, unknown> }> => {\n const outputs: Record<string, unknown> = {};\n\n let realPnpm = \"pnpm\";\n try {\n const { execSync } = require(\"child_process\");\n const isWindows = process.platform === \"win32\";\n const cmd = isWindows ? \"where pnpm\" : \"which pnpm\";\n const stdout = execSync(cmd, { encoding: \"utf8\" });\n const lines = stdout.split(/\\r?\\n/).map(l => l.trim()).filter(Boolean);\n if (isWindows) {\n realPnpm = lines.find(l => l.endsWith(\".cmd\") || l.endsWith(\".exe\")) || lines[0] || \"pnpm\";\n } else {\n realPnpm = lines[0] || \"pnpm\";\n }\n // Need to escape backslashes for JS string literal\n realPnpm = realPnpm.replace(/\\\\/g, \"\\\\\\\\\");\n } catch (e) {\n // fallback\n }\n\n // Create a pnpm shim because ensureNPMPackage expects a JS file runnable by node\n const pnpmShimPath = join(options.sandboxPath, \"pnpm-shim.cjs\");\n await writeFile(\n pnpmShimPath,\n `const { spawnSync } = require('child_process');\nconst result = spawnSync('${realPnpm}', process.argv.slice(2), { stdio: 'inherit', shell: true });\nprocess.exit(result.status ?? 0);`,\n );\n\n const context: ActionRunnerData<A> = {\n inputs: options.inputs,\n log: (...args: any[]) => {\n console.log(\"[Runner Log]\", ...args);\n },\n setOutput: (key: any, value: any) => {\n console.log(`[Runner Output] ${key} = ${value}`);\n outputs[key] = value;\n },\n cwd: options.sandboxPath,\n paths: {\n cache: join(options.sandboxPath, \"cache\"),\n pnpm: pnpmShimPath,\n node: process.execPath,\n userData: join(options.sandboxPath, \"user-data\"),\n modules: join(options.sandboxPath, \"modules\"),\n thirdparty: join(options.sandboxPath, \"thirdparty\"),\n },\n api: {\n fetchAsset: async (packageName: string) => {\n const sandboxAssetPath = join(options.sandboxPath, \"assets\", packageName);\n if (existsSyncSync(sandboxAssetPath)) {\n return sandboxAssetPath;\n }\n // Fallback to real monorepo assets\n // Normalize: remove @pipelab/ prefix if present\n const folderName = packageName.startsWith(\"@pipelab/\")\n ? packageName.replace(\"@pipelab/\", \"\")\n : packageName;\n\n const projectRoot = findProjectRoot(__dirname);\n return join(projectRoot, \"assets\", folderName);\n },\n },\n // @ts-ignore - Mocking BrowserWindow\n browserWindow: undefined,\n abortSignal: new AbortController().signal,\n context: new PipelabContext({\n userDataPath: join(options.sandboxPath, \"user-data\"),\n }),\n // @ts-ignore - Mocking setMeta\n setMeta: () => {},\n meta: {} as any,\n };\n\n // Set environment variables for the test if provided\n const originalEnv = { ...process.env };\n if (options.extraEnv) {\n Object.assign(process.env, options.extraEnv);\n }\n\n try {\n await runner(context);\n } finally {\n // Restore original environment\n if (options.extraEnv) {\n // Remove keys that were added\n for (const key in options.extraEnv) {\n if (!(key in originalEnv)) {\n delete process.env[key];\n }\n }\n // Restore original values\n Object.assign(process.env, originalEnv);\n }\n }\n\n return { outputs };\n};\n\n/**\n * Runs the packaged electron app (smoke test)\n */\nexport const runElectronApp = async (app_path: string, options: { timeoutMs?: number } = {}) => {\n const child = execa(app_path, [], {\n cleanup: true,\n timeout: options.timeoutMs || 120000,\n });\n return child;\n};\n"],"mappings":";;;;;;;;;;;;AAcA,MAAM,YAAY,QADC,cAAc,OAAO,KAAK,IAAI,CACZ;;;;AAKrC,SAAgB,gBAAgB,UAA0B;CACxD,IAAI,OAAO;AACX,QAAO,SAAS,QAAQ,KAAK,EAAE;AAC7B,MAAIA,WAAe,KAAK,MAAM,sBAAsB,CAAC,CACnD,QAAO;AAET,SAAO,QAAQ,KAAK;;AAEtB,OAAM,IAAI,MAAM,oDAAoD;;AAGtE,MAAa,YAAY,QAAQ,aAAa;AAC9C,MAAa,QAAQ,QAAQ,aAAa;AAC1C,MAAa,UAAU,QAAQ,aAAa;;;;;AAM5C,MAAa,gBAAgB,OAAO,WAAmB;CACrD,MAAM,cAAc,KAAK,QAAQ,EAAE,GAAG,OAAO,GAAG,KAAK,QAAQ,CAAC,SAAS,GAAG,CAAC,UAAU,EAAE,GAAG;CAE1F,MAAM,QAAQ;EACZ,OAAO,KAAK,aAAa,QAAQ;EACjC,QAAQ,KAAK,aAAa,SAAS;EACnC,UAAU,KAAK,aAAa,YAAY;EACxC,SAAS,KAAK,aAAa,UAAU;EACrC,YAAY,KAAK,aAAa,aAAa;EAC5C;AAED,OAAM,MAAM,aAAa,EAAE,WAAW,MAAM,CAAC;AAC7C,OAAM,QAAQ,IAAI;EAChB,MAAM,MAAM,OAAO,EAAE,WAAW,MAAM,CAAC;EACvC,MAAM,MAAM,QAAQ,EAAE,WAAW,MAAM,CAAC;EACxC,MAAM,MAAM,UAAU,EAAE,WAAW,MAAM,CAAC;EAC3C,CAAC;AAEF,QAAO;EACL,MAAM;EACN;EAIA,YAAY,OACV,cACA,SACA,UAA0C,EAAE,KACzC;GACH,MAAM,WAAW,KAAK,aAAa,aAAa;GAChD,IAAI,eAAe;AAEnB,OAAI,QAAQ,cAAc,OAAO,YAEtB,QAAQ,UACjB,gBAAe,GAAG,SAAS,GAAG,QAAQ;OAGtC,gBADqB,gBAAgB,KAAK,aAAa,GACzB,WAAW,YAAY,GAAG,SAAS,QAAQ,GAAG,SAAS;GAGvF,MAAM,iBAAiB,YACnB,yDACA;AAEJ,SAAM,MAAM,QAAQ,aAAa,EAAE,EAAE,WAAW,MAAM,CAAC;AACvD,SAAM,UAAU,cAAc,WAAW,eAAe;AAExD,OAAI,CAAC,UACH,OAAM,MAAM,cAAc,IAAM;AAGlC,UAAO;;EAET,QAAQ,YAAY;AAClB,SAAM,GAAG,aAAa;IACpB,WAAW;IACX,OAAO;IACP,YAAY;IACZ,YAAY;IACb,CAAC;;EAEL;;;;;AAMH,MAAa,SAAS,OACpB,MACA,UAGI,EAAE,KACH;CACH,MAAM,cAAc,gBAAgB,UAAU;AAG9C,QAAO,MAAM,OAAO,CAFJ,QAAQ,aAAa,wBAAwB,EAE/B,GAAG,KAAK,EAAE;EACtC,KAAK,QAAQ,OAAO;EACpB,KAAK;GACH,GAAG,QAAQ;GACX,yBAAyB;GACzB,GAAG,QAAQ;GACZ;EACF,CAAC;;;;;AAMJ,MAAa,YAAY,OACvB,QACA,YAKkD;CAClD,MAAM,UAAmC,EAAE;CAE3C,IAAI,WAAW;AACf,KAAI;EACF,MAAM,EAAE,aAAA,UAAqB,gBAAgB;EAC7C,MAAM,YAAY,QAAQ,aAAa;EAGvC,MAAM,QADS,SADH,YAAY,eAAe,cACV,EAAE,UAAU,QAAQ,CAAC,CAC7B,MAAM,QAAQ,CAAC,KAAI,MAAK,EAAE,MAAM,CAAC,CAAC,OAAO,QAAQ;AACtE,MAAI,UACF,YAAW,MAAM,MAAK,MAAK,EAAE,SAAS,OAAO,IAAI,EAAE,SAAS,OAAO,CAAC,IAAI,MAAM,MAAM;MAEpF,YAAW,MAAM,MAAM;AAGzB,aAAW,SAAS,QAAQ,OAAO,OAAO;UACnC,GAAG;CAKZ,MAAM,eAAe,KAAK,QAAQ,aAAa,gBAAgB;AAC/D,OAAM,UACJ,cACA;4BACwB,SAAS;mCAElC;CAED,MAAM,UAA+B;EACnC,QAAQ,QAAQ;EAChB,MAAM,GAAG,SAAgB;AACvB,WAAQ,IAAI,gBAAgB,GAAG,KAAK;;EAEtC,YAAY,KAAU,UAAe;AACnC,WAAQ,IAAI,mBAAmB,IAAI,KAAK,QAAQ;AAChD,WAAQ,OAAO;;EAEjB,KAAK,QAAQ;EACb,OAAO;GACL,OAAO,KAAK,QAAQ,aAAa,QAAQ;GACzC,MAAM;GACN,MAAM,QAAQ;GACd,UAAU,KAAK,QAAQ,aAAa,YAAY;GAChD,SAAS,KAAK,QAAQ,aAAa,UAAU;GAC7C,YAAY,KAAK,QAAQ,aAAa,aAAa;GACpD;EACD,KAAK,EACH,YAAY,OAAO,gBAAwB;GACzC,MAAM,mBAAmB,KAAK,QAAQ,aAAa,UAAU,YAAY;AACzE,OAAIA,WAAe,iBAAiB,CAClC,QAAO;GAIT,MAAM,aAAa,YAAY,WAAW,YAAY,GAClD,YAAY,QAAQ,aAAa,GAAG,GACpC;AAGJ,UAAO,KADa,gBAAgB,UAAU,EACrB,UAAU,WAAW;KAEjD;EAED,eAAe,KAAA;EACf,aAAa,IAAI,iBAAiB,CAAC;EACnC,SAAS,IAAI,eAAe,EAC1B,cAAc,KAAK,QAAQ,aAAa,YAAY,EACrD,CAAC;EAEF,eAAe;EACf,MAAM,EAAE;EACT;CAGD,MAAM,cAAc,EAAE,GAAG,QAAQ,KAAK;AACtC,KAAI,QAAQ,SACV,QAAO,OAAO,QAAQ,KAAK,QAAQ,SAAS;AAG9C,KAAI;AACF,QAAM,OAAO,QAAQ;WACb;AAER,MAAI,QAAQ,UAAU;AAEpB,QAAK,MAAM,OAAO,QAAQ,SACxB,KAAI,EAAE,OAAO,aACX,QAAO,QAAQ,IAAI;AAIvB,UAAO,OAAO,QAAQ,KAAK,YAAY;;;AAI3C,QAAO,EAAE,SAAS;;;;;AAMpB,MAAa,iBAAiB,OAAO,UAAkB,UAAkC,EAAE,KAAK;AAK9F,QAJc,MAAM,UAAU,EAAE,EAAE;EAChC,SAAS;EACT,SAAS,QAAQ,aAAa;EAC/B,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pipelab/test-utils",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.35",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Testing utilities for Pipelab plugins and monorepo",
|
|
6
6
|
"license": "FSL-1.1-MIT",
|
|
@@ -27,13 +27,13 @@
|
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"execa": "9.5.1",
|
|
30
|
-
"@pipelab/plugin-core": "1.0.0-beta.
|
|
30
|
+
"@pipelab/plugin-core": "1.0.0-beta.35"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@types/node": "24.12.2",
|
|
34
34
|
"tsdown": "0.21.2",
|
|
35
35
|
"typescript": "^5.0.0",
|
|
36
|
-
"@pipelab/tsconfig": "1.0.0-beta.
|
|
36
|
+
"@pipelab/tsconfig": "1.0.0-beta.28"
|
|
37
37
|
},
|
|
38
38
|
"scripts": {
|
|
39
39
|
"build": "tsdown",
|
package/src/index.ts
CHANGED
|
@@ -137,12 +137,30 @@ export const runAction = async <A extends Action>(
|
|
|
137
137
|
): Promise<{ outputs: Record<string, unknown> }> => {
|
|
138
138
|
const outputs: Record<string, unknown> = {};
|
|
139
139
|
|
|
140
|
+
let realPnpm = "pnpm";
|
|
141
|
+
try {
|
|
142
|
+
const { execSync } = require("child_process");
|
|
143
|
+
const isWindows = process.platform === "win32";
|
|
144
|
+
const cmd = isWindows ? "where pnpm" : "which pnpm";
|
|
145
|
+
const stdout = execSync(cmd, { encoding: "utf8" });
|
|
146
|
+
const lines = stdout.split(/\r?\n/).map(l => l.trim()).filter(Boolean);
|
|
147
|
+
if (isWindows) {
|
|
148
|
+
realPnpm = lines.find(l => l.endsWith(".cmd") || l.endsWith(".exe")) || lines[0] || "pnpm";
|
|
149
|
+
} else {
|
|
150
|
+
realPnpm = lines[0] || "pnpm";
|
|
151
|
+
}
|
|
152
|
+
// Need to escape backslashes for JS string literal
|
|
153
|
+
realPnpm = realPnpm.replace(/\\/g, "\\\\");
|
|
154
|
+
} catch (e) {
|
|
155
|
+
// fallback
|
|
156
|
+
}
|
|
157
|
+
|
|
140
158
|
// Create a pnpm shim because ensureNPMPackage expects a JS file runnable by node
|
|
141
159
|
const pnpmShimPath = join(options.sandboxPath, "pnpm-shim.cjs");
|
|
142
160
|
await writeFile(
|
|
143
161
|
pnpmShimPath,
|
|
144
162
|
`const { spawnSync } = require('child_process');
|
|
145
|
-
const result = spawnSync('
|
|
163
|
+
const result = spawnSync('${realPnpm}', process.argv.slice(2), { stdio: 'inherit', shell: true });
|
|
146
164
|
process.exit(result.status ?? 0);`,
|
|
147
165
|
);
|
|
148
166
|
|