Skip to content

Commit 8b5a944

Browse files
authored
Show error for a corrupted config file (#955)
Better error messaging when config file is corrupted. Should help with cases like this: #942 When we detect profile loading/parsing error (that comes from the CLI), we proceed with the configuration wizard without any pre-defined profiles, but also show a warning notification to the users, prompting them to open their config file and fix it.
1 parent 33aff1e commit 8b5a944

File tree

2 files changed

+76
-24
lines changed

2 files changed

+76
-24
lines changed

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

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ host = example.com
181181
path,
182182
new Context({
183183
logger: logging.NamedLogger.getOrCreate(
184-
"cli-wrapper-test",
184+
"cli-profile-format-test",
185185
{
186186
factory: () => {
187187
return {
@@ -209,4 +209,38 @@ host = example.com
209209
assert.ok(typoLog.level === "error");
210210
});
211211
});
212+
213+
it("should show error for corrupted config file and return empty profile list", async () => {
214+
const logFilePath = getTempLogFilePath();
215+
const cli = createCliWrapper(logFilePath);
216+
217+
await withFile(async ({path}) => {
218+
await writeFile(path, `[bad]\ntest 123`);
219+
const logs: {level: string; msg?: string; meta: any}[] = [];
220+
const profiles = await cli.listProfiles(
221+
path,
222+
new Context({
223+
logger: logging.NamedLogger.getOrCreate(
224+
"cli-parsing-error-test",
225+
{
226+
factory: () => {
227+
return {
228+
log: (level, msg, meta) => {
229+
logs.push({level, msg, meta});
230+
},
231+
};
232+
},
233+
}
234+
),
235+
})
236+
);
237+
const errorLog = logs.find(
238+
(log) =>
239+
log.msg?.includes("Failed to parse Databricks Config File")
240+
);
241+
assert.ok(errorLog !== undefined);
242+
assert.ok(errorLog.level === "error");
243+
assert.equal(profiles.length, 0);
244+
});
245+
});
212246
});

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

Lines changed: 41 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -104,16 +104,32 @@ export class CliWrapper {
104104
@context ctx?: Context
105105
): Promise<Array<ConfigEntry>> {
106106
const cmd = this.getListProfilesCommand();
107-
const res = await execFile(cmd.command, cmd.args, {
108-
env: {
109-
/* eslint-disable @typescript-eslint/naming-convention */
110-
HOME: process.env.HOME,
111-
DATABRICKS_CONFIG_FILE:
112-
configfilePath || process.env.DATABRICKS_CONFIG_FILE,
113-
DATABRICKS_OUTPUT_FORMAT: "json",
114-
/* eslint-enable @typescript-eslint/naming-convention */
115-
},
116-
});
107+
108+
let res;
109+
try {
110+
res = await execFile(cmd.command, cmd.args, {
111+
env: {
112+
/* eslint-disable @typescript-eslint/naming-convention */
113+
HOME: process.env.HOME,
114+
DATABRICKS_CONFIG_FILE:
115+
configfilePath || process.env.DATABRICKS_CONFIG_FILE,
116+
DATABRICKS_OUTPUT_FORMAT: "json",
117+
/* eslint-enable @typescript-eslint/naming-convention */
118+
},
119+
});
120+
} catch (e) {
121+
let msg = "Failed to load Databricks Config File";
122+
if (e instanceof Error) {
123+
if (e.message.includes("cannot parse config file")) {
124+
msg =
125+
"Failed to parse Databricks Config File, please make sure it's in the correct ini format";
126+
}
127+
}
128+
ctx?.logger?.error(msg, e);
129+
this.showConfigFileWarning(msg);
130+
return [];
131+
}
132+
117133
const profiles = JSON.parse(res.stdout).profiles || [];
118134
const result = [];
119135

@@ -135,24 +151,26 @@ export class CliWrapper {
135151
msg = `Error parsing profile ${profile.name}`;
136152
}
137153
ctx?.logger?.error(msg, e);
138-
window
139-
.showWarningMessage(
140-
msg,
141-
"Open Databricks Config File",
142-
"Ignore"
143-
)
144-
.then((choice) => {
145-
if (choice === "Open Databricks Config File") {
146-
commands.executeCommand(
147-
"databricks.connection.openDatabricksConfigFile"
148-
);
149-
}
150-
});
154+
this.showConfigFileWarning(msg);
151155
}
152156
}
153157
return result;
154158
}
155159

160+
private async showConfigFileWarning(msg: string) {
161+
const openAction = "Open Databricks Config File";
162+
const choice = await window.showWarningMessage(
163+
msg,
164+
openAction,
165+
"Ignore"
166+
);
167+
if (choice === openAction) {
168+
commands.executeCommand(
169+
"databricks.connection.openDatabricksConfigFile"
170+
);
171+
}
172+
}
173+
156174
public async getBundleSchema(): Promise<string> {
157175
const execFile = promisify(execFileCb);
158176
const {stdout} = await execFile(this.cliPath, ["bundle", "schema"]);

0 commit comments

Comments
 (0)