Skip to content

Commit 157fb6f

Browse files
Backend for reading and writing overrides for bundle config (#901)
## Changes * Adds * `BundleConfigReaderWriter`: Manages reading and writing configs to/from the `BundleFileSet` * `ConfigOverrideReaderWriter`: Manages reading and writing configs to/from the `StateStorage` * `ConfigModel`: Provides a centralised view of the configs after applying any overrides. This is the single source of truth for all features that require reading/writing these configs. ## Tests <!-- How is this tested? -->
1 parent f356219 commit 157fb6f

File tree

18 files changed

+751
-34
lines changed

18 files changed

+751
-34
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"plugins": ["eslint-plugin-local-rules"],
3+
"rules": {
4+
"local-rules/mutex-synchronised-decorator": "error"
5+
}
6+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/* eslint-disable */
2+
require("ts-node").register({
3+
transpileOnly: true,
4+
compilerOptions: {
5+
module: "commonjs",
6+
},
7+
});
8+
9+
module.exports = {
10+
"mutex-synchronised-decorator":
11+
require("./rules/mutexSynchronisedDecorator").default,
12+
};
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/* eslint-disable no-console */
2+
import {ESLintUtils, AST_NODE_TYPES} from "@typescript-eslint/utils";
3+
4+
const rule = ESLintUtils.RuleCreator.withoutDocs({
5+
create(context) {
6+
return {
7+
// eslint-disable-next-line @typescript-eslint/naming-convention
8+
Decorator(node) {
9+
if (
10+
node.expression.type === "CallExpression" &&
11+
node.expression.callee.type ===
12+
AST_NODE_TYPES.MemberExpression &&
13+
node.expression.callee.object.type ===
14+
AST_NODE_TYPES.Identifier &&
15+
node.expression.callee.object.name === "Mutex" &&
16+
node.expression.callee.property.type ===
17+
AST_NODE_TYPES.Identifier &&
18+
node.expression.callee.property.name === "synchronise" &&
19+
node.expression.arguments.length > 0
20+
) {
21+
const mutexName =
22+
node.expression.arguments[0].type ===
23+
AST_NODE_TYPES.Literal
24+
? (node.expression.arguments[0].value as string)
25+
: "";
26+
27+
if (node.parent.parent?.type !== AST_NODE_TYPES.ClassBody) {
28+
return context.report({
29+
node,
30+
messageId: "decoratorNotInClass",
31+
});
32+
}
33+
34+
const exists = node.parent.parent.body.some((element) => {
35+
return (
36+
element.type ===
37+
AST_NODE_TYPES.PropertyDefinition &&
38+
element.key.type === AST_NODE_TYPES.Identifier &&
39+
element.key.name === mutexName
40+
);
41+
});
42+
43+
const className =
44+
node.parent.parent.parent?.type ===
45+
AST_NODE_TYPES.ClassDeclaration
46+
? node.parent.parent.parent.id?.name
47+
: undefined;
48+
49+
if (!exists) {
50+
return context.report({
51+
node,
52+
messageId: "synchronisedMutexNotInClass",
53+
data: {
54+
mutexName,
55+
className,
56+
},
57+
});
58+
}
59+
}
60+
},
61+
};
62+
},
63+
meta: {
64+
type: "problem",
65+
schema: [],
66+
messages: {
67+
decoratorNotInClass:
68+
"Mutex.synchronized() should be used inside a class",
69+
synchronisedMutexNotInClass:
70+
'Mutex "{{mutexName}}" is not defined in class "{{className}}".',
71+
},
72+
},
73+
defaultOptions: [],
74+
});
75+
76+
export default rule;
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"transpileOnly": true,
3+
"compilerOptions": {
4+
"module": "Node16"
5+
}
6+
}

packages/databricks-vscode/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -709,6 +709,7 @@
709709
"@sinonjs/fake-timers": "^10.3.0",
710710
"@types/bcryptjs": "^2.4.2",
711711
"@types/chai": "^4.3.5",
712+
"@types/eslint": "^8.44.6",
712713
"@types/fs-extra": "^11.0.1",
713714
"@types/mocha": "^10.0.2",
714715
"@types/mock-require": "^2.0.1",
@@ -720,6 +721,7 @@
720721
"@types/yargs": "^17.0.24",
721722
"@typescript-eslint/eslint-plugin": "^6.0.0",
722723
"@typescript-eslint/parser": "^6.0.0",
724+
"@typescript-eslint/utils": "^6.9.0",
723725
"@vscode/test-electron": "^2.3.3",
724726
"@wdio/cli": "^8.12.2",
725727
"@wdio/local-runner": "^8.12.1",
@@ -729,6 +731,7 @@
729731
"chai": "^4.3.7",
730732
"esbuild": "^0.19.4",
731733
"eslint": "^8.51.0",
734+
"eslint-plugin-local-rules": "^2.0.0",
732735
"fs-extra": "^11.1.1",
733736
"glob": "^10.3.10",
734737
"json-schema-to-typescript": "^13.1.1",

packages/databricks-vscode/src/bundle/BundleFileSet.ts

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {merge} from "lodash";
44
import * as yaml from "yaml";
55
import path from "path";
66
import {BundleSchema} from "./BundleSchema";
7-
import {readFile} from "fs/promises";
7+
import {readFile, writeFile} from "fs/promises";
88
import {CachedValue} from "../locking/CachedValue";
99
import minimatch from "minimatch";
1010

@@ -13,6 +13,10 @@ export async function parseBundleYaml(file: Uri) {
1313
return data as BundleSchema;
1414
}
1515

16+
export async function writeBundleYaml(file: Uri, data: BundleSchema) {
17+
await writeFile(file.fsPath, yaml.stringify(data));
18+
}
19+
1620
function toGlobPath(path: string) {
1721
if (process.platform === "win32") {
1822
return path.replace(/\\/g, "/");
@@ -21,7 +25,7 @@ function toGlobPath(path: string) {
2125
}
2226
export class BundleFileSet {
2327
private rootFilePattern: string = "{bundle,databricks}.{yaml,yml}";
24-
private _mergedBundle: CachedValue<BundleSchema> =
28+
public readonly bundleDataCache: CachedValue<BundleSchema> =
2529
new CachedValue<BundleSchema>(async () => {
2630
let bundle = {};
2731
await this.forEach(async (data) => {
@@ -88,13 +92,15 @@ export class BundleFileSet {
8892
return [rootFile, ...((await this.getIncludedFiles()) ?? [])];
8993
}
9094

91-
async findFileWithPredicate(predicate: (file: Uri) => Promise<boolean>) {
92-
const matchedFiles: Uri[] = [];
93-
for (const file of await this.allFiles()) {
94-
if (await predicate(file)) {
95-
matchedFiles.push(file);
95+
async findFile(
96+
predicate: (data: BundleSchema, file: Uri) => Promise<boolean>
97+
) {
98+
const matchedFiles: {data: BundleSchema; file: Uri}[] = [];
99+
this.forEach(async (data, file) => {
100+
if (await predicate(data, file)) {
101+
matchedFiles.push({data, file});
96102
}
97-
}
103+
});
98104
return matchedFiles;
99105
}
100106

@@ -123,12 +129,4 @@ export class BundleFileSet {
123129
async isBundleFile(e: Uri) {
124130
return this.isRootBundleFile(e) || (await this.isIncludedBundleFile(e));
125131
}
126-
127-
async invalidateMergedBundleCache() {
128-
await this._mergedBundle.invalidate();
129-
}
130-
131-
get mergedBundle() {
132-
return this._mergedBundle.value;
133-
}
134132
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import {BundleSchema} from "./BundleSchema";
2+
3+
export type BundleTarget = Required<BundleSchema>["targets"][string];

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ export class DatabricksCliSyncParser {
123123
return;
124124
}
125125
}
126+
this.syncStateCallback("ERROR", data);
126127
}
127128

128129
private matchForErrors(line: string) {

0 commit comments

Comments
 (0)