Skip to content

Commit

Permalink
make the workerd compatibility date retrieval more stable by fetching…
Browse files Browse the repository at this point in the history
… it directly from the npm registry (#4627)
  • Loading branch information
dario-piotrowicz authored Dec 22, 2023
1 parent 0f424cf commit 44cbd66
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 30 deletions.
5 changes: 5 additions & 0 deletions .changeset/lucky-ghosts-sell.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"create-cloudflare": patch
---

make the workerd compatibility date retrieval more stable by fetching it directly from the npm registry
45 changes: 31 additions & 14 deletions packages/create-cloudflare/src/helpers/__tests__/command.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { spawn } from "cross-spawn";
import { detectPackageManager } from "helpers/packages";
import { Response, fetch } from "undici";
import { beforeEach, afterEach, describe, expect, test, vi } from "vitest";
import whichPMRuns from "which-pm-runs";
import {
Expand All @@ -14,13 +15,15 @@ import {
let spawnResultCode = 0;
let spawnStdout: string | undefined = undefined;
let spawnStderr: string | undefined = undefined;
let fetchResult: Response | undefined = undefined;

describe("Command Helpers", () => {
afterEach(() => {
vi.clearAllMocks();
spawnResultCode = 0;
spawnStdout = undefined;
spawnStderr = undefined;
fetchResult = undefined;
});

beforeEach(() => {
Expand Down Expand Up @@ -48,6 +51,20 @@ describe("Command Helpers", () => {

return { spawn: mockedSpawn };
});

// Mock out the undici fetch function
vi.mock("undici", async () => {
const actual = (await vi.importActual("undici")) as Record<
string,
unknown
>;
const mockedFetch = vi.fn().mockImplementation(() => {
return fetchResult;
});

return { ...actual, fetch: mockedFetch };
});

vi.mock("which-pm-runs");
vi.mocked(whichPMRuns).mockReturnValue({ name: "npm", version: "8.3.1" });

Expand Down Expand Up @@ -160,31 +177,31 @@ describe("Command Helpers", () => {

describe("getWorkerdCompatibilityDate()", () => {
test("normal flow", async () => {
spawnStdout = "2.20250110.5";
fetchResult = new Response(
JSON.stringify({
"dist-tags": { latest: "2.20250110.5" },
})
);
const date = await getWorkerdCompatibilityDate();
expectSilentSpawnWith("npm info workerd dist-tags.latest");
expect(fetch).toHaveBeenCalledWith("https://registry.npmjs.org/workerd");
expect(date).toBe("2025-01-10");
});

test("empty result", async () => {
spawnStdout = "";
fetchResult = new Response(
JSON.stringify({
"dist-tags": { latest: "" },
})
);
const date = await getWorkerdCompatibilityDate();
expectSilentSpawnWith("npm info workerd dist-tags.latest");
expect(fetch).toHaveBeenCalledWith("https://registry.npmjs.org/workerd");
expect(date).toBe("2023-05-18");
});

test("verbose output (e.g. yarn or debug mode)", async () => {
spawnStdout =
"Debugger attached.\nyarn info v1.22.19\n2.20250110.5\n✨ Done in 0.83s.";
const date = await getWorkerdCompatibilityDate();
expectSilentSpawnWith("npm info workerd dist-tags.latest");
expect(date).toBe("2025-01-10");
});

test("command failed", async () => {
spawnResultCode = 1;
fetchResult = new Response("Unknown error");
const date = await getWorkerdCompatibilityDate();
expectSilentSpawnWith("npm info workerd dist-tags.latest");
expect(fetch).toHaveBeenCalledWith("https://registry.npmjs.org/workerd");
expect(date).toBe("2023-05-18");
});
});
Expand Down
46 changes: 30 additions & 16 deletions packages/create-cloudflare/src/helpers/command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { brandColor, dim } from "@cloudflare/cli/colors";
import { isInteractive, spinner } from "@cloudflare/cli/interactive";
import { spawn } from "cross-spawn";
import { getFrameworkCli } from "frameworks/index";
import { fetch } from "undici";
import { quoteShellArgs } from "../common";
import { detectPackageManager } from "./packages";
import type { PagesGeneratorContext } from "types";
Expand Down Expand Up @@ -381,23 +382,36 @@ export const listAccounts = async () => {
* @returns The latest compatibility date for workerd in the form "YYYY-MM-DD"
*/
export async function getWorkerdCompatibilityDate() {
const { npm } = detectPackageManager();

return runCommand([npm, "info", "workerd", "dist-tags.latest"], {
silent: true,
captureOutput: true,
const { compatDate: workerdCompatibilityDate } = await printAsyncStatus<{
compatDate: string;
isFallback: boolean;
}>({
useSpinner: true,
startText: "Retrieving current workerd compatibility date",
transformOutput: (result) => {
// The format of the workerd version is `major.yyyymmdd.patch`.
const match = result.match(/\d+\.(\d{4})(\d{2})(\d{2})\.\d+/);

if (!match) {
throw new Error("Could not find workerd date");
}
const [, year, month, date] = match;
return `${year}-${month}-${date}`;
doneText: ({ compatDate, isFallback }) =>
`${brandColor("compatibility date")}${
isFallback ? dim(" Could not find workerd date, falling back to") : ""
} ${dim(compatDate)}`,
async promise() {
try {
const resp = await fetch("https://registry.npmjs.org/workerd");
const workerdNpmInfo = (await resp.json()) as {
"dist-tags": { latest: string };
};
const result = workerdNpmInfo["dist-tags"].latest;

// The format of the workerd version is `major.yyyymmdd.patch`.
const match = result.match(/\d+\.(\d{4})(\d{2})(\d{2})\.\d+/);

if (match) {
const [, year, month, date] = match ?? [];
return { compatDate: `${year}-${month}-${date}`, isFallback: false };
}
} catch {}

return { compatDate: "2023-05-18", isFallback: true };
},
fallbackOutput: () => "2023-05-18",
doneText: (output) => `${brandColor("compatibility date")} ${dim(output)}`,
});

return workerdCompatibilityDate;
}

0 comments on commit 44cbd66

Please sign in to comment.