Skip to content

Commit 22537ce

Browse files
authored
Merge branch 'main' into codeql/upgrade-to-v2.23.6
2 parents b23c002 + 2e9aaf6 commit 22537ce

File tree

13 files changed

+1539
-1105
lines changed

13 files changed

+1539
-1105
lines changed

extractors/cds/tools/cds-extractor.ts

Lines changed: 39 additions & 155 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,16 @@ import { join } from 'path';
33
import { sync as globSync } from 'glob';
44

55
import { orchestrateCompilation } from './src/cds/compiler';
6-
import { buildCdsProjectDependencyGraph } from './src/cds/parser';
7-
import { runJavaScriptExtractor } from './src/codeql';
6+
import { buildCdsProjectDependencyGraph, type CdsDependencyGraph } from './src/cds/parser';
7+
import { handleEarlyExit, runJavaScriptExtractionWithMarker } from './src/codeql';
88
import {
99
addCompilationDiagnostic,
1010
addDependencyGraphDiagnostic,
1111
addDependencyInstallationDiagnostic,
1212
addEnvironmentSetupDiagnostic,
13-
addJavaScriptExtractorDiagnostic,
1413
addNoCdsProjectsDiagnostic,
1514
} from './src/diagnostics';
16-
import { configureLgtmIndexFilters, setupAndValidateEnvironment } from './src/environment';
15+
import { setupAndValidateEnvironment } from './src/environment';
1716
import {
1817
cdsExtractorLog,
1918
generateStatusReport,
@@ -27,31 +26,28 @@ import {
2726
import { cacheInstallDependencies } from './src/packageManager';
2827
import { validateArguments } from './src/utils';
2928

30-
// Validate the script arguments.
29+
// ============================================================================
30+
// Main Extraction Flow
31+
// ============================================================================
32+
33+
// Validate arguments
3134
const validationResult = validateArguments(process.argv);
3235
if (!validationResult.isValid) {
3336
console.warn(validationResult.usageMessage);
34-
// For invalid arguments, we can't proceed but we also can't add diagnostics since we don't have
35-
// the necessary context (sourceRoot, codeqlExePath). Log the issue and exit gracefully.
3637
console.log(
3738
`CDS extractor terminated due to invalid arguments: ${validationResult.usageMessage}`,
3839
);
3940
console.log(`Completed run of the cds-extractor.js script for the CDS extractor.`);
40-
process.exit(0); // Use exit code 0 to not fail the overall JavaScript extractor
41+
process.exit(0);
4142
}
4243

43-
// Get the validated and sanitized arguments.
4444
const { sourceRoot } = validationResult.args!;
4545

46-
// Initialize the unified logging system with the source root directory.
46+
// Initialize logging
4747
setSourceRootDirectory(sourceRoot);
48-
49-
// Log the start of the CDS extractor session as a whole.
5048
logExtractorStart(sourceRoot);
5149

52-
// Setup the environment and validate all requirements first, before changing
53-
// directory back to the "sourceRoot" directory. This ensures we can properly locate
54-
// the CodeQL tools.
50+
// Setup and validate environment
5551
logPerformanceTrackingStart('Environment Setup');
5652
const {
5753
success: envSetupSuccess,
@@ -64,25 +60,18 @@ logPerformanceTrackingStop('Environment Setup');
6460

6561
if (!envSetupSuccess) {
6662
const codeqlExe = platformInfo.isWindows ? 'codeql.exe' : 'codeql';
67-
const errorMessage = `'${codeqlExe} database index-files --language cds' terminated early due to: ${errorMessages.join(
68-
', ',
69-
)}.`;
70-
63+
const errorMessage = `'${codeqlExe} database index-files --language cds' terminated early due to: ${errorMessages.join(', ')}.`;
7164
cdsExtractorLog('warn', errorMessage);
7265

73-
// Add diagnostic for environment setup failure if we have a codeqlExePath
7466
if (codeqlExePath) {
7567
addEnvironmentSetupDiagnostic(sourceRoot, errorMessage, codeqlExePath);
7668
}
7769

78-
// Continue with a warning instead of exiting - let JavaScript extractor proceed
7970
logExtractorStop(
8071
false,
8172
'Warning: Environment setup failed, continuing with limited functionality',
8273
);
8374
} else {
84-
// Force this script, and any process it spawns, to use the project (source) root
85-
// directory as the current working directory.
8675
process.chdir(sourceRoot);
8776
}
8877

@@ -91,17 +80,9 @@ cdsExtractorLog(
9180
`CodeQL CDS extractor using autobuild mode for scan of project source root directory '${sourceRoot}'.`,
9281
);
9382

83+
// Build CDS project dependency graph
9484
cdsExtractorLog('info', 'Building CDS project dependency graph...');
95-
96-
// Build the CDS project `dependencyGraph` as the foundation for the extraction process.
97-
// This graph will contain all discovered CDS projects, their dependencies, the `.cds`
98-
// files discovered within each project, the expected `.cds.json` files for each project
99-
// and the compilation status of such `.cds.json` files.
100-
//
101-
// The `dependencyGraph` will be updated as CDS extractor phases progress, allowing for
102-
// a single data structure to be used for planning, execution, retries (i.e. error handling),
103-
// debugging, and final reporting.
104-
let dependencyGraph;
85+
let dependencyGraph: CdsDependencyGraph;
10586

10687
try {
10788
logPerformanceTrackingStart('Dependency Graph Build');
@@ -113,7 +94,7 @@ try {
11394
`${dependencyGraph.projects.size} projects, ${dependencyGraph.statusSummary.totalCdsFiles} CDS files`,
11495
);
11596

116-
// Log details about discovered projects for debugging
97+
// Log project details
11798
if (dependencyGraph.projects.size > 0) {
11899
for (const [projectDir, project] of dependencyGraph.projects.entries()) {
119100
cdsExtractorLog(
@@ -122,11 +103,12 @@ try {
122103
);
123104
}
124105
} else {
106+
// No CDS projects detected - try direct file search as diagnostic
125107
cdsExtractorLog(
126108
'error',
127109
'No CDS projects were detected. This is an unrecoverable error as there is nothing to scan.',
128110
);
129-
// Let's also try to find CDS files directly as a backup check
111+
130112
try {
131113
const allCdsFiles = Array.from(
132114
new Set([
@@ -139,6 +121,7 @@ try {
139121
'info',
140122
`Direct search found ${allCdsFiles.length} CDS files in the source tree.`,
141123
);
124+
142125
if (allCdsFiles.length > 0) {
143126
cdsExtractorLog(
144127
'info',
@@ -158,160 +141,96 @@ try {
158141
cdsExtractorLog('warn', `Could not perform direct CDS file search: ${String(globError)}`);
159142
}
160143

161-
// Add diagnostic warning for no CDS projects detected
162144
const warningMessage =
163145
'No CDS projects were detected. This may be expected if the source does not contain CAP/CDS projects.';
164146
if (codeqlExePath) {
165147
addNoCdsProjectsDiagnostic(sourceRoot, warningMessage, codeqlExePath);
166148
}
167149

168-
// Continue instead of exiting - let JavaScript extractor proceed with non-CDS files
169150
logExtractorStop(false, 'Warning: No CDS projects detected, skipping CDS-specific processing');
170-
171-
// Skip the rest of CDS processing and go directly to JavaScript extraction
172-
configureLgtmIndexFilters();
173-
174-
// Run CodeQL's JavaScript extractor to process any remaining files
175-
logPerformanceTrackingStart('JavaScript Extraction');
176-
const extractorResult = runJavaScriptExtractor(
151+
handleEarlyExit(
177152
sourceRoot,
178-
autobuildScriptPath || '', // Use empty string if autobuildScriptPath is undefined
153+
autobuildScriptPath || '',
179154
codeqlExePath,
155+
'JavaScript extraction completed (CDS processing was skipped)',
180156
);
181-
logPerformanceTrackingStop('JavaScript Extraction');
182-
183-
if (!extractorResult.success && extractorResult.error) {
184-
cdsExtractorLog('error', `Error running JavaScript extractor: ${extractorResult.error}`);
185-
if (codeqlExePath) {
186-
addJavaScriptExtractorDiagnostic(
187-
sourceRoot,
188-
extractorResult.error,
189-
codeqlExePath,
190-
sourceRoot,
191-
);
192-
}
193-
logExtractorStop(false, 'JavaScript extractor failed');
194-
} else {
195-
logExtractorStop(true, 'JavaScript extraction completed (CDS processing was skipped)');
196-
}
197-
198-
console.log(`Completed run of the cds-extractor.js script for the CDS extractor.`);
199-
process.exit(0); // Graceful exit to skip the rest of the processing
200157
}
201158
} catch (error) {
202159
const errorMessage = `Failed to build CDS dependency graph: ${String(error)}`;
203160
cdsExtractorLog('error', errorMessage);
204161

205-
// Add diagnostic for dependency graph build failure
206162
if (codeqlExePath) {
207163
addDependencyGraphDiagnostic(sourceRoot, errorMessage, codeqlExePath);
208164
}
209165

210-
// Continue with a warning instead of exiting - let JavaScript extractor proceed with non-CDS files
211166
logExtractorStop(
212167
false,
213168
'Warning: Dependency graph build failed, skipping CDS-specific processing',
214169
);
215-
216-
// Skip the rest of CDS processing and go directly to JavaScript extraction
217-
configureLgtmIndexFilters();
218-
219-
// Run CodeQL's JavaScript extractor to process any remaining files
220-
logPerformanceTrackingStart('JavaScript Extraction');
221-
const extractorResult = runJavaScriptExtractor(
170+
handleEarlyExit(
222171
sourceRoot,
223-
autobuildScriptPath || '', // Use empty string if autobuildScriptPath is undefined
172+
autobuildScriptPath || '',
224173
codeqlExePath,
174+
'JavaScript extraction completed (CDS processing was skipped)',
225175
);
226-
logPerformanceTrackingStop('JavaScript Extraction');
227-
228-
if (!extractorResult.success && extractorResult.error) {
229-
cdsExtractorLog('error', `Error running JavaScript extractor: ${extractorResult.error}`);
230-
if (codeqlExePath) {
231-
addJavaScriptExtractorDiagnostic(
232-
sourceRoot,
233-
extractorResult.error,
234-
codeqlExePath,
235-
sourceRoot,
236-
);
237-
}
238-
logExtractorStop(false, 'JavaScript extractor failed');
239-
} else {
240-
logExtractorStop(true, 'JavaScript extraction completed (CDS processing was skipped)');
241-
}
242-
243-
console.log(`Completed run of the cds-extractor.js script for the CDS extractor.`);
244-
process.exit(0); // Graceful exit to skip the rest of the processing
245176
}
246177

178+
// Install dependencies
247179
logPerformanceTrackingStart('Dependency Installation');
248180
const projectCacheDirMap = cacheInstallDependencies(dependencyGraph, sourceRoot, codeqlExePath);
249181
logPerformanceTrackingStop('Dependency Installation');
250182

251-
// Check if dependency installation resulted in any usable project mappings
252183
if (projectCacheDirMap.size === 0) {
253184
cdsExtractorLog(
254185
'error',
255186
'No project cache directory mappings were created. This indicates that dependency installation failed for all discovered projects.',
256187
);
257188

258-
// This is a critical error if we have projects but no cache mappings
259189
if (dependencyGraph.projects.size > 0) {
260190
const errorMessage = `Found ${dependencyGraph.projects.size} CDS projects but failed to install dependencies for any of them. Cannot proceed with compilation.`;
261191
cdsExtractorLog('error', errorMessage);
262192

263-
// Add diagnostic for dependency installation failure
264193
if (codeqlExePath) {
265194
addDependencyInstallationDiagnostic(sourceRoot, errorMessage, codeqlExePath);
266195
}
267196

268-
// Continue with a warning instead of exiting - let JavaScript extractor proceed
269197
logExtractorStop(
270198
false,
271199
'Warning: Dependency installation failed for all projects, continuing with limited functionality',
272200
);
273201
}
274202

275-
// If we have no projects and no cache mappings, this should have been caught earlier
276203
cdsExtractorLog(
277204
'warn',
278205
'No projects and no cache mappings - this should have been detected earlier.',
279206
);
280207
}
281208

209+
// Collect all CDS files to process
282210
const cdsFilePathsToProcess: string[] = [];
283-
284-
// Use the dependency graph to collect all `.cds` files from each project.
285-
// We want to "extract" all `.cds` files from all projects so that we have a copy
286-
// of each `.cds` source file in the CodeQL database.
287211
for (const project of dependencyGraph.projects.values()) {
288212
cdsFilePathsToProcess.push(...project.cdsFiles);
289213
}
290214

291-
// TODO : Improve logging / debugging of dependencyGraph.statusSummary. Just log the JSON?
292215
cdsExtractorLog(
293216
'info',
294217
`Found ${cdsFilePathsToProcess.length} total CDS files, ${dependencyGraph.statusSummary.totalCdsFiles} CDS files in dependency graph`,
295218
);
296219

220+
// Compile CDS files
297221
logPerformanceTrackingStart('CDS Compilation');
298222
try {
299-
// Use the new orchestrated compilation approach (autobuild mode, no debug)
300223
orchestrateCompilation(dependencyGraph, projectCacheDirMap, codeqlExePath);
301224

302-
// Handle compilation failures for normal mode
303225
if (!dependencyGraph.statusSummary.overallSuccess) {
304226
cdsExtractorLog(
305227
'error',
306228
`Compilation completed with failures: ${dependencyGraph.statusSummary.failedCompilations} failed out of ${dependencyGraph.statusSummary.totalCompilationTasks} total tasks`,
307229
);
308230

309-
// Add diagnostics for critical errors
310231
for (const error of dependencyGraph.errors.critical) {
311232
cdsExtractorLog('error', `Critical error in ${error.phase}: ${error.message}`);
312233
}
313-
314-
// Don't exit with error - let the JavaScript extractor run on whatever was compiled
315234
}
316235

317236
logPerformanceTrackingStop('CDS Compilation');
@@ -320,67 +239,32 @@ try {
320239
logPerformanceTrackingStop('CDS Compilation');
321240
cdsExtractorLog('error', `Compilation orchestration failed: ${String(error)}`);
322241

323-
// Add diagnostic for the overall failure
324242
if (cdsFilePathsToProcess.length > 0) {
325243
addCompilationDiagnostic(
326-
cdsFilePathsToProcess[0], // Use first file as representative
244+
cdsFilePathsToProcess[0],
327245
`Compilation orchestration failed: ${String(error)}`,
328246
codeqlExePath,
329247
sourceRoot,
330248
);
331249
}
332250
}
333251

334-
// Configure the "LGTM" index filters for proper extraction.
335-
configureLgtmIndexFilters();
336-
337-
// Run CodeQL's JavaScript extractor to process the .cds source files and
338-
// the compiled .cds.json files.
339-
logPerformanceTrackingStart('JavaScript Extraction');
340-
const extractionStartTime = Date.now();
341-
const extractorResult = runJavaScriptExtractor(sourceRoot, autobuildScriptPath, codeqlExePath);
342-
const extractionEndTime = Date.now();
343-
logPerformanceTrackingStop('JavaScript Extraction');
344-
345-
// Update the dependency graph's performance metrics with the extraction duration
346-
dependencyGraph.statusSummary.performance.extractionDurationMs =
347-
extractionEndTime - extractionStartTime;
348-
349-
// Calculate total duration by summing all phases
350-
const totalDuration =
351-
dependencyGraph.statusSummary.performance.parsingDurationMs +
352-
dependencyGraph.statusSummary.performance.compilationDurationMs +
353-
dependencyGraph.statusSummary.performance.extractionDurationMs;
354-
dependencyGraph.statusSummary.performance.totalDurationMs = totalDuration;
355-
356-
if (!extractorResult.success && extractorResult.error) {
357-
cdsExtractorLog('error', `Error running JavaScript extractor: ${extractorResult.error}`);
358-
359-
// Add diagnostic for JavaScript extractor failure
360-
if (codeqlExePath && dependencyGraph.projects.size > 0) {
361-
// Use the first CDS file as a representative file for the diagnostic
362-
const firstProject = Array.from(dependencyGraph.projects.values())[0];
363-
const representativeFile = firstProject.cdsFiles[0] || sourceRoot;
364-
addJavaScriptExtractorDiagnostic(
365-
representativeFile,
366-
extractorResult.error,
367-
codeqlExePath,
368-
sourceRoot,
369-
);
370-
}
252+
// Run JavaScript extraction with marker file handling
253+
const extractionSuccess = runJavaScriptExtractionWithMarker(
254+
sourceRoot,
255+
autobuildScriptPath,
256+
codeqlExePath,
257+
dependencyGraph,
258+
);
371259

372-
logExtractorStop(false, 'JavaScript extractor failed');
373-
} else {
374-
logExtractorStop(true, 'CDS extraction completed successfully');
375-
}
260+
logExtractorStop(
261+
extractionSuccess,
262+
extractionSuccess ? 'CDS extraction completed successfully' : 'JavaScript extractor failed',
263+
);
376264

377265
cdsExtractorLog(
378266
'info',
379267
'CDS Extractor Status Report : Final...\n' + generateStatusReport(dependencyGraph),
380268
);
381269

382-
// Use the `cds-extractor.js` name in the log message as that is the name of the script
383-
// that is actually run by the `codeql database index-files` command. This TypeScript
384-
// file is where the code/logic is edited/implemented, but the runnable script is
385-
// generated by the TypeScript compiler and is named `cds-extractor.js`.
386270
console.log(`Completed run of the cds-extractor.js script for the CDS extractor.`);

0 commit comments

Comments
 (0)