From 3a8c5c421acf6f0359cb246dabc355f7ea42263a Mon Sep 17 00:00:00 2001 From: Daniel Walsh Date: Fri, 6 Sep 2024 07:49:26 +0100 Subject: [PATCH] Add deployment alias url to `pages deploy` --- .changeset/angry-socks-pretend.md | 5 + .../src/__tests__/pages/deploy.test.ts | 254 +++++++++++------- packages/wrangler/src/pages/deploy.tsx | 7 +- 3 files changed, 169 insertions(+), 97 deletions(-) create mode 100644 .changeset/angry-socks-pretend.md diff --git a/.changeset/angry-socks-pretend.md b/.changeset/angry-socks-pretend.md new file mode 100644 index 000000000000..c2292dd0c26b --- /dev/null +++ b/.changeset/angry-socks-pretend.md @@ -0,0 +1,5 @@ +--- +"wrangler": patch +--- + +feat: add "Deployment alias URL" to `wrangler pages deploy` if an alias is available for this deployment. diff --git a/packages/wrangler/src/__tests__/pages/deploy.test.ts b/packages/wrangler/src/__tests__/pages/deploy.test.ts index 5f0e257243b2..6fab25846656 100644 --- a/packages/wrangler/src/__tests__/pages/deploy.test.ts +++ b/packages/wrangler/src/__tests__/pages/deploy.test.ts @@ -249,11 +249,11 @@ describe("pages deploy", () => { expect(getProjectRequestCount).toBe(2); expect(normalizeProgressSteps(std.out)).toMatchInlineSnapshot(` - "✨ Success! Uploaded 1 files (TIMINGS) + "✨ Success! Uploaded 1 files (TIMINGS) - 🌎 Deploying... - ✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/" - `); + 🌎 Deploying... + ✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/" + `); }); it("should retry uploads", async () => { @@ -420,11 +420,11 @@ describe("pages deploy", () => { expect(getProjectRequestCount).toBe(2); expect(normalizeProgressSteps(std.out)).toMatchInlineSnapshot(` - "✨ Success! Uploaded 1 files (TIMINGS) + "✨ Success! Uploaded 1 files (TIMINGS) - 🌎 Deploying... - ✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/" - `); + 🌎 Deploying... + ✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/" + `); }); it("should retry POST /deployments", async () => { @@ -582,11 +582,11 @@ describe("pages deploy", () => { expect(requests.length).toBe(2); expect(normalizeProgressSteps(std.out)).toMatchInlineSnapshot(` - "✨ Success! Uploaded 1 files (TIMINGS) + "✨ Success! Uploaded 1 files (TIMINGS) - 🌎 Deploying... - ✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/" - `); + 🌎 Deploying... + ✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/" + `); }); it("should retry GET /deployments/:deploymentId", async () => { @@ -802,13 +802,13 @@ describe("pages deploy", () => { expect(getProjectRequestCount).toEqual(2); expect(getDeploymentDetailsRequestCount).toEqual(3); expect(normalizeProgressSteps(std.out)).toMatchInlineSnapshot(` - "✨ Compiled Worker successfully - ✨ Success! Uploaded 1 files (TIMINGS) + "✨ Compiled Worker successfully + ✨ Success! Uploaded 1 files (TIMINGS) - ✨ Uploading Functions bundle - 🌎 Deploying... - ✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/" - `); + ✨ Uploading Functions bundle + 🌎 Deploying... + ✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/" + `); expect(std.err).toMatchInlineSnapshot(`""`); }); @@ -1010,11 +1010,11 @@ describe("pages deploy", () => { await runWrangler("pages deploy . --project-name=foo"); expect(normalizeProgressSteps(std.out)).toMatchInlineSnapshot(` - "✨ Success! Uploaded 1 files (TIMINGS) + "✨ Success! Uploaded 1 files (TIMINGS) - 🌎 Deploying... - ✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/" - `); + 🌎 Deploying... + ✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/" + `); }); it("should try to use multiple buckets (up to the max concurrency)", async () => { @@ -1204,11 +1204,11 @@ describe("pages deploy", () => { ); expect(normalizeProgressSteps(std.out)).toMatchInlineSnapshot(` - "✨ Success! Uploaded 4 files (TIMINGS) + "✨ Success! Uploaded 4 files (TIMINGS) - 🌎 Deploying... - ✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/" - `); + 🌎 Deploying... + ✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/" + `); }); it("should resolve child directories correctly", async () => { @@ -1397,11 +1397,11 @@ describe("pages deploy", () => { ); expect(normalizeProgressSteps(std.out)).toMatchInlineSnapshot(` - "✨ Success! Uploaded 4 files (TIMINGS) + "✨ Success! Uploaded 4 files (TIMINGS) - 🌎 Deploying... - ✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/" - `); + 🌎 Deploying... + ✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/" + `); }); it("should resolve the current directory correctly", async () => { @@ -1592,11 +1592,11 @@ describe("pages deploy", () => { ); expect(normalizeProgressSteps(std.out)).toMatchInlineSnapshot(` - "✨ Success! Uploaded 4 files (TIMINGS) + "✨ Success! Uploaded 4 files (TIMINGS) - 🌎 Deploying... - ✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/" - `); + 🌎 Deploying... + ✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/" + `); }); it("should not error when directory names contain periods and houses a extensionless file", async () => { @@ -1981,13 +1981,13 @@ describe("pages deploy", () => { expect(getProjectRequestCount).toEqual(2); expect(normalizeProgressSteps(std.out)).toMatchInlineSnapshot(` - "✨ Compiled Worker successfully - ✨ Success! Uploaded 1 files (TIMINGS) + "✨ Compiled Worker successfully + ✨ Success! Uploaded 1 files (TIMINGS) - ✨ Uploading Functions bundle - 🌎 Deploying... - ✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/" - `); + ✨ Uploading Functions bundle + 🌎 Deploying... + ✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/" + `); expect(std.err).toMatchInlineSnapshot('""'); }); @@ -2236,13 +2236,13 @@ async function onRequest() { expect(getProjectRequestCount).toEqual(2); expect(normalizeProgressSteps(std.out)).toMatchInlineSnapshot(` - "✨ Compiled Worker successfully - ✨ Success! Uploaded 1 files (TIMINGS) + "✨ Compiled Worker successfully + ✨ Success! Uploaded 1 files (TIMINGS) - ✨ Uploading Functions bundle - 🌎 Deploying... - ✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/" - `); + ✨ Uploading Functions bundle + 🌎 Deploying... + ✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/" + `); // make sure there were no errors expect(std.err).toMatchInlineSnapshot('""'); @@ -2504,14 +2504,14 @@ async function onRequest() { expect(getProjectRequestCount).toEqual(2); expect(normalizeProgressSteps(std.out)).toMatchInlineSnapshot(` - "✨ Compiled Worker successfully - ✨ Success! Uploaded 1 files (TIMINGS) + "✨ Compiled Worker successfully + ✨ Success! Uploaded 1 files (TIMINGS) - ✨ Uploading Functions bundle - ✨ Uploading _routes.json - 🌎 Deploying... - ✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/" - `); + ✨ Uploading Functions bundle + ✨ Uploading _routes.json + 🌎 Deploying... + ✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/" + `); expect(std.warn).toMatchInlineSnapshot(`""`); expect(std.err).toMatchInlineSnapshot('""'); @@ -3038,13 +3038,13 @@ Failed to publish your Function. Got error: Uncaught TypeError: a is not a funct expect(getProjectRequestCount).toEqual(2); expect(normalizeProgressSteps(std.out)).toMatchInlineSnapshot(` - "✨ Success! Uploaded 1 files (TIMINGS) + "✨ Success! Uploaded 1 files (TIMINGS) - ✨ Compiled Worker successfully - ✨ Uploading Worker bundle - 🌎 Deploying... - ✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/" - `); + ✨ Compiled Worker successfully + ✨ Uploading Worker bundle + 🌎 Deploying... + ✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/" + `); expect(std.err).toMatchInlineSnapshot('""'); }); @@ -3307,13 +3307,13 @@ Failed to publish your Function. Got error: Uncaught TypeError: a is not a funct expect(getProjectRequestCount).toEqual(2); expect(normalizeProgressSteps(std.out)).toMatchInlineSnapshot(` - "✨ Success! Uploaded 1 files (TIMINGS) + "✨ Success! Uploaded 1 files (TIMINGS) - ✨ Compiled Worker successfully - ✨ Uploading Worker bundle - 🌎 Deploying... - ✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/" - `); + ✨ Compiled Worker successfully + ✨ Uploading Worker bundle + 🌎 Deploying... + ✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/" + `); // make sure there were no errors expect(std.err).toMatchInlineSnapshot('""'); @@ -3573,14 +3573,14 @@ Failed to publish your Function. Got error: Uncaught TypeError: a is not a funct expect(getProjectRequestCount).toEqual(2); expect(normalizeProgressSteps(std.out)).toMatchInlineSnapshot(` - "✨ Success! Uploaded 1 files (TIMINGS) + "✨ Success! Uploaded 1 files (TIMINGS) - ✨ Compiled Worker successfully - ✨ Uploading Worker bundle - ✨ Uploading _routes.json - 🌎 Deploying... - ✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/" - `); + ✨ Compiled Worker successfully + ✨ Uploading Worker bundle + ✨ Uploading _routes.json + 🌎 Deploying... + ✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/" + `); expect(std.warn).toMatchInlineSnapshot(`""`); expect(std.err).toMatchInlineSnapshot(`""`); @@ -3934,13 +3934,13 @@ and that at least one include rule is provided. expect(getProjectRequestCount).toEqual(2); expect(normalizeProgressSteps(std.out)).toMatchInlineSnapshot(` - "✨ Success! Uploaded 1 files (TIMINGS) + "✨ Success! Uploaded 1 files (TIMINGS) - ✨ Compiled Worker successfully - ✨ Uploading Worker bundle - 🌎 Deploying... - ✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/" - `); + ✨ Compiled Worker successfully + ✨ Uploading Worker bundle + 🌎 Deploying... + ✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/" + `); expect(std.err).toMatchInlineSnapshot('""'); }); @@ -4300,12 +4300,12 @@ and that at least one include rule is provided. await runWrangler("pages deploy public --project-name=foo --no-bundle"); expect(normalizeProgressSteps(std.out)).toMatchInlineSnapshot(` - "✨ Success! Uploaded 1 files (TIMINGS) + "✨ Success! Uploaded 1 files (TIMINGS) - ✨ Uploading Worker bundle - 🌎 Deploying... - ✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/" - `); + ✨ Uploading Worker bundle + 🌎 Deploying... + ✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/" + `); expect(std.err).toMatchInlineSnapshot('""'); }); @@ -4713,13 +4713,13 @@ Failed to publish your Function. Got error: Uncaught TypeError: a is not a funct expect(getProjectRequestCount).toEqual(2); expect(normalizeProgressSteps(std.out)).toMatchInlineSnapshot(` - "✨ Success! Uploaded 1 files (TIMINGS) + "✨ Success! Uploaded 1 files (TIMINGS) - ✨ Compiled Worker successfully - ✨ Uploading Worker bundle - 🌎 Deploying... - ✨ Deployment complete! Take a peek over at https://abcxyz.pages-is-awesome.pages.dev/" - `); + ✨ Compiled Worker successfully + ✨ Uploading Worker bundle + 🌎 Deploying... + ✨ Deployment complete! Take a peek over at https://abcxyz.pages-is-awesome.pages.dev/" + `); expect(std.err).toMatchInlineSnapshot('""'); }); @@ -4981,13 +4981,13 @@ Failed to publish your Function. Got error: Uncaught TypeError: a is not a funct expect(getProjectRequestCount).toEqual(2); expect(normalizeProgressSteps(std.out)).toMatchInlineSnapshot(` - "✨ Success! Uploaded 1 files (TIMINGS) + "✨ Success! Uploaded 1 files (TIMINGS) - ✨ Compiled Worker successfully - ✨ Uploading Worker bundle - 🌎 Deploying... - ✨ Deployment complete! Take a peek over at https://abcxyz.pages-project.pages.dev/" - `); + ✨ Compiled Worker successfully + ✨ Uploading Worker bundle + 🌎 Deploying... + ✨ Deployment complete! Take a peek over at https://abcxyz.pages-project.pages.dev/" + `); expect(std.err).toMatchInlineSnapshot('""'); }); @@ -4997,7 +4997,8 @@ Failed to publish your Function. Got error: Uncaught TypeError: a is not a funct generatedWorkerBundleCheck: ( workerJsContent: FormDataEntryValue | null ) => Promise, - compatibility_flags?: string[] + compatibility_flags?: string[], + aliases?: string[], ) => { mockGetUploadTokenRequest( "<>", @@ -5069,6 +5070,7 @@ Failed to publish your Function. Got error: Uncaught TypeError: a is not a funct errors: [], messages: [], result: { + aliases, latest_stage: { name: "deploy", status: "success", @@ -5370,6 +5372,66 @@ Failed to publish your Function. Got error: Uncaught TypeError: a is not a funct await runWrangler("pages deploy"); }); }); + + describe('deployment aliases', () => { + it("should support outputting an alias url", async () => { + // set up the directory of static files to upload. + mkdirSync("public"); + writeFileSync("public/README.md", "This is a readme"); + + simulateServer(async () => {}, [], ['https://staging.foo.pages.dev']); + + await runWrangler("pages deploy public --project-name=foo"); + + expect(normalizeProgressSteps(std.out)).toMatchInlineSnapshot(` + "✨ Success! Uploaded 1 files (TIMINGS) + + 🌎 Deploying... + ✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/ + ✨ Deployment alias URL: https://staging.foo.pages.dev" + `); + + expect(std.err).toMatchInlineSnapshot(`""`); + }); + + it("ignores custom domains", async () => { + // set up the directory of static files to upload. + mkdirSync("public"); + writeFileSync("public/README.md", "This is a readme"); + + simulateServer(async () => {}, [], ['https://example.com']); + + await runWrangler("pages deploy public --project-name=foo"); + + expect(normalizeProgressSteps(std.out)).toMatchInlineSnapshot(` + "✨ Success! Uploaded 1 files (TIMINGS) + + 🌎 Deploying... + ✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/" + `); + + expect(std.err).toMatchInlineSnapshot(`""`); + }); + + it("continues to work fine if no aliases", async () => { + // set up the directory of static files to upload. + mkdirSync("public"); + writeFileSync("public/README.md", "This is a readme"); + + simulateServer(async () => {}, [], []); + + await runWrangler("pages deploy public --project-name=foo"); + + expect(normalizeProgressSteps(std.out)).toMatchInlineSnapshot(` + "✨ Success! Uploaded 1 files (TIMINGS) + + 🌎 Deploying... + ✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/" + `); + + expect(std.err).toMatchInlineSnapshot(`""`); + }); + }); }); function mockGetProjectHandler( diff --git a/packages/wrangler/src/pages/deploy.tsx b/packages/wrangler/src/pages/deploy.tsx index 4506ecde2873..680b115b9c2a 100644 --- a/packages/wrangler/src/pages/deploy.tsx +++ b/packages/wrangler/src/pages/deploy.tsx @@ -365,6 +365,7 @@ export const Handler = async (args: PagesDeployArgs) => { }); let latestDeploymentStage: DeploymentStage | undefined; + let alias: string | undefined; let attempts = 0; logger.log("🌎 Deploying..."); @@ -393,6 +394,9 @@ export const Handler = async (args: PagesDeployArgs) => { `/accounts/${accountId}/pages/projects/${projectName}/deployments/${deploymentResponse.id}` ); latestDeploymentStage = deployment.latest_stage; + // Aliases is an array but will only ever return one pages.dev + // If preview, this will return a branch alias. If production, this will return custom domains + alias = (deployment.aliases?.filter((alias) => alias.endsWith('.pages.dev')) ?? [])[0]; } catch (err) { // don't retry if API call retruned an error logger.debug( @@ -406,7 +410,8 @@ export const Handler = async (args: PagesDeployArgs) => { latestDeploymentStage?.status === "success" ) { logger.log( - `✨ Deployment complete! Take a peek over at ${deploymentResponse.url}` + `✨ Deployment complete! Take a peek over at ${deploymentResponse.url}` + + (alias ? `\n✨ Deployment alias URL: ${alias}` : "") ); } else if ( latestDeploymentStage?.name === "deploy" &&