Skip to content

Commit a48b1f8

Browse files
Merge pull request #2256 from github/elena/yer-a-lizard-query
Improvements to skeleton query flow
2 parents f377bb9 + f8b0eca commit a48b1f8

File tree

4 files changed

+98
-22
lines changed

4 files changed

+98
-22
lines changed

extensions/ql-vscode/src/databaseFetcher.ts

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import fetch, { Response } from "node-fetch";
22
import { zip } from "zip-a-folder";
33
import { Open } from "unzipper";
4-
import { Uri, CancellationToken, window } from "vscode";
4+
import { Uri, CancellationToken, window, InputBoxOptions } from "vscode";
55
import { CodeQLCliServer } from "./cli";
66
import {
77
ensureDir,
@@ -92,17 +92,7 @@ export async function promptImportGithubDatabase(
9292
token: CancellationToken,
9393
cli?: CodeQLCliServer,
9494
): Promise<DatabaseItem | undefined> {
95-
progress({
96-
message: "Choose repository",
97-
step: 1,
98-
maxStep: 2,
99-
});
100-
const githubRepo = await window.showInputBox({
101-
title:
102-
'Enter a GitHub repository URL or "name with owner" (e.g. https://github.com/github/codeql or github/codeql)',
103-
placeHolder: "https://github.com/<owner>/<repo> or <owner>/<repo>",
104-
ignoreFocusOut: true,
105-
});
95+
const githubRepo = await askForGitHubRepo(progress);
10696
if (!githubRepo) {
10797
return;
10898
}
@@ -128,6 +118,30 @@ export async function promptImportGithubDatabase(
128118
return;
129119
}
130120

121+
export async function askForGitHubRepo(
122+
progress?: ProgressCallback,
123+
suggestedValue?: string,
124+
): Promise<string | undefined> {
125+
progress?.({
126+
message: "Choose repository",
127+
step: 1,
128+
maxStep: 2,
129+
});
130+
131+
const options: InputBoxOptions = {
132+
title:
133+
'Enter a GitHub repository URL or "name with owner" (e.g. https://github.com/github/codeql or github/codeql)',
134+
placeHolder: "https://github.com/<owner>/<repo> or <owner>/<repo>",
135+
ignoreFocusOut: true,
136+
};
137+
138+
if (suggestedValue) {
139+
options.value = suggestedValue;
140+
}
141+
142+
return await window.showInputBox(options);
143+
}
144+
131145
/**
132146
* Downloads a database from GitHub
133147
*

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -911,6 +911,17 @@ export class DatabaseManager extends DisposableObject {
911911
return dbs[0];
912912
}
913913

914+
public async digForDatabaseWithSameLanguage(
915+
language: string,
916+
): Promise<DatabaseItem | undefined> {
917+
const dbItems = this.databaseItems || [];
918+
const dbs = dbItems.filter((db) => db.language === language);
919+
if (dbs.length === 0) {
920+
return undefined;
921+
}
922+
return dbs[0];
923+
}
924+
914925
/**
915926
* Returns the index of the workspace folder that corresponds to the source archive of `item`
916927
* if there is one, and -1 otherwise.

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

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { getErrorMessage } from "./pure/helpers-pure";
99
import { QlPackGenerator } from "./qlpack-generator";
1010
import { DatabaseManager } from "./local-databases";
1111
import * as databaseFetcher from "./databaseFetcher";
12-
import { ProgressCallback } from "./progress";
12+
import { ProgressCallback, UserCancellationException } from "./progress";
1313

1414
type QueryLanguagesToDatabaseMap = Record<string, string>;
1515

@@ -207,9 +207,17 @@ export class SkeletonQueryWizard {
207207
});
208208

209209
const githubRepoNwo = QUERY_LANGUAGE_TO_DATABASE_REPO[this.language];
210+
const chosenRepo = await databaseFetcher.askForGitHubRepo(
211+
undefined,
212+
githubRepoNwo,
213+
);
214+
215+
if (!chosenRepo) {
216+
throw new UserCancellationException("No GitHub repository provided");
217+
}
210218

211219
await databaseFetcher.downloadGitHubDatabase(
212-
githubRepoNwo,
220+
chosenRepo,
213221
this.databaseManager,
214222
this.storagePath,
215223
this.credentials,
@@ -231,17 +239,30 @@ export class SkeletonQueryWizard {
231239

232240
const databaseNwo = QUERY_LANGUAGE_TO_DATABASE_REPO[this.language];
233241

234-
const databaseItem = await this.databaseManager.digForDatabaseItem(
242+
// Check that we haven't already downloaded a database for this language
243+
const existingDatabaseItem = await this.databaseManager.digForDatabaseItem(
235244
this.language,
236245
databaseNwo,
237246
);
238247

239-
if (databaseItem) {
248+
if (existingDatabaseItem) {
240249
// select the found database
241-
await this.databaseManager.setCurrentDatabaseItem(databaseItem);
250+
await this.databaseManager.setCurrentDatabaseItem(existingDatabaseItem);
242251
} else {
243-
// download new database and select it
244-
await this.downloadDatabase();
252+
const sameLanguageDatabaseItem =
253+
await this.databaseManager.digForDatabaseWithSameLanguage(
254+
this.language,
255+
);
256+
257+
if (sameLanguageDatabaseItem) {
258+
// select the found database
259+
await this.databaseManager.setCurrentDatabaseItem(
260+
sameLanguageDatabaseItem,
261+
);
262+
} else {
263+
// download new database and select it
264+
await this.downloadDatabase();
265+
}
245266
}
246267
}
247268
}

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

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ describe("SkeletonQueryWizard", () => {
3232
let downloadGitHubDatabaseSpy: jest.SpiedFunction<
3333
typeof databaseFetcher.downloadGitHubDatabase
3434
>;
35+
let askForGitHubRepoSpy: jest.SpiedFunction<
36+
typeof databaseFetcher.askForGitHubRepo
37+
>;
3538
let openTextDocumentSpy: jest.SpiedFunction<
3639
typeof workspace.openTextDocument
3740
>;
@@ -42,6 +45,7 @@ describe("SkeletonQueryWizard", () => {
4245
const mockDatabaseManager = mockedObject<DatabaseManager>({
4346
setCurrentDatabaseItem: jest.fn(),
4447
digForDatabaseItem: jest.fn(),
48+
digForDatabaseWithSameLanguage: jest.fn(),
4549
});
4650
const mockCli = mockedObject<CodeQLCliServer>({
4751
resolveLanguages: jest
@@ -58,6 +62,8 @@ describe("SkeletonQueryWizard", () => {
5862
getSupportedLanguages: jest.fn(),
5963
});
6064

65+
jest.spyOn(extLogger, "log").mockResolvedValue(undefined);
66+
6167
beforeEach(async () => {
6268
dir = tmp.dirSync({
6369
prefix: "skeleton_query_wizard_",
@@ -101,6 +107,10 @@ describe("SkeletonQueryWizard", () => {
101107
mockDatabaseManager,
102108
token,
103109
);
110+
111+
askForGitHubRepoSpy = jest
112+
.spyOn(databaseFetcher, "askForGitHubRepo")
113+
.mockResolvedValue(QUERY_LANGUAGE_TO_DATABASE_REPO[chosenLanguage]);
104114
});
105115

106116
afterEach(async () => {
@@ -250,10 +260,30 @@ describe("SkeletonQueryWizard", () => {
250260
.mockResolvedValue(undefined);
251261
});
252262

253-
it("should download a new database for language", async () => {
254-
await wizard.execute();
263+
describe("if the user choses to downloaded the suggested database from GitHub", () => {
264+
it("should download a new database for language", async () => {
265+
await wizard.execute();
266+
267+
expect(askForGitHubRepoSpy).toHaveBeenCalled();
268+
expect(downloadGitHubDatabaseSpy).toHaveBeenCalled();
269+
});
270+
});
271+
272+
describe("if the user choses to download a different database from GitHub than the one suggested", () => {
273+
beforeEach(() => {
274+
const chosenGitHubRepo = "pickles-owner/pickles-repo";
275+
276+
askForGitHubRepoSpy = jest
277+
.spyOn(databaseFetcher, "askForGitHubRepo")
278+
.mockResolvedValue(chosenGitHubRepo);
279+
});
280+
281+
it("should download the newly chosen database", async () => {
282+
await wizard.execute();
255283

256-
expect(downloadGitHubDatabaseSpy).toHaveBeenCalled();
284+
expect(askForGitHubRepoSpy).toHaveBeenCalled();
285+
expect(downloadGitHubDatabaseSpy).toHaveBeenCalled();
286+
});
257287
});
258288
});
259289
});

0 commit comments

Comments
 (0)