Skip to content

Commit 64e92b5

Browse files
committed
CDS extractor diagnostics instead of exit errors
This commit addresses a regression in the behavior of the CDS extractor in some cases and/or for some CAP projects. Specifically, this commit: - Removes calls like `process.exit(1)` from the CDS extractor codebase. - Adds new diagnostic warnings for error conditions that had previously resulted in a non-zero exit code being returned from `cds-extractor.ts`. - Adds unit tests to ensure that fails if the `cds-extractor.ts` file contains any `process.exit(n)` call where `n != 0`. - Updates eslint configs for the CDS extractor to resolve reported errors.
1 parent 3b58942 commit 64e92b5

File tree

7 files changed

+498
-99
lines changed

7 files changed

+498
-99
lines changed

extractors/cds/tools/cds-extractor.ts

Lines changed: 128 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,14 @@ import { sync as globSync } from 'glob';
55
import { orchestrateCompilation } from './src/cds/compiler';
66
import { buildCdsProjectDependencyGraph } from './src/cds/parser';
77
import { runJavaScriptExtractor } from './src/codeql';
8-
import { addCompilationDiagnostic } from './src/diagnostics';
8+
import {
9+
addCompilationDiagnostic,
10+
addDependencyGraphDiagnostic,
11+
addDependencyInstallationDiagnostic,
12+
addEnvironmentSetupDiagnostic,
13+
addJavaScriptExtractorDiagnostic,
14+
addNoCdsProjectsDiagnostic,
15+
} from './src/diagnostics';
916
import { configureLgtmIndexFilters, setupAndValidateEnvironment } from './src/environment';
1017
import {
1118
cdsExtractorLog,
@@ -24,8 +31,13 @@ import { validateArguments } from './src/utils';
2431
const validationResult = validateArguments(process.argv);
2532
if (!validationResult.isValid) {
2633
console.warn(validationResult.usageMessage);
27-
// Exit with an error code on invalid use of this script.
28-
process.exit(1);
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.
36+
console.log(
37+
`CDS extractor terminated due to invalid arguments: ${validationResult.usageMessage}`,
38+
);
39+
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
2941
}
3042

3143
// Get the validated and sanitized arguments.
@@ -52,21 +64,28 @@ logPerformanceTrackingStop('Environment Setup');
5264

5365
if (!envSetupSuccess) {
5466
const codeqlExe = platformInfo.isWindows ? 'codeql.exe' : 'codeql';
55-
cdsExtractorLog(
56-
'warn',
57-
`'${codeqlExe} database index-files --language cds' terminated early due to: ${errorMessages.join(
58-
', ',
59-
)}.`,
67+
const errorMessage = `'${codeqlExe} database index-files --language cds' terminated early due to: ${errorMessages.join(
68+
', ',
69+
)}.`;
70+
71+
cdsExtractorLog('warn', errorMessage);
72+
73+
// Add diagnostic for environment setup failure if we have a codeqlExePath
74+
if (codeqlExePath) {
75+
addEnvironmentSetupDiagnostic(sourceRoot, errorMessage, codeqlExePath);
76+
}
77+
78+
// Continue with a warning instead of exiting - let JavaScript extractor proceed
79+
logExtractorStop(
80+
false,
81+
'Warning: Environment setup failed, continuing with limited functionality',
6082
);
61-
// Exit with an error code when environment setup fails.
62-
logExtractorStop(false, 'Terminated: Environment setup failed');
63-
process.exit(1);
83+
} else {
84+
// Force this script, and any process it spawns, to use the project (source) root
85+
// directory as the current working directory.
86+
process.chdir(sourceRoot);
6487
}
6588

66-
// Force this script, and any process it spawns, to use the project (source) root
67-
// directory as the current working directory.
68-
process.chdir(sourceRoot);
69-
7089
cdsExtractorLog(
7190
'info',
7291
`CodeQL CDS extractor using autobuild mode for scan of project source root directory '${sourceRoot}'.`,
@@ -139,15 +158,81 @@ try {
139158
cdsExtractorLog('warn', `Could not perform direct CDS file search: ${String(globError)}`);
140159
}
141160

142-
// Exit early since we have no CDS projects to process
143-
logExtractorStop(false, 'Terminated: No CDS projects detected');
144-
process.exit(1);
161+
// Add diagnostic warning for no CDS projects detected
162+
const warningMessage =
163+
'No CDS projects were detected. This may be expected if the source does not contain CAP/CDS projects.';
164+
if (codeqlExePath) {
165+
addNoCdsProjectsDiagnostic(sourceRoot, warningMessage, codeqlExePath);
166+
}
167+
168+
// Continue instead of exiting - let JavaScript extractor proceed with non-CDS files
169+
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(
177+
sourceRoot,
178+
autobuildScriptPath || '', // Use empty string if autobuildScriptPath is undefined
179+
codeqlExePath,
180+
);
181+
logPerformanceTrackingStop('JavaScript Extraction');
182+
logPerformanceTrackingStop('JavaScript Extraction');
183+
184+
if (!extractorResult.success && extractorResult.error) {
185+
cdsExtractorLog('error', `Error running JavaScript extractor: ${extractorResult.error}`);
186+
if (codeqlExePath) {
187+
addJavaScriptExtractorDiagnostic(sourceRoot, extractorResult.error, codeqlExePath);
188+
}
189+
logExtractorStop(false, 'JavaScript extractor failed');
190+
} else {
191+
logExtractorStop(true, 'JavaScript extraction completed (CDS processing was skipped)');
192+
}
193+
194+
console.log(`Completed run of the cds-extractor.js script for the CDS extractor.`);
195+
process.exit(0); // Graceful exit to skip the rest of the processing
145196
}
146197
} catch (error) {
147-
cdsExtractorLog('error', `Failed to build CDS dependency graph: ${String(error)}`);
148-
// Exit with error since we can't continue without a proper dependency graph
149-
logExtractorStop(false, 'Terminated: Dependency graph build failed');
150-
process.exit(1);
198+
const errorMessage = `Failed to build CDS dependency graph: ${String(error)}`;
199+
cdsExtractorLog('error', errorMessage);
200+
201+
// Add diagnostic for dependency graph build failure
202+
if (codeqlExePath) {
203+
addDependencyGraphDiagnostic(sourceRoot, errorMessage, codeqlExePath);
204+
}
205+
206+
// Continue with a warning instead of exiting - let JavaScript extractor proceed with non-CDS files
207+
logExtractorStop(
208+
false,
209+
'Warning: Dependency graph build failed, skipping CDS-specific processing',
210+
);
211+
212+
// Skip the rest of CDS processing and go directly to JavaScript extraction
213+
configureLgtmIndexFilters();
214+
215+
// Run CodeQL's JavaScript extractor to process any remaining files
216+
logPerformanceTrackingStart('JavaScript Extraction');
217+
const extractorResult = runJavaScriptExtractor(
218+
sourceRoot,
219+
autobuildScriptPath || '', // Use empty string if autobuildScriptPath is undefined
220+
codeqlExePath,
221+
);
222+
logPerformanceTrackingStop('JavaScript Extraction');
223+
224+
if (!extractorResult.success && extractorResult.error) {
225+
cdsExtractorLog('error', `Error running JavaScript extractor: ${extractorResult.error}`);
226+
if (codeqlExePath) {
227+
addJavaScriptExtractorDiagnostic(sourceRoot, extractorResult.error, codeqlExePath);
228+
}
229+
logExtractorStop(false, 'JavaScript extractor failed');
230+
} else {
231+
logExtractorStop(true, 'JavaScript extraction completed (CDS processing was skipped)');
232+
}
233+
234+
console.log(`Completed run of the cds-extractor.js script for the CDS extractor.`);
235+
process.exit(0); // Graceful exit to skip the rest of the processing
151236
}
152237

153238
logPerformanceTrackingStart('Dependency Installation');
@@ -163,12 +248,19 @@ if (projectCacheDirMap.size === 0) {
163248

164249
// This is a critical error if we have projects but no cache mappings
165250
if (dependencyGraph.projects.size > 0) {
166-
cdsExtractorLog(
167-
'error',
168-
`Found ${dependencyGraph.projects.size} CDS projects but failed to install dependencies for any of them. Cannot proceed with compilation.`,
251+
const errorMessage = `Found ${dependencyGraph.projects.size} CDS projects but failed to install dependencies for any of them. Cannot proceed with compilation.`;
252+
cdsExtractorLog('error', errorMessage);
253+
254+
// Add diagnostic for dependency installation failure
255+
if (codeqlExePath) {
256+
addDependencyInstallationDiagnostic(sourceRoot, errorMessage, codeqlExePath);
257+
}
258+
259+
// Continue with a warning instead of exiting - let JavaScript extractor proceed
260+
logExtractorStop(
261+
false,
262+
'Warning: Dependency installation failed for all projects, continuing with limited functionality',
169263
);
170-
logExtractorStop(false, 'Terminated: Dependency installation failed for all projects');
171-
process.exit(1);
172264
}
173265

174266
// If we have no projects and no cache mappings, this should have been caught earlier
@@ -253,6 +345,15 @@ dependencyGraph.statusSummary.performance.totalDurationMs = totalDuration;
253345

254346
if (!extractorResult.success && extractorResult.error) {
255347
cdsExtractorLog('error', `Error running JavaScript extractor: ${extractorResult.error}`);
348+
349+
// Add diagnostic for JavaScript extractor failure
350+
if (codeqlExePath && dependencyGraph.projects.size > 0) {
351+
// Use the first CDS file as a representative file for the diagnostic
352+
const firstProject = Array.from(dependencyGraph.projects.values())[0];
353+
const representativeFile = firstProject.cdsFiles[0] || sourceRoot;
354+
addJavaScriptExtractorDiagnostic(representativeFile, extractorResult.error, codeqlExePath);
355+
}
356+
256357
logExtractorStop(false, 'JavaScript extractor failed');
257358
} else {
258359
logExtractorStop(true, 'CDS extraction completed successfully');

0 commit comments

Comments
 (0)