Add logic to trigger model evaluation run (#3397)
This commit is contained in:
@@ -977,6 +977,7 @@ async function activateWithInstalledDistribution(
|
||||
const modelEditorModule = await ModelEditorModule.initialize(
|
||||
app,
|
||||
dbm,
|
||||
variantAnalysisManager,
|
||||
cliServer,
|
||||
qs,
|
||||
tmpDir.name,
|
||||
|
||||
@@ -31,6 +31,7 @@ import { getModelsAsDataLanguage } from "./languages";
|
||||
import { INITIAL_MODE } from "./shared/mode";
|
||||
import { isSupportedLanguage } from "./supported-languages";
|
||||
import { DefaultNotifier, checkConsistency } from "./consistency-check";
|
||||
import type { VariantAnalysisManager } from "../variant-analysis/variant-analysis-manager";
|
||||
|
||||
export class ModelEditorModule extends DisposableObject {
|
||||
private readonly queryStorageDir: string;
|
||||
@@ -43,6 +44,7 @@ export class ModelEditorModule extends DisposableObject {
|
||||
private constructor(
|
||||
private readonly app: App,
|
||||
private readonly databaseManager: DatabaseManager,
|
||||
private readonly variantAnalysisManager: VariantAnalysisManager,
|
||||
private readonly cliServer: CodeQLCliServer,
|
||||
private readonly queryRunner: QueryRunner,
|
||||
baseQueryStorageDir: string,
|
||||
@@ -65,6 +67,7 @@ export class ModelEditorModule extends DisposableObject {
|
||||
public static async initialize(
|
||||
app: App,
|
||||
databaseManager: DatabaseManager,
|
||||
variantAnalysisManager: VariantAnalysisManager,
|
||||
cliServer: CodeQLCliServer,
|
||||
queryRunner: QueryRunner,
|
||||
queryStorageDir: string,
|
||||
@@ -72,6 +75,7 @@ export class ModelEditorModule extends DisposableObject {
|
||||
const modelEditorModule = new ModelEditorModule(
|
||||
app,
|
||||
databaseManager,
|
||||
variantAnalysisManager,
|
||||
cliServer,
|
||||
queryRunner,
|
||||
queryStorageDir,
|
||||
@@ -240,6 +244,7 @@ export class ModelEditorModule extends DisposableObject {
|
||||
this.modelingEvents,
|
||||
this.modelConfig,
|
||||
this.databaseManager,
|
||||
this.variantAnalysisManager,
|
||||
this.cliServer,
|
||||
this.queryRunner,
|
||||
this.queryStorageDir,
|
||||
|
||||
@@ -59,6 +59,7 @@ import { runSuggestionsQuery } from "./suggestion-queries";
|
||||
import { parseAccessPathSuggestionRowsToOptions } from "./suggestions-bqrs";
|
||||
import { ModelEvaluator } from "./model-evaluator";
|
||||
import type { ModelEvaluationRunState } from "./shared/model-evaluation-run-state";
|
||||
import type { VariantAnalysisManager } from "../variant-analysis/variant-analysis-manager";
|
||||
|
||||
export class ModelEditorView extends AbstractWebview<
|
||||
ToModelEditorMessage,
|
||||
@@ -77,6 +78,7 @@ export class ModelEditorView extends AbstractWebview<
|
||||
private readonly modelingEvents: ModelingEvents,
|
||||
private readonly modelConfig: ModelConfigListener,
|
||||
private readonly databaseManager: DatabaseManager,
|
||||
private readonly variantAnalysisManager: VariantAnalysisManager,
|
||||
private readonly cliServer: CodeQLCliServer,
|
||||
private readonly queryRunner: QueryRunner,
|
||||
private readonly queryStorageDir: string,
|
||||
@@ -115,9 +117,13 @@ export class ModelEditorView extends AbstractWebview<
|
||||
this.languageDefinition = getModelsAsDataLanguage(language);
|
||||
|
||||
this.modelEvaluator = new ModelEvaluator(
|
||||
this.app.logger,
|
||||
this.cliServer,
|
||||
modelingStore,
|
||||
modelingEvents,
|
||||
this.variantAnalysisManager,
|
||||
databaseItem,
|
||||
language,
|
||||
this.updateModelEvaluationRun.bind(this),
|
||||
);
|
||||
this.push(this.modelEvaluator);
|
||||
@@ -801,6 +807,7 @@ export class ModelEditorView extends AbstractWebview<
|
||||
this.modelingEvents,
|
||||
this.modelConfig,
|
||||
this.databaseManager,
|
||||
this.variantAnalysisManager,
|
||||
this.cliServer,
|
||||
this.queryRunner,
|
||||
this.queryStorageDir,
|
||||
|
||||
@@ -3,14 +3,24 @@ import type { ModelingEvents } from "./modeling-events";
|
||||
import type { DatabaseItem } from "../databases/local-databases";
|
||||
import type { ModelEvaluationRun } from "./model-evaluation-run";
|
||||
import { DisposableObject } from "../common/disposable-object";
|
||||
import { sleep } from "../common/time";
|
||||
import type { ModelEvaluationRunState } from "./shared/model-evaluation-run-state";
|
||||
import type { BaseLogger } from "../common/logging";
|
||||
import type { CodeQLCliServer } from "../codeql-cli/cli";
|
||||
import type { VariantAnalysisManager } from "../variant-analysis/variant-analysis-manager";
|
||||
import type { QueryLanguage } from "../common/query-language";
|
||||
import { resolveCodeScanningQueryPack } from "../variant-analysis/code-scanning-pack";
|
||||
import { withProgress } from "../common/vscode/progress";
|
||||
import type { VariantAnalysis } from "../variant-analysis/shared/variant-analysis";
|
||||
|
||||
export class ModelEvaluator extends DisposableObject {
|
||||
public constructor(
|
||||
private readonly logger: BaseLogger,
|
||||
private readonly cliServer: CodeQLCliServer,
|
||||
private readonly modelingStore: ModelingStore,
|
||||
private readonly modelingEvents: ModelingEvents,
|
||||
private readonly variantAnalysisManager: VariantAnalysisManager,
|
||||
private readonly dbItem: DatabaseItem,
|
||||
private readonly language: QueryLanguage,
|
||||
private readonly updateView: (
|
||||
run: ModelEvaluationRunState,
|
||||
) => Promise<void>,
|
||||
@@ -28,18 +38,48 @@ export class ModelEvaluator extends DisposableObject {
|
||||
};
|
||||
this.modelingStore.updateModelEvaluationRun(this.dbItem, evaluationRun);
|
||||
|
||||
// For now, just wait 5 seconds and then update the store.
|
||||
// In the future, this will be replaced with the actual evaluation process.
|
||||
void sleep(5000).then(() => {
|
||||
const completedEvaluationRun: ModelEvaluationRun = {
|
||||
isPreparing: false,
|
||||
variantAnalysisId: undefined,
|
||||
};
|
||||
this.modelingStore.updateModelEvaluationRun(
|
||||
this.dbItem,
|
||||
completedEvaluationRun,
|
||||
);
|
||||
});
|
||||
// Build pack
|
||||
const qlPack = await resolveCodeScanningQueryPack(
|
||||
this.logger,
|
||||
this.cliServer,
|
||||
this.language,
|
||||
);
|
||||
|
||||
if (!qlPack) {
|
||||
this.modelingStore.updateModelEvaluationRun(this.dbItem, undefined);
|
||||
throw new Error("Unable to trigger evaluation run");
|
||||
}
|
||||
|
||||
// Submit variant analysis and monitor progress
|
||||
return withProgress(
|
||||
async (progress, token) => {
|
||||
let variantAnalysisId: number | undefined = undefined;
|
||||
try {
|
||||
variantAnalysisId =
|
||||
await this.variantAnalysisManager.runVariantAnalysis(
|
||||
qlPack,
|
||||
progress,
|
||||
token,
|
||||
);
|
||||
} catch (e) {
|
||||
this.modelingStore.updateModelEvaluationRun(this.dbItem, undefined);
|
||||
throw e;
|
||||
}
|
||||
|
||||
if (variantAnalysisId) {
|
||||
this.monitorVariantAnalysis(variantAnalysisId);
|
||||
} else {
|
||||
this.modelingStore.updateModelEvaluationRun(this.dbItem, undefined);
|
||||
throw new Error(
|
||||
"Unable to trigger variant analysis for evaluation run",
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "Run Variant Analysis",
|
||||
cancellable: true,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
public async stopEvaluation() {
|
||||
@@ -55,19 +95,51 @@ export class ModelEvaluator extends DisposableObject {
|
||||
private registerToModelingEvents() {
|
||||
this.push(
|
||||
this.modelingEvents.onModelEvaluationRunChanged(async (event) => {
|
||||
if (
|
||||
event.evaluationRun &&
|
||||
event.dbUri === this.dbItem.databaseUri.toString()
|
||||
) {
|
||||
const run: ModelEvaluationRunState = {
|
||||
isPreparing: event.evaluationRun.isPreparing,
|
||||
|
||||
// TODO: Get variant analysis from id.
|
||||
variantAnalysis: undefined,
|
||||
};
|
||||
await this.updateView(run);
|
||||
if (event.dbUri === this.dbItem.databaseUri.toString()) {
|
||||
if (!event.evaluationRun) {
|
||||
await this.updateView({
|
||||
isPreparing: false,
|
||||
variantAnalysis: undefined,
|
||||
});
|
||||
} else {
|
||||
const variantAnalysis = await this.getVariantAnalysisForRun(
|
||||
event.evaluationRun,
|
||||
);
|
||||
const run: ModelEvaluationRunState = {
|
||||
isPreparing: event.evaluationRun.isPreparing,
|
||||
variantAnalysis,
|
||||
};
|
||||
await this.updateView(run);
|
||||
}
|
||||
}
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
private async getVariantAnalysisForRun(
|
||||
evaluationRun: ModelEvaluationRun,
|
||||
): Promise<VariantAnalysis | undefined> {
|
||||
if (evaluationRun.variantAnalysisId) {
|
||||
return await this.variantAnalysisManager.getVariantAnalysis(
|
||||
evaluationRun.variantAnalysisId,
|
||||
);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private monitorVariantAnalysis(variantAnalysisId: number) {
|
||||
this.push(
|
||||
this.variantAnalysisManager.onVariantAnalysisStatusUpdated(
|
||||
async (variantAnalysis) => {
|
||||
// Make sure it's the variant analysis we're interested in
|
||||
if (variantAnalysisId === variantAnalysis.id) {
|
||||
await this.updateView({
|
||||
isPreparing: false,
|
||||
variantAnalysis,
|
||||
});
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -378,7 +378,7 @@ export class ModelingStore extends DisposableObject {
|
||||
|
||||
public updateModelEvaluationRun(
|
||||
dbItem: DatabaseItem,
|
||||
evaluationRun: ModelEvaluationRun,
|
||||
evaluationRun: ModelEvaluationRun | undefined,
|
||||
) {
|
||||
this.changeModelEvaluationRun(dbItem, (state) => {
|
||||
state.modelEvaluationRun = evaluationRun;
|
||||
|
||||
@@ -298,7 +298,7 @@ export class VariantAnalysisManager
|
||||
qlPackDetails: QlPackDetails,
|
||||
progress: ProgressCallback,
|
||||
token: CancellationToken,
|
||||
): Promise<void> {
|
||||
): Promise<number | undefined> {
|
||||
await saveBeforeStart();
|
||||
|
||||
progress({
|
||||
@@ -379,7 +379,7 @@ export class VariantAnalysisManager
|
||||
} catch (e: unknown) {
|
||||
// If the error is handled by the handleRequestError function, we don't need to throw
|
||||
if (e instanceof RequestError && handleRequestError(e, this.app.logger)) {
|
||||
return;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
throw e;
|
||||
@@ -405,6 +405,8 @@ export class VariantAnalysisManager
|
||||
"codeQL.monitorNewVariantAnalysis",
|
||||
processedVariantAnalysis,
|
||||
);
|
||||
|
||||
return processedVariantAnalysis.id;
|
||||
}
|
||||
|
||||
public async rehydrateVariantAnalysis(variantAnalysis: VariantAnalysis) {
|
||||
|
||||
@@ -12,6 +12,7 @@ import { createMockModelingStore } from "../../../__mocks__/model-editor/modelin
|
||||
import type { ModelConfigListener } from "../../../../src/config";
|
||||
import { createMockModelingEvents } from "../../../__mocks__/model-editor/modelingEventsMock";
|
||||
import { QueryLanguage } from "../../../../src/common/query-language";
|
||||
import type { VariantAnalysisManager } from "../../../../src/variant-analysis/variant-analysis-manager";
|
||||
|
||||
describe("ModelEditorView", () => {
|
||||
const app = createMockApp({});
|
||||
@@ -21,6 +22,7 @@ describe("ModelEditorView", () => {
|
||||
onDidChangeConfiguration: jest.fn(),
|
||||
});
|
||||
const databaseManager = mockEmptyDatabaseManager();
|
||||
const variantAnalysisManager = mockedObject<VariantAnalysisManager>({});
|
||||
const cliServer = mockedObject<CodeQLCliServer>({});
|
||||
const queryRunner = mockedObject<QueryRunner>({});
|
||||
const queryStorageDir = "/a/b/c/d";
|
||||
@@ -48,6 +50,7 @@ describe("ModelEditorView", () => {
|
||||
modelingEvents,
|
||||
modelConfig,
|
||||
databaseManager,
|
||||
variantAnalysisManager,
|
||||
cliServer,
|
||||
queryRunner,
|
||||
queryStorageDir,
|
||||
|
||||
Reference in New Issue
Block a user