From 2762ba05af168c840371bead7c907fa991fa4dc6 Mon Sep 17 00:00:00 2001 From: lihbr Date: Tue, 12 May 2026 16:57:28 +0900 Subject: [PATCH 01/12] ci: run on windows --- .github/workflows/publish.yml | 4 ++-- .github/workflows/validate.yml | 27 +++++++++++++++++++++++---- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index d1a381a..1777582 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -9,7 +9,7 @@ on: jobs: release: if: github.event_name == 'push' && github.repository_owner == 'prismicio' - runs-on: ubuntu-latest + runs-on: blacksmith-2vcpu-ubuntu-2404-arm permissions: contents: write issues: write @@ -41,7 +41,7 @@ jobs: prerelease: if: "!cancelled() && github.repository_owner == 'prismicio'" needs: [release] - runs-on: ubuntu-latest + runs-on: blacksmith-2vcpu-ubuntu-2404-arm permissions: contents: read id-token: write diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index dea4c33..0ec362a 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -4,7 +4,7 @@ on: push jobs: lint: - runs-on: ubuntu-latest + runs-on: blacksmith-2vcpu-ubuntu-2404-arm steps: - uses: actions/checkout@v6 - uses: actions/setup-node@v6 @@ -15,7 +15,7 @@ jobs: - run: npm run lint build: - runs-on: ubuntu-latest + runs-on: blacksmith-2vcpu-ubuntu-2404-arm env: MODE: production steps: @@ -29,7 +29,26 @@ jobs: test: name: test (Node.js ${{ matrix.node }}) - runs-on: ubuntu-latest + runs-on: blacksmith-2vcpu-ubuntu-2404 + strategy: + matrix: + node: [20, 22, 24] + fail-fast: false + steps: + - uses: actions/checkout@v6 + - uses: actions/setup-node@v6 + with: + node-version: ${{ matrix.node }} + cache: npm + - run: npm ci + - run: npm run unit + env: + E2E_PRISMIC_EMAIL: ${{ secrets.E2E_PRISMIC_EMAIL }} + E2E_PRISMIC_PASSWORD: ${{ secrets.E2E_PRISMIC_PASSWORD }} + + test-win32: + name: test (Node.js ${{ matrix.node }}) + runs-on: blacksmith-2vcpu-windows-2025 strategy: matrix: node: [20, 22, 24] @@ -48,7 +67,7 @@ jobs: types: name: "types (TypeScript ${{ matrix.typescript }})" - runs-on: ubuntu-latest + runs-on: blacksmith-2vcpu-ubuntu-2404-arm strategy: matrix: typescript: ["5.4", "5.6", "5.7", "5.8", "5.9"] From 03d0681eee627eb8d7515ae7312c2d7d047db152 Mon Sep 17 00:00:00 2001 From: lihbr Date: Tue, 12 May 2026 17:08:23 +0900 Subject: [PATCH 02/12] ci: run on windows --- .github/workflows/validate.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 0ec362a..77fad0d 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -29,7 +29,7 @@ jobs: test: name: test (Node.js ${{ matrix.node }}) - runs-on: blacksmith-2vcpu-ubuntu-2404 + runs-on: blacksmith-4vcpu-ubuntu-2404 strategy: matrix: node: [20, 22, 24] @@ -47,8 +47,8 @@ jobs: E2E_PRISMIC_PASSWORD: ${{ secrets.E2E_PRISMIC_PASSWORD }} test-win32: - name: test (Node.js ${{ matrix.node }}) - runs-on: blacksmith-2vcpu-windows-2025 + name: test windows (Node.js ${{ matrix.node }}) + runs-on: blacksmith-4vcpu-windows-2025 strategy: matrix: node: [20, 22, 24] From 8286af4bf78d6e57e10e42e65e2c0680527162d9 Mon Sep 17 00:00:00 2001 From: lihbr Date: Tue, 12 May 2026 17:53:15 +0900 Subject: [PATCH 03/12] fix(win32): glob patterns --- src/adapters/index.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/adapters/index.ts b/src/adapters/index.ts index b4d2f15..d2c2aea 100644 --- a/src/adapters/index.ts +++ b/src/adapters/index.ts @@ -2,7 +2,7 @@ import type { CustomType, SharedSlice } from "@prismicio/types-internal/lib/cust import { pascalCase } from "change-case"; import { rm } from "node:fs/promises"; -import { fileURLToPath, pathToFileURL } from "node:url"; +import { pathToFileURL } from "node:url"; import { generateTypes } from "prismic-ts-codegen"; import { glob } from "tinyglobby"; @@ -79,9 +79,8 @@ export abstract class Adapter { const libraries = await this.getSliceLibraries(); for (const library of libraries) { - const modelGlob = new URL("*/model.json", library); const sliceModelPaths = Array.from( - await glob(fileURLToPath(modelGlob), { absolute: true }), + await glob("*/model.json", { absolute: true, cwd: library }), (path) => pathToFileURL(path), ); const slices = await Promise.all( @@ -139,9 +138,8 @@ export abstract class Adapter { const libraries = await this.getCustomTypeLibraries(); for (const library of libraries) { - const modelGlob = new URL("*/index.json", library); const customTypeModelPaths = Array.from( - await glob(fileURLToPath(modelGlob), { absolute: true }), + await glob("*/index.json", { absolute: true, cwd: library }), (path) => pathToFileURL(path), ); const customTypes = await Promise.all( From ee3957055ed1388663069e7e3bdcd0721b08beaa Mon Sep 17 00:00:00 2001 From: lihbr Date: Tue, 12 May 2026 17:54:24 +0900 Subject: [PATCH 04/12] test(win32): ignore tmp directory deletion failures --- test/it.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/it.ts b/test/it.ts index aef546a..c07c0f7 100644 --- a/test/it.ts +++ b/test/it.ts @@ -35,7 +35,11 @@ export const it = test.extend({ home: async ({}, use) => { const dir = await mkdtemp(join(tmpdir(), "prismic-test-")); await use(pathToFileURL(dir + "/")); - await rm(dir, { recursive: true, force: true }); + try { + await rm(dir, { recursive: true, force: true }); + } catch { + // noop + } }, project: async ({ home, repo }, use) => { const projectPath = new URL("project/", home); From dfcda573e1371e81050a3d25cbe809e0867932a7 Mon Sep 17 00:00:00 2001 From: lihbr Date: Tue, 12 May 2026 18:06:56 +0900 Subject: [PATCH 05/12] test(win32): increase timeout --- test/gen-setup.test.ts | 4 ++-- test/init.test.ts | 2 +- test/pull.test.ts | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/test/gen-setup.test.ts b/test/gen-setup.test.ts index b47b3a6..1fb6451 100644 --- a/test/gen-setup.test.ts +++ b/test/gen-setup.test.ts @@ -8,7 +8,7 @@ it("supports --help", async ({ expect, prismic }) => { expect(stdout).toContain("prismic gen setup [options]"); }); -it("generates setup files", async ({ expect, project, prismic }) => { +it("generates setup files", { timeout: 30_000 }, async ({ expect, project, prismic }) => { const { exitCode, stdout } = await prismic("gen", ["setup"]); expect(exitCode).toBe(0); expect(stdout).toContain("Generated setup files"); @@ -25,7 +25,7 @@ it("generates setup files", async ({ expect, project, prismic }) => { await expect(project).toHaveFile("package-lock.json"); }); -it("skips existing files", async ({ expect, project, prismic }) => { +it("skips existing files", { timeout: 30_000 }, async ({ expect, project, prismic }) => { const customContent = "// custom client file\n"; await writeFile(new URL("prismicio.js", project), customContent); diff --git a/test/init.test.ts b/test/init.test.ts index 1060916..85fb963 100644 --- a/test/init.test.ts +++ b/test/init.test.ts @@ -121,7 +121,7 @@ it("fails when Type Builder is not enabled", async ({ expect, project, prismic, expect(stderr).toContain("Type Builder"); }); -it("installs dependencies", async ({ expect, project, prismic, repo }) => { +it("installs dependencies", { timeout: 30_000 }, async ({ expect, project, prismic, repo }) => { await rm(new URL("prismic.config.json", project)); const { exitCode } = await prismic("init", ["--repo", repo]); diff --git a/test/pull.test.ts b/test/pull.test.ts index afc5276..c3eb567 100644 --- a/test/pull.test.ts +++ b/test/pull.test.ts @@ -1,4 +1,5 @@ import { writeFile, mkdir } from "node:fs/promises"; +import { sep } from "node:path"; import { fileURLToPath } from "node:url"; import { x } from "tinyexec"; @@ -252,7 +253,7 @@ it.sequential("blocks pull when local model files have uncommitted changes", asy const second = await prismic("pull", ["--repo", repo]); expect(second.exitCode).toBe(1); expect(second.stderr).toContain("uncommitted"); - expect(second.stderr).toContain(`customtypes/${customType.id}/index.json`); + expect(second.stderr).toContain(`customtypes/${customType.id}/index.json`.replaceAll("/", sep)); }); it.sequential("refuses to delete local models without --force when not tracked by git", async ({ From ab0608982c05bbfdbb79a8fd3a5c69acb3d766ba Mon Sep 17 00:00:00 2001 From: lihbr Date: Tue, 12 May 2026 18:19:23 +0900 Subject: [PATCH 06/12] test(win32): retry temp directory deletion after delay --- test/it.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/it.ts b/test/it.ts index c07c0f7..3860d84 100644 --- a/test/it.ts +++ b/test/it.ts @@ -38,7 +38,9 @@ export const it = test.extend({ try { await rm(dir, { recursive: true, force: true }); } catch { - // noop + // Retry once with delay + await new Promise((res) => setTimeout(res, 1000)); + await rm(dir, { recursive: true, force: true }); } }, project: async ({ home, repo }, use) => { From 6d736880e7569a9c67c1d81ed4dff915b41d1ad0 Mon Sep 17 00:00:00 2001 From: lihbr Date: Tue, 12 May 2026 18:41:37 +0900 Subject: [PATCH 07/12] wip: debug win ci --- .github/workflows/validate.yml | 2 +- src/commands/pull.ts | 3 +++ src/lib/git.ts | 1 + test/pull.test.ts | 1 + 4 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 77fad0d..a4b3ce3 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -60,7 +60,7 @@ jobs: node-version: ${{ matrix.node }} cache: npm - run: npm ci - - run: npm run unit + - run: npm run unit pull.test.ts env: E2E_PRISMIC_EMAIL: ${{ secrets.E2E_PRISMIC_EMAIL }} E2E_PRISMIC_PASSWORD: ${{ secrets.E2E_PRISMIC_PASSWORD }} diff --git a/src/commands/pull.ts b/src/commands/pull.ts index 866609b..6713ee5 100644 --- a/src/commands/pull.ts +++ b/src/commands/pull.ts @@ -43,8 +43,11 @@ export default createCommand(config, async ({ values }) => { adapter.getSliceLibraries(), ]); + console.log({ gitRoot }) + if (!force && gitRoot) { const dirtyPaths = await getDirtyPaths(gitRoot); + console.log({ dirtyPaths }) const dirtyFiles = dirtyPaths .filter( (path) => diff --git a/src/lib/git.ts b/src/lib/git.ts index 804f7bb..fc46a05 100644 --- a/src/lib/git.ts +++ b/src/lib/git.ts @@ -22,6 +22,7 @@ export async function getDirtyPaths(gitRoot: URL): Promise { nodeOptions: { cwd: fileURLToPath(gitRoot) }, throwOnError: true, }); + console.log({ stdout }) const paths: URL[] = []; for (const line of stdout.split("\n")) { if (line.length < 4) continue; diff --git a/test/pull.test.ts b/test/pull.test.ts index c3eb567..91729bc 100644 --- a/test/pull.test.ts +++ b/test/pull.test.ts @@ -251,6 +251,7 @@ it.sequential("blocks pull when local model files have uncommitted changes", asy await writeFile(modelPath, JSON.stringify({ ...customType, label: "Edited locally" }, null, 2)); const second = await prismic("pull", ["--repo", repo]); + console.log(second) expect(second.exitCode).toBe(1); expect(second.stderr).toContain("uncommitted"); expect(second.stderr).toContain(`customtypes/${customType.id}/index.json`.replaceAll("/", sep)); From ecf1f137334a10fddd7550569d3edd5ebd59772e Mon Sep 17 00:00:00 2001 From: lihbr Date: Tue, 12 May 2026 18:47:56 +0900 Subject: [PATCH 08/12] wip: debug win ci --- src/commands/pull.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/commands/pull.ts b/src/commands/pull.ts index 6713ee5..e862b6f 100644 --- a/src/commands/pull.ts +++ b/src/commands/pull.ts @@ -57,6 +57,7 @@ export default createCommand(config, async ({ values }) => { customTypeLibraries.some((lib) => isDescendant(lib, path))), ) .map((path) => relativePathname(projectRoot, path)); + console.log({ dirtyFiles }) if (dirtyFiles.length > 0) { throw new CommandError(` From 064783c0b06de3c42b17a056062a71a933f603e6 Mon Sep 17 00:00:00 2001 From: lihbr Date: Tue, 12 May 2026 18:49:41 +0900 Subject: [PATCH 09/12] wip: debug win ci --- src/commands/pull.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/commands/pull.ts b/src/commands/pull.ts index e862b6f..43e42a4 100644 --- a/src/commands/pull.ts +++ b/src/commands/pull.ts @@ -57,7 +57,18 @@ export default createCommand(config, async ({ values }) => { customTypeLibraries.some((lib) => isDescendant(lib, path))), ) .map((path) => relativePathname(projectRoot, path)); - console.log({ dirtyFiles }) + console.log({ projectRoot, customTypeLibraries, sliceLibraries }); + console.log( + dirtyPaths.map((path) => ({ + path, + isIndex: path.pathname.endsWith("/index.json"), + customTypeMatches: customTypeLibraries.map((lib) => ({ + lib, + matches: isDescendant(lib, path), + })), + })), + ); + console.log({ dirtyFiles }); if (dirtyFiles.length > 0) { throw new CommandError(` From 2c734809b150837167ca3c154ce60ebda33eff4e Mon Sep 17 00:00:00 2001 From: lihbr Date: Tue, 12 May 2026 19:02:15 +0900 Subject: [PATCH 10/12] wip: debug win ci --- src/commands/pull.ts | 15 --------------- src/lib/git.ts | 4 ++-- src/project.ts | 5 +++-- test/pull.test.ts | 1 - 4 files changed, 5 insertions(+), 20 deletions(-) diff --git a/src/commands/pull.ts b/src/commands/pull.ts index 43e42a4..866609b 100644 --- a/src/commands/pull.ts +++ b/src/commands/pull.ts @@ -43,11 +43,8 @@ export default createCommand(config, async ({ values }) => { adapter.getSliceLibraries(), ]); - console.log({ gitRoot }) - if (!force && gitRoot) { const dirtyPaths = await getDirtyPaths(gitRoot); - console.log({ dirtyPaths }) const dirtyFiles = dirtyPaths .filter( (path) => @@ -57,18 +54,6 @@ export default createCommand(config, async ({ values }) => { customTypeLibraries.some((lib) => isDescendant(lib, path))), ) .map((path) => relativePathname(projectRoot, path)); - console.log({ projectRoot, customTypeLibraries, sliceLibraries }); - console.log( - dirtyPaths.map((path) => ({ - path, - isIndex: path.pathname.endsWith("/index.json"), - customTypeMatches: customTypeLibraries.map((lib) => ({ - lib, - matches: isDescendant(lib, path), - })), - })), - ); - console.log({ dirtyFiles }); if (dirtyFiles.length > 0) { throw new CommandError(` diff --git a/src/lib/git.ts b/src/lib/git.ts index fc46a05..0d53211 100644 --- a/src/lib/git.ts +++ b/src/lib/git.ts @@ -1,3 +1,4 @@ +import { realpath } from "node:fs/promises"; import { fileURLToPath, pathToFileURL } from "node:url"; import { x } from "tinyexec"; @@ -10,7 +11,7 @@ export async function getGitRoot(start: URL): Promise { throwOnError: true, }); const top = stdout.trim(); - return top ? appendTrailingSlash(pathToFileURL(top)) : undefined; + return top ? appendTrailingSlash(pathToFileURL(await realpath(top))) : undefined; } catch { return undefined; } @@ -22,7 +23,6 @@ export async function getDirtyPaths(gitRoot: URL): Promise { nodeOptions: { cwd: fileURLToPath(gitRoot) }, throwOnError: true, }); - console.log({ stdout }) const paths: URL[] = []; for (const line of stdout.split("\n")) { if (line.length < 4) continue; diff --git a/src/project.ts b/src/project.ts index 0772b46..86b0ddd 100644 --- a/src/project.ts +++ b/src/project.ts @@ -1,6 +1,7 @@ import type { CustomType } from "@prismicio/types-internal/lib/customtypes"; -import { readFile, rm, writeFile } from "node:fs/promises"; +import { readFile, realpath, rm, writeFile } from "node:fs/promises"; +import { fileURLToPath, pathToFileURL } from "node:url"; import * as z from "zod/mini"; import { getVariantData } from "./clients/amplitude"; @@ -201,7 +202,7 @@ export async function findProjectRoot(): Promise { } } const projectRoot = new URL(".", configPath); - return projectRoot; + return appendTrailingSlash(pathToFileURL(await realpath(fileURLToPath(projectRoot)))); } export async function safeGetRepositoryName(): Promise { diff --git a/test/pull.test.ts b/test/pull.test.ts index 91729bc..c3eb567 100644 --- a/test/pull.test.ts +++ b/test/pull.test.ts @@ -251,7 +251,6 @@ it.sequential("blocks pull when local model files have uncommitted changes", asy await writeFile(modelPath, JSON.stringify({ ...customType, label: "Edited locally" }, null, 2)); const second = await prismic("pull", ["--repo", repo]); - console.log(second) expect(second.exitCode).toBe(1); expect(second.stderr).toContain("uncommitted"); expect(second.stderr).toContain(`customtypes/${customType.id}/index.json`.replaceAll("/", sep)); From b914f325c19d53d8b9b7ec7312c4b3f27019a55c Mon Sep 17 00:00:00 2001 From: lihbr Date: Tue, 12 May 2026 19:05:26 +0900 Subject: [PATCH 11/12] ci: run all tests --- .github/workflows/validate.yml | 2 +- test/it.ts | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index a4b3ce3..77fad0d 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -60,7 +60,7 @@ jobs: node-version: ${{ matrix.node }} cache: npm - run: npm ci - - run: npm run unit pull.test.ts + - run: npm run unit env: E2E_PRISMIC_EMAIL: ${{ secrets.E2E_PRISMIC_EMAIL }} E2E_PRISMIC_PASSWORD: ${{ secrets.E2E_PRISMIC_PASSWORD }} diff --git a/test/it.ts b/test/it.ts index 3860d84..8b912ae 100644 --- a/test/it.ts +++ b/test/it.ts @@ -38,9 +38,11 @@ export const it = test.extend({ try { await rm(dir, { recursive: true, force: true }); } catch { - // Retry once with delay - await new Promise((res) => setTimeout(res, 1000)); - await rm(dir, { recursive: true, force: true }); + // Noop on CI, retry once with delay locally + if (!process.env.CI) { + await new Promise((res) => setTimeout(res, 1000)); + await rm(dir, { recursive: true, force: true }); + } } }, project: async ({ home, repo }, use) => { From c501c2d392e1a5587f8b5ac26b4bb74a58fabb51 Mon Sep 17 00:00:00 2001 From: lihbr Date: Tue, 12 May 2026 20:59:59 +0900 Subject: [PATCH 12/12] ci: fix publish workflow --- .github/workflows/publish.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 1777582..d1a381a 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -9,7 +9,7 @@ on: jobs: release: if: github.event_name == 'push' && github.repository_owner == 'prismicio' - runs-on: blacksmith-2vcpu-ubuntu-2404-arm + runs-on: ubuntu-latest permissions: contents: write issues: write @@ -41,7 +41,7 @@ jobs: prerelease: if: "!cancelled() && github.repository_owner == 'prismicio'" needs: [release] - runs-on: blacksmith-2vcpu-ubuntu-2404-arm + runs-on: ubuntu-latest permissions: contents: read id-token: write