Skip to content

Commit 2aa3d31

Browse files
chore: convert rollback to createCommand (#7498)
* chore: convert rollback to createCommand add positional chore: fix description * Update packages/wrangler/src/versions/rollback/index.ts * Update packages/wrangler/src/versions/rollback/index.ts * chore: update snapshot --------- Co-authored-by: Carmen Popoviciu <[email protected]>
1 parent 32e0616 commit 2aa3d31

File tree

3 files changed

+103
-115
lines changed

3 files changed

+103
-115
lines changed

packages/wrangler/src/__tests__/deployments.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,7 @@ describe("deployments", () => {
383383

384384
it("should require a worker name", async () => {
385385
await expect(runWrangler("rollback")).rejects.toMatchInlineSnapshot(
386-
`[Error: You need to provide a name of your worker. Either pass it as a cli arg with \`--name <name>\` or in your config file as \`name = "<name>"\`]`
386+
`[Error: You need to provide a name for your Worker. Either pass it as a cli arg with \`--name <name>\` or in your configuration file as \`name = "<name>"\`]`
387387
);
388388

389389
expect(requests.count).toEqual(0);

packages/wrangler/src/index.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ import { deploymentsListCommand } from "./versions/deployments/list";
168168
import { deploymentsStatusCommand } from "./versions/deployments/status";
169169
import { deploymentsViewCommand } from "./versions/deployments/view";
170170
import { versionsListCommand } from "./versions/list";
171-
import registerVersionsRollbackCommand from "./versions/rollback";
171+
import { versionsRollbackCommand } from "./versions/rollback";
172172
import { versionsSecretNamespace } from "./versions/secrets";
173173
import { versionsSecretBulkCommand } from "./versions/secrets/bulk";
174174
import { versionsSecretDeleteCommand } from "./versions/secrets/delete";
@@ -546,7 +546,10 @@ export function createCLIParser(argv: string[]) {
546546
const rollbackDescription = "🔙 Rollback a deployment for a Worker";
547547

548548
if (experimentalGradualRollouts) {
549-
registerVersionsRollbackCommand(wrangler, rollbackDescription);
549+
registry.define([
550+
{ command: "wrangler rollback", definition: versionsRollbackCommand },
551+
]);
552+
registry.registerNamespace("rollback");
550553
} else {
551554
wrangler.command(
552555
"rollback [deployment-id]",

packages/wrangler/src/versions/rollback/index.ts

Lines changed: 97 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -1,153 +1,138 @@
11
import * as cli from "@cloudflare/cli";
22
import { spinnerWhile } from "@cloudflare/cli/interactive";
3-
import { readConfig } from "../../config";
3+
import { createCommand } from "../../core/create-command";
44
import { confirm, prompt } from "../../dialogs";
55
import { UserError } from "../../errors";
66
import { logger } from "../../logger";
77
import { APIError } from "../../parse";
88
import { requireAuth } from "../../user";
99
import { createDeployment, fetchLatestDeployments, fetchVersion } from "../api";
1010
import { printLatestDeployment, printVersions } from "../deploy";
11-
import type {
12-
CommonYargsArgv,
13-
StrictYargsOptionsToInterface,
14-
} from "../../yargs-types";
1511
import type { VersionId } from "../types";
1612

1713
export const CANNOT_ROLLBACK_WITH_MODIFIED_SECERT_CODE = 10220;
1814

19-
type VersionsRollbackArgs = StrictYargsOptionsToInterface<
20-
typeof versionsRollbackOptions
21-
>;
22-
23-
export default function registerVersionsRollbackCommand(
24-
yargs: CommonYargsArgv,
25-
description = "🔙 Rollback to a Worker Version"
26-
) {
27-
return yargs.command(
28-
"rollback [version-id]",
29-
description,
30-
versionsRollbackOptions,
31-
versionsRollbackHandler
32-
);
33-
}
34-
35-
function versionsRollbackOptions(rollbackYargs: CommonYargsArgv) {
36-
return rollbackYargs
37-
.positional("version-id", {
15+
export const versionsRollbackCommand = createCommand({
16+
args: {
17+
"version-id": {
3818
describe: "The ID of the Worker Version to rollback to",
3919
type: "string",
4020
demandOption: false,
41-
})
42-
.option("name", {
43-
describe: "The name of your worker",
21+
},
22+
name: {
23+
describe: "The name of your Worker",
4424
type: "string",
45-
})
46-
.option("message", {
25+
},
26+
message: {
4727
alias: "m",
4828
describe: "The reason for this rollback",
4929
type: "string",
5030
default: undefined,
51-
})
52-
.option("yes", {
31+
},
32+
yes: {
5333
alias: "y",
5434
describe: "Automatically accept defaults to prompts",
5535
type: "boolean",
5636
default: false,
57-
});
58-
}
37+
},
38+
},
39+
positionalArgs: ["version-id"],
40+
metadata: {
41+
description: "🔙 Rollback a deployment for a Worker",
42+
owner: "Workers: Authoring and Testing",
43+
status: "stable",
44+
},
45+
handler: async function handleRollback(args, { config }) {
46+
const accountId = await requireAuth(config);
47+
const workerName = args.name ?? config.name;
48+
49+
if (workerName === undefined) {
50+
throw new UserError(
51+
'You need to provide a name for your Worker. Either pass it as a cli arg with `--name <name>` or in your configuration file as `name = "<name>"`'
52+
);
53+
}
5954

60-
async function versionsRollbackHandler(args: VersionsRollbackArgs) {
61-
const config = readConfig(args);
62-
const accountId = await requireAuth(config);
63-
const workerName = args.name ?? config.name;
55+
await printLatestDeployment(accountId, workerName, new Map());
6456

65-
if (workerName === undefined) {
66-
throw new UserError(
67-
'You need to provide a name of your worker. Either pass it as a cli arg with `--name <name>` or in your config file as `name = "<name>"`'
68-
);
69-
}
57+
const versionId =
58+
args.versionId ??
59+
(await spinnerWhile({
60+
promise: fetchDefaultRollbackVersionId(accountId, workerName),
61+
startMessage: "Finding latest stable Worker Version to rollback to",
62+
endMessage: "",
63+
}));
7064

71-
await printLatestDeployment(accountId, workerName, new Map());
65+
const message = await prompt(
66+
"Please provide an optional message for this rollback (120 characters max)",
67+
{
68+
defaultValue: args.message ?? "Rollback",
69+
}
70+
);
7271

73-
const versionId =
74-
args.versionId ??
75-
(await spinnerWhile({
76-
promise: fetchDefaultRollbackVersionId(accountId, workerName),
77-
startMessage: "Finding latest stable Worker Version to rollback to",
78-
endMessage: "",
79-
}));
72+
const version = await fetchVersion(accountId, workerName, versionId);
73+
cli.warn(
74+
`You are about to rollback to Worker Version ${versionId}.\nThis will immediately replace the current deployment and become the active deployment across all your deployed triggers.\nHowever, your local development environment will not be affected by this rollback.\nRolling back to a previous deployment will not rollback any of the bound resources (Durable Object, D1, R2, KV, etc).`,
75+
{ multiline: true, shape: cli.shapes.leftT }
76+
);
77+
const rollbackTraffic = new Map([[versionId, 100]]);
78+
printVersions([version], rollbackTraffic);
8079

81-
const message = await prompt(
82-
"Please provide an optional message for this rollback (120 characters max)",
83-
{
84-
defaultValue: args.message ?? "Rollback",
80+
const confirmed = await confirm(
81+
"Are you sure you want to deploy this Worker Version to 100% of traffic?",
82+
{ defaultValue: true }
83+
);
84+
if (!confirmed) {
85+
cli.cancel("Aborting rollback...");
86+
return;
8587
}
86-
);
8788

88-
const version = await fetchVersion(accountId, workerName, versionId);
89-
cli.warn(
90-
`You are about to rollback to Worker Version ${versionId}.\nThis will immediately replace the current deployment and become the active deployment across all your deployed triggers.\nHowever, your local development environment will not be affected by this rollback.\nRolling back to a previous deployment will not rollback any of the bound resources (Durable Object, D1, R2, KV, etc).`,
91-
{ multiline: true, shape: cli.shapes.leftT }
92-
);
93-
const rollbackTraffic = new Map([[versionId, 100]]);
94-
printVersions([version], rollbackTraffic);
95-
96-
const confirmed = await confirm(
97-
"Are you sure you want to deploy this Worker Version to 100% of traffic?",
98-
{ defaultValue: true }
99-
);
100-
if (!confirmed) {
101-
cli.cancel("Aborting rollback...");
102-
return;
103-
}
104-
105-
logger.log("Performing rollback...");
106-
try {
107-
await createDeployment(accountId, workerName, rollbackTraffic, message);
108-
} catch (e) {
109-
if (
110-
e instanceof APIError &&
111-
e.code === CANNOT_ROLLBACK_WITH_MODIFIED_SECERT_CODE
112-
) {
113-
// This is not great but is the best way I could think to handle for now
114-
const errorMsg = e.notes[0].text.replace(
115-
` [code: ${CANNOT_ROLLBACK_WITH_MODIFIED_SECERT_CODE}]`,
116-
""
117-
);
118-
const targetString = "The following secrets have changed:";
119-
const changedSecrets = errorMsg
120-
.substring(errorMsg.indexOf(targetString) + targetString.length + 1)
121-
.split(", ");
122-
123-
const secretConfirmation = await confirm(
124-
`The following secrets have changed since version ${versionId} was deployed. ` +
125-
`Please confirm you wish to continue with the rollback\n` +
126-
changedSecrets.map((secret) => ` * ${secret}`).join("\n")
127-
);
128-
129-
if (secretConfirmation) {
130-
await createDeployment(
131-
accountId,
132-
workerName,
133-
rollbackTraffic,
134-
message,
135-
true
89+
logger.log("Performing rollback...");
90+
try {
91+
await createDeployment(accountId, workerName, rollbackTraffic, message);
92+
} catch (e) {
93+
if (
94+
e instanceof APIError &&
95+
e.code === CANNOT_ROLLBACK_WITH_MODIFIED_SECERT_CODE
96+
) {
97+
// This is not great but is the best way I could think to handle for now
98+
const errorMsg = e.notes[0].text.replace(
99+
` [code: ${CANNOT_ROLLBACK_WITH_MODIFIED_SECERT_CODE}]`,
100+
""
136101
);
102+
const targetString = "The following secrets have changed:";
103+
const changedSecrets = errorMsg
104+
.substring(errorMsg.indexOf(targetString) + targetString.length + 1)
105+
.split(", ");
106+
107+
const secretConfirmation = await confirm(
108+
`The following secrets have changed since version ${versionId} was deployed. ` +
109+
`Please confirm you wish to continue with the rollback\n` +
110+
changedSecrets.map((secret) => ` * ${secret}`).join("\n")
111+
);
112+
113+
if (secretConfirmation) {
114+
await createDeployment(
115+
accountId,
116+
workerName,
117+
rollbackTraffic,
118+
message,
119+
true
120+
);
121+
} else {
122+
cli.cancel("Aborting rollback...");
123+
}
137124
} else {
138-
cli.cancel("Aborting rollback...");
125+
throw e;
139126
}
140-
} else {
141-
throw e;
142127
}
143-
}
144128

145-
cli.success(
146-
`Worker Version ${versionId} has been deployed to 100% of traffic.`
147-
);
129+
cli.success(
130+
`Worker Version ${versionId} has been deployed to 100% of traffic.`
131+
);
148132

149-
logger.log("\nCurrent Version ID: " + versionId);
150-
}
133+
logger.log("\nCurrent Version ID: " + versionId);
134+
},
135+
});
151136

152137
async function fetchDefaultRollbackVersionId(
153138
accountId: string,

0 commit comments

Comments
 (0)