diff --git a/src/overlay/status.test.ts b/src/overlay/status.test.ts new file mode 100644 index 000000000..325988ebc --- /dev/null +++ b/src/overlay/status.test.ts @@ -0,0 +1,51 @@ +import test from "ava"; + +import { mockCodeQLVersion, setupTests } from "../testing-utils"; +import { DiskUsage } from "../util"; + +import { getCacheKey } from "./status"; + +setupTests(test); + +function makeDiskUsage(totalGiB: number): DiskUsage { + return { + numTotalBytes: totalGiB * 1024 * 1024 * 1024, + numAvailableBytes: 0, + }; +} + +test("getCacheKey incorporates language, CodeQL version, and disk space", async (t) => { + const codeql = mockCodeQLVersion("2.20.0"); + t.is( + await getCacheKey(codeql, "javascript", makeDiskUsage(50)), + "codeql-overlay-status-javascript-2.20.0-runner-50GB", + ); + t.is( + await getCacheKey(codeql, "python", makeDiskUsage(50)), + "codeql-overlay-status-python-2.20.0-runner-50GB", + ); + t.is( + await getCacheKey( + mockCodeQLVersion("2.21.0"), + "javascript", + makeDiskUsage(50), + ), + "codeql-overlay-status-javascript-2.21.0-runner-50GB", + ); + t.is( + await getCacheKey(codeql, "javascript", makeDiskUsage(100)), + "codeql-overlay-status-javascript-2.20.0-runner-100GB", + ); +}); + +test("getCacheKey rounds disk space down to nearest 10 GiB", async (t) => { + const codeql = mockCodeQLVersion("2.20.0"); + t.is( + await getCacheKey(codeql, "javascript", makeDiskUsage(14)), + "codeql-overlay-status-javascript-2.20.0-runner-10GB", + ); + t.is( + await getCacheKey(codeql, "javascript", makeDiskUsage(19)), + "codeql-overlay-status-javascript-2.20.0-runner-10GB", + ); +}); diff --git a/src/overlay/status.ts b/src/overlay/status.ts new file mode 100644 index 000000000..4695dce70 --- /dev/null +++ b/src/overlay/status.ts @@ -0,0 +1,31 @@ +/* + * We perform enablement checks for overlay analysis to avoid using it on runners that are too small + * to support it. However these checks cannot avoid every potential issue without being overly + * conservative. Therefore, if our enablement checks enable overlay analysis for a runner that is + * too small, we want to remember that, so that we will not try to use overlay analysis until + * something changes (e.g. a larger runner is provisioned, or a new CodeQL version is released). + * + * We use the Actions cache as a lightweight way of providing this functionality. + */ + +import { type CodeQL } from "../codeql"; +import { DiskUsage } from "../util"; + +export async function getCacheKey( + codeql: CodeQL, + language: string, + diskUsage: DiskUsage, +): Promise { + // Total disk space, rounded to the nearest 10 GB. This is included in the cache key so that if a + // customer upgrades their runner, we will try again to use overlay analysis, even if the CodeQL + // version has not changed. We round to the nearest 10 GB to work around small differences in disk + // space. + // + // Limitation: this can still flip from "too small" to "large enough" and back again if the disk + // space fluctuates above and below a multiple of 10 GB. + const diskSpaceToNearest10Gb = `${10 * Math.floor(diskUsage.numTotalBytes / (10 * 1024 * 1024 * 1024))}GB`; + + // Include the CodeQL version in the cache key so we will try again to use overlay analysis when + // new queries and libraries that may be more efficient are released. + return `codeql-overlay-status-${language}-${(await codeql.getVersion()).version}-runner-${diskSpaceToNearest10Gb}`; +}