Skip to content

Commit fc03ec6

Browse files
committed
refactor: fall back to non-overlay analysis when diff-informed analysis is unavailable
1 parent ee09113 commit fc03ec6

File tree

5 files changed

+228
-95
lines changed

5 files changed

+228
-95
lines changed

lib/init-action.js

Lines changed: 59 additions & 37 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/config-utils.test.ts

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2199,3 +2199,64 @@ test.serial(
21992199
});
22002200
},
22012201
);
2202+
2203+
test.serial(
2204+
"applyIncrementalAnalysisSettings: no-op when mode is not Overlay and diff-informed is unavailable",
2205+
(t) => {
2206+
const config = createTestConfig({});
2207+
config.overlayDatabaseMode = OverlayDatabaseMode.None;
2208+
const logger = getRunnerLogger(true);
2209+
2210+
configUtils.applyIncrementalAnalysisSettings(config, false, logger);
2211+
2212+
t.is(config.overlayDatabaseMode, OverlayDatabaseMode.None);
2213+
t.deepEqual(config.extraQueryExclusions, []);
2214+
},
2215+
);
2216+
2217+
test.serial(
2218+
"applyIncrementalAnalysisSettings: keeps overlay mode and adds exclusions when diff-informed analysis is available",
2219+
(t) => {
2220+
const config = createTestConfig({});
2221+
config.overlayDatabaseMode = OverlayDatabaseMode.Overlay;
2222+
const logger = getRunnerLogger(true);
2223+
2224+
configUtils.applyIncrementalAnalysisSettings(config, true, logger);
2225+
2226+
t.is(config.overlayDatabaseMode, OverlayDatabaseMode.Overlay);
2227+
t.deepEqual(config.extraQueryExclusions, [
2228+
{ exclude: { tags: "exclude-from-incremental" } },
2229+
]);
2230+
},
2231+
);
2232+
2233+
test.serial(
2234+
"applyIncrementalAnalysisSettings: reverts to None without exclusions when diff-informed analysis is unavailable",
2235+
(t) => {
2236+
const config = createTestConfig({});
2237+
config.overlayDatabaseMode =
2238+
OverlayDatabaseMode.Overlay as OverlayDatabaseMode;
2239+
const logger = getRunnerLogger(true);
2240+
2241+
configUtils.applyIncrementalAnalysisSettings(config, false, logger);
2242+
2243+
t.is(config.overlayDatabaseMode, OverlayDatabaseMode.None);
2244+
t.deepEqual(config.extraQueryExclusions, []);
2245+
},
2246+
);
2247+
2248+
test.serial(
2249+
"applyIncrementalAnalysisSettings: adds exclusions for diff-informed-only runs",
2250+
(t) => {
2251+
const config = createTestConfig({});
2252+
config.overlayDatabaseMode = OverlayDatabaseMode.None;
2253+
const logger = getRunnerLogger(true);
2254+
2255+
configUtils.applyIncrementalAnalysisSettings(config, true, logger);
2256+
2257+
t.is(config.overlayDatabaseMode, OverlayDatabaseMode.None);
2258+
t.deepEqual(config.extraQueryExclusions, [
2259+
{ exclude: { tags: "exclude-from-incremental" } },
2260+
]);
2261+
},
2262+
);

src/config-utils.ts

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import {
3131
addNoLanguageDiagnostic,
3232
makeTelemetryDiagnostic,
3333
} from "./diagnostics";
34-
import { shouldPerformDiffInformedAnalysis } from "./diff-informed-analysis-utils";
34+
import { prepareDiffInformedAnalysis } from "./diff-informed-analysis-utils";
3535
import { EnvVar } from "./environment";
3636
import * as errorMessages from "./error-messages";
3737
import { Feature, FeatureEnablement } from "./feature-flags";
@@ -1075,6 +1075,32 @@ function hasQueryCustomisation(userConfig: UserConfig): boolean {
10751075
);
10761076
}
10771077

1078+
export function applyIncrementalAnalysisSettings(
1079+
config: Config,
1080+
diffInformedAnalysisAvailable: boolean,
1081+
logger: Logger,
1082+
): void {
1083+
if (
1084+
config.overlayDatabaseMode === OverlayDatabaseMode.Overlay &&
1085+
!diffInformedAnalysisAvailable
1086+
) {
1087+
logger.warning(
1088+
"Diff-informed analysis is not available for this pull request. " +
1089+
`Reverting overlay database mode to ${OverlayDatabaseMode.None}.`,
1090+
);
1091+
config.overlayDatabaseMode = OverlayDatabaseMode.None;
1092+
}
1093+
1094+
if (
1095+
config.overlayDatabaseMode === OverlayDatabaseMode.Overlay ||
1096+
diffInformedAnalysisAvailable
1097+
) {
1098+
config.extraQueryExclusions.push({
1099+
exclude: { tags: "exclude-from-incremental" },
1100+
});
1101+
}
1102+
}
1103+
10781104
/**
10791105
* Load and return the config.
10801106
*
@@ -1229,18 +1255,17 @@ export async function initConfig(
12291255
);
12301256
}
12311257

1232-
if (
1233-
config.overlayDatabaseMode === OverlayDatabaseMode.Overlay ||
1234-
(await shouldPerformDiffInformedAnalysis(
1235-
inputs.codeql,
1236-
inputs.features,
1237-
logger,
1238-
))
1239-
) {
1240-
config.extraQueryExclusions.push({
1241-
exclude: { tags: "exclude-from-incremental" },
1242-
});
1243-
}
1258+
const diffInformedAnalysisAvailable = await prepareDiffInformedAnalysis(
1259+
inputs.codeql,
1260+
inputs.features,
1261+
logger,
1262+
);
1263+
1264+
applyIncrementalAnalysisSettings(
1265+
config,
1266+
diffInformedAnalysisAvailable,
1267+
logger,
1268+
);
12441269

12451270
if (await isTrapCachingEnabled(features, config.overlayDatabaseMode)) {
12461271
const { trapCaches, trapCacheDownloadTime } = await downloadCacheWithTime(

src/diff-informed-analysis-utils.ts

Lines changed: 69 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ import type { PullRequestBranches } from "./actions-util";
55
import { getApiClient, getGitHubVersion } from "./api-client";
66
import type { CodeQL } from "./codeql";
77
import { Feature, FeatureEnablement } from "./feature-flags";
8-
import { Logger } from "./logging";
8+
import { Logger, withGroupAsync } from "./logging";
99
import { getRepositoryNwoFromEnv } from "./repository";
10-
import { GitHubVariant, satisfiesGHESVersion } from "./util";
10+
import { getErrorMessage, GitHubVariant, satisfiesGHESVersion } from "./util";
1111

1212
/**
1313
* This interface is an abbreviated version of the file diff object returned by
@@ -69,6 +69,46 @@ export async function getDiffInformedAnalysisBranches(
6969
return branches;
7070
}
7171

72+
/**
73+
* Prepares the diff ranges needed for diff-informed analysis for the current
74+
* run.
75+
*
76+
* @returns `true` if diff-informed analysis is ready to use for this run,
77+
* otherwise `false`.
78+
*/
79+
export async function prepareDiffInformedAnalysis(
80+
codeql: CodeQL,
81+
features: FeatureEnablement,
82+
logger: Logger,
83+
): Promise<boolean> {
84+
try {
85+
const branches = await getDiffInformedAnalysisBranches(
86+
codeql,
87+
features,
88+
logger,
89+
);
90+
if (!branches) {
91+
return false;
92+
}
93+
94+
return await withGroupAsync("Computing PR diff ranges", async () => {
95+
try {
96+
return await computeAndPersistDiffRanges(branches, logger);
97+
} catch (e) {
98+
logger.warning(
99+
`Failed to compute diff-informed analysis ranges: ${getErrorMessage(e)}`,
100+
);
101+
return false;
102+
}
103+
});
104+
} catch (e) {
105+
logger.warning(
106+
`Failed to determine diff-informed analysis availability: ${getErrorMessage(e)}`,
107+
);
108+
return false;
109+
}
110+
}
111+
72112
export interface DiffThunkRange {
73113
/** Relative path from the repository root, using forward slashes as separators. */
74114
path: string;
@@ -151,6 +191,33 @@ export async function getPullRequestEditedDiffRanges(
151191
return results;
152192
}
153193

194+
/**
195+
* Compute and persist the diff ranges for a pull request. This fetches the
196+
* diff from the GitHub API and writes it to the diff ranges JSON file so that
197+
* CodeQL can use it for diff-informed analysis.
198+
*
199+
* @param branches The base and head branches of the pull request, as returned
200+
* by `getDiffInformedAnalysisBranches`.
201+
* @param logger
202+
* @returns `true` if the diff ranges were successfully computed and persisted,
203+
* otherwise `false`.
204+
*/
205+
export async function computeAndPersistDiffRanges(
206+
branches: PullRequestBranches,
207+
logger: Logger,
208+
): Promise<boolean> {
209+
const ranges = await getPullRequestEditedDiffRanges(branches, logger);
210+
if (ranges === undefined) {
211+
return false;
212+
}
213+
writeDiffRangesJsonFile(logger, ranges);
214+
const distinctFiles = new Set(ranges.map((r) => r.path)).size;
215+
logger.info(
216+
`Persisted ${ranges.length} diff range(s) across ${distinctFiles} file(s).`,
217+
);
218+
return true;
219+
}
220+
154221
async function getFileDiffsWithBasehead(
155222
branches: PullRequestBranches,
156223
logger: Logger,

0 commit comments

Comments
 (0)