Skip to content

Commit 33602dd

Browse files
authored
Let users cancel deploy and destroy actions (#1375)
## Changes Let users cancel deploy and destroy actions ## Tests Manual ad existing tests
1 parent ddc5d2a commit 33602dd

File tree

3 files changed

+57
-24
lines changed

3 files changed

+57
-24
lines changed

packages/databricks-vscode/src/bundle/models/BundleRemoteStateModel.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {WorkspaceConfigs} from "../../vscode-objs/WorkspaceConfigs";
99
import {logging} from "@databricks/databricks-sdk";
1010
import {Loggers} from "../../logger";
1111
import {WorkspaceFolderManager} from "../../vscode-objs/WorkspaceFolderManager";
12+
import {CancellationToken} from "vscode";
1213

1314
/* eslint-disable @typescript-eslint/naming-convention */
1415
export type BundleResourceModifiedStatus = "created" | "deleted" | "updated";
@@ -63,7 +64,7 @@ export class BundleRemoteStateModel extends BaseModelWithStateCache<BundleRemote
6364
}
6465

6566
@Mutex.synchronise("mutex")
66-
public async deploy(force = false) {
67+
public async deploy(force = false, token?: CancellationToken) {
6768
if (this.target === undefined) {
6869
throw new Error("Target is undefined");
6970
}
@@ -77,12 +78,13 @@ export class BundleRemoteStateModel extends BaseModelWithStateCache<BundleRemote
7778
this.workspaceFolder,
7879
this.workspaceConfigs.databrickscfgLocation,
7980
this.logger,
80-
force
81+
force,
82+
token
8183
);
8284
}
8385

8486
@Mutex.synchronise("mutex")
85-
public async destroy(force = false) {
87+
public async destroy(force = false, token: CancellationToken) {
8688
if (this.target === undefined) {
8789
throw new Error("Target is undefined");
8890
}
@@ -96,7 +98,8 @@ export class BundleRemoteStateModel extends BaseModelWithStateCache<BundleRemote
9698
this.workspaceFolder,
9799
this.workspaceConfigs.databrickscfgLocation,
98100
this.logger,
99-
force
101+
force,
102+
token
100103
);
101104
}
102105

packages/databricks-vscode/src/cli/CliWrapper.ts

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,12 @@ export class ProcessError extends Error {
145145
}
146146
}
147147

148+
export class CancellationError extends Error {
149+
constructor() {
150+
super("Cancelled");
151+
}
152+
}
153+
148154
export async function waitForProcess(
149155
p: ChildProcessWithoutNullStreams,
150156
onStdOut?: (data: string) => void,
@@ -195,7 +201,8 @@ async function runBundleCommand(
195201
outputHandlers: {
196202
onStdOut?: (data: string) => void;
197203
onStdError?: (data: string) => void;
198-
} = {}
204+
} = {},
205+
cancellationToken?: CancellationToken
199206
) {
200207
const defaultOutputHandlers = {
201208
onStdOut: (data: string) => {
@@ -219,27 +226,36 @@ async function runBundleCommand(
219226
});
220227

221228
logger?.debug(quote([cmd, ...args]), {bundleOpName});
229+
const abortController = new AbortController();
230+
cancellationToken?.onCancellationRequested(() => abortController.abort());
222231
let options: SpawnOptionsWithoutStdio = {
223232
cwd: workspaceFolder.fsPath,
224233
env: removeUndefinedKeys(env),
234+
signal: abortController.signal,
225235
};
226236

227237
({cmd, args, options} = getEscapedCommandAndAgrs(cmd, args, options));
228238
try {
229239
const p = spawn(cmd, args, options);
230-
231240
const {stdout, stderr} = await waitForProcess(p, onStdOut, onStdError);
232241
logger?.info(displayLogs.end, {
233242
bundleOpName,
234243
});
235244
logger?.debug("output", {stdout, stderr, bundleOpName});
236245
return {stdout, stderr};
237246
} catch (e: any) {
238-
logger?.error(`${displayLogs.error} ${e.message ?? ""}`, {
239-
...e,
240-
bundleOpName,
241-
});
242-
throw new ProcessError(e.message, e.code);
247+
if (cancellationToken?.isCancellationRequested) {
248+
logger?.warn(`${displayLogs.error} Reason: Cancelled`, {
249+
bundleOpName,
250+
});
251+
throw new CancellationError();
252+
} else {
253+
logger?.error(`${displayLogs.error} ${e.message ?? ""}`, {
254+
...e,
255+
bundleOpName,
256+
});
257+
throw new ProcessError(e.message, e.code);
258+
}
243259
}
244260
}
245261
/**
@@ -574,7 +590,8 @@ export class CliWrapper {
574590
workspaceFolder: Uri,
575591
configfilePath?: string,
576592
logger?: logging.NamedLogger,
577-
force = false
593+
force = false,
594+
token?: CancellationToken
578595
) {
579596
await commands.executeCommand("databricks.bundle.showLogs");
580597
return await runBundleCommand(
@@ -598,7 +615,9 @@ export class CliWrapper {
598615
error: "Failed to deploy the bundle.",
599616
},
600617
await this.getBundleCommandEnvVars(authProvider, configfilePath),
601-
logger
618+
logger,
619+
{},
620+
token
602621
);
603622
}
604623

@@ -608,7 +627,8 @@ export class CliWrapper {
608627
workspaceFolder: Uri,
609628
configfilePath?: string,
610629
logger?: logging.NamedLogger,
611-
force = false
630+
force = false,
631+
token?: CancellationToken
612632
) {
613633
await commands.executeCommand("databricks.bundle.showLogs");
614634
return await runBundleCommand(
@@ -629,7 +649,9 @@ export class CliWrapper {
629649
error: "Failed to destroy the bundle.",
630650
},
631651
await this.getBundleCommandEnvVars(authProvider, configfilePath),
632-
logger
652+
logger,
653+
{},
654+
token
633655
);
634656
}
635657

packages/databricks-vscode/src/ui/bundle-resource-explorer/BundleCommands.ts

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -91,11 +91,11 @@ export class BundleCommands implements Disposable {
9191
this.whenContext.setDeploymentState("deploying");
9292
const mode = await this.configModel.get("mode");
9393
const target = this.configModel.target;
94+
const prettyMode = humaniseMode(mode);
95+
const title = `Deploying the bundle to ${prettyMode} target "${target}".`;
9496
if (mode !== "development") {
9597
const choice = await window.showInformationMessage(
96-
`Deploying bundle to ${humaniseMode(
97-
mode
98-
)} target "${target}".`,
98+
title,
9999
{modal: true},
100100
"Continue"
101101
);
@@ -107,9 +107,13 @@ export class BundleCommands implements Disposable {
107107
}
108108
}
109109
await window.withProgress(
110-
{location: ProgressLocation.Notification, cancellable: false},
111-
async () => {
112-
await this.bundleRemoteStateModel.deploy(force);
110+
{
111+
location: ProgressLocation.Notification,
112+
title: title,
113+
cancellable: true,
114+
},
115+
async (progress, token) => {
116+
await this.bundleRemoteStateModel.deploy(force, token);
113117
}
114118
);
115119

@@ -187,9 +191,13 @@ export class BundleCommands implements Disposable {
187191
try {
188192
this.whenContext.setDeploymentState("deploying");
189193
await window.withProgress(
190-
{location: ProgressLocation.Notification, cancellable: false},
191-
async () => {
192-
await this.bundleRemoteStateModel.destroy(force);
194+
{
195+
location: ProgressLocation.Notification,
196+
title: "Destroying the bundle",
197+
cancellable: true,
198+
},
199+
async (progress, token) => {
200+
await this.bundleRemoteStateModel.destroy(force, token);
193201
}
194202
);
195203

0 commit comments

Comments
 (0)