diff --git a/.changeset/thin-pots-camp.md b/.changeset/thin-pots-camp.md new file mode 100644 index 000000000000..e578c1d1ca85 --- /dev/null +++ b/.changeset/thin-pots-camp.md @@ -0,0 +1,84 @@ +--- +"wrangler": minor +--- + +feat: add support for redirecting Wrangler to a generated config when running deploy-related commands + +This new feature is designed for build tools and frameworks to provide a deploy-specific configuration, +which Wrangler can use instead of user configuration when running deploy-related commands. +It is not expected that developers of Workers will need to use this feature directly. + +### Affected commands + +The commands that use this feature are: + +- `wrangler deploy` +- `wrangler dev` +- `wrangler versions upload` +- `wrangler versions deploy` +- `wrangler pages deploy` +- `wrangler pages build` +- `wrangler pages build-env` + +### Config redirect file + +When running these commands, Wrangler will look up the directory tree from the current working directory for a file at the path `.wrangler/deploy/config.json`. This file must contain only a single JSON object of the form: + +```json +{ "configPath": "../../path/to/wrangler.json" } +``` + +When this file exists Wrangler will follow the `configPath` (relative to the `.wrangler/deploy/config.json` file) to find an alternative Wrangler configuration file to load and use as part of this command. + +When this happens Wrangler will display a warning to the user to indicate that the configuration has been redirected to a different file than the user's configuration file. + +### Custom build tool example + +A common approach that a build tool might choose to implement. + +- The user writes code that uses Cloudflare Workers resources, configured via a user `wrangler.toml` file. + + ```toml + name = "my-worker" + main = "src/index.ts" + [[kv_namespaces]] + binding = "" + id = "" + ``` + + Note that this configuration points `main` at user code entry-point. + +- The user runs a custom build, which might read the `wrangler.toml` to find the entry-point: + + ```bash + > my-tool build + ``` + +- This tool generates a `dist` directory that contains both compiled code and a new deployment configuration file, but also a `.wrangler/deploy/config.json` file that redirects Wrangler to this new deployment configuration file: + + ```plain + - dist + - index.js + - wrangler.json + - .wrangler + - deploy + - config.json + ``` + + The `dist/wrangler.json` will contain: + + ```json + { + "name": "my-worker", + "main": "./index.js", + "kv_namespaces": [{ "binding": "", "id": "" }] + } + ``` + + And the `.wrangler/deploy/config.json` will contain: + + ```json + { + "configPath": "../../dist/wrangler.json" + } + ``` diff --git a/.prettierignore b/.prettierignore index d55c0a6c1427..aee96a33703f 100644 --- a/.prettierignore +++ b/.prettierignore @@ -40,3 +40,7 @@ templates/*/dist # This file intentionally has a syntax error fixtures/interactive-dev-tests/src/startup-error.ts + +# These are generated by the build step +fixtures/pages-redirected-config/build/* +fixtures/redirected-config-worker/build/* \ No newline at end of file diff --git a/fixtures/import-npm/package-lock.json b/fixtures/import-npm/package-lock.json deleted file mode 100644 index 11234218d1a9..000000000000 --- a/fixtures/import-npm/package-lock.json +++ /dev/null @@ -1,185 +0,0 @@ -{ - "name": "import-npm", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "import-npm", - "workspaces": [ - "packages/*" - ] - }, - "../../packages/workers-tsconfig": { - "name": "@cloudflare/workers-tsconfig", - "version": "0.0.0", - "dev": true - }, - "../../packages/wrangler": { - "version": "3.95.0", - "dev": true, - "license": "MIT OR Apache-2.0", - "dependencies": { - "@cloudflare/kv-asset-handler": "workspace:*", - "@cloudflare/workers-shared": "workspace:*", - "@esbuild-plugins/node-globals-polyfill": "^0.2.3", - "@esbuild-plugins/node-modules-polyfill": "^0.2.2", - "blake3-wasm": "^2.1.5", - "chokidar": "^4.0.1", - "date-fns": "^4.1.0", - "esbuild": "0.17.19", - "itty-time": "^1.0.6", - "miniflare": "workspace:*", - "nanoid": "^3.3.3", - "path-to-regexp": "^6.3.0", - "resolve": "^1.22.8", - "selfsigned": "^2.0.1", - "source-map": "^0.6.1", - "unenv": "npm:unenv-nightly@2.0.0-20241204-140205-a5d5190", - "workerd": "1.20241205.0", - "xxhash-wasm": "^1.0.1" - }, - "bin": { - "wrangler": "bin/wrangler.js", - "wrangler2": "bin/wrangler.js" - }, - "devDependencies": { - "@cloudflare/cli": "workspace:*", - "@cloudflare/eslint-config-worker": "workspace:*", - "@cloudflare/pages-shared": "workspace:^", - "@cloudflare/types": "6.18.4", - "@cloudflare/workers-tsconfig": "workspace:*", - "@cloudflare/workers-types": "^4.20241205.0", - "@cspotcode/source-map-support": "0.8.1", - "@iarna/toml": "^3.0.0", - "@microsoft/api-extractor": "^7.47.0", - "@sentry/node": "^7.86.0", - "@sentry/types": "^7.86.0", - "@sentry/utils": "^7.86.0", - "@types/body-parser": "^1.19.2", - "@types/command-exists": "^1.2.0", - "@types/express": "^4.17.13", - "@types/glob-to-regexp": "^0.4.1", - "@types/is-ci": "^3.0.0", - "@types/javascript-time-ago": "^2.0.3", - "@types/mime": "^3.0.4", - "@types/minimatch": "^5.1.2", - "@types/prompts": "^2.0.14", - "@types/resolve": "^1.20.6", - "@types/shell-quote": "^1.7.2", - "@types/signal-exit": "^3.0.1", - "@types/supports-color": "^8.1.1", - "@types/ws": "^8.5.7", - "@types/yargs": "^17.0.22", - "@vitest/ui": "catalog:default", - "@webcontainer/env": "^1.1.0", - "body-parser": "^1.20.0", - "chalk": "^5.2.0", - "cli-table3": "^0.6.3", - "cmd-shim": "^4.1.0", - "command-exists": "^1.2.9", - "concurrently": "^8.2.2", - "devtools-protocol": "^0.0.1182435", - "dotenv": "^16.0.0", - "execa": "^6.1.0", - "express": "^4.18.1", - "find-up": "^6.3.0", - "get-port": "^7.0.0", - "glob-to-regexp": "^0.4.1", - "http-terminator": "^3.2.0", - "https-proxy-agent": "7.0.2", - "ignore": "^5.2.0", - "is-ci": "^3.0.1", - "javascript-time-ago": "^2.5.4", - "md5-file": "5.0.0", - "mime": "^3.0.0", - "minimatch": "^5.1.0", - "mock-socket": "^9.3.1", - "msw": "2.4.3", - "open": "^8.4.0", - "p-queue": "^7.2.0", - "patch-console": "^1.0.0", - "pretty-bytes": "^6.0.0", - "prompts": "^2.4.2", - "semiver": "^1.1.0", - "shell-quote": "^1.8.1", - "signal-exit": "^3.0.7", - "strip-ansi": "^7.1.0", - "supports-color": "^9.2.2", - "timeago.js": "^4.0.2", - "ts-dedent": "^2.2.0", - "ts-json-schema-generator": "^1.5.0", - "undici": "catalog:default", - "update-check": "^1.5.4", - "vitest": "catalog:default", - "vitest-websocket-mock": "^0.4.0", - "ws": "^8.18.0", - "xdg-app-paths": "^8.3.0", - "yargs": "^17.7.2" - }, - "engines": { - "node": ">=16.17.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - }, - "peerDependencies": { - "@cloudflare/workers-types": "^4.20241205.0" - }, - "peerDependenciesMeta": { - "@cloudflare/workers-types": { - "optional": true - } - } - }, - "../import-wasm-static": {}, - "node_modules/@cloudflare/workers-tsconfig": { - "resolved": "../../packages/workers-tsconfig", - "link": true - }, - "node_modules/@fastify/busboy": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", - "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14" - } - }, - "node_modules/import-example": { - "resolved": "packages/import-example", - "link": true - }, - "node_modules/import-wasm-static": { - "resolved": "../import-wasm-static", - "link": true - }, - "node_modules/undici": { - "version": "5.28.4", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.4.tgz", - "integrity": "sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@fastify/busboy": "^2.0.0" - }, - "engines": { - "node": ">=14.0" - } - }, - "node_modules/wrangler": { - "resolved": "../../packages/wrangler", - "link": true - }, - "packages/import-example": { - "dependencies": { - "import-wasm-static": "../../../../fixtures/import-wasm-static" - }, - "devDependencies": { - "@cloudflare/workers-tsconfig": "../../../../packages/workers-tsconfig", - "undici": "^5.28.4", - "wrangler": "../../../../packages/wrangler" - } - } - } -} diff --git a/fixtures/import-npm/package.json b/fixtures/import-npm/package.json index eb8252f6b488..a791a1642969 100644 --- a/fixtures/import-npm/package.json +++ b/fixtures/import-npm/package.json @@ -7,9 +7,10 @@ "packages/*" ], "scripts": { - "check:type": "rm -rf node_modules && npm install && npm run check:type --workspaces", - "test:ci": "npm install && npm run test:ci --workspaces", - "test:watch": "npm install && npm run test:watch --workspaces", - "type:tests": "rm -rf node_modules && npm install && npm run type:tests --workspaces" + "_clean_install": "rm -rf node_modules && npm install --no-package-lock", + "check:type": "npm run check:type --workspaces", + "test:ci": "npm run test:ci --workspaces", + "test:watch": "npm run test:watch --workspaces", + "type:tests": "npm run type:tests --workspaces" } } diff --git a/fixtures/import-npm/turbo.json b/fixtures/import-npm/turbo.json index ac10a3dc52e8..55164732b49a 100644 --- a/fixtures/import-npm/turbo.json +++ b/fixtures/import-npm/turbo.json @@ -1,11 +1,18 @@ { "extends": ["//"], "tasks": { - "test": { - "dependsOn": ["wrangler#build"] + "_clean_install": {}, + "check:type": { + "dependsOn": ["_clean_install"] + }, + "test:watch": { + "dependsOn": ["_clean_install"] + }, + "type:tests": { + "dependsOn": ["_clean_install"] }, "test:ci": { - "dependsOn": ["wrangler#build"] + "dependsOn": ["_clean_install", "wrangler#build"] } } } diff --git a/fixtures/pages-redirected-config/.gitignore b/fixtures/pages-redirected-config/.gitignore new file mode 100644 index 000000000000..2cf1da454af0 --- /dev/null +++ b/fixtures/pages-redirected-config/.gitignore @@ -0,0 +1,2 @@ +dist +build \ No newline at end of file diff --git a/fixtures/pages-redirected-config/package.json b/fixtures/pages-redirected-config/package.json new file mode 100644 index 000000000000..6c19f514440f --- /dev/null +++ b/fixtures/pages-redirected-config/package.json @@ -0,0 +1,23 @@ +{ + "name": "pages-redirected-config", + "private": true, + "description": "", + "license": "ISC", + "author": "", + "main": "src/index.js", + "scripts": { + "build": "node -r esbuild-register tools/build.ts", + "check:type": "tsc", + "dev": "pnpm run build && wrangler pages dev", + "test:ci": "pnpm run build && vitest run" + }, + "devDependencies": { + "@cloudflare/workers-tsconfig": "workspace:^", + "undici": "catalog:default", + "vitest": "catalog:default", + "wrangler": "workspace:*" + }, + "volta": { + "extends": "../../package.json" + } +} diff --git a/fixtures/pages-redirected-config/src/index.js b/fixtures/pages-redirected-config/src/index.js new file mode 100644 index 000000000000..e1ce8e64af6b --- /dev/null +++ b/fixtures/pages-redirected-config/src/index.js @@ -0,0 +1,5 @@ +export default { + async fetch(request, env) { + return new Response("Generated: " + env.generated ?? false); + }, +}; diff --git a/fixtures/pages-redirected-config/tests/index.test.ts b/fixtures/pages-redirected-config/tests/index.test.ts new file mode 100644 index 000000000000..e30c7fec1f73 --- /dev/null +++ b/fixtures/pages-redirected-config/tests/index.test.ts @@ -0,0 +1,54 @@ +import { rmSync, writeFileSync } from "fs"; +import { resolve } from "path"; +import { fetch } from "undici"; +import { describe, it } from "vitest"; +import { runWranglerPagesDev } from "../../shared/src/run-wrangler-long-lived"; + +const basePath = resolve(__dirname, ".."); + +describe("wrangler pages dev", () => { + it("uses the generated config if there is no wrangler.toml", async ({ + expect, + onTestFinished, + }) => { + const { ip, port, stop } = await runWranglerPagesDev(basePath, undefined, [ + "--port=0", + "--inspector-port=0", + ]); + onTestFinished(async () => await stop?.()); + + // Note that the local protocol defaults to http + const response = await fetch(`http://${ip}:${port}/`); + const text = await response.text(); + expect(response.status).toBe(200); + expect(text).toMatchInlineSnapshot(`"Generated: true"`); + }); + + it("uses the generated config instead of a user wrangler.toml", async ({ + expect, + onTestFinished, + }) => { + writeFileSync( + "wrangler.toml", + [ + `name = "redirected-config-worker"`, + `compatibility_date = "2024-12-01"`, + `pages_build_output_dir = "public"`, + ].join("\n") + ); + const { ip, port, stop } = await runWranglerPagesDev(basePath, undefined, [ + "--port=0", + "--inspector-port=0", + ]); + onTestFinished(async () => { + rmSync("wrangler.toml", { force: true }); + await stop?.(); + }); + + // Note that the local protocol defaults to http + const response = await fetch(`http://${ip}:${port}/`); + const text = await response.text(); + expect(response.status).toBe(200); + expect(text).toMatchInlineSnapshot(`"Generated: true"`); + }); +}); diff --git a/fixtures/pages-redirected-config/tools/build.ts b/fixtures/pages-redirected-config/tools/build.ts new file mode 100644 index 000000000000..01594c49f463 --- /dev/null +++ b/fixtures/pages-redirected-config/tools/build.ts @@ -0,0 +1,24 @@ +import { copyFileSync, mkdirSync, rmSync, writeFileSync } from "fs"; + +// Create a pseudo build directory +rmSync("build", { recursive: true, force: true }); +mkdirSync("build"); +const config = { + name: "redirected-config-worker", + compatibility_date: "2024-12-01", + pages_build_output_dir: "./public", + vars: { generated: true }, +}; +writeFileSync("build/wrangler.json", JSON.stringify(config, undefined, 2)); + +mkdirSync("build/public"); +copyFileSync("src/index.js", "build/public/_worker.js"); + +// Create the redirect file +rmSync(".wrangler/deploy", { recursive: true, force: true }); +mkdirSync(".wrangler/deploy", { recursive: true }); +const redirect = { configPath: "../../build/wrangler.json" }; +writeFileSync( + ".wrangler/deploy/config.json", + JSON.stringify(redirect, undefined, 2) +); diff --git a/fixtures/pages-redirected-config/tsconfig.json b/fixtures/pages-redirected-config/tsconfig.json new file mode 100644 index 000000000000..b901134e4e79 --- /dev/null +++ b/fixtures/pages-redirected-config/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "target": "ES2020", + "esModuleInterop": true, + "module": "CommonJS", + "lib": ["ES2020"], + "types": ["node"], + "skipLibCheck": true, + "moduleResolution": "node", + "noEmit": true + }, + "include": ["tests", "../../node-types.d.ts"] +} diff --git a/fixtures/pages-redirected-config/turbo.json b/fixtures/pages-redirected-config/turbo.json new file mode 100644 index 000000000000..3394ff556c71 --- /dev/null +++ b/fixtures/pages-redirected-config/turbo.json @@ -0,0 +1,9 @@ +{ + "$schema": "http://turbo.build/schema.json", + "extends": ["//"], + "tasks": { + "build": { + "outputs": ["build/**"] + } + } +} diff --git a/fixtures/pages-redirected-config/vitest.config.mts b/fixtures/pages-redirected-config/vitest.config.mts new file mode 100644 index 000000000000..846cddc41995 --- /dev/null +++ b/fixtures/pages-redirected-config/vitest.config.mts @@ -0,0 +1,9 @@ +import { defineProject, mergeConfig } from "vitest/config"; +import configShared from "../../vitest.shared"; + +export default mergeConfig( + configShared, + defineProject({ + test: {}, + }) +); diff --git a/fixtures/redirected-config-worker/.gitignore b/fixtures/redirected-config-worker/.gitignore new file mode 100644 index 000000000000..2cf1da454af0 --- /dev/null +++ b/fixtures/redirected-config-worker/.gitignore @@ -0,0 +1,2 @@ +dist +build \ No newline at end of file diff --git a/fixtures/redirected-config-worker/package.json b/fixtures/redirected-config-worker/package.json new file mode 100644 index 000000000000..44a6770bed68 --- /dev/null +++ b/fixtures/redirected-config-worker/package.json @@ -0,0 +1,23 @@ +{ + "name": "redirected-config-worker", + "private": true, + "description": "", + "license": "ISC", + "author": "", + "main": "src/index.js", + "scripts": { + "build": "node -r esbuild-register tools/build.ts", + "check:type": "tsc", + "dev": "pnpm run build && wrangler dev", + "test:ci": "pnpm run build && vitest run" + }, + "devDependencies": { + "@cloudflare/workers-tsconfig": "workspace:^", + "undici": "catalog:default", + "vitest": "catalog:default", + "wrangler": "workspace:*" + }, + "volta": { + "extends": "../../package.json" + } +} diff --git a/fixtures/redirected-config-worker/src/index.js b/fixtures/redirected-config-worker/src/index.js new file mode 100644 index 000000000000..e1ce8e64af6b --- /dev/null +++ b/fixtures/redirected-config-worker/src/index.js @@ -0,0 +1,5 @@ +export default { + async fetch(request, env) { + return new Response("Generated: " + env.generated ?? false); + }, +}; diff --git a/fixtures/redirected-config-worker/tests/index.test.ts b/fixtures/redirected-config-worker/tests/index.test.ts new file mode 100644 index 000000000000..81e8f5a8c68b --- /dev/null +++ b/fixtures/redirected-config-worker/tests/index.test.ts @@ -0,0 +1,40 @@ +import { resolve } from "path"; +import { fetch } from "undici"; +import { describe, it } from "vitest"; +import { runWranglerDev } from "../../shared/src/run-wrangler-long-lived"; + +const basePath = resolve(__dirname, ".."); + +describe("'wrangler dev' correctly renders pages", () => { + it("uses the generated config", async ({ expect, onTestFinished }) => { + const { ip, port, stop } = await runWranglerDev(basePath, [ + "--port=0", + "--inspector-port=0", + ]); + onTestFinished(async () => await stop?.()); + + // Note that the local protocol defaults to http + const response = await fetch(`http://${ip}:${port}/`); + const text = await response.text(); + expect(response.status).toBe(200); + expect(text).toMatchInlineSnapshot(`"Generated: true"`); + }); + + it("uses a custom config from command line rather than generated config", async ({ + expect, + onTestFinished, + }) => { + const { ip, port, stop } = await runWranglerDev(basePath, [ + "-c=wrangler.toml", + "--port=0", + "--inspector-port=0", + ]); + onTestFinished(async () => await stop?.()); + + // Note that the local protocol defaults to http + const response = await fetch(`http://${ip}:${port}/`); + const text = await response.text(); + expect(response.status).toBe(200); + expect(text).toMatchInlineSnapshot(`"Generated: undefined"`); + }); +}); diff --git a/fixtures/redirected-config-worker/tools/build.ts b/fixtures/redirected-config-worker/tools/build.ts new file mode 100644 index 000000000000..a5b0f354931e --- /dev/null +++ b/fixtures/redirected-config-worker/tools/build.ts @@ -0,0 +1,22 @@ +import { copyFileSync, mkdirSync, rmSync, writeFileSync } from "fs"; + +// Create a pseudo build directory +rmSync("build", { recursive: true, force: true }); +mkdirSync("build"); +const config = { + name: "redirected-config-worker", + compatibility_date: "2024-12-01", + main: "index.js", + vars: { generated: true }, +}; +writeFileSync("build/wrangler.json", JSON.stringify(config, undefined, 2)); +copyFileSync("src/index.js", "build/index.js"); + +// Create the redirect file +rmSync(".wrangler/deploy", { recursive: true, force: true }); +mkdirSync(".wrangler/deploy", { recursive: true }); +const redirect = { configPath: "../../build/wrangler.json" }; +writeFileSync( + ".wrangler/deploy/config.json", + JSON.stringify(redirect, undefined, 2) +); diff --git a/fixtures/redirected-config-worker/tsconfig.json b/fixtures/redirected-config-worker/tsconfig.json new file mode 100644 index 000000000000..b901134e4e79 --- /dev/null +++ b/fixtures/redirected-config-worker/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "target": "ES2020", + "esModuleInterop": true, + "module": "CommonJS", + "lib": ["ES2020"], + "types": ["node"], + "skipLibCheck": true, + "moduleResolution": "node", + "noEmit": true + }, + "include": ["tests", "../../node-types.d.ts"] +} diff --git a/fixtures/redirected-config-worker/turbo.json b/fixtures/redirected-config-worker/turbo.json new file mode 100644 index 000000000000..3394ff556c71 --- /dev/null +++ b/fixtures/redirected-config-worker/turbo.json @@ -0,0 +1,9 @@ +{ + "$schema": "http://turbo.build/schema.json", + "extends": ["//"], + "tasks": { + "build": { + "outputs": ["build/**"] + } + } +} diff --git a/fixtures/redirected-config-worker/vitest.config.mts b/fixtures/redirected-config-worker/vitest.config.mts new file mode 100644 index 000000000000..846cddc41995 --- /dev/null +++ b/fixtures/redirected-config-worker/vitest.config.mts @@ -0,0 +1,9 @@ +import { defineProject, mergeConfig } from "vitest/config"; +import configShared from "../../vitest.shared"; + +export default mergeConfig( + configShared, + defineProject({ + test: {}, + }) +); diff --git a/fixtures/redirected-config-worker/wrangler.toml b/fixtures/redirected-config-worker/wrangler.toml new file mode 100644 index 000000000000..449bd0b5b2de --- /dev/null +++ b/fixtures/redirected-config-worker/wrangler.toml @@ -0,0 +1,4 @@ +name = "redirected-config-worker" +compatibility_date = "2024-12-01" + +main = "src/index.js" diff --git a/fixtures/shared/src/run-wrangler-long-lived.ts b/fixtures/shared/src/run-wrangler-long-lived.ts index b16460b41a7e..0eb2439e55e9 100644 --- a/fixtures/shared/src/run-wrangler-long-lived.ts +++ b/fixtures/shared/src/run-wrangler-long-lived.ts @@ -92,11 +92,15 @@ async function runLongLivedWrangler( const chunks: Buffer[] = []; wranglerProcess.stdout?.on("data", (chunk) => { - console.log(`[${command}]`, chunk.toString()); + if (process.env.WRANGLER_LOG === "debug") { + console.log(`[${command}]`, chunk.toString()); + } chunks.push(chunk); }); wranglerProcess.stderr?.on("data", (chunk) => { - console.log(`[${command}]`, chunk.toString()); + if (process.env.WRANGLER_LOG === "debug") { + console.log(`[${command}]`, chunk.toString()); + } chunks.push(chunk); }); const getOutput = () => Buffer.concat(chunks).toString(); diff --git a/packages/wrangler/e2e/dev-registry.test.ts b/packages/wrangler/e2e/dev-registry.test.ts index 273cf7cb041f..77da2d88f3af 100644 --- a/packages/wrangler/e2e/dev-registry.test.ts +++ b/packages/wrangler/e2e/dev-registry.test.ts @@ -99,27 +99,25 @@ describe("unstable_dev()", () => { const childWorker = await unstable_dev( "${child.replaceAll("\\", "/")}/src/index.ts", { - configPath: "${child.replaceAll("\\", "/")}/wrangler.toml", experimental: { disableExperimentalWarning: true, }, } ); + // Wait long enough for the child to register itself on the Worker Registry + // before we boot up the parent that needs to know about it. await setTimeout(2000) const parentWorker = await unstable_dev( "src/index.ts", { - configPath: "wrangler.toml", experimental: { disableExperimentalWarning: true, }, } ); - await setTimeout(2000) - console.log(await parentWorker.fetch("/").then(r => r.text())) process.exit(0); diff --git a/packages/wrangler/e2e/dev-with-resources.test.ts b/packages/wrangler/e2e/dev-with-resources.test.ts index 1910d82e7d18..f464c54b9ab2 100644 --- a/packages/wrangler/e2e/dev-with-resources.test.ts +++ b/packages/wrangler/e2e/dev-with-resources.test.ts @@ -8,6 +8,9 @@ import WebSocket from "ws"; import { WranglerE2ETestHelper } from "./helpers/e2e-wrangler-test"; import { generateResourceName } from "./helpers/generate-resource-name"; +const port = await getPort(); +const inspectorPort = await getPort(); + const RUNTIMES = [ { flags: "", runtime: "local" }, { flags: "--remote", runtime: "remote" }, @@ -60,7 +63,9 @@ describe.sequential.each(RUNTIMES)("Core: $flags", ({ runtime, flags }) => { } `, }); - const worker = helper.runLongLived(`wrangler dev ${flags}`); + const worker = helper.runLongLived( + `wrangler dev ${flags} --port ${port} --inspector-port ${inspectorPort}` + ); const { url } = await worker.waitForReady(); let res = await fetch(url); @@ -98,7 +103,9 @@ describe.sequential.each(RUNTIMES)("Core: $flags", ({ runtime, flags }) => { }); `, }); - const worker = helper.runLongLived(`wrangler dev ${flags}`); + const worker = helper.runLongLived( + `wrangler dev ${flags} --port ${port} --inspector-port ${inspectorPort}` + ); const { url } = await worker.waitForReady(); let res = await fetch(url); expect(await res.text()).toBe("service worker"); @@ -147,7 +154,9 @@ describe.sequential.each(RUNTIMES)("Core: $flags", ({ runtime, flags }) => { } `, }); - const worker = helper.runLongLived(`wrangler dev ${flags}`); + const worker = helper.runLongLived( + `wrangler dev ${flags} --port ${port} --inspector-port ${inspectorPort}` + ); const { url } = await worker.waitForReady(); const res = await fetch(url); expect(await res.json()).toEqual({ @@ -158,8 +167,6 @@ describe.sequential.each(RUNTIMES)("Core: $flags", ({ runtime, flags }) => { }); it("starts inspector and allows debugging", async () => { - const inspectorPort = await getPort(); - await helper.seed({ "wrangler.toml": dedent` name = "${workerName}" @@ -173,7 +180,7 @@ describe.sequential.each(RUNTIMES)("Core: $flags", ({ runtime, flags }) => { `, }); const worker = helper.runLongLived( - `wrangler dev ${flags} --inspector-port=${inspectorPort}` + `wrangler dev ${flags} --port ${port} --inspector-port ${inspectorPort}` ); await worker.waitForReady(); const inspectorUrl = new URL(`ws://127.0.0.1:${inspectorPort}`); @@ -198,7 +205,7 @@ describe.sequential.each(RUNTIMES)("Core: $flags", ({ runtime, flags }) => { `, }); const worker = helper.runLongLived( - `wrangler dev ${flags} --local-protocol=https` + `wrangler dev ${flags} --port ${port} --inspector-port ${inspectorPort} --local-protocol=https` ); const { url } = await worker.waitForReady(); const parsedURL = new URL(url); @@ -224,7 +231,7 @@ describe.sequential.each(RUNTIMES)("Core: $flags", ({ runtime, flags }) => { }); // TODO(soon): explore using `--host` for remote mode in this test const worker = helper.runLongLived( - `wrangler dev ${flags} --local-upstream=example.com` + `wrangler dev ${flags} --port ${port} --inspector-port ${inspectorPort} --local-upstream=example.com` ); const { url } = await worker.waitForReady(); const res = await fetch(url); @@ -270,7 +277,9 @@ describe.sequential.each(RUNTIMES)("Bindings: $flags", ({ runtime, flags }) => { }); `, }); - const worker = helper.runLongLived(`wrangler dev ${flags}`); + const worker = helper.runLongLived( + `wrangler dev ${flags} --port ${port} --inspector-port ${inspectorPort}` + ); const { url } = await worker.waitForReady(); const res = await fetch(url); expect(await res.json()).toEqual({ @@ -298,7 +307,9 @@ describe.sequential.each(RUNTIMES)("Bindings: $flags", ({ runtime, flags }) => { }); `, }); - const worker = helper.runLongLived(`wrangler dev ${flags}`); + const worker = helper.runLongLived( + `wrangler dev ${flags} --port ${port} --inspector-port ${inspectorPort}` + ); const { url } = await worker.waitForReady(); const res = await fetch(url); expect(await res.text()).toBe("3"); @@ -330,7 +341,9 @@ describe.sequential.each(RUNTIMES)("Bindings: $flags", ({ runtime, flags }) => { } `, }); - const worker = helper.runLongLived(`wrangler dev ${flags}`); + const worker = helper.runLongLived( + `wrangler dev ${flags} --port ${port} --inspector-port ${inspectorPort}` + ); const { url } = await worker.waitForReady(); const res = await fetch(url); expect(await res.text()).toBe("existing-value"); @@ -399,7 +412,9 @@ describe.sequential.each(RUNTIMES)("Bindings: $flags", ({ runtime, flags }) => { `, }); - const worker = helper.runLongLived(`wrangler dev ${flags}`); + const worker = helper.runLongLived( + `wrangler dev ${flags} --port ${port} --inspector-port ${inspectorPort}` + ); const { url } = await worker.waitForReady(); const res = await fetch(url); expect(await res.text()).toBe("

👋

"); @@ -432,7 +447,9 @@ describe.sequential.each(RUNTIMES)("Bindings: $flags", ({ runtime, flags }) => { } `, }); - const worker = helper.runLongLived(`wrangler dev ${flags}`); + const worker = helper.runLongLived( + `wrangler dev ${flags} --port ${port} --inspector-port ${inspectorPort}` + ); const { url } = await worker.waitForReady(); const res = await fetch(url); expect(await res.text()).toBe("existing-value"); @@ -483,7 +500,9 @@ describe.sequential.each(RUNTIMES)("Bindings: $flags", ({ runtime, flags }) => { `wrangler d1 execute ${d1ResourceFlags} DB --file schema.sql` ); // D1 defaults to `--local`, so we deliberately use `flags`, not `resourceFlags` - const worker = helper.runLongLived(`wrangler dev ${flags}`); + const worker = helper.runLongLived( + `wrangler dev ${flags} --port ${port} --inspector-port ${inspectorPort}` + ); const { url } = await worker.waitForReady(); const res = await fetch(url); expect(await res.json()).toEqual([{ key: "key1", value: "value1" }]); @@ -551,7 +570,7 @@ describe.sequential.each(RUNTIMES)("Bindings: $flags", ({ runtime, flags }) => { }); const worker = helper.runLongLived( - `wrangler dev ${flags} --experimental-vectorize-bind-to-prod` + `wrangler dev ${flags} --port ${port} --inspector-port ${inspectorPort} --experimental-vectorize-bind-to-prod` ); const { url } = await worker.waitForReady(); const res = await fetch(url); @@ -585,7 +604,9 @@ describe.sequential.each(RUNTIMES)("Bindings: $flags", ({ runtime, flags }) => { `, }); - const worker = helper.runLongLived(`wrangler dev ${flags}`); + const worker = helper.runLongLived( + `wrangler dev ${flags} --port ${port} --inspector-port ${inspectorPort}` + ); const { url } = await worker.waitForReady(); const res = await fetch(url); @@ -619,7 +640,9 @@ describe.sequential.each(RUNTIMES)("Bindings: $flags", ({ runtime, flags }) => { } `, }); - const worker = helper.runLongLived(`wrangler dev ${flags}`); + const worker = helper.runLongLived( + `wrangler dev ${flags} --port ${port} --inspector-port ${inspectorPort}` + ); const { url } = await worker.waitForReady(); await fetch(url); await worker.readUntil(/✉️/); @@ -659,7 +682,9 @@ describe.sequential.each(RUNTIMES)("Bindings: $flags", ({ runtime, flags }) => { } `, }); - const worker = helper.runLongLived(`wrangler dev ${flags}`); + const worker = helper.runLongLived( + `wrangler dev ${flags} --port ${port} --inspector-port ${inspectorPort}` + ); const { url } = await worker.waitForReady(); const res = await fetch(url); diff --git a/packages/wrangler/e2e/pages-dev.test.ts b/packages/wrangler/e2e/pages-dev.test.ts index 6045bd0e1949..6971cae67d82 100644 --- a/packages/wrangler/e2e/pages-dev.test.ts +++ b/packages/wrangler/e2e/pages-dev.test.ts @@ -9,115 +9,117 @@ import { WranglerE2ETestHelper } from "./helpers/e2e-wrangler-test"; import { fetchText } from "./helpers/fetch-text"; import { normalizeOutput } from "./helpers/normalize"; -describe.each([{ cmd: "wrangler pages dev" }])("Pages $cmd", ({ cmd }) => { - it("should warn if no [--compatibility_date] command line arg was specified", async () => { - const helper = new WranglerE2ETestHelper(); - await helper.seed({ - "_worker.js": dedent` +const port = await getPort(); +const inspectorPort = await getPort(); + +describe.sequential.each([{ cmd: "wrangler pages dev" }])( + "Pages $cmd", + ({ cmd }) => { + it("should warn if no [--compatibility_date] command line arg was specified", async () => { + const helper = new WranglerE2ETestHelper(); + await helper.seed({ + "_worker.js": dedent` export default { fetch(request, env) { return new Response("Testing [--compatibility_date]") } }`, + }); + const worker = helper.runLongLived( + `${cmd} --port ${port} --inspector-port ${inspectorPort} .` + ); + const { url } = await worker.waitForReady(); + + const currentDate = new Date().toISOString().substring(0, 10); + const output = worker.currentOutput.replaceAll( + currentDate, + "" + ); + expect(output).toContain( + `No compatibility_date was specified. Using today's date: .` + ); + expect(output).toContain( + `❯❯ Add one to your Wrangler configuration file: compatibility_date = "", or` + ); + expect(output).toContain( + `❯❯ Pass it in your terminal: wrangler pages dev [] --compatibility-date=` + ); + + const text = await fetchText(url); + expect(text).toBe("Testing [--compatibility_date]"); }); - const port = await getPort(); - const worker = helper.runLongLived(`${cmd} --port ${port} .`); - const { url } = await worker.waitForReady(); - - const currentDate = new Date().toISOString().substring(0, 10); - const output = worker.currentOutput.replaceAll( - currentDate, - "" - ); - expect(output).toContain( - `No compatibility_date was specified. Using today's date: .` - ); - expect(output).toContain( - `❯❯ Add one to your Wrangler configuration file: compatibility_date = "", or` - ); - expect(output).toContain( - `❯❯ Pass it in your terminal: wrangler pages dev [] --compatibility-date=` - ); - - const text = await fetchText(url); - expect(text).toBe("Testing [--compatibility_date]"); - }); - - it("should warn that [--experimental-local] is no longer required, if specified", async () => { - const helper = new WranglerE2ETestHelper(); - const port = await getPort(); - const worker = helper.runLongLived( - `${cmd} --port ${port} . --experimental-local` - ); - await helper.seed({ - "_worker.js": dedent` + + it("should warn that [--experimental-local] is no longer required, if specified", async () => { + const helper = new WranglerE2ETestHelper(); + const worker = helper.runLongLived( + `${cmd} --port ${port} --inspector-port ${inspectorPort} . --experimental-local` + ); + await helper.seed({ + "_worker.js": dedent` export default { fetch(request, env) { return new Response("Testing [--experimental-local]") } }`, + }); + const { url } = await worker.waitForReady(); + const text = await fetchText(url); + expect(text).toBe("Testing [--experimental-local]"); + expect(await worker.currentOutput).toContain( + `--experimental-local is no longer required and will be removed in a future version` + ); + }); + + it("should show [--service] related warnings if specified as arg in the command line", async () => { + const helper = new WranglerE2ETestHelper(); + const worker = helper.runLongLived( + `${cmd} --port ${port} --inspector-port ${inspectorPort} . --service STAGING_SERVICE=test-worker@staging` + ); + + await worker.readUntil( + /Support for service binding environments is experimental/ + ); }); - const { url } = await worker.waitForReady(); - const text = await fetchText(url); - expect(text).toBe("Testing [--experimental-local]"); - expect(await worker.currentOutput).toContain( - `--experimental-local is no longer required and will be removed in a future version` - ); - }); - - it("should show [--service] related warnings if specified as arg in the command line", async () => { - const helper = new WranglerE2ETestHelper(); - const port = await getPort(); - const worker = helper.runLongLived( - `${cmd} --port ${port} . --service STAGING_SERVICE=test-worker@staging` - ); - - await worker.readUntil( - /Support for service binding environments is experimental/ - ); - }); - - it("should warn if bindings specified as args in the command line are invalid", async () => { - const helper = new WranglerE2ETestHelper(); - const port = await getPort(); - const worker = helper.runLongLived( - `${cmd} . --port ${port} --service test --kv = --do test --d1 = --r2 =` - ); - await worker.waitForReady(); - expect(await worker.currentOutput).toContain( - `Could not parse Service binding: test` - ); - expect(await worker.currentOutput).toContain( - `Could not parse KV binding: =` - ); - expect(await worker.currentOutput).toContain( - `Could not parse Durable Object binding: test` - ); - expect(await worker.currentOutput).toContain( - `Could not parse R2 binding: =` - ); - expect(await worker.currentOutput).toContain( - `Could not parse D1 binding: =` - ); - }); - - it("should use bindings specified as args in the command line", async () => { - const helper = new WranglerE2ETestHelper(); - await helper.seed({ - "_worker.js": dedent` + + it("should warn if bindings specified as args in the command line are invalid", async () => { + const helper = new WranglerE2ETestHelper(); + const worker = helper.runLongLived( + `${cmd} --inspector-port ${inspectorPort} . --port ${port} --service test --kv = --do test --d1 = --r2 =` + ); + await worker.waitForReady(); + expect(await worker.currentOutput).toContain( + `Could not parse Service binding: test` + ); + expect(await worker.currentOutput).toContain( + `Could not parse KV binding: =` + ); + expect(await worker.currentOutput).toContain( + `Could not parse Durable Object binding: test` + ); + expect(await worker.currentOutput).toContain( + `Could not parse R2 binding: =` + ); + expect(await worker.currentOutput).toContain( + `Could not parse D1 binding: =` + ); + }); + + it("should use bindings specified as args in the command line", async () => { + const helper = new WranglerE2ETestHelper(); + await helper.seed({ + "_worker.js": dedent` export default { fetch(request, env) { return new Response("Hello world") } }`, - }); - const port = await getPort(); - const worker = helper.runLongLived( - `${cmd} . --port ${port} --service TEST_SERVICE=test-worker --kv TEST_KV --do TEST_DO=TestDurableObject@a --d1 TEST_D1 --r2 TEST_R2` - ); - await worker.waitForReady(); - expect(normalizeOutput(worker.currentOutput)).toContain( - dedent`Your worker has access to the following bindings: + }); + const worker = helper.runLongLived( + `${cmd} --inspector-port ${inspectorPort} . --port ${port} --service TEST_SERVICE=test-worker --kv TEST_KV --do TEST_DO=TestDurableObject@a --d1 TEST_D1 --r2 TEST_R2` + ); + await worker.waitForReady(); + expect(normalizeOutput(worker.currentOutput)).toContain( + dedent`Your worker has access to the following bindings: - Durable Objects: - TEST_DO: TestDurableObject (defined in a [not connected]) - KV Namespaces: @@ -129,176 +131,180 @@ describe.each([{ cmd: "wrangler pages dev" }])("Pages $cmd", ({ cmd }) => { - Services: - TEST_SERVICE: test-worker [not connected] ` - ); - }); + ); + }); - it("should support wrangler.toml", async () => { - const helper = new WranglerE2ETestHelper(); - await helper.seed({ - "public/_worker.js": dedent` + it("should support wrangler.toml", async () => { + const helper = new WranglerE2ETestHelper(); + await helper.seed({ + "public/_worker.js": dedent` export default { async fetch(request, env) { return new Response("Pages supports wrangler.toml ⚡️⚡️") } }`, - "wrangler.toml": dedent` + "wrangler.toml": dedent` name = "pages-project" pages_build_output_dir = "public" compatibility_date = "2023-01-01" `, - }); - const port = await getPort(); - const worker = helper.runLongLived(`${cmd} --port ${port}`); - const { url } = await worker.waitForReady(); + }); + const worker = helper.runLongLived( + `${cmd} --port ${port} --inspector-port ${inspectorPort}` + ); + const { url } = await worker.waitForReady(); - const text = await fetchText(url); - expect(text).toBe("Pages supports wrangler.toml ⚡️⚡️"); - }); + const text = await fetchText(url); + expect(text).toBe("Pages supports wrangler.toml ⚡️⚡️"); + }); - it("should recover from syntax error during dev session (_worker)", async () => { - const helper = new WranglerE2ETestHelper(); - const worker = helper.runLongLived(`${cmd} .`); + it("should recover from syntax error during dev session (_worker)", async () => { + const helper = new WranglerE2ETestHelper(); + const worker = helper.runLongLived(`${cmd} .`); - await helper.seed({ - "_worker.js": dedent` + await helper.seed({ + "_worker.js": dedent` export default { fetch(request, env) { return new Response("Hello World!") } }`, - }); + }); - const { url } = await worker.waitForReady(); + const { url } = await worker.waitForReady(); - await expect(fetch(url).then((r) => r.text())).resolves.toBe( - "Hello World!" - ); + await expect(fetch(url).then((r) => r.text())).resolves.toBe( + "Hello World!" + ); - await helper.seed({ - "_worker.js": dedent` + await helper.seed({ + "_worker.js": dedent` export default { fetch(request, env) { return new Response("Updated Worker!") } // Syntax Error } }`, - }); + }); - await setTimeout(5_000); + await setTimeout(5_000); - await worker.readUntil(/Failed to build/); + await worker.readUntil(/Failed to build/); - // And then make sure Wrangler hasn't crashed - await helper.seed({ - "_worker.js": dedent` + // And then make sure Wrangler hasn't crashed + await helper.seed({ + "_worker.js": dedent` export default { fetch(request, env) { return new Response("Updated Worker!") } }`, - }); - await worker.waitForReload(); + }); + await worker.waitForReload(); - await expect(fetch(url).then((r) => r.text())).resolves.toBe( - "Updated Worker!" - ); - }); + await expect(fetch(url).then((r) => r.text())).resolves.toBe( + "Updated Worker!" + ); + }); - it("should recover from syntax error during dev session (Functions)", async () => { - const helper = new WranglerE2ETestHelper(); - const port = await getPort(); - const worker = helper.runLongLived(`${cmd} --port ${port} .`); + it("should recover from syntax error during dev session (Functions)", async () => { + const helper = new WranglerE2ETestHelper(); + const worker = helper.runLongLived( + `${cmd} --port ${port} --inspector-port ${inspectorPort} .` + ); - await helper.seed({ - "functions/_middleware.js": dedent` + await helper.seed({ + "functions/_middleware.js": dedent` export async function onRequest() { return new Response("Hello World!") }`, - }); + }); - const { url } = await worker.waitForReady(); + const { url } = await worker.waitForReady(); - await expect(fetch(url).then((r) => r.text())).resolves.toBe( - "Hello World!" - ); + await expect(fetch(url).then((r) => r.text())).resolves.toBe( + "Hello World!" + ); - await helper.seed({ - "functions/_middleware.js": dedent` + await helper.seed({ + "functions/_middleware.js": dedent` export async function onRequest() { return new Response("Updated Worker!") } // Syntax Error }`, - }); + }); - await setTimeout(5_000); + await setTimeout(5_000); - await worker.readUntil(/Failed to build Functions/); + await worker.readUntil(/Failed to build Functions/); - // And then make sure Wrangler hasn't crashed - await helper.seed({ - "functions/_middleware.js": dedent` + // And then make sure Wrangler hasn't crashed + await helper.seed({ + "functions/_middleware.js": dedent` export async function onRequest() { return new Response("Updated Worker!") }`, - }); - await worker.waitForReload(); + }); + await worker.waitForReload(); - await expect(fetch(url).then((r) => r.text())).resolves.toBe( - "Updated Worker!" - ); - }); + await expect(fetch(url).then((r) => r.text())).resolves.toBe( + "Updated Worker!" + ); + }); - it("should validate _routes.json during dev session, and fallback to default value", async () => { - const helper = new WranglerE2ETestHelper(); - await helper.seed({ - "functions/foo.ts": dedent` + it("should validate _routes.json during dev session, and fallback to default value", async () => { + const helper = new WranglerE2ETestHelper(); + await helper.seed({ + "functions/foo.ts": dedent` export async function onRequest() { return new Response("FOO"); }`, - "_routes.json": dedent` + "_routes.json": dedent` { "version": 1, "include": ["/foo"], "exclude": [] } `, - }); - const port = await getPort(); - const worker = helper.runLongLived(`${cmd} --port ${port} .`); + }); + const worker = helper.runLongLived( + `${cmd} --port ${port} --inspector-port ${inspectorPort} .` + ); - const { url } = await worker.waitForReady(); + const { url } = await worker.waitForReady(); - const foo = await fetchText(`${url}/foo`); + const foo = await fetchText(`${url}/foo`); - expect(foo).toBe("FOO"); + expect(foo).toBe("FOO"); - // invalid _routes.json because include rule does not start with `/` - await helper.seed({ - "_routes.json": dedent` + // invalid _routes.json because include rule does not start with `/` + await helper.seed({ + "_routes.json": dedent` { "version": 1, "include": ["foo"], "exclude": [] } `, - }); + }); - await worker.readUntil(/FatalError: Invalid _routes.json file found/); - await worker.readUntil(/All rules must start with '\/'/); - }); + await worker.readUntil(/FatalError: Invalid _routes.json file found/); + await worker.readUntil(/All rules must start with '\/'/); + }); - it("should use top-level configuration specified in `wrangler.toml`", async () => { - const helper = new WranglerE2ETestHelper(); - const port = await getPort(); - const worker = helper.runLongLived(`${cmd} --port ${port}`); - await helper.seed({ - "public/_worker.js": dedent` + it("should use top-level configuration specified in `wrangler.toml`", async () => { + const helper = new WranglerE2ETestHelper(); + const worker = helper.runLongLived( + `${cmd} --port ${port} --inspector-port ${inspectorPort}` + ); + await helper.seed({ + "public/_worker.js": dedent` export default { async fetch(request, env) { return new Response(env.PAGES + " " + "supports wrangler.toml") } }`, - "wrangler.toml": dedent` + "wrangler.toml": dedent` name = "pages-project" pages_build_output_dir = "public" # commenting this out would result in a warning. If there is no "compatibility_date" @@ -312,45 +318,45 @@ describe.each([{ cmd: "wrangler pages dev" }])("Pages $cmd", ({ cmd }) => { binding = "KV_BINDING_TOML" id = "KV_ID_TOML" `, - }); - const { url } = await worker.waitForReady(); + }); + const { url } = await worker.waitForReady(); - const text = await fetchText(url); + const text = await fetchText(url); - expect(text).toBe("⚡️ Pages ⚡️ supports wrangler.toml"); - expect(normalizeOutput(worker.currentOutput)).toContain( - dedent`Your worker has access to the following bindings: + expect(text).toBe("⚡️ Pages ⚡️ supports wrangler.toml"); + expect(normalizeOutput(worker.currentOutput)).toContain( + dedent`Your worker has access to the following bindings: - KV Namespaces: - KV_BINDING_TOML: KV_ID_TOML (local) - Vars: - PAGES: "⚡️ Pages ⚡️" ` - ); - }); - - it("should merge (with override) `wrangler.toml` configuration with configuration provided via the command line, with command line args taking precedence", async () => { - const helper = new WranglerE2ETestHelper(); - const port = await getPort(); - - const flags = [ - ` --binding VAR1=NEW_VAR_1 VAR3=VAR_3_ARGS`, - ` --kv KV_BINDING_1_TOML=NEW_KV_ID_1 KV_BINDING_3_ARGS=KV_ID_3_ARGS`, - ` --do DO_BINDING_1_TOML=NEW_DO_1@NEW_DO_SCRIPT_1 DO_BINDING_3_ARGS=DO_3_ARGS@DO_SCRIPT_3_ARGS`, - ` --d1 D1_BINDING_1_TOML=NEW_D1_NAME_1 D1_BINDING_3_ARGS=D1_NAME_3_ARGS`, - ` --r2 R2_BINDING_1_TOML=NEW_R2_BUCKET_1 R2_BINDING_3_TOML=R2_BUCKET_3_ARGS`, - ` --service SERVICE_BINDING_1_TOML=NEW_SERVICE_NAME_1 SERVICE_BINDING_3_TOML=SERVICE_NAME_3_ARGS`, - ` --ai AI_BINDING_2_TOML`, - ` --port ${port}`, - ]; - const worker = helper.runLongLived(`${cmd} ${flags.join("")}`); - await helper.seed({ - "public/_worker.js": dedent` + ); + }); + + it("should merge (with override) `wrangler.toml` configuration with configuration provided via the command line, with command line args taking precedence", async () => { + const helper = new WranglerE2ETestHelper(); + + const flags = [ + ` --binding VAR1=NEW_VAR_1 VAR3=VAR_3_ARGS`, + ` --kv KV_BINDING_1_TOML=NEW_KV_ID_1 KV_BINDING_3_ARGS=KV_ID_3_ARGS`, + ` --do DO_BINDING_1_TOML=NEW_DO_1@NEW_DO_SCRIPT_1 DO_BINDING_3_ARGS=DO_3_ARGS@DO_SCRIPT_3_ARGS`, + ` --d1 D1_BINDING_1_TOML=NEW_D1_NAME_1 D1_BINDING_3_ARGS=D1_NAME_3_ARGS`, + ` --r2 R2_BINDING_1_TOML=NEW_R2_BUCKET_1 R2_BINDING_3_TOML=R2_BUCKET_3_ARGS`, + ` --service SERVICE_BINDING_1_TOML=NEW_SERVICE_NAME_1 SERVICE_BINDING_3_TOML=SERVICE_NAME_3_ARGS`, + ` --ai AI_BINDING_2_TOML`, + ]; + const worker = helper.runLongLived( + `${cmd} --port ${port} --inspector-port ${inspectorPort} ${flags.join("")}` + ); + await helper.seed({ + "public/_worker.js": dedent` export default { async fetch(request, env) { return new Response("Pages supports wrangler.toml ⚡️") } }`, - "wrangler.toml": dedent` + "wrangler.toml": dedent` name = "pages-project" pages_build_output_dir = "public" compatibility_date = "2023-01-01" @@ -417,268 +423,275 @@ describe.each([{ cmd: "wrangler pages dev" }])("Pages $cmd", ({ cmd }) => { [ai] binding = "AI_BINDING_1_TOML" `, - }); - await worker.waitForReady(); + }); + await worker.waitForReady(); - // We only care about the list of bindings and warnings, so strip other output - const [prestartOutput] = normalizeOutput(worker.currentOutput).split( - "⎔ Starting local server..." - ); + // We only care about the list of bindings and warnings, so strip other output + const [prestartOutput] = normalizeOutput(worker.currentOutput).split( + "⎔ Starting local server..." + ); - expect(prestartOutput).toMatchSnapshot(); - }); + expect(prestartOutput).toMatchSnapshot(); + }); - it("should pick up wrangler.toml configuration even in cases when `pages_build_output_dir` was not specified, but the command argument was", async () => { - const helper = new WranglerE2ETestHelper(); + it("should pick up wrangler.toml configuration even in cases when `pages_build_output_dir` was not specified, but the command argument was", async () => { + const helper = new WranglerE2ETestHelper(); - await helper.seed({ - "public/_worker.js": dedent` + await helper.seed({ + "public/_worker.js": dedent` export default { async fetch(request, env) { return new Response(env.PAGES_EMOJI + " Pages supports wrangler.toml" + " " + env.PAGES_EMOJI) } }`, - "wrangler.toml": dedent` + "wrangler.toml": dedent` name = "pages-project" compatibility_date = "2023-01-01" [vars] PAGES_EMOJI = "⚡️" `, - }); + }); - const port = await getPort(); - const worker = helper.runLongLived(`${cmd} --port ${port} public`); - const { url } = await worker.waitForReady(); - await expect(fetchText(url)).resolves.toBe( - "⚡️ Pages supports wrangler.toml ⚡️" - ); - }); + const worker = helper.runLongLived( + `${cmd} --port ${port} --inspector-port ${inspectorPort} public` + ); + const { url } = await worker.waitForReady(); + await expect(fetchText(url)).resolves.toBe( + "⚡️ Pages supports wrangler.toml ⚡️" + ); + }); - describe("watch mode", () => { - it("should modify worker during dev session (Functions)", async () => { - const helper = new WranglerE2ETestHelper(); + describe("watch mode", () => { + it("should modify worker during dev session (Functions)", async () => { + const helper = new WranglerE2ETestHelper(); - await helper.seed({ - "functions/_middleware.js": dedent` + await helper.seed({ + "functions/_middleware.js": dedent` export async function onRequest() { return new Response("Hello World!") }`, - }); + }); - const port = await getPort(); - const worker = helper.runLongLived(`wrangler pages dev --port ${port} .`); - const { url } = await worker.waitForReady(); + const worker = helper.runLongLived( + `${cmd} --port ${port} --inspector-port ${inspectorPort} .` + ); + const { url } = await worker.waitForReady(); - let text = await fetchText(url); - expect(text).toBe("Hello World!"); + let text = await fetchText(url); + expect(text).toBe("Hello World!"); - await helper.seed({ - "functions/_middleware.js": dedent` + await helper.seed({ + "functions/_middleware.js": dedent` export async function onRequest() { return new Response("Updated Worker!") }`, - }); + }); - await worker.waitForReload(); + await worker.waitForReload(); - text = await fetchText(url); - expect(text).toBe("Updated Worker!"); + text = await fetchText(url); + expect(text).toBe("Updated Worker!"); - // Ensure Wrangler doesn't write tmp files in the functions directory—regression test for https://github.com/cloudflare/workers-sdk/issues/7440 - expect( - existsSync(path.join(helper.tmpPath, "functions/.wrangler")) - ).toBeFalsy(); - }); + // Ensure Wrangler doesn't write tmp files in the functions directory—regression test for https://github.com/cloudflare/workers-sdk/issues/7440 + expect( + existsSync(path.join(helper.tmpPath, "functions/.wrangler")) + ).toBeFalsy(); + }); - it("should support modifying dependencies during dev session (Functions)", async () => { - const helper = new WranglerE2ETestHelper(); + it("should support modifying dependencies during dev session (Functions)", async () => { + const helper = new WranglerE2ETestHelper(); - await helper.seed({ - "utils/greetings.js": dedent` + await helper.seed({ + "utils/greetings.js": dedent` export const hello = "Hello World!" export const hi = "Hi there!" `, - "functions/greetings/_middleware.js": dedent` + "functions/greetings/_middleware.js": dedent` import { hello } from "../../utils/greetings" export async function onRequest() { return new Response(hello) }`, - "functions/hi.js": dedent` + "functions/hi.js": dedent` import { hi } from "../utils/greetings" export async function onRequest() { return new Response(hi) }`, - }); + }); - const port = await getPort(); - const worker = helper.runLongLived(`wrangler pages dev --port ${port} .`); - const { url } = await worker.waitForReady(); + const worker = helper.runLongLived( + `${cmd} --port ${port} --inspector-port ${inspectorPort} .` + ); + const { url } = await worker.waitForReady(); - let hello = await fetchText(`${url}/greetings/hello`); - expect(hello).toBe("Hello World!"); + let hello = await fetchText(`${url}/greetings/hello`); + expect(hello).toBe("Hello World!"); - let hi = await fetchText(`${url}/hi`); - expect(hi).toBe("Hi there!"); + let hi = await fetchText(`${url}/hi`); + expect(hi).toBe("Hi there!"); - await helper.seed({ - "utils/greetings.js": dedent` + await helper.seed({ + "utils/greetings.js": dedent` export const hello = "Hey World!" export const hi = "Hey there!" `, - }); + }); - await worker.waitForReload(); + await worker.waitForReload(); - hello = await fetchText(`${url}/greetings/hello`); - expect(hello).toBe("Hey World!"); + hello = await fetchText(`${url}/greetings/hello`); + expect(hello).toBe("Hey World!"); - hi = await fetchText(`${url}/hi`); - expect(hi).toBe("Hey there!"); - }); + hi = await fetchText(`${url}/hi`); + expect(hi).toBe("Hey there!"); + }); - it("should support modifying external modules during dev session (Functions)", async () => { - const helper = new WranglerE2ETestHelper(); + it("should support modifying external modules during dev session (Functions)", async () => { + const helper = new WranglerE2ETestHelper(); - await helper.seed({ - "modules/my-html.html": dedent` + await helper.seed({ + "modules/my-html.html": dedent`

Hello HTML World!

`, - "functions/hello.js": dedent` + "functions/hello.js": dedent` import html from "../modules/my-html.html"; export async function onRequest() { return new Response(html); }`, - }); + }); - const port = await getPort(); - const worker = helper.runLongLived(`wrangler pages dev --port ${port} .`); - const { url } = await worker.waitForReady(); + const worker = helper.runLongLived( + `${cmd} --port ${port} --inspector-port ${inspectorPort} .` + ); + const { url } = await worker.waitForReady(); - let hello = await fetchText(`${url}/hello`); - expect(hello).toBe("

Hello HTML World!

"); + let hello = await fetchText(`${url}/hello`); + expect(hello).toBe("

Hello HTML World!

"); - await helper.seed({ - "modules/my-html.html": dedent` + await helper.seed({ + "modules/my-html.html": dedent`

Updated HTML!

`, - }); + }); - await worker.waitForReload(); + await worker.waitForReload(); - hello = await fetchText(`${url}/hello`); - expect(hello).toBe("

Updated HTML!

"); - }); + hello = await fetchText(`${url}/hello`); + expect(hello).toBe("

Updated HTML!

"); + }); - it("should modify worker during dev session (_worker)", async () => { - const helper = new WranglerE2ETestHelper(); + it("should modify worker during dev session (_worker)", async () => { + const helper = new WranglerE2ETestHelper(); - await helper.seed({ - "_worker.js": dedent` + await helper.seed({ + "_worker.js": dedent` export default { fetch(request, env) { return new Response("Hello World!") } }`, - }); + }); - const port = await getPort(); - const worker = helper.runLongLived(`wrangler pages dev --port ${port} .`); - const { url } = await worker.waitForReady(); + const worker = helper.runLongLived( + `${cmd} --port ${port} --inspector-port ${inspectorPort} .` + ); + const { url } = await worker.waitForReady(); - let hello = await fetchText(url); - expect(hello).toBe("Hello World!"); + let hello = await fetchText(url); + expect(hello).toBe("Hello World!"); - await helper.seed({ - "_worker.js": dedent` + await helper.seed({ + "_worker.js": dedent` export default { fetch(request, env) { return new Response("Updated Worker!") } }`, - }); + }); - await worker.waitForReload(); + await worker.waitForReload(); - hello = await fetchText(url); - expect(hello).toBe("Updated Worker!"); - }); + hello = await fetchText(url); + expect(hello).toBe("Updated Worker!"); + }); - it("should support modifying dependencies during dev session (_worker)", async () => { - const helper = new WranglerE2ETestHelper(); + it("should support modifying dependencies during dev session (_worker)", async () => { + const helper = new WranglerE2ETestHelper(); - await helper.seed({ - "pets/bear.js": dedent` + await helper.seed({ + "pets/bear.js": dedent` export const bear = "BEAR!" `, - "_worker.js": dedent` + "_worker.js": dedent` import { bear } from "./pets/bear" export default { fetch(request, env) { return new Response(bear) } }`, - }); + }); - const port = await getPort(); - const worker = helper.runLongLived(`wrangler pages dev --port ${port} .`); - const { url } = await worker.waitForReady(); + const worker = helper.runLongLived( + `${cmd} --port ${port} --inspector-port ${inspectorPort} .` + ); + const { url } = await worker.waitForReady(); - let bear = await fetchText(url); - expect(bear).toBe("BEAR!"); + let bear = await fetchText(url); + expect(bear).toBe("BEAR!"); - await helper.seed({ - "pets/bear.js": dedent` + await helper.seed({ + "pets/bear.js": dedent` export const bear = "We love BEAR!" `, - }); + }); - await worker.waitForReload(); + await worker.waitForReload(); - bear = await fetchText(url); - expect(bear).toBe("We love BEAR!"); - }); + bear = await fetchText(url); + expect(bear).toBe("We love BEAR!"); + }); - it("should support modifying external modules during dev session (_worker)", async () => { - const helper = new WranglerE2ETestHelper(); + it("should support modifying external modules during dev session (_worker)", async () => { + const helper = new WranglerE2ETestHelper(); - await helper.seed({ - "graham.html": dedent` + await helper.seed({ + "graham.html": dedent`

Graham the dog

`, - "_worker.js": dedent` + "_worker.js": dedent` import html from "./graham.html" export default { fetch(request, env) { return new Response(html) } }`, - }); + }); - const port = await getPort(); - const worker = helper.runLongLived(`wrangler pages dev --port ${port} .`); - const { url } = await worker.waitForReady(); + const worker = helper.runLongLived( + `${cmd} --port ${port} --inspector-port ${inspectorPort} .` + ); + const { url } = await worker.waitForReady(); - let graham = await fetchText(url); - expect(graham).toBe("

Graham the dog

"); + let graham = await fetchText(url); + expect(graham).toBe("

Graham the dog

"); - await helper.seed({ - "graham.html": dedent` + await helper.seed({ + "graham.html": dedent`

Graham is the bestest doggo

`, - }); + }); - await worker.waitForReload(); + await worker.waitForReload(); - graham = await fetchText(url); - expect(graham).toBe("

Graham is the bestest doggo

"); - }); + graham = await fetchText(url); + expect(graham).toBe("

Graham is the bestest doggo

"); + }); - it("should support modifying _routes.json during dev session", async () => { - const helper = new WranglerE2ETestHelper(); + it("should support modifying _routes.json during dev session", async () => { + const helper = new WranglerE2ETestHelper(); - await helper.seed({ - "_worker.js": dedent` + await helper.seed({ + "_worker.js": dedent` export default { async fetch(request, env) { const url = new URL(request.url); @@ -691,43 +704,45 @@ describe.each([{ cmd: "wrangler pages dev" }])("Pages $cmd", ({ cmd }) => { return new Response("Hello _routes.json") } }`, - "_routes.json": dedent` + "_routes.json": dedent` { "version": 1, "include": ["/foo", "/bar"], "exclude": [] } `, - "index.html": dedent` + "index.html": dedent` hello world `, - }); - const port = await getPort(); - const worker = helper.runLongLived(`wrangler pages dev --port ${port} .`); - const { url } = await worker.waitForReady(); + }); + const worker = helper.runLongLived( + `${cmd} --port ${port} --inspector-port ${inspectorPort} .` + ); + const { url } = await worker.waitForReady(); - const foo = await fetchText(`${url}/foo`); - expect(foo).toBe("foo"); + const foo = await fetchText(`${url}/foo`); + expect(foo).toBe("foo"); - const bar = await fetchText(`${url}/bar`); - expect(bar).toBe("bar"); + const bar = await fetchText(`${url}/bar`); + expect(bar).toBe("bar"); - await helper.seed({ - "_routes.json": dedent` + await helper.seed({ + "_routes.json": dedent` { "version": 1, "include": ["/foo"], "exclude": ["/bar"] } `, - }); - await worker.waitForReload(); + }); + await worker.waitForReload(); - const foo2 = await fetchText(`${url}/foo`); - expect(foo2).toBe("foo"); + const foo2 = await fetchText(`${url}/foo`); + expect(foo2).toBe("foo"); - const bar2 = await fetchText(`${url}/bar`); - expect(bar2).toBe("hello world"); + const bar2 = await fetchText(`${url}/bar`); + expect(bar2).toBe("hello world"); + }); }); - }); -}); + } +); diff --git a/packages/wrangler/package.json b/packages/wrangler/package.json index d9a8fbba8837..17bb0b1ffcfb 100644 --- a/packages/wrangler/package.json +++ b/packages/wrangler/package.json @@ -61,10 +61,10 @@ "generate-json-schema": "pnpm exec ts-json-schema-generator --no-type-check --path src/config/config.ts --type RawConfig --out config-schema.json", "prepublishOnly": "SOURCEMAPS=false pnpm run -w build", "start": "pnpm run bundle && cross-env NODE_OPTIONS=--enable-source-maps ./bin/wrangler.js", - "test": "pnpm run assert-git-version && vitest", + "test": "dotenv -- pnpm run assert-git-version && dotenv -- vitest", "test:ci": "pnpm run test run", "test:debug": "pnpm run test --silent=false --verbose=true", - "test:e2e": "vitest -c ./e2e/vitest.config.mts", + "test:e2e": "dotenv -- vitest -c ./e2e/vitest.config.mts", "test:watch": "pnpm run test --testTimeout=50000 --watch", "type:tests": "tsc -p ./src/__tests__/tsconfig.json && tsc -p ./e2e/tsconfig.json" }, diff --git a/packages/wrangler/src/__tests__/configuration.pages.test.ts b/packages/wrangler/src/__tests__/config/configuration.pages.test.ts similarity index 98% rename from packages/wrangler/src/__tests__/configuration.pages.test.ts rename to packages/wrangler/src/__tests__/config/configuration.pages.test.ts index 9b7ae8155208..42063bf5954b 100644 --- a/packages/wrangler/src/__tests__/configuration.pages.test.ts +++ b/packages/wrangler/src/__tests__/config/configuration.pages.test.ts @@ -1,10 +1,10 @@ import path from "node:path"; -import { normalizeAndValidateConfig } from "../config/validation"; +import { normalizeAndValidateConfig } from "../../config/validation"; import { generateRawConfigForPages, generateRawEnvConfigForPages, -} from "./helpers/generate-wrangler-config"; -import type { RawConfig, RawEnvironment } from "../config"; +} from "../helpers/generate-wrangler-config"; +import type { RawConfig, RawEnvironment } from "../../config"; describe("normalizeAndValidateConfig()", () => { describe("Pages configuration", () => { @@ -30,6 +30,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( pagesRawConfig, undefined, + undefined, { env: undefined, } @@ -130,6 +131,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( pagesRawConfig, undefined, + undefined, { env: "preview", } @@ -230,6 +232,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( pagesRawConfig, undefined, + undefined, { env: "production", } @@ -349,6 +352,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( pagesRawConfig, undefined, + undefined, { env: "unsupported-env-name", } @@ -457,6 +461,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( pagesRawConfig, undefined, + undefined, { env: "preview", } @@ -565,6 +570,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( pagesRawConfig, undefined, + undefined, { env: "production", } @@ -671,6 +677,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( pagesRawConfig, undefined, + undefined, { env: "unsupported-env-name", } @@ -780,6 +787,7 @@ describe("normalizeAndValidateConfig()", () => { ], }, undefined, + undefined, { env: undefined } ); @@ -800,6 +808,7 @@ describe("normalizeAndValidateConfig()", () => { }, }, undefined, + undefined, { env: "preview", } diff --git a/packages/wrangler/src/__tests__/configuration.test.ts b/packages/wrangler/src/__tests__/config/configuration.test.ts similarity index 97% rename from packages/wrangler/src/__tests__/configuration.test.ts rename to packages/wrangler/src/__tests__/config/configuration.test.ts index 5083e0a84602..d0e511057d82 100644 --- a/packages/wrangler/src/__tests__/configuration.test.ts +++ b/packages/wrangler/src/__tests__/config/configuration.test.ts @@ -1,17 +1,17 @@ import * as fs from "fs"; import path from "node:path"; -import { experimental_readRawConfig, readConfig } from "../config"; -import { normalizeAndValidateConfig } from "../config/validation"; -import { run } from "../experimental-flags"; -import { normalizeString } from "./helpers/normalize"; -import { runInTempDir } from "./helpers/run-in-tmp"; -import { writeWranglerConfig } from "./helpers/write-wrangler-config"; +import { experimental_readRawConfig, readConfig } from "../../config"; +import { normalizeAndValidateConfig } from "../../config/validation"; +import { run } from "../../experimental-flags"; +import { normalizeString } from "../helpers/normalize"; +import { runInTempDir } from "../helpers/run-in-tmp"; +import { writeWranglerConfig } from "../helpers/write-wrangler-config"; import type { ConfigFields, RawConfig, RawDevConfig, RawEnvironment, -} from "../config"; +} from "../../config"; describe("readConfig()", () => { runInTempDir(); @@ -49,9 +49,14 @@ describe("readConfig()", () => { describe("normalizeAndValidateConfig()", () => { it("should use defaults for empty configuration", () => { - const { config, diagnostics } = normalizeAndValidateConfig({}, undefined, { - env: undefined, - }); + const { config, diagnostics } = normalizeAndValidateConfig( + {}, + undefined, + undefined, + { + env: undefined, + } + ); expect(config).toEqual({ account_id: undefined, @@ -157,6 +162,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( expectedConfig, undefined, + undefined, { env: undefined } ); @@ -181,6 +187,8 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( expectedConfig as unknown as RawConfig, undefined, + undefined, + { env: undefined } ); @@ -210,6 +218,8 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( expectedConfig as unknown as RawConfig, undefined, + undefined, + { env: undefined } ); @@ -231,6 +241,8 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( expectedConfig as unknown as RawConfig, undefined, + undefined, + { env: undefined } ); @@ -251,6 +263,8 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( expectedConfig as unknown as RawConfig, undefined, + undefined, + { env: undefined } ); @@ -272,6 +286,8 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( expectedConfig as unknown as RawConfig, undefined, + undefined, + { env: undefined } ); @@ -294,6 +310,8 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( expectedConfig, undefined, + undefined, + { env: undefined } ); @@ -307,9 +325,14 @@ describe("normalizeAndValidateConfig()", () => { compatibility_date: "2024–10–01", // en-dash }; - const result = normalizeAndValidateConfig(expectedConfig, undefined, { - env: undefined, - }); + const result = normalizeAndValidateConfig( + expectedConfig, + undefined, + undefined, + { + env: undefined, + } + ); expect(result.config).toEqual(expect.objectContaining(expectedConfig)); expect(result.diagnostics.hasWarnings()).toBe(false); @@ -327,9 +350,14 @@ describe("normalizeAndValidateConfig()", () => { compatibility_date: "2024—10—01", // em-dash }; - const result = normalizeAndValidateConfig(expectedConfig, undefined, { - env: undefined, - }); + const result = normalizeAndValidateConfig( + expectedConfig, + undefined, + undefined, + { + env: undefined, + } + ); expect(result.config).toEqual(expect.objectContaining(expectedConfig)); expect(result.diagnostics.hasWarnings()).toBe(false); @@ -350,6 +378,8 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( expectedConfig, undefined, + undefined, + { env: undefined } ); @@ -368,9 +398,14 @@ describe("normalizeAndValidateConfig()", () => { compatibility_date: "2024—100—01", // invalid date + em-dash }; - const result = normalizeAndValidateConfig(expectedConfig, undefined, { - env: undefined, - }); + const result = normalizeAndValidateConfig( + expectedConfig, + undefined, + undefined, + { + env: undefined, + } + ); expect(result.config).toEqual(expect.objectContaining(expectedConfig)); expect(result.diagnostics.hasWarnings()).toBe(false); @@ -399,6 +434,8 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( expectedConfig, undefined, + undefined, + { env: undefined } ); @@ -430,6 +467,8 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( expectedConfig, undefined, + undefined, + { env: undefined } ); @@ -466,6 +505,8 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( expectedConfig as unknown as RawConfig, undefined, + undefined, + { env: undefined } ); @@ -500,6 +541,8 @@ describe("normalizeAndValidateConfig()", () => { }, } as unknown as RawConfig, undefined, + undefined, + { env: undefined } ); @@ -533,6 +576,8 @@ describe("normalizeAndValidateConfig()", () => { alias: "some silly string", } as unknown as RawConfig, undefined, + undefined, + { env: undefined } ); @@ -553,6 +598,8 @@ describe("normalizeAndValidateConfig()", () => { }, } as unknown as RawConfig, undefined, + undefined, + { env: undefined } ); @@ -573,6 +620,8 @@ describe("normalizeAndValidateConfig()", () => { }, } as unknown as RawConfig, undefined, + undefined, + { env: undefined } ); @@ -594,6 +643,8 @@ describe("normalizeAndValidateConfig()", () => { legacy_assets: "path/to/assets", } as unknown as RawConfig, undefined, + undefined, + { env: undefined } ); @@ -622,6 +673,8 @@ describe("normalizeAndValidateConfig()", () => { legacy_assets: 123, } as unknown as RawConfig, undefined, + undefined, + { env: undefined } ); expect(config.legacy_assets).toBeUndefined(); @@ -651,6 +704,8 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( expectedConfig, undefined, + undefined, + { env: undefined } ); @@ -685,6 +740,8 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( expectedConfig as unknown as RawConfig, undefined, + undefined, + { env: undefined } ); @@ -718,6 +775,8 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( expectedConfig, "project/wrangler.toml", + "project/wrangler.toml", + { env: undefined } ); @@ -746,6 +805,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( expectedConfig, "project/wrangler.toml", + "project/wrangler.toml", { env: undefined } ); @@ -778,6 +838,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( expectedConfig as unknown as RawConfig, "project/wrangler.toml", + "project/wrangler.toml", { env: undefined } ); @@ -805,6 +866,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( expectedConfig, "project/wrangler.toml", + "project/wrangler.toml", { env: undefined } ); @@ -831,6 +893,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( expectedConfig as unknown as RawConfig, "project/wrangler.toml", + "project/wrangler.toml", { env: undefined } ); @@ -858,6 +921,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( expectedConfig, "project/wrangler.toml", + "project/wrangler.toml", { env: undefined } ); @@ -884,6 +948,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( expectedConfig as unknown as RawConfig, "project/wrangler.toml", + "project/wrangler.toml", { env: undefined } ); @@ -908,6 +973,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( expectedConfig, "project/wrangler.toml", + "project/wrangler.toml", { env: undefined } ); @@ -931,6 +997,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( rawConfig, undefined, + undefined, { env: undefined } ); @@ -968,6 +1035,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( expectedConfig, "project/wrangler.toml", + "project/wrangler.toml", { env: undefined } ); @@ -1122,6 +1190,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( expectedConfig, "wrangler.toml", + "wrangler.toml", { env: undefined } ); @@ -1206,6 +1275,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( expectedConfig, undefined, + undefined, { env: undefined } ); @@ -1287,6 +1357,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( expectedConfig, undefined, + undefined, { env: undefined } ); @@ -1307,6 +1378,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( expectedConfig, undefined, + undefined, { env: undefined } ); @@ -1323,6 +1395,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( expectedConfig, undefined, + undefined, { env: undefined } ); @@ -1342,6 +1415,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( expectedConfig, undefined, + undefined, { env: undefined } ); @@ -1360,6 +1434,7 @@ describe("normalizeAndValidateConfig()", () => { main: "index.js", }, undefined, + undefined, { env: undefined, "dispatch-namespace": "test-namespace" } ); expect(diagnostics.hasWarnings()).toBe(false); @@ -1383,6 +1458,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( expectedConfig, path.resolve("project/wrangler.toml"), + path.resolve("project/wrangler.toml"), { env: undefined } ); @@ -1423,6 +1499,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( expectedConfig, undefined, + undefined, { env: undefined } ); @@ -1448,6 +1525,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( expectedConfig, "project/wrangler.toml", + "project/wrangler.toml", { env: undefined } ); @@ -1473,6 +1551,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( expectedConfig, "project/wrangler.toml", + "project/wrangler.toml", { env: undefined } ); @@ -1510,6 +1589,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( expectedConfig, "project/wrangler.toml", + "project/wrangler.toml", { env: undefined } ); @@ -1543,6 +1623,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { durable_objects: [] } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -1557,6 +1638,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { durable_objects: "BAD" } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -1571,6 +1653,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { durable_objects: 999 } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -1585,6 +1668,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { durable_objects: null } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -1599,6 +1683,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { durable_objects: {} } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -1613,6 +1698,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { durable_objects: { bindings: {} } } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -1627,6 +1713,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { durable_objects: { bindings: "BAD" } } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -1641,6 +1728,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { durable_objects: { bindings: 999 } } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -1655,6 +1743,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { durable_objects: { bindings: null } } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -1698,6 +1787,7 @@ describe("normalizeAndValidateConfig()", () => { }, } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -1763,6 +1853,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( expectedConfig, undefined, + undefined, { env: undefined } ); @@ -1792,6 +1883,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( expectedConfig as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -1835,6 +1927,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( expectedConfig as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -1863,6 +1956,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( expectedConfig, undefined, + undefined, { env: undefined } ); @@ -1882,6 +1976,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( expectedConfig as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -1909,6 +2004,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( expectedConfig as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -1937,6 +2033,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( expectedConfig, undefined, + undefined, { env: undefined } ); @@ -1957,6 +2054,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( expectedConfig as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -1974,6 +2072,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { browser: [] } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -1988,6 +2087,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { browser: "BAD" } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -2002,6 +2102,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { browser: 999 } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -2016,6 +2117,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { browser: null } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -2033,6 +2135,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { vectorize: {} } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -2058,6 +2161,7 @@ describe("normalizeAndValidateConfig()", () => { ], } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -2076,6 +2180,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { vectorize: "BAD" } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -2090,6 +2195,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { vectorize: 999 } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -2104,6 +2210,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { vectorize: null } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -2121,6 +2228,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { ai: [] } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -2135,6 +2243,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { ai: "BAD" } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -2149,6 +2258,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { ai: 999 } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -2163,6 +2273,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { ai: null } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -2180,6 +2291,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { version_metadata: [] } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -2194,6 +2306,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { version_metadata: "BAD" } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -2208,6 +2321,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { version_metadata: 999 } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -2222,6 +2336,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { version_metadata: null } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -2238,6 +2353,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { cloudchamber: null } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -2252,6 +2368,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { cloudchamber: [] } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -2266,6 +2383,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { cloudchamber: "test" } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -2280,6 +2398,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { cloudchamber: 22 } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -2302,6 +2421,7 @@ describe("normalizeAndValidateConfig()", () => { }, } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -2322,6 +2442,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { kv_namespaces: {} } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -2336,6 +2457,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { kv_namespaces: "BAD" } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -2350,6 +2472,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { kv_namespaces: 999 } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -2364,6 +2487,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { kv_namespaces: null } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -2390,6 +2514,7 @@ describe("normalizeAndValidateConfig()", () => { ], } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -2419,6 +2544,7 @@ describe("normalizeAndValidateConfig()", () => { kv_namespaces: [{ binding: "VALID" }], } as unknown as RawConfig, undefined, + undefined, { env: undefined } ) ); @@ -2447,6 +2573,7 @@ describe("normalizeAndValidateConfig()", () => { ], } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -2466,6 +2593,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { d1_databases: {} } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -2480,6 +2608,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { d1_databases: "BAD" } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -2494,6 +2623,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { d1_databases: 999 } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -2508,6 +2638,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { d1_databases: null } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -2534,6 +2665,7 @@ describe("normalizeAndValidateConfig()", () => { ], } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(` @@ -2568,6 +2700,7 @@ describe("normalizeAndValidateConfig()", () => { d1_databases: [{ binding: "VALID" }], } as unknown as RawConfig, undefined, + undefined, { env: undefined } ) ); @@ -2582,6 +2715,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { hyperdrive: {} } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -2596,6 +2730,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { hyperdrive: "BAD" } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -2610,6 +2745,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { hyperdrive: 999 } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -2624,6 +2760,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { hyperdrive: null } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -2642,6 +2779,7 @@ describe("normalizeAndValidateConfig()", () => { ], } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -2658,6 +2796,7 @@ describe("normalizeAndValidateConfig()", () => { ], } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(` @@ -2680,6 +2819,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( { queues: [] } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -2707,6 +2847,7 @@ describe("normalizeAndValidateConfig()", () => { }, } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -2753,6 +2894,7 @@ describe("normalizeAndValidateConfig()", () => { }, } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -2786,6 +2928,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { r2_buckets: {} } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -2800,6 +2943,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { r2_buckets: "BAD" } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -2814,6 +2958,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { r2_buckets: 999 } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -2828,6 +2973,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { r2_buckets: null } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -2854,6 +3000,7 @@ describe("normalizeAndValidateConfig()", () => { ], } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -2883,6 +3030,7 @@ describe("normalizeAndValidateConfig()", () => { d1_databases: [{ binding: "VALID" }], } as unknown as RawConfig, undefined, + undefined, { env: undefined } ) ); @@ -2897,6 +3045,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { services: {} } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -2916,6 +3065,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { services: "BAD" } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -2935,6 +3085,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { services: 999 } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -2954,6 +3105,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { services: null } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -3002,6 +3154,7 @@ describe("normalizeAndValidateConfig()", () => { ], } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -3038,6 +3191,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { analytics_engine_datasets: {} } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -3052,6 +3206,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { analytics_engine_datasets: "BAD" } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -3066,6 +3221,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { analytics_engine_datasets: 999 } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -3080,6 +3236,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { analytics_engine_datasets: null } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -3104,6 +3261,7 @@ describe("normalizeAndValidateConfig()", () => { ], } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -3126,6 +3284,7 @@ describe("normalizeAndValidateConfig()", () => { dispatch_namespaces: "just a string", } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -3167,6 +3326,7 @@ describe("normalizeAndValidateConfig()", () => { ], } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); expect(diagnostics.hasWarnings()).toBe(false); @@ -3265,6 +3425,7 @@ describe("normalizeAndValidateConfig()", () => { ], } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); expect(diagnostics.hasWarnings()).toBe(false); @@ -3299,6 +3460,7 @@ describe("normalizeAndValidateConfig()", () => { mtls_certificates: "just a string", } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -3341,6 +3503,7 @@ describe("normalizeAndValidateConfig()", () => { ], } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -3373,6 +3536,7 @@ describe("normalizeAndValidateConfig()", () => { // @ts-expect-error purposely using an invalid value { pipelines: {} }, undefined, + undefined, { env: undefined } ); @@ -3388,6 +3552,7 @@ describe("normalizeAndValidateConfig()", () => { // @ts-expect-error purposely using an invalid value { pipelines: "BAD" }, undefined, + undefined, { env: undefined } ); @@ -3403,6 +3568,7 @@ describe("normalizeAndValidateConfig()", () => { // @ts-expect-error purposely using an invalid value { pipelines: 999 }, undefined, + undefined, { env: undefined } ); @@ -3418,6 +3584,7 @@ describe("normalizeAndValidateConfig()", () => { // @ts-expect-error purposely using an invalid value { pipelines: null }, undefined, + undefined, { env: undefined } ); @@ -3439,6 +3606,7 @@ describe("normalizeAndValidateConfig()", () => { ], } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -3458,6 +3626,7 @@ describe("normalizeAndValidateConfig()", () => { ], } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(` @@ -3480,6 +3649,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { unsafe: [] } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -3497,6 +3667,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { unsafe: "BAD" } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -3514,6 +3685,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { unsafe: 999 } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -3531,6 +3703,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { unsafe: null } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -3548,6 +3721,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { unsafe: {} } satisfies RawConfig, undefined, + undefined, { env: undefined } ); @@ -3569,6 +3743,7 @@ describe("normalizeAndValidateConfig()", () => { }, } as RawConfig, undefined, + undefined, { env: undefined } ); @@ -3587,6 +3762,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { unsafe: { bindings: {} } } as RawConfig, undefined, + undefined, { env: undefined } ); @@ -3604,6 +3780,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { unsafe: { bindings: "BAD" } } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -3621,6 +3798,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { unsafe: { bindings: 999 } } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -3638,6 +3816,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { unsafe: { bindings: null } } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -3668,6 +3847,7 @@ describe("normalizeAndValidateConfig()", () => { }, } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -3695,6 +3875,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { unsafe: { metadata: [] } } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -3712,6 +3893,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { unsafe: { metadata: "BAD" } } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -3729,6 +3911,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { unsafe: { metadata: 999 } } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -3746,6 +3929,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { unsafe: { metadata: null } } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -3765,6 +3949,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { unsafe: { bindings: [] } } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -3778,6 +3963,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { placement: { mode: "off", hint: "wnam" } }, undefined, + undefined, { env: undefined } ); @@ -3791,6 +3977,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { placement: { mode: "smart", hint: "wnam" } }, undefined, + undefined, { env: undefined } ); @@ -3814,6 +4001,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( rawConfig, undefined, + undefined, { env: undefined } ); @@ -3842,6 +4030,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( rawConfig, undefined, + undefined, { env: undefined } ); @@ -3862,6 +4051,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics, config } = normalizeAndValidateConfig( rawConfig, undefined, + undefined, { env: "dev", } @@ -3891,9 +4081,14 @@ describe("normalizeAndValidateConfig()", () => { it("should error if we specify an environment that does not match the named environments", () => { const rawConfig: RawConfig = { env: { ENV1: {} } }; - const { diagnostics } = normalizeAndValidateConfig(rawConfig, undefined, { - env: "DEV", - }); + const { diagnostics } = normalizeAndValidateConfig( + rawConfig, + undefined, + undefined, + { + env: "DEV", + } + ); expect(diagnostics.renderErrors()).toMatchInlineSnapshot(` "Processing wrangler configuration: - No environment found in configuration with name \\"DEV\\". @@ -3948,6 +4143,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( { ...rawConfig, env: { dev: {} } }, undefined, + undefined, { env: "dev" } ); @@ -4028,6 +4224,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( rawConfig, undefined, + undefined, { env: "ENV1" } ); @@ -4049,6 +4246,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( rawConfig, undefined, + undefined, { env: "DEV" } ); @@ -4074,6 +4272,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( rawConfig, undefined, + undefined, { env: "DEV" } ); @@ -4107,6 +4306,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( rawConfig, undefined, + undefined, { env: "DEV" } ); @@ -4139,6 +4339,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( rawConfig, undefined, + undefined, { env: "DEV" } ); @@ -4171,6 +4372,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( rawConfig, undefined, + undefined, { env: "DEV" } ); @@ -4225,6 +4427,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( rawConfig, undefined, + undefined, { env: "ENV1" } ); @@ -4299,6 +4502,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( { env: { ENV1: expectedConfig } }, undefined, + undefined, { env: "ENV1" } ); @@ -4347,6 +4551,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( rawConfig, undefined, + undefined, { env: undefined } ); @@ -4363,6 +4568,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( rawConfig, undefined, + undefined, { env: undefined } ); @@ -4395,6 +4601,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( rawConfig, undefined, + undefined, { env: undefined } ); @@ -4429,6 +4636,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( rawConfig, undefined, + undefined, { env: "ENV1" } ); @@ -4454,6 +4662,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( rawConfig, undefined, + undefined, { env: "ENV1" } ); @@ -4489,6 +4698,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( rawConfig, undefined, + undefined, { env: "ENV1" } ); @@ -4538,6 +4748,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( rawConfig, undefined, + undefined, { env: "ENV1" } ); @@ -4563,6 +4774,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { env: { ENV1: { durable_objects: [] } } } as unknown as RawConfig, undefined, + undefined, { env: "ENV1" } ); @@ -4579,6 +4791,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { env: { ENV1: { durable_objects: "BAD" } } } as unknown as RawConfig, undefined, + undefined, { env: "ENV1" } ); @@ -4595,6 +4808,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { env: { ENV1: { durable_objects: 999 } } } as unknown as RawConfig, undefined, + undefined, { env: "ENV1" } ); @@ -4611,6 +4825,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { env: { ENV1: { durable_objects: null } } } as unknown as RawConfig, undefined, + undefined, { env: "ENV1" } ); @@ -4627,6 +4842,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { env: { ENV1: { durable_objects: {} } } } as unknown as RawConfig, undefined, + undefined, { env: "ENV1" } ); @@ -4645,6 +4861,7 @@ describe("normalizeAndValidateConfig()", () => { env: { ENV1: { durable_objects: { bindings: {} } } }, } as unknown as RawConfig, undefined, + undefined, { env: "ENV1" } ); @@ -4663,6 +4880,7 @@ describe("normalizeAndValidateConfig()", () => { env: { ENV1: { durable_objects: { bindings: "BAD" } } }, } as unknown as RawConfig, undefined, + undefined, { env: "ENV1" } ); @@ -4681,6 +4899,7 @@ describe("normalizeAndValidateConfig()", () => { env: { ENV1: { durable_objects: { bindings: 999 } } }, } as unknown as RawConfig, undefined, + undefined, { env: "ENV1" } ); @@ -4699,6 +4918,7 @@ describe("normalizeAndValidateConfig()", () => { env: { ENV1: { durable_objects: { bindings: null } } }, } as unknown as RawConfig, undefined, + undefined, { env: "ENV1" } ); @@ -4732,6 +4952,7 @@ describe("normalizeAndValidateConfig()", () => { }, } as unknown as RawConfig, undefined, + undefined, { env: "ENV1" } ); @@ -4782,6 +5003,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( { env: { ENV1: expectedConfig } }, undefined, + undefined, { env: "ENV1" } ); @@ -4811,6 +5033,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( { env: { ENV1: expectedConfig as unknown as RawConfig } }, undefined, + undefined, { env: "ENV1" } ); @@ -4856,6 +5079,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( { env: { ENV1: expectedConfig as unknown as RawConfig } }, undefined, + undefined, { env: "ENV1" } ); @@ -4881,6 +5105,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { env: { ENV1: { kv_namespaces: {} } } } as unknown as RawConfig, undefined, + undefined, { env: "ENV1" } ); @@ -4897,6 +5122,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { env: { ENV1: { kv_namespaces: "BAD" } } } as unknown as RawConfig, undefined, + undefined, { env: "ENV1" } ); @@ -4913,6 +5139,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { env: { ENV1: { kv_namespaces: 999 } } } as unknown as RawConfig, undefined, + undefined, { env: "ENV1" } ); @@ -4929,6 +5156,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { env: { ENV1: { kv_namespaces: null } } } as unknown as RawConfig, undefined, + undefined, { env: "ENV1" } ); @@ -4960,6 +5188,7 @@ describe("normalizeAndValidateConfig()", () => { }, } as unknown as RawConfig, undefined, + undefined, { env: "ENV1" } ); @@ -4983,6 +5212,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { env: { ENV1: { r2_buckets: {} } } } as unknown as RawConfig, undefined, + undefined, { env: "ENV1" } ); @@ -4999,6 +5229,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { env: { ENV1: { r2_buckets: "BAD" } } } as unknown as RawConfig, undefined, + undefined, { env: "ENV1" } ); @@ -5015,6 +5246,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { env: { ENV1: { r2_buckets: 999 } } } as unknown as RawConfig, undefined, + undefined, { env: "ENV1" } ); @@ -5031,6 +5263,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { env: { ENV1: { r2_buckets: null } } } as unknown as RawConfig, undefined, + undefined, { env: "ENV1" } ); @@ -5062,6 +5295,7 @@ describe("normalizeAndValidateConfig()", () => { }, } as unknown as RawConfig, undefined, + undefined, { env: "ENV1" } ); @@ -5087,6 +5321,7 @@ describe("normalizeAndValidateConfig()", () => { env: { ENV1: { analytics_engine_datasets: {} } }, } as unknown as RawConfig, undefined, + undefined, { env: "ENV1" } ); @@ -5105,6 +5340,7 @@ describe("normalizeAndValidateConfig()", () => { env: { ENV1: { analytics_engine_datasets: "BAD" } }, } as unknown as RawConfig, undefined, + undefined, { env: "ENV1" } ); @@ -5123,6 +5359,7 @@ describe("normalizeAndValidateConfig()", () => { env: { ENV1: { analytics_engine_datasets: 999 } }, } as unknown as RawConfig, undefined, + undefined, { env: "ENV1" } ); @@ -5141,6 +5378,7 @@ describe("normalizeAndValidateConfig()", () => { env: { ENV1: { analytics_engine_datasets: null } }, } as unknown as RawConfig, undefined, + undefined, { env: "ENV1" } ); @@ -5171,6 +5409,7 @@ describe("normalizeAndValidateConfig()", () => { }, } as unknown as RawConfig, undefined, + undefined, { env: "ENV1" } ); @@ -5193,6 +5432,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { env: { ENV1: { unsafe: [] } } } as unknown as RawConfig, undefined, + undefined, { env: "ENV1" } ); @@ -5214,6 +5454,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { env: { ENV1: { unsafe: "BAD" } } } as unknown as RawConfig, undefined, + undefined, { env: "ENV1" } ); @@ -5235,6 +5476,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { env: { ENV1: { unsafe: 999 } } } as unknown as RawConfig, undefined, + undefined, { env: "ENV1" } ); @@ -5256,6 +5498,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { env: { ENV1: { unsafe: null } } } as unknown as RawConfig, undefined, + undefined, { env: "ENV1" } ); @@ -5277,6 +5520,7 @@ describe("normalizeAndValidateConfig()", () => { const { diagnostics } = normalizeAndValidateConfig( { env: { ENV1: { unsafe: {} } } } as RawConfig, undefined, + undefined, { env: "ENV1" } ); @@ -5298,6 +5542,7 @@ describe("normalizeAndValidateConfig()", () => { env: { ENV1: { unsafe: { bindings: [] } } }, } as RawConfig, undefined, + undefined, { env: "ENV1" } ); @@ -5316,6 +5561,7 @@ describe("normalizeAndValidateConfig()", () => { env: { ENV1: { unsafe: { invalid: true } } }, } as RawConfig, undefined, + undefined, { env: "ENV1" } ); @@ -5338,6 +5584,7 @@ describe("normalizeAndValidateConfig()", () => { env: { ENV1: { unsafe: { bindings: {} } } }, } as unknown as RawConfig, undefined, + undefined, { env: "ENV1" } ); @@ -5361,6 +5608,7 @@ describe("normalizeAndValidateConfig()", () => { env: { ENV1: { unsafe: { bindings: "BAD" } } }, } as unknown as RawConfig, undefined, + undefined, { env: "ENV1" } ); @@ -5384,6 +5632,7 @@ describe("normalizeAndValidateConfig()", () => { env: { ENV1: { unsafe: { bindings: 999 } } }, } as unknown as RawConfig, undefined, + undefined, { env: "ENV1" } ); @@ -5407,6 +5656,7 @@ describe("normalizeAndValidateConfig()", () => { env: { ENV1: { unsafe: { bindings: null } } }, } as unknown as RawConfig, undefined, + undefined, { env: "ENV1" } ); @@ -5445,6 +5695,7 @@ describe("normalizeAndValidateConfig()", () => { }, } as unknown as RawConfig, undefined, + undefined, { env: "ENV1" } ); @@ -5478,6 +5729,7 @@ describe("normalizeAndValidateConfig()", () => { env: { ENV1: { unsafe: { metadata: [] } } }, } as unknown as RawConfig, undefined, + undefined, { env: "ENV1" } ); @@ -5501,6 +5753,7 @@ describe("normalizeAndValidateConfig()", () => { env: { ENV1: { unsafe: { metadata: "BAD" } } }, } as unknown as RawConfig, undefined, + undefined, { env: "ENV1" } ); @@ -5524,6 +5777,7 @@ describe("normalizeAndValidateConfig()", () => { env: { ENV1: { unsafe: { metadata: 999 } } }, } as unknown as RawConfig, undefined, + undefined, { env: "ENV1" } ); @@ -5547,6 +5801,7 @@ describe("normalizeAndValidateConfig()", () => { env: { ENV1: { unsafe: { metadata: null } } }, } as unknown as RawConfig, undefined, + undefined, { env: "ENV1" } ); @@ -5572,6 +5827,7 @@ describe("normalizeAndValidateConfig()", () => { tail_consumers: "this sure isn't an array", } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -5604,6 +5860,7 @@ describe("normalizeAndValidateConfig()", () => { ], } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -5630,6 +5887,7 @@ describe("normalizeAndValidateConfig()", () => { }, } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -5656,6 +5914,7 @@ describe("normalizeAndValidateConfig()", () => { }, } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -5682,6 +5941,7 @@ describe("normalizeAndValidateConfig()", () => { }, } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -5705,6 +5965,7 @@ describe("normalizeAndValidateConfig()", () => { }, } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -5725,6 +5986,7 @@ describe("normalizeAndValidateConfig()", () => { }, } satisfies RawConfig, undefined, + undefined, { env: undefined } ); @@ -5746,6 +6008,7 @@ describe("normalizeAndValidateConfig()", () => { }, } as unknown as RawConfig, undefined, + undefined, { env: undefined } ); @@ -5779,6 +6042,7 @@ describe("normalizeAndValidateConfig()", () => { }, }, undefined, + undefined, { env: "ENV1" } ); @@ -5835,6 +6099,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( expectedConfig, undefined, + undefined, { env: "ENV1" } ); @@ -5883,6 +6148,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( expectedConfig, undefined, + undefined, { env: "ENV1" } ); @@ -5928,6 +6194,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( expectedConfig, undefined, + undefined, { env: "ENV1" } ); @@ -5968,6 +6235,7 @@ describe("normalizeAndValidateConfig()", () => { const { config, diagnostics } = normalizeAndValidateConfig( expectedConfig, undefined, + undefined, { env: "ENV1" } ); @@ -6018,17 +6286,27 @@ describe("normalizeAndValidateConfig()", () => { }, }; - const result1 = normalizeAndValidateConfig(expectedConfig, undefined, { - env: "ENV1", - }); + const result1 = normalizeAndValidateConfig( + expectedConfig, + undefined, + undefined, + { + env: "ENV1", + } + ); expect(result1.config).toEqual(expect.objectContaining(environment1)); expect(result1.diagnostics.hasErrors()).toBe(false); expect(result1.diagnostics.hasWarnings()).toBe(false); - const result2 = normalizeAndValidateConfig(expectedConfig, undefined, { - env: "ENV2", - }); + const result2 = normalizeAndValidateConfig( + expectedConfig, + undefined, + undefined, + { + env: "ENV2", + } + ); expect(result2.config).toEqual(expect.objectContaining(environment2)); expect(result2.diagnostics.hasErrors()).toBe(false); diff --git a/packages/wrangler/src/__tests__/config/findWranglerConfig.test.ts b/packages/wrangler/src/__tests__/config/findWranglerConfig.test.ts new file mode 100644 index 000000000000..792b5c3d3585 --- /dev/null +++ b/packages/wrangler/src/__tests__/config/findWranglerConfig.test.ts @@ -0,0 +1,278 @@ +import path from "node:path"; +import { findWranglerConfig } from "../../config/config-helpers"; +import { mockConsoleMethods } from "../helpers/mock-console"; +import { normalizeString } from "../helpers/normalize"; +import { runInTempDir } from "../helpers/run-in-tmp"; +import { seed } from "../helpers/seed"; + +describe("config findWranglerConfig()", () => { + runInTempDir(); + const std = mockConsoleMethods(); + const NO_LOGS = { debug: "", err: "", info: "", out: "", warn: "" }; + + describe("(useRedirectIfAvailable: false)", () => { + it.each(["toml", "json", "jsonc"])( + "should find the nearest wrangler.%s to the reference directory", + async (ext) => { + await seed({ + [`wrangler.${ext}`]: "DUMMY", + [`foo/wrangler.${ext}`]: "DUMMY", + [`foo/bar/wrangler.${ext}`]: "DUMMY", + [`foo/bar/qux/holder.txt`]: "DUMMY", + }); + expect(findWranglerConfig(".")).toEqual({ + configPath: path.resolve(`wrangler.${ext}`), + userConfigPath: path.resolve(`wrangler.${ext}`), + }); + expect(findWranglerConfig("./foo")).toEqual({ + configPath: path.resolve(`foo/wrangler.${ext}`), + userConfigPath: path.resolve(`foo/wrangler.${ext}`), + }); + expect(findWranglerConfig("./foo/bar")).toEqual({ + configPath: path.resolve(`foo/bar/wrangler.${ext}`), + userConfigPath: path.resolve(`foo/bar/wrangler.${ext}`), + }); + expect(findWranglerConfig("./foo/bar/qux")).toEqual({ + configPath: path.resolve(`foo/bar/wrangler.${ext}`), + userConfigPath: path.resolve(`foo/bar/wrangler.${ext}`), + }); + expect(std).toEqual(NO_LOGS); + } + ); + + describe.each([ + ["json", "jsonc"], + ["json", "toml"], + ["jsonc", "toml"], + ])("should prefer the wrangler.%s over wrangler.%s", (ext1, ext2) => { + it("in the same directory", async () => { + await seed({ + [`wrangler.${ext1}`]: "DUMMY", + [`wrangler.${ext2}`]: "DUMMY", + }); + expect(findWranglerConfig(".")).toEqual({ + configPath: path.resolve(`wrangler.${ext1}`), + userConfigPath: path.resolve(`wrangler.${ext1}`), + }); + expect(std).toEqual(NO_LOGS); + }); + + it("in different directories", async () => { + await seed({ + [`wrangler.${ext1}`]: "DUMMY", + [`foo/wrangler.${ext2}`]: "DUMMY", + }); + expect(findWranglerConfig("./foo")).toEqual({ + configPath: path.resolve(`wrangler.${ext1}`), + userConfigPath: path.resolve(`wrangler.${ext1}`), + }); + expect(std).toEqual(NO_LOGS); + }); + }); + + it("should return user config path even if a deploy config is found", async () => { + await seed({ + [`wrangler.toml`]: "DUMMY", + [".wrangler/deploy/config.json"]: `{"configPath": "../../dist/wrangler.json" }`, + [`dist/wrangler.json`]: "DUMMY", + }); + expect(findWranglerConfig(".")).toEqual({ + configPath: path.resolve(`wrangler.toml`), + userConfigPath: path.resolve(`wrangler.toml`), + }); + expect(std).toEqual(NO_LOGS); + }); + }); + + describe("(useRedirectIfAvailable: true)", () => { + it("should return redirected config path if no user config and a deploy config is found", async () => { + await seed({ + [".wrangler/deploy/config.json"]: `{"configPath": "../../dist/wrangler.json" }`, + [`dist/wrangler.json`]: "DUMMY", + ["foo/holder.txt"]: "DUMMY", + }); + expect(findWranglerConfig(".", { useRedirectIfAvailable: true })).toEqual( + { + configPath: path.resolve(`dist/wrangler.json`), + } + ); + expect( + findWranglerConfig("./foo", { useRedirectIfAvailable: true }) + ).toEqual({ + configPath: path.resolve(`dist/wrangler.json`), + }); + expect(std).toMatchInlineSnapshot(` + Object { + "debug": "", + "err": "", + "info": "", + "out": "", + "warn": "▲ [WARNING] Using redirected Wrangler configuration. + + Configuration being used: \\"dist/wrangler.json\\" + Original user's configuration: \\"\\" + Deploy configuration file: \\".wrangler/deploy/config.json\\" + + + ▲ [WARNING] Using redirected Wrangler configuration. + + Configuration being used: \\"dist/wrangler.json\\" + Original user's configuration: \\"\\" + Deploy configuration file: \\".wrangler/deploy/config.json\\" + + ", + } + `); + }); + + it("should return redirected config path if matching user config and a deploy config is found", async () => { + await seed({ + [`wrangler.toml`]: "DUMMY", + [".wrangler/deploy/config.json"]: `{"configPath": "../../dist/wrangler.json" }`, + [`dist/wrangler.json`]: "DUMMY", + ["foo/holder.txt"]: "DUMMY", + }); + expect(findWranglerConfig(".", { useRedirectIfAvailable: true })).toEqual( + { + configPath: path.resolve(`dist/wrangler.json`), + userConfigPath: path.resolve(`wrangler.toml`), + } + ); + expect( + findWranglerConfig("./foo", { useRedirectIfAvailable: true }) + ).toEqual({ + configPath: path.resolve(`dist/wrangler.json`), + userConfigPath: path.resolve(`wrangler.toml`), + }); + expect(std).toMatchInlineSnapshot(` + Object { + "debug": "", + "err": "", + "info": "", + "out": "", + "warn": "▲ [WARNING] Using redirected Wrangler configuration. + + Configuration being used: \\"dist/wrangler.json\\" + Original user's configuration: \\"wrangler.toml\\" + Deploy configuration file: \\".wrangler/deploy/config.json\\" + + + ▲ [WARNING] Using redirected Wrangler configuration. + + Configuration being used: \\"dist/wrangler.json\\" + Original user's configuration: \\"wrangler.toml\\" + Deploy configuration file: \\".wrangler/deploy/config.json\\" + + ", + } + `); + }); + + it("should error if deploy config is not valid JSON", async () => { + await seed({ + [".wrangler/deploy/config.json"]: `INVALID JSON`, + }); + + let error; + try { + findWranglerConfig(".", { useRedirectIfAvailable: true }); + } catch (e) { + error = e; + } + + expect(normalizeString(`${error}`)).toMatchInlineSnapshot(` + "Error: Failed to parse the deploy configuration file at .wrangler/deploy/config.json + X [ERROR] InvalidSymbol + + /.wrangler/deploy/config.json:1:0: +  1 │ INVALID JSON + ╵ ~~~~~~~ + + " + `); + expect(std).toEqual(NO_LOGS); + }); + + it("should error if deploy config does not contain a `configPath` property", async () => { + await seed({ + [".wrangler/deploy/config.json"]: `{}`, + }); + + let error; + try { + findWranglerConfig(".", { useRedirectIfAvailable: true }); + } catch (e) { + error = e; + } + + expect(normalizeString(`${error}`)).toMatchInlineSnapshot(` + "Error: A deploy configuration file was found at \\".wrangler/deploy/config.json\\". + But this is not valid - the required \\"configPath\\" property was not found. + Instead this file contains: + \`\`\` + {} + \`\`\`" + `); + expect(std).toEqual(NO_LOGS); + }); + + it("should error if redirected config file does not exist", async () => { + await seed({ + [".wrangler/deploy/config.json"]: `{ "configPath": "missing/wrangler.json" }`, + }); + + let error; + try { + findWranglerConfig(".", { useRedirectIfAvailable: true }); + } catch (e) { + error = e; + } + + expect(normalizeString(`${error}`)).toMatchInlineSnapshot(` + "Error: There is a deploy configuration at \\".wrangler/deploy/config.json\\". + But the redirected configuration path it points to, \\".wrangler/deploy/missing/wrangler.json\\", does not exist." + `); + expect(std).toEqual(NO_LOGS); + }); + + it("should error if deploy config file and user config file do not have the same base path", async () => { + await seed({ + [`foo/wrangler.toml`]: "DUMMY", + ["foo/bar/.wrangler/deploy/config.json"]: `{ "configPath": "../../dist/wrangler.json" }`, + [`foo/bar/dist/wrangler.json`]: "DUMMY", + + [`bar/foo/wrangler.toml`]: "DUMMY", + ["bar/.wrangler/deploy/config.json"]: `{ "configPath": "../../dist/wrangler.json" }`, + [`bar/dist/wrangler.json`]: "DUMMY", + }); + + let error; + try { + findWranglerConfig("foo/bar", { useRedirectIfAvailable: true }); + } catch (e) { + error = e; + } + + expect(normalizeString(`${error}`)).toMatchInlineSnapshot(` + "Error: Found both a user configuration file at \\"foo/wrangler.toml\\" + and a deploy configuration file at \\"foo/bar/.wrangler/deploy/config.json\\". + But these do not share the same base path so it is not clear which should be used." + `); + expect(std).toEqual(NO_LOGS); + + try { + error = undefined; + findWranglerConfig("bar/foo", { useRedirectIfAvailable: true }); + } catch (e) { + error = e; + } + + expect(normalizeString(`${error}`)).toMatchInlineSnapshot(` + "Error: Found both a user configuration file at \\"bar/foo/wrangler.toml\\" + and a deploy configuration file at \\"bar/.wrangler/deploy/config.json\\". + But these do not share the same base path so it is not clear which should be used." + `); + expect(std).toEqual(NO_LOGS); + }); + }); +}); diff --git a/packages/wrangler/src/__tests__/d1/migrate.test.ts b/packages/wrangler/src/__tests__/d1/migrate.test.ts index 47c7412494c9..9d858a7f320b 100644 --- a/packages/wrangler/src/__tests__/d1/migrate.test.ts +++ b/packages/wrangler/src/__tests__/d1/migrate.test.ts @@ -1,4 +1,3 @@ -import { cwd } from "process"; import { http, HttpResponse } from "msw"; import { reinitialiseAuthTokens } from "../../user"; import { mockAccountId, mockApiToken } from "../helpers/mock-account-id"; @@ -47,9 +46,7 @@ describe("migrate", () => { // If we get to the point where we are checking for migrations then we have not been asked to log in. await expect( runWrangler("d1 migrations apply DATABASE") - ).rejects.toThrowError( - `No migrations present at ${cwd().replaceAll("\\", "/")}/migrations.` - ); + ).rejects.toThrowError(`No migrations present at /migrations.`); }); it("should try to read D1 config from wrangler.toml", async () => { @@ -68,9 +65,7 @@ describe("migrate", () => { // If we get to the point where we are checking for migrations then we have not checked wrangler.toml. await expect( runWrangler("d1 migrations apply DATABASE") - ).rejects.toThrowError( - `No migrations present at ${cwd().replaceAll("\\", "/")}/migrations.` - ); + ).rejects.toThrowError(`No migrations present at /migrations.`); }); it("should reject the use of --preview with --local", async () => { @@ -221,9 +216,7 @@ Your database may not be available to serve requests during the migration, conti // If we get to the point where we are checking for migrations then we have not been asked to log in. await expect( runWrangler("d1 migrations list --local DATABASE") - ).rejects.toThrowError( - `No migrations present at ${cwd().replaceAll("\\", "/")}/migrations.` - ); + ).rejects.toThrowError(`No migrations present at /migrations.`); }); it("should use the custom migrations folder when provided", async () => { @@ -241,10 +234,7 @@ Your database may not be available to serve requests during the migration, conti await expect( runWrangler("d1 migrations list --local DATABASE") ).rejects.toThrowError( - `No migrations present at ${cwd().replaceAll( - "\\", - "/" - )}/my-migrations-go-here.` + `No migrations present at /my-migrations-go-here.` ); }); @@ -276,9 +266,7 @@ Your database may not be available to serve requests during the migration, conti // If we get to the point where we are checking for migrations then we have not checked wrangler.toml. await expect( runWrangler("d1 migrations list DATABASE") - ).rejects.toThrowError( - `No migrations present at ${cwd().replaceAll("\\", "/")}/migrations.` - ); + ).rejects.toThrowError(`No migrations present at /migrations.`); }); }); }); diff --git a/packages/wrangler/src/__tests__/get-entry.test.ts b/packages/wrangler/src/__tests__/get-entry.test.ts index aa938d5054dc..6801f867b11e 100644 --- a/packages/wrangler/src/__tests__/get-entry.test.ts +++ b/packages/wrangler/src/__tests__/get-entry.test.ts @@ -131,6 +131,7 @@ describe("getEntry()", () => { ...defaultWranglerConfig, main: "src/index.ts", configPath: "other-worker/wrangler.toml", + userConfigPath: "other-worker/wrangler.toml", }, "deploy" ); diff --git a/packages/wrangler/src/__tests__/helpers/normalize.ts b/packages/wrangler/src/__tests__/helpers/normalize.ts index b07664de31b7..fe0c4473549e 100644 --- a/packages/wrangler/src/__tests__/helpers/normalize.ts +++ b/packages/wrangler/src/__tests__/helpers/normalize.ts @@ -5,7 +5,7 @@ export function normalizeString(input: string): string { return normalizeErrorMarkers( replaceByte( stripTrailingWhitespace( - normalizeSlashes(normalizeTempDirs(stripTimings(input))) + normalizeSlashes(normalizeCwd(normalizeTempDirs(stripTimings(input)))) ) ) ); @@ -29,6 +29,13 @@ function normalizeSlashes(str: string): string { return str.replace(/\\/g, "/"); } +/** + * Replace any use of the current working directory with `` to avoid cross OS issues. + */ +function normalizeCwd(str: string): string { + return str.replaceAll(process.cwd(), ""); +} + /** * Strip "timing data" out of the `stdout` string, since this is not always deterministic. * diff --git a/packages/wrangler/src/__tests__/helpers/write-wrangler-config.ts b/packages/wrangler/src/__tests__/helpers/write-wrangler-config.ts index b81b8d091f67..24cb803d9b1a 100644 --- a/packages/wrangler/src/__tests__/helpers/write-wrangler-config.ts +++ b/packages/wrangler/src/__tests__/helpers/write-wrangler-config.ts @@ -1,4 +1,5 @@ -import * as fs from "fs"; +import * as fs from "node:fs"; +import { dirname } from "node:path"; import { formatConfigSnippet } from "../../config"; import type { RawConfig } from "../../config"; @@ -7,6 +8,7 @@ export function writeWranglerConfig( config: RawConfig = {}, path = "./wrangler.toml" ) { + fs.mkdirSync(dirname(path), { recursive: true }); fs.writeFileSync( path, formatConfigSnippet( diff --git a/packages/wrangler/src/__tests__/pages/pages-build-env.test.ts b/packages/wrangler/src/__tests__/pages/pages-build-env.test.ts index 8895ac532b7f..fb5035049d3d 100644 --- a/packages/wrangler/src/__tests__/pages/pages-build-env.test.ts +++ b/packages/wrangler/src/__tests__/pages/pages-build-env.test.ts @@ -1,11 +1,12 @@ /* eslint-disable turbo/no-undeclared-env-vars */ -import { readFileSync, writeFileSync } from "node:fs"; +import { mkdirSync, readFileSync, writeFileSync } from "node:fs"; import { logger } from "../../logger"; import { EXIT_CODE_INVALID_PAGES_CONFIG, EXIT_CODE_NO_CONFIG_FOUND, } from "../../pages/errors"; import { mockConsoleMethods } from "../helpers/mock-console"; +import { normalizeString } from "../helpers/normalize"; import { runInTempDir } from "../helpers/run-in-tmp"; import { runWrangler } from "../helpers/run-wrangler"; import { writeWranglerConfig } from "../helpers/write-wrangler-config"; @@ -391,4 +392,34 @@ describe("pages build env", () => { `"{\\"vars\\":{\\"VAR1\\":\\"PREVIEW_VALUE1\\",\\"VAR2\\":\\"PREVIEW_VALUE2\\",\\"PREVIEW_VAR3\\":\\"PREVIEW_VALUE3\\"},\\"pages_build_output_dir\\":\\"dist\\"}"` ); }); + + it("should render output directory path relative to project directory, even if wrangler config is redirected", async () => { + vi.stubEnv("PAGES_ENVIRONMENT", ""); + writeWranglerConfig( + { + // Note this path is relative to the "generated" wrangler.json + pages_build_output_dir: "./dist", + }, + "build/wrangler.json" + ); + mkdirSync(".wrangler/deploy", { recursive: true }); + writeFileSync( + ".wrangler/deploy/config.json", + JSON.stringify({ configPath: "../../build/wrangler.json" }) + ); + + await runWrangler("pages functions build-env . --outfile data.json"); + expect(std.out).toMatchInlineSnapshot(` + "Checking for configuration in a Wrangler configuration file (BETA) + + Found wrangler.json file. Reading build configuration... + pages_build_output_dir: build/dist + Build environment variables: (none found)" + `); + expect( + normalizeString( + JSON.parse(readFileSync("data.json", "utf8")).pages_build_output_dir + ) + ).toEqual("build/dist"); + }); }); diff --git a/packages/wrangler/src/__tests__/type-generation.test.ts b/packages/wrangler/src/__tests__/type-generation.test.ts index 79268ed7dbc9..435f178a15bc 100644 --- a/packages/wrangler/src/__tests__/type-generation.test.ts +++ b/packages/wrangler/src/__tests__/type-generation.test.ts @@ -256,13 +256,12 @@ describe("generateTypes()", () => { `); }); - it("should show a warning when no custom config file is detected", async () => { - await runWrangler("types -c hello.toml"); - expect(std.warn).toMatchInlineSnapshot(` - "▲ [WARNING] No config file detected (at hello.toml), aborting - - " - `); + it("should error when a specified custom config file is missing", async () => { + await expect(() => + runWrangler("types -c hello.toml") + ).rejects.toMatchInlineSnapshot( + `[ParseError: Could not read file: hello.toml]` + ); }); it("should respect the top level -c|--config flag", async () => { diff --git a/packages/wrangler/src/api/pages/deploy.ts b/packages/wrangler/src/api/pages/deploy.ts index 0ed97aa4ba7d..ed9a88461bef 100644 --- a/packages/wrangler/src/api/pages/deploy.ts +++ b/packages/wrangler/src/api/pages/deploy.ts @@ -160,7 +160,10 @@ export async function deploy({ let config: Config | undefined; try { - config = readPagesConfig({ ...args, env }); + config = readPagesConfig( + { ...args, env }, + { useRedirectIfAvailable: true } + ); } catch (err) { if ( !( diff --git a/packages/wrangler/src/api/startDevWorker/ConfigController.ts b/packages/wrangler/src/api/startDevWorker/ConfigController.ts index d8a71ed43cb0..23349099b0e0 100644 --- a/packages/wrangler/src/api/startDevWorker/ConfigController.ts +++ b/packages/wrangler/src/api/startDevWorker/ConfigController.ts @@ -67,7 +67,7 @@ async function resolveDevConfig( const localPersistencePath = getLocalPersistencePath( input.dev?.persist, - config.configPath + config ); const { host, routes } = await getHostAndRoutes( @@ -418,25 +418,29 @@ export class ConfigController extends Controller { const signal = this.#abortController.signal; this.latestInput = input; try { - const fileConfig = readConfig({ - config: input.config, - env: input.env, - "dispatch-namespace": undefined, - "legacy-env": !input.legacy?.enableServiceEnvironments, - remote: input.dev?.remote, - upstreamProtocol: - input.dev?.origin?.secure === undefined - ? undefined - : input.dev?.origin?.secure - ? "https" - : "http", - localProtocol: - input.dev?.server?.secure === undefined - ? undefined - : input.dev?.server?.secure - ? "https" - : "http", - }); + const fileConfig = readConfig( + { + script: input.entrypoint, + config: input.config, + env: input.env, + "dispatch-namespace": undefined, + "legacy-env": !input.legacy?.enableServiceEnvironments, + remote: input.dev?.remote, + upstreamProtocol: + input.dev?.origin?.secure === undefined + ? undefined + : input.dev?.origin?.secure + ? "https" + : "http", + localProtocol: + input.dev?.server?.secure === undefined + ? undefined + : input.dev?.server?.secure + ? "https" + : "http", + }, + { useRedirectIfAvailable: true } + ); if (typeof vitest === "undefined") { void this.#ensureWatchingConfig(fileConfig.configPath); diff --git a/packages/wrangler/src/config/config-helpers.ts b/packages/wrangler/src/config/config-helpers.ts index a02b6a47bf26..11201a86116a 100644 --- a/packages/wrangler/src/config/config-helpers.ts +++ b/packages/wrangler/src/config/config-helpers.ts @@ -1,35 +1,139 @@ -import path from "path"; +import fs from "node:fs"; +import path from "node:path"; import { findUpSync } from "find-up"; +import dedent from "ts-dedent"; +import { UserError } from "../errors"; +import { logger } from "../logger"; +import { formatMessage, ParseError, parseJSONC, readFileSync } from "../parse"; + +export type ResolveConfigPathOptions = { + useRedirectIfAvailable?: boolean; +}; + +export type ConfigPaths = { + /** Absolute path to the actual configuration being used (possibly redirected from the user's config). */ + configPath: string | undefined; + /** Absolute path to the user's configuration, which may not be the same as `configPath` if it was redirected. */ + userConfigPath: string | undefined; +}; /** * Resolve the path to the configuration file, given the `config` and `script` optional command line arguments. * `config` takes precedence, then `script`, then we just use the cwd. + * + * Returns an object with two paths: `configPath` and `userConfigPath`. If defined these are absolute file paths. */ -export function resolveWranglerConfigPath({ - config, - script, -}: { - config?: string; - script?: string; -}): string | undefined { +export function resolveWranglerConfigPath( + { + config, + script, + }: { + config?: string; + script?: string; + }, + options: { useRedirectIfAvailable?: boolean } +): ConfigPaths { if (config !== undefined) { - return config; + return { userConfigPath: config, configPath: config }; } const leafPath = script !== undefined ? path.dirname(script) : process.cwd(); - return findWranglerConfig(leafPath); + + return findWranglerConfig(leafPath, options); } /** - * Find the wrangler config file by searching up the file-system + * Find the wrangler configuration file by searching up the file-system * from the current working directory. */ export function findWranglerConfig( - referencePath: string = process.cwd() -): string | undefined { - return ( + referencePath: string = process.cwd(), + { useRedirectIfAvailable = false } = {} +): ConfigPaths { + const userConfigPath = findUpSync(`wrangler.json`, { cwd: referencePath }) ?? findUpSync(`wrangler.jsonc`, { cwd: referencePath }) ?? - findUpSync(`wrangler.toml`, { cwd: referencePath }) - ); + findUpSync(`wrangler.toml`, { cwd: referencePath }); + + return { + userConfigPath, + configPath: useRedirectIfAvailable + ? findRedirectedWranglerConfig(referencePath, userConfigPath) + : userConfigPath, + }; +} + +/** + * Check whether there is a configuration file that indicates that we should redirect the user configuration. + * @param cwd + * @param userConfigPath + * @returns + */ +function findRedirectedWranglerConfig( + cwd: string, + userConfigPath: string | undefined +) { + const PATH_TO_DEPLOY_CONFIG = ".wrangler/deploy/config.json"; + const deployConfigPath = findUpSync(PATH_TO_DEPLOY_CONFIG, { cwd }); + if (deployConfigPath === undefined) { + return userConfigPath; + } + + let redirectedConfigPath: string | undefined; + const deployConfigFile = readFileSync(deployConfigPath); + try { + const deployConfig: { configPath?: string } = parseJSONC( + deployConfigFile, + deployConfigPath + ); + redirectedConfigPath = + deployConfig.configPath && + path.resolve(path.dirname(deployConfigPath), deployConfig.configPath); + } catch (e) { + throw new UserError( + dedent` + Failed to parse the deploy configuration file at ${path.relative(".", deployConfigPath)} + ${e instanceof ParseError ? formatMessage(e) : e} + ` + ); + } + if (!redirectedConfigPath) { + throw new UserError(dedent` + A deploy configuration file was found at "${path.relative(".", deployConfigPath)}". + But this is not valid - the required "configPath" property was not found. + Instead this file contains: + \`\`\` + ${deployConfigFile} + \`\`\` + `); + } + + if (redirectedConfigPath) { + if (!fs.existsSync(redirectedConfigPath)) { + throw new UserError(dedent` + There is a deploy configuration at "${path.relative(".", deployConfigPath)}". + But the redirected configuration path it points to, "${path.relative(".", redirectedConfigPath)}", does not exist. + `); + } + if (userConfigPath) { + if ( + path.join(path.dirname(userConfigPath), PATH_TO_DEPLOY_CONFIG) !== + deployConfigPath + ) { + throw new UserError(dedent` + Found both a user configuration file at "${path.relative(".", userConfigPath)}" + and a deploy configuration file at "${path.relative(".", deployConfigPath)}". + But these do not share the same base path so it is not clear which should be used. + `); + } + } + + logger.warn(dedent` + Using redirected Wrangler configuration. + Configuration being used: "${path.relative(".", redirectedConfigPath)}" + Original user's configuration: "${userConfigPath ? path.relative(".", userConfigPath) : ""}" + Deploy configuration file: "${path.relative(".", deployConfigPath)}" + `); + return redirectedConfigPath; + } } diff --git a/packages/wrangler/src/config/config.ts b/packages/wrangler/src/config/config.ts index 92f0285d6d35..ad4c1d4f0fec 100644 --- a/packages/wrangler/src/config/config.ts +++ b/packages/wrangler/src/config/config.ts @@ -31,7 +31,10 @@ export type RawConfig = Partial> & EnvironmentMap & { $schema?: string }; export interface ConfigFields { + /** The path to the Wrangler configuration file (if any, and possibly redirected from the user Wrangler configuration) used to create this configuration. */ configPath: string | undefined; + /** The path to the user's Wrangler configuration file (if any), which may have been redirected to another file that used to create this configuration. */ + userConfigPath: string | undefined; /** * A boolean to enable "legacy" style wrangler environments (from Wrangler v1). @@ -327,6 +330,7 @@ export const defaultWranglerConfig: Config = { /*====================================================*/ /* TOP-LEVEL ONLY FIELDS */ configPath: undefined, + userConfigPath: undefined, legacy_env: true, site: undefined, legacy_assets: undefined, diff --git a/packages/wrangler/src/config/index.ts b/packages/wrangler/src/config/index.ts index b1b73f933ad6..cc02893e564b 100644 --- a/packages/wrangler/src/config/index.ts +++ b/packages/wrangler/src/config/index.ts @@ -1,4 +1,5 @@ import fs from "node:fs"; +import path from "node:path"; import TOML from "@iarna/toml"; import dotenv from "dotenv"; import { FatalError, UserError } from "../errors"; @@ -10,6 +11,7 @@ import { isPagesConfig, normalizeAndValidateConfig } from "./validation"; import { validatePagesConfig } from "./validation-pages"; import type { CommonYargsOptions } from "../yargs-types"; import type { Config, OnlyCamelCase, RawConfig } from "./config"; +import type { ResolveConfigPathOptions } from "./config-helpers"; import type { NormalizeAndValidateConfigArgs } from "./validation"; export type { @@ -62,31 +64,35 @@ export function formatConfigSnippet( } } -type ReadConfigCommandArgs = NormalizeAndValidateConfigArgs & { +export type ReadConfigCommandArgs = NormalizeAndValidateConfigArgs & { config?: string; script?: string; }; +export type ReadConfigOptions = ResolveConfigPathOptions & { + hideWarnings?: boolean; +}; + /** * Get the Wrangler configuration; read it from the give `configPath` if available. */ export function readConfig( args: ReadConfigCommandArgs, - options?: { hideWarnings?: boolean } -): Config; -export function readConfig( - args: ReadConfigCommandArgs, - { hideWarnings = false }: { hideWarnings?: boolean } = {} + options: ReadConfigOptions = {} ): Config { - const { rawConfig, configPath } = experimental_readRawConfig(args); + const { rawConfig, configPath, userConfigPath } = experimental_readRawConfig( + args, + options + ); const { config, diagnostics } = normalizeAndValidateConfig( rawConfig, configPath, + userConfigPath, args ); - if (diagnostics.hasWarnings() && !hideWarnings) { + if (diagnostics.hasWarnings() && !options?.hideWarnings) { logger.warn(diagnostics.renderWarnings()); } if (diagnostics.hasErrors()) { @@ -98,23 +104,27 @@ export function readConfig( export function readPagesConfig( args: ReadConfigCommandArgs, - { hideWarnings = false }: { hideWarnings?: boolean } = {} + options: ReadConfigOptions = {} ): Omit & { pages_build_output_dir: string } { let rawConfig: RawConfig; let configPath: string | undefined; + let userConfigPath: string | undefined; try { - ({ rawConfig, configPath } = experimental_readRawConfig(args)); + ({ rawConfig, configPath, userConfigPath } = experimental_readRawConfig( + args, + options + )); } catch (e) { logger.error(e); throw new FatalError( - `Your ${configFileName(configPath)} file is not a valid Pages config file`, + `Your ${configFileName(configPath)} file is not a valid Pages configuration file`, EXIT_CODE_INVALID_PAGES_CONFIG ); } if (!isPagesConfig(rawConfig)) { throw new FatalError( - `Your ${configFileName(configPath)} file is not a valid Pages config file`, + `Your ${configFileName(configPath)} file is not a valid Pages configuration file`, EXIT_CODE_INVALID_PAGES_CONFIG ); } @@ -122,10 +132,11 @@ export function readPagesConfig( const { config, diagnostics } = normalizeAndValidateConfig( rawConfig, configPath, + userConfigPath, args ); - if (diagnostics.hasWarnings() && !hideWarnings) { + if (diagnostics.hasWarnings() && !options.hideWarnings) { logger.warn(diagnostics.renderWarnings()); } if (diagnostics.hasErrors()) { @@ -153,17 +164,25 @@ export function readPagesConfig( } export const experimental_readRawConfig = ( - args: ReadConfigCommandArgs -): { rawConfig: RawConfig; configPath: string | undefined } => { + args: ReadConfigCommandArgs, + options: ReadConfigOptions = {} +): { + rawConfig: RawConfig; + configPath: string | undefined; + userConfigPath: string | undefined; +} => { // Load the configuration from disk if available - const configPath = resolveWranglerConfigPath(args); + const { configPath, userConfigPath } = resolveWranglerConfigPath( + args, + options + ); let rawConfig: RawConfig = {}; if (configPath?.endsWith("toml")) { rawConfig = parseTOML(readFileSync(configPath), configPath); } else if (configPath?.endsWith("json") || configPath?.endsWith("jsonc")) { rawConfig = parseJSONC(readFileSync(configPath), configPath); } - return { rawConfig, configPath }; + return { rawConfig, configPath, userConfigPath }; }; export function withConfig( @@ -182,29 +201,32 @@ export interface DotEnv { parsed: dotenv.DotenvParseOutput; } -function tryLoadDotEnv(path: string): DotEnv | undefined { +function tryLoadDotEnv(basePath: string): DotEnv | undefined { try { - const parsed = dotenv.parse(fs.readFileSync(path)); - return { path, parsed }; + const parsed = dotenv.parse(fs.readFileSync(basePath)); + return { path: basePath, parsed }; } catch (e) { if ((e as { code: string }).code === "ENOENT") { logger.debug( - `.env file not found at "${path}". Continuing... For more details, refer to https://developers.cloudflare.com/workers/wrangler/system-environment-variables/` + `.env file not found at "${path.relative(".", basePath)}". Continuing... For more details, refer to https://developers.cloudflare.com/workers/wrangler/system-environment-variables/` ); } else { - logger.debug(`Failed to load .env file "${path}":`, e); + logger.debug( + `Failed to load .env file "${path.relative(".", basePath)}":`, + e + ); } } } /** - * Loads a dotenv file from , preferring to read . if - * is defined and that file exists. + * Loads a dotenv file from `envPath`, preferring to read `${envPath}.${env}` if + * `env` is defined and that file exists. */ -export function loadDotEnv(path: string, env?: string): DotEnv | undefined { +export function loadDotEnv(envPath: string, env?: string): DotEnv | undefined { if (env === undefined) { - return tryLoadDotEnv(path); + return tryLoadDotEnv(envPath); } else { - return tryLoadDotEnv(`${path}.${env}`) ?? tryLoadDotEnv(path); + return tryLoadDotEnv(`${envPath}.${env}`) ?? tryLoadDotEnv(envPath); } } diff --git a/packages/wrangler/src/config/validation-pages.ts b/packages/wrangler/src/config/validation-pages.ts index a948b7189695..763f0d2e7675 100644 --- a/packages/wrangler/src/config/validation-pages.ts +++ b/packages/wrangler/src/config/validation-pages.ts @@ -36,9 +36,10 @@ const supportedPagesConfigFields = [ "dev", "mtls_certificates", "browser", - // normalizeAndValidateConfig() sets this value - "configPath", "upload_source_maps", + // normalizeAndValidateConfig() sets these values + "configPath", + "userConfigPath", ] as const; export function validatePagesConfig( diff --git a/packages/wrangler/src/config/validation.ts b/packages/wrangler/src/config/validation.ts index a36826ed1cc1..4a4bf22aba25 100644 --- a/packages/wrangler/src/config/validation.ts +++ b/packages/wrangler/src/config/validation.ts @@ -61,6 +61,7 @@ export type NormalizeAndValidateConfigArgs = { remote?: boolean; localProtocol?: string; upstreamProtocol?: string; + script?: string; }; const ENGLISH = new Intl.ListFormat("en-US"); @@ -80,6 +81,7 @@ export function isPagesConfig(rawConfig: RawConfig): boolean { export function normalizeAndValidateConfig( rawConfig: RawConfig, configPath: string | undefined, + userConfigPath: string | undefined, args: NormalizeAndValidateConfigArgs ): { config: Config; @@ -266,6 +268,7 @@ export function normalizeAndValidateConfig( // Process the top-level default environment configuration. const config: Config = { configPath, + userConfigPath, pages_build_output_dir: normalizeAndValidatePagesBuildOutputDir( configPath, rawConfig.pages_build_output_dir @@ -328,7 +331,7 @@ function applyPythonConfig( config: Config, args: NormalizeAndValidateConfigArgs ) { - const mainModule = "script" in args ? args.script : config.main; + const mainModule = args.script ?? config.main; if (typeof mainModule === "string" && mainModule.endsWith(".py")) { // Workers with a python entrypoint should have bundling turned off, since all of Wrangler's bundling is JS/TS specific config.no_bundle = true; diff --git a/packages/wrangler/src/core/register-yargs-command.ts b/packages/wrangler/src/core/register-yargs-command.ts index 86c0fb9f10fc..8fca4a91b88b 100644 --- a/packages/wrangler/src/core/register-yargs-command.ts +++ b/packages/wrangler/src/core/register-yargs-command.ts @@ -104,6 +104,8 @@ function createHandler(def: CommandDefinition) { def.behaviour?.provideConfig ?? true ? readConfig(args, { hideWarnings: !(def.behaviour?.printConfigWarnings ?? true), + useRedirectIfAvailable: + def.behaviour?.useConfigRedirectIfAvailable, }) : defaultWranglerConfig, errors: { UserError, FatalError }, diff --git a/packages/wrangler/src/core/types.ts b/packages/wrangler/src/core/types.ts index 1edb9784b733..ff0fc6fce83f 100644 --- a/packages/wrangler/src/core/types.ts +++ b/packages/wrangler/src/core/types.ts @@ -116,6 +116,11 @@ export type CommandDefinition< overrideExperimentalFlags?: ( args: HandlerArgs ) => ExperimentalFlags; + + /** + * If true, then look for a redirect file at `.wrangler/deploy/config.json` and use that to find the Wrangler configuration file. + */ + useConfigRedirectIfAvailable?: boolean; }; /** diff --git a/packages/wrangler/src/d1/execute.ts b/packages/wrangler/src/d1/execute.ts index 60a673843ef3..2b063ff4ee2a 100644 --- a/packages/wrangler/src/d1/execute.ts +++ b/packages/wrangler/src/d1/execute.ts @@ -276,7 +276,7 @@ async function executeLocally({ } const id = localDB.previewDatabaseUuid ?? localDB.uuid; - const persistencePath = getLocalPersistencePath(persistTo, config.configPath); + const persistencePath = getLocalPersistencePath(persistTo, config); const d1Persist = path.join(persistencePath, "v3", "d1"); logger.log( diff --git a/packages/wrangler/src/d1/export.ts b/packages/wrangler/src/d1/export.ts index d83be9b30bd6..98476c7be9e7 100644 --- a/packages/wrangler/src/d1/export.ts +++ b/packages/wrangler/src/d1/export.ts @@ -117,7 +117,7 @@ async function exportLocal( // TODO: should we allow customising persistence path? // Should it be --persist-to for consistency (even though this isn't persisting anything)? - const persistencePath = getLocalPersistencePath(undefined, config.configPath); + const persistencePath = getLocalPersistencePath(undefined, config); const d1Persist = path.join(persistencePath, "v3", "d1"); logger.log( diff --git a/packages/wrangler/src/deploy/index.ts b/packages/wrangler/src/deploy/index.ts index fa8a391815d8..0ff1c3119650 100644 --- a/packages/wrangler/src/deploy/index.ts +++ b/packages/wrangler/src/deploy/index.ts @@ -2,7 +2,6 @@ import assert from "node:assert"; import path from "node:path"; import { getAssetsOptions, validateAssetsArgsAndConfig } from "../assets"; import { configFileName, readConfig } from "../config"; -import { resolveWranglerConfigPath } from "../config/config-helpers"; import { getEntry } from "../deployment-bundle/entry"; import { UserError } from "../errors"; import { run } from "../experimental-flags"; @@ -271,15 +270,17 @@ async function deployWorker(args: DeployArgs) { ); } - const configPath = resolveWranglerConfigPath(args); - const projectRoot = configPath && path.dirname(configPath); - const config = readConfig(args); + const config = readConfig(args, { useRedirectIfAvailable: true }); if (config.pages_build_output_dir) { throw new UserError( "It looks like you've run a Workers-specific command in a Pages project.\n" + "For Pages, please run `wrangler pages deploy` instead." ); } + // We use the `userConfigPath` to compute the root of a project, + // rather than a redirected (potentially generated) `configPath`. + const projectRoot = + config.userConfigPath && path.dirname(config.userConfigPath); const entry = await getEntry(args, config, "deploy"); @@ -346,11 +347,7 @@ async function deployWorker(args: DeployArgs) { if (!args.dryRun) { assert(accountId, "Missing account ID"); - await verifyWorkerMatchesCITag( - accountId, - name, - path.relative(entry.projectRoot, config.configPath ?? "wrangler.toml") - ); + await verifyWorkerMatchesCITag(accountId, name, config.configPath); } const { sourceMapSize, versionId, workerTag, targets } = await deploy({ config, diff --git a/packages/wrangler/src/deployment-bundle/entry.ts b/packages/wrangler/src/deployment-bundle/entry.ts index 23ff0dce5661..6b3d0ebd072a 100644 --- a/packages/wrangler/src/deployment-bundle/entry.ts +++ b/packages/wrangler/src/deployment-bundle/entry.ts @@ -60,9 +60,9 @@ export async function getEntry( if (args.script) { paths = resolveEntryWithScript(args.script); } else if (config.main !== undefined) { - paths = resolveEntryWithMain(config.main, config.configPath); + paths = resolveEntryWithMain(config.main, config); } else if (entryPoint) { - paths = resolveEntryWithEntryPoint(entryPoint, config.configPath); + paths = resolveEntryWithEntryPoint(entryPoint, config); } else if ( args.legacyAssets || config.legacy_assets || diff --git a/packages/wrangler/src/deployment-bundle/resolve-entry.ts b/packages/wrangler/src/deployment-bundle/resolve-entry.ts index 2da92e262709..cfb5ef54c55d 100644 --- a/packages/wrangler/src/deployment-bundle/resolve-entry.ts +++ b/packages/wrangler/src/deployment-bundle/resolve-entry.ts @@ -1,5 +1,6 @@ import path from "path"; import { getBasePath } from "../paths"; +import type { Config } from "../config"; export function resolveEntryWithScript(script: string): { absolutePath: string; @@ -12,31 +13,36 @@ export function resolveEntryWithScript(script: string): { export function resolveEntryWithMain( main: string, - configPath?: string + config: Config ): { absolutePath: string; relativePath: string; projectRoot: string; } { - const projectRoot = path.resolve(path.dirname(configPath ?? ".")); - const file = path.resolve(projectRoot, main); - const relativePath = path.relative(projectRoot, file) || "."; - return { absolutePath: file, relativePath, projectRoot }; + // The project root is where the user defined the Worker via the Wrangler configuration (or the current working directory). + // The entry root is the base path used in bundling the source code for the Worker, + // which may be different from the project root if the Wrangler was redirected to use a different Wrangler configuration file. + const projectRoot = path.resolve(path.dirname(config.userConfigPath ?? ".")); + const entryRoot = path.resolve(path.dirname(config.configPath ?? ".")); + const absolutePath = path.resolve(entryRoot, main); + const relativePath = path.relative(entryRoot, absolutePath) || "."; + return { absolutePath, relativePath, projectRoot }; } export function resolveEntryWithEntryPoint( entryPoint: string, - configPath?: string + config: Config ): { absolutePath: string; relativePath: string; projectRoot: string; } { - const projectRoot = path.resolve(path.dirname(configPath ?? ".")); + const projectRoot = path.resolve(path.dirname(config.userConfigPath ?? ".")); + const entryRoot = path.resolve(path.dirname(config.configPath ?? ".")); const file = path.extname(entryPoint) ? path.resolve(entryPoint) : path.resolve(entryPoint, "index.js"); - const relativePath = path.relative(projectRoot, file) || "."; + const relativePath = path.relative(entryRoot, file) || "."; return { absolutePath: file, relativePath, projectRoot }; } diff --git a/packages/wrangler/src/dev.ts b/packages/wrangler/src/dev.ts index f2b029641f60..833cc452b10f 100644 --- a/packages/wrangler/src/dev.ts +++ b/packages/wrangler/src/dev.ts @@ -12,7 +12,6 @@ import { } from "./api/startDevWorker/utils"; import { getAssetsOptions } from "./assets"; import { configFileName, formatConfigSnippet } from "./config"; -import { resolveWranglerConfigPath } from "./config/config-helpers"; import { createCommand } from "./core/create-command"; import { validateRoutes } from "./deploy/deploy"; import { validateNodeCompatMode } from "./deployment-bundle/node-compat"; @@ -698,8 +697,6 @@ export async function startDev(args: StartDevOptions) { ); } - const configPath = resolveWranglerConfigPath(args); - const authHook: AsyncHook]> = async ( config ) => { @@ -722,8 +719,8 @@ export async function startDev(args: StartDevOptions) { }; }; - if (Array.isArray(configPath)) { - const runtime = new MultiworkerRuntimeController(configPath.length); + if (Array.isArray(args.config)) { + const runtime = new MultiworkerRuntimeController(args.config.length); const primaryDevEnv = new DevEnv({ runtimes: [runtime] }); @@ -733,7 +730,7 @@ export async function startDev(args: StartDevOptions) { // Set up the primary DevEnv (the one that the ProxyController will connect to) devEnv = [ - await setupDevEnv(primaryDevEnv, configPath[0], authHook, { + await setupDevEnv(primaryDevEnv, args.config[0], authHook, { ...args, disableDevRegistry: true, multiworkerPrimary: true, @@ -743,7 +740,7 @@ export async function startDev(args: StartDevOptions) { // Set up all auxiliary DevEnvs devEnv.push( ...(await Promise.all( - (configPath as string[]).slice(1).map((c) => { + (args.config as string[]).slice(1).map((c) => { return setupDevEnv( new DevEnv({ runtimes: [runtime], @@ -813,7 +810,7 @@ export async function startDev(args: StartDevOptions) { unregisterHotKeys = registerDevHotKeys(devEnv, args); } - await setupDevEnv(devEnv, configPath, authHook, args); + await setupDevEnv(devEnv, args.config, authHook, args); } return { diff --git a/packages/wrangler/src/dev/dev-vars.ts b/packages/wrangler/src/dev/dev-vars.ts index ddd6922f96ba..9d889dfd2598 100644 --- a/packages/wrangler/src/dev/dev-vars.ts +++ b/packages/wrangler/src/dev/dev-vars.ts @@ -12,7 +12,7 @@ import type { Config } from "../config"; * * It is useful during development, to provide these types of variable locally. * When running `wrangler dev` we will look for a file called `.dev.vars`, situated - * next to the Wrangler configuration file (or in the current working directory if there is no + * next to the User's Wrangler configuration file (or in the current working directory if there is no * Wrangler configuration). If the `--env ` option is set, we'll first look for * `.dev.vars.`. * @@ -20,11 +20,13 @@ import type { Config } from "../config"; * bindings provided in the Wrangler configuration file. */ export function getVarsForDev( - config: Pick, + config: Pick, env: string | undefined, silent = false ): Config["vars"] { - const configDir = path.resolve(path.dirname(config.configPath ?? ".")); + const configDir = path.resolve( + config.userConfigPath ? path.dirname(config.userConfigPath) : "." + ); const devVarsPath = path.resolve(configDir, ".dev.vars"); const loaded = loadDotEnv(devVarsPath, env); if (loaded !== undefined) { diff --git a/packages/wrangler/src/dev/get-local-persistence-path.ts b/packages/wrangler/src/dev/get-local-persistence-path.ts index 4263d344703e..591d72c2c899 100644 --- a/packages/wrangler/src/dev/get-local-persistence-path.ts +++ b/packages/wrangler/src/dev/get-local-persistence-path.ts @@ -1,18 +1,15 @@ import path from "node:path"; +import type { Config } from "../config"; +/** + * Get a path to where we shall store persisted state in local dev. + * + * We use the `userConfigPath` rather than the potentially redirected `configPath` + * to decide the path to this directory. + */ export function getLocalPersistencePath( persistTo: string | undefined, - configPath: string | undefined -): string; - -export function getLocalPersistencePath( - persistTo: string | undefined, - configPath: string | undefined -): string | null; - -export function getLocalPersistencePath( - persistTo: string | undefined, - configPath: string | undefined + { userConfigPath }: Config ) { return persistTo ? // If path specified, always treat it as relative to cwd() @@ -20,7 +17,7 @@ export function getLocalPersistencePath( : // Otherwise, treat it as relative to the Wrangler configuration file, // if one can be found, otherwise cwd() path.resolve( - configPath ? path.dirname(configPath) : process.cwd(), + userConfigPath ? path.dirname(userConfigPath) : process.cwd(), ".wrangler/state" ); } diff --git a/packages/wrangler/src/kv/helpers.ts b/packages/wrangler/src/kv/helpers.ts index 61d271dd4374..10c708989512 100644 --- a/packages/wrangler/src/kv/helpers.ts +++ b/packages/wrangler/src/kv/helpers.ts @@ -436,11 +436,11 @@ export function getKVNamespaceId( // https://devblogs.microsoft.com/typescript/announcing-typescript-5-2/#using-declarations-and-explicit-resource-management export async function usingLocalNamespace( persistTo: string | undefined, - configPath: string | undefined, + config: Config, namespaceId: string, closure: (namespace: ReplaceWorkersTypes) => Promise ): Promise { - const persist = getLocalPersistencePath(persistTo, configPath); + const persist = getLocalPersistencePath(persistTo, config); const persistOptions = buildPersistOptions(persist); const mf = new Miniflare({ script: diff --git a/packages/wrangler/src/kv/index.ts b/packages/wrangler/src/kv/index.ts index 12c0b779c3f6..28889db2f7f4 100644 --- a/packages/wrangler/src/kv/index.ts +++ b/packages/wrangler/src/kv/index.ts @@ -350,7 +350,7 @@ export const kvKeyPutCommand = createCommand({ if (args.local) { await usingLocalNamespace( args.persistTo, - config.configPath, + config, namespaceId, (namespace) => namespace.put(key, new Blob([value]).stream(), { @@ -434,7 +434,7 @@ export const kvKeyListCommand = createCommand({ if (args.local) { const listResult = await usingLocalNamespace( args.persistTo, - config.configPath, + config, namespaceId, (namespace) => namespace.list({ prefix }) ); @@ -513,7 +513,7 @@ export const kvKeyGetCommand = createCommand({ if (args.local) { const val = await usingLocalNamespace( args.persistTo, - config.configPath, + config, namespaceId, async (namespace) => { const stream = await namespace.get(key, "stream"); @@ -598,7 +598,7 @@ export const kvKeyDeleteCommand = createCommand({ if (args.local) { await usingLocalNamespace( args.persistTo, - config.configPath, + config, namespaceId, (namespace) => namespace.delete(key) ); @@ -730,7 +730,7 @@ export const kvBulkPutCommand = createCommand({ if (args.local) { await usingLocalNamespace( args.persistTo, - config.configPath, + config, namespaceId, async (namespace) => { for (const value of content) { @@ -855,7 +855,7 @@ export const kvBulkDeleteCommand = createCommand({ if (args.local) { await usingLocalNamespace( args.persistTo, - config.configPath, + config, namespaceId, async (namespace) => { for (const key of keysToDelete) { diff --git a/packages/wrangler/src/pages/build-env.ts b/packages/wrangler/src/pages/build-env.ts index 4076f5905675..22bdaa0fa4ef 100644 --- a/packages/wrangler/src/pages/build-env.ts +++ b/packages/wrangler/src/pages/build-env.ts @@ -42,7 +42,9 @@ export const Handler = async (args: PagesBuildEnvArgs) => { "Checking for configuration in a Wrangler configuration file (BETA)\n" ); - const configPath = findWranglerConfig(args.projectDir); + const { configPath } = findWranglerConfig(args.projectDir, { + useRedirectIfAvailable: true, + }); if (!configPath || !existsSync(configPath)) { logger.debug("No Wrangler configuration file found. Exiting."); process.exitCode = EXIT_CODE_NO_CONFIG_FOUND; diff --git a/packages/wrangler/src/pages/build.ts b/packages/wrangler/src/pages/build.ts index 5a5c97ee04f7..0bc011c30e40 100644 --- a/packages/wrangler/src/pages/build.ts +++ b/packages/wrangler/src/pages/build.ts @@ -354,7 +354,9 @@ async function maybeReadPagesConfig( if (!args.projectDirectory || !args.buildMetadataPath) { return; } - const configPath = findWranglerConfig(args.projectDirectory); + const { configPath } = findWranglerConfig(args.projectDirectory, { + useRedirectIfAvailable: true, + }); // Fail early if the config file doesn't exist if (!configPath || !existsSync(configPath)) { return undefined; diff --git a/packages/wrangler/src/pages/deploy.ts b/packages/wrangler/src/pages/deploy.ts index b0b325e91aff..985ef008d0b2 100644 --- a/packages/wrangler/src/pages/deploy.ts +++ b/packages/wrangler/src/pages/deploy.ts @@ -115,7 +115,9 @@ export const Handler = async (args: PagesDeployArgs) => { } let config: Config | undefined; - const configPath = findWranglerConfig(process.cwd()); + const { configPath } = findWranglerConfig(process.cwd(), { + useRedirectIfAvailable: true, + }); try { /* diff --git a/packages/wrangler/src/pages/dev.ts b/packages/wrangler/src/pages/dev.ts index bf3e0a258567..9967059f509d 100644 --- a/packages/wrangler/src/pages/dev.ts +++ b/packages/wrangler/src/pages/dev.ts @@ -303,7 +303,10 @@ export const Handler = async (args: PagesDevArguments) => { // for `dev` we always use the top-level config, which means we need // to read the config file with `env` set to `undefined` - const config = readConfig({ ...args, env: undefined }); + const config = readConfig( + { ...args, env: undefined }, + { useRedirectIfAvailable: true } + ); const resolvedDirectory = args.directory ?? config.pages_build_output_dir; const [_pages, _dev, ...remaining] = args._; const command = remaining; diff --git a/packages/wrangler/src/pages/secret/index.ts b/packages/wrangler/src/pages/secret/index.ts index 11b0e5b33856..fe12608945f6 100644 --- a/packages/wrangler/src/pages/secret/index.ts +++ b/packages/wrangler/src/pages/secret/index.ts @@ -42,7 +42,7 @@ async function pagesProject( ); } let config: Config | undefined; - const configPath = findWranglerConfig(process.cwd()); + const { configPath } = findWranglerConfig(process.cwd()); try { /* diff --git a/packages/wrangler/src/r2/helpers.ts b/packages/wrangler/src/r2/helpers.ts index 25830e4b3fff..43efa2122852 100644 --- a/packages/wrangler/src/r2/helpers.ts +++ b/packages/wrangler/src/r2/helpers.ts @@ -350,14 +350,14 @@ export async function deleteR2Object( export async function usingLocalBucket( persistTo: string | undefined, - configPath: string | undefined, + config: Config, bucketName: string, closure: ( namespace: ReplaceWorkersTypes, mf: Miniflare ) => Promise ): Promise { - const persist = getLocalPersistencePath(persistTo, configPath); + const persist = getLocalPersistencePath(persistTo, config); const persistOptions = buildPersistOptions(persist); const mf = new Miniflare({ modules: true, diff --git a/packages/wrangler/src/r2/object.ts b/packages/wrangler/src/r2/object.ts index fa88dba1896c..dea39df0711f 100644 --- a/packages/wrangler/src/r2/object.ts +++ b/packages/wrangler/src/r2/object.ts @@ -95,7 +95,7 @@ export const r2ObjectGetCommand = createCommand({ if (objectGetYargs.local) { await usingLocalBucket( objectGetYargs.persistTo, - config.configPath, + config, bucket, async (r2Bucket) => { const object = await r2Bucket.get(key); @@ -274,7 +274,7 @@ export const r2ObjectPutCommand = createCommand({ if (local) { await usingLocalBucket( persistTo, - config.configPath, + config, bucket, async (r2Bucket, mf) => { const putOptions: R2PutOptions = { @@ -376,11 +376,8 @@ export const r2ObjectDeleteCommand = createCommand({ logger.log(`Deleting object "${key}" from bucket "${fullBucketName}".`); if (args.local) { - await usingLocalBucket( - args.persistTo, - config.configPath, - bucket, - (r2Bucket) => r2Bucket.delete(key) + await usingLocalBucket(args.persistTo, config, bucket, (r2Bucket) => + r2Bucket.delete(key) ); } else { const accountId = await requireAuth(config); diff --git a/packages/wrangler/src/type-generation/index.ts b/packages/wrangler/src/type-generation/index.ts index 347b55f8cec7..b3ef27d136a7 100644 --- a/packages/wrangler/src/type-generation/index.ts +++ b/packages/wrangler/src/type-generation/index.ts @@ -3,7 +3,6 @@ import { basename, dirname, extname, join, relative, resolve } from "node:path"; import { findUpSync } from "find-up"; import { getNodeCompat } from "miniflare"; import { readConfig } from "../config"; -import { resolveWranglerConfigPath } from "../config/config-helpers"; import { getEntry } from "../deployment-bundle/entry"; import { getVarsForDev } from "../dev/dev-vars"; import { CommandLineArgsError, UserError } from "../errors"; @@ -63,11 +62,11 @@ export async function typesHandler( await printWranglerBanner(); - const configPath = resolveWranglerConfigPath(args); + const config = readConfig(args); if ( - !configPath || - !fs.existsSync(configPath) || - fs.statSync(configPath).isDirectory() + !config.configPath || + !fs.existsSync(config.configPath) || + fs.statSync(config.configPath).isDirectory() ) { logger.warn( `No config file detected${ @@ -77,8 +76,6 @@ export async function typesHandler( return; } - const config = readConfig(args); - // args.xRuntime will be a string if the user passes "--x-include-runtime" or "--x-include-runtime=..." if (typeof args.experimentalIncludeRuntime === "string") { logger.log(`Generating runtime types...`); @@ -89,7 +86,7 @@ export async function typesHandler( }); const tsconfigPath = - config.tsconfig ?? join(dirname(configPath), "tsconfig.json"); + config.tsconfig ?? join(dirname(config.configPath), "tsconfig.json"); const tsconfigTypes = readTsconfigTypes(tsconfigPath); const { mode } = getNodeCompat( config.compatibility_date, @@ -108,7 +105,10 @@ export async function typesHandler( } const secrets = getVarsForDev( - { configPath, vars: {} }, + // We do not want `getVarsForDev()` to merge in the standard vars into the dev vars + // because we want to be able to work with secrets differently to vars. + // So we pass in a fake vars object here. + { ...config, vars: {} }, args.env, true ) as Record; diff --git a/packages/wrangler/src/versions/deploy.ts b/packages/wrangler/src/versions/deploy.ts index ab596e0781d6..74cececee0f9 100644 --- a/packages/wrangler/src/versions/deploy.ts +++ b/packages/wrangler/src/versions/deploy.ts @@ -47,6 +47,10 @@ export const versionsDeployCommand = createCommand({ owner: "Workers: Authoring and Testing", status: "stable", }, + behaviour: { + useConfigRedirectIfAvailable: true, + }, + args: { name: { describe: "Name of the worker", diff --git a/packages/wrangler/src/versions/upload.ts b/packages/wrangler/src/versions/upload.ts index 94f6d2e2c56f..6c12e4b1992a 100644 --- a/packages/wrangler/src/versions/upload.ts +++ b/packages/wrangler/src/versions/upload.ts @@ -282,7 +282,7 @@ export const versionsUploadCommand = createCommand({ }, }, behaviour: { - provideConfig: true, + useConfigRedirectIfAvailable: true, }, handler: async function versionsUploadHandler(args, { config }) { const entry = await getEntry(args, config, "versions upload"); @@ -346,11 +346,7 @@ export const versionsUploadCommand = createCommand({ if (!args.dryRun) { assert(accountId, "Missing account ID"); - await verifyWorkerMatchesCITag( - accountId, - name, - path.relative(entry.projectRoot, config.configPath ?? "wrangler.toml") - ); + await verifyWorkerMatchesCITag(accountId, name, config.configPath); } if (!args.dryRun) { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 465591eb467b..d841d4fa1e99 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -603,6 +603,21 @@ importers: specifier: workspace:* version: link:../../packages/wrangler + fixtures/pages-redirected-config: + devDependencies: + '@cloudflare/workers-tsconfig': + specifier: workspace:^ + version: link:../../packages/workers-tsconfig + undici: + specifier: catalog:default + version: 5.28.4 + vitest: + specifier: catalog:default + version: 2.1.8(@types/node@18.19.59)(@vitest/ui@2.1.8)(msw@2.4.3(typescript@5.6.3))(supports-color@9.2.2) + wrangler: + specifier: workspace:* + version: link:../../packages/wrangler + fixtures/pages-simple-assets: devDependencies: '@cloudflare/workers-tsconfig': @@ -771,6 +786,21 @@ importers: specifier: workspace:* version: link:../../packages/wrangler + fixtures/redirected-config-worker: + devDependencies: + '@cloudflare/workers-tsconfig': + specifier: workspace:^ + version: link:../../packages/workers-tsconfig + undici: + specifier: catalog:default + version: 5.28.4 + vitest: + specifier: catalog:default + version: 2.1.8(@types/node@18.19.59)(@vitest/ui@2.1.8)(msw@2.4.3(typescript@5.6.3))(supports-color@9.2.2) + wrangler: + specifier: workspace:* + version: link:../../packages/wrangler + fixtures/routing-app: {} fixtures/rules-app: {} @@ -12941,7 +12971,7 @@ snapshots: '@vue/compiler-core': 3.3.4 '@vue/shared': 3.3.4 estree-walker: 2.0.2 - magic-string: 0.30.11 + magic-string: 0.30.14 '@vue/shared@3.3.4': {}