Skip to content

Commit 20070db

Browse files
Fix multiple quote issue for .databricks.env file. (#686)
## Changes * Variables being added to .databricks.env were being added with multiple quotes. This was because of the following sequence of events: * Vscode would try to search for user env file (.env) and not find it. * It would then try to search for mspython python.envFile and not find it. * Finally it will set the userEnvFile to .env and the mspython python.envFile to .databricks/.databricks.env. * At the same time, if another instance of vscode is running in the same project, it will go through the same steps, but this time find mspython python.envFile to be .databricks/.databricks.env. It will use this value for userEnvFile. * Now both values are set to .databricks/.databricks.env. This is an issue. This is fixed by * Stripping quotes * More strict checking for .databricks/.databricks.env appearing in userEnvFile. This pr also adds an integration test for running .ipynb as jobs. --------- Signed-off-by: kartikgupta-db <kartik.gupta@databricks.com>
1 parent 97e7319 commit 20070db

File tree

4 files changed

+121
-10
lines changed

4 files changed

+121
-10
lines changed

packages/databricks-vscode/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,7 @@
373373
},
374374
{
375375
"command": "databricks.run.runEditorContentsAsWorkflow",
376-
"when": "resourceLangId == python"
376+
"when": "resourceLangId == python || resourceExtname == .ipynb"
377377
},
378378
{
379379
"command": "databricks.wsfs.createFolder",

packages/databricks-vscode/src/file-managers/DatabricksEnvFileManager.ts

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {logging} from "@databricks/databricks-sdk";
2020
import {Loggers} from "../logger";
2121
import {Context, context} from "@databricks/databricks-sdk/dist/context";
2222
import {MsPythonExtensionWrapper} from "../language/MsPythonExtensionWrapper";
23+
import {NamedLogger} from "@databricks/databricks-sdk/dist/logging";
2324

2425
export class DatabricksEnvFileManager implements Disposable {
2526
private disposables: Disposable[] = [];
@@ -48,18 +49,27 @@ export class DatabricksEnvFileManager implements Disposable {
4849
systemVariableResolver.resolve(unresolvedDatabricksEnvFile)
4950
);
5051

51-
const unresolvedUserEnvFile = workspaceConfigs.userEnvFile
52+
const unresolvedUserEnvFile = this.isValidUserEnvPath(
53+
workspaceConfigs.userEnvFile,
54+
[unresolvedDatabricksEnvFile, this.databricksEnvPath.fsPath]
55+
)
5256
? workspaceConfigs.userEnvFile
53-
: !workspaceConfigs.msPythonEnvFile ||
54-
workspaceConfigs.msPythonEnvFile.includes(
55-
this.databricksEnvPath.fsPath
56-
)
57-
? path.join("${workspaceFolder}", ".env")
58-
: workspaceConfigs.msPythonEnvFile;
57+
: this.isValidUserEnvPath(workspaceConfigs.msPythonEnvFile, [
58+
unresolvedDatabricksEnvFile,
59+
this.databricksEnvPath.fsPath,
60+
])
61+
? workspaceConfigs.msPythonEnvFile
62+
: path.join("${workspaceFolder}", ".env");
5963
this.userEnvPath = Uri.file(
6064
systemVariableResolver.resolve(unresolvedUserEnvFile)
6165
);
6266

67+
NamedLogger.getOrCreate(Loggers.Extension).debug("Env file locations", {
68+
unresolvedDatabricksEnvFile,
69+
unresolvedUserEnvFile,
70+
msEnvFile: workspaceConfigs.msPythonEnvFile,
71+
});
72+
6373
workspaceConfigs.msPythonEnvFile = unresolvedDatabricksEnvFile;
6474
workspaceConfigs.userEnvFile = unresolvedUserEnvFile;
6575

@@ -125,6 +135,13 @@ export class DatabricksEnvFileManager implements Disposable {
125135
);
126136
}
127137

138+
private isValidUserEnvPath(
139+
path: string | undefined,
140+
excludes: string[]
141+
): path is string {
142+
return path !== undefined && !excludes.includes(path);
143+
}
144+
128145
private async disableStatusBarButton() {
129146
const featureState = await this.featureManager.isEnabled(
130147
"debugging.dbconnect"
@@ -263,7 +280,10 @@ export class DatabricksEnvFileManager implements Disposable {
263280
const data = Object.entries({
264281
...databricksEnvVars,
265282
...userEnvVars,
266-
}).map(([key, value]) => `${key}="${value}"`);
283+
}).map(([key, value]) => {
284+
value = value?.replaceAll(/^"|"$/g, "");
285+
return `${key}="${value}"`;
286+
});
267287
try {
268288
const oldData = await readFile(
269289
this.databricksEnvPath.fsPath,

packages/databricks-vscode/src/test/e2e/run_job_on_cluster_with_workspace.e2e.ts

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/* eslint-disable @typescript-eslint/naming-convention */
12
import path from "node:path";
23
import * as fs from "fs/promises";
34
import assert from "node:assert";
@@ -56,6 +57,30 @@ describe("Run job on cluster with workspace", async function () {
5657
].join("\n")
5758
);
5859

60+
await fs.writeFile(
61+
path.join(projectDir, "notebook_ipynb.ipynb"),
62+
JSON.stringify({
63+
cells: [
64+
{
65+
cell_type: "code",
66+
execution_count: null,
67+
metadata: {},
68+
outputs: [],
69+
source: ['print("hello")'],
70+
},
71+
],
72+
metadata: {
73+
kernelspec: {
74+
display_name: "Python 3",
75+
language: "python",
76+
name: "python3",
77+
},
78+
orig_nbformat: 4,
79+
},
80+
nbformat: 4,
81+
nbformat_minor: 2,
82+
})
83+
);
5984
const section = await getViewSection("CONFIGURATION");
6085
assert(section);
6186
await waitForTreeItems(section);
@@ -129,6 +154,72 @@ describe("Run job on cluster with workspace", async function () {
129154
webView.close();
130155
});
131156

157+
it("should run a jupyter notebook as a job on a cluster", async () => {
158+
await startSyncIfStopped();
159+
await waitForSyncComplete();
160+
161+
const workbench = await driver.getWorkbench();
162+
const editorView = workbench.getEditorView();
163+
await editorView.closeAllEditors();
164+
165+
// open file
166+
const input = await workbench.openCommandPrompt();
167+
await sleep(200);
168+
await input.setText("notebook_ipynb.ipynb");
169+
await input.confirm();
170+
await sleep(500);
171+
172+
// run file
173+
await workbench.executeQuickPick(
174+
"Databricks: Run File as Workflow on Databricks"
175+
);
176+
177+
await dismissNotifications();
178+
const webView = await workbench.getWebviewByTitle(/Databricks Job Run/);
179+
await webView.open();
180+
181+
/* eslint-disable @typescript-eslint/naming-convention */
182+
const labelToDefaults = {
183+
taskRunId: {label: "task-run-id", default: /N\\A/},
184+
clusterId: {label: "cluster", default: /N\\A/},
185+
startTime: {label: "run-start-time", default: /-/},
186+
endTime: {label: "run-end-time", default: /-/},
187+
duration: {label: "run-duration", default: /-/},
188+
status: {label: "run-status", default: /Synchronizing/},
189+
};
190+
/* eslint-enable @typescript-eslint/naming-convention */
191+
192+
// wait for job to get a task id
193+
await browser.waitUntil(
194+
async () =>
195+
(
196+
await browser.getTextByLabel(
197+
labelToDefaults.taskRunId.label
198+
)
199+
).match(labelToDefaults.taskRunId.default) === null,
200+
{
201+
timeoutMsg: "Job did not start",
202+
}
203+
);
204+
205+
expect(
206+
await browser.getTextByLabel(labelToDefaults.startTime.label)
207+
).not.toHaveText(labelToDefaults.startTime.default);
208+
209+
await browser.waitUntil(
210+
async () =>
211+
(
212+
await browser.getTextByLabel(labelToDefaults.status.label)
213+
).match(/Succeeded/) !== null,
214+
{
215+
timeout: 20000,
216+
interval: 50,
217+
timeoutMsg: "Job did not reach succeeded status after 20s.",
218+
}
219+
);
220+
221+
webView.close();
222+
});
132223
it("should run a python file as a job on a cluster", async () => {
133224
await startSyncIfStopped();
134225
await waitForSyncComplete();

packages/databricks-vscode/src/workspace-fs/WorkspaceFsWorkflowWrapper.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ export class WorkspaceFsWorkflowWrapper {
8989
originalJson["cells"] = [bootstrapJson].concat(
9090
originalJson["cells"] ?? []
9191
);
92-
this.createFile(
92+
return this.createFile(
9393
getWrapperPath(remoteFilePath, [
9494
"databricks",
9595
"notebook",

0 commit comments

Comments
 (0)