mirror of
https://github.com/github/codeql-action.git
synced 2026-10-21 02:01:27 +00:00
Delete unused CodeQL bundles from the toolcache before downloading
When we download a bundle the toolcache often already holds a different one that the job will not use, and on GitHub-hosted runners it shares a filesystem with the workspace, so it takes space away from the analysis. Empty the toolcache before downloading, which also frees space for the archive during extraction, and which is safe because getting as far as a download means the tools were not resolved from the toolcache. Skip this once a step has obtained the tools, since a later step may run a path it was given, and gate it on the runner being GitHub-hosted and on a feature flag that is off by default. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -2,6 +2,7 @@ import * as fs from "fs";
|
||||
import { OutgoingHttpHeaders } from "http";
|
||||
import * as path from "path";
|
||||
|
||||
import * as core from "@actions/core";
|
||||
import * as toolcache from "@actions/tool-cache";
|
||||
import { default as deepEqual } from "fast-deep-equal";
|
||||
import * as semver from "semver";
|
||||
@@ -10,6 +11,7 @@ import { v4 as uuidV4 } from "uuid";
|
||||
import {
|
||||
isAnalyzingPullRequest,
|
||||
isDynamicWorkflow,
|
||||
isGitHubHostedRunner,
|
||||
isRunningLocalAction,
|
||||
} from "./actions-util";
|
||||
import * as api from "./api-client";
|
||||
@@ -19,6 +21,7 @@ import {
|
||||
makeDiagnostic,
|
||||
makeTelemetryDiagnostic,
|
||||
} from "./diagnostics";
|
||||
import { EnvVar } from "./environment";
|
||||
import {
|
||||
CODEQL_VERSION_ZSTD_BUNDLE,
|
||||
CodeQLDefaultVersionInfo,
|
||||
@@ -30,8 +33,10 @@ import { Logger } from "./logging";
|
||||
import { getCodeQlVersionsForOverlayBaseDatabases } from "./overlay/caching";
|
||||
import * as tar from "./tar";
|
||||
import {
|
||||
deleteToolcacheBundles,
|
||||
downloadAndExtract,
|
||||
getToolcacheDirectory,
|
||||
ToolcacheCleanupResult,
|
||||
ToolsDownloadStatusReport,
|
||||
writeToolcacheMarkerFile,
|
||||
} from "./tools-download";
|
||||
@@ -784,6 +789,7 @@ export const downloadCodeQL = async function (
|
||||
apiDetails: api.GitHubApiDetails,
|
||||
tarVersion: tar.TarVersion | undefined,
|
||||
tempDir: string,
|
||||
features: FeatureEnablement,
|
||||
logger: Logger,
|
||||
): Promise<{
|
||||
codeqlFolder: string;
|
||||
@@ -817,6 +823,8 @@ export const downloadCodeQL = async function (
|
||||
const extractedBundlePath =
|
||||
toolcacheInfo?.path ?? getTempExtractionDir(tempDir);
|
||||
|
||||
await tryDeleteToolcacheBundles(toolcacheInfo?.version, features, logger);
|
||||
|
||||
const statusReport = await downloadAndExtract(
|
||||
codeqlURL,
|
||||
compressionMethod,
|
||||
@@ -869,6 +877,60 @@ function getToolcacheDestinationInfo(
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reclaims disk space by deleting the CodeQL tools from the toolcache, if enabled.
|
||||
*
|
||||
* On GitHub-hosted runners the toolcache shares a filesystem with the workspace, so tools left in
|
||||
* the toolcache take up space that the analysis could use instead.
|
||||
*
|
||||
* @param destinationVersion The toolcache version number that the tools will be stored under, or
|
||||
* `undefined` if they will not be stored in the toolcache.
|
||||
*/
|
||||
async function tryDeleteToolcacheBundles(
|
||||
destinationVersion: string | undefined,
|
||||
features: FeatureEnablement,
|
||||
logger: Logger,
|
||||
): Promise<void> {
|
||||
// A step that has already obtained the CodeQL tools may hand out a path into the toolcache that a
|
||||
// later step runs, so only the first step to obtain them can know that nothing else relies on it.
|
||||
if (util.getOptionalEnvVar(EnvVar.HAS_OBTAINED_CODEQL_TOOLS) !== undefined) {
|
||||
logger.debug(
|
||||
"Not deleting the CodeQL tools from the toolcache since a previous step in this job has " +
|
||||
"already obtained them.",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// If we are not going to add the tools to the toolcache, we are extracting them somewhere else
|
||||
// and emptying the toolcache would not buy us the space we need.
|
||||
if (
|
||||
destinationVersion === undefined ||
|
||||
!isGitHubHostedRunner() ||
|
||||
!(await features.getValue(Feature.CleanupToolcacheBundles))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
let result: ToolcacheCleanupResult = { deletedVersions: [], failed: true };
|
||||
|
||||
try {
|
||||
result = await deleteToolcacheBundles(logger);
|
||||
} catch (e) {
|
||||
logger.info(
|
||||
`Unable to reclaim disk space from the toolcache: ${util.getErrorMessage(e)}`,
|
||||
);
|
||||
}
|
||||
|
||||
addNoLanguageDiagnostic(
|
||||
undefined,
|
||||
makeTelemetryDiagnostic(
|
||||
"codeql-action/toolcache-bundle-cleanup",
|
||||
"Toolcache CodeQL bundle cleanup",
|
||||
{ ...result },
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
export function getCodeQLURLVersion(url: string): string {
|
||||
const match = url.match(/\/codeql-bundle-(.*)\//);
|
||||
if (match === null || match.length < 2) {
|
||||
@@ -978,6 +1040,7 @@ export async function setupCodeQLBundle(
|
||||
apiDetails,
|
||||
zstdAvailability.version,
|
||||
tempDir,
|
||||
features,
|
||||
logger,
|
||||
);
|
||||
toolsVersion = result.toolsVersion;
|
||||
@@ -989,6 +1052,11 @@ export async function setupCodeQLBundle(
|
||||
default:
|
||||
util.assertNever(source);
|
||||
}
|
||||
|
||||
// Record that this job now has a copy of the CodeQL tools, so that a later step doesn't delete
|
||||
// the toolcache out from under the path we are about to return.
|
||||
core.exportVariable(EnvVar.HAS_OBTAINED_CODEQL_TOOLS, "true");
|
||||
|
||||
return {
|
||||
codeqlFolder,
|
||||
toolsDownloadStatusReport,
|
||||
|
||||
Reference in New Issue
Block a user