Skip to content

Commit 6ca06f4

Browse files
committed
Upload overlay-base database to actions cache
1 parent d42ce71 commit 6ca06f4

File tree

2 files changed

+118
-2
lines changed

2 files changed

+118
-2
lines changed

src/analyze-action.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import { EnvVar } from "./environment";
2727
import { Features } from "./feature-flags";
2828
import { Language } from "./languages";
2929
import { getActionsLogger, Logger } from "./logging";
30+
import { uploadOverlayBaseDatabaseToCache } from "./overlay-database-utils";
3031
import { getRepositoryNwo } from "./repository";
3132
import * as statusReport from "./status-report";
3233
import {
@@ -349,6 +350,9 @@ async function run() {
349350
// Possibly upload the database bundles for remote queries
350351
await uploadDatabases(repositoryNwo, config, apiDetails, logger);
351352

353+
// Possibly upload the overlay-base database to actions cache
354+
await uploadOverlayBaseDatabaseToCache(codeql, config, logger);
355+
352356
// Possibly upload the TRAP caches for later re-use
353357
const trapCacheUploadStartTime = performance.now();
354358
didUploadTrapCaches = await uploadTrapCaches(codeql, config, logger);

src/overlay-database-utils.ts

Lines changed: 114 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
import * as fs from "fs";
22
import * as path from "path";
33

4-
import { getTemporaryDirectory } from "./actions-util";
4+
import * as actionsCache from "@actions/cache";
5+
6+
import { getRequiredInput, getTemporaryDirectory } from "./actions-util";
7+
import { type CodeQL } from "./codeql";
58
import { type Config } from "./config-utils";
6-
import { getFileOidsUnderPath } from "./git-utils";
9+
import { getCommitOid, getFileOidsUnderPath } from "./git-utils";
710
import { Logger } from "./logging";
11+
import { isInTestMode, withTimeout } from "./util";
812

913
export enum OverlayDatabaseMode {
1014
Overlay = "overlay",
@@ -122,3 +126,111 @@ function computeChangedFiles(
122126
}
123127
return changes;
124128
}
129+
130+
// Constants for database caching
131+
const CACHE_VERSION = 1;
132+
const CACHE_PREFIX = "codeql-overlay-base-database";
133+
const MAX_CACHE_OPERATION_MS = 120_000; // Two minutes
134+
135+
/**
136+
* Uploads the overlay-base database to the GitHub Actions cache. If conditions
137+
* for uploading are not met, the function does nothing and returns false.
138+
*
139+
* This function uses the `checkout_path` input to determine the repository path
140+
* and works only when called from `analyze` or `upload-sarif`.
141+
*
142+
* @param codeql The CodeQL instance
143+
* @param config The configuration object
144+
* @param logger The logger instance
145+
* @returns A promise that resolves to true if the upload was performed and
146+
* successfully completed, or false otherwise
147+
*/
148+
export async function uploadOverlayBaseDatabaseToCache(
149+
codeql: CodeQL,
150+
config: Config,
151+
logger: Logger,
152+
): Promise<boolean> {
153+
const overlayDatabaseMode = config.augmentationProperties.overlayDatabaseMode;
154+
if (overlayDatabaseMode !== OverlayDatabaseMode.OverlayBase) {
155+
logger.debug(
156+
`Overlay database mode is ${overlayDatabaseMode}. ` +
157+
"Skip uploading overlay-base database to cache.",
158+
);
159+
return false;
160+
}
161+
if (!config.augmentationProperties.useOverlayDatabaseCaching) {
162+
logger.debug(
163+
"Overlay database caching is disabled. " +
164+
"Skip uploading overlay-base database to cache.",
165+
);
166+
return false;
167+
}
168+
if (isInTestMode()) {
169+
logger.debug(
170+
"In test mode. Skip uploading overlay-base database to cache.",
171+
);
172+
return false;
173+
}
174+
175+
// An overlay-base database should contain the base database OIDs file.
176+
// Verifying that the file exists serves as a sanity check.
177+
const baseDatabaseOidsFilePath = getBaseDatabaseOidsFilePath(config);
178+
if (!fs.existsSync(baseDatabaseOidsFilePath)) {
179+
logger.warning(
180+
"Cannot upload overlay-base database to cache: " +
181+
`${baseDatabaseOidsFilePath} does not exist`,
182+
);
183+
return false;
184+
}
185+
186+
const dbLocation = config.dbLocation;
187+
const codeQlVersion = (await codeql.getVersion()).version;
188+
const checkoutPath = getRequiredInput("checkout_path");
189+
const cacheKey = await generateCacheKey(config, codeQlVersion, checkoutPath);
190+
logger.info(
191+
`Uploading overlay-base database to Actions cache with key ${cacheKey}`,
192+
);
193+
194+
try {
195+
const cacheId = await withTimeout(
196+
MAX_CACHE_OPERATION_MS,
197+
actionsCache.saveCache([dbLocation], cacheKey),
198+
() => {},
199+
);
200+
if (cacheId === undefined) {
201+
logger.warning("Timed out while uploading overlay-base database");
202+
return false;
203+
}
204+
} catch (error) {
205+
logger.warning(
206+
"Failed to upload overlay-base database to cache: " +
207+
`${error instanceof Error ? error.message : String(error)}`,
208+
);
209+
return false;
210+
}
211+
logger.info(`Successfully uploaded overlay-base database from ${dbLocation}`);
212+
return true;
213+
}
214+
215+
async function generateCacheKey(
216+
config: Config,
217+
codeQlVersion: string,
218+
checkoutPath: string,
219+
): Promise<string> {
220+
const sha = await getCommitOid(checkoutPath);
221+
return `${getCacheRestoreKey(config, codeQlVersion)}${sha}`;
222+
}
223+
224+
function getCacheRestoreKey(config: Config, codeQlVersion: string): string {
225+
// The restore key (prefix) specifies which cached overlay-base databases are
226+
// compatible with the current analysis: the cached database must have the
227+
// same cache version and the same CodeQL bundle version.
228+
//
229+
// Actions cache supports using multiple restore keys to indicate preference.
230+
// Technically we prefer a cached overlay-base database with the same SHA as
231+
// we are analyzing. However, since overlay-base databases are built from the
232+
// default branch and used in PR analysis, it is exceedingly unlikely that
233+
// the commit SHA will ever be the same, so we can just leave it out.
234+
const languages = [...config.languages].sort().join("_");
235+
return `${CACHE_PREFIX}-${CACHE_VERSION}-${languages}-${codeQlVersion}-`;
236+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy