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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .changeset/funny-comics-lick.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
"wrangler": minor
---

feature: log version preview url when previews exist

The version upload API returns a field indicating whether
a preview exists for that version. If a preview exists and
workers.dev is enabled, wrangler will now log the full
URL on version upload.

This does not impact wrangler deploy, which only prints the
workers.dev route of the latest deployment.
18 changes: 18 additions & 0 deletions .changeset/modern-scissors-relax.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
"wrangler": patch
---

chore: fix version upload log order

Previously deploy prints:
upload timings
deploy timings
current version id

while version upload prints:
worker version id
upload timings

This change makes version upload more similar to deploy by printing
version id after upload, which also makes more sense, as version ID can
only be known after upload has finished.
2 changes: 1 addition & 1 deletion packages/wrangler/e2e/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ describe("uploading Worker versions", () => {
// Check the output looks correct
expect(normalize(upload.stdout)).toMatchInlineSnapshot(`
"Total Upload: xx KiB / gzip: xx KiB
Worker Version ID: 00000000-0000-0000-0000-000000000000
Uploaded tmp-e2e-worker-00000000-0000-0000-0000-000000000000 (TIMINGS)
Worker Version ID: 00000000-0000-0000-0000-000000000000
To deploy this version to production traffic use the command wrangler versions deploy --experimental-versions
Changes to non-versioned settings (config properties 'logpush' or 'tail_consumers') take effect after your next deployment using the command wrangler versions deploy --experimental-versions
Changes to triggers (routes, custom domains, cron schedules, etc) must be applied with the command wrangler triggers deploy --experimental-versions"
Expand Down
4 changes: 2 additions & 2 deletions packages/wrangler/e2e/versions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ describe("versions deploy", { timeout: TIMEOUT }, () => {
expect(normalize(upload.stdout)).toMatchInlineSnapshot(`
"Total Upload: xx KiB / gzip: xx KiB
Worker Startup Time: (TIMINGS)
Worker Version ID: 00000000-0000-0000-0000-000000000000
Uploaded tmp-e2e-worker-00000000-0000-0000-0000-000000000000 (TIMINGS)
Worker Version ID: 00000000-0000-0000-0000-000000000000
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Never realised that version upload had this before -- deploy is correct (uploaded then version)

To deploy this version to production traffic use the command wrangler versions deploy
Changes to non-versioned settings (config properties 'logpush' or 'tail_consumers') take effect after your next deployment using the command wrangler versions deploy
Changes to triggers (routes, custom domains, cron schedules, etc) must be applied with the command wrangler triggers deploy"
Expand Down Expand Up @@ -176,8 +176,8 @@ describe("versions deploy", { timeout: TIMEOUT }, () => {
expect(normalize(upload.stdout)).toMatchInlineSnapshot(`
"Total Upload: xx KiB / gzip: xx KiB
Worker Startup Time: (TIMINGS)
Worker Version ID: 00000000-0000-0000-0000-000000000000
Uploaded tmp-e2e-worker-00000000-0000-0000-0000-000000000000 (TIMINGS)
Worker Version ID: 00000000-0000-0000-0000-000000000000
To deploy this version to production traffic use the command wrangler versions deploy
Changes to non-versioned settings (config properties 'logpush' or 'tail_consumers') take effect after your next deployment using the command wrangler versions deploy
Changes to triggers (routes, custom domains, cron schedules, etc) must be applied with the command wrangler triggers deploy"
Expand Down
129 changes: 102 additions & 27 deletions packages/wrangler/src/__tests__/versions/versions.upload.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import * as fs from "node:fs";
import { http, HttpResponse } from "msw";
import { mockAccountId, mockApiToken } from "../helpers/mock-account-id";
import { mockConsoleMethods } from "../helpers/mock-console";
import { useMockIsTTY } from "../helpers/mock-istty";
import { mockSubDomainRequest } from "../helpers/mock-workers-subdomain";
import { msw } from "../helpers/msw";
import { createFetchResult, msw } from "../helpers/msw";
import { runInTempDir } from "../helpers/run-in-tmp";
import { runWrangler } from "../helpers/run-wrangler";
import { writeWorkerSource } from "../helpers/write-worker-source";
Expand All @@ -17,56 +16,68 @@ describe("versions upload", () => {
const { setIsTTY } = useMockIsTTY();
const std = mockConsoleMethods();

test("should print bindings & startup time on versions upload", async () => {
function mockGetScript() {
msw.use(
http.get(
`*/accounts/:accountId/workers/services/:scriptName`,
({ params }) => {
expect(params.scriptName).toEqual("test-worker");

return HttpResponse.json(
{
success: true,
errors: [],
messages: [],
result: {
default_environment: {
script: {
last_deployed_from: "wrangler",
},
createFetchResult({
default_environment: {
script: {
last_deployed_from: "wrangler",
},
},
},
{ status: 200 }
})
);
},
{ once: true }
),
)
);
}
function mockUploadVersion(has_preview: boolean) {
msw.use(
http.post(
`*/accounts/:accountId/workers/scripts/:scriptName/versions`,
({ params }) => {
expect(params.scriptName).toEqual("test-worker");

return HttpResponse.json(
{
success: true,
errors: [],
messages: [],
result: {
id: "51e4886e-2db7-4900-8d38-fbfecfeab993",
startup_time_ms: 500,
createFetchResult({
id: "51e4886e-2db7-4900-8d38-fbfecfeab993",
startup_time_ms: 500,
metadata: {
has_preview: has_preview,
},
},
{ status: 200 }
})
);
},
{ once: true }
)
);
mockSubDomainRequest();
}

function mockGetWorkerSubdomain(available_on_subdomain: boolean) {
msw.use(
http.get(
`*/accounts/:accountId/workers/scripts/:scriptName/subdomain`,
({ params }) => {
expect(params.scriptName).toEqual("test-worker");
return HttpResponse.json(
createFetchResult({ enabled: available_on_subdomain })
);
}
)
);
}

test("should print bindings & startup time on versions upload", async () => {
mockGetScript();
mockUploadVersion(false);

// Setup
fs.mkdirSync("./versions-upload-test-worker", { recursive: true });
writeWranglerToml({
name: "test-worker",
main: "./index.js",
Expand Down Expand Up @@ -98,8 +109,72 @@ describe("versions upload", () => {
\\"abc\\": \\"def\\",
\\"bool\\": true
}
Uploaded test-worker (TIMINGS)
Worker Version ID: 51e4886e-2db7-4900-8d38-fbfecfeab993"
`);
});

test("should print preview url if version has preview", async () => {
mockGetScript();
mockUploadVersion(true);
mockGetWorkerSubdomain(true);
mockSubDomainRequest();

// Setup
writeWranglerToml({
name: "test-worker",
main: "./index.js",
vars: {
TEST: "test-string",
},
});
writeWorkerSource();
setIsTTY(false);

const result = runWrangler("versions upload --x-versions");

await expect(result).resolves.toBeUndefined();

expect(std.out).toMatchInlineSnapshot(`
"Total Upload: xx KiB / gzip: xx KiB
Worker Startup Time: 500 ms
Your worker has access to the following bindings:
- Vars:
- TEST: \\"test-string\\"
Uploaded test-worker (TIMINGS)
Worker Version ID: 51e4886e-2db7-4900-8d38-fbfecfeab993
Uploaded test-worker (TIMINGS)"
Version Preview URL: https://51e4886e-test-worker.test-sub-domain.workers.dev"
`);
});

it("should not print preview url workers_dev is false", async () => {
mockGetScript();
mockUploadVersion(true);
mockGetWorkerSubdomain(false);

// Setup
writeWranglerToml({
name: "test-worker",
main: "./index.js",
vars: {
TEST: "test-string",
},
});
writeWorkerSource();
setIsTTY(false);

const result = runWrangler("versions upload --x-versions");

await expect(result).resolves.toBeUndefined();

expect(std.out).toMatchInlineSnapshot(`
"Total Upload: xx KiB / gzip: xx KiB
Worker Startup Time: 500 ms
Your worker has access to the following bindings:
- Vars:
- TEST: \\"test-string\\"
Uploaded test-worker (TIMINGS)
Worker Version ID: 51e4886e-2db7-4900-8d38-fbfecfeab993"
`);
});
});
1 change: 1 addition & 0 deletions packages/wrangler/src/config/environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ interface EnvironmentInheritable {
* test and deploy your Worker.
*
* // Carmen according to our tests the default is undefined
* // warning: you must force "workers_dev: true" in tests to match expected behavior
* @default `true` (This is a breaking change from Wrangler v1)
* @breaking
* @inheritable
Expand Down
56 changes: 31 additions & 25 deletions packages/wrangler/src/versions/upload.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
import path from "node:path";
import { URLSearchParams } from "node:url";
import { blue, gray } from "@cloudflare/cli/colors";
import { fetchResult } from "../cfetch";
import { printBindings } from "../config";
Expand Down Expand Up @@ -31,6 +30,7 @@ import { isNavigatorDefined } from "../navigator-user-agent";
import { ParseError } from "../parse";
import { getWranglerTmpDir } from "../paths";
import { ensureQueuesExistByConfig } from "../queues/client";
import { getWorkersDevSubdomain } from "../routes";
import {
getSourceMappedString,
maybeRetrieveFileSourceMap,
Expand Down Expand Up @@ -233,7 +233,7 @@ See https://developers.cloudflare.com/workers/platform/compatibility-dates for m

const start = Date.now();
const workerName = scriptName;
const workerUrl = `/accounts/${accountId}/workers/scripts/${scriptName}/versions`;
const workerUrl = `/accounts/${accountId}/workers/scripts/${scriptName}`;

const { format } = props.entry;

Expand All @@ -254,6 +254,9 @@ See https://developers.cloudflare.com/workers/platform/compatibility-dates for m
"You cannot configure [data_blobs] with an ES module worker. Instead, import the file directly in your code, and optionally configure `[rules]` in your wrangler.toml"
);
}

let hasPreview = false;

try {
if (props.noBundle) {
// if we're not building, let's just copy the entry to the destination directory
Expand Down Expand Up @@ -458,39 +461,27 @@ See https://developers.cloudflare.com/workers/platform/compatibility-dates for m
await ensureQueuesExistByConfig(config);
let bindingsPrinted = false;

// Upload the script so it has time to propagate.
// We can also now tell whether available_on_subdomain is set
// Upload the version.
try {
const body = createWorkerUploadForm(worker);

const result = await fetchResult<{
available_on_subdomain: boolean;
id: string | null;
etag: string | null;
pipeline_hash: string | null;
mutable_pipeline_id: string | null;
deployment_id: string | null;
id: string;
startup_time_ms: number;
}>(
workerUrl,
{
method: "POST",
body,
headers: await getMetricsUsageHeaders(config.send_metrics),
},
new URLSearchParams({
include_subdomain_availability: "true",
// pass excludeScript so the whole body of the
// script doesn't get included in the response
excludeScript: "true",
})
);
metadata: {
has_preview: boolean;
};
}>(`${workerUrl}/versions`, {
method: "POST",
body,
headers: await getMetricsUsageHeaders(config.send_metrics),
});

logger.log("Worker Startup Time:", result.startup_time_ms, "ms");
bindingsPrinted = true;
printBindings({ ...withoutStaticAssets, vars: maskedVars });
logger.log("Worker Version ID:", result.id);
versionId = result.id;
hasPreview = result.metadata.has_preview;
} catch (err) {
if (!bindingsPrinted) {
printBindings({ ...withoutStaticAssets, vars: maskedVars });
Expand Down Expand Up @@ -553,6 +544,21 @@ See https://developers.cloudflare.com/workers/platform/compatibility-dates for m
const uploadMs = Date.now() - start;

logger.log("Uploaded", workerName, formatTime(uploadMs));
logger.log("Worker Version ID:", versionId);

if (versionId && hasPreview) {
const { enabled: available_on_subdomain } = await fetchResult<{
enabled: boolean;
}>(`${workerUrl}/subdomain`);

if (available_on_subdomain) {
const userSubdomain = await getWorkersDevSubdomain(accountId);
const shortVersion = versionId.slice(0, 8);
logger.log(
`Version Preview URL: https://${shortVersion}-${workerName}.${userSubdomain}.workers.dev`
);
}
}

const cmdVersionsDeploy = blue("wrangler versions deploy");
const cmdTriggersDeploy = blue("wrangler triggers deploy");
Expand Down