Skip to content

Commit 264d9fc

Browse files
authored
Fix parsing .databrickscfg profiles that contain a dot (#498)
fixes #497
1 parent 275ea87 commit 264d9fc

File tree

5 files changed

+80
-4
lines changed

5 files changed

+80
-4
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import {parse} from "ini";
2+
import assert from "node:assert";
3+
import {flattenIniObject} from "./KnownConfigLoader";
4+
5+
describe(__filename, () => {
6+
it("should handle profiles with a dot in the name", () => {
7+
const config = flattenIniObject(
8+
parse(`[foo.bar]
9+
host = https://foo.bar
10+
11+
[.foo]
12+
host = https://foo
13+
14+
[bar]
15+
host = https://bar`)
16+
);
17+
18+
assert.equal(config["foo.bar"].host, "https://foo.bar");
19+
assert.equal(config[".foo"].host, "https://foo");
20+
assert.equal(config["bar"].host, "https://bar");
21+
});
22+
});

packages/databricks-sdk-js/src/config/KnownConfigLoader.ts

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ export class KnownConfigLoader implements Loader {
2525
return;
2626
}
2727

28-
const iniFile = parse(
29-
await fs.readFile(configPath, {encoding: "utf-8"})
28+
const iniFile = flattenIniObject(
29+
parse(await fs.readFile(configPath, {encoding: "utf-8"}))
3030
);
3131

3232
const profile = cfg.profile || "DEFAULT";
@@ -49,3 +49,44 @@ export class KnownConfigLoader implements Loader {
4949
cfg.attributes.resolveFromStringMap(iniFile[profile]);
5050
}
5151
}
52+
53+
/**
54+
* The ini library encodes dots as nested objects, which is not what we want.
55+
* See: https://github.com/npm/ini/issues/22
56+
*
57+
* Reduce the nested object back to a flat object by concatenating object keys with a `.`
58+
*/
59+
export function flattenIniObject(obj: {[key: string]: any}): {
60+
[key: string]: any;
61+
} {
62+
function _flattenIniObject(
63+
obj: {
64+
[key: string]: any;
65+
},
66+
topLevel: Array<string> = [],
67+
resp = {}
68+
) {
69+
const props: Record<string, any> = {};
70+
for (const key in obj) {
71+
if (typeof obj[key] === "object") {
72+
topLevel.push(key);
73+
resp = {
74+
...resp,
75+
..._flattenIniObject(obj[key], topLevel, resp),
76+
};
77+
} else {
78+
props[key] = obj[key];
79+
}
80+
}
81+
82+
const topLevelName = topLevel.join(".");
83+
if (topLevelName !== "" && Object.keys(props).length > 0) {
84+
resp = {...resp, [topLevelName]: props};
85+
}
86+
87+
topLevel.pop();
88+
return resp;
89+
}
90+
91+
return _flattenIniObject(obj);
92+
}

packages/databricks-sdk-js/src/config/testdata/.databrickscfg

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,8 @@ azure_client_secret = 10000002
3434

3535
[gcp-example]
3636
host = https://123.4.gcp.databricks.com/
37-
google_credentials = paw48590aw8e09t8apu
37+
google_credentials = paw48590aw8e09t8apu
38+
39+
[pat.with.dot]
40+
host = https://dbc-XXXXXXXX-YYYY.cloud.databricks.com/
41+
token = PT0+IC9kZXYvdXJhbmRvbSA8PT0KYFZ

packages/databricks-sdk-js/src/config/testdata/unified-auth-cases.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,15 @@
129129
},
130130
"assert_error": "default auth: cannot configure default credentials. Config: token=***, profile=nohost. Env: DATABRICKS_CONFIG_PROFILE"
131131
},
132+
{
133+
"name": "TestConfig_PatFromDatabricksCfg_DotProfile",
134+
"env": {
135+
"DATABRICKS_CONFIG_PROFILE": "pat.with.dot",
136+
"HOME": "testdata"
137+
},
138+
"assert_auth": "pat",
139+
"assert_host": "https://dbc-XXXXXXXX-YYYY.cloud.databricks.com"
140+
},
132141
{
133142
"name": "TestConfig_ConfigProfileAndToken",
134143
"env": {

packages/databricks-vscode/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -707,4 +707,4 @@
707707
],
708708
"report-dir": "coverage"
709709
}
710-
}
710+
}

0 commit comments

Comments
 (0)