Skip to content

Commit 7b962ff

Browse files
authored
DLT diagnostics (#1471)
## Changes - Report diagnostics based on ERROR and WARN pipeline events - Add "more info" action to relevant events in the resource explorer, open a file and notification when clicked - Add generic "run bundle resource" action (a but unrelated to the rest of the changes...) ## Tests Manual and existing tests
1 parent 1f1df4b commit 7b962ff

File tree

10 files changed

+472
-28
lines changed

10 files changed

+472
-28
lines changed

packages/databricks-vscode/package.json

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,13 @@
217217
"enablement": "databricks.context.activated && databricks.context.bundle.isTargetSet && databricks.context.bundle.deploymentState == idle",
218218
"category": "Databricks"
219219
},
220+
{
221+
"command": "databricks.bundle.deployAndRunFromInput",
222+
"icon": "$(run)",
223+
"title": "Deploy the bundle and run a resource",
224+
"enablement": "databricks.context.activated && databricks.context.bundle.isTargetSet && databricks.context.bundle.deploymentState == idle",
225+
"category": "Databricks"
226+
},
220227
{
221228
"command": "databricks.bundle.deployAndRunJob",
222229
"icon": "$(run)",
@@ -248,10 +255,24 @@
248255
"enablement": "databricks.context.activated && databricks.context.bundle.isTargetSet && databricks.context.bundle.deploymentState == idle",
249256
"category": "Databricks"
250257
},
258+
{
259+
"command": "databricks.bundle.clearPipelineDiagnostics",
260+
"icon": "$(clear-all)",
261+
"title": "Clear pipeline diagnostics",
262+
"enablement": "databricks.context.activated && databricks.context.bundle.isTargetSet",
263+
"category": "Databricks"
264+
},
265+
{
266+
"command": "databricks.bundle.showPipelineEventDetails",
267+
"icon": "$(info)",
268+
"title": "Show more information",
269+
"enablement": "databricks.context.activated && databricks.context.bundle.isTargetSet",
270+
"category": "Databricks"
271+
},
251272
{
252273
"command": "databricks.bundle.cancelRun",
253274
"title": "Cancel run",
254-
"icon": "$(debug-stop)",
275+
"icon": "$(stop)",
255276
"enablement": "databricks.context.activated && databricks.context.bundle.isTargetSet && databricks.context.bundle.deploymentState == idle",
256277
"category": "Databricks"
257278
},
@@ -638,6 +659,16 @@
638659
"when": "view == dabsResourceExplorerView && viewItem =~ /^databricks.bundle.resource=pipelines.runnable.*$/ && databricks.context.bundle.deploymentState == idle",
639660
"group": "navigation@0"
640661
},
662+
{
663+
"command": "databricks.bundle.showPipelineEventDetails",
664+
"when": "view == dabsResourceExplorerView && viewItem =~ /^databricks.bundle.*.has-pipeline-details.*$/",
665+
"group": "inline@0"
666+
},
667+
{
668+
"command": "databricks.bundle.showPipelineEventDetails",
669+
"when": "view == dabsResourceExplorerView && viewItem =~ /^databricks.bundle.*.has-pipeline-details.*$/",
670+
"group": "navigation@0"
671+
},
641672
{
642673
"command": "databricks.bundle.cancelRun",
643674
"when": "view == dabsResourceExplorerView && viewItem =~ /^databricks.bundle.*.cancellable.*$/ && databricks.context.bundle.deploymentState == idle",
@@ -780,6 +811,10 @@
780811
"command": "databricks.bundle.deployAndRunSelectedTables",
781812
"when": "false"
782813
},
814+
{
815+
"command": "databricks.bundle.showPipelineEventDetails",
816+
"when": "false"
817+
},
783818
{
784819
"command": "databricks.bundle.cancelRun",
785820
"when": "false"

packages/databricks-vscode/src/bundle/BundlePipelinesManager.test.ts

Lines changed: 62 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,15 @@ import {BundleRunStatusManager} from "./run/BundleRunStatusManager";
33
import {ConfigModel} from "../configuration/models/ConfigModel";
44
import {mock, instance, when} from "ts-mockito";
55
import assert from "assert";
6-
import {EventEmitter} from "vscode";
6+
import {EventEmitter, Uri} from "vscode";
77
import {install, InstalledClock} from "@sinonjs/fake-timers";
88
import {ConnectionManager} from "../configuration/ConnectionManager";
9+
import {locationToRange} from "./BundlePipelinesManager";
10+
import path from "node:path";
11+
import os from "os";
12+
import fs from "fs/promises";
913

10-
describe(__filename, () => {
14+
describe("BundlePipelinesManager", () => {
1115
let connectionManager: ConnectionManager;
1216
let runStatusManager: BundleRunStatusManager;
1317
let configModel: ConfigModel;
@@ -117,7 +121,7 @@ describe(__filename, () => {
117121
/* eslint-disable @typescript-eslint/naming-convention */
118122
const finalFullRefreshRun = {
119123
data: {
120-
creation_time: 200,
124+
creation_time: 300,
121125
refresh_selection: [],
122126
state: "COMPLETED",
123127
},
@@ -138,4 +142,59 @@ describe(__filename, () => {
138142
assert(datasets.has("table_new"));
139143
assert(datasets.has("table_final"));
140144
});
145+
146+
describe("locationToRange", () => {
147+
it("should return correct range for a given location in a text file", async () => {
148+
const uri = Uri.file("/path/to/file.py");
149+
// eslint-disable-next-line @typescript-eslint/naming-convention
150+
const location = {path: "/path/to/file.py", line_number: 10};
151+
const range = await locationToRange(uri, location);
152+
assert.strictEqual(range.start.line, 9);
153+
assert.strictEqual(range.end.line, 9);
154+
});
155+
156+
it("should return correct range for a given location in a notebook file", async () => {
157+
const uri = Uri.file("/path/to/notebook.ipynb");
158+
const location = {
159+
path: "/path/to/notebook.ipynb",
160+
// eslint-disable-next-line @typescript-eslint/naming-convention
161+
line_number: 5,
162+
// eslint-disable-next-line @typescript-eslint/naming-convention
163+
notebook_cell_number: 2,
164+
};
165+
const range = await locationToRange(uri, location, "IPYNB");
166+
assert.strictEqual(range.start.line, 4);
167+
assert.strictEqual(range.end.line, 4);
168+
});
169+
170+
it("should handle PY_DBNB file type correctly", async () => {
171+
// const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "test-"));
172+
const filePath = path.join(os.tmpdir(), "notebook.py");
173+
const uri = Uri.file(filePath);
174+
const fileContent = `# Databricks notebook source
175+
print('cell 1')
176+
177+
# COMMAND ----------
178+
print('cell 2')
179+
print('still cell 2')
180+
181+
182+
# COMMAND ----------
183+
print('cell 3')`;
184+
185+
await fs.writeFile(filePath, fileContent);
186+
187+
const location = {
188+
path: filePath,
189+
// eslint-disable-next-line @typescript-eslint/naming-convention
190+
line_number: 1,
191+
// eslint-disable-next-line @typescript-eslint/naming-convention
192+
notebook_cell_number: 3,
193+
};
194+
195+
const range = await locationToRange(uri, location, "PY_DBNB");
196+
assert.strictEqual(range.start.line, 9);
197+
assert.strictEqual(range.end.line, 9);
198+
});
199+
});
141200
});

0 commit comments

Comments
 (0)