Skip to content

Commit

Permalink
[Pages] feat: add wrangler pages project delete command (#3293)
Browse files Browse the repository at this point in the history
  • Loading branch information
petebacondarwin authored May 23, 2023
1 parent 2b709ce commit 4a88db3
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 1 deletion.
5 changes: 5 additions & 0 deletions .changeset/lazy-boxes-deny.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"wrangler": minor
---

feat: add `wrangler pages project delete` command
103 changes: 103 additions & 0 deletions packages/wrangler/src/__tests__/pages/project-delete.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import { rest } from "msw";
import { endEventLoop } from "../helpers/end-event-loop";
import { mockAccountId, mockApiToken } from "../helpers/mock-account-id";
import { mockConsoleMethods } from "../helpers/mock-console";
import { mockConfirm, clearDialogs } from "../helpers/mock-dialogs";
import { useMockIsTTY } from "../helpers/mock-istty";
import { msw } from "../helpers/msw";
import { runInTempDir } from "../helpers/run-in-tmp";
import { runWrangler } from "../helpers/run-wrangler";

describe("project delete", () => {
const std = mockConsoleMethods();

runInTempDir();
mockAccountId();
mockApiToken();
const { setIsTTY } = useMockIsTTY();

beforeEach(() => {
setIsTTY(true);
});

afterEach(async () => {
// Force a tick to ensure that all promises resolve
await endEventLoop();
// Reset MSW after tick to ensure that all requests have been handled
msw.resetHandlers();
msw.restoreHandlers();
clearDialogs();
});

it("should delete a project with the given name", async () => {
msw.use(
rest.delete(
"*/accounts/:accountId/pages/projects/:projectName",
async (req, res, ctx) => {
expect(req.params.accountId).toEqual("some-account-id");
expect(req.params.projectName).toEqual("some-project-name");
return res.once(
ctx.status(200),
ctx.json({
result: null,
success: true,
errors: [],
messages: [],
})
);
}
)
);

mockConfirm({
text: `Are you sure you want to delete "some-project-name"? This action cannot be undone.`,
result: true,
});

await runWrangler("pages project delete some-project-name");

expect(std.out).toMatchInlineSnapshot(`
"Deleting some-project-name
Successfully deleted some-project-name"
`);
});

it("should not delete a project if confirmation refused", async () => {
mockConfirm({
text: `Are you sure you want to delete "some-project-name-2"? This action cannot be undone.`,
result: false,
});

await runWrangler("pages project delete some-project-name-2");

expect(std.out).toMatchInlineSnapshot(`""`);
});

it("should delete a project without asking if --yes provided", async () => {
msw.use(
rest.delete(
"*/accounts/:accountId/pages/projects/:projectName",
async (req, res, ctx) => {
expect(req.params.accountId).toEqual("some-account-id");
expect(req.params.projectName).toEqual("some-project-name");
return res.once(
ctx.status(200),
ctx.json({
result: null,
success: true,
errors: [],
messages: [],
})
);
}
)
);

await runWrangler("pages project delete some-project-name -y");

expect(std.out).toMatchInlineSnapshot(`
"Deleting some-project-name
Successfully deleted some-project-name"
`);
});
});
6 changes: 6 additions & 0 deletions packages/wrangler/src/pages/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@ export function pages(yargs: CommonYargsArgv) {
Projects.CreateOptions,
Projects.CreateHandler
)
.command(
"delete [project-name]",
"Delete a Cloudflare Pages project",
Projects.DeleteOptions,
Projects.DeleteHandler
)
.command("upload [directory]", false, Upload.Options, Upload.Handler)
.epilogue(pagesBetaWarning)
)
Expand Down
42 changes: 41 additions & 1 deletion packages/wrangler/src/pages/projects.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import React from "react";
import { format as timeagoFormat } from "timeago.js";
import { fetchResult } from "../cfetch";
import { getConfigCache, saveToConfigCache } from "../config-cache";
import { prompt } from "../dialogs";
import { confirm, prompt } from "../dialogs";
import { FatalError } from "../errors";
import { logger } from "../logger";
import * as metrics from "../metrics";
Expand Down Expand Up @@ -157,3 +157,43 @@ export async function CreateHandler({
);
await metrics.sendMetricsEvent("create pages project");
}

export function DeleteOptions(yargs: CommonYargsArgv) {
return yargs
.positional("project-name", {
type: "string",
demandOption: true,
description: "The name of your Pages project",
})
.options({
yes: {
alias: "y",
type: "boolean",
description: 'Answer "yes" to confirm project deletion',
},
})
.epilogue(pagesBetaWarning);
}

export async function DeleteHandler(
args: StrictYargsOptionsToInterface<typeof DeleteOptions>
) {
const config = getConfigCache<PagesConfigCache>(PAGES_CONFIG_CACHE_FILENAME);
const accountId = await requireAuth(config);

const confirmed =
args.yes ||
(await confirm(
`Are you sure you want to delete "${args.projectName}"? This action cannot be undone.`
));

if (confirmed) {
logger.log("Deleting", args.projectName);
await fetchResult(
`/accounts/${accountId}/pages/projects/${args.projectName}`,
{ method: "DELETE" }
);

logger.log("Successfully deleted", args.projectName);
}
}

0 comments on commit 4a88db3

Please sign in to comment.