From 27e0aab854b2ef6117a6ea1f6bf268213da9874b Mon Sep 17 00:00:00 2001 From: Pete Bacon Darwin Date: Wed, 8 Jan 2025 09:32:40 +0000 Subject: [PATCH] feat: add support for redirecting Wrangler to a generated config when running deploy commands (#7442) * Do not console log wrangler output during normal fixture tests This creates a lot of unwanted logging in the console. The logging is still dumped to the console if the test times out, or if `WRANGLER_LOG=debug` is set as env var. * no need to get relative config path for calls to verifyWorkerMatchesCITag() * feat: add support for redirecting Wrangler to a generated config when running deploy 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 commands. It is not expected that developers of Workers will need to use this feature directly. The commands that use this feature are: - `wrangler deploy` - `wrangler dev` - `wrangler versions upload` - `wrangler versions deploy` 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 use the `configPath` (relative to the `deploy.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. 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" } ``` * add config redirect fixture with tests * Add config redirect support for Pages commands * refactor: compute both the actual config path and the original user's configuration * add `userConfigPath` to the `Config` type so it can be used where needed * add fixture and test for redirected config in a pages project * Do not check formatting of generated fixture files * clean node_modules for npm-import fixture before testing * fix unstable_dev tests * run more Wrangler e2e tests on safe ports * Requires that you create a `.env` file in the `packages/wrangler` directory containing: ``` CLOUDFLARE_ACCOUNT_ID= CLOUDFLARE_API_TOKEN= WRANGLER="node " WRANGLER_IMPORT="" ```` * correctly configure python workers when no command line script is provided * test: ensure that `pages functions build-env` command outputs correct relative pages_build_output_dir path * Improve error message when deploy/config.json is not valid * Complete jsdoc description * Update jsdocs to note that the result of `resolveWranglerConfigPath()` contains absolute paths. * PR feedback * rename `useRedirect` to `useRedirectIfAvailable` * Rename command definition behaviour from "useConfigRedirect" to "useConfigRedirectIfAvailable" * Add clarifying comment * Do not store package-lock.json for import-npm fixture This fixture does not need a package lockfile to work. * Remove unnecessary option in test --- .changeset/thin-pots-camp.md | 84 ++ .prettierignore | 4 + fixtures/import-npm/package-lock.json | 185 ----- fixtures/import-npm/package.json | 9 +- fixtures/import-npm/turbo.json | 13 +- fixtures/pages-redirected-config/.gitignore | 2 + fixtures/pages-redirected-config/package.json | 23 + fixtures/pages-redirected-config/src/index.js | 5 + .../tests/index.test.ts | 54 ++ .../pages-redirected-config/tools/build.ts | 24 + .../pages-redirected-config/tsconfig.json | 13 + fixtures/pages-redirected-config/turbo.json | 9 + .../pages-redirected-config/vitest.config.mts | 9 + fixtures/redirected-config-worker/.gitignore | 2 + .../redirected-config-worker/package.json | 23 + .../redirected-config-worker/src/index.js | 5 + .../tests/index.test.ts | 40 + .../redirected-config-worker/tools/build.ts | 22 + .../redirected-config-worker/tsconfig.json | 13 + fixtures/redirected-config-worker/turbo.json | 9 + .../vitest.config.mts | 9 + .../redirected-config-worker/wrangler.toml | 4 + .../shared/src/run-wrangler-long-lived.ts | 8 +- packages/wrangler/e2e/dev-registry.test.ts | 6 +- .../wrangler/e2e/dev-with-resources.test.ts | 61 +- packages/wrangler/e2e/pages-dev.test.ts | 751 +++++++++--------- packages/wrangler/package.json | 4 +- .../{ => config}/configuration.pages.test.ts | 15 +- .../{ => config}/configuration.test.ts | 334 +++++++- .../config/findWranglerConfig.test.ts | 278 +++++++ .../wrangler/src/__tests__/d1/migrate.test.ts | 22 +- .../wrangler/src/__tests__/get-entry.test.ts | 1 + .../src/__tests__/helpers/normalize.ts | 9 +- .../helpers/write-wrangler-config.ts | 4 +- .../__tests__/pages/pages-build-env.test.ts | 33 +- .../src/__tests__/type-generation.test.ts | 13 +- packages/wrangler/src/api/pages/deploy.ts | 5 +- .../api/startDevWorker/ConfigController.ts | 44 +- .../wrangler/src/config/config-helpers.ts | 136 +++- packages/wrangler/src/config/config.ts | 4 + packages/wrangler/src/config/index.ts | 76 +- .../wrangler/src/config/validation-pages.ts | 5 +- packages/wrangler/src/config/validation.ts | 5 +- .../src/core/register-yargs-command.ts | 2 + packages/wrangler/src/core/types.ts | 5 + packages/wrangler/src/d1/execute.ts | 2 +- packages/wrangler/src/d1/export.ts | 2 +- packages/wrangler/src/deploy/index.ts | 15 +- .../wrangler/src/deployment-bundle/entry.ts | 4 +- .../src/deployment-bundle/resolve-entry.ts | 22 +- packages/wrangler/src/dev.ts | 13 +- packages/wrangler/src/dev/dev-vars.ts | 8 +- .../src/dev/get-local-persistence-path.ts | 21 +- packages/wrangler/src/kv/helpers.ts | 4 +- packages/wrangler/src/kv/index.ts | 12 +- packages/wrangler/src/pages/build-env.ts | 4 +- packages/wrangler/src/pages/build.ts | 4 +- packages/wrangler/src/pages/deploy.ts | 4 +- packages/wrangler/src/pages/dev.ts | 5 +- packages/wrangler/src/pages/secret/index.ts | 2 +- packages/wrangler/src/r2/helpers.ts | 4 +- packages/wrangler/src/r2/object.ts | 11 +- .../wrangler/src/type-generation/index.ts | 18 +- packages/wrangler/src/versions/deploy.ts | 4 + packages/wrangler/src/versions/upload.ts | 8 +- pnpm-lock.yaml | 32 +- 66 files changed, 1788 insertions(+), 793 deletions(-) create mode 100644 .changeset/thin-pots-camp.md delete mode 100644 fixtures/import-npm/package-lock.json create mode 100644 fixtures/pages-redirected-config/.gitignore create mode 100644 fixtures/pages-redirected-config/package.json create mode 100644 fixtures/pages-redirected-config/src/index.js create mode 100644 fixtures/pages-redirected-config/tests/index.test.ts create mode 100644 fixtures/pages-redirected-config/tools/build.ts create mode 100644 fixtures/pages-redirected-config/tsconfig.json create mode 100644 fixtures/pages-redirected-config/turbo.json create mode 100644 fixtures/pages-redirected-config/vitest.config.mts create mode 100644 fixtures/redirected-config-worker/.gitignore create mode 100644 fixtures/redirected-config-worker/package.json create mode 100644 fixtures/redirected-config-worker/src/index.js create mode 100644 fixtures/redirected-config-worker/tests/index.test.ts create mode 100644 fixtures/redirected-config-worker/tools/build.ts create mode 100644 fixtures/redirected-config-worker/tsconfig.json create mode 100644 fixtures/redirected-config-worker/turbo.json create mode 100644 fixtures/redirected-config-worker/vitest.config.mts create mode 100644 fixtures/redirected-config-worker/wrangler.toml rename packages/wrangler/src/__tests__/{ => config}/configuration.pages.test.ts (98%) rename packages/wrangler/src/__tests__/{ => config}/configuration.test.ts (97%) create mode 100644 packages/wrangler/src/__tests__/config/findWranglerConfig.test.ts 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': {}