Skip to content
69 changes: 67 additions & 2 deletions packages/databricks-vscode/src/bundle/BundleFileSet.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ describe(__filename, async function () {
await tmpdir.cleanup();
});

function getWorkspaceFolderManagerMock() {
function getWorkspaceFolderManagerMock(projectDir?: string) {
const mockWorkspaceFolderManager = mock<WorkspaceFolderManager>();
const mockWorkspaceFolder = mock<WorkspaceFolder>();
const uri = Uri.file(tmpdir.path);
const uri = Uri.file(projectDir ?? tmpdir.path);
when(mockWorkspaceFolder.uri).thenReturn(uri);
when(mockWorkspaceFolderManager.activeWorkspaceFolder).thenReturn(
instance(mockWorkspaceFolder)
Expand Down Expand Up @@ -73,6 +73,71 @@ describe(__filename, async function () {
expect(await bundleFileSet.getRootFile()).to.be.undefined;
});

describe("parent-directory includes", async () => {
it("getIncludedFiles should find files referenced via .. paths", async () => {
// Structure: tmpdir/shared/config.yml (included), tmpdir/project/sub/ (project root)
const sharedDir = path.join(tmpdir.path, "shared");
const projectDir = path.join(tmpdir.path, "project", "sub");
await fs.mkdir(sharedDir, {recursive: true});
await fs.mkdir(projectDir, {recursive: true});

const sharedFile = path.join(sharedDir, "config.yml");
const sharedFile2 = path.join(sharedDir, "config2.yml");
await fs.writeFile(sharedFile, "");
await fs.writeFile(sharedFile2, "");

const rootBundleData: BundleSchema = {
include: ["../../shared/config.yml", "../../shared/config2.yml"],
};
await fs.writeFile(
path.join(projectDir, "databricks.yml"),
yaml.stringify(rootBundleData)
);

const bundleFileSet = new BundleFileSet(
getWorkspaceFolderManagerMock(projectDir)
);

const files = await bundleFileSet.getIncludedFiles();
expect(files).to.not.be.undefined;
expect(files!.map((f) => f.fsPath).sort()).to.deep.equal(
[sharedFile, sharedFile2].sort()
);
});

it("isIncludedBundleFile should return true for files referenced via .. paths", async () => {
const sharedDir = path.join(tmpdir.path, "shared");
const projectDir = path.join(tmpdir.path, "project", "sub");
await fs.mkdir(sharedDir, {recursive: true});
await fs.mkdir(projectDir, {recursive: true});

const sharedFile = path.join(sharedDir, "config.yml");
await fs.writeFile(sharedFile, "");

const rootBundleData: BundleSchema = {
include: ["../../shared/config.yml", "local.yml"],
};
await fs.writeFile(
path.join(projectDir, "databricks.yml"),
yaml.stringify(rootBundleData)
);

const bundleFileSet = new BundleFileSet(
getWorkspaceFolderManagerMock(projectDir)
);

expect(
await bundleFileSet.isIncludedBundleFile(Uri.file(sharedFile))
).to.be.true;

expect(
await bundleFileSet.isIncludedBundleFile(
Uri.file(path.join(projectDir, "other.yml"))
)
).to.be.false;
});
});

describe("file listing", async () => {
beforeEach(async () => {
const rootBundleData: BundleSchema = {
Expand Down
65 changes: 40 additions & 25 deletions packages/databricks-vscode/src/bundle/BundleFileSet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,33 +88,47 @@ export class BundleFileSet {
return Uri.file(rootFile[0]);
}

async getIncludedFilesGlob() {
private async getIncludePatterns(): Promise<string[]> {
const rootFile = await this.getRootFile();
if (rootFile === undefined) {
return undefined;
return [];
}
const bundle = await parseBundleYaml(rootFile);
if (!bundle?.include?.length) {
return [];
}
const bundle = await parseBundleYaml(Uri.file(rootFile.fsPath));
if (bundle?.include === undefined || bundle?.include.length === 0) {
return bundle.include;
}

async getIncludedFilesGlob() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it used anywhere now?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not used, removed

const patterns = await this.getIncludePatterns();
if (patterns.length === 0) {
return undefined;
}
if (bundle?.include.length === 1) {
return bundle.include[0];
if (patterns.length === 1) {
return patterns[0];
}
return `{${bundle.include.join(",")}}`;
return `{${patterns.join(",")}}`;
}

async getIncludedFiles() {
const includedFilesGlob = await this.getIncludedFilesGlob();
if (includedFilesGlob !== undefined) {
return (
await glob.glob(
toGlobPath(
path.join(this.projectRoot.fsPath, includedFilesGlob)
),
{nocase: process.platform === "win32"}
)
).map((i) => Uri.file(i));
const patterns = await this.getIncludePatterns();
if (patterns.length === 0) {
return undefined;
}

const allFiles: string[] = [];
for (const pattern of patterns) {
const absolutePattern = toGlobPath(
path.resolve(this.projectRoot.fsPath, pattern)
);
const files = await glob.glob(absolutePattern, {
nocase: process.platform === "win32",
});
allFiles.push(...files);
}

return [...new Set(allFiles)].map((f) => Uri.file(f));
}

async allFiles() {
Expand Down Expand Up @@ -152,15 +166,16 @@ export class BundleFileSet {
}

async isIncludedBundleFile(e: Uri) {
let includedFilesGlob = await this.getIncludedFilesGlob();
if (includedFilesGlob === undefined) {
return false;
const patterns = await this.getIncludePatterns();
for (const pattern of patterns) {
const absolutePattern = toGlobPath(
path.resolve(this.projectRoot.fsPath, pattern)
);
if (minimatch(toGlobPath(e.fsPath), absolutePattern)) {
return true;
}
}
includedFilesGlob = getAbsoluteGlobPath(
includedFilesGlob,
this.projectRoot
);
return minimatch(e.fsPath, toGlobPath(includedFilesGlob));
return false;
}

async isBundleFile(e: Uri) {
Expand Down