Skip to content

Commit

Permalink
feat: implement a basic wrangler delete
Browse files Browse the repository at this point in the history
This PR adds a simple (but useful!) implementation for `wrangler delete`. Of note, it'll delete a given service, including all it's bindings. It uses the same api as the dashboard.
  • Loading branch information
threepointone committed Oct 18, 2022
1 parent ccfdd0b commit cd0c62c
Show file tree
Hide file tree
Showing 5 changed files with 172 additions and 0 deletions.
7 changes: 7 additions & 0 deletions .changeset/rare-eels-pay.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"wrangler": patch
---

feat: implement a basic `wrangler delete`

This PR adds a simple (but useful!) implementation for `wrangler delete`. Of note, it'll delete a given service, including all it's bindings. It uses the same api as the dashboard.
76 changes: 76 additions & 0 deletions packages/wrangler/src/__tests__/delete.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { mockAccountId, mockApiToken } from "./helpers/mock-account-id";
import { setMockResponse, unsetAllMocks } from "./helpers/mock-cfetch";
import { mockConsoleMethods } from "./helpers/mock-console";
import { runInTempDir } from "./helpers/run-in-tmp";
import { runWrangler } from "./helpers/run-wrangler";
import writeWranglerToml from "./helpers/write-wrangler-toml";

describe("delete", () => {
mockAccountId();
mockApiToken();
runInTempDir();

afterEach(() => {
unsetAllMocks();
});

const std = mockConsoleMethods();

it("should delete an entire service by name", async () => {
mockDeleteWorkerRequest({ name: "my-script" });
await runWrangler("delete --name my-script");

expect(std).toMatchInlineSnapshot(`
Object {
"debug": "",
"err": "",
"out": "Successfully deleted my-script",
"warn": "",
}
`);
});

it("should delete a script by configuration", async () => {
writeWranglerToml();
mockDeleteWorkerRequest();
await runWrangler("delete");

expect(std).toMatchInlineSnapshot(`
Object {
"debug": "",
"err": "",
"out": "Successfully deleted test-name",
"warn": "",
}
`);
});
});

/** Create a mock handler for the request to upload a worker script. */
function mockDeleteWorkerRequest(
options: {
name?: string;
env?: string;
legacyEnv?: boolean;
} = {}
) {
const { env, legacyEnv, name } = options;
setMockResponse(
// there's no special handling for environments yet
"/accounts/:accountId/workers/services/:scriptName",
"DELETE",
async ([_url, accountId, scriptName], { method }, queryParams) => {
expect(accountId).toEqual("some-account-id");
expect(method).toEqual("DELETE");
expect(scriptName).toEqual(
legacyEnv && env
? `${name || "test-name"}-${env}`
: `${name || "test-name"}`
);

expect(queryParams.get("force")).toEqual("true");

return null;
}
);
}
79 changes: 79 additions & 0 deletions packages/wrangler/src/delete.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import path from "path";
import { fetchResult } from "./cfetch";
import { findWranglerToml, readConfig } from "./config";
import { logger } from "./logger";
import * as metrics from "./metrics";
import { requireAuth } from "./user";
import { getScriptName, printWranglerBanner } from "./index";
import type { ConfigPath } from "./index";
import type { YargsOptionsToInterface } from "./yargs-types";
import type { Argv, ArgumentsCamelCase } from "yargs";

export function deleteOptions(yargs: Argv) {
return yargs
.option("env", {
type: "string",
requiresArg: true,
describe: "Perform on a specific environment",
alias: "e",
})
.positional("script", {
describe: "The path to an entry point for your worker",
type: "string",
requiresArg: true,
})
.option("name", {
describe: "Name of the worker",
type: "string",
requiresArg: true,
})
.option("assets", {
describe: "Static assets to be served",
type: "string",
requiresArg: true,
})
.option("site", {
describe: "Root folder of static assets for Workers Sites",
type: "string",
requiresArg: true,
})
.option("dry-run", {
describe: "Don't actually publish",
type: "boolean",
})
.option("legacy-env", {
type: "boolean",
describe: "Use legacy environments",
hidden: true,
});
}

type DeleteArgs = YargsOptionsToInterface<typeof deleteOptions>;

export async function deleteHandler(args: ArgumentsCamelCase<DeleteArgs>) {
await printWranglerBanner();

const configPath =
(args.config as ConfigPath) ||
(args.script && findWranglerToml(path.dirname(args.script)));
const config = readConfig(configPath, args);
await metrics.sendMetricsEvent(
"delete worker script",
{},
{ sendMetrics: config.send_metrics }
);

const accountId = args.dryRun ? undefined : await requireAuth(config);

const scriptName = getScriptName(args, config);

await fetchResult(
`/accounts/${accountId}/workers/services/${scriptName}`,
{ method: "DELETE" },
new URLSearchParams({ force: "true" })
);

logger.log("Successfully deleted", scriptName);

// TODO: maybe delete sites/assets kv namespace as well?
}
9 changes: 9 additions & 0 deletions packages/wrangler/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import { whoami } from "./whoami";

import type { Config } from "./config";
import type Yargs from "yargs";
import { deleteHandler, deleteOptions } from "./delete";

export type ConfigPath = string | undefined;

Expand Down Expand Up @@ -258,6 +259,14 @@ export function createCLIParser(argv: string[]) {
publishHandler
);

// delete
wrangler.command(
"delete [script]",
"🗑 Delete your Worker from Cloudflare.",
deleteOptions,
deleteHandler
);

// tail
wrangler.command(
"tail [worker]",
Expand Down
1 change: 1 addition & 0 deletions packages/wrangler/src/metrics/send-event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type { Properties } from "./metrics-dispatcher";
export type EventNames =
| "view accounts"
| "deploy worker script"
| "delete worker script"
| "begin log stream"
| "end log stream"
| "create encrypted variable"
Expand Down

0 comments on commit cd0c62c

Please sign in to comment.