From 8d7024224de5e6338521a705834ae024556a5b9f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 5 Jul 2026 06:33:46 +0000 Subject: [PATCH 1/4] Initial plan From aa786259cfdd18ff93070b0a9a0c3a7179c53d02 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 5 Jul 2026 06:45:22 +0000 Subject: [PATCH 2/4] refactor: deduplicate skip query gate logic Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/check_skip_if_helpers.cjs | 72 ++++++++++++++++++- .../setup/js/check_skip_if_helpers.test.cjs | 62 ++++++++++++++++ actions/setup/js/check_skip_if_match.cjs | 63 +++++----------- actions/setup/js/check_skip_if_no_match.cjs | 63 +++++----------- 4 files changed, 165 insertions(+), 95 deletions(-) diff --git a/actions/setup/js/check_skip_if_helpers.cjs b/actions/setup/js/check_skip_if_helpers.cjs index 1ede805da65..9165de8eee6 100644 --- a/actions/setup/js/check_skip_if_helpers.cjs +++ b/actions/setup/js/check_skip_if_helpers.cjs @@ -1,6 +1,10 @@ // @ts-check /// +const { getErrorMessage } = require("./error_helpers.cjs"); +const { ERR_API, ERR_CONFIG } = require("./error_codes.cjs"); +const { writeDenialSummary } = require("./pre_activation_summary.cjs"); + /** * Builds the GitHub search query, optionally scoping it to the current repository. * @param {string} skipQuery - The base query string @@ -18,4 +22,70 @@ function buildSearchQuery(skipQuery, skipScope) { return searchQuery; } -module.exports = { buildSearchQuery }; +/** + * Shared runner for skip-if query gates. + * @param {{ + * skipQuery: string | undefined; + * workflowName: string | undefined; + * thresholdStr: string | undefined; + * thresholdEnvVar: string; + * thresholdLabel: string; + * checkLabel: string; + * outputName: string; + * skipScope: string | undefined; + * shouldSkip: (totalCount: number, threshold: number) => boolean; + * warningMessage: (totalCount: number, threshold: number) => string; + * successMessage: (totalCount: number, threshold: number) => string; + * denialSummaryMessage: (totalCount: number, threshold: number) => string; + * denialSummaryNextStep: string; + * }} options + */ +async function runSkipQueryGate(options) { + const { skipQuery, workflowName, thresholdStr = "1", thresholdEnvVar, thresholdLabel, checkLabel, outputName, skipScope, shouldSkip, warningMessage, successMessage, denialSummaryMessage, denialSummaryNextStep } = options; + + if (!skipQuery) { + core.setFailed(`${ERR_CONFIG}: Configuration error: GH_AW_SKIP_QUERY not specified.`); + return; + } + + if (!workflowName) { + core.setFailed(`${ERR_CONFIG}: Configuration error: GH_AW_WORKFLOW_NAME not specified.`); + return; + } + + const threshold = parseInt(thresholdStr, 10); + if (isNaN(threshold) || threshold < 1) { + core.setFailed(`${ERR_CONFIG}: Configuration error: ${thresholdEnvVar} must be a positive integer, got "${thresholdStr}".`); + return; + } + + core.info(`Checking ${checkLabel} query: ${skipQuery}`); + core.info(`${thresholdLabel}: ${threshold}`); + + const searchQuery = buildSearchQuery(skipQuery, skipScope); + + try { + const { + data: { total_count: totalCount }, + } = await github.rest.search.issuesAndPullRequests({ + q: searchQuery, + per_page: 1, + }); + + core.info(`Search found ${totalCount} matching items`); + + if (shouldSkip(totalCount, threshold)) { + core.warning(warningMessage(totalCount, threshold)); + core.setOutput(outputName, "false"); + await writeDenialSummary(denialSummaryMessage(totalCount, threshold), denialSummaryNextStep); + return; + } + + core.info(successMessage(totalCount, threshold)); + core.setOutput(outputName, "true"); + } catch (error) { + core.setFailed(`${ERR_API}: Failed to execute search query: ${getErrorMessage(error)}`); + } +} + +module.exports = { buildSearchQuery, runSkipQueryGate }; diff --git a/actions/setup/js/check_skip_if_helpers.test.cjs b/actions/setup/js/check_skip_if_helpers.test.cjs index 54ac24a41b1..05ce37c286e 100644 --- a/actions/setup/js/check_skip_if_helpers.test.cjs +++ b/actions/setup/js/check_skip_if_helpers.test.cjs @@ -69,6 +69,68 @@ describe("check_skip_if_helpers.cjs - buildSearchQuery", () => { }); }); + describe("check_skip_if_helpers.cjs - runSkipQueryGate", () => { + /** @returns {Promise<{runSkipQueryGate: (options: any) => Promise}>} */ + const loadModule = () => import("./check_skip_if_helpers.cjs"); + + beforeEach(() => { + global.github = { + rest: { + search: { + issuesAndPullRequests: vi.fn(), + }, + }, + }; + }); + + it("uses thresholdEnvVar in validation errors", async () => { + const { runSkipQueryGate } = await loadModule(); + + await runSkipQueryGate({ + skipQuery: "is:issue is:open", + workflowName: "test-workflow", + thresholdStr: "invalid", + thresholdEnvVar: "GH_AW_SKIP_MAX_MATCHES", + thresholdLabel: "Maximum matches threshold", + checkLabel: "skip-if-match", + outputName: "skip_check_ok", + skipScope: undefined, + shouldSkip: () => false, + warningMessage: () => "", + successMessage: () => "", + denialSummaryMessage: () => "", + denialSummaryNextStep: "", + }); + + expect(mockCore.setFailed).toHaveBeenCalledWith(expect.stringContaining("GH_AW_SKIP_MAX_MATCHES must be a positive integer")); + expect(global.github.rest.search.issuesAndPullRequests).not.toHaveBeenCalled(); + }); + + it("applies policy decision and output name when skip condition matches", async () => { + global.github.rest.search.issuesAndPullRequests.mockResolvedValue({ data: { total_count: 2 } }); + const { runSkipQueryGate } = await loadModule(); + + await runSkipQueryGate({ + skipQuery: "is:issue is:open", + workflowName: "test-workflow", + thresholdStr: "1", + thresholdEnvVar: "GH_AW_SKIP_MAX_MATCHES", + thresholdLabel: "Maximum matches threshold", + checkLabel: "skip-if-match", + outputName: "skip_check_ok", + skipScope: undefined, + shouldSkip: (totalCount, threshold) => totalCount >= threshold, + warningMessage: () => "skip warning", + successMessage: () => "success message", + denialSummaryMessage: () => "summary message", + denialSummaryNextStep: "summary next step", + }); + + expect(mockCore.warning).toHaveBeenCalledWith("skip warning"); + expect(mockCore.setOutput).toHaveBeenCalledWith("skip_check_ok", "false"); + }); + }); + describe("scope: default (repo-scoped)", () => { it("appends repo:owner/repo when skipScope is undefined", async () => { const { buildSearchQuery } = await loadModule(); diff --git a/actions/setup/js/check_skip_if_match.cjs b/actions/setup/js/check_skip_if_match.cjs index fc379c91e7a..a4dc5c23810 100644 --- a/actions/setup/js/check_skip_if_match.cjs +++ b/actions/setup/js/check_skip_if_match.cjs @@ -1,57 +1,26 @@ // @ts-check /// -const { getErrorMessage } = require("./error_helpers.cjs"); -const { ERR_API, ERR_CONFIG } = require("./error_codes.cjs"); -const { buildSearchQuery } = require("./check_skip_if_helpers.cjs"); -const { writeDenialSummary } = require("./pre_activation_summary.cjs"); +const { runSkipQueryGate } = require("./check_skip_if_helpers.cjs"); async function main() { const { GH_AW_SKIP_QUERY: skipQuery, GH_AW_WORKFLOW_NAME: workflowName, GH_AW_SKIP_MAX_MATCHES: maxMatchesStr = "1", GH_AW_SKIP_SCOPE: skipScope } = process.env; - if (!skipQuery) { - core.setFailed(`${ERR_CONFIG}: Configuration error: GH_AW_SKIP_QUERY not specified.`); - return; - } - - if (!workflowName) { - core.setFailed(`${ERR_CONFIG}: Configuration error: GH_AW_WORKFLOW_NAME not specified.`); - return; - } - - const maxMatches = parseInt(maxMatchesStr, 10); - if (isNaN(maxMatches) || maxMatches < 1) { - core.setFailed(`${ERR_CONFIG}: Configuration error: GH_AW_SKIP_MAX_MATCHES must be a positive integer, got "${maxMatchesStr}".`); - return; - } - - core.info(`Checking skip-if-match query: ${skipQuery}`); - core.info(`Maximum matches threshold: ${maxMatches}`); - - const searchQuery = buildSearchQuery(skipQuery, skipScope); - - try { - const { - data: { total_count: totalCount }, - } = await github.rest.search.issuesAndPullRequests({ - q: searchQuery, - per_page: 1, - }); - - core.info(`Search found ${totalCount} matching items`); - - if (totalCount >= maxMatches) { - core.warning(`🔍 Skip condition matched (${totalCount} items found, threshold: ${maxMatches}). Workflow execution will be prevented by activation job.`); - core.setOutput("skip_check_ok", "false"); - await writeDenialSummary(`Skip-if-match query matched: ${totalCount} item(s) found (threshold: ${maxMatches}).`, "Update `on.skip-if-match:` in the workflow frontmatter if this skip was unexpected."); - return; - } - - core.info(`✓ Found ${totalCount} matches (below threshold of ${maxMatches}), workflow can proceed`); - core.setOutput("skip_check_ok", "true"); - } catch (error) { - core.setFailed(`${ERR_API}: Failed to execute search query: ${getErrorMessage(error)}`); - } + await runSkipQueryGate({ + skipQuery, + workflowName, + thresholdStr: maxMatchesStr, + thresholdEnvVar: "GH_AW_SKIP_MAX_MATCHES", + thresholdLabel: "Maximum matches threshold", + checkLabel: "skip-if-match", + outputName: "skip_check_ok", + skipScope, + shouldSkip: (totalCount, threshold) => totalCount >= threshold, + warningMessage: (totalCount, threshold) => `🔍 Skip condition matched (${totalCount} items found, threshold: ${threshold}). Workflow execution will be prevented by activation job.`, + successMessage: (totalCount, threshold) => `✓ Found ${totalCount} matches (below threshold of ${threshold}), workflow can proceed`, + denialSummaryMessage: (totalCount, threshold) => `Skip-if-match query matched: ${totalCount} item(s) found (threshold: ${threshold}).`, + denialSummaryNextStep: "Update `on.skip-if-match:` in the workflow frontmatter if this skip was unexpected.", + }); } module.exports = { main }; diff --git a/actions/setup/js/check_skip_if_no_match.cjs b/actions/setup/js/check_skip_if_no_match.cjs index b3edfef7803..6d67cf8f032 100644 --- a/actions/setup/js/check_skip_if_no_match.cjs +++ b/actions/setup/js/check_skip_if_no_match.cjs @@ -1,57 +1,26 @@ // @ts-check /// -const { getErrorMessage } = require("./error_helpers.cjs"); -const { ERR_API, ERR_CONFIG } = require("./error_codes.cjs"); -const { buildSearchQuery } = require("./check_skip_if_helpers.cjs"); -const { writeDenialSummary } = require("./pre_activation_summary.cjs"); +const { runSkipQueryGate } = require("./check_skip_if_helpers.cjs"); async function main() { const { GH_AW_SKIP_QUERY: skipQuery, GH_AW_WORKFLOW_NAME: workflowName, GH_AW_SKIP_MIN_MATCHES: minMatchesStr = "1", GH_AW_SKIP_SCOPE: skipScope } = process.env; - if (!skipQuery) { - core.setFailed(`${ERR_CONFIG}: Configuration error: GH_AW_SKIP_QUERY not specified.`); - return; - } - - if (!workflowName) { - core.setFailed(`${ERR_CONFIG}: Configuration error: GH_AW_WORKFLOW_NAME not specified.`); - return; - } - - const minMatches = parseInt(minMatchesStr, 10); - if (isNaN(minMatches) || minMatches < 1) { - core.setFailed(`${ERR_CONFIG}: Configuration error: GH_AW_SKIP_MIN_MATCHES must be a positive integer, got "${minMatchesStr}".`); - return; - } - - core.info(`Checking skip-if-no-match query: ${skipQuery}`); - core.info(`Minimum matches threshold: ${minMatches}`); - - const searchQuery = buildSearchQuery(skipQuery, skipScope); - - try { - const { - data: { total_count: totalCount }, - } = await github.rest.search.issuesAndPullRequests({ - q: searchQuery, - per_page: 1, - }); - - core.info(`Search found ${totalCount} matching items`); - - if (totalCount < minMatches) { - core.warning(`🔍 Skip condition matched (${totalCount} items found, minimum required: ${minMatches}). Workflow execution will be prevented by activation job.`); - core.setOutput("skip_no_match_check_ok", "false"); - await writeDenialSummary(`Skip-if-no-match query returned too few results: ${totalCount} item(s) found (minimum required: ${minMatches}).`, "Update `on.skip-if-no-match:` in the workflow frontmatter if this skip was unexpected."); - return; - } - - core.info(`✓ Found ${totalCount} matches (meets or exceeds minimum of ${minMatches}), workflow can proceed`); - core.setOutput("skip_no_match_check_ok", "true"); - } catch (error) { - core.setFailed(`${ERR_API}: Failed to execute search query: ${getErrorMessage(error)}`); - } + await runSkipQueryGate({ + skipQuery, + workflowName, + thresholdStr: minMatchesStr, + thresholdEnvVar: "GH_AW_SKIP_MIN_MATCHES", + thresholdLabel: "Minimum matches threshold", + checkLabel: "skip-if-no-match", + outputName: "skip_no_match_check_ok", + skipScope, + shouldSkip: (totalCount, threshold) => totalCount < threshold, + warningMessage: (totalCount, threshold) => `🔍 Skip condition matched (${totalCount} items found, minimum required: ${threshold}). Workflow execution will be prevented by activation job.`, + successMessage: (totalCount, threshold) => `✓ Found ${totalCount} matches (meets or exceeds minimum of ${threshold}), workflow can proceed`, + denialSummaryMessage: (totalCount, threshold) => `Skip-if-no-match query returned too few results: ${totalCount} item(s) found (minimum required: ${threshold}).`, + denialSummaryNextStep: "Update `on.skip-if-no-match:` in the workflow frontmatter if this skip was unexpected.", + }); } module.exports = { main }; From 08ad2b900d827fab84b4a6191f506a565fc031ca Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 5 Jul 2026 07:57:33 +0000 Subject: [PATCH 3/4] refactor: address review feedback on runSkipQueryGate helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Break single-line destructure to multi-line (Prettier at printWidth:240 normalizes it; semantically correct) - Use workflowName in log line — eliminates dead validation - Remove thresholdStr default from helper (callers own their defaults) - Move runSkipQueryGate describe to top-level sibling of buildSearchQuery - Remove duplicate loadModule inside runSkipQueryGate describe - Add missing test cases: skipQuery/workflowName early-exit guards, success path (skip condition not met), API error path - Assert writeDenialSummary side effects in skip-path test Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/check_skip_if_helpers.cjs | 4 +- .../setup/js/check_skip_if_helpers.test.cjs | 149 ++++++++++-------- 2 files changed, 90 insertions(+), 63 deletions(-) diff --git a/actions/setup/js/check_skip_if_helpers.cjs b/actions/setup/js/check_skip_if_helpers.cjs index 9165de8eee6..7c688232d5f 100644 --- a/actions/setup/js/check_skip_if_helpers.cjs +++ b/actions/setup/js/check_skip_if_helpers.cjs @@ -41,7 +41,7 @@ function buildSearchQuery(skipQuery, skipScope) { * }} options */ async function runSkipQueryGate(options) { - const { skipQuery, workflowName, thresholdStr = "1", thresholdEnvVar, thresholdLabel, checkLabel, outputName, skipScope, shouldSkip, warningMessage, successMessage, denialSummaryMessage, denialSummaryNextStep } = options; + const { skipQuery, workflowName, thresholdStr, thresholdEnvVar, thresholdLabel, checkLabel, outputName, skipScope, shouldSkip, warningMessage, successMessage, denialSummaryMessage, denialSummaryNextStep } = options; if (!skipQuery) { core.setFailed(`${ERR_CONFIG}: Configuration error: GH_AW_SKIP_QUERY not specified.`); @@ -53,6 +53,8 @@ async function runSkipQueryGate(options) { return; } + core.info(`Running ${checkLabel} gate for workflow: ${workflowName}`); + const threshold = parseInt(thresholdStr, 10); if (isNaN(threshold) || threshold < 1) { core.setFailed(`${ERR_CONFIG}: Configuration error: ${thresholdEnvVar} must be a positive integer, got "${thresholdStr}".`); diff --git a/actions/setup/js/check_skip_if_helpers.test.cjs b/actions/setup/js/check_skip_if_helpers.test.cjs index 05ce37c286e..4e9970658d6 100644 --- a/actions/setup/js/check_skip_if_helpers.test.cjs +++ b/actions/setup/js/check_skip_if_helpers.test.cjs @@ -69,68 +69,6 @@ describe("check_skip_if_helpers.cjs - buildSearchQuery", () => { }); }); - describe("check_skip_if_helpers.cjs - runSkipQueryGate", () => { - /** @returns {Promise<{runSkipQueryGate: (options: any) => Promise}>} */ - const loadModule = () => import("./check_skip_if_helpers.cjs"); - - beforeEach(() => { - global.github = { - rest: { - search: { - issuesAndPullRequests: vi.fn(), - }, - }, - }; - }); - - it("uses thresholdEnvVar in validation errors", async () => { - const { runSkipQueryGate } = await loadModule(); - - await runSkipQueryGate({ - skipQuery: "is:issue is:open", - workflowName: "test-workflow", - thresholdStr: "invalid", - thresholdEnvVar: "GH_AW_SKIP_MAX_MATCHES", - thresholdLabel: "Maximum matches threshold", - checkLabel: "skip-if-match", - outputName: "skip_check_ok", - skipScope: undefined, - shouldSkip: () => false, - warningMessage: () => "", - successMessage: () => "", - denialSummaryMessage: () => "", - denialSummaryNextStep: "", - }); - - expect(mockCore.setFailed).toHaveBeenCalledWith(expect.stringContaining("GH_AW_SKIP_MAX_MATCHES must be a positive integer")); - expect(global.github.rest.search.issuesAndPullRequests).not.toHaveBeenCalled(); - }); - - it("applies policy decision and output name when skip condition matches", async () => { - global.github.rest.search.issuesAndPullRequests.mockResolvedValue({ data: { total_count: 2 } }); - const { runSkipQueryGate } = await loadModule(); - - await runSkipQueryGate({ - skipQuery: "is:issue is:open", - workflowName: "test-workflow", - thresholdStr: "1", - thresholdEnvVar: "GH_AW_SKIP_MAX_MATCHES", - thresholdLabel: "Maximum matches threshold", - checkLabel: "skip-if-match", - outputName: "skip_check_ok", - skipScope: undefined, - shouldSkip: (totalCount, threshold) => totalCount >= threshold, - warningMessage: () => "skip warning", - successMessage: () => "success message", - denialSummaryMessage: () => "summary message", - denialSummaryNextStep: "summary next step", - }); - - expect(mockCore.warning).toHaveBeenCalledWith("skip warning"); - expect(mockCore.setOutput).toHaveBeenCalledWith("skip_check_ok", "false"); - }); - }); - describe("scope: default (repo-scoped)", () => { it("appends repo:owner/repo when skipScope is undefined", async () => { const { buildSearchQuery } = await loadModule(); @@ -171,3 +109,90 @@ describe("check_skip_if_helpers.cjs - buildSearchQuery", () => { }); }); }); + +describe("check_skip_if_helpers.cjs - runSkipQueryGate", () => { + /** @returns {Promise<{runSkipQueryGate: (options: any) => Promise}>} */ + const loadModule = () => import("./check_skip_if_helpers.cjs"); + + /** @type {Record} */ + const baseOptions = { + skipQuery: "is:issue is:open", + workflowName: "test-workflow", + thresholdStr: "1", + thresholdEnvVar: "GH_AW_SKIP_MAX_MATCHES", + thresholdLabel: "Maximum matches threshold", + checkLabel: "skip-if-match", + outputName: "skip_check_ok", + skipScope: undefined, + shouldSkip: (/** @type {number} */ totalCount, /** @type {number} */ threshold) => totalCount >= threshold, + warningMessage: () => "skip warning", + successMessage: () => "success message", + denialSummaryMessage: () => "summary message", + denialSummaryNextStep: "summary next step", + }; + + beforeEach(() => { + global.github = { + rest: { + search: { + issuesAndPullRequests: vi.fn(), + }, + }, + }; + }); + + it("fails with config error when skipQuery is undefined", async () => { + const { runSkipQueryGate } = await loadModule(); + await runSkipQueryGate({ ...baseOptions, skipQuery: undefined }); + expect(mockCore.setFailed).toHaveBeenCalledWith(expect.stringContaining("GH_AW_SKIP_QUERY not specified")); + expect(global.github.rest.search.issuesAndPullRequests).not.toHaveBeenCalled(); + }); + + it("fails with config error when workflowName is undefined", async () => { + const { runSkipQueryGate } = await loadModule(); + await runSkipQueryGate({ ...baseOptions, workflowName: undefined }); + expect(mockCore.setFailed).toHaveBeenCalledWith(expect.stringContaining("GH_AW_WORKFLOW_NAME not specified")); + expect(global.github.rest.search.issuesAndPullRequests).not.toHaveBeenCalled(); + }); + + it("uses thresholdEnvVar in validation errors", async () => { + const { runSkipQueryGate } = await loadModule(); + await runSkipQueryGate({ ...baseOptions, thresholdStr: "invalid" }); + expect(mockCore.setFailed).toHaveBeenCalledWith(expect.stringContaining("GH_AW_SKIP_MAX_MATCHES must be a positive integer")); + expect(global.github.rest.search.issuesAndPullRequests).not.toHaveBeenCalled(); + }); + + it("applies policy decision and output name when skip condition matches", async () => { + global.github.rest.search.issuesAndPullRequests.mockResolvedValue({ data: { total_count: 2 } }); + const { runSkipQueryGate } = await loadModule(); + + await runSkipQueryGate({ ...baseOptions }); + + expect(mockCore.warning).toHaveBeenCalledWith("skip warning"); + expect(mockCore.setOutput).toHaveBeenCalledWith("skip_check_ok", "false"); + expect(mockCore.summary.addRaw).toHaveBeenCalled(); + expect(mockCore.summary.write).toHaveBeenCalled(); + }); + + it("sets output to true and logs success when skip condition is not met", async () => { + global.github.rest.search.issuesAndPullRequests.mockResolvedValue({ data: { total_count: 0 } }); + const { runSkipQueryGate } = await loadModule(); + const successMessage = vi.fn(() => "all clear"); + + await runSkipQueryGate({ ...baseOptions, successMessage }); + + expect(mockCore.setOutput).toHaveBeenCalledWith("skip_check_ok", "true"); + expect(successMessage).toHaveBeenCalledWith(0, 1); + expect(mockCore.warning).not.toHaveBeenCalled(); + }); + + it("calls setFailed with ERR_API prefix when search throws", async () => { + global.github.rest.search.issuesAndPullRequests.mockRejectedValue(new Error("rate limited")); + const { runSkipQueryGate } = await loadModule(); + + await runSkipQueryGate({ ...baseOptions }); + + expect(mockCore.setFailed).toHaveBeenCalledWith(expect.stringContaining("ERR_API")); + expect(mockCore.setFailed).toHaveBeenCalledWith(expect.stringContaining("rate limited")); + }); +}); From 21dac8f23ddcec482e0d60ecabda5e77c77c3f13 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 5 Jul 2026 09:41:47 +0000 Subject: [PATCH 4/4] fix: resolve TS2345 type error and address remaining review threads - Fix TS2345: parseInt(thresholdStr ?? "", 10) so undefined thresholdStr falls through to the isNaN guard instead of failing type-check - Add prettier-ignore + multi-line destructure for readability - Add ambient globals comment (core, github, context) for discoverability by static analysis and IDE tooling Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com> --- actions/setup/js/check_skip_if_helpers.cjs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/actions/setup/js/check_skip_if_helpers.cjs b/actions/setup/js/check_skip_if_helpers.cjs index 7c688232d5f..ed8813d5168 100644 --- a/actions/setup/js/check_skip_if_helpers.cjs +++ b/actions/setup/js/check_skip_if_helpers.cjs @@ -40,8 +40,15 @@ function buildSearchQuery(skipQuery, skipScope) { * denialSummaryNextStep: string; * }} options */ +// Ambient globals provided by @actions/github-script: core, github, context async function runSkipQueryGate(options) { - const { skipQuery, workflowName, thresholdStr, thresholdEnvVar, thresholdLabel, checkLabel, outputName, skipScope, shouldSkip, warningMessage, successMessage, denialSummaryMessage, denialSummaryNextStep } = options; + // prettier-ignore + const { + skipQuery, workflowName, thresholdStr, + thresholdEnvVar, thresholdLabel, checkLabel, outputName, skipScope, + shouldSkip, warningMessage, successMessage, + denialSummaryMessage, denialSummaryNextStep, + } = options; if (!skipQuery) { core.setFailed(`${ERR_CONFIG}: Configuration error: GH_AW_SKIP_QUERY not specified.`); @@ -55,7 +62,7 @@ async function runSkipQueryGate(options) { core.info(`Running ${checkLabel} gate for workflow: ${workflowName}`); - const threshold = parseInt(thresholdStr, 10); + const threshold = parseInt(thresholdStr ?? "", 10); if (isNaN(threshold) || threshold < 1) { core.setFailed(`${ERR_CONFIG}: Configuration error: ${thresholdEnvVar} must be a positive integer, got "${thresholdStr}".`); return;