Skip to content

Commit 5e930d3

Browse files
committed
refactor: fall back to non-overlay analysis when diff-informed analysis is unavailable
1 parent 34950e1 commit 5e930d3

File tree

4 files changed

+160
-0
lines changed

4 files changed

+160
-0
lines changed

lib/init-action.js

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

src/init-action.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import {
4040
import {
4141
getDiffInformedAnalysisBranches,
4242
getPullRequestEditedDiffRanges,
43+
shouldPerformDiffInformedAnalysis,
4344
writeDiffRangesJsonFile,
4445
} from "./diff-informed-analysis-utils";
4546
import { EnvVar } from "./environment";
@@ -64,6 +65,7 @@ import {
6465
downloadOverlayBaseDatabaseFromCache,
6566
OverlayBaseDatabaseDownloadStats,
6667
OverlayDatabaseMode,
68+
revertOverlayModeIfDiffInformedUnavailable,
6769
} from "./overlay";
6870
import { getRepositoryNwo, RepositoryNwo } from "./repository";
6971
import { ToolsSource } from "./setup-codeql";
@@ -438,6 +440,27 @@ async function run(startedAt: Date) {
438440
return;
439441
}
440442

443+
let diffInformedAnalysisExpected = false;
444+
try {
445+
diffInformedAnalysisExpected = await shouldPerformDiffInformedAnalysis(
446+
codeql,
447+
features,
448+
logger,
449+
);
450+
} catch (e) {
451+
logger.warning(
452+
`Failed to determine diff-informed analysis availability: ${getErrorMessage(e)}`,
453+
);
454+
// Treat errors conservatively: assume diff-informed was expected so that
455+
// the overlay fallback triggers if the diff ranges file is missing.
456+
diffInformedAnalysisExpected = true;
457+
}
458+
revertOverlayModeIfDiffInformedUnavailable(
459+
config,
460+
diffInformedAnalysisExpected,
461+
logger,
462+
);
463+
441464
let overlayBaseDatabaseStats: OverlayBaseDatabaseDownloadStats | undefined;
442465
let dependencyCachingStatus: DependencyCacheRestoreStatusReport | undefined;
443466
try {

src/overlay/index.test.ts

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {
2424
getCacheRestoreKeyPrefix,
2525
getCacheSaveKey,
2626
OverlayDatabaseMode,
27+
revertOverlayModeIfDiffInformedUnavailable,
2728
writeBaseDatabaseOidsFile,
2829
writeOverlayChangesFile,
2930
} from ".";
@@ -602,3 +603,77 @@ test.serial("overlay-base database cache keys remain stable", async (t) => {
602603
`Expected save key "${saveKey}" to start with restore key prefix "${restoreKeyPrefix}"`,
603604
);
604605
});
606+
607+
test.serial(
608+
"revertOverlayModeIfDiffInformedUnavailable: no-op when mode is not Overlay",
609+
(t) => {
610+
const config = createTestConfig({});
611+
config.overlayDatabaseMode = OverlayDatabaseMode.None;
612+
const logger = getRunnerLogger(true);
613+
614+
revertOverlayModeIfDiffInformedUnavailable(config, true, logger);
615+
616+
t.is(config.overlayDatabaseMode, OverlayDatabaseMode.None);
617+
},
618+
);
619+
620+
test.serial(
621+
"revertOverlayModeIfDiffInformedUnavailable: no-op when diff ranges file exists",
622+
async (t) => {
623+
await withTmpDir(async (tmpDir) => {
624+
const config = createTestConfig({});
625+
config.overlayDatabaseMode = OverlayDatabaseMode.Overlay;
626+
const logger = getRunnerLogger(true);
627+
628+
// Create the diff ranges file so it exists
629+
const diffRangesPath = path.join(tmpDir, "pr-diff-range.json");
630+
await fs.promises.writeFile(diffRangesPath, "[]");
631+
const stub = sinon
632+
.stub(actionsUtil, "getDiffRangesJsonFilePath")
633+
.returns(diffRangesPath);
634+
635+
try {
636+
revertOverlayModeIfDiffInformedUnavailable(config, true, logger);
637+
t.is(config.overlayDatabaseMode, OverlayDatabaseMode.Overlay);
638+
} finally {
639+
stub.restore();
640+
}
641+
});
642+
},
643+
);
644+
645+
test.serial(
646+
"revertOverlayModeIfDiffInformedUnavailable: reverts to None when diff ranges file is missing",
647+
(t) => {
648+
const config = createTestConfig({});
649+
config.overlayDatabaseMode =
650+
OverlayDatabaseMode.Overlay as OverlayDatabaseMode;
651+
const logger = getRunnerLogger(true);
652+
653+
const stub = sinon
654+
.stub(actionsUtil, "getDiffRangesJsonFilePath")
655+
.returns("/nonexistent/path/pr-diff-range.json");
656+
657+
try {
658+
revertOverlayModeIfDiffInformedUnavailable(config, true, logger);
659+
t.is(
660+
config.overlayDatabaseMode,
661+
OverlayDatabaseMode.None as OverlayDatabaseMode,
662+
);
663+
} finally {
664+
stub.restore();
665+
}
666+
},
667+
);
668+
669+
test.serial(
670+
"revertOverlayModeIfDiffInformedUnavailable: no-op when diff-informed analysis is not expected",
671+
(t) => {
672+
const config = createTestConfig({});
673+
config.overlayDatabaseMode = OverlayDatabaseMode.Overlay;
674+
const logger = getRunnerLogger(true);
675+
676+
revertOverlayModeIfDiffInformedUnavailable(config, false, logger);
677+
t.is(config.overlayDatabaseMode, OverlayDatabaseMode.Overlay);
678+
},
679+
);

src/overlay/index.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,39 @@ const OVERLAY_BASE_DATABASE_MAX_UPLOAD_SIZE_MB = 7500;
6262
const OVERLAY_BASE_DATABASE_MAX_UPLOAD_SIZE_BYTES =
6363
OVERLAY_BASE_DATABASE_MAX_UPLOAD_SIZE_MB * 1_000_000;
6464

65+
/**
66+
* If overlay analysis is enabled but diff-informed analysis failed to produce
67+
* its output file, reverts the overlay database mode to `None`. Overlay
68+
* without diff-informed is an untested combination that can produce inaccurate
69+
* results, so we fall back to a full non-overlay analysis instead.
70+
*
71+
* @param config The configuration object whose `overlayDatabaseMode` may be mutated.
72+
* @param diffInformedAnalysisExpected Whether diff-informed analysis was expected
73+
* to run for this workflow. When true and the diff ranges file is missing, the
74+
* overlay mode is reverted.
75+
* @param logger The logger instance.
76+
*/
77+
export function revertOverlayModeIfDiffInformedUnavailable(
78+
config: Config,
79+
diffInformedAnalysisExpected: boolean,
80+
logger: Logger,
81+
): void {
82+
if (config.overlayDatabaseMode !== OverlayDatabaseMode.Overlay) {
83+
return;
84+
}
85+
86+
if (
87+
diffInformedAnalysisExpected &&
88+
!fs.existsSync(actionsUtil.getDiffRangesJsonFilePath())
89+
) {
90+
logger.warning(
91+
"Diff-informed analysis is not available for this pull request. " +
92+
`Reverting overlay database mode to ${OverlayDatabaseMode.None}.`,
93+
);
94+
config.overlayDatabaseMode = OverlayDatabaseMode.None;
95+
}
96+
}
97+
6598
/**
6699
* Writes a JSON file containing Git OIDs for all tracked files (represented
67100
* by path relative to the source root) under the source root. The file is

0 commit comments

Comments
 (0)