Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/dark-rocks-smoke.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"wrangler": patch
---

Fixed Wrangler's error handling for both invalid commands with and without the `--help` flag, ensuring consistent and clear error messages.

Additionally, it also ensures that if you provide an invalid argument to a valid command, Wrangler will now correctly display that specific commands help menu.
5 changes: 5 additions & 0 deletions .changeset/tough-views-make.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@cloudflare/vite-plugin": minor
---

Use [Hook Filters](https://vite.dev/guide/api-plugin#hook-filters) to optimize plugin performance with Vite 8. This skips unnecessary Rust-to-JS calls with Rolldown powered Vite.
8 changes: 8 additions & 0 deletions .github/workflows/changesets.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,14 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GH_ACCESS_TOKEN }}

# Switch to Node 22 for non-npm package deployments because quick-edit
# builds native modules (tree-sitter) that are not compatible with
# Node 24's C++20 requirement for V8 headers.
- name: Switch to Node 22 for non-npm package deployments
uses: actions/setup-node@v4
with:
node-version: 22

- name: Deploy non-NPM Packages
id: deploy
run: |
Expand Down
4 changes: 2 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,5 +130,5 @@ Every change to package code requires a changeset or it will not trigger a relea

**Changeset Format:**

- Do not use conventional commit prefixes (e.g., `fix:`, `feat:`) in changeset descriptions
- Start with a capital letter and describe the change directly (e.g., "Remove unused option" not "fix: remove unused option")
The changeset descriptions can either use conventional commit prefixes (e.g., "fix: remove unused option") or
start with a capital letter and describe the change directly (e.g., "Remove unused option" not").
2 changes: 1 addition & 1 deletion fixtures/ratelimit-app/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"lib": ["esnext"],
"types": ["node"],
"skipLibCheck": true,
"moduleResolution": "node",
"moduleResolution": "bundler",
"noEmit": true
},
"include": ["tests"]
Expand Down
54 changes: 9 additions & 45 deletions fixtures/workflow-multiple/tests/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,53 +42,17 @@ describe("Workflows", () => {
}

it("creates two instances with same id in two different workflows", async () => {
const createResult = {
id: "test",
status: {
status: "running",
__LOCAL_DEV_STEP_OUTPUTS: [],
output: null,
},
};

// Create both workflow instances
// Note: We don't assert the intermediate "running" status because the workflow
// may complete before we can observe it, causing flaky tests on fast CI machines
await Promise.all([
expect(
fetchJson(`http://${ip}:${port}/create?workflowName=1&id=test`)
).resolves.toStrictEqual(createResult),
expect(
fetchJson(`http://${ip}:${port}/create?workflowName=2&id=test`)
).resolves.toStrictEqual(createResult),
fetchJson(`http://${ip}:${port}/create?workflowName=1&id=test`),
fetchJson(`http://${ip}:${port}/create?workflowName=2&id=test`),
]);

const firstResult = {
id: "test",
status: {
status: "running",
__LOCAL_DEV_STEP_OUTPUTS: [{ output: "First step result" }],
output: null,
},
};
// Wait for both workflows to complete with their final outputs
await Promise.all([
vi.waitFor(
async () => {
await expect(
fetchJson(`http://${ip}:${port}/status?workflowName=1&id=test`)
).resolves.toStrictEqual(firstResult);
},
{ timeout: 5000 }
),
vi.waitFor(
async () => {
await expect(
fetchJson(`http://${ip}:${port}/status?workflowName=2&id=test`)
).resolves.toStrictEqual(firstResult);
},
{ timeout: 5000 }
),
]);

await Promise.all([
await vi.waitFor(
async () => {
await expect(
fetchJson(`http://${ip}:${port}/status?workflowName=1&id=test`)
Expand All @@ -104,9 +68,9 @@ describe("Workflows", () => {
},
});
},
{ timeout: 5000 }
{ timeout: 10000 }
),
await vi.waitFor(
vi.waitFor(
async () => {
await expect(
fetchJson(`http://${ip}:${port}/status?workflowName=2&id=test`)
Expand All @@ -122,7 +86,7 @@ describe("Workflows", () => {
},
});
},
{ timeout: 5000 }
{ timeout: 10000 }
),
]);
});
Expand Down
1 change: 1 addition & 0 deletions packages/containers-shared/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"devDependencies": {
"@cloudflare/eslint-config-shared": "workspace:*",
"@cloudflare/workers-tsconfig": "workspace:*",
"@cloudflare/workers-utils": "workspace:*",
"@types/node": "catalog:default",
"eslint": "catalog:default",
"typescript": "catalog:default",
Expand Down
2 changes: 1 addition & 1 deletion packages/containers-shared/src/build.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { spawn } from "node:child_process";
import { readFileSync } from "node:fs";
import { UserError } from "./error";
import { UserError } from "@cloudflare/workers-utils";
import type {
BuildArgs,
ContainerDevOptions,
Expand Down
33 changes: 0 additions & 33 deletions packages/containers-shared/src/error.ts

This file was deleted.

2 changes: 1 addition & 1 deletion packages/containers-shared/src/images.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { UserError } from "@cloudflare/workers-utils";
import { buildImage } from "./build";
import { ExternalRegistryKind } from "./client/models/ExternalRegistryKind";
import { UserError } from "./error";
import { getCloudflareContainerRegistry } from "./knobs";
import { dockerLoginImageRegistry } from "./login";
import { getCloudflareRegistryWithAccountNamespace } from "./registry";
Expand Down
2 changes: 1 addition & 1 deletion packages/containers-shared/src/inspect.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { spawn } from "node:child_process";
import { UserError } from "./error";
import { UserError } from "@cloudflare/workers-utils";

export async function dockerImageInspect(
dockerPath: string,
Expand Down
2 changes: 1 addition & 1 deletion packages/containers-shared/src/login.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { spawn } from "node:child_process";
import { UserError } from "@cloudflare/workers-utils";
import { ImageRegistriesService, ImageRegistryPermissions } from "./client";
import { UserError } from "./error";

/**
* Gets push and pull credentials for a configured image registry
Expand Down
53 changes: 1 addition & 52 deletions packages/containers-shared/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { execFileSync, spawn } from "node:child_process";
import { randomUUID } from "node:crypto";
import { existsSync, statSync } from "node:fs";
import path from "node:path";
import { UserError } from "./error";
import { UserError } from "@cloudflare/workers-utils";
import { dockerImageInspect } from "./inspect";
import type { ContainerDevOptions } from "./types";
import type { StdioOptions } from "node:child_process";
Expand Down Expand Up @@ -99,55 +97,6 @@ export const verifyDockerInstalled = async (
}
};

export function isDir(inputPath: string) {
const stats = statSync(inputPath);
return stats.isDirectory();
}

/** returns true if it is a dockerfile, false if it is a registry link, throws if neither */
export const isDockerfile = (
image: string,
configPath: string | undefined
): boolean => {
const baseDir = configPath ? path.dirname(configPath) : process.cwd();
const maybeDockerfile = path.resolve(baseDir, image);
if (existsSync(maybeDockerfile)) {
if (isDir(maybeDockerfile)) {
throw new UserError(
`${image} is a directory, you should specify a path to the Dockerfile`
);
}
return true;
}

const errorPrefix = `The image "${image}" does not appear to be a valid path to a Dockerfile, or a valid image registry path:\n`;
// not found, not a dockerfile, let's try parsing the image ref as an URL?
try {
new URL(`https://${image}`);
} catch (e) {
if (e instanceof Error) {
throw new UserError(errorPrefix + e.message);
}
throw e;
}
const imageParts = image.split("/");

if (!imageParts[imageParts.length - 1]?.includes(":")) {
throw new UserError(
errorPrefix +
`If this is an image registry path, it needs to include at least a tag ':' (e.g: docker.io/httpd:1)`
);
}
// validate URL
if (image.includes("://")) {
throw new UserError(
errorPrefix +
`Image reference should not include the protocol part (e.g: docker.io/httpd:1, not https://docker.io/httpd:1)`
);
}
return false;
};

/**
* Kills and removes any containers which come from the given image tag
*/
Expand Down
2 changes: 1 addition & 1 deletion packages/containers-shared/tests/docker-context.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { execFileSync } from "node:child_process";
import { UserError } from "@cloudflare/workers-utils";
import { afterEach, describe, expect, it, vi } from "vitest";
import { UserError } from "../src/error";
import { resolveDockerHost } from "../src/utils";

vi.mock("node:child_process");
Expand Down
56 changes: 0 additions & 56 deletions packages/containers-shared/tests/helpers/run-in-tmp-dir.ts

This file was deleted.

Loading
Loading