diff --git a/lib/analyze-action.js b/lib/analyze-action.js index 8b936b19d2..23e4d2c47b 100644 --- a/lib/analyze-action.js +++ b/lib/analyze-action.js @@ -91049,7 +91049,8 @@ async function uploadOverlayBaseDatabaseToCache(codeql, config, logger) { const cacheSaveKey = await getCacheSaveKey( config, codeQlVersion, - checkoutPath + checkoutPath, + logger ); logger.info( `Uploading overlay-base database to Actions cache with key ${cacheSaveKey}` @@ -91074,13 +91075,23 @@ async function uploadOverlayBaseDatabaseToCache(codeql, config, logger) { logger.info(`Successfully uploaded overlay-base database from ${dbLocation}`); return true; } -async function getCacheSaveKey(config, codeQlVersion, checkoutPath) { +async function getCacheSaveKey(config, codeQlVersion, checkoutPath, logger) { + let runId = 1; + let attemptId = 1; + try { + runId = getWorkflowRunID(); + attemptId = getWorkflowRunAttempt(); + } catch (e) { + logger.warning( + `Failed to get workflow run ID or attempt ID. Reason: ${getErrorMessage(e)}` + ); + } const sha = await getCommitOid(checkoutPath); const restoreKeyPrefix = await getCacheRestoreKeyPrefix( config, codeQlVersion ); - return `${restoreKeyPrefix}${sha}`; + return `${restoreKeyPrefix}${sha}-${runId}-${attemptId}`; } async function getCacheRestoreKeyPrefix(config, codeQlVersion) { const languages = [...config.languages].sort().join("_"); diff --git a/src/overlay-database-utils.test.ts b/src/overlay-database-utils.test.ts index ca52f1d88a..cee0d45f13 100644 --- a/src/overlay-database-utils.test.ts +++ b/src/overlay-database-utils.test.ts @@ -11,6 +11,8 @@ import * as gitUtils from "./git-utils"; import { getRunnerLogger } from "./logging"; import { downloadOverlayBaseDatabaseFromCache, + getCacheRestoreKeyPrefix, + getCacheSaveKey, OverlayDatabaseMode, writeBaseDatabaseOidsFile, writeOverlayChangesFile, @@ -261,3 +263,48 @@ test( }, false, ); + +test("overlay-base database cache keys remain stable", async (t) => { + const logger = getRunnerLogger(true); + const config = createTestConfig({ languages: ["python", "javascript"] }); + const codeQlVersion = "2.23.0"; + const commitOid = "abc123def456"; + + sinon.stub(apiClient, "getAutomationID").resolves("test-automation-id/"); + sinon.stub(gitUtils, "getCommitOid").resolves(commitOid); + sinon.stub(actionsUtil, "getWorkflowRunID").returns(12345); + sinon.stub(actionsUtil, "getWorkflowRunAttempt").returns(1); + + const saveKey = await getCacheSaveKey( + config, + codeQlVersion, + "checkout-path", + logger, + ); + const expectedSaveKey = + "codeql-overlay-base-database-1-c5666c509a2d9895-javascript_python-2.23.0-abc123def456-12345-1"; + t.is( + saveKey, + expectedSaveKey, + "Cache save key changed unexpectedly. " + + "This may indicate breaking changes in the cache key generation logic.", + ); + + const restoreKeyPrefix = await getCacheRestoreKeyPrefix( + config, + codeQlVersion, + ); + const expectedRestoreKeyPrefix = + "codeql-overlay-base-database-1-c5666c509a2d9895-javascript_python-2.23.0-"; + t.is( + restoreKeyPrefix, + expectedRestoreKeyPrefix, + "Cache restore key prefix changed unexpectedly. " + + "This may indicate breaking changes in the cache key generation logic.", + ); + + t.true( + saveKey.startsWith(restoreKeyPrefix), + `Expected save key "${saveKey}" to start with restore key prefix "${restoreKeyPrefix}"`, + ); +}); diff --git a/src/overlay-database-utils.ts b/src/overlay-database-utils.ts index 1de76fef77..7934c50140 100644 --- a/src/overlay-database-utils.ts +++ b/src/overlay-database-utils.ts @@ -4,13 +4,19 @@ import * as path from "path"; import * as actionsCache from "@actions/cache"; -import { getRequiredInput, getTemporaryDirectory } from "./actions-util"; +import { + getRequiredInput, + getTemporaryDirectory, + getWorkflowRunAttempt, + getWorkflowRunID, +} from "./actions-util"; import { getAutomationID } from "./api-client"; import { type CodeQL } from "./codeql"; import { type Config } from "./config-utils"; import { getCommitOid, getFileOidsUnderPath } from "./git-utils"; import { Logger, withGroupAsync } from "./logging"; import { + getErrorMessage, isInTestMode, tryGetFolderBytes, waitForResultWithTimeLimit, @@ -271,6 +277,7 @@ export async function uploadOverlayBaseDatabaseToCache( config, codeQlVersion, checkoutPath, + logger, ); logger.info( `Uploading overlay-base database to Actions cache with key ${cacheSaveKey}`, @@ -448,17 +455,28 @@ export async function downloadOverlayBaseDatabaseFromCache( * The key consists of the restore key prefix (which does not include the * commit SHA) and the commit SHA of the current checkout. */ -async function getCacheSaveKey( +export async function getCacheSaveKey( config: Config, codeQlVersion: string, checkoutPath: string, + logger: Logger, ): Promise { + let runId = 1; + let attemptId = 1; + try { + runId = getWorkflowRunID(); + attemptId = getWorkflowRunAttempt(); + } catch (e) { + logger.warning( + `Failed to get workflow run ID or attempt ID. Reason: ${getErrorMessage(e)}`, + ); + } const sha = await getCommitOid(checkoutPath); const restoreKeyPrefix = await getCacheRestoreKeyPrefix( config, codeQlVersion, ); - return `${restoreKeyPrefix}${sha}`; + return `${restoreKeyPrefix}${sha}-${runId}-${attemptId}`; } /** @@ -475,7 +493,7 @@ async function getCacheSaveKey( * not include the commit SHA. This allows us to restore the most recent * compatible overlay-base database. */ -async function getCacheRestoreKeyPrefix( +export async function getCacheRestoreKeyPrefix( config: Config, codeQlVersion: string, ): Promise {