Skip to content

Commit 80ae9a4

Browse files
authored
Merge pull request #2658 from github/nora-koen/data-extensions-editor-without-ql-submodule
Remove submodules dependency from data extension editor
2 parents 1289ab5 + 868fae0 commit 80ae9a4

File tree

7 files changed

+339
-229
lines changed

7 files changed

+339
-229
lines changed

extensions/ql-vscode/src/data-extensions-editor/auto-model-usages-query.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,14 @@ import { QueryRunner } from "../query-server";
66
import { DatabaseItem } from "../databases/local-databases";
77
import { interpretResultsSarif } from "../query-results";
88
import { ProgressCallback } from "../common/vscode/progress";
9+
import { Mode } from "./shared/mode";
910

1011
type Options = {
1112
cliServer: CodeQLCliServer;
1213
queryRunner: QueryRunner;
1314
databaseItem: DatabaseItem;
1415
queryStorageDir: string;
16+
queryDir: string;
1517

1618
progress: ProgressCallback;
1719
};
@@ -23,6 +25,7 @@ export async function getAutoModelUsages({
2325
queryRunner,
2426
databaseItem,
2527
queryStorageDir,
28+
queryDir,
2629
progress,
2730
}: Options): Promise<UsageSnippetsBySignature> {
2831
const maxStep = 1500;
@@ -32,11 +35,12 @@ export async function getAutoModelUsages({
3235
// This will re-run the query that was already run when opening the data extensions editor. This
3336
// might be unnecessary, but this makes it really easy to get the path to the BQRS file which we
3437
// need to interpret the results.
35-
const queryResult = await runQuery("applicationModeQuery", {
38+
const queryResult = await runQuery(Mode.Application, {
3639
cliServer,
3740
queryRunner,
3841
queryStorageDir,
3942
databaseItem,
43+
queryDir,
4044
progress: (update) =>
4145
progress({
4246
maxStep,

extensions/ql-vscode/src/data-extensions-editor/data-extensions-editor-module.ts

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,17 @@ import { join } from "path";
99
import { App } from "../common/app";
1010
import { withProgress } from "../common/vscode/progress";
1111
import { pickExtensionPack } from "./extension-pack-picker";
12-
import { showAndLogErrorMessage } from "../common/logging";
12+
import {
13+
showAndLogErrorMessage,
14+
showAndLogExceptionWithTelemetry,
15+
} from "../common/logging";
16+
import { dir } from "tmp-promise";
17+
import { fetchExternalApiQueries } from "./queries";
18+
import { telemetryListener } from "../common/vscode/telemetry";
19+
import { redactableError } from "../common/errors";
20+
import { extLogger } from "../common/logging/vscode";
21+
import { isQueryLanguage } from "../common/query-language";
22+
import { setUpPack } from "./external-api-usage-query";
1323

1424
const SUPPORTED_LANGUAGES: string[] = ["java", "csharp"];
1525

@@ -60,10 +70,14 @@ export class DataExtensionsEditorModule {
6070
return;
6171
}
6272

63-
if (!SUPPORTED_LANGUAGES.includes(db.language)) {
73+
const language = db.language;
74+
if (
75+
!SUPPORTED_LANGUAGES.includes(language) ||
76+
!isQueryLanguage(language)
77+
) {
6478
void showAndLogErrorMessage(
6579
this.app.logger,
66-
`The data extensions editor is not supported for ${db.language} databases.`,
80+
`The data extensions editor is not supported for ${language} databases.`,
6781
);
6882
return;
6983
}
@@ -99,13 +113,29 @@ export class DataExtensionsEditorModule {
99113
return;
100114
}
101115

116+
const query = fetchExternalApiQueries[language];
117+
if (!query) {
118+
void showAndLogExceptionWithTelemetry(
119+
extLogger,
120+
telemetryListener,
121+
redactableError`No external API usage query found for language ${language}`,
122+
);
123+
return;
124+
}
125+
126+
// Create new temporary directory for query files and pack dependencies
127+
const queryDir = (await dir({ unsafeCleanup: true })).path;
128+
await setUpPack(queryDir, query, language);
129+
await this.cliServer.packInstall(queryDir);
130+
102131
const view = new DataExtensionsEditorView(
103132
this.ctx,
104133
this.app,
105134
this.databaseManager,
106135
this.cliServer,
107136
this.queryRunner,
108137
this.queryStorageDir,
138+
queryDir,
109139
db,
110140
modelFile,
111141
);

extensions/ql-vscode/src/data-extensions-editor/data-extensions-editor-view.ts

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ export class DataExtensionsEditorView extends AbstractWebview<
7171
private readonly cliServer: CodeQLCliServer,
7272
private readonly queryRunner: QueryRunner,
7373
private readonly queryStorageDir: string,
74+
private readonly queryDir: string,
7475
private readonly databaseItem: DatabaseItem,
7576
private readonly extensionPack: ExtensionPack,
7677
private mode: Mode = Mode.Application,
@@ -248,19 +249,15 @@ export class DataExtensionsEditorView extends AbstractWebview<
248249
async (progress) => {
249250
try {
250251
const cancellationTokenSource = new CancellationTokenSource();
251-
const queryResult = await runQuery(
252-
this.mode === Mode.Framework
253-
? "frameworkModeQuery"
254-
: "applicationModeQuery",
255-
{
256-
cliServer: this.cliServer,
257-
queryRunner: this.queryRunner,
258-
databaseItem: this.databaseItem,
259-
queryStorageDir: this.queryStorageDir,
260-
progress: (update) => progress({ ...update, maxStep: 1500 }),
261-
token: cancellationTokenSource.token,
262-
},
263-
);
252+
const queryResult = await runQuery(this.mode, {
253+
cliServer: this.cliServer,
254+
queryRunner: this.queryRunner,
255+
databaseItem: this.databaseItem,
256+
queryStorageDir: this.queryStorageDir,
257+
queryDir: this.queryDir,
258+
progress: (update) => progress({ ...update, maxStep: 1500 }),
259+
token: cancellationTokenSource.token,
260+
});
264261
if (!queryResult) {
265262
return;
266263
}
@@ -432,6 +429,7 @@ export class DataExtensionsEditorView extends AbstractWebview<
432429
cliServer: this.cliServer,
433430
queryRunner: this.queryRunner,
434431
queryStorageDir: this.queryStorageDir,
432+
queryDir: this.queryDir,
435433
databaseItem: this.databaseItem,
436434
progress: (update) => progress({ ...update, maxStep }),
437435
});
@@ -512,6 +510,7 @@ export class DataExtensionsEditorView extends AbstractWebview<
512510
this.cliServer,
513511
this.queryRunner,
514512
this.queryStorageDir,
513+
this.queryDir,
515514
addedDatabase,
516515
modelFile,
517516
Mode.Framework,

extensions/ql-vscode/src/data-extensions-editor/extension-pack-picker.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ export async function pickExtensionPack(
4343

4444
// Get all existing extension packs in the workspace
4545
const additionalPacks = getOnDiskWorkspaceFolders();
46+
// the CLI doesn't check packs in the .github folder, so we need to add it manually
47+
if (additionalPacks.length === 1) {
48+
additionalPacks.push(`${additionalPacks[0]}/.github`);
49+
}
4650
const extensionPacksInfo = await cliServer.resolveQlpacks(
4751
additionalPacks,
4852
true,

extensions/ql-vscode/src/data-extensions-editor/external-api-usage-query.ts

Lines changed: 43 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,44 @@
11
import { CoreCompletedQuery, QueryRunner } from "../query-server";
2-
import { dir } from "tmp-promise";
3-
import { writeFile } from "fs-extra";
4-
import { dump as dumpYaml } from "js-yaml";
52
import { getOnDiskWorkspaceFolders } from "../common/vscode/workspace-folders";
63
import { extLogger } from "../common/logging/vscode";
74
import { showAndLogExceptionWithTelemetry, TeeLogger } from "../common/logging";
8-
import { isQueryLanguage } from "../common/query-language";
95
import { CancellationToken } from "vscode";
106
import { CodeQLCliServer } from "../codeql-cli/cli";
117
import { DatabaseItem } from "../databases/local-databases";
128
import { ProgressCallback } from "../common/vscode/progress";
13-
import { fetchExternalApiQueries } from "./queries";
149
import { QueryResultType } from "../query-server/new-messages";
15-
import { join } from "path";
1610
import { redactableError } from "../common/errors";
1711
import { telemetryListener } from "../common/vscode/telemetry";
12+
import { join } from "path";
13+
import { Mode } from "./shared/mode";
14+
import { writeFile } from "fs-extra";
1815
import { Query } from "./queries/query";
16+
import { QueryLanguage } from "../common/query-language";
17+
import { dump } from "js-yaml";
1918

2019
type RunQueryOptions = {
2120
cliServer: Pick<CodeQLCliServer, "resolveQlpacks">;
2221
queryRunner: Pick<QueryRunner, "createQueryRun" | "logger">;
2322
databaseItem: Pick<DatabaseItem, "contents" | "databaseUri" | "language">;
2423
queryStorageDir: string;
24+
queryDir: string;
2525

2626
progress: ProgressCallback;
2727
token: CancellationToken;
2828
};
2929

30-
export async function runQuery(
31-
queryName: keyof Omit<Query, "dependencies">,
32-
{
33-
cliServer,
34-
queryRunner,
35-
databaseItem,
36-
queryStorageDir,
37-
progress,
38-
token,
39-
}: RunQueryOptions,
40-
): Promise<CoreCompletedQuery | undefined> {
41-
// The below code is temporary to allow for rapid prototyping of the queries. Once the queries are stabilized, we will
42-
// move these queries into the `github/codeql` repository and use them like any other contextual (e.g. AST) queries.
43-
// This is intentionally not pretty code, as it will be removed soon.
44-
// For a reference of what this should do in the future, see the previous implementation in
45-
// https://github.com/github/vscode-codeql/blob/089d3566ef0bc67d9b7cc66e8fd6740b31c1c0b0/extensions/ql-vscode/src/data-extensions-editor/external-api-usage-query.ts#L33-L72
46-
47-
if (!isQueryLanguage(databaseItem.language)) {
48-
void showAndLogExceptionWithTelemetry(
49-
extLogger,
50-
telemetryListener,
51-
redactableError`Unsupported database language ${databaseItem.language}`,
52-
);
53-
return;
54-
}
55-
56-
const query = fetchExternalApiQueries[databaseItem.language];
57-
if (!query) {
58-
void showAndLogExceptionWithTelemetry(
59-
extLogger,
60-
telemetryListener,
61-
redactableError`No external API usage query found for language ${databaseItem.language}`,
30+
export async function setUpPack(
31+
queryDir: string,
32+
query: Query,
33+
language: QueryLanguage,
34+
) {
35+
Object.values(Mode).map(async (mode) => {
36+
const queryFile = join(
37+
queryDir,
38+
`FetchExternalApis${mode.charAt(0).toUpperCase() + mode.slice(1)}Mode.ql`,
6239
);
63-
return;
64-
}
65-
66-
const queryDir = (await dir({ unsafeCleanup: true })).path;
67-
const queryFile = join(queryDir, "FetchExternalApis.ql");
68-
await writeFile(queryFile, query[queryName], "utf8");
40+
await writeFile(queryFile, query[`${mode}ModeQuery`], "utf8");
41+
});
6942

7043
if (query.dependencies) {
7144
for (const [filename, contents] of Object.entries(query.dependencies)) {
@@ -78,18 +51,42 @@ export async function runQuery(
7851
name: "codeql/external-api-usage",
7952
version: "0.0.0",
8053
dependencies: {
81-
[`codeql/${databaseItem.language}-all`]: "*",
54+
[`codeql/${language}-all`]: "*",
8255
},
8356
};
8457

8558
const qlpackFile = join(queryDir, "codeql-pack.yml");
86-
await writeFile(qlpackFile, dumpYaml(syntheticQueryPack), "utf8");
59+
await writeFile(qlpackFile, dump(syntheticQueryPack), "utf8");
60+
}
61+
62+
export async function runQuery(
63+
mode: Mode,
64+
{
65+
cliServer,
66+
queryRunner,
67+
databaseItem,
68+
queryStorageDir,
69+
queryDir,
70+
progress,
71+
token,
72+
}: RunQueryOptions,
73+
): Promise<CoreCompletedQuery | undefined> {
74+
// The below code is temporary to allow for rapid prototyping of the queries. Once the queries are stabilized, we will
75+
// move these queries into the `github/codeql` repository and use them like any other contextual (e.g. AST) queries.
76+
// This is intentionally not pretty code, as it will be removed soon.
77+
// For a reference of what this should do in the future, see the previous implementation in
78+
// https://github.com/github/vscode-codeql/blob/089d3566ef0bc67d9b7cc66e8fd6740b31c1c0b0/extensions/ql-vscode/src/data-extensions-editor/external-api-usage-query.ts#L33-L72
8779

8880
const additionalPacks = getOnDiskWorkspaceFolders();
8981
const extensionPacks = Object.keys(
9082
await cliServer.resolveQlpacks(additionalPacks, true),
9183
);
9284

85+
const queryFile = join(
86+
queryDir,
87+
`FetchExternalApis${mode.charAt(0).toUpperCase() + mode.slice(1)}Mode.ql`,
88+
);
89+
9390
const queryRun = queryRunner.createQueryRun(
9491
databaseItem.databaseUri.fsPath,
9592
{

extensions/ql-vscode/test/vscode-tests/no-workspace/data-extensions-editor/extension-pack-picker.test.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,10 @@ describe("pickExtensionPack", () => {
9999
name: "codeql-custom-queries-java",
100100
index: 0,
101101
};
102-
additionalPacks = [Uri.file(tmpDir).fsPath];
102+
additionalPacks = [
103+
Uri.file(tmpDir).fsPath,
104+
`${Uri.file(tmpDir).fsPath}/.github`,
105+
];
103106
workspaceFoldersSpy = jest
104107
.spyOn(workspace, "workspaceFolders", "get")
105108
.mockReturnValue([workspaceFolder]);

0 commit comments

Comments
 (0)