11import { CodeQLCliServer , SourceInfo } from "../codeql-cli/cli" ;
2- import { QueryRunner } from "../query-server" ;
2+ import { CoreCompletedQuery , QueryRunner } from "../query-server" ;
33import { DatabaseItem } from "../databases/local-databases" ;
44import { ProgressCallback } from "../common/vscode/progress" ;
55import * as Sarif from "sarif" ;
66import { qlpackOfDatabase , resolveQueries } from "../local-queries" ;
7- import { extLogger } from "../common/logging/vscode" ;
87import { Mode } from "./shared/mode" ;
9- import { QlPacksForLanguage } from "../databases/qlpack" ;
10- import { createLockFileForStandardQuery } from "../local-queries/standard-queries" ;
11- import { CancellationToken , CancellationTokenSource } from "vscode" ;
128import { getOnDiskWorkspaceFolders } from "../common/vscode/workspace-folders" ;
13- import { showAndLogExceptionWithTelemetry , TeeLogger } from "../common/logging" ;
14- import { QueryResultType } from "../query-server/new-messages" ;
15- import { telemetryListener } from "../common/vscode/telemetry" ;
16- import { redactableError } from "../common/errors" ;
179import { interpretResultsSarif } from "../query-results" ;
1810import { join } from "path" ;
1911import { assertNever } from "../common/helpers-pure" ;
2012import { dir } from "tmp-promise" ;
2113import { writeFile , outputFile } from "fs-extra" ;
2214import { dump as dumpYaml } from "js-yaml" ;
2315import { MethodSignature } from "./external-api-usage" ;
16+ import { runQuery } from "../local-queries/run-query" ;
17+ import { QueryMetadata } from "../common/interface-types" ;
18+ import { CancellationTokenSource } from "vscode" ;
2419
2520function modeTag ( mode : Mode ) : string {
2621 switch ( mode ) {
@@ -59,22 +54,13 @@ export async function runAutoModelQueries({
5954 progress,
6055 cancellationTokenSource,
6156} : AutoModelQueriesOptions ) : Promise < AutoModelQueriesResult | undefined > {
62- const qlpack = await qlpackOfDatabase ( cliServer , databaseItem ) ;
63-
64- // CodeQL needs to have access to the database to be able to retrieve the
65- // snippets from it. The source location prefix is used to determine the
66- // base path of the database.
67- const sourceLocationPrefix = await databaseItem . getSourceLocationPrefix (
57+ // First, resolve the query that we want to run.
58+ const queryPath = await resolveAutomodelQueries (
6859 cliServer ,
60+ databaseItem ,
61+ "candidates" ,
62+ mode ,
6963 ) ;
70- const sourceArchiveUri = databaseItem . sourceArchive ;
71- const sourceInfo =
72- sourceArchiveUri === undefined
73- ? undefined
74- : {
75- sourceArchive : sourceArchiveUri . fsPath ,
76- sourceLocationPrefix,
77- } ;
7864
7965 // Generate a pack containing the candidate filters
8066 const filterPackDir = await generateCandidateFilterPack (
@@ -87,30 +73,89 @@ export async function runAutoModelQueries({
8773 await cliServer . resolveQlpacks ( additionalPacks , true ) ,
8874 ) ;
8975
90- const candidates = await runAutoModelQuery ( {
91- mode,
92- queryTag : "candidates" ,
76+ // Run the actual query
77+ const completedQuery = await runQuery ( {
9378 cliServer,
9479 queryRunner,
9580 databaseItem,
96- qlpack ,
97- sourceInfo ,
81+ queryPath ,
82+ queryStorageDir ,
9883 additionalPacks,
9984 extensionPacks,
100- queryStorageDir,
10185 progress,
10286 token : cancellationTokenSource . token ,
10387 } ) ;
10488
105- if ( ! candidates ) {
89+ if ( ! completedQuery ) {
10690 return undefined ;
10791 }
10892
93+ // Get metadata for the query. This is required to interpret the results. We already know the kind is problem
94+ // (because of the constraint in resolveQueries), so we don't need any more checks on the metadata.
95+ const metadata = await cliServer . resolveMetadata ( queryPath ) ;
96+
97+ // CodeQL needs to have access to the database to be able to retrieve the
98+ // snippets from it. The source location prefix is used to determine the
99+ // base path of the database.
100+ const sourceLocationPrefix = await databaseItem . getSourceLocationPrefix (
101+ cliServer ,
102+ ) ;
103+ const sourceArchiveUri = databaseItem . sourceArchive ;
104+ const sourceInfo =
105+ sourceArchiveUri === undefined
106+ ? undefined
107+ : {
108+ sourceArchive : sourceArchiveUri . fsPath ,
109+ sourceLocationPrefix,
110+ } ;
111+
112+ const candidates = await interpretAutomodelResults (
113+ cliServer ,
114+ completedQuery ,
115+ metadata ,
116+ sourceInfo ,
117+ ) ;
118+
109119 return {
110120 candidates,
111121 } ;
112122}
113123
124+ async function resolveAutomodelQueries (
125+ cliServer : CodeQLCliServer ,
126+ databaseItem : DatabaseItem ,
127+ queryTag : string ,
128+ mode : Mode ,
129+ ) : Promise < string > {
130+ const qlpack = await qlpackOfDatabase ( cliServer , databaseItem ) ;
131+
132+ // First, resolve the query that we want to run.
133+ // All queries are tagged like this:
134+ // internal extract automodel <mode> <queryTag>
135+ // Example: internal extract automodel framework-mode candidates
136+ const queries = await resolveQueries (
137+ cliServer ,
138+ qlpack ,
139+ `Extract automodel ${ queryTag } ` ,
140+ {
141+ kind : "problem" ,
142+ "tags contain all" : [ "automodel" , modeTag ( mode ) , ...queryTag . split ( " " ) ] ,
143+ } ,
144+ ) ;
145+ if ( queries . length > 1 ) {
146+ throw new Error (
147+ `Found multiple auto model queries for ${ mode } ${ queryTag } . Can't continue` ,
148+ ) ;
149+ }
150+ if ( queries . length === 0 ) {
151+ throw new Error (
152+ `Did not found any auto model queries for ${ mode } ${ queryTag } . Can't continue` ,
153+ ) ;
154+ }
155+
156+ return queries [ 0 ] ;
157+ }
158+
114159/**
115160 * generateCandidateFilterPack will create a temporary extension pack.
116161 * This pack will contain a filter that will restrict the automodel queries
@@ -167,107 +212,15 @@ export async function generateCandidateFilterPack(
167212 return packDir ;
168213}
169214
170- type AutoModelQueryOptions = {
171- queryTag : string ;
172- mode : Mode ;
173- cliServer : CodeQLCliServer ;
174- queryRunner : QueryRunner ;
175- databaseItem : DatabaseItem ;
176- qlpack : QlPacksForLanguage ;
177- sourceInfo : SourceInfo | undefined ;
178- additionalPacks : string [ ] ;
179- extensionPacks : string [ ] ;
180- queryStorageDir : string ;
181-
182- progress : ProgressCallback ;
183- token : CancellationToken ;
184- } ;
185-
186- async function runAutoModelQuery ( {
187- queryTag,
188- mode,
189- cliServer,
190- queryRunner,
191- databaseItem,
192- qlpack,
193- sourceInfo,
194- additionalPacks,
195- extensionPacks,
196- queryStorageDir,
197- progress,
198- token,
199- } : AutoModelQueryOptions ) : Promise < Sarif . Log | undefined > {
200- // First, resolve the query that we want to run.
201- // All queries are tagged like this:
202- // internal extract automodel <mode> <queryTag>
203- // Example: internal extract automodel framework-mode candidates
204- const queries = await resolveQueries (
205- cliServer ,
206- qlpack ,
207- `Extract automodel ${ queryTag } ` ,
208- {
209- kind : "problem" ,
210- "tags contain all" : [ "automodel" , modeTag ( mode ) , ...queryTag . split ( " " ) ] ,
211- } ,
212- ) ;
213- if ( queries . length > 1 ) {
214- throw new Error (
215- `Found multiple auto model queries for ${ mode } ${ queryTag } . Can't continue` ,
216- ) ;
217- }
218- if ( queries . length === 0 ) {
219- throw new Error (
220- `Did not found any auto model queries for ${ mode } ${ queryTag } . Can't continue` ,
221- ) ;
222- }
223-
224- const queryPath = queries [ 0 ] ;
225- const { cleanup : cleanupLockFile } = await createLockFileForStandardQuery (
226- cliServer ,
227- queryPath ,
228- ) ;
229-
230- // Get metadata for the query. This is required to interpret the results. We already know the kind is problem
231- // (because of the constraint in resolveQueries), so we don't need any more checks on the metadata.
232- const metadata = await cliServer . resolveMetadata ( queryPath ) ;
233-
234- const queryRun = queryRunner . createQueryRun (
235- databaseItem . databaseUri . fsPath ,
236- {
237- queryPath,
238- quickEvalPosition : undefined ,
239- quickEvalCountOnly : false ,
240- } ,
241- false ,
242- additionalPacks ,
243- extensionPacks ,
244- queryStorageDir ,
245- undefined ,
246- undefined ,
247- ) ;
248-
249- const completedQuery = await queryRun . evaluate (
250- progress ,
251- token ,
252- new TeeLogger ( queryRunner . logger , queryRun . outputDir . logPath ) ,
253- ) ;
254-
255- await cleanupLockFile ?.( ) ;
256-
257- if ( completedQuery . resultType !== QueryResultType . SUCCESS ) {
258- void showAndLogExceptionWithTelemetry (
259- extLogger ,
260- telemetryListener ,
261- redactableError `Auto-model query ${ queryTag } failed: ${
262- completedQuery . message ?? "No message"
263- } `,
264- ) ;
265- return ;
266- }
267-
215+ async function interpretAutomodelResults (
216+ cliServer : CodeQLCliServer ,
217+ completedQuery : CoreCompletedQuery ,
218+ metadata : QueryMetadata ,
219+ sourceInfo : SourceInfo | undefined ,
220+ ) : Promise < Sarif . Log > {
268221 const interpretedResultsPath = join (
269- queryStorageDir ,
270- `interpreted- results- ${ queryTag . replaceAll ( " " , "-" ) } - ${ queryRun . id } . sarif` ,
222+ completedQuery . outputDir . querySaveDir ,
223+ " results. sarif" ,
271224 ) ;
272225
273226 // eslint-disable-next-line @typescript-eslint/no-unused-vars -- We only need the actual SARIF data, not the extra fields added by SarifInterpretationData
0 commit comments