Skip to content

Commit 9b647ff

Browse files
Merge pull request #2310 from github/yer-a-workspace-query
Stop pushing QL pack as top level folder to avoid confusing the user
2 parents ffa643c + 9c79799 commit 9b647ff

File tree

7 files changed

+118
-102
lines changed

7 files changed

+118
-102
lines changed

extensions/ql-vscode/src/helpers.ts

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
} from "fs-extra";
99
import { glob } from "glob";
1010
import { load } from "js-yaml";
11-
import { join, basename } from "path";
11+
import { join, basename, dirname } from "path";
1212
import { dirSync } from "tmp-promise";
1313
import {
1414
ExtensionContext,
@@ -791,3 +791,39 @@ export async function* walkDirectory(
791791
}
792792
}
793793
}
794+
795+
/**
796+
* Returns the path of the first folder in the workspace.
797+
* This is used to decide where to create skeleton QL packs.
798+
*
799+
* If the first folder is a QL pack, then the parent folder is returned.
800+
* This is because the vscode-codeql-starter repo contains a ql pack in
801+
* the first folder.
802+
*
803+
* This is a temporary workaround until we can retire the
804+
* vscode-codeql-starter repo.
805+
*/
806+
807+
export function getFirstWorkspaceFolder() {
808+
const workspaceFolders = getOnDiskWorkspaceFolders();
809+
810+
if (!workspaceFolders || workspaceFolders.length === 0) {
811+
throw new Error("No workspace folders found");
812+
}
813+
814+
const firstFolderFsPath = workspaceFolders[0];
815+
816+
// For the vscode-codeql-starter repo, the first folder will be a ql pack
817+
// so we need to get the parent folder
818+
if (
819+
firstFolderFsPath.includes(
820+
join("vscode-codeql-starter", "codeql-custom-queries"),
821+
)
822+
) {
823+
// return the parent folder
824+
return dirname(firstFolderFsPath);
825+
} else {
826+
// if the first folder is not a ql pack, then we are in a normal workspace
827+
return firstFolderFsPath;
828+
}
829+
}

extensions/ql-vscode/src/local-databases.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
showAndLogExceptionWithTelemetry,
1212
isFolderAlreadyInWorkspace,
1313
showBinaryChoiceDialog,
14+
getFirstWorkspaceFolder,
1415
} from "./helpers";
1516
import { ProgressCallback, withProgress } from "./progress";
1617
import {
@@ -29,6 +30,7 @@ import { isCodespacesTemplate } from "./config";
2930
import { QlPackGenerator } from "./qlpack-generator";
3031
import { QueryLanguage } from "./common/query-language";
3132
import { App } from "./common/app";
33+
import { existsSync } from "fs";
3234

3335
/**
3436
* databases.ts
@@ -662,8 +664,13 @@ export class DatabaseManager extends DisposableObject {
662664
return;
663665
}
664666

667+
const firstWorkspaceFolder = getFirstWorkspaceFolder();
665668
const folderName = `codeql-custom-queries-${databaseItem.language}`;
666-
if (isFolderAlreadyInWorkspace(folderName)) {
669+
670+
if (
671+
existsSync(join(firstWorkspaceFolder, folderName)) ||
672+
isFolderAlreadyInWorkspace(folderName)
673+
) {
667674
return;
668675
}
669676

@@ -680,7 +687,7 @@ export class DatabaseManager extends DisposableObject {
680687
folderName,
681688
databaseItem.language as QueryLanguage,
682689
this.cli,
683-
this.ctx.storageUri?.fsPath,
690+
firstWorkspaceFolder,
684691
);
685692
await qlPackGenerator.generate();
686693
} catch (e: unknown) {

extensions/ql-vscode/src/qlpack-generator.ts

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import { writeFile } from "fs-extra";
1+
import { mkdir, writeFile } from "fs-extra";
22
import { dump } from "js-yaml";
33
import { join } from "path";
4-
import { Uri, workspace } from "vscode";
4+
import { Uri } from "vscode";
55
import { CodeQLCliServer } from "./cli";
66
import { QueryLanguage } from "./common/query-language";
77

@@ -44,14 +44,7 @@ export class QlPackGenerator {
4444
}
4545

4646
private async createWorkspaceFolder() {
47-
await workspace.fs.createDirectory(this.folderUri);
48-
49-
const end = (workspace.workspaceFolders || []).length;
50-
51-
workspace.updateWorkspaceFolders(end, 0, {
52-
name: this.folderName,
53-
uri: this.folderUri,
54-
});
47+
await mkdir(this.folderUri.fsPath);
5548
}
5649

5750
private async createQlPackYaml() {

extensions/ql-vscode/src/skeleton-query-wizard.ts

Lines changed: 11 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,20 @@
1-
import { join, dirname } from "path";
1+
import { join } from "path";
22
import { CancellationToken, Uri, workspace, window as Window } from "vscode";
33
import { CodeQLCliServer } from "./cli";
44
import { OutputChannelLogger } from "./common";
55
import { Credentials } from "./common/authentication";
66
import { QueryLanguage } from "./common/query-language";
7-
import { askForLanguage, isFolderAlreadyInWorkspace } from "./helpers";
7+
import {
8+
askForLanguage,
9+
getFirstWorkspaceFolder,
10+
isFolderAlreadyInWorkspace,
11+
} from "./helpers";
812
import { getErrorMessage } from "./pure/helpers-pure";
913
import { QlPackGenerator } from "./qlpack-generator";
1014
import { DatabaseItem, DatabaseManager } from "./local-databases";
1115
import { ProgressCallback, UserCancellationException } from "./progress";
1216
import { askForGitHubRepo, downloadGitHubDatabase } from "./databaseFetcher";
17+
import { existsSync } from "fs";
1318

1419
type QueryLanguagesToDatabaseMap = Record<string, string>;
1520

@@ -50,11 +55,11 @@ export class SkeletonQueryWizard {
5055
return;
5156
}
5257

53-
this.qlPackStoragePath = this.getFirstStoragePath();
58+
this.qlPackStoragePath = getFirstWorkspaceFolder();
5459

55-
const skeletonPackAlreadyExists = isFolderAlreadyInWorkspace(
56-
this.folderName,
57-
);
60+
const skeletonPackAlreadyExists =
61+
existsSync(join(this.qlPackStoragePath, this.folderName)) ||
62+
isFolderAlreadyInWorkspace(this.folderName);
5863

5964
if (skeletonPackAlreadyExists) {
6065
// just create a new example query file in skeleton QL pack
@@ -93,27 +98,6 @@ export class SkeletonQueryWizard {
9398
});
9499
}
95100

96-
public getFirstStoragePath() {
97-
const workspaceFolders = workspace.workspaceFolders;
98-
99-
if (!workspaceFolders || workspaceFolders.length === 0) {
100-
throw new Error("No workspace folders found");
101-
}
102-
103-
const firstFolder = workspaceFolders[0];
104-
const firstFolderFsPath = firstFolder.uri.fsPath;
105-
106-
// For the vscode-codeql-starter repo, the first folder will be a ql pack
107-
// so we need to get the parent folder
108-
if (firstFolderFsPath.includes("codeql-custom-queries")) {
109-
// return the parent folder
110-
return dirname(firstFolderFsPath);
111-
} else {
112-
// if the first folder is not a ql pack, then we are in a normal workspace
113-
return firstFolderFsPath;
114-
}
115-
}
116-
117101
private async chooseLanguage() {
118102
this.progress({
119103
message: "Choose language",

extensions/ql-vscode/test/vscode-tests/cli-integration/skeleton-query-wizard.test.ts

Lines changed: 2 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -82,11 +82,11 @@ describe("SkeletonQueryWizard", () => {
8282
jest.spyOn(workspace, "workspaceFolders", "get").mockReturnValue([
8383
{
8484
name: `codespaces-codeql`,
85-
uri: { fsPath: storagePath },
85+
uri: { fsPath: storagePath, scheme: "file" },
8686
},
8787
{
8888
name: "/second/folder/path",
89-
uri: { fsPath: storagePath },
89+
uri: { fsPath: storagePath, scheme: "file" },
9090
},
9191
] as WorkspaceFolder[]);
9292

@@ -302,66 +302,6 @@ describe("SkeletonQueryWizard", () => {
302302
});
303303
});
304304

305-
describe("getFirstStoragePath", () => {
306-
it("should return the first workspace folder", async () => {
307-
jest.spyOn(workspace, "workspaceFolders", "get").mockReturnValue([
308-
{
309-
name: "codespaces-codeql",
310-
uri: { fsPath: "codespaces-codeql" },
311-
},
312-
] as WorkspaceFolder[]);
313-
314-
wizard = new SkeletonQueryWizard(
315-
mockCli,
316-
jest.fn(),
317-
credentials,
318-
extLogger,
319-
mockDatabaseManager,
320-
token,
321-
storagePath,
322-
);
323-
324-
expect(wizard.getFirstStoragePath()).toEqual("codespaces-codeql");
325-
});
326-
327-
describe("if user is in vscode-codeql-starter workspace", () => {
328-
it("should set storage path to parent folder", async () => {
329-
jest.spyOn(workspace, "workspaceFolders", "get").mockReturnValue([
330-
{
331-
name: "codeql-custom-queries-cpp",
332-
uri: {
333-
fsPath: join(
334-
"vscode-codeql-starter",
335-
"codeql-custom-queries-cpp",
336-
),
337-
},
338-
},
339-
{
340-
name: "codeql-custom-queries-csharp",
341-
uri: {
342-
fsPath: join(
343-
"vscode-codeql-starter",
344-
"codeql-custom-queries-csharp",
345-
),
346-
},
347-
},
348-
] as WorkspaceFolder[]);
349-
350-
wizard = new SkeletonQueryWizard(
351-
mockCli,
352-
jest.fn(),
353-
credentials,
354-
extLogger,
355-
mockDatabaseManager,
356-
token,
357-
storagePath,
358-
);
359-
360-
expect(wizard.getFirstStoragePath()).toEqual("vscode-codeql-starter");
361-
});
362-
});
363-
});
364-
365305
describe("findDatabaseItemByNwo", () => {
366306
describe("when the item exists", () => {
367307
it("should return the database item", async () => {

extensions/ql-vscode/test/vscode-tests/minimal-workspace/local-databases.test.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -687,6 +687,22 @@ describe("local databases", () => {
687687
);
688688
});
689689
});
690+
691+
describe("when the QL pack already exists", () => {
692+
beforeEach(() => {
693+
fs.mkdirSync(join(dir.name, `codeql-custom-queries-${language}`));
694+
});
695+
696+
it("should exit early", async () => {
697+
showBinaryChoiceDialogSpy = jest
698+
.spyOn(helpers, "showBinaryChoiceDialog")
699+
.mockResolvedValue(false);
700+
701+
await (databaseManager as any).createSkeletonPacks(mockDbItem);
702+
703+
expect(generateSpy).not.toBeCalled();
704+
});
705+
});
690706
});
691707

692708
describe("openDatabase", () => {

extensions/ql-vscode/test/vscode-tests/no-workspace/helpers.test.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import {
2626
import { DirResult } from "tmp";
2727

2828
import {
29+
getFirstWorkspaceFolder,
2930
getInitialQueryContents,
3031
InvocationRateLimiter,
3132
isFolderAlreadyInWorkspace,
@@ -678,3 +679,42 @@ describe("prepareCodeTour", () => {
678679
});
679680
});
680681
});
682+
683+
describe("getFirstWorkspaceFolder", () => {
684+
it("should return the first workspace folder", async () => {
685+
jest.spyOn(workspace, "workspaceFolders", "get").mockReturnValue([
686+
{
687+
name: "codespaces-codeql",
688+
uri: { fsPath: "codespaces-codeql", scheme: "file" },
689+
},
690+
] as WorkspaceFolder[]);
691+
692+
expect(getFirstWorkspaceFolder()).toEqual("codespaces-codeql");
693+
});
694+
695+
describe("if user is in vscode-codeql-starter workspace", () => {
696+
it("should set storage path to parent folder", async () => {
697+
jest.spyOn(workspace, "workspaceFolders", "get").mockReturnValue([
698+
{
699+
name: "codeql-custom-queries-cpp",
700+
uri: {
701+
fsPath: join("vscode-codeql-starter", "codeql-custom-queries-cpp"),
702+
scheme: "file",
703+
},
704+
},
705+
{
706+
name: "codeql-custom-queries-csharp",
707+
uri: {
708+
fsPath: join(
709+
"vscode-codeql-starter",
710+
"codeql-custom-queries-csharp",
711+
),
712+
scheme: "file",
713+
},
714+
},
715+
] as WorkspaceFolder[]);
716+
717+
expect(getFirstWorkspaceFolder()).toEqual("vscode-codeql-starter");
718+
});
719+
});
720+
});

0 commit comments

Comments
 (0)