Skip to content

Commit 97daab1

Browse files
authored
Improve environment setup UX (#1395)
## Changes - Let users proceed with dbconnect installation when there's mismatch in dbr an python versions - Show a warning message when there's mismatch in dbr and python versions - Focus configuration panel when users click on Databricks Connect status bar button - Show a notification when clicking on the above button when everything is setup already <img width="913" alt="Screenshot 2024-10-16 at 16 23 02" src="https://github.com/user-attachments/assets/87ca7cbf-5a82-4b45-932f-7fb0e9ee4179"> ## Tests Manually and existing tests
1 parent 9c864af commit 97daab1

File tree

6 files changed

+76
-57
lines changed

6 files changed

+76
-57
lines changed

packages/databricks-vscode/src/feature-manager/FeatureManager.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export interface FeatureStepState {
2020
available: boolean;
2121
title?: string;
2222
message?: string;
23+
warning?: string;
2324
action?: FeatureEnableAction;
2425
isDisabledByFf?: boolean;
2526
}

packages/databricks-vscode/src/feature-manager/MultiStepAccessVerfier.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,12 +76,13 @@ export abstract class MultiStepAccessVerifier implements Feature {
7676
});
7777
}
7878

79-
acceptStep(id: string, title?: string, message?: string) {
79+
acceptStep(id: string, title?: string, message?: string, warning?: string) {
8080
return this.updateStep({
8181
id: id,
8282
available: true,
8383
title,
8484
message,
85+
warning,
8586
});
8687
}
8788

packages/databricks-vscode/src/language/EnvironmentCommands.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {window} from "vscode";
1+
import {window, commands} from "vscode";
22
import {FeatureManager} from "../feature-manager/FeatureManager";
33
import {MsPythonExtensionWrapper} from "./MsPythonExtensionWrapper";
44
import {Cluster} from "../sdk-extensions";
@@ -12,6 +12,7 @@ export class EnvironmentCommands {
1212
) {}
1313

1414
async setup(stepId?: string) {
15+
commands.executeCommand("configurationView.focus");
1516
await window.withProgress(
1617
{location: {viewId: "configurationView"}},
1718
() => this._setup(stepId)
@@ -24,6 +25,9 @@ export class EnvironmentCommands {
2425
true
2526
);
2627
if (state.available) {
28+
window.showInformationMessage(
29+
"Python environment and Databricks Connect are already set up."
30+
);
2731
return true;
2832
}
2933
for (const [, step] of state.steps) {

packages/databricks-vscode/src/language/EnvironmentDependenciesVerifier.ts

Lines changed: 21 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -161,38 +161,6 @@ export class EnvironmentDependenciesVerifier extends MultiStepAccessVerifier {
161161

162162
async checkPythonEnvironment(): Promise<FeatureStepState> {
163163
const env = await this.pythonExtension.pythonEnvironment;
164-
const dbrVersionParts =
165-
this.connectionManager.cluster?.dbrVersion || [];
166-
// DBR 13 and 14 require python 3.10
167-
if (
168-
(dbrVersionParts[0] === 13 || dbrVersionParts[0] === 14) &&
169-
!this.matchEnvironmentVersion(env, 3, 10)
170-
) {
171-
return this.rejectStep(
172-
"checkPythonEnvironment",
173-
"Activate an environment with Python 3.10",
174-
`The python version should match DBR ${
175-
dbrVersionParts[0]
176-
} requirements. ${this.printEnvironment(env)}`,
177-
this.selectPythonInterpreter.bind(this)
178-
);
179-
}
180-
// DBR 15 requires python 3.11
181-
if (
182-
dbrVersionParts[0] === 15 &&
183-
!this.matchEnvironmentVersion(env, 3, 11)
184-
) {
185-
return this.rejectStep(
186-
"checkPythonEnvironment",
187-
"Activate an environment with Python 3.11",
188-
`The version should match DBR ${
189-
dbrVersionParts[0]
190-
} requirements. ${this.printEnvironment(env)}`,
191-
this.selectPythonInterpreter.bind(this)
192-
);
193-
}
194-
// If we don't know DBR version (no cluster is connected or new version is released and the extension isn't updated yet),
195-
// we still check that environment is active and has python >= 3.10
196164
const envVersionTooLow =
197165
env?.version && (env.version.major !== 3 || env.version.minor < 10);
198166
const noEnvironment = !env?.environment;
@@ -215,10 +183,30 @@ export class EnvironmentDependenciesVerifier extends MultiStepAccessVerifier {
215183
this.selectPythonInterpreter.bind(this)
216184
);
217185
}
186+
const dbrVersionParts =
187+
this.connectionManager.cluster?.dbrVersion || [];
188+
let warning;
189+
if (
190+
(dbrVersionParts[0] === 13 || dbrVersionParts[0] === 14) &&
191+
!this.matchEnvironmentVersion(env, 3, 10)
192+
) {
193+
warning = `Use python 3.10 to match DBR ${
194+
dbrVersionParts[0]
195+
} requirements. ${this.printEnvironment(env)}`;
196+
}
197+
if (
198+
dbrVersionParts[0] === 15 &&
199+
!this.matchEnvironmentVersion(env, 3, 11)
200+
) {
201+
warning = `Use python 3.11 to match DBR ${
202+
dbrVersionParts[0]
203+
} requirements. ${this.printEnvironment(env)}`;
204+
}
218205
return this.acceptStep(
219206
"checkPythonEnvironment",
220207
`Active Environment: ${env.environment.name}`,
221-
env.executable.uri?.fsPath
208+
env.executable.uri?.fsPath,
209+
warning
222210
);
223211
}
224212

packages/databricks-vscode/src/test/e2e/wdio.conf.ts

Lines changed: 39 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import path from "node:path";
88
import {fileURLToPath} from "url";
99
import assert from "assert";
1010
import fs from "fs/promises";
11-
import {ApiError, Config, WorkspaceClient} from "@databricks/databricks-sdk";
11+
import {Config, WorkspaceClient} from "@databricks/databricks-sdk";
1212
import * as ElementCustomCommands from "./customCommands/elementCustomCommands.ts";
1313
import {execFile as execFileCb} from "node:child_process";
1414
import {cpSync, mkdirSync, rmSync} from "node:fs";
@@ -588,26 +588,44 @@ function getWorkspaceClient(config: Config) {
588588

589589
async function startCluster(
590590
workspaceClient: WorkspaceClient,
591-
clusterId: string
591+
clusterId: string,
592+
attempt = 0
592593
) {
593-
console.log(`Starting cluster: ${clusterId}`);
594-
595-
try {
596-
await (
597-
await workspaceClient.clusters.start({
598-
cluster_id: clusterId,
599-
})
600-
).wait({
601-
onProgress: async (state) => {
602-
console.log(`Cluster state: ${state.state}`);
603-
},
604-
});
605-
} catch (e: unknown) {
606-
if (!(e instanceof ApiError && e.message.includes("INVALID_STATE"))) {
607-
throw e;
608-
}
609-
console.log(e.message);
594+
console.log(`Cluster ID: ${clusterId}`);
595+
if (attempt > 100) {
596+
throw new Error("Failed to start the cluster: too many attempts");
597+
}
598+
const cluster = await workspaceClient.clusters.get({
599+
cluster_id: clusterId,
600+
});
601+
console.log(`Cluster State: ${cluster.state}`);
602+
switch (cluster.state) {
603+
case "RUNNING":
604+
console.log("Cluster is already running");
605+
break;
606+
case "TERMINATED":
607+
case "ERROR":
608+
case "UNKNOWN":
609+
console.log("Starting the cluster...");
610+
await (
611+
await workspaceClient.clusters.start({
612+
cluster_id: clusterId,
613+
})
614+
).wait({
615+
onProgress: async (state) => {
616+
console.log(`Cluster state: ${state.state}`);
617+
},
618+
});
619+
break;
620+
case "PENDING":
621+
case "RESIZING":
622+
case "TERMINATING":
623+
case "RESTARTING":
624+
console.log("Waiting and retrying...");
625+
await sleep(10000);
626+
await startCluster(workspaceClient, clusterId, attempt + 1);
627+
break;
628+
default:
629+
throw new Error(`Unknown cluster state: ${cluster.state}`);
610630
}
611-
612-
console.log(`Cluster started`);
613631
}

packages/databricks-vscode/src/ui/configuration-view/EnvironmentComponent.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ export class EnvironmentComponent extends BaseComponent {
6464
const environmentState = await this.featureManager.isEnabled(
6565
"environment.dependencies"
6666
);
67-
const children = [];
67+
const children: ConfigurationTreeItem[] = [];
6868
for (const [id, step] of environmentState.steps) {
6969
if (!step.available) {
7070
children.push({
@@ -93,6 +93,13 @@ export class EnvironmentComponent extends BaseComponent {
9393
tooltip: step.message,
9494
iconPath: new ThemeIcon("check"),
9595
});
96+
if (step.warning) {
97+
children.push({
98+
contextValue: getItemContext(id, true),
99+
label: step.warning,
100+
iconPath: new ThemeIcon("warning"),
101+
});
102+
}
96103
}
97104
}
98105
return children;

0 commit comments

Comments
 (0)