Skip to content

Commit

Permalink
Let users cancel deploy and destroy actions (#1375)
Browse files Browse the repository at this point in the history
## Changes
Let users cancel deploy and destroy actions

## Tests
Manual ad existing tests
  • Loading branch information
ilia-db authored Sep 25, 2024
1 parent ddc5d2a commit 33602dd
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {WorkspaceConfigs} from "../../vscode-objs/WorkspaceConfigs";
import {logging} from "@databricks/databricks-sdk";
import {Loggers} from "../../logger";
import {WorkspaceFolderManager} from "../../vscode-objs/WorkspaceFolderManager";
import {CancellationToken} from "vscode";

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

@Mutex.synchronise("mutex")
public async deploy(force = false) {
public async deploy(force = false, token?: CancellationToken) {
if (this.target === undefined) {
throw new Error("Target is undefined");
}
Expand All @@ -77,12 +78,13 @@ export class BundleRemoteStateModel extends BaseModelWithStateCache<BundleRemote
this.workspaceFolder,
this.workspaceConfigs.databrickscfgLocation,
this.logger,
force
force,
token
);
}

@Mutex.synchronise("mutex")
public async destroy(force = false) {
public async destroy(force = false, token: CancellationToken) {
if (this.target === undefined) {
throw new Error("Target is undefined");
}
Expand All @@ -96,7 +98,8 @@ export class BundleRemoteStateModel extends BaseModelWithStateCache<BundleRemote
this.workspaceFolder,
this.workspaceConfigs.databrickscfgLocation,
this.logger,
force
force,
token
);
}

Expand Down
44 changes: 33 additions & 11 deletions packages/databricks-vscode/src/cli/CliWrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,12 @@ export class ProcessError extends Error {
}
}

export class CancellationError extends Error {
constructor() {
super("Cancelled");
}
}

export async function waitForProcess(
p: ChildProcessWithoutNullStreams,
onStdOut?: (data: string) => void,
Expand Down Expand Up @@ -195,7 +201,8 @@ async function runBundleCommand(
outputHandlers: {
onStdOut?: (data: string) => void;
onStdError?: (data: string) => void;
} = {}
} = {},
cancellationToken?: CancellationToken
) {
const defaultOutputHandlers = {
onStdOut: (data: string) => {
Expand All @@ -219,27 +226,36 @@ async function runBundleCommand(
});

logger?.debug(quote([cmd, ...args]), {bundleOpName});
const abortController = new AbortController();
cancellationToken?.onCancellationRequested(() => abortController.abort());
let options: SpawnOptionsWithoutStdio = {
cwd: workspaceFolder.fsPath,
env: removeUndefinedKeys(env),
signal: abortController.signal,
};

({cmd, args, options} = getEscapedCommandAndAgrs(cmd, args, options));
try {
const p = spawn(cmd, args, options);

const {stdout, stderr} = await waitForProcess(p, onStdOut, onStdError);
logger?.info(displayLogs.end, {
bundleOpName,
});
logger?.debug("output", {stdout, stderr, bundleOpName});
return {stdout, stderr};
} catch (e: any) {
logger?.error(`${displayLogs.error} ${e.message ?? ""}`, {
...e,
bundleOpName,
});
throw new ProcessError(e.message, e.code);
if (cancellationToken?.isCancellationRequested) {
logger?.warn(`${displayLogs.error} Reason: Cancelled`, {
bundleOpName,
});
throw new CancellationError();
} else {
logger?.error(`${displayLogs.error} ${e.message ?? ""}`, {
...e,
bundleOpName,
});
throw new ProcessError(e.message, e.code);
}
}
}
/**
Expand Down Expand Up @@ -574,7 +590,8 @@ export class CliWrapper {
workspaceFolder: Uri,
configfilePath?: string,
logger?: logging.NamedLogger,
force = false
force = false,
token?: CancellationToken
) {
await commands.executeCommand("databricks.bundle.showLogs");
return await runBundleCommand(
Expand All @@ -598,7 +615,9 @@ export class CliWrapper {
error: "Failed to deploy the bundle.",
},
await this.getBundleCommandEnvVars(authProvider, configfilePath),
logger
logger,
{},
token
);
}

Expand All @@ -608,7 +627,8 @@ export class CliWrapper {
workspaceFolder: Uri,
configfilePath?: string,
logger?: logging.NamedLogger,
force = false
force = false,
token?: CancellationToken
) {
await commands.executeCommand("databricks.bundle.showLogs");
return await runBundleCommand(
Expand All @@ -629,7 +649,9 @@ export class CliWrapper {
error: "Failed to destroy the bundle.",
},
await this.getBundleCommandEnvVars(authProvider, configfilePath),
logger
logger,
{},
token
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,11 @@ export class BundleCommands implements Disposable {
this.whenContext.setDeploymentState("deploying");
const mode = await this.configModel.get("mode");
const target = this.configModel.target;
const prettyMode = humaniseMode(mode);
const title = `Deploying the bundle to ${prettyMode} target "${target}".`;
if (mode !== "development") {
const choice = await window.showInformationMessage(
`Deploying bundle to ${humaniseMode(
mode
)} target "${target}".`,
title,
{modal: true},
"Continue"
);
Expand All @@ -107,9 +107,13 @@ export class BundleCommands implements Disposable {
}
}
await window.withProgress(
{location: ProgressLocation.Notification, cancellable: false},
async () => {
await this.bundleRemoteStateModel.deploy(force);
{
location: ProgressLocation.Notification,
title: title,
cancellable: true,
},
async (progress, token) => {
await this.bundleRemoteStateModel.deploy(force, token);
}
);

Expand Down Expand Up @@ -187,9 +191,13 @@ export class BundleCommands implements Disposable {
try {
this.whenContext.setDeploymentState("deploying");
await window.withProgress(
{location: ProgressLocation.Notification, cancellable: false},
async () => {
await this.bundleRemoteStateModel.destroy(force);
{
location: ProgressLocation.Notification,
title: "Destroying the bundle",
cancellable: true,
},
async (progress, token) => {
await this.bundleRemoteStateModel.destroy(force, token);
}
);

Expand Down

0 comments on commit 33602dd

Please sign in to comment.