From adf39dd33fc2c348e314b2fee8b62ef59bc7ba42 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Fri, 17 Oct 2025 11:16:00 +0100 Subject: [PATCH 1/6] Add function for `starting` status report --- lib/init-action.js | 25 ++++++++++++++----------- src/init-action.ts | 37 ++++++++++++++++++++++++++----------- 2 files changed, 40 insertions(+), 22 deletions(-) diff --git a/lib/init-action.js b/lib/init-action.js index a113b2728f..13c46ce34a 100644 --- a/lib/init-action.js +++ b/lib/init-action.js @@ -90683,6 +90683,19 @@ async function getWorkflowAbsolutePath(logger) { } // src/init-action.ts +async function sendStartingStatusReport(startedAt, config, logger) { + const statusReportBase = await createStatusReportBase( + "init" /* Init */, + "starting", + startedAt, + config, + await checkDiskUsage(logger), + logger + ); + if (statusReportBase !== void 0) { + await sendStatusReport(statusReportBase); + } +} async function sendCompletedStatusReport(startedAt, config, configFile, toolsDownloadStatusReport, toolsFeatureFlagsValid, toolsSource, toolsVersion, overlayBaseDatabaseStats, dependencyCachingResults, logger, error2) { const statusReportBase = await createStatusReportBase( "init" /* Init */, @@ -90773,17 +90786,7 @@ async function run() { getOptionalInput("source-root") || "" ); try { - const statusReportBase = await createStatusReportBase( - "init" /* Init */, - "starting", - startedAt, - config, - await checkDiskUsage(logger), - logger - ); - if (statusReportBase !== void 0) { - await sendStatusReport(statusReportBase); - } + await sendStartingStatusReport(startedAt, config, logger); const codeQLDefaultVersionInfo = await features.getDefaultCliVersion( gitHubVersion.type ); diff --git a/src/init-action.ts b/src/init-action.ts index 0dbe957a76..beef425e93 100644 --- a/src/init-action.ts +++ b/src/init-action.ts @@ -96,6 +96,31 @@ interface InitToolsDownloadFields { tools_feature_flags_valid?: boolean; } +/** + * Sends a status report indicating that the `init` Action is starting. + * + * @param startedAt + * @param config + * @param logger + */ +async function sendStartingStatusReport( + startedAt: Date, + config: configUtils.Config | undefined, + logger: Logger, +) { + const statusReportBase = await createStatusReportBase( + ActionName.Init, + "starting", + startedAt, + config, + await checkDiskUsage(logger), + logger, + ); + if (statusReportBase !== undefined) { + await sendStatusReport(statusReportBase); + } +} + async function sendCompletedStatusReport( startedAt: Date, config: configUtils.Config | undefined, @@ -227,17 +252,7 @@ async function run() { ); try { - const statusReportBase = await createStatusReportBase( - ActionName.Init, - "starting", - startedAt, - config, - await checkDiskUsage(logger), - logger, - ); - if (statusReportBase !== undefined) { - await sendStatusReport(statusReportBase); - } + await sendStartingStatusReport(startedAt, config, logger); const codeQLDefaultVersionInfo = await features.getDefaultCliVersion( gitHubVersion.type, ); From bc93b04b0ca361d2da9e6dece7b00c0bf4d93eb2 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Fri, 17 Oct 2025 11:43:00 +0100 Subject: [PATCH 2/6] Add `initAnalysisKinds` for `analysis-kinds` enablement logic --- src/analyses.test.ts | 33 ++++++++++++++++++++++++++++++++ src/analyses.ts | 45 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 77 insertions(+), 1 deletion(-) diff --git a/src/analyses.test.ts b/src/analyses.test.ts index 2c314c2c1a..e48cc47d5e 100644 --- a/src/analyses.test.ts +++ b/src/analyses.test.ts @@ -1,12 +1,19 @@ import test from "ava"; +import * as sinon from "sinon"; +import * as actionsUtil from "./actions-util"; import { AnalysisKind, + initAnalysisKinds, parseAnalysisKinds, supportedAnalysisKinds, } from "./analyses"; +import { getRunnerLogger } from "./logging"; +import { setupTests } from "./testing-utils"; import { ConfigurationError } from "./util"; +setupTests(test); + test("All known analysis kinds can be parsed successfully", async (t) => { for (const analysisKind of supportedAnalysisKinds) { t.deepEqual(await parseAnalysisKinds(analysisKind), [analysisKind]); @@ -34,3 +41,29 @@ test("Parsing analysis kinds requires at least one analysis kind", async (t) => instanceOf: ConfigurationError, }); }); + +test("initAnalysisKinds - returns expected analysis kinds for `analysis-kinds` input", async (t) => { + const requiredInputStub = sinon.stub(actionsUtil, "getRequiredInput"); + requiredInputStub + .withArgs("analysis-kinds") + .returns("code-scanning,code-quality"); + const result = await initAnalysisKinds(getRunnerLogger(true)); + t.assert(result.includes(AnalysisKind.CodeScanning)); + t.assert(result.includes(AnalysisKind.CodeQuality)); +}); + +test("initAnalysisKinds - includes `code-quality` when deprecated `quality-queries` input is used", async (t) => { + const requiredInputStub = sinon.stub(actionsUtil, "getRequiredInput"); + requiredInputStub.withArgs("analysis-kinds").returns("code-scanning"); + const optionalInputStub = sinon.stub(actionsUtil, "getOptionalInput"); + optionalInputStub.withArgs("quality-queries").returns("code-quality"); + const result = await initAnalysisKinds(getRunnerLogger(true)); + t.assert(result.includes(AnalysisKind.CodeScanning)); + t.assert(result.includes(AnalysisKind.CodeQuality)); +}); + +test("initAnalysisKinds - throws if `analysis-kinds` input is invalid", async (t) => { + const requiredInputStub = sinon.stub(actionsUtil, "getRequiredInput"); + requiredInputStub.withArgs("analysis-kinds").returns("no-such-thing"); + await t.throwsAsync(initAnalysisKinds(getRunnerLogger(true))); +}); diff --git a/src/analyses.ts b/src/analyses.ts index 7cac51a345..2c5d20b113 100644 --- a/src/analyses.ts +++ b/src/analyses.ts @@ -1,4 +1,8 @@ -import { fixCodeQualityCategory } from "./actions-util"; +import { + fixCodeQualityCategory, + getOptionalInput, + getRequiredInput, +} from "./actions-util"; import { Logger } from "./logging"; import { ConfigurationError } from "./util"; @@ -41,6 +45,45 @@ export async function parseAnalysisKinds( ); } +/** + * Initialises the analysis kinds for the analysis based on the `analysis-kinds` input. + * This function will also use the deprecated `quality-queries` input as an indicator to enable `code-quality`. + * If the `analysis-kinds` input cannot be parsed, a `ConfigurationError` is thrown. + * + * @param logger The logger to use. + * @returns The array of enabled analysis kinds. + * @throws A `ConfigurationError` if the `analysis-kinds` input cannot be parsed. + */ +export async function initAnalysisKinds( + logger: Logger, +): Promise { + const analysisKinds = await parseAnalysisKinds( + getRequiredInput("analysis-kinds"), + ); + + // Warn that `quality-queries` is deprecated if there is an argument for it. + const qualityQueriesInput = getOptionalInput("quality-queries"); + + if (qualityQueriesInput !== undefined) { + logger.warning( + "The `quality-queries` input is deprecated and will be removed in a future version of the CodeQL Action. " + + "Use the `analysis-kinds` input to configure different analysis kinds instead.", + ); + } + + // For backwards compatibility, add Code Quality to the enabled analysis kinds + // if an input to `quality-queries` was specified. We should remove this once + // `quality-queries` is no longer used. + if ( + !analysisKinds.includes(AnalysisKind.CodeQuality) && + qualityQueriesInput !== undefined + ) { + analysisKinds.push(AnalysisKind.CodeQuality); + } + + return analysisKinds; +} + /** The queries to use for Code Quality analyses. */ export const codeQualityQueries: string[] = ["code-quality"]; From 3c8d00aea0cc4dafc9d4d6f3e12d0f5b165bd4a9 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Fri, 17 Oct 2025 11:46:35 +0100 Subject: [PATCH 3/6] Initialise analysis kinds before `starting` status report --- lib/init-action.js | 77 +++++++++++++++++++++++----------------- src/config-utils.test.ts | 6 ++-- src/config-utils.ts | 18 ++-------- src/init-action.ts | 10 ++++-- 4 files changed, 56 insertions(+), 55 deletions(-) diff --git a/lib/init-action.js b/lib/init-action.js index 13c46ce34a..90b03bef68 100644 --- a/lib/init-action.js +++ b/lib/init-action.js @@ -86062,6 +86062,46 @@ function isAnalyzingPullRequest() { return getPullRequestBranches() !== void 0; } +// src/analyses.ts +var AnalysisKind = /* @__PURE__ */ ((AnalysisKind2) => { + AnalysisKind2["CodeScanning"] = "code-scanning"; + AnalysisKind2["CodeQuality"] = "code-quality"; + return AnalysisKind2; +})(AnalysisKind || {}); +var supportedAnalysisKinds = new Set(Object.values(AnalysisKind)); +async function parseAnalysisKinds(input) { + const components = input.split(","); + if (components.length < 1) { + throw new ConfigurationError( + "At least one analysis kind must be configured." + ); + } + for (const component of components) { + if (!supportedAnalysisKinds.has(component)) { + throw new ConfigurationError(`Unknown analysis kind: ${component}`); + } + } + return Array.from( + new Set(components.map((component) => component)) + ); +} +async function initAnalysisKinds(logger) { + const analysisKinds = await parseAnalysisKinds( + getRequiredInput("analysis-kinds") + ); + const qualityQueriesInput = getOptionalInput("quality-queries"); + if (qualityQueriesInput !== void 0) { + logger.warning( + "The `quality-queries` input is deprecated and will be removed in a future version of the CodeQL Action. Use the `analysis-kinds` input to configure different analysis kinds instead." + ); + } + if (!analysisKinds.includes("code-quality" /* CodeQuality */) && qualityQueriesInput !== void 0) { + analysisKinds.push("code-quality" /* CodeQuality */); + } + return analysisKinds; +} +var codeQualityQueries = ["code-quality"]; + // src/api-client.ts var core5 = __toESM(require_core()); var githubUtils = __toESM(require_utils4()); @@ -86254,31 +86294,6 @@ var fs9 = __toESM(require("fs")); var path11 = __toESM(require("path")); var import_perf_hooks = require("perf_hooks"); -// src/analyses.ts -var AnalysisKind = /* @__PURE__ */ ((AnalysisKind2) => { - AnalysisKind2["CodeScanning"] = "code-scanning"; - AnalysisKind2["CodeQuality"] = "code-quality"; - return AnalysisKind2; -})(AnalysisKind || {}); -var supportedAnalysisKinds = new Set(Object.values(AnalysisKind)); -async function parseAnalysisKinds(input) { - const components = input.split(","); - if (components.length < 1) { - throw new ConfigurationError( - "At least one analysis kind must be configured." - ); - } - for (const component of components) { - if (!supportedAnalysisKinds.has(component)) { - throw new ConfigurationError(`Unknown analysis kind: ${component}`); - } - } - return Array.from( - new Set(components.map((component) => component)) - ); -} -var codeQualityQueries = ["code-quality"]; - // src/config/db-config.ts var path7 = __toESM(require("path")); var semver2 = __toESM(require_semver2()); @@ -87691,10 +87706,8 @@ async function getRawLanguages(languagesInput, repository, sourceRoot, logger) { }; } async function initActionState({ - analysisKindsInput, languagesInput, queriesInput, - qualityQueriesInput, packsInput, buildModeInput, dbLocation, @@ -87710,12 +87723,9 @@ async function initActionState({ githubVersion, features, repositoryProperties, + analysisKinds, logger }, userConfig) { - const analysisKinds = await parseAnalysisKinds(analysisKindsInput); - if (!analysisKinds.includes("code-quality" /* CodeQuality */) && qualityQueriesInput !== void 0) { - analysisKinds.push("code-quality" /* CodeQuality */); - } const languages = await getLanguages( codeql, languagesInput, @@ -90786,7 +90796,8 @@ async function run() { getOptionalInput("source-root") || "" ); try { - await sendStartingStatusReport(startedAt, config, logger); + const analysisKinds = await initAnalysisKinds(logger); + await sendStartingStatusReport(startedAt, { analysisKinds }, logger); const codeQLDefaultVersionInfo = await features.getDefaultCliVersion( gitHubVersion.type ); @@ -90840,7 +90851,7 @@ async function run() { ); } config = await initConfig2({ - analysisKindsInput: getRequiredInput("analysis-kinds"), + analysisKinds, languagesInput: getOptionalInput("languages"), queriesInput: getOptionalInput("queries"), qualityQueriesInput, diff --git a/src/config-utils.test.ts b/src/config-utils.test.ts index 566a719ca0..2dab4ee601 100644 --- a/src/config-utils.test.ts +++ b/src/config-utils.test.ts @@ -49,7 +49,7 @@ function createTestInitConfigInputs( return Object.assign( {}, { - analysisKindsInput: "code-scanning", + analysisKinds: [AnalysisKind.CodeScanning], languagesInput: undefined, queriesInput: undefined, qualityQueriesInput: undefined, @@ -189,7 +189,7 @@ test("load code quality config", async (t) => { const config = await configUtils.initConfig( createTestInitConfigInputs({ - analysisKindsInput: "code-quality", + analysisKinds: [AnalysisKind.CodeQuality], languagesInput: languages, repository: { owner: "github", repo: "example" }, tempDir, @@ -273,7 +273,7 @@ test("initActionState doesn't throw if there are queries configured in the repos await t.notThrowsAsync(async () => { const config = await configUtils.initConfig( createTestInitConfigInputs({ - analysisKindsInput: "code-quality", + analysisKinds: [AnalysisKind.CodeQuality], languagesInput: languages, repository: { owner: "github", repo: "example" }, tempDir, diff --git a/src/config-utils.ts b/src/config-utils.ts index e6c87bf5a6..7c4dc72576 100644 --- a/src/config-utils.ts +++ b/src/config-utils.ts @@ -11,7 +11,6 @@ import { CodeQuality, codeQualityQueries, CodeScanning, - parseAnalysisKinds, } from "./analyses"; import * as api from "./api-client"; import { CachingKind, getCachingKind } from "./caching-utils"; @@ -373,7 +372,6 @@ export async function getRawLanguages( /** Inputs required to initialize a configuration. */ export interface InitConfigInputs { - analysisKindsInput: string; languagesInput: string | undefined; queriesInput: string | undefined; qualityQueriesInput: string | undefined; @@ -396,6 +394,7 @@ export interface InitConfigInputs { apiDetails: api.GitHubApiCombinedDetails; features: FeatureEnablement; repositoryProperties: RepositoryProperties; + analysisKinds: AnalysisKind[]; logger: Logger; } @@ -405,10 +404,8 @@ export interface InitConfigInputs { */ export async function initActionState( { - analysisKindsInput, languagesInput, queriesInput, - qualityQueriesInput, packsInput, buildModeInput, dbLocation, @@ -424,22 +421,11 @@ export async function initActionState( githubVersion, features, repositoryProperties, + analysisKinds, logger, }: InitConfigInputs, userConfig: UserConfig, ): Promise { - const analysisKinds = await parseAnalysisKinds(analysisKindsInput); - - // For backwards compatibility, add Code Quality to the enabled analysis kinds - // if an input to `quality-queries` was specified. We should remove this once - // `quality-queries` is no longer used. - if ( - !analysisKinds.includes(AnalysisKind.CodeQuality) && - qualityQueriesInput !== undefined - ) { - analysisKinds.push(AnalysisKind.CodeQuality); - } - const languages = await getLanguages( codeql, languagesInput, diff --git a/src/init-action.ts b/src/init-action.ts index beef425e93..dbad71bfdf 100644 --- a/src/init-action.ts +++ b/src/init-action.ts @@ -15,6 +15,7 @@ import { getTemporaryDirectory, persistInputs, } from "./actions-util"; +import { initAnalysisKinds } from "./analyses"; import { getGitHubVersion } from "./api-client"; import { getDependencyCachingEnabled, @@ -105,7 +106,7 @@ interface InitToolsDownloadFields { */ async function sendStartingStatusReport( startedAt: Date, - config: configUtils.Config | undefined, + config: Partial | undefined, logger: Logger, ) { const statusReportBase = await createStatusReportBase( @@ -252,7 +253,10 @@ async function run() { ); try { - await sendStartingStatusReport(startedAt, config, logger); + // This may throw a `ConfigurationError` before we have sent the `starting` status report. + const analysisKinds = await initAnalysisKinds(logger); + // Send a status report indicating that an analysis is starting. + await sendStartingStatusReport(startedAt, { analysisKinds }, logger); const codeQLDefaultVersionInfo = await features.getDefaultCliVersion( gitHubVersion.type, ); @@ -319,7 +323,7 @@ async function run() { } config = await initConfig({ - analysisKindsInput: getRequiredInput("analysis-kinds"), + analysisKinds, languagesInput: getOptionalInput("languages"), queriesInput: getOptionalInput("queries"), qualityQueriesInput, From 9bd9b03572e2bfc4559977c0c611a0bfab3f2708 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Fri, 17 Oct 2025 13:22:41 +0100 Subject: [PATCH 4/6] Remove now unused `qualityQueriesInput` from `InitConfigInputs` --- lib/init-action.js | 7 ------- src/config-utils.test.ts | 1 - src/config-utils.ts | 1 - src/init-action.ts | 11 ----------- 4 files changed, 20 deletions(-) diff --git a/lib/init-action.js b/lib/init-action.js index 90b03bef68..99d76a41d9 100644 --- a/lib/init-action.js +++ b/lib/init-action.js @@ -90844,17 +90844,10 @@ async function run() { logger.info("Experimental Rust analysis enabled"); } } - const qualityQueriesInput = getOptionalInput("quality-queries"); - if (qualityQueriesInput !== void 0) { - logger.warning( - "The `quality-queries` input is deprecated and will be removed in a future version of the CodeQL Action. Use the `analysis-kinds` input to configure different analysis kinds instead." - ); - } config = await initConfig2({ analysisKinds, languagesInput: getOptionalInput("languages"), queriesInput: getOptionalInput("queries"), - qualityQueriesInput, packsInput: getOptionalInput("packs"), buildModeInput: getOptionalInput("build-mode"), configFile, diff --git a/src/config-utils.test.ts b/src/config-utils.test.ts index 2dab4ee601..c7d20a46f3 100644 --- a/src/config-utils.test.ts +++ b/src/config-utils.test.ts @@ -52,7 +52,6 @@ function createTestInitConfigInputs( analysisKinds: [AnalysisKind.CodeScanning], languagesInput: undefined, queriesInput: undefined, - qualityQueriesInput: undefined, packsInput: undefined, configFile: undefined, dbLocation: undefined, diff --git a/src/config-utils.ts b/src/config-utils.ts index 7c4dc72576..25d7a949e5 100644 --- a/src/config-utils.ts +++ b/src/config-utils.ts @@ -374,7 +374,6 @@ export async function getRawLanguages( export interface InitConfigInputs { languagesInput: string | undefined; queriesInput: string | undefined; - qualityQueriesInput: string | undefined; packsInput: string | undefined; configFile: string | undefined; dbLocation: string | undefined; diff --git a/src/init-action.ts b/src/init-action.ts index dbad71bfdf..8a2f72d0d1 100644 --- a/src/init-action.ts +++ b/src/init-action.ts @@ -312,21 +312,10 @@ async function run() { } } - // Warn that `quality-queries` is deprecated if there is an argument for it. - const qualityQueriesInput = getOptionalInput("quality-queries"); - - if (qualityQueriesInput !== undefined) { - logger.warning( - "The `quality-queries` input is deprecated and will be removed in a future version of the CodeQL Action. " + - "Use the `analysis-kinds` input to configure different analysis kinds instead.", - ); - } - config = await initConfig({ analysisKinds, languagesInput: getOptionalInput("languages"), queriesInput: getOptionalInput("queries"), - qualityQueriesInput, packsInput: getOptionalInput("packs"), buildModeInput: getOptionalInput("build-mode"), configFile, From 57c7b0a8846ea6a4249e9adbb4c082c1eccf3233 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Fri, 17 Oct 2025 13:33:55 +0100 Subject: [PATCH 5/6] Rename `initAnalysisKinds` to `getAnalysisKinds` and cache results --- lib/init-action.js | 16 ++++++++++------ src/analyses.test.ts | 14 +++++++------- src/analyses.ts | 20 +++++++++++++++----- src/init-action.ts | 4 ++-- 4 files changed, 34 insertions(+), 20 deletions(-) diff --git a/lib/init-action.js b/lib/init-action.js index 99d76a41d9..0c7936f842 100644 --- a/lib/init-action.js +++ b/lib/init-action.js @@ -86085,8 +86085,12 @@ async function parseAnalysisKinds(input) { new Set(components.map((component) => component)) ); } -async function initAnalysisKinds(logger) { - const analysisKinds = await parseAnalysisKinds( +var cachedAnalysisKinds; +async function getAnalysisKinds(logger, skipCache = false) { + if (!skipCache && cachedAnalysisKinds !== void 0) { + return cachedAnalysisKinds; + } + cachedAnalysisKinds = await parseAnalysisKinds( getRequiredInput("analysis-kinds") ); const qualityQueriesInput = getOptionalInput("quality-queries"); @@ -86095,10 +86099,10 @@ async function initAnalysisKinds(logger) { "The `quality-queries` input is deprecated and will be removed in a future version of the CodeQL Action. Use the `analysis-kinds` input to configure different analysis kinds instead." ); } - if (!analysisKinds.includes("code-quality" /* CodeQuality */) && qualityQueriesInput !== void 0) { - analysisKinds.push("code-quality" /* CodeQuality */); + if (!cachedAnalysisKinds.includes("code-quality" /* CodeQuality */) && qualityQueriesInput !== void 0) { + cachedAnalysisKinds.push("code-quality" /* CodeQuality */); } - return analysisKinds; + return cachedAnalysisKinds; } var codeQualityQueries = ["code-quality"]; @@ -90796,7 +90800,7 @@ async function run() { getOptionalInput("source-root") || "" ); try { - const analysisKinds = await initAnalysisKinds(logger); + const analysisKinds = await getAnalysisKinds(logger); await sendStartingStatusReport(startedAt, { analysisKinds }, logger); const codeQLDefaultVersionInfo = await features.getDefaultCliVersion( gitHubVersion.type diff --git a/src/analyses.test.ts b/src/analyses.test.ts index e48cc47d5e..9178ffbd5a 100644 --- a/src/analyses.test.ts +++ b/src/analyses.test.ts @@ -4,7 +4,7 @@ import * as sinon from "sinon"; import * as actionsUtil from "./actions-util"; import { AnalysisKind, - initAnalysisKinds, + getAnalysisKinds, parseAnalysisKinds, supportedAnalysisKinds, } from "./analyses"; @@ -42,28 +42,28 @@ test("Parsing analysis kinds requires at least one analysis kind", async (t) => }); }); -test("initAnalysisKinds - returns expected analysis kinds for `analysis-kinds` input", async (t) => { +test("getAnalysisKinds - returns expected analysis kinds for `analysis-kinds` input", async (t) => { const requiredInputStub = sinon.stub(actionsUtil, "getRequiredInput"); requiredInputStub .withArgs("analysis-kinds") .returns("code-scanning,code-quality"); - const result = await initAnalysisKinds(getRunnerLogger(true)); + const result = await getAnalysisKinds(getRunnerLogger(true), true); t.assert(result.includes(AnalysisKind.CodeScanning)); t.assert(result.includes(AnalysisKind.CodeQuality)); }); -test("initAnalysisKinds - includes `code-quality` when deprecated `quality-queries` input is used", async (t) => { +test("getAnalysisKinds - includes `code-quality` when deprecated `quality-queries` input is used", async (t) => { const requiredInputStub = sinon.stub(actionsUtil, "getRequiredInput"); requiredInputStub.withArgs("analysis-kinds").returns("code-scanning"); const optionalInputStub = sinon.stub(actionsUtil, "getOptionalInput"); optionalInputStub.withArgs("quality-queries").returns("code-quality"); - const result = await initAnalysisKinds(getRunnerLogger(true)); + const result = await getAnalysisKinds(getRunnerLogger(true), true); t.assert(result.includes(AnalysisKind.CodeScanning)); t.assert(result.includes(AnalysisKind.CodeQuality)); }); -test("initAnalysisKinds - throws if `analysis-kinds` input is invalid", async (t) => { +test("getAnalysisKinds - throws if `analysis-kinds` input is invalid", async (t) => { const requiredInputStub = sinon.stub(actionsUtil, "getRequiredInput"); requiredInputStub.withArgs("analysis-kinds").returns("no-such-thing"); - await t.throwsAsync(initAnalysisKinds(getRunnerLogger(true))); + await t.throwsAsync(getAnalysisKinds(getRunnerLogger(true), true)); }); diff --git a/src/analyses.ts b/src/analyses.ts index 2c5d20b113..a8d172e3b6 100644 --- a/src/analyses.ts +++ b/src/analyses.ts @@ -45,19 +45,29 @@ export async function parseAnalysisKinds( ); } +// Used to avoid re-parsing the input after we have done it once. +let cachedAnalysisKinds: AnalysisKind[] | undefined; + /** * Initialises the analysis kinds for the analysis based on the `analysis-kinds` input. * This function will also use the deprecated `quality-queries` input as an indicator to enable `code-quality`. * If the `analysis-kinds` input cannot be parsed, a `ConfigurationError` is thrown. * * @param logger The logger to use. + * @param skipCache For testing, whether to ignore the cached values (default: false). + * * @returns The array of enabled analysis kinds. * @throws A `ConfigurationError` if the `analysis-kinds` input cannot be parsed. */ -export async function initAnalysisKinds( +export async function getAnalysisKinds( logger: Logger, + skipCache: boolean = false, ): Promise { - const analysisKinds = await parseAnalysisKinds( + if (!skipCache && cachedAnalysisKinds !== undefined) { + return cachedAnalysisKinds; + } + + cachedAnalysisKinds = await parseAnalysisKinds( getRequiredInput("analysis-kinds"), ); @@ -75,13 +85,13 @@ export async function initAnalysisKinds( // if an input to `quality-queries` was specified. We should remove this once // `quality-queries` is no longer used. if ( - !analysisKinds.includes(AnalysisKind.CodeQuality) && + !cachedAnalysisKinds.includes(AnalysisKind.CodeQuality) && qualityQueriesInput !== undefined ) { - analysisKinds.push(AnalysisKind.CodeQuality); + cachedAnalysisKinds.push(AnalysisKind.CodeQuality); } - return analysisKinds; + return cachedAnalysisKinds; } /** The queries to use for Code Quality analyses. */ diff --git a/src/init-action.ts b/src/init-action.ts index 8a2f72d0d1..5196550e27 100644 --- a/src/init-action.ts +++ b/src/init-action.ts @@ -15,7 +15,7 @@ import { getTemporaryDirectory, persistInputs, } from "./actions-util"; -import { initAnalysisKinds } from "./analyses"; +import { getAnalysisKinds } from "./analyses"; import { getGitHubVersion } from "./api-client"; import { getDependencyCachingEnabled, @@ -254,7 +254,7 @@ async function run() { try { // This may throw a `ConfigurationError` before we have sent the `starting` status report. - const analysisKinds = await initAnalysisKinds(logger); + const analysisKinds = await getAnalysisKinds(logger); // Send a status report indicating that an analysis is starting. await sendStartingStatusReport(startedAt, { analysisKinds }, logger); const codeQLDefaultVersionInfo = await features.getDefaultCliVersion( From fa7bdf055936bea552da9c58f425daa8bb13d51d Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Fri, 17 Oct 2025 13:40:18 +0100 Subject: [PATCH 6/6] Call `getAnalysisKinds` a second time, and ignore exceptions thrown during the first call --- lib/init-action.js | 18 +++++++++++++----- src/init-action.ts | 19 ++++++++++++++++--- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/lib/init-action.js b/lib/init-action.js index 0c7936f842..dea48d3bff 100644 --- a/lib/init-action.js +++ b/lib/init-action.js @@ -86063,10 +86063,10 @@ function isAnalyzingPullRequest() { } // src/analyses.ts -var AnalysisKind = /* @__PURE__ */ ((AnalysisKind2) => { - AnalysisKind2["CodeScanning"] = "code-scanning"; - AnalysisKind2["CodeQuality"] = "code-quality"; - return AnalysisKind2; +var AnalysisKind = /* @__PURE__ */ ((AnalysisKind3) => { + AnalysisKind3["CodeScanning"] = "code-scanning"; + AnalysisKind3["CodeQuality"] = "code-quality"; + return AnalysisKind3; })(AnalysisKind || {}); var supportedAnalysisKinds = new Set(Object.values(AnalysisKind)); async function parseAnalysisKinds(input) { @@ -90800,7 +90800,14 @@ async function run() { getOptionalInput("source-root") || "" ); try { - const analysisKinds = await getAnalysisKinds(logger); + let analysisKinds; + try { + analysisKinds = await getAnalysisKinds(logger); + } catch (err) { + logger.debug( + `Failed to parse analysis kinds for 'starting' status report: ${getErrorMessage(err)}` + ); + } await sendStartingStatusReport(startedAt, { analysisKinds }, logger); const codeQLDefaultVersionInfo = await features.getDefaultCliVersion( gitHubVersion.type @@ -90848,6 +90855,7 @@ async function run() { logger.info("Experimental Rust analysis enabled"); } } + analysisKinds = await getAnalysisKinds(logger); config = await initConfig2({ analysisKinds, languagesInput: getOptionalInput("languages"), diff --git a/src/init-action.ts b/src/init-action.ts index 5196550e27..c6bfb136e8 100644 --- a/src/init-action.ts +++ b/src/init-action.ts @@ -15,7 +15,7 @@ import { getTemporaryDirectory, persistInputs, } from "./actions-util"; -import { getAnalysisKinds } from "./analyses"; +import { AnalysisKind, getAnalysisKinds } from "./analyses"; import { getGitHubVersion } from "./api-client"; import { getDependencyCachingEnabled, @@ -253,8 +253,20 @@ async function run() { ); try { - // This may throw a `ConfigurationError` before we have sent the `starting` status report. - const analysisKinds = await getAnalysisKinds(logger); + // Parsing the `analysis-kinds` input may throw a `ConfigurationError`, which we don't want before + // we have called `sendStartingStatusReport` below. However, we want the analysis kinds for that status + // report. To work around this, we ignore exceptions that are thrown here and then call `getAnalysisKinds` + // a second time later. The second call will then throw the exception again. If `getAnalysisKinds` is + // successful, the results are cached so that we don't duplicate the work in normal runs. + let analysisKinds: AnalysisKind[] | undefined; + try { + analysisKinds = await getAnalysisKinds(logger); + } catch (err) { + logger.debug( + `Failed to parse analysis kinds for 'starting' status report: ${getErrorMessage(err)}`, + ); + } + // Send a status report indicating that an analysis is starting. await sendStartingStatusReport(startedAt, { analysisKinds }, logger); const codeQLDefaultVersionInfo = await features.getDefaultCliVersion( @@ -312,6 +324,7 @@ async function run() { } } + analysisKinds = await getAnalysisKinds(logger); config = await initConfig({ analysisKinds, languagesInput: getOptionalInput("languages"),