Skip to content

Commit f4a866b

Browse files
authored
Add logic to trigger model evaluation run (#3397)
1 parent a62522e commit f4a866b

File tree

7 files changed

+117
-27
lines changed

7 files changed

+117
-27
lines changed

extensions/ql-vscode/src/extension.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -977,6 +977,7 @@ async function activateWithInstalledDistribution(
977977
const modelEditorModule = await ModelEditorModule.initialize(
978978
app,
979979
dbm,
980+
variantAnalysisManager,
980981
cliServer,
981982
qs,
982983
tmpDir.name,

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import { getModelsAsDataLanguage } from "./languages";
3131
import { INITIAL_MODE } from "./shared/mode";
3232
import { isSupportedLanguage } from "./supported-languages";
3333
import { DefaultNotifier, checkConsistency } from "./consistency-check";
34+
import type { VariantAnalysisManager } from "../variant-analysis/variant-analysis-manager";
3435

3536
export class ModelEditorModule extends DisposableObject {
3637
private readonly queryStorageDir: string;
@@ -43,6 +44,7 @@ export class ModelEditorModule extends DisposableObject {
4344
private constructor(
4445
private readonly app: App,
4546
private readonly databaseManager: DatabaseManager,
47+
private readonly variantAnalysisManager: VariantAnalysisManager,
4648
private readonly cliServer: CodeQLCliServer,
4749
private readonly queryRunner: QueryRunner,
4850
baseQueryStorageDir: string,
@@ -65,13 +67,15 @@ export class ModelEditorModule extends DisposableObject {
6567
public static async initialize(
6668
app: App,
6769
databaseManager: DatabaseManager,
70+
variantAnalysisManager: VariantAnalysisManager,
6871
cliServer: CodeQLCliServer,
6972
queryRunner: QueryRunner,
7073
queryStorageDir: string,
7174
): Promise<ModelEditorModule> {
7275
const modelEditorModule = new ModelEditorModule(
7376
app,
7477
databaseManager,
78+
variantAnalysisManager,
7579
cliServer,
7680
queryRunner,
7781
queryStorageDir,
@@ -240,6 +244,7 @@ export class ModelEditorModule extends DisposableObject {
240244
this.modelingEvents,
241245
this.modelConfig,
242246
this.databaseManager,
247+
this.variantAnalysisManager,
243248
this.cliServer,
244249
this.queryRunner,
245250
this.queryStorageDir,

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ import { runSuggestionsQuery } from "./suggestion-queries";
5959
import { parseAccessPathSuggestionRowsToOptions } from "./suggestions-bqrs";
6060
import { ModelEvaluator } from "./model-evaluator";
6161
import type { ModelEvaluationRunState } from "./shared/model-evaluation-run-state";
62+
import type { VariantAnalysisManager } from "../variant-analysis/variant-analysis-manager";
6263

6364
export class ModelEditorView extends AbstractWebview<
6465
ToModelEditorMessage,
@@ -77,6 +78,7 @@ export class ModelEditorView extends AbstractWebview<
7778
private readonly modelingEvents: ModelingEvents,
7879
private readonly modelConfig: ModelConfigListener,
7980
private readonly databaseManager: DatabaseManager,
81+
private readonly variantAnalysisManager: VariantAnalysisManager,
8082
private readonly cliServer: CodeQLCliServer,
8183
private readonly queryRunner: QueryRunner,
8284
private readonly queryStorageDir: string,
@@ -115,9 +117,13 @@ export class ModelEditorView extends AbstractWebview<
115117
this.languageDefinition = getModelsAsDataLanguage(language);
116118

117119
this.modelEvaluator = new ModelEvaluator(
120+
this.app.logger,
121+
this.cliServer,
118122
modelingStore,
119123
modelingEvents,
124+
this.variantAnalysisManager,
120125
databaseItem,
126+
language,
121127
this.updateModelEvaluationRun.bind(this),
122128
);
123129
this.push(this.modelEvaluator);
@@ -801,6 +807,7 @@ export class ModelEditorView extends AbstractWebview<
801807
this.modelingEvents,
802808
this.modelConfig,
803809
this.databaseManager,
810+
this.variantAnalysisManager,
804811
this.cliServer,
805812
this.queryRunner,
806813
this.queryStorageDir,

extensions/ql-vscode/src/model-editor/model-evaluator.ts

Lines changed: 96 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,24 @@ import type { ModelingEvents } from "./modeling-events";
33
import type { DatabaseItem } from "../databases/local-databases";
44
import type { ModelEvaluationRun } from "./model-evaluation-run";
55
import { DisposableObject } from "../common/disposable-object";
6-
import { sleep } from "../common/time";
76
import type { ModelEvaluationRunState } from "./shared/model-evaluation-run-state";
7+
import type { BaseLogger } from "../common/logging";
8+
import type { CodeQLCliServer } from "../codeql-cli/cli";
9+
import type { VariantAnalysisManager } from "../variant-analysis/variant-analysis-manager";
10+
import type { QueryLanguage } from "../common/query-language";
11+
import { resolveCodeScanningQueryPack } from "../variant-analysis/code-scanning-pack";
12+
import { withProgress } from "../common/vscode/progress";
13+
import type { VariantAnalysis } from "../variant-analysis/shared/variant-analysis";
814

915
export class ModelEvaluator extends DisposableObject {
1016
public constructor(
17+
private readonly logger: BaseLogger,
18+
private readonly cliServer: CodeQLCliServer,
1119
private readonly modelingStore: ModelingStore,
1220
private readonly modelingEvents: ModelingEvents,
21+
private readonly variantAnalysisManager: VariantAnalysisManager,
1322
private readonly dbItem: DatabaseItem,
23+
private readonly language: QueryLanguage,
1424
private readonly updateView: (
1525
run: ModelEvaluationRunState,
1626
) => Promise<void>,
@@ -28,18 +38,48 @@ export class ModelEvaluator extends DisposableObject {
2838
};
2939
this.modelingStore.updateModelEvaluationRun(this.dbItem, evaluationRun);
3040

31-
// For now, just wait 5 seconds and then update the store.
32-
// In the future, this will be replaced with the actual evaluation process.
33-
void sleep(5000).then(() => {
34-
const completedEvaluationRun: ModelEvaluationRun = {
35-
isPreparing: false,
36-
variantAnalysisId: undefined,
37-
};
38-
this.modelingStore.updateModelEvaluationRun(
39-
this.dbItem,
40-
completedEvaluationRun,
41-
);
42-
});
41+
// Build pack
42+
const qlPack = await resolveCodeScanningQueryPack(
43+
this.logger,
44+
this.cliServer,
45+
this.language,
46+
);
47+
48+
if (!qlPack) {
49+
this.modelingStore.updateModelEvaluationRun(this.dbItem, undefined);
50+
throw new Error("Unable to trigger evaluation run");
51+
}
52+
53+
// Submit variant analysis and monitor progress
54+
return withProgress(
55+
async (progress, token) => {
56+
let variantAnalysisId: number | undefined = undefined;
57+
try {
58+
variantAnalysisId =
59+
await this.variantAnalysisManager.runVariantAnalysis(
60+
qlPack,
61+
progress,
62+
token,
63+
);
64+
} catch (e) {
65+
this.modelingStore.updateModelEvaluationRun(this.dbItem, undefined);
66+
throw e;
67+
}
68+
69+
if (variantAnalysisId) {
70+
this.monitorVariantAnalysis(variantAnalysisId);
71+
} else {
72+
this.modelingStore.updateModelEvaluationRun(this.dbItem, undefined);
73+
throw new Error(
74+
"Unable to trigger variant analysis for evaluation run",
75+
);
76+
}
77+
},
78+
{
79+
title: "Run Variant Analysis",
80+
cancellable: true,
81+
},
82+
);
4383
}
4484

4585
public async stopEvaluation() {
@@ -55,19 +95,51 @@ export class ModelEvaluator extends DisposableObject {
5595
private registerToModelingEvents() {
5696
this.push(
5797
this.modelingEvents.onModelEvaluationRunChanged(async (event) => {
58-
if (
59-
event.evaluationRun &&
60-
event.dbUri === this.dbItem.databaseUri.toString()
61-
) {
62-
const run: ModelEvaluationRunState = {
63-
isPreparing: event.evaluationRun.isPreparing,
64-
65-
// TODO: Get variant analysis from id.
66-
variantAnalysis: undefined,
67-
};
68-
await this.updateView(run);
98+
if (event.dbUri === this.dbItem.databaseUri.toString()) {
99+
if (!event.evaluationRun) {
100+
await this.updateView({
101+
isPreparing: false,
102+
variantAnalysis: undefined,
103+
});
104+
} else {
105+
const variantAnalysis = await this.getVariantAnalysisForRun(
106+
event.evaluationRun,
107+
);
108+
const run: ModelEvaluationRunState = {
109+
isPreparing: event.evaluationRun.isPreparing,
110+
variantAnalysis,
111+
};
112+
await this.updateView(run);
113+
}
69114
}
70115
}),
71116
);
72117
}
118+
119+
private async getVariantAnalysisForRun(
120+
evaluationRun: ModelEvaluationRun,
121+
): Promise<VariantAnalysis | undefined> {
122+
if (evaluationRun.variantAnalysisId) {
123+
return await this.variantAnalysisManager.getVariantAnalysis(
124+
evaluationRun.variantAnalysisId,
125+
);
126+
}
127+
return undefined;
128+
}
129+
130+
private monitorVariantAnalysis(variantAnalysisId: number) {
131+
this.push(
132+
this.variantAnalysisManager.onVariantAnalysisStatusUpdated(
133+
async (variantAnalysis) => {
134+
// Make sure it's the variant analysis we're interested in
135+
if (variantAnalysisId === variantAnalysis.id) {
136+
await this.updateView({
137+
isPreparing: false,
138+
variantAnalysis,
139+
});
140+
}
141+
},
142+
),
143+
);
144+
}
73145
}

extensions/ql-vscode/src/model-editor/modeling-store.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,7 @@ export class ModelingStore extends DisposableObject {
378378

379379
public updateModelEvaluationRun(
380380
dbItem: DatabaseItem,
381-
evaluationRun: ModelEvaluationRun,
381+
evaluationRun: ModelEvaluationRun | undefined,
382382
) {
383383
this.changeModelEvaluationRun(dbItem, (state) => {
384384
state.modelEvaluationRun = evaluationRun;

extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ export class VariantAnalysisManager
298298
qlPackDetails: QlPackDetails,
299299
progress: ProgressCallback,
300300
token: CancellationToken,
301-
): Promise<void> {
301+
): Promise<number | undefined> {
302302
await saveBeforeStart();
303303

304304
progress({
@@ -379,7 +379,7 @@ export class VariantAnalysisManager
379379
} catch (e: unknown) {
380380
// If the error is handled by the handleRequestError function, we don't need to throw
381381
if (e instanceof RequestError && handleRequestError(e, this.app.logger)) {
382-
return;
382+
return undefined;
383383
}
384384

385385
throw e;
@@ -405,6 +405,8 @@ export class VariantAnalysisManager
405405
"codeQL.monitorNewVariantAnalysis",
406406
processedVariantAnalysis,
407407
);
408+
409+
return processedVariantAnalysis.id;
408410
}
409411

410412
public async rehydrateVariantAnalysis(variantAnalysis: VariantAnalysis) {

extensions/ql-vscode/test/vscode-tests/no-workspace/model-editor/model-editor-view.test.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { createMockModelingStore } from "../../../__mocks__/model-editor/modelin
1212
import type { ModelConfigListener } from "../../../../src/config";
1313
import { createMockModelingEvents } from "../../../__mocks__/model-editor/modelingEventsMock";
1414
import { QueryLanguage } from "../../../../src/common/query-language";
15+
import type { VariantAnalysisManager } from "../../../../src/variant-analysis/variant-analysis-manager";
1516

1617
describe("ModelEditorView", () => {
1718
const app = createMockApp({});
@@ -21,6 +22,7 @@ describe("ModelEditorView", () => {
2122
onDidChangeConfiguration: jest.fn(),
2223
});
2324
const databaseManager = mockEmptyDatabaseManager();
25+
const variantAnalysisManager = mockedObject<VariantAnalysisManager>({});
2426
const cliServer = mockedObject<CodeQLCliServer>({});
2527
const queryRunner = mockedObject<QueryRunner>({});
2628
const queryStorageDir = "/a/b/c/d";
@@ -48,6 +50,7 @@ describe("ModelEditorView", () => {
4850
modelingEvents,
4951
modelConfig,
5052
databaseManager,
53+
variantAnalysisManager,
5154
cliServer,
5255
queryRunner,
5356
queryStorageDir,

0 commit comments

Comments
 (0)