Skip to content

Commit

Permalink
Provide validation around experimental_serve_directly usage in dev an…
Browse files Browse the repository at this point in the history
…d deploy
  • Loading branch information
WillTaylorDev authored and CarmenPopoviciu committed Dec 19, 2024
1 parent 4fe93de commit 95e00b2
Show file tree
Hide file tree
Showing 24 changed files with 1,405 additions and 160 deletions.
5 changes: 5 additions & 0 deletions .changeset/clean-peas-exist.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"wrangler": patch
---

Add file prefix option to wrangler pipelines commands
7 changes: 7 additions & 0 deletions .changeset/swift-bulldogs-repeat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"wrangler": patch
---

The `x-provision` experimental flag now identifies draft and inherit bindings by looking up the current binding settings.

Draft bindings can then be provisioned (connected to new or existing KV, D1, or R2 resources) during `wrangler deploy`.
5 changes: 5 additions & 0 deletions .changeset/swift-zebras-guess.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"wrangler": minor
---

Provide validation around assets.experimental_serve_directly
5 changes: 5 additions & 0 deletions packages/wrangler/e2e/helpers/normalize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export function normalizeOutput(
removeWorkerPreviewUrl,
removeUUID,
removeBinding,
removeKVId,
normalizeErrorMarkers,
replaceByte,
stripTrailingWhitespace,
Expand Down Expand Up @@ -77,6 +78,10 @@ function removeBinding(str: string) {
);
}

function removeKVId(str: string) {
return str.replace(/([0-9a-f]{32})/g, "00000000000000000000000000000000");
}

/**
* Remove the Wrangler version/update check header
*/
Expand Down
195 changes: 195 additions & 0 deletions packages/wrangler/e2e/provision.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
import assert from "node:assert";
import dedent from "ts-dedent";
import { fetch } from "undici";
import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { CLOUDFLARE_ACCOUNT_ID } from "./helpers/account-id";
import { WranglerE2ETestHelper } from "./helpers/e2e-wrangler-test";
import { fetchText } from "./helpers/fetch-text";
import { generateResourceName } from "./helpers/generate-resource-name";
import { normalizeOutput } from "./helpers/normalize";
import { retry } from "./helpers/retry";

const TIMEOUT = 500_000;
const normalize = (str: string) => {
return normalizeOutput(str, {
[CLOUDFLARE_ACCOUNT_ID]: "CLOUDFLARE_ACCOUNT_ID",
});
};
const workerName = generateResourceName();

describe("provisioning", { timeout: TIMEOUT }, () => {
let deployedUrl: string;
let kvId: string;
let d1Id: string;
const helper = new WranglerE2ETestHelper();

it("can run dev without resource ids", async () => {
const worker = helper.runLongLived("wrangler dev --x-provision");

const { url } = await worker.waitForReady();
await fetch(url);

const text = await fetchText(url);

expect(text).toMatchInlineSnapshot(`"Hello World!"`);
});

beforeAll(async () => {
await helper.seed({
"wrangler.toml": dedent`
name = "${workerName}"
main = "src/index.ts"
compatibility_date = "2023-01-01"
[[kv_namespaces]]
binding = "KV"
[[r2_buckets]]
binding = "R2"
[[d1_databases]]
binding = "D1"
`,
"src/index.ts": dedent`
export default {
fetch(request) {
return new Response("Hello World!")
}
}`,
"package.json": dedent`
{
"name": "${workerName}",
"version": "0.0.0",
"private": true
}
`,
});
});

it("can provision resources and deploy worker", async () => {
const worker = helper.runLongLived(
`wrangler deploy --x-provision --x-auto-create`
);
await worker.exitCode;
const output = await worker.output;
expect(normalize(output)).toMatchInlineSnapshot(`
"Total Upload: xx KiB / gzip: xx KiB
The following bindings need to be provisioned:
- KV Namespaces:
- KV
- D1 Databases:
- D1
- R2 Buckets:
- R2
Provisioning KV (KV Namespace)...
🌀 Creating new KV Namespace "tmp-e2e-worker-00000000-0000-0000-0000-000000000000-kv"...
✨ KV provisioned with tmp-e2e-worker-00000000-0000-0000-0000-000000000000-kv
--------------------------------------
Provisioning D1 (D1 Database)...
🌀 Creating new D1 Database "tmp-e2e-worker-00000000-0000-0000-0000-000000000000-d1"...
✨ D1 provisioned with tmp-e2e-worker-00000000-0000-0000-0000-000000000000-d1
--------------------------------------
Provisioning R2 (R2 Bucket)...
🌀 Creating new R2 Bucket "tmp-e2e-worker-00000000-0000-0000-0000-000000000000-r2"...
✨ R2 provisioned with tmp-e2e-worker-00000000-0000-0000-0000-000000000000-r2
--------------------------------------
🎉 All resources provisioned, continuing with deployment...
Your worker has access to the following bindings:
- KV Namespaces:
- KV: 00000000000000000000000000000000
- D1 Databases:
- D1: 00000000-0000-0000-0000-000000000000
- R2 Buckets:
- R2: tmp-e2e-worker-00000000-0000-0000-0000-000000000000-r2
Uploaded tmp-e2e-worker-00000000-0000-0000-0000-000000000000 (TIMINGS)
Deployed tmp-e2e-worker-00000000-0000-0000-0000-000000000000 triggers (TIMINGS)
https://tmp-e2e-worker-00000000-0000-0000-0000-000000000000.SUBDOMAIN.workers.dev
Current Version ID: 00000000-0000-0000-0000-000000000000"
`);
const urlMatch = output.match(
/(?<url>https:\/\/tmp-e2e-.+?\..+?\.workers\.dev)/
);
assert(urlMatch?.groups);
deployedUrl = urlMatch.groups.url;

const kvMatch = output.match(/- KV: (?<kv>[0-9a-f]{32})/);
assert(kvMatch?.groups);
kvId = kvMatch.groups.kv;

const d1Match = output.match(/- D1: (?<d1>\w{8}-\w{4}-\w{4}-\w{4}-\w{12})/);
assert(d1Match?.groups);
d1Id = d1Match.groups.d1;

const { text } = await retry(
(s) => s.status !== 200,
async () => {
const r = await fetch(deployedUrl);
return { text: await r.text(), status: r.status };
}
);
expect(text).toMatchInlineSnapshot('"Hello World!"');
});

it("can inherit bindings on re-deploy and won't re-provision", async () => {
const worker = helper.runLongLived(`wrangler deploy --x-provision`);
await worker.exitCode;
const output = await worker.output;
expect(normalize(output)).toMatchInlineSnapshot(`
"Total Upload: xx KiB / gzip: xx KiB
Your worker has access to the following bindings:
- KV Namespaces:
- KV
- D1 Databases:
- D1
- R2 Buckets:
- R2
Uploaded tmp-e2e-worker-00000000-0000-0000-0000-000000000000 (TIMINGS)
Deployed tmp-e2e-worker-00000000-0000-0000-0000-000000000000 triggers (TIMINGS)
https://tmp-e2e-worker-00000000-0000-0000-0000-000000000000.SUBDOMAIN.workers.dev
Current Version ID: 00000000-0000-0000-0000-000000000000"
`);

const { text } = await retry(
(s) => s.status !== 200,
async () => {
const r = await fetch(deployedUrl);
return { text: await r.text(), status: r.status };
}
);
expect(text).toMatchInlineSnapshot('"Hello World!"');
});

afterAll(async () => {
// we need to add d1 back into the config because otherwise wrangler will
// call the api for all 5000 or so db's the e2e test account has
// :(
await helper.seed({
"wrangler.toml": dedent`
name = "${workerName}"
main = "src/index.ts"
compatibility_date = "2023-01-01"
[[d1_databases]]
binding = "D1"
database_name = "${workerName}-d1"
database_id = "${d1Id}"
`,
});
let output = await helper.run(`wrangler r2 bucket delete ${workerName}-r2`);
expect(output.stdout).toContain(`Deleted bucket`);
output = await helper.run(`wrangler d1 delete ${workerName}-d1 -y`);
expect(output.stdout).toContain(`Deleted '${workerName}-d1' successfully.`);
output = await helper.run(`wrangler delete`);
expect(output.stdout).toContain("Successfully deleted");
const status = await retry(
(s) => s === 200 || s === 500,
() => fetch(deployedUrl).then((r) => r.status)
);
expect(status).toBe(404);

output = await helper.run(
`wrangler kv namespace delete --namespace-id ${kvId}`
);
expect(output.stdout).toContain(`Deleted KV namespace`);
}, TIMEOUT);
});
Loading

0 comments on commit 95e00b2

Please sign in to comment.