From 2a4d1eca6b732672fca26419579398455d4bbbb7 Mon Sep 17 00:00:00 2001 From: Henry Mercer Date: Mon, 2 Mar 2026 19:55:35 +0100 Subject: [PATCH] Add env var to enable file coverage on PRs --- lib/analyze-action.js | 9 +++++- lib/init-action.js | 8 ++++- src/analyze.ts | 17 +++++++--- src/environment.ts | 5 +++ src/init.test.ts | 72 +++++++++++++++++++++++++++++++++++++++++++ src/init.ts | 16 ++++++++-- 6 files changed, 119 insertions(+), 8 deletions(-) diff --git a/lib/analyze-action.js b/lib/analyze-action.js index eb6908c66..a51765db8 100644 --- a/lib/analyze-action.js +++ b/lib/analyze-action.js @@ -110807,7 +110807,14 @@ async function runQueries(sarifFolder, memoryFlag, threadsFlag, diffRangePackDir } if (!config.enableFileCoverageInformation) { const isOrgOwned = github2.context.payload.repository?.owner.type === "Organization"; - const reenableMessage = isOrgOwned ? ` To enable file coverage information on pull requests, set the '${"github-codeql-enable-file-coverage-on-prs" /* ENABLE_FILE_COVERAGE_ON_PRS */}' repository property to 'true'.` : ""; + let reenableMessage; + if (isOrgOwned) { + reenableMessage = ` To enable file coverage information on pull requests, set the '${"github-codeql-enable-file-coverage-on-prs" /* ENABLE_FILE_COVERAGE_ON_PRS */}' repository property to 'true'.`; + } else if (!isDefaultSetup()) { + reenableMessage = ` To enable file coverage information on pull requests, set the '${"CODEQL_ACTION_ENABLE_FILE_COVERAGE_ON_PRS" /* ENABLE_FILE_COVERAGE_ON_PRS */}' environment variable to 'true'.`; + } else { + reenableMessage = ""; + } logger.info( `To speed up pull request analysis, file coverage information is only enabled when analyzing the default branch and protected branches.${reenableMessage}` ); diff --git a/lib/init-action.js b/lib/init-action.js index 9f81a4a76..b824100a1 100644 --- a/lib/init-action.js +++ b/lib/init-action.js @@ -109056,9 +109056,15 @@ function cleanupDatabaseClusterDirectory(config, logger, options = {}, rmSync2 = async function getFileCoverageInformationEnabled(debugMode, repositoryNwo, features, repositoryProperties, logger) { if (debugMode) return true; if (!isAnalyzingPullRequest()) return true; + if (process.env["CODEQL_ACTION_ENABLE_FILE_COVERAGE_ON_PRS" /* ENABLE_FILE_COVERAGE_ON_PRS */] === "true") { + logger.info( + `File coverage information on pull requests has been enabled by the '${"CODEQL_ACTION_ENABLE_FILE_COVERAGE_ON_PRS" /* ENABLE_FILE_COVERAGE_ON_PRS */}' environment variable. This may increase the time it takes to analyze pull requests, particularly on large repositories.` + ); + return true; + } if (repositoryProperties["github-codeql-enable-file-coverage-on-prs" /* ENABLE_FILE_COVERAGE_ON_PRS */] === true) { logger.info( - `File coverage information on pull requests has been enabled by the '${"github-codeql-enable-file-coverage-on-prs" /* ENABLE_FILE_COVERAGE_ON_PRS */}' repository property. This will increase the time it takes to analyze pull requests, particularly on large repositories.` + `File coverage information on pull requests has been enabled by the '${"github-codeql-enable-file-coverage-on-prs" /* ENABLE_FILE_COVERAGE_ON_PRS */}' repository property. This may increase the time it takes to analyze pull requests, particularly on large repositories.` ); return true; } diff --git a/src/analyze.ts b/src/analyze.ts index 550856547..5cdb11967 100644 --- a/src/analyze.ts +++ b/src/analyze.ts @@ -6,7 +6,11 @@ import * as github from "@actions/github"; import * as io from "@actions/io"; import * as yaml from "js-yaml"; -import { getTemporaryDirectory, PullRequestBranches } from "./actions-util"; +import { + getTemporaryDirectory, + isDefaultSetup, + PullRequestBranches, +} from "./actions-util"; import * as analyses from "./analyses"; import { setupCppAutobuild } from "./autobuild"; import { type CodeQL } from "./codeql"; @@ -506,9 +510,14 @@ export async function runQueries( if (!config.enableFileCoverageInformation) { const isOrgOwned = github.context.payload.repository?.owner.type === "Organization"; - const reenableMessage = isOrgOwned - ? ` To enable file coverage information on pull requests, set the '${RepositoryPropertyName.ENABLE_FILE_COVERAGE_ON_PRS}' repository property to 'true'.` - : ""; + let reenableMessage: string; + if (isOrgOwned) { + reenableMessage = ` To enable file coverage information on pull requests, set the '${RepositoryPropertyName.ENABLE_FILE_COVERAGE_ON_PRS}' repository property to 'true'.`; + } else if (!isDefaultSetup()) { + reenableMessage = ` To enable file coverage information on pull requests, set the '${EnvVar.ENABLE_FILE_COVERAGE_ON_PRS}' environment variable to 'true'.`; + } else { + reenableMessage = ""; + } logger.info( `To speed up pull request analysis, file coverage information is only enabled when analyzing the default branch and protected branches.${reenableMessage}`, ); diff --git a/src/environment.ts b/src/environment.ts index 75fc3a7de..a8b2e9711 100644 --- a/src/environment.ts +++ b/src/environment.ts @@ -142,6 +142,11 @@ export enum EnvVar { */ ANALYSIS_KEY = "CODEQL_ACTION_ANALYSIS_KEY", + /** + * Whether to enable file coverage information on pull requests. + */ + ENABLE_FILE_COVERAGE_ON_PRS = "CODEQL_ACTION_ENABLE_FILE_COVERAGE_ON_PRS", + /** Used by Code Scanning Risk Assessment to communicate the assessment ID to the CodeQL Action. */ RISK_ASSESSMENT_ID = "CODEQL_ACTION_RISK_ASSESSMENT_ID", } diff --git a/src/init.test.ts b/src/init.test.ts index d7c679927..264fa7862 100644 --- a/src/init.test.ts +++ b/src/init.test.ts @@ -6,6 +6,7 @@ import * as sinon from "sinon"; import * as actionsUtil from "./actions-util"; import { createStubCodeQL } from "./codeql"; +import { EnvVar } from "./environment"; import { Feature } from "./feature-flags"; import { RepositoryPropertyName } from "./feature-flags/properties"; import { @@ -546,3 +547,74 @@ test("file coverage information enabled when repository property enables it on P ), ); }); + +test("file coverage information enabled when env var enables it on PRs", async (t) => { + sinon.stub(actionsUtil, "isAnalyzingPullRequest").returns(true); + process.env[EnvVar.ENABLE_FILE_COVERAGE_ON_PRS] = "true"; + t.teardown(() => { + delete process.env[EnvVar.ENABLE_FILE_COVERAGE_ON_PRS]; + }); + + const messages: LoggedMessage[] = []; + const logger = getRecordingLogger(messages); + + t.true( + await getFileCoverageInformationEnabled( + false, // debugMode + parseRepositoryNwo("github/codeql-action"), + createFeatures([Feature.SkipFileCoverageOnPrs]), + {}, + logger, + ), + ); + + t.true( + messages.some( + (m) => + m.type === "info" && + typeof m.message === "string" && + m.message.includes(EnvVar.ENABLE_FILE_COVERAGE_ON_PRS), + ), + ); +}); + +test("file coverage env var takes precedence over repository property", async (t) => { + sinon.stub(actionsUtil, "isAnalyzingPullRequest").returns(true); + process.env[EnvVar.ENABLE_FILE_COVERAGE_ON_PRS] = "true"; + t.teardown(() => { + delete process.env[EnvVar.ENABLE_FILE_COVERAGE_ON_PRS]; + }); + + const messages: LoggedMessage[] = []; + const logger = getRecordingLogger(messages); + + t.true( + await getFileCoverageInformationEnabled( + false, // debugMode + parseRepositoryNwo("github/codeql-action"), + createFeatures([Feature.SkipFileCoverageOnPrs]), + { + [RepositoryPropertyName.ENABLE_FILE_COVERAGE_ON_PRS]: true, + }, + logger, + ), + ); + + // Should mention the env var, not the repo property + t.true( + messages.some( + (m) => + m.type === "info" && + typeof m.message === "string" && + m.message.includes(EnvVar.ENABLE_FILE_COVERAGE_ON_PRS), + ), + ); + t.false( + messages.some( + (m) => + m.type === "info" && + typeof m.message === "string" && + m.message.includes(RepositoryPropertyName.ENABLE_FILE_COVERAGE_ON_PRS), + ), + ); +}); diff --git a/src/init.ts b/src/init.ts index 17abb713b..81e379b1e 100644 --- a/src/init.ts +++ b/src/init.ts @@ -13,6 +13,7 @@ import { import { GitHubApiDetails } from "./api-client"; import { CodeQL, setupCodeQL } from "./codeql"; import * as configUtils from "./config-utils"; +import { EnvVar } from "./environment"; import { CodeQLDefaultVersionInfo, Feature, @@ -317,6 +318,17 @@ export async function getFileCoverageInformationEnabled( // it is used to populate the status page. if (!isAnalyzingPullRequest()) return true; + // Allow users to opt in to file coverage on PRs via an environment variable. + if (process.env[EnvVar.ENABLE_FILE_COVERAGE_ON_PRS] === "true") { + logger.info( + "File coverage information on pull requests has been enabled by the " + + `'${EnvVar.ENABLE_FILE_COVERAGE_ON_PRS}' environment variable. ` + + "This may increase the time it takes to analyze pull requests, " + + "particularly on large repositories.", + ); + return true; + } + // Allow repository owners to opt in to file coverage on PRs via a // repository property. if ( @@ -326,8 +338,8 @@ export async function getFileCoverageInformationEnabled( logger.info( "File coverage information on pull requests has been enabled by the " + `'${RepositoryPropertyName.ENABLE_FILE_COVERAGE_ON_PRS}' repository property. ` + - "This will increase the time it takes to analyze pull requests, particularly on " + - "large repositories.", + "This may increase the time it takes to analyze pull requests, " + + "particularly on large repositories.", ); return true; }