Skip to content

Commit e68f2bf

Browse files
Show correct default value for variables in bundle variable UI (#1277)
## Changes Fixes #1272 ## Tests <!-- How is this tested? -->
1 parent e86956b commit e68f2bf

File tree

6 files changed

+245
-22
lines changed

6 files changed

+245
-22
lines changed

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

Lines changed: 10 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -85,16 +85,16 @@ export class BundleVariableModel extends BaseModelWithStateCache<BundleVariableM
8585
this.disposables.push(
8686
this.overrideFileWatcher,
8787
this.overrideFileWatcher.onDidChange(async () => {
88-
await this.stateCache.refresh();
8988
await this.bundleValidateModel.refresh();
89+
await this.stateCache.refresh();
9090
}),
9191
this.overrideFileWatcher.onDidCreate(async () => {
92-
await this.stateCache.refresh();
9392
await this.bundleValidateModel.refresh();
93+
await this.stateCache.refresh();
9494
}),
9595
this.overrideFileWatcher.onDidDelete(async () => {
96-
await this.stateCache.refresh();
9796
await this.bundleValidateModel.refresh();
97+
await this.stateCache.refresh();
9898
})
9999
);
100100
}
@@ -204,32 +204,21 @@ export class BundleVariableModel extends BaseModelWithStateCache<BundleVariableM
204204
}
205205

206206
async getEnvVariables(): Promise<Record<string, string>> {
207-
const variables = (await this.stateCache.value).variables ?? {};
207+
const overrides = await this.getVariableOverrides();
208208
return Object.fromEntries(
209-
Object.entries(variables)
210-
.filter(
211-
([key]) => variables[key].vscodeOverrideValue !== undefined
212-
)
213-
.map(([key, value]) => [
214-
`BUNDLE_VAR_${key}`,
215-
value.vscodeOverrideValue,
216-
])
209+
Object.entries(overrides)
210+
.filter(([key]) => overrides[key] !== undefined)
211+
.map(([key, value]) => [`BUNDLE_VAR_${key}`, value])
217212
) as Record<string, string>;
218213
}
219214

220215
async getFileContent() {
221-
const variables = (await this.stateCache.value).variables ?? {};
216+
const variables = await this.getVariableOverrides();
222217
return JSON.stringify(
223218
Object.fromEntries(
224219
Object.entries(variables)
225-
.filter((v) => v[1].lookup === undefined)
226-
.map(([key, value]) => [
227-
key,
228-
value.vscodeOverrideValue ??
229-
value.valueInTarget ??
230-
value.default ??
231-
"",
232-
])
220+
.filter((v) => v[1] !== undefined)
221+
.map(([key, value]) => [key, value ?? ""])
233222
),
234223
null,
235224
4

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,25 @@ export class ProcessError extends Error {
4747
}
4848

4949
showErrorMessage(prefix?: string) {
50+
if (this.message.includes("no value assigned to required variable")) {
51+
window
52+
.showErrorMessage(
53+
(prefix?.trimEnd().concat(" ") ?? "") +
54+
`No value assigned to required variables.`,
55+
"Assign Values"
56+
)
57+
.then((choice) => {
58+
if (choice === "Assign Values") {
59+
commands.executeCommand("databricks.bundle.showLogs");
60+
commands.executeCommand("dabsVariableView.focus");
61+
commands.executeCommand(
62+
"databricks.bundle.variable.openFile"
63+
);
64+
}
65+
});
66+
return;
67+
}
68+
5069
window
5170
.showErrorMessage(
5271
(prefix?.trimEnd().concat(" ") ?? "") +
Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
import assert from "node:assert";
2+
import {
3+
dismissNotifications,
4+
getUniqueResourceName,
5+
getViewSection,
6+
waitForLogin,
7+
waitForTreeItems,
8+
} from "./utils/commonUtils.ts";
9+
import {CustomTreeSection, TextEditor, Workbench} from "wdio-vscode-service";
10+
import {
11+
getBasicBundleConfig,
12+
writeRootBundleConfig,
13+
} from "./utils/dabsFixtures.ts";
14+
import {BundleSchema} from "../../bundle/types.ts";
15+
16+
describe("Bundle Variables", async function () {
17+
let workbench: Workbench;
18+
let vscodeWorkspaceRoot: string;
19+
let schemaDef: BundleSchema;
20+
21+
this.timeout(3 * 60 * 1000);
22+
23+
async function createProjectWithJob() {
24+
const projectName = getUniqueResourceName("bundle_variables");
25+
/* eslint-disable @typescript-eslint/naming-convention */
26+
schemaDef = getBasicBundleConfig({
27+
bundle: {
28+
name: projectName,
29+
deployment: {},
30+
},
31+
variables: {
32+
varWithDefault: {
33+
default: "default",
34+
},
35+
},
36+
targets: {
37+
dev_test: {
38+
variables: {
39+
varWithDefault: "dev",
40+
},
41+
},
42+
},
43+
});
44+
45+
/* eslint-enable @typescript-eslint/naming-convention */
46+
await writeRootBundleConfig(schemaDef, vscodeWorkspaceRoot);
47+
}
48+
49+
before(async function () {
50+
assert(
51+
process.env.WORKSPACE_PATH,
52+
"WORKSPACE_PATH env var doesn't exist"
53+
);
54+
assert(
55+
process.env.DATABRICKS_HOST,
56+
"DATABRICKS_HOST env var doesn't exist"
57+
);
58+
59+
workbench = await browser.getWorkbench();
60+
vscodeWorkspaceRoot = process.env.WORKSPACE_PATH;
61+
await createProjectWithJob();
62+
await dismissNotifications();
63+
});
64+
65+
it("should wait for extension activation", async () => {
66+
const section = await getViewSection("CONFIGURATION");
67+
assert(section);
68+
});
69+
70+
it("should wait for connection", async () => {
71+
await waitForLogin("DEFAULT");
72+
await dismissNotifications();
73+
});
74+
75+
async function assertVariableValue(
76+
section: CustomTreeSection,
77+
variableName: string,
78+
expected: {value?: string; defaultValue?: string}
79+
) {
80+
await section.expand();
81+
const variableTreeItem = await section.findItem(variableName);
82+
assert(variableTreeItem);
83+
assert.strictEqual(
84+
await variableTreeItem.getDescription(),
85+
expected.value
86+
);
87+
88+
if (expected.defaultValue) {
89+
const defaultValueTreeItem = (
90+
await section.openItem(variableName)
91+
)[0];
92+
assert(defaultValueTreeItem);
93+
assert.strictEqual(
94+
await defaultValueTreeItem.getLabel(),
95+
"Default"
96+
);
97+
assert.strictEqual(
98+
await defaultValueTreeItem.getDescription(),
99+
expected.defaultValue
100+
);
101+
}
102+
}
103+
104+
it("should find bundle variable explorer and load default variables", async function () {
105+
const section = (await getViewSection("BUNDLE VARIABLES VIEW")) as
106+
| CustomTreeSection
107+
| undefined;
108+
assert(section);
109+
await waitForTreeItems(section, 20_000);
110+
111+
await assertVariableValue(section, "varWithDefault", {
112+
value: "dev",
113+
defaultValue: "default",
114+
});
115+
});
116+
117+
it("should override default variable", async function () {
118+
await browser.executeWorkbench((vscode) => {
119+
vscode.commands.executeCommand(
120+
"databricks.bundle.variable.openFile"
121+
);
122+
});
123+
const editor = (await workbench
124+
.getEditorView()
125+
.openEditor("vscode.bundlevars.json")) as TextEditor;
126+
assert(editor);
127+
128+
await editor.clearText();
129+
await editor.setText(
130+
JSON.stringify({varWithDefault: "new value"}, null, 4)
131+
);
132+
await editor.save();
133+
134+
const section = (await getViewSection("BUNDLE VARIABLES VIEW")) as
135+
| CustomTreeSection
136+
| undefined;
137+
assert(section);
138+
await waitForTreeItems(section, 5_000);
139+
140+
await browser.waitUntil(
141+
async () => {
142+
await assertVariableValue(section, "varWithDefault", {
143+
value: "new value",
144+
defaultValue: "default",
145+
});
146+
return true;
147+
},
148+
{
149+
timeout: 10_000,
150+
interval: 2_000,
151+
timeoutMsg: "Variable value not updated",
152+
}
153+
);
154+
});
155+
156+
it("should revert overrides", async function () {
157+
const section = (await getViewSection("BUNDLE VARIABLES VIEW")) as
158+
| CustomTreeSection
159+
| undefined;
160+
assert(section);
161+
await waitForTreeItems(section, 5_000);
162+
163+
const action = await section.getAction(
164+
"Reset bundle variables to default values"
165+
);
166+
167+
assert(action);
168+
await (await action.elem).click();
169+
170+
await browser.waitUntil(
171+
async () => {
172+
await assertVariableValue(section, "varWithDefault", {
173+
value: "dev",
174+
defaultValue: "default",
175+
});
176+
return true;
177+
},
178+
{
179+
timeout: 10_000,
180+
interval: 2_000,
181+
timeoutMsg: "Variable value not updated",
182+
}
183+
);
184+
});
185+
186+
it("should update view if bundle changes", async function () {
187+
schemaDef.targets!["dev_test"].variables!["varWithDefault"] =
188+
"changed value in bundle";
189+
190+
await writeRootBundleConfig(schemaDef, vscodeWorkspaceRoot);
191+
192+
const section = (await getViewSection("BUNDLE VARIABLES VIEW")) as
193+
| CustomTreeSection
194+
| undefined;
195+
assert(section);
196+
await waitForTreeItems(section, 5_000);
197+
198+
await browser.waitUntil(
199+
async () => {
200+
await assertVariableValue(section, "varWithDefault", {
201+
value: "changed value in bundle",
202+
defaultValue: "default",
203+
});
204+
return true;
205+
},
206+
{
207+
timeout: 10_000,
208+
interval: 2_000,
209+
timeoutMsg: "Variable value not updated",
210+
}
211+
);
212+
});
213+
});

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ describe("Automatically refresh resource explorer", async function () {
5656
const schemaDef: BundleSchema = getBasicBundleConfig({
5757
bundle: {
5858
name: projectName,
59+
deployment: {},
5960
},
6061
targets: {
6162
dev_test: {

packages/databricks-vscode/src/test/e2e/utils/commonUtils.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ const ViewSectionTypes = [
1515
"CONFIGURATION",
1616
"WORKSPACE EXPLORER",
1717
"BUNDLE RESOURCE EXPLORER",
18+
"BUNDLE VARIABLES VIEW",
1819
] as const;
1920
export type ViewSectionType = (typeof ViewSectionTypes)[number];
2021

packages/databricks-vscode/src/ui/bundle-variables/VariableTreeNode.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export class VariableTreeNode implements BundleVariableTreeNode {
2828
return [
2929
new TreeItemTreeNode({
3030
label: "Default",
31-
description: this.value.valueInTarget,
31+
description: this.value.default ?? this.value.valueInTarget,
3232
}),
3333
];
3434
}

0 commit comments

Comments
 (0)