Procházet zdrojové kódy

Merge pull request #167 from Tahshsa/fix/windows-tests-and-publish-manifests

Fix Windows test failures and restore workspace: protocol in manifests
Junxian Ma před 7 měsíci
rodič
revize
7169701632

+ 3 - 1
.github/workflows/ci.yml

@@ -8,9 +8,11 @@ on:
 
 jobs:
   build-and-test:
-    runs-on: ubuntu-latest
+    runs-on: ${{ matrix.os }}
     strategy:
+      fail-fast: false
       matrix:
+        os: [ubuntu-latest, windows-latest]
         node-version: [20, 22]
 
     steps:

+ 4 - 2
packages/cli/src/__tests__/daemon.test.ts

@@ -1,4 +1,5 @@
 import { beforeEach, describe, expect, it, vi } from "vitest";
+import { join } from "node:path";
 
 const readFileMock = vi.fn();
 const writeFileMock = vi.fn();
@@ -83,8 +84,9 @@ describe("daemon command", () => {
       upCommand.parseAsync(["node", "up", "--quiet"]),
     ).rejects.toMatchObject({ code: 1 });
 
-    expect(writeFileMock).toHaveBeenCalledWith("/project/inkos.pid", expect.any(String), "utf-8");
-    expect(unlinkMock).toHaveBeenCalledWith("/project/inkos.pid");
+    const pidPath = join("/project", "inkos.pid");
+    expect(writeFileMock).toHaveBeenCalledWith(pidPath, expect.any(String), "utf-8");
+    expect(unlinkMock).toHaveBeenCalledWith(pidPath);
 
     exitSpy.mockRestore();
   });

+ 3 - 1
packages/cli/src/__tests__/publish-package.test.ts

@@ -17,10 +17,12 @@ const sourceStudioPackageJsonPromise = readFile(resolve(studioDir, "package.json
 );
 
 async function packPackage(packageDir: string, packDir: string) {
-  execFileSync("npm", ["pack", "--pack-destination", packDir], {
+  const npmCmd = process.platform === "win32" ? "npm.cmd" : "npm";
+  execFileSync(npmCmd, ["pack", "--pack-destination", packDir], {
     cwd: packageDir,
     env: process.env,
     encoding: "utf-8",
+    shell: process.platform === "win32",
   });
 
   const tgzFiles = (await readdir(packDir)).filter((name) => name.endsWith(".tgz"));

+ 35 - 21
packages/cli/src/__tests__/studio-runtime.test.ts

@@ -1,5 +1,5 @@
 import { beforeEach, describe, expect, it, vi } from "vitest";
-import { dirname, resolve } from "node:path";
+import { dirname, join, resolve } from "node:path";
 import { fileURLToPath } from "node:url";
 
 const accessMock = vi.fn();
@@ -16,12 +16,31 @@ describe("studio runtime resolution", () => {
     vi.resetModules();
   });
 
+  const tsSourceEntry = join("/repo", "packages", "studio", "src", "api", "index.ts");
+  const tsxLoader = join("/repo", "packages", "studio", "node_modules", "tsx", "dist", "loader.mjs");
+  const projectBuiltEntry = join(
+    "/repo",
+    "test-project",
+    "node_modules",
+    "@actalk",
+    "inkos-studio",
+    "dist",
+    "api",
+    "index.js",
+  );
+  const cliBuiltEntry = join(
+    cliPackageRoot,
+    "node_modules",
+    "@actalk",
+    "inkos-studio",
+    "dist",
+    "api",
+    "index.js",
+  );
+
   it("prefers the repository-local tsx loader for monorepo sources", async () => {
     accessMock.mockImplementation(async (path: string) => {
-      if (
-        path === "/repo/packages/studio/src/api/index.ts" ||
-        path === "/repo/packages/studio/node_modules/tsx/dist/loader.mjs"
-      ) {
+      if (path === tsSourceEntry || path === tsxLoader) {
         return;
       }
       throw new Error(`missing: ${path}`);
@@ -31,20 +50,15 @@ describe("studio runtime resolution", () => {
     const launch = await resolveStudioLaunch("/repo/test-project");
 
     expect(launch).toEqual({
-      studioEntry: "/repo/packages/studio/src/api/index.ts",
+      studioEntry: tsSourceEntry,
       command: "node",
-      args: [
-        "--import",
-        "/repo/packages/studio/node_modules/tsx/dist/loader.mjs",
-        "/repo/packages/studio/src/api/index.ts",
-        "/repo/test-project",
-      ],
+      args: ["--import", tsxLoader, tsSourceEntry, "/repo/test-project"],
     });
   });
 
   it("finds monorepo packages/studio sources from a project directory", async () => {
     accessMock.mockImplementation(async (path: string) => {
-      if (path === "/repo/packages/studio/src/api/index.ts") {
+      if (path === tsSourceEntry) {
         return;
       }
       throw new Error(`missing: ${path}`);
@@ -54,15 +68,15 @@ describe("studio runtime resolution", () => {
     const launch = await resolveStudioLaunch("/repo/test-project");
 
     expect(launch).toEqual({
-      studioEntry: "/repo/packages/studio/src/api/index.ts",
+      studioEntry: tsSourceEntry,
       command: "npx",
-      args: ["tsx", "/repo/packages/studio/src/api/index.ts", "/repo/test-project"],
+      args: ["tsx", tsSourceEntry, "/repo/test-project"],
     });
   });
 
   it("uses node for built JavaScript entries", async () => {
     accessMock.mockImplementation(async (path: string) => {
-      if (path === "/repo/test-project/node_modules/@actalk/inkos-studio/dist/api/index.js") {
+      if (path === projectBuiltEntry) {
         return;
       }
       throw new Error(`missing: ${path}`);
@@ -72,15 +86,15 @@ describe("studio runtime resolution", () => {
     const launch = await resolveStudioLaunch("/repo/test-project");
 
     expect(launch).toEqual({
-      studioEntry: "/repo/test-project/node_modules/@actalk/inkos-studio/dist/api/index.js",
+      studioEntry: projectBuiltEntry,
       command: "node",
-      args: ["/repo/test-project/node_modules/@actalk/inkos-studio/dist/api/index.js", "/repo/test-project"],
+      args: [projectBuiltEntry, "/repo/test-project"],
     });
   });
 
   it("falls back to the CLI installation's bundled studio runtime", async () => {
     accessMock.mockImplementation(async (path: string) => {
-      if (path === `${cliPackageRoot}/node_modules/@actalk/inkos-studio/dist/api/index.js`) {
+      if (path === cliBuiltEntry) {
         return;
       }
       throw new Error(`missing: ${path}`);
@@ -90,9 +104,9 @@ describe("studio runtime resolution", () => {
     const launch = await resolveStudioLaunch("/repo/test-project");
 
     expect(launch).toEqual({
-      studioEntry: `${cliPackageRoot}/node_modules/@actalk/inkos-studio/dist/api/index.js`,
+      studioEntry: cliBuiltEntry,
       command: "node",
-      args: [`${cliPackageRoot}/node_modules/@actalk/inkos-studio/dist/api/index.js`, "/repo/test-project"],
+      args: [cliBuiltEntry, "/repo/test-project"],
     });
   });
 

+ 15 - 4
packages/cli/src/__tests__/studio.test.ts

@@ -1,4 +1,5 @@
 import { beforeEach, describe, expect, it, vi } from "vitest";
+import { join } from "node:path";
 
 const accessMock = vi.fn();
 const spawnMock = vi.fn(() => ({
@@ -28,8 +29,9 @@ describe("studio command", () => {
   });
 
   it("launches TypeScript sources through tsx in monorepo mode", async () => {
+    const tsEntry = join("/project", "packages", "studio", "src", "api", "index.ts");
     accessMock.mockImplementation(async (path: string) => {
-      if (path === "/project/packages/studio/src/api/index.ts") {
+      if (path === tsEntry) {
         return;
       }
       throw new Error(`missing: ${path}`);
@@ -40,7 +42,7 @@ describe("studio command", () => {
 
     expect(spawnMock).toHaveBeenCalledWith(
       "npx",
-      ["tsx", "/project/packages/studio/src/api/index.ts", "/project"],
+      ["tsx", tsEntry, "/project"],
       expect.objectContaining({
         cwd: "/project",
         stdio: "inherit",
@@ -50,8 +52,17 @@ describe("studio command", () => {
   });
 
   it("launches built JavaScript entries through node", async () => {
+    const jsEntry = join(
+      "/project",
+      "node_modules",
+      "@actalk",
+      "inkos-studio",
+      "dist",
+      "api",
+      "index.js",
+    );
     accessMock.mockImplementation(async (path: string) => {
-      if (path === "/project/node_modules/@actalk/inkos-studio/dist/api/index.js") {
+      if (path === jsEntry) {
         return;
       }
       throw new Error(`missing: ${path}`);
@@ -62,7 +73,7 @@ describe("studio command", () => {
 
     expect(spawnMock).toHaveBeenCalledWith(
       "node",
-      ["/project/node_modules/@actalk/inkos-studio/dist/api/index.js", "/project"],
+      [jsEntry, "/project"],
       expect.objectContaining({
         cwd: "/project",
         stdio: "inherit",