From ba8088007998204f75ccb12b2fdbb870c1071a72 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 18 Sep 2026 13:11:14 +0000 Subject: [PATCH 01/47] Update changelog and version after v4.38.1 --- CHANGELOG.md | 4 ++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b8a7189e20..267b4e557e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ See the [releases page](https://github.com/github/codeql-action/releases) for the relevant changes to the CodeQL CLI and language packs. +## [UNRELEASED] + +No user facing changes. + ## 4.38.1 - 18 Sept 2026 - The CodeQL Action now has experimental support for CodeQL releases for which per-language bundles are available. Per-language bundles support analysis for a single language and are therefore smaller than the combined bundles that allow analysis for all supported languages. As a result, per-language bundles take up less space on disk and are faster to download. We expect to roll this change out to everyone in the coming weeks. [#4146](https://github.com/github/codeql-action/pull/4146) diff --git a/package-lock.json b/package-lock.json index 17a4eee8c3..d4f189db2a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "codeql", - "version": "4.38.1", + "version": "4.38.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "codeql", - "version": "4.38.1", + "version": "4.38.2", "license": "MIT", "workspaces": [ "pr-checks" diff --git a/package.json b/package.json index c7ad53e2e0..7f31e80e93 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codeql", - "version": "4.38.1", + "version": "4.38.2", "private": true, "description": "CodeQL action", "scripts": { From f8b1c08e6dfaa417c8626f557accae8a15613e6c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 18 Sep 2026 13:11:23 +0000 Subject: [PATCH 02/47] Rebuild --- lib/entry-points.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/entry-points.js b/lib/entry-points.js index f8a7d6e76a..0f1282075e 100644 --- a/lib/entry-points.js +++ b/lib/entry-points.js @@ -146167,7 +146167,7 @@ function getDiffRangesJsonFilePath(env = getEnv()) { return path2.join(getTemporaryDirectory(env), PR_DIFF_RANGE_JSON_FILENAME); } function getActionVersion() { - return "4.38.1"; + return "4.38.2"; } function getWorkflowEventName(env = getEnv()) { return env.getRequired("GITHUB_EVENT_NAME" /* GITHUB_EVENT_NAME */); From cb31eabcd8c75b939c159b0f04b821a0bfd130f6 Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Fri, 18 Sep 2026 09:04:47 -0500 Subject: [PATCH 03/47] Do not include trailing newlines in `NO_CHANGES_STR` Changing `NO_CHANGES_STR` to just be the text will make it easier to insert/use. To not break anything, I added the deleted newlines to the locations where `NO_CHANGES_STR` was used. --- pr-checks/bundle-changelog.test.ts | 4 ++-- pr-checks/changelog.ts | 8 +++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/pr-checks/bundle-changelog.test.ts b/pr-checks/bundle-changelog.test.ts index 6cc4d096ba..fad06826a6 100644 --- a/pr-checks/bundle-changelog.test.ts +++ b/pr-checks/bundle-changelog.test.ts @@ -112,7 +112,7 @@ ${NO_CHANGES_STR}`; describe("updateChangelog", async () => { await it("removes `NO_CHANGES_STR` if present in [UNRELEASED] section", async () => { const result = updateChangelog(EMPTY_CHANGELOG, ""); - assert.ok(!result.includes(NO_CHANGES_STR.trim())); + assert.ok(!result.includes(NO_CHANGES_STR)); }); await it("doesn't remove `NO_CHANGES_STR` if present in versioned section", async () => { @@ -120,7 +120,7 @@ describe("updateChangelog", async () => { EMPTY_CHANGELOG.replace(UNRELEASED_PLACEHOLDER, "1.2.3"), "", ); - assert.ok(result.includes(NO_CHANGES_STR.trim())); + assert.ok(result.includes(NO_CHANGES_STR)); }); await it("throws if there are no sections", async () => { diff --git a/pr-checks/changelog.ts b/pr-checks/changelog.ts index 4cf1e75494..fc17199d6a 100644 --- a/pr-checks/changelog.ts +++ b/pr-checks/changelog.ts @@ -6,14 +6,16 @@ import { CHANGELOG_FILE, DryRunOption } from "./config"; export const UNRELEASED_PLACEHOLDER = "[UNRELEASED]"; /** The default contents for a section in the changelog. */ -export const NO_CHANGES_STR = "No user facing changes.\n\n"; +export const NO_CHANGES_STR = "No user facing changes."; /** Placeholder changelog content for a new release. */ export const EMPTY_CHANGELOG = `# CodeQL Action Changelog ## ${UNRELEASED_PLACEHOLDER} -${NO_CHANGES_STR}`; +${NO_CHANGES_STR} + +`; /** * Represents sections in a changelog. @@ -204,7 +206,7 @@ export function processChangelogForBackports( // Add an entry if we didn't keep any. if (!foundContent) { - section.bodyLines.push(NO_CHANGES_STR.trim()); + section.bodyLines.push(NO_CHANGES_STR); } } From 47d607e2c1eebf3c9382b1872b2f902a7915bbc4 Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Fri, 18 Sep 2026 09:06:31 -0500 Subject: [PATCH 04/47] Add changelog parsing helper `getHeader` --- pr-checks/changelog.test.ts | 19 +++++++++++++++++++ pr-checks/changelog.ts | 5 +++++ 2 files changed, 24 insertions(+) diff --git a/pr-checks/changelog.test.ts b/pr-checks/changelog.test.ts index 817852e3e1..45658154fc 100755 --- a/pr-checks/changelog.test.ts +++ b/pr-checks/changelog.test.ts @@ -10,6 +10,7 @@ import { describe, it } from "node:test"; import { EMPTY_CHANGELOG, + getHeader, getReleaseDateString, parseChangelog, processChangelogForBackports, @@ -20,6 +21,24 @@ import { CHANGELOG_FILE } from "./config"; const testDate = new Date(2026, 7, 14); +describe("getHeader", async () => { + await it("returns non-headers unchanged", () => { + assert.equal("foo", getHeader("foo")); + assert.equal("- bar", getHeader("- bar")); + }); + await it("strips octothorpes", async () => { + assert.equal("foo", getHeader("# foo")); + assert.equal("foo", getHeader("## foo")); + assert.equal("foo", getHeader("### foo")); + assert.equal("foo", getHeader("#### foo")); + assert.equal("foo", getHeader("##### foo")); + assert.equal("foo", getHeader("###### foo")); + }); + await it("strips whitespace", async () => { + assert.equal("foo", getHeader("# foo ")); + }); +}); + describe("getReleaseDateString", async () => { await it("formats dates as expected", async () => { assert.equal(getReleaseDateString(testDate), "14 Aug 2026"); diff --git a/pr-checks/changelog.ts b/pr-checks/changelog.ts index fc17199d6a..8265430243 100644 --- a/pr-checks/changelog.ts +++ b/pr-checks/changelog.ts @@ -33,6 +33,11 @@ export interface Changelog { sections: ChangelogSection[]; } +/** Returns the text of a CHANGELOG.md header (without the '## ' prefix). */ +export function getHeader(headerLine: string): string { + return headerLine.replace(/^#+\s+/, "").trimEnd(); +} + /** Returns `date` formatted as `DD Mon YYYY`. */ export function getReleaseDateString(today: Date = new Date()): string { return today.toLocaleDateString("en-GB", { From bb1dc5460bab614d5c8c05120b7e5465e04d8417 Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Fri, 18 Sep 2026 09:07:44 -0500 Subject: [PATCH 05/47] Add CHANGELOG function `addBodyLinesToUnreleasedSection` This will be used by the `pr-checks/changenotes.mts` script to "compile" the latest release entry of CHANGELOG.md. --- pr-checks/changelog.test.ts | 79 +++++++++++++++++++++++++++++++++++++ pr-checks/changelog.ts | 53 +++++++++++++++++++++++++ 2 files changed, 132 insertions(+) diff --git a/pr-checks/changelog.test.ts b/pr-checks/changelog.test.ts index 45658154fc..b88f9b0c07 100755 --- a/pr-checks/changelog.test.ts +++ b/pr-checks/changelog.test.ts @@ -9,13 +9,17 @@ import * as fs from "node:fs"; import { describe, it } from "node:test"; import { + addBodyLinesToUnreleasedSection, + ChangelogSection, EMPTY_CHANGELOG, getHeader, getReleaseDateString, + NO_CHANGES_STR, parseChangelog, processChangelogForBackports, renderChangelog, setVersionAndDate, + UNRELEASED_PLACEHOLDER, } from "./changelog"; import { CHANGELOG_FILE } from "./config"; @@ -89,3 +93,78 @@ describe("processChangelogForBackports", async () => { assert.deepEqual(result.split("\n"), testChangelogResult.split("\n")); }); }); + +describe("addBodyLinesToUnreleasedSection", async () => { + function newChangelogWithSections(sections: ChangelogSection[]) { + return { + preamble: [], + sections, + }; + } + + await it("throws error if '[UNRELEASED]' section does not exist", async () => { + const emptyChangelog = newChangelogWithSections([]); + assert.throws(() => addBodyLinesToUnreleasedSection(emptyChangelog, [])); + + const releasedChangelog = newChangelogWithSections([ + { + headerLine: "## Release 1.0.0", + bodyLines: [], + }, + { + headerLine: "## Release 2.0.0", + bodyLines: [], + }, + { + headerLine: "## Release 3.0.0", + bodyLines: [], + }, + ]); + assert.throws(() => addBodyLinesToUnreleasedSection(releasedChangelog, [])); + }); + + await it("overwrites 'No user facing changes.'", async () => { + const changelog = newChangelogWithSections([ + { + headerLine: `## ${UNRELEASED_PLACEHOLDER}`, + bodyLines: ["", NO_CHANGES_STR, ""], + }, + ]); + + addBodyLinesToUnreleasedSection(changelog, ["- foo"]); + + assert.equal(changelog.sections[0].bodyLines.length, 3); + assert.deepEqual(changelog.sections[0].bodyLines, ["", "- foo", ""]); + }); + + await it("does nothing if lines is empty", async () => { + const changelog = newChangelogWithSections([ + { + headerLine: `## ${UNRELEASED_PLACEHOLDER}`, + bodyLines: ["", NO_CHANGES_STR, ""], + }, + ]); + const changelogClone = structuredClone(changelog); + + addBodyLinesToUnreleasedSection(changelog, []); + + assert.deepEqual(changelog, changelogClone); + }); + + await it("inserts a line", async () => { + const changelog = newChangelogWithSections([ + { + headerLine: `## ${UNRELEASED_PLACEHOLDER}`, + bodyLines: ["", "- Added a new dependency.", ""], + }, + ]); + const lineToInsert = "- foo"; + + addBodyLinesToUnreleasedSection(changelog, [lineToInsert]); + + assert.equal(changelog.sections[0].bodyLines.length, 4); + assert.ok( + changelog.sections[0].bodyLines.some((line) => line === lineToInsert), + ); + }); +}); diff --git a/pr-checks/changelog.ts b/pr-checks/changelog.ts index 8265430243..ec765b4c8f 100644 --- a/pr-checks/changelog.ts +++ b/pr-checks/changelog.ts @@ -132,6 +132,59 @@ export function parseChangelog(content: string): Changelog { return { preamble, sections }; } +/** + * Inserts the changenotes `notes` under the `[UNRELEASED]` section of `changelog`. + * If the section contains the stock message {@link NO_CHANGES_STR}, then + * `notes` will be inserted in place and the stock message will be deleted. + * + * This function will throw an exception if `[UNRELEASED]` does not exist. + * + * @param changelog The CHANGELOG object to modify. + * @param lines The changenotes to insert. + */ +export function addBodyLinesToUnreleasedSection( + changelog: Changelog, + lines: string[], +) { + // Find the '[UNRELEASED]' section. + let unreleasedSection: ChangelogSection | undefined; + for (const section of changelog.sections) { + if (getHeader(section.headerLine) === UNRELEASED_PLACEHOLDER) { + unreleasedSection = section; + break; + } + } + + // Ensure that the '[UNRELEASED]' section exists first. + if (unreleasedSection === undefined) { + throw Error( + "Cannot put changenotes into CHANGELOG.md's '[UNRELEASED]' section because it does not exist", + ); + } + + let insertAtIndex = 0; + let deleteCount = 0; + + // If the section contains an empty line, preserve it -- insert afterward. + if ( + unreleasedSection.bodyLines.length > 0 && + unreleasedSection.bodyLines[0] === "" + ) { + insertAtIndex++; + } + + // If the section contains the stock message 'No user facing changes.' + if ( + lines.length > 0 && + unreleasedSection.bodyLines.length > insertAtIndex && + unreleasedSection.bodyLines[insertAtIndex].trim() === NO_CHANGES_STR + ) { + deleteCount++; // Delete the line by incrementing the delete marker. + } + + unreleasedSection.bodyLines.splice(insertAtIndex, deleteCount, ...lines); +} + /** * Combines an array of lines into a single string by adding line breaks. */ From 1ee32652624bab3b2447ddd6f0d5794ec2ea6f1a Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Fri, 18 Sep 2026 09:23:03 -0500 Subject: [PATCH 06/47] Add `changenotes.mts flush` command This command will "flush" or move the changenotes in the `unreleased-change-notes` directory to the `[UNRELEASED]` section of the CHANGELOG.md file. --- pr-checks/changenotes.mts | 52 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/pr-checks/changenotes.mts b/pr-checks/changenotes.mts index 2fb86b0cac..c7a10d0229 100755 --- a/pr-checks/changenotes.mts +++ b/pr-checks/changenotes.mts @@ -1,11 +1,20 @@ #!/usr/bin/env npx tsx import * as fs from "node:fs"; +import { readFileSync } from "node:fs"; import { pathToFileURL } from "node:url"; import { parseArgs } from "node:util"; +import path from "path"; +import { matter } from "lite-matter"; + +import { + addBodyLinesToUnreleasedSection, + parseChangelog, + renderChangelog, +} from "./changelog"; import { isValidAllChangenoteFiles } from "./changelog/validate.mjs"; -import { CHANGENOTES_DIR } from "./config"; +import { CHANGELOG_FILE, CHANGENOTES_DIR } from "./config"; const entryPoint = process.argv[1]; if (entryPoint && import.meta.url === pathToFileURL(entryPoint).href) { @@ -27,6 +36,8 @@ function main(): number { case undefined: case "help": return usage(); + case "flush": + return flush(); case "validate": return validate(); default: @@ -36,10 +47,47 @@ function main(): number { } function usage(): number { - console.log(`Usage: changenotes.mts validate`); + const message = + "Usage: changenotes.mts flush\n" + + " changenotes.mts validate\n" + + " changenotes.mts help"; + console.log(message); return 0; } +function flush(): number { + try { + // Get the file paths to our changenotes; these will be useful later. + const changenotePaths = fs + .readdirSync(CHANGENOTES_DIR) + .filter((name) => name !== ".gitkeep") + .map((name) => path.join(CHANGENOTES_DIR, name)); + + // From the file paths, we read the files to obtain the actual notes themselves. + const changenotes = changenotePaths.map((filePath) => { + const fileBody = readFileSync(filePath).toString(); + const { content } = matter(fileBody); + return content.trim(); + }); + + const changelogContents = fs.readFileSync(CHANGELOG_FILE).toString(); + const changelog = parseChangelog(changelogContents); + addBodyLinesToUnreleasedSection(changelog, changenotes); + fs.writeFileSync(CHANGELOG_FILE, renderChangelog(changelog)); + + // Delete changenotes only after successful processing. + for (const p of changenotePaths) { + fs.unlinkSync(p); + } + + return 0; + } catch (e) { + console.error("Failed to flush changenotes to 'CHANGELOG.md'", e); + } + + return 1; +} + function validate(): number { try { if (isValidAllChangenoteFiles(fs.readdirSync(CHANGENOTES_DIR))) { From bffae1c4b8f56e1f31092864ec57102c0c026ac2 Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Fri, 18 Sep 2026 11:22:39 -0500 Subject: [PATCH 07/47] Use `withChangelog` I/O helper --- pr-checks/changenotes.mts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/pr-checks/changenotes.mts b/pr-checks/changenotes.mts index c7a10d0229..06b10da8eb 100755 --- a/pr-checks/changenotes.mts +++ b/pr-checks/changenotes.mts @@ -12,9 +12,10 @@ import { addBodyLinesToUnreleasedSection, parseChangelog, renderChangelog, + withChangelog, } from "./changelog"; import { isValidAllChangenoteFiles } from "./changelog/validate.mjs"; -import { CHANGELOG_FILE, CHANGENOTES_DIR } from "./config"; +import { CHANGENOTES_DIR } from "./config"; const entryPoint = process.argv[1]; if (entryPoint && import.meta.url === pathToFileURL(entryPoint).href) { @@ -70,10 +71,11 @@ function flush(): number { return content.trim(); }); - const changelogContents = fs.readFileSync(CHANGELOG_FILE).toString(); - const changelog = parseChangelog(changelogContents); - addBodyLinesToUnreleasedSection(changelog, changenotes); - fs.writeFileSync(CHANGELOG_FILE, renderChangelog(changelog)); + withChangelog((contents) => { + const changelog = parseChangelog(contents); + addBodyLinesToUnreleasedSection(changelog, changenotes); + return renderChangelog(changelog); + }, {}); // Delete changenotes only after successful processing. for (const p of changenotePaths) { From b246e5606946f9e44193fd31a37458b82052507a Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Fri, 18 Sep 2026 11:28:17 -0500 Subject: [PATCH 08/47] Use `ExitCode` instead of `0`/`1` --- pr-checks/changenotes.mts | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/pr-checks/changenotes.mts b/pr-checks/changenotes.mts index 06b10da8eb..fd3225b911 100755 --- a/pr-checks/changenotes.mts +++ b/pr-checks/changenotes.mts @@ -6,6 +6,7 @@ import { pathToFileURL } from "node:url"; import { parseArgs } from "node:util"; import path from "path"; +import { ExitCode } from "@actions/core"; import { matter } from "lite-matter"; import { @@ -23,11 +24,11 @@ if (entryPoint && import.meta.url === pathToFileURL(entryPoint).href) { process.exit(main()); } catch (error) { console.error(error); - process.exit(1); + process.exit(ExitCode.Failure); } } -function main(): number { +function main(): ExitCode { const { positionals } = parseArgs({ allowPositionals: true, strict: true, @@ -43,20 +44,20 @@ function main(): number { return validate(); default: console.error(`Unknown command: ${command}`); - return 1; + return ExitCode.Failure; } } -function usage(): number { +function usage(): ExitCode { const message = "Usage: changenotes.mts flush\n" + " changenotes.mts validate\n" + " changenotes.mts help"; console.log(message); - return 0; + return ExitCode.Success; } -function flush(): number { +function flush(): ExitCode { try { // Get the file paths to our changenotes; these will be useful later. const changenotePaths = fs @@ -82,19 +83,19 @@ function flush(): number { fs.unlinkSync(p); } - return 0; + return ExitCode.Success; } catch (e) { console.error("Failed to flush changenotes to 'CHANGELOG.md'", e); } - return 1; + return ExitCode.Failure; } -function validate(): number { +function validate(): ExitCode { try { if (isValidAllChangenoteFiles(fs.readdirSync(CHANGENOTES_DIR))) { console.log(`All changenotes in '${CHANGENOTES_DIR}' are valid.`); - return 0; + return ExitCode.Success; } } catch (error) { console.error( @@ -102,5 +103,5 @@ function validate(): number { error, ); } - return 1; + return ExitCode.Failure; } From d63b2a40db843ae6d4d33fcca9dbf0cd3e5384e0 Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Fri, 18 Sep 2026 11:42:46 -0500 Subject: [PATCH 09/47] Assume '[UNRELEASED]' section is first section --- pr-checks/changelog.ts | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/pr-checks/changelog.ts b/pr-checks/changelog.ts index ec765b4c8f..e738f2a4a1 100644 --- a/pr-checks/changelog.ts +++ b/pr-checks/changelog.ts @@ -146,20 +146,9 @@ export function addBodyLinesToUnreleasedSection( changelog: Changelog, lines: string[], ) { - // Find the '[UNRELEASED]' section. - let unreleasedSection: ChangelogSection | undefined; - for (const section of changelog.sections) { - if (getHeader(section.headerLine) === UNRELEASED_PLACEHOLDER) { - unreleasedSection = section; - break; - } - } - - // Ensure that the '[UNRELEASED]' section exists first. - if (unreleasedSection === undefined) { - throw Error( - "Cannot put changenotes into CHANGELOG.md's '[UNRELEASED]' section because it does not exist", - ); + const unreleasedSection = changelog.sections[0]; + if (getHeader(unreleasedSection.headerLine) !== UNRELEASED_PLACEHOLDER) { + throw Error("'[UNRELEASED]' is not the first section of 'CHANGELOG.md'"); } let insertAtIndex = 0; From 128614ad8b661f91e7038d97c93e89fbe6c26857 Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Fri, 18 Sep 2026 12:24:19 -0500 Subject: [PATCH 10/47] Simplify `getHeader` to operate on `ChangelogSection`s --- pr-checks/changelog.test.ts | 24 +++++++++++++++--------- pr-checks/changelog.ts | 10 ++++++---- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/pr-checks/changelog.test.ts b/pr-checks/changelog.test.ts index b88f9b0c07..2e8712ea8b 100755 --- a/pr-checks/changelog.test.ts +++ b/pr-checks/changelog.test.ts @@ -26,20 +26,26 @@ import { CHANGELOG_FILE } from "./config"; const testDate = new Date(2026, 7, 14); describe("getHeader", async () => { + function Section(headerLine: string): ChangelogSection { + return { + headerLine, + bodyLines: [], + }; + } await it("returns non-headers unchanged", () => { - assert.equal("foo", getHeader("foo")); - assert.equal("- bar", getHeader("- bar")); + assert.equal("foo", getHeader(Section("foo"))); + assert.equal("- bar", getHeader(Section("- bar"))); }); await it("strips octothorpes", async () => { - assert.equal("foo", getHeader("# foo")); - assert.equal("foo", getHeader("## foo")); - assert.equal("foo", getHeader("### foo")); - assert.equal("foo", getHeader("#### foo")); - assert.equal("foo", getHeader("##### foo")); - assert.equal("foo", getHeader("###### foo")); + assert.equal("foo", getHeader(Section("# foo"))); + assert.equal("foo", getHeader(Section("## foo"))); + assert.equal("foo", getHeader(Section("### foo"))); + assert.equal("foo", getHeader(Section("#### foo"))); + assert.equal("foo", getHeader(Section("##### foo"))); + assert.equal("foo", getHeader(Section("###### foo"))); }); await it("strips whitespace", async () => { - assert.equal("foo", getHeader("# foo ")); + assert.equal("foo", getHeader(Section("# foo "))); }); }); diff --git a/pr-checks/changelog.ts b/pr-checks/changelog.ts index e738f2a4a1..fa992d6eda 100644 --- a/pr-checks/changelog.ts +++ b/pr-checks/changelog.ts @@ -33,9 +33,11 @@ export interface Changelog { sections: ChangelogSection[]; } -/** Returns the text of a CHANGELOG.md header (without the '## ' prefix). */ -export function getHeader(headerLine: string): string { - return headerLine.replace(/^#+\s+/, "").trimEnd(); +/** + * Returns the text of the header (without the '## ' prefix) of the given section. + * */ +export function getHeader(section: ChangelogSection): string { + return section.headerLine.replace(/^#+\s+/, "").trimEnd(); } /** Returns `date` formatted as `DD Mon YYYY`. */ @@ -147,7 +149,7 @@ export function addBodyLinesToUnreleasedSection( lines: string[], ) { const unreleasedSection = changelog.sections[0]; - if (getHeader(unreleasedSection.headerLine) !== UNRELEASED_PLACEHOLDER) { + if (getHeader(unreleasedSection) !== UNRELEASED_PLACEHOLDER) { throw Error("'[UNRELEASED]' is not the first section of 'CHANGELOG.md'"); } From bc0efd6d9138ed65d251d7762a29ddd22614fc6a Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Fri, 18 Sep 2026 12:35:41 -0500 Subject: [PATCH 11/47] Simplify `addBodyLinesToUnreleasedSection` --- pr-checks/changelog.test.ts | 17 ++++++----------- pr-checks/changelog.ts | 27 ++++++++------------------- 2 files changed, 14 insertions(+), 30 deletions(-) diff --git a/pr-checks/changelog.test.ts b/pr-checks/changelog.test.ts index 2e8712ea8b..8132e65766 100755 --- a/pr-checks/changelog.test.ts +++ b/pr-checks/changelog.test.ts @@ -108,25 +108,20 @@ describe("addBodyLinesToUnreleasedSection", async () => { }; } - await it("throws error if '[UNRELEASED]' section does not exist", async () => { - const emptyChangelog = newChangelogWithSections([]); - assert.throws(() => addBodyLinesToUnreleasedSection(emptyChangelog, [])); - - const releasedChangelog = newChangelogWithSections([ + await it("throws error if '[UNRELEASED]' section is not first", async () => { + const invalidChangelog = newChangelogWithSections([ { headerLine: "## Release 1.0.0", bodyLines: [], }, { - headerLine: "## Release 2.0.0", - bodyLines: [], - }, - { - headerLine: "## Release 3.0.0", + headerLine: `## ${UNRELEASED_PLACEHOLDER}`, bodyLines: [], }, ]); - assert.throws(() => addBodyLinesToUnreleasedSection(releasedChangelog, [])); + assert.throws(() => + addBodyLinesToUnreleasedSection(invalidChangelog, ["foo"]), + ); }); await it("overwrites 'No user facing changes.'", async () => { diff --git a/pr-checks/changelog.ts b/pr-checks/changelog.ts index fa992d6eda..e159a06a98 100644 --- a/pr-checks/changelog.ts +++ b/pr-checks/changelog.ts @@ -148,32 +148,21 @@ export function addBodyLinesToUnreleasedSection( changelog: Changelog, lines: string[], ) { + // Do nothing if there is nothing to insert. + if (lines.length === 0) return; + const unreleasedSection = changelog.sections[0]; if (getHeader(unreleasedSection) !== UNRELEASED_PLACEHOLDER) { throw Error("'[UNRELEASED]' is not the first section of 'CHANGELOG.md'"); } - let insertAtIndex = 0; - let deleteCount = 0; - - // If the section contains an empty line, preserve it -- insert afterward. - if ( - unreleasedSection.bodyLines.length > 0 && - unreleasedSection.bodyLines[0] === "" - ) { - insertAtIndex++; - } - - // If the section contains the stock message 'No user facing changes.' - if ( - lines.length > 0 && - unreleasedSection.bodyLines.length > insertAtIndex && - unreleasedSection.bodyLines[insertAtIndex].trim() === NO_CHANGES_STR - ) { - deleteCount++; // Delete the line by incrementing the delete marker. + if (unreleasedSection.bodyLines.includes(NO_CHANGES_STR)) { + unreleasedSection.bodyLines = ["", ...lines, ""]; + return; } - unreleasedSection.bodyLines.splice(insertAtIndex, deleteCount, ...lines); + // Insert `lines` after the first blank line. + unreleasedSection.bodyLines.splice(1, 0, ...lines); } /** From 977b29b897eab1468a089ac1278b1b7c351bcffd Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Fri, 18 Sep 2026 13:47:06 -0500 Subject: [PATCH 12/47] Replace `splice` with `push` and `pop` --- pr-checks/changelog.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pr-checks/changelog.ts b/pr-checks/changelog.ts index e159a06a98..18bffa51a3 100644 --- a/pr-checks/changelog.ts +++ b/pr-checks/changelog.ts @@ -161,8 +161,9 @@ export function addBodyLinesToUnreleasedSection( return; } - // Insert `lines` after the first blank line. - unreleasedSection.bodyLines.splice(1, 0, ...lines); + unreleasedSection.bodyLines.pop(); // Remove the last empty line. + unreleasedSection.bodyLines.push(...lines); + unreleasedSection.bodyLines.push(""); } /** From 7f54212a01b1fcd5c22896032d6c677591788874 Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Fri, 18 Sep 2026 13:49:18 -0500 Subject: [PATCH 13/47] Rename `flush` command to `assemble` --- pr-checks/changenotes.mts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pr-checks/changenotes.mts b/pr-checks/changenotes.mts index fd3225b911..6480b19537 100755 --- a/pr-checks/changenotes.mts +++ b/pr-checks/changenotes.mts @@ -38,8 +38,8 @@ function main(): ExitCode { case undefined: case "help": return usage(); - case "flush": - return flush(); + case "assemble": + return assemble(); case "validate": return validate(); default: @@ -50,14 +50,14 @@ function main(): ExitCode { function usage(): ExitCode { const message = - "Usage: changenotes.mts flush\n" + + "Usage: changenotes.mts assemble\n" + " changenotes.mts validate\n" + " changenotes.mts help"; console.log(message); return ExitCode.Success; } -function flush(): ExitCode { +function assemble(): ExitCode { try { // Get the file paths to our changenotes; these will be useful later. const changenotePaths = fs @@ -85,7 +85,7 @@ function flush(): ExitCode { return ExitCode.Success; } catch (e) { - console.error("Failed to flush changenotes to 'CHANGELOG.md'", e); + console.error("Failed to assemble changenotes to 'CHANGELOG.md'", e); } return ExitCode.Failure; From a92f7fb68832cf532975c676aac5741c34cc63b2 Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Fri, 18 Sep 2026 15:01:59 -0500 Subject: [PATCH 14/47] Refactor changenote file listing into function to D.R.Y. --- pr-checks/changenotes.mts | 51 ++++++++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 14 deletions(-) diff --git a/pr-checks/changenotes.mts b/pr-checks/changenotes.mts index 6480b19537..9a5c21cf03 100755 --- a/pr-checks/changenotes.mts +++ b/pr-checks/changenotes.mts @@ -1,7 +1,6 @@ #!/usr/bin/env npx tsx import * as fs from "node:fs"; -import { readFileSync } from "node:fs"; import { pathToFileURL } from "node:url"; import { parseArgs } from "node:util"; import path from "path"; @@ -18,6 +17,39 @@ import { import { isValidAllChangenoteFiles } from "./changelog/validate.mjs"; import { CHANGENOTES_DIR } from "./config"; +/** + * Describes a changenote file, including its file path, frontmatter, and content. + */ +interface ChangenoteFile { + name: string; + data: Record; + content: string; +} + +/** + * Returns the absolute file paths of all files in + * {@link CHANGENOTES_DIR} (except ".gitkeep"). + * */ +function listUnreleasedChangenoteDir(): string[] { + return fs + .readdirSync(CHANGENOTES_DIR) + .filter((name) => name !== ".gitkeep") + .map((name) => path.join(CHANGENOTES_DIR, name)); +} + +/** + * Scans the {@link CHANGENOTES_DIR} directory for changenote files + * and returns a parsed listing of those changenote files. + */ +function getChangenotes(): ChangenoteFile[] { + return listUnreleasedChangenoteDir().map((name) => { + return { + name, + ...matter(fs.readFileSync(name, "utf-8")), + }; + }); +} + const entryPoint = process.argv[1]; if (entryPoint && import.meta.url === pathToFileURL(entryPoint).href) { try { @@ -59,22 +91,13 @@ function usage(): ExitCode { function assemble(): ExitCode { try { - // Get the file paths to our changenotes; these will be useful later. - const changenotePaths = fs - .readdirSync(CHANGENOTES_DIR) - .filter((name) => name !== ".gitkeep") - .map((name) => path.join(CHANGENOTES_DIR, name)); - - // From the file paths, we read the files to obtain the actual notes themselves. - const changenotes = changenotePaths.map((filePath) => { - const fileBody = readFileSync(filePath).toString(); - const { content } = matter(fileBody); - return content.trim(); - }); + const changenotes = getChangenotes(); + const changenoteBodies = changenotes.map((c) => c.content); + const changenotePaths = changenotes.map((c) => c.name); withChangelog((contents) => { const changelog = parseChangelog(contents); - addBodyLinesToUnreleasedSection(changelog, changenotes); + addBodyLinesToUnreleasedSection(changelog, changenoteBodies); return renderChangelog(changelog); }, {}); From 771560691a49adf7ee17519f5091ca8f747d0ce9 Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Mon, 21 Sep 2026 16:28:36 -0500 Subject: [PATCH 15/47] Update JSDoc comment with parameter `lines` Co-authored-by: Michael B. Gale --- pr-checks/changelog.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pr-checks/changelog.ts b/pr-checks/changelog.ts index 18bffa51a3..45a7977126 100644 --- a/pr-checks/changelog.ts +++ b/pr-checks/changelog.ts @@ -135,9 +135,9 @@ export function parseChangelog(content: string): Changelog { } /** - * Inserts the changenotes `notes` under the `[UNRELEASED]` section of `changelog`. + * Inserts the changenotes `lines` in the `[UNRELEASED]` section of `changelog`. * If the section contains the stock message {@link NO_CHANGES_STR}, then - * `notes` will be inserted in place and the stock message will be deleted. + * `lines` will be inserted in place and the stock message will be deleted. * * This function will throw an exception if `[UNRELEASED]` does not exist. * From 598cda36cf3f4ab1d9ab514b3015be59b2b46eed Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Mon, 21 Sep 2026 16:28:52 -0500 Subject: [PATCH 16/47] Apply suggestion from @mbg Co-authored-by: Michael B. Gale --- pr-checks/changelog.ts | 502 ++++++++++++++++++++--------------------- 1 file changed, 251 insertions(+), 251 deletions(-) diff --git a/pr-checks/changelog.ts b/pr-checks/changelog.ts index 45a7977126..76a3093456 100644 --- a/pr-checks/changelog.ts +++ b/pr-checks/changelog.ts @@ -1,253 +1,253 @@ -import * as fs from "node:fs"; - -import { CHANGELOG_FILE, DryRunOption } from "./config"; - -/** The placeholder in the header for unreleased changes. */ -export const UNRELEASED_PLACEHOLDER = "[UNRELEASED]"; - -/** The default contents for a section in the changelog. */ -export const NO_CHANGES_STR = "No user facing changes."; - -/** Placeholder changelog content for a new release. */ -export const EMPTY_CHANGELOG = `# CodeQL Action Changelog - -## ${UNRELEASED_PLACEHOLDER} - -${NO_CHANGES_STR} - -`; - -/** - * Represents sections in a changelog. - */ -export interface ChangelogSection { - headerLine: string; - bodyLines: string[]; -} - -/** - * Represents a changelog. - */ -export interface Changelog { - preamble: string[]; - sections: ChangelogSection[]; -} - -/** - * Returns the text of the header (without the '## ' prefix) of the given section. - * */ -export function getHeader(section: ChangelogSection): string { - return section.headerLine.replace(/^#+\s+/, "").trimEnd(); -} - -/** Returns `date` formatted as `DD Mon YYYY`. */ -export function getReleaseDateString(today: Date = new Date()): string { - return today.toLocaleDateString("en-GB", { - day: "2-digit", - month: "short", - year: "numeric", - }); -} - -export interface OpenChangelogOptions { - initChangelog?: boolean; -} - -export function withChangelog( - transformer: (contents: string) => string, - options: DryRunOption & OpenChangelogOptions, -): void { - let content: string; - - if (options.initChangelog && !fs.existsSync(CHANGELOG_FILE)) { - content = EMPTY_CHANGELOG; - } else { - content = fs.readFileSync(CHANGELOG_FILE, "utf8"); - } - - if (!options.dryRun) { - fs.writeFileSync(CHANGELOG_FILE, transformer(content), "utf8"); - } else { - console.info(`[DRY RUN] Would have written updated changelog.`); - } -} - -/** - * Updates the `[UNRELEASED]` marker in `CHANGELOG.md` with the given version - * and today's date. - */ -export function setVersionAndDate( - version: string, - content: string, - date: Date = new Date(), -): string { - const versionAndDate = `${version} - ${getReleaseDateString(date)}`; - return content.replace(UNRELEASED_PLACEHOLDER, versionAndDate); -} - -/** - * Parses `content` into a structured representation of a changelog. - * - * @param content The contents of the changelog file. - */ -export function parseChangelog(content: string): Changelog { - const lines = content.split("\n"); - let i = 0; - - const preamble: string[] = []; - const sections: ChangelogSection[] = []; - let currentSection: ChangelogSection | undefined = undefined; - - // Process all lines of the input file. - while (i < lines.length) { - const line = lines[i]; - - // Sections of the changelog start with `## `. - if (line.startsWith("## ")) { - // We have discovered a new section. If `currentSection` is already defined, - // then this marks the end of that section. Push it to the array of sections - // in the changelog. - if (currentSection !== undefined) { - sections.push(currentSection); - } - - // Initialise the new section. - currentSection = { headerLine: line, bodyLines: [] }; - } else if (currentSection !== undefined) { - // Add lines between the section header and the next to the current section. - currentSection.bodyLines.push(line); - } else { - // This is neither a section header nor are we in a section already, - // so this line is part of the preamble. - preamble.push(line); - } - - i++; - } - - // Push the current section to the array of completed sections, if there is - // still one unfinished. - if (currentSection !== undefined) { - sections.push(currentSection); - } - - return { preamble, sections }; -} - -/** +import * as fs from "node:fs"; + +import { CHANGELOG_FILE, DryRunOption } from "./config"; + +/** The placeholder in the header for unreleased changes. */ +export const UNRELEASED_PLACEHOLDER = "[UNRELEASED]"; + +/** The default contents for a section in the changelog. */ +export const NO_CHANGES_STR = "No user facing changes."; + +/** Placeholder changelog content for a new release. */ +export const EMPTY_CHANGELOG = `# CodeQL Action Changelog + +## ${UNRELEASED_PLACEHOLDER} + +${NO_CHANGES_STR} + +`; + +/** + * Represents sections in a changelog. + */ +export interface ChangelogSection { + headerLine: string; + bodyLines: string[]; +} + +/** + * Represents a changelog. + */ +export interface Changelog { + preamble: string[]; + sections: ChangelogSection[]; +} + +/** + * Returns the text of the header (without the '## ' prefix) of the given section. + * */ +export function getHeader(section: ChangelogSection): string { + return section.headerLine.replace(/^#+\s+/, "").trimEnd(); +} + +/** Returns `date` formatted as `DD Mon YYYY`. */ +export function getReleaseDateString(today: Date = new Date()): string { + return today.toLocaleDateString("en-GB", { + day: "2-digit", + month: "short", + year: "numeric", + }); +} + +export interface OpenChangelogOptions { + initChangelog?: boolean; +} + +export function withChangelog( + transformer: (contents: string) => string, + options: DryRunOption & OpenChangelogOptions, +): void { + let content: string; + + if (options.initChangelog && !fs.existsSync(CHANGELOG_FILE)) { + content = EMPTY_CHANGELOG; + } else { + content = fs.readFileSync(CHANGELOG_FILE, "utf8"); + } + + if (!options.dryRun) { + fs.writeFileSync(CHANGELOG_FILE, transformer(content), "utf8"); + } else { + console.info(`[DRY RUN] Would have written updated changelog.`); + } +} + +/** + * Updates the `[UNRELEASED]` marker in `CHANGELOG.md` with the given version + * and today's date. + */ +export function setVersionAndDate( + version: string, + content: string, + date: Date = new Date(), +): string { + const versionAndDate = `${version} - ${getReleaseDateString(date)}`; + return content.replace(UNRELEASED_PLACEHOLDER, versionAndDate); +} + +/** + * Parses `content` into a structured representation of a changelog. + * + * @param content The contents of the changelog file. + */ +export function parseChangelog(content: string): Changelog { + const lines = content.split("\n"); + let i = 0; + + const preamble: string[] = []; + const sections: ChangelogSection[] = []; + let currentSection: ChangelogSection | undefined = undefined; + + // Process all lines of the input file. + while (i < lines.length) { + const line = lines[i]; + + // Sections of the changelog start with `## `. + if (line.startsWith("## ")) { + // We have discovered a new section. If `currentSection` is already defined, + // then this marks the end of that section. Push it to the array of sections + // in the changelog. + if (currentSection !== undefined) { + sections.push(currentSection); + } + + // Initialise the new section. + currentSection = { headerLine: line, bodyLines: [] }; + } else if (currentSection !== undefined) { + // Add lines between the section header and the next to the current section. + currentSection.bodyLines.push(line); + } else { + // This is neither a section header nor are we in a section already, + // so this line is part of the preamble. + preamble.push(line); + } + + i++; + } + + // Push the current section to the array of completed sections, if there is + // still one unfinished. + if (currentSection !== undefined) { + sections.push(currentSection); + } + + return { preamble, sections }; +} + +/** * Inserts the changenotes `lines` in the `[UNRELEASED]` section of `changelog`. - * If the section contains the stock message {@link NO_CHANGES_STR}, then + * If the section contains the stock message {@link NO_CHANGES_STR}, then * `lines` will be inserted in place and the stock message will be deleted. - * - * This function will throw an exception if `[UNRELEASED]` does not exist. - * - * @param changelog The CHANGELOG object to modify. - * @param lines The changenotes to insert. - */ -export function addBodyLinesToUnreleasedSection( - changelog: Changelog, - lines: string[], -) { - // Do nothing if there is nothing to insert. - if (lines.length === 0) return; - - const unreleasedSection = changelog.sections[0]; - if (getHeader(unreleasedSection) !== UNRELEASED_PLACEHOLDER) { - throw Error("'[UNRELEASED]' is not the first section of 'CHANGELOG.md'"); - } - - if (unreleasedSection.bodyLines.includes(NO_CHANGES_STR)) { - unreleasedSection.bodyLines = ["", ...lines, ""]; - return; - } - - unreleasedSection.bodyLines.pop(); // Remove the last empty line. - unreleasedSection.bodyLines.push(...lines); - unreleasedSection.bodyLines.push(""); -} - -/** - * Combines an array of lines into a single string by adding line breaks. - */ -export function unlines(lines: string[]): string { - return `${lines.join("\n")}`; -} - -/** - * Renders a given changelog to a string. - */ -export function renderChangelog(changelog: Changelog): string { - let result = unlines(changelog.preamble); - - for (const section of changelog.sections) { - result += `\n${section.headerLine}\n${unlines(section.bodyLines)}`; - } - - return result; -} - -/** - * Processes changelog entries for a backport, converting version references - * from the source major version to the target major version and filtering - * entries that only apply to newer versions. - */ -export function processChangelogForBackports( - sourceBranchMajorVersion: string, - targetBranchMajorVersion: string, - content: string, -): string { - // Changelog entries can use the following format to indicate - // that they only apply to newer versions - const someVersionsOnlyRegex = /\[v(\d+)\+ only\]/; - - // Parse the changelog. - const changelog = parseChangelog(content); - - if (changelog.sections.length === 0) { - throw new Error("Could not find any change sections in CHANGELOG.md"); - } - - // Filter out changelog entries that only apply to newer versions and - // update the section headings with the backport major version for - // sections we keep. - for (const section of changelog.sections) { - // Update the section headings with the backport major version. - section.headerLine = section.headerLine.replace( - `## ${sourceBranchMajorVersion}`, - `## ${targetBranchMajorVersion}`, - ); - - const filteredEntries: string[] = []; - let foundContent = false; - - for (const line of section.bodyLines) { - // Skip the entry if `someVersionsOnlyRegex` matches and the major version - // of the target branch is smaller than the required version. - const match = someVersionsOnlyRegex.exec(line); - if ( - match && - Number.parseInt(targetBranchMajorVersion) < Number.parseInt(match[1]) - ) { - continue; - } - - // Keep the line. - filteredEntries.push(line); - - // Set `foundContent` to `true` if the line is not empty. - if (line.trim() !== "") { - foundContent = true; - } - } - - // Update the section with the retained entries. - section.bodyLines = filteredEntries; - - // Add an entry if we didn't keep any. - if (!foundContent) { - section.bodyLines.push(NO_CHANGES_STR); - } - } - - return renderChangelog(changelog); -} + * + * This function will throw an exception if `[UNRELEASED]` does not exist. + * + * @param changelog The CHANGELOG object to modify. + * @param lines The changenotes to insert. + */ +export function addBodyLinesToUnreleasedSection( + changelog: Changelog, + lines: string[], +) { + // Do nothing if there is nothing to insert. + if (lines.length === 0) return; + + const unreleasedSection = changelog.sections[0]; + if (getHeader(unreleasedSection) !== UNRELEASED_PLACEHOLDER) { + throw Error(`'${UNRELEASED_PLACEHOLDER}' is not the first section of 'CHANGELOG.md'`); + } + + if (unreleasedSection.bodyLines.includes(NO_CHANGES_STR)) { + unreleasedSection.bodyLines = ["", ...lines, ""]; + return; + } + + unreleasedSection.bodyLines.pop(); // Remove the last empty line. + unreleasedSection.bodyLines.push(...lines); + unreleasedSection.bodyLines.push(""); +} + +/** + * Combines an array of lines into a single string by adding line breaks. + */ +export function unlines(lines: string[]): string { + return `${lines.join("\n")}`; +} + +/** + * Renders a given changelog to a string. + */ +export function renderChangelog(changelog: Changelog): string { + let result = unlines(changelog.preamble); + + for (const section of changelog.sections) { + result += `\n${section.headerLine}\n${unlines(section.bodyLines)}`; + } + + return result; +} + +/** + * Processes changelog entries for a backport, converting version references + * from the source major version to the target major version and filtering + * entries that only apply to newer versions. + */ +export function processChangelogForBackports( + sourceBranchMajorVersion: string, + targetBranchMajorVersion: string, + content: string, +): string { + // Changelog entries can use the following format to indicate + // that they only apply to newer versions + const someVersionsOnlyRegex = /\[v(\d+)\+ only\]/; + + // Parse the changelog. + const changelog = parseChangelog(content); + + if (changelog.sections.length === 0) { + throw new Error("Could not find any change sections in CHANGELOG.md"); + } + + // Filter out changelog entries that only apply to newer versions and + // update the section headings with the backport major version for + // sections we keep. + for (const section of changelog.sections) { + // Update the section headings with the backport major version. + section.headerLine = section.headerLine.replace( + `## ${sourceBranchMajorVersion}`, + `## ${targetBranchMajorVersion}`, + ); + + const filteredEntries: string[] = []; + let foundContent = false; + + for (const line of section.bodyLines) { + // Skip the entry if `someVersionsOnlyRegex` matches and the major version + // of the target branch is smaller than the required version. + const match = someVersionsOnlyRegex.exec(line); + if ( + match && + Number.parseInt(targetBranchMajorVersion) < Number.parseInt(match[1]) + ) { + continue; + } + + // Keep the line. + filteredEntries.push(line); + + // Set `foundContent` to `true` if the line is not empty. + if (line.trim() !== "") { + foundContent = true; + } + } + + // Update the section with the retained entries. + section.bodyLines = filteredEntries; + + // Add an entry if we didn't keep any. + if (!foundContent) { + section.bodyLines.push(NO_CHANGES_STR); + } + } + + return renderChangelog(changelog); +} From c496c6cceb2cee0566ea8dd194c7915be1420850 Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Mon, 21 Sep 2026 16:31:55 -0500 Subject: [PATCH 17/47] Rename `name` to `absolutePath` for clarity --- pr-checks/changenotes.mts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pr-checks/changenotes.mts b/pr-checks/changenotes.mts index 9a5c21cf03..d19d2da83b 100755 --- a/pr-checks/changenotes.mts +++ b/pr-checks/changenotes.mts @@ -21,7 +21,7 @@ import { CHANGENOTES_DIR } from "./config"; * Describes a changenote file, including its file path, frontmatter, and content. */ interface ChangenoteFile { - name: string; + absolutePath: string; data: Record; content: string; } @@ -42,10 +42,10 @@ function listUnreleasedChangenoteDir(): string[] { * and returns a parsed listing of those changenote files. */ function getChangenotes(): ChangenoteFile[] { - return listUnreleasedChangenoteDir().map((name) => { + return listUnreleasedChangenoteDir().map((absolutePath) => { return { - name, - ...matter(fs.readFileSync(name, "utf-8")), + absolutePath, + ...matter(fs.readFileSync(absolutePath, "utf-8")), }; }); } @@ -93,7 +93,7 @@ function assemble(): ExitCode { try { const changenotes = getChangenotes(); const changenoteBodies = changenotes.map((c) => c.content); - const changenotePaths = changenotes.map((c) => c.name); + const changenotePaths = changenotes.map((c) => c.absolutePath); withChangelog((contents) => { const changelog = parseChangelog(contents); From 02631222091e92e55383c4e23534b590cadc795a Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Mon, 21 Sep 2026 16:32:44 -0500 Subject: [PATCH 18/47] Format code with `npm run lint-fix` --- pr-checks/changelog.ts | 508 +++++++++++++++++++++-------------------- 1 file changed, 255 insertions(+), 253 deletions(-) diff --git a/pr-checks/changelog.ts b/pr-checks/changelog.ts index 76a3093456..bee141d2fd 100644 --- a/pr-checks/changelog.ts +++ b/pr-checks/changelog.ts @@ -1,253 +1,255 @@ -import * as fs from "node:fs"; - -import { CHANGELOG_FILE, DryRunOption } from "./config"; - -/** The placeholder in the header for unreleased changes. */ -export const UNRELEASED_PLACEHOLDER = "[UNRELEASED]"; - -/** The default contents for a section in the changelog. */ -export const NO_CHANGES_STR = "No user facing changes."; - -/** Placeholder changelog content for a new release. */ -export const EMPTY_CHANGELOG = `# CodeQL Action Changelog - -## ${UNRELEASED_PLACEHOLDER} - -${NO_CHANGES_STR} - -`; - -/** - * Represents sections in a changelog. - */ -export interface ChangelogSection { - headerLine: string; - bodyLines: string[]; -} - -/** - * Represents a changelog. - */ -export interface Changelog { - preamble: string[]; - sections: ChangelogSection[]; -} - -/** - * Returns the text of the header (without the '## ' prefix) of the given section. - * */ -export function getHeader(section: ChangelogSection): string { - return section.headerLine.replace(/^#+\s+/, "").trimEnd(); -} - -/** Returns `date` formatted as `DD Mon YYYY`. */ -export function getReleaseDateString(today: Date = new Date()): string { - return today.toLocaleDateString("en-GB", { - day: "2-digit", - month: "short", - year: "numeric", - }); -} - -export interface OpenChangelogOptions { - initChangelog?: boolean; -} - -export function withChangelog( - transformer: (contents: string) => string, - options: DryRunOption & OpenChangelogOptions, -): void { - let content: string; - - if (options.initChangelog && !fs.existsSync(CHANGELOG_FILE)) { - content = EMPTY_CHANGELOG; - } else { - content = fs.readFileSync(CHANGELOG_FILE, "utf8"); - } - - if (!options.dryRun) { - fs.writeFileSync(CHANGELOG_FILE, transformer(content), "utf8"); - } else { - console.info(`[DRY RUN] Would have written updated changelog.`); - } -} - -/** - * Updates the `[UNRELEASED]` marker in `CHANGELOG.md` with the given version - * and today's date. - */ -export function setVersionAndDate( - version: string, - content: string, - date: Date = new Date(), -): string { - const versionAndDate = `${version} - ${getReleaseDateString(date)}`; - return content.replace(UNRELEASED_PLACEHOLDER, versionAndDate); -} - -/** - * Parses `content` into a structured representation of a changelog. - * - * @param content The contents of the changelog file. - */ -export function parseChangelog(content: string): Changelog { - const lines = content.split("\n"); - let i = 0; - - const preamble: string[] = []; - const sections: ChangelogSection[] = []; - let currentSection: ChangelogSection | undefined = undefined; - - // Process all lines of the input file. - while (i < lines.length) { - const line = lines[i]; - - // Sections of the changelog start with `## `. - if (line.startsWith("## ")) { - // We have discovered a new section. If `currentSection` is already defined, - // then this marks the end of that section. Push it to the array of sections - // in the changelog. - if (currentSection !== undefined) { - sections.push(currentSection); - } - - // Initialise the new section. - currentSection = { headerLine: line, bodyLines: [] }; - } else if (currentSection !== undefined) { - // Add lines between the section header and the next to the current section. - currentSection.bodyLines.push(line); - } else { - // This is neither a section header nor are we in a section already, - // so this line is part of the preamble. - preamble.push(line); - } - - i++; - } - - // Push the current section to the array of completed sections, if there is - // still one unfinished. - if (currentSection !== undefined) { - sections.push(currentSection); - } - - return { preamble, sections }; -} - -/** - * Inserts the changenotes `lines` in the `[UNRELEASED]` section of `changelog`. - * If the section contains the stock message {@link NO_CHANGES_STR}, then - * `lines` will be inserted in place and the stock message will be deleted. - * - * This function will throw an exception if `[UNRELEASED]` does not exist. - * - * @param changelog The CHANGELOG object to modify. - * @param lines The changenotes to insert. - */ -export function addBodyLinesToUnreleasedSection( - changelog: Changelog, - lines: string[], -) { - // Do nothing if there is nothing to insert. - if (lines.length === 0) return; - - const unreleasedSection = changelog.sections[0]; - if (getHeader(unreleasedSection) !== UNRELEASED_PLACEHOLDER) { - throw Error(`'${UNRELEASED_PLACEHOLDER}' is not the first section of 'CHANGELOG.md'`); - } - - if (unreleasedSection.bodyLines.includes(NO_CHANGES_STR)) { - unreleasedSection.bodyLines = ["", ...lines, ""]; - return; - } - - unreleasedSection.bodyLines.pop(); // Remove the last empty line. - unreleasedSection.bodyLines.push(...lines); - unreleasedSection.bodyLines.push(""); -} - -/** - * Combines an array of lines into a single string by adding line breaks. - */ -export function unlines(lines: string[]): string { - return `${lines.join("\n")}`; -} - -/** - * Renders a given changelog to a string. - */ -export function renderChangelog(changelog: Changelog): string { - let result = unlines(changelog.preamble); - - for (const section of changelog.sections) { - result += `\n${section.headerLine}\n${unlines(section.bodyLines)}`; - } - - return result; -} - -/** - * Processes changelog entries for a backport, converting version references - * from the source major version to the target major version and filtering - * entries that only apply to newer versions. - */ -export function processChangelogForBackports( - sourceBranchMajorVersion: string, - targetBranchMajorVersion: string, - content: string, -): string { - // Changelog entries can use the following format to indicate - // that they only apply to newer versions - const someVersionsOnlyRegex = /\[v(\d+)\+ only\]/; - - // Parse the changelog. - const changelog = parseChangelog(content); - - if (changelog.sections.length === 0) { - throw new Error("Could not find any change sections in CHANGELOG.md"); - } - - // Filter out changelog entries that only apply to newer versions and - // update the section headings with the backport major version for - // sections we keep. - for (const section of changelog.sections) { - // Update the section headings with the backport major version. - section.headerLine = section.headerLine.replace( - `## ${sourceBranchMajorVersion}`, - `## ${targetBranchMajorVersion}`, - ); - - const filteredEntries: string[] = []; - let foundContent = false; - - for (const line of section.bodyLines) { - // Skip the entry if `someVersionsOnlyRegex` matches and the major version - // of the target branch is smaller than the required version. - const match = someVersionsOnlyRegex.exec(line); - if ( - match && - Number.parseInt(targetBranchMajorVersion) < Number.parseInt(match[1]) - ) { - continue; - } - - // Keep the line. - filteredEntries.push(line); - - // Set `foundContent` to `true` if the line is not empty. - if (line.trim() !== "") { - foundContent = true; - } - } - - // Update the section with the retained entries. - section.bodyLines = filteredEntries; - - // Add an entry if we didn't keep any. - if (!foundContent) { - section.bodyLines.push(NO_CHANGES_STR); - } - } - - return renderChangelog(changelog); -} +import * as fs from "node:fs"; + +import { CHANGELOG_FILE, DryRunOption } from "./config"; + +/** The placeholder in the header for unreleased changes. */ +export const UNRELEASED_PLACEHOLDER = "[UNRELEASED]"; + +/** The default contents for a section in the changelog. */ +export const NO_CHANGES_STR = "No user facing changes."; + +/** Placeholder changelog content for a new release. */ +export const EMPTY_CHANGELOG = `# CodeQL Action Changelog + +## ${UNRELEASED_PLACEHOLDER} + +${NO_CHANGES_STR} + +`; + +/** + * Represents sections in a changelog. + */ +export interface ChangelogSection { + headerLine: string; + bodyLines: string[]; +} + +/** + * Represents a changelog. + */ +export interface Changelog { + preamble: string[]; + sections: ChangelogSection[]; +} + +/** + * Returns the text of the header (without the '## ' prefix) of the given section. + * */ +export function getHeader(section: ChangelogSection): string { + return section.headerLine.replace(/^#+\s+/, "").trimEnd(); +} + +/** Returns `date` formatted as `DD Mon YYYY`. */ +export function getReleaseDateString(today: Date = new Date()): string { + return today.toLocaleDateString("en-GB", { + day: "2-digit", + month: "short", + year: "numeric", + }); +} + +export interface OpenChangelogOptions { + initChangelog?: boolean; +} + +export function withChangelog( + transformer: (contents: string) => string, + options: DryRunOption & OpenChangelogOptions, +): void { + let content: string; + + if (options.initChangelog && !fs.existsSync(CHANGELOG_FILE)) { + content = EMPTY_CHANGELOG; + } else { + content = fs.readFileSync(CHANGELOG_FILE, "utf8"); + } + + if (!options.dryRun) { + fs.writeFileSync(CHANGELOG_FILE, transformer(content), "utf8"); + } else { + console.info(`[DRY RUN] Would have written updated changelog.`); + } +} + +/** + * Updates the `[UNRELEASED]` marker in `CHANGELOG.md` with the given version + * and today's date. + */ +export function setVersionAndDate( + version: string, + content: string, + date: Date = new Date(), +): string { + const versionAndDate = `${version} - ${getReleaseDateString(date)}`; + return content.replace(UNRELEASED_PLACEHOLDER, versionAndDate); +} + +/** + * Parses `content` into a structured representation of a changelog. + * + * @param content The contents of the changelog file. + */ +export function parseChangelog(content: string): Changelog { + const lines = content.split("\n"); + let i = 0; + + const preamble: string[] = []; + const sections: ChangelogSection[] = []; + let currentSection: ChangelogSection | undefined = undefined; + + // Process all lines of the input file. + while (i < lines.length) { + const line = lines[i]; + + // Sections of the changelog start with `## `. + if (line.startsWith("## ")) { + // We have discovered a new section. If `currentSection` is already defined, + // then this marks the end of that section. Push it to the array of sections + // in the changelog. + if (currentSection !== undefined) { + sections.push(currentSection); + } + + // Initialise the new section. + currentSection = { headerLine: line, bodyLines: [] }; + } else if (currentSection !== undefined) { + // Add lines between the section header and the next to the current section. + currentSection.bodyLines.push(line); + } else { + // This is neither a section header nor are we in a section already, + // so this line is part of the preamble. + preamble.push(line); + } + + i++; + } + + // Push the current section to the array of completed sections, if there is + // still one unfinished. + if (currentSection !== undefined) { + sections.push(currentSection); + } + + return { preamble, sections }; +} + +/** + * Inserts the changenotes `lines` in the `[UNRELEASED]` section of `changelog`. + * If the section contains the stock message {@link NO_CHANGES_STR}, then + * `lines` will be inserted in place and the stock message will be deleted. + * + * This function will throw an exception if `[UNRELEASED]` does not exist. + * + * @param changelog The CHANGELOG object to modify. + * @param lines The changenotes to insert. + */ +export function addBodyLinesToUnreleasedSection( + changelog: Changelog, + lines: string[], +) { + // Do nothing if there is nothing to insert. + if (lines.length === 0) return; + + const unreleasedSection = changelog.sections[0]; + if (getHeader(unreleasedSection) !== UNRELEASED_PLACEHOLDER) { + throw Error( + `'${UNRELEASED_PLACEHOLDER}' is not the first section of 'CHANGELOG.md'`, + ); + } + + if (unreleasedSection.bodyLines.includes(NO_CHANGES_STR)) { + unreleasedSection.bodyLines = ["", ...lines, ""]; + return; + } + + unreleasedSection.bodyLines.pop(); // Remove the last empty line. + unreleasedSection.bodyLines.push(...lines); + unreleasedSection.bodyLines.push(""); +} + +/** + * Combines an array of lines into a single string by adding line breaks. + */ +export function unlines(lines: string[]): string { + return `${lines.join("\n")}`; +} + +/** + * Renders a given changelog to a string. + */ +export function renderChangelog(changelog: Changelog): string { + let result = unlines(changelog.preamble); + + for (const section of changelog.sections) { + result += `\n${section.headerLine}\n${unlines(section.bodyLines)}`; + } + + return result; +} + +/** + * Processes changelog entries for a backport, converting version references + * from the source major version to the target major version and filtering + * entries that only apply to newer versions. + */ +export function processChangelogForBackports( + sourceBranchMajorVersion: string, + targetBranchMajorVersion: string, + content: string, +): string { + // Changelog entries can use the following format to indicate + // that they only apply to newer versions + const someVersionsOnlyRegex = /\[v(\d+)\+ only\]/; + + // Parse the changelog. + const changelog = parseChangelog(content); + + if (changelog.sections.length === 0) { + throw new Error("Could not find any change sections in CHANGELOG.md"); + } + + // Filter out changelog entries that only apply to newer versions and + // update the section headings with the backport major version for + // sections we keep. + for (const section of changelog.sections) { + // Update the section headings with the backport major version. + section.headerLine = section.headerLine.replace( + `## ${sourceBranchMajorVersion}`, + `## ${targetBranchMajorVersion}`, + ); + + const filteredEntries: string[] = []; + let foundContent = false; + + for (const line of section.bodyLines) { + // Skip the entry if `someVersionsOnlyRegex` matches and the major version + // of the target branch is smaller than the required version. + const match = someVersionsOnlyRegex.exec(line); + if ( + match && + Number.parseInt(targetBranchMajorVersion) < Number.parseInt(match[1]) + ) { + continue; + } + + // Keep the line. + filteredEntries.push(line); + + // Set `foundContent` to `true` if the line is not empty. + if (line.trim() !== "") { + foundContent = true; + } + } + + // Update the section with the retained entries. + section.bodyLines = filteredEntries; + + // Add an entry if we didn't keep any. + if (!foundContent) { + section.bodyLines.push(NO_CHANGES_STR); + } + } + + return renderChangelog(changelog); +} From c0bd54fdf4a49ae453d9ad729e6898dd6fd0a24b Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Mon, 21 Sep 2026 16:36:10 -0500 Subject: [PATCH 19/47] Replace JSDoc text with `@throws` --- pr-checks/changelog.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pr-checks/changelog.ts b/pr-checks/changelog.ts index bee141d2fd..af79666d28 100644 --- a/pr-checks/changelog.ts +++ b/pr-checks/changelog.ts @@ -139,7 +139,7 @@ export function parseChangelog(content: string): Changelog { * If the section contains the stock message {@link NO_CHANGES_STR}, then * `lines` will be inserted in place and the stock message will be deleted. * - * This function will throw an exception if `[UNRELEASED]` does not exist. + * @throws Error -- if the [UNRELEASED] section does not exist. * * @param changelog The CHANGELOG object to modify. * @param lines The changenotes to insert. From b1668d6234eb740e49d28a1b1b78a3947d629516 Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Mon, 21 Sep 2026 16:40:26 -0500 Subject: [PATCH 20/47] Flesh out a comment --- pr-checks/changelog.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pr-checks/changelog.ts b/pr-checks/changelog.ts index af79666d28..496310d21f 100644 --- a/pr-checks/changelog.ts +++ b/pr-checks/changelog.ts @@ -163,7 +163,9 @@ export function addBodyLinesToUnreleasedSection( return; } - unreleasedSection.bodyLines.pop(); // Remove the last empty line. + // The last body line should be a blank line (for spacing). + // Remove it so that we can add `lines` and then add the blank line back. + unreleasedSection.bodyLines.pop(); unreleasedSection.bodyLines.push(...lines); unreleasedSection.bodyLines.push(""); } From 669351e8804d1bed1bd9f9ae4b4d3542e7b495b1 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Wed, 16 Sep 2026 12:29:46 +0100 Subject: [PATCH 21/47] Replace `getRequiredEnvParam` calls in `init` and `setup-codeql` action --- lib/entry-points.js | 14 ++++++++------ src/init-action.ts | 13 +++++++------ src/setup-codeql-action.ts | 7 +++---- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/lib/entry-points.js b/lib/entry-points.js index 0f1282075e..ebb980a70b 100644 --- a/lib/entry-points.js +++ b/lib/entry-points.js @@ -162239,8 +162239,8 @@ async function run3(actionState) { apiDetails = { auth: getRequiredInput("token"), externalRepoAuth: getOptionalInput("external-repository-token"), - url: getRequiredEnvParam("GITHUB_SERVER_URL"), - apiURL: getRequiredEnvParam("GITHUB_API_URL") + url: actionState.env.getRequired("GITHUB_SERVER_URL" /* GITHUB_SERVER_URL */), + apiURL: actionState.env.getRequired("GITHUB_API_URL" /* GITHUB_API_URL */) }; const gitHubVersion = await getGitHubVersion(); checkGitHubVersionInRange(gitHubVersion, logger); @@ -162259,7 +162259,7 @@ async function run3(actionState) { const repositoryProperties = repositoryPropertiesResult.orElse({}); core22.exportVariable("CODEQL_ACTION_INIT_HAS_RUN" /* INIT_ACTION_HAS_RUN */, "true"); sourceRoot = path25.resolve( - getRequiredEnvParam("GITHUB_WORKSPACE"), + actionState.env.getRequired("GITHUB_WORKSPACE" /* GITHUB_WORKSPACE */), getOptionalInput("source-root") || "" ); let analysisKinds; @@ -162355,7 +162355,9 @@ async function run3(actionState) { repository: repositoryNwo, tempDir: getTemporaryDirectory(), codeql, - workspacePath: getRequiredEnvParam("GITHUB_WORKSPACE"), + workspacePath: actionState.env.getRequired( + "GITHUB_WORKSPACE" /* GITHUB_WORKSPACE */ + ), sourceRoot, githubVersion: gitHubVersion, apiDetails, @@ -163254,8 +163256,8 @@ async function run6(actionState) { const apiDetails = { auth: getRequiredInput("token"), externalRepoAuth: getOptionalInput("external-repository-token"), - url: getRequiredEnvParam("GITHUB_SERVER_URL"), - apiURL: getRequiredEnvParam("GITHUB_API_URL") + url: actionState.env.getRequired("GITHUB_SERVER_URL" /* GITHUB_SERVER_URL */), + apiURL: actionState.env.getRequired("GITHUB_API_URL" /* GITHUB_API_URL */) }; const gitHubVersion = await getGitHubVersion(); checkGitHubVersionInRange(gitHubVersion, logger); diff --git a/src/init-action.ts b/src/init-action.ts index 79c509a5be..e770fe9788 100644 --- a/src/init-action.ts +++ b/src/init-action.ts @@ -38,7 +38,7 @@ import { makeDiagnostic, makeTelemetryDiagnostic, } from "./diagnostics"; -import { EnvVar } from "./environment"; +import { ActionsEnvVars, EnvVar } from "./environment"; import { Feature, FeatureEnablement, initFeatures } from "./feature-flags"; import { loadRepositoryProperties } from "./feature-flags/properties"; import { @@ -81,7 +81,6 @@ import { DEFAULT_DEBUG_ARTIFACT_NAME, DEFAULT_DEBUG_DATABASE_NAME, getCodeQLMemoryLimit, - getRequiredEnvParam, getThreadsFlagValue, initializeEnvironment, ConfigurationError, @@ -225,8 +224,8 @@ async function run( apiDetails = { auth: getRequiredInput("token"), externalRepoAuth: getOptionalInput("external-repository-token"), - url: getRequiredEnvParam("GITHUB_SERVER_URL"), - apiURL: getRequiredEnvParam("GITHUB_API_URL"), + url: actionState.env.getRequired(ActionsEnvVars.GITHUB_SERVER_URL), + apiURL: actionState.env.getRequired(ActionsEnvVars.GITHUB_API_URL), }; const gitHubVersion = await getGitHubVersion(); @@ -255,7 +254,7 @@ async function run( // source-root is relative, it is relative to the GITHUB_WORKSPACE. If // source-root is absolute, it is used as given. sourceRoot = path.resolve( - getRequiredEnvParam("GITHUB_WORKSPACE"), + actionState.env.getRequired(ActionsEnvVars.GITHUB_WORKSPACE), getOptionalInput("source-root") || "", ); @@ -383,7 +382,9 @@ async function run( repository: repositoryNwo, tempDir: getTemporaryDirectory(), codeql, - workspacePath: getRequiredEnvParam("GITHUB_WORKSPACE"), + workspacePath: actionState.env.getRequired( + ActionsEnvVars.GITHUB_WORKSPACE, + ), sourceRoot, githubVersion: gitHubVersion, apiDetails, diff --git a/src/setup-codeql-action.ts b/src/setup-codeql-action.ts index 4bd53e517f..91666f19cd 100644 --- a/src/setup-codeql-action.ts +++ b/src/setup-codeql-action.ts @@ -12,7 +12,7 @@ import { getGitHubVersion } from "./api-client"; import { CodeQL } from "./codeql"; import { ComputedInput, getToolsInput } from "./config/inputs"; import { getRawLanguagesNoAutodetect } from "./config-utils"; -import { EnvVar } from "./environment"; +import { ActionsEnvVars, EnvVar } from "./environment"; import { initFeatures } from "./feature-flags"; import { loadRepositoryProperties } from "./feature-flags/properties"; import { initCodeQL } from "./init"; @@ -32,7 +32,6 @@ import { checkDiskUsage, checkForTimeout, checkGitHubVersionInRange, - getRequiredEnvParam, initializeEnvironment, ConfigurationError, wrapError, @@ -108,8 +107,8 @@ async function run( const apiDetails = { auth: getRequiredInput("token"), externalRepoAuth: getOptionalInput("external-repository-token"), - url: getRequiredEnvParam("GITHUB_SERVER_URL"), - apiURL: getRequiredEnvParam("GITHUB_API_URL"), + url: actionState.env.getRequired(ActionsEnvVars.GITHUB_SERVER_URL), + apiURL: actionState.env.getRequired(ActionsEnvVars.GITHUB_API_URL), }; const gitHubVersion = await getGitHubVersion(); From 3a30b151d697aa175402c28a99aca0d24aef4d0c Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Wed, 16 Sep 2026 12:35:13 +0100 Subject: [PATCH 22/47] Refactor `setupDiffInformedQueryRun` querying `checkout_path` itself --- lib/entry-points.js | 16 +++++++++++----- src/analyze-action.ts | 14 +++++++++++--- src/analyze.ts | 4 ++-- 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/lib/entry-points.js b/lib/entry-points.js index ebb980a70b..c49550e59b 100644 --- a/lib/entry-points.js +++ b/lib/entry-points.js @@ -153887,7 +153887,7 @@ async function finalizeDatabaseCreation(codeql, features, config, threadsFlag, m trap_import_duration_ms: Math.round(trapImportTime) }; } -async function setupDiffInformedQueryRun(logger) { +async function setupDiffInformedQueryRun(logger, checkoutPath) { return await withGroupAsync( "Generating diff range extension pack", async () => { @@ -153898,7 +153898,6 @@ async function setupDiffInformedQueryRun(logger) { ); return void 0; } - const checkoutPath = getRequiredInput("checkout_path"); const packDir = writeDiffRangeDataExtensionPack( logger, diffRanges, @@ -156547,7 +156546,11 @@ async function runAutobuildIfLegacyGoWorkflow(config, logger) { ); await runAutobuild(config, "go" /* go */, logger); } -async function run({ startedAt, logger }) { +async function run({ + startedAt, + logger, + actions +}) { let uploadResults = void 0; let runStats = void 0; let config = void 0; @@ -156613,7 +156616,11 @@ async function run({ startedAt, logger }) { getOptionalInput("ram") || process.env["CODEQL_RAM"], logger ); - const diffRangePackDir = await setupDiffInformedQueryRun(logger); + const checkoutPath = actions.getRequiredInput("checkout_path"); + const diffRangePackDir = await setupDiffInformedQueryRun( + logger, + checkoutPath + ); await warnIfGoInstalledAfterInit(config, logger); await runAutobuildIfLegacyGoWorkflow(config, logger); dbCreationTimings = await runFinalize( @@ -156653,7 +156660,6 @@ async function run({ startedAt, logger }) { getOptionalInput("upload") ); if (runStats) { - const checkoutPath = getRequiredInput("checkout_path"); const category = getOptionalInput("category"); uploadResults = await postProcessAndUploadSarif( logger, diff --git a/src/analyze-action.ts b/src/analyze-action.ts index c3c2e40e7f..2a64ed3c54 100644 --- a/src/analyze-action.ts +++ b/src/analyze-action.ts @@ -212,7 +212,11 @@ async function runAutobuildIfLegacyGoWorkflow(config: Config, logger: Logger) { await runAutobuild(config, BuiltInLanguage.go, logger); } -async function run({ startedAt, logger }: ActionState<["Base", "Logger"]>) { +async function run({ + startedAt, + logger, + actions, +}: ActionState<["Base", "Logger", "Actions"]>) { // To capture errors appropriately, keep as much code within the try-catch as // possible, and only use safe functions outside. @@ -307,8 +311,13 @@ async function run({ startedAt, logger }: ActionState<["Base", "Logger"]>) { logger, ); + const checkoutPath = actions.getRequiredInput("checkout_path"); + // Setup diff informed analysis if needed (based on whether init created the file) - const diffRangePackDir = await setupDiffInformedQueryRun(logger); + const diffRangePackDir = await setupDiffInformedQueryRun( + logger, + checkoutPath, + ); await warnIfGoInstalledAfterInit(config, logger); await runAutobuildIfLegacyGoWorkflow(config, logger); @@ -354,7 +363,6 @@ async function run({ startedAt, logger }: ActionState<["Base", "Logger"]>) { actionsUtil.getOptionalInput("upload"), ); if (runStats) { - const checkoutPath = actionsUtil.getRequiredInput("checkout_path"); const category = actionsUtil.getOptionalInput("category"); uploadResults = await postProcessAndUploadSarif( diff --git a/src/analyze.ts b/src/analyze.ts index 411477b597..8f90711682 100644 --- a/src/analyze.ts +++ b/src/analyze.ts @@ -5,7 +5,7 @@ import { performance } from "perf_hooks"; import * as io from "@actions/io"; import * as yaml from "js-yaml"; -import { getTemporaryDirectory, getRequiredInput } from "./actions-util"; +import { getTemporaryDirectory } from "./actions-util"; import * as analyses from "./analyses"; import { setupCppAutobuild } from "./autobuild"; import { type CodeQL } from "./codeql"; @@ -233,6 +233,7 @@ async function finalizeDatabaseCreation( */ export async function setupDiffInformedQueryRun( logger: Logger, + checkoutPath: string, ): Promise { return await withGroupAsync( "Generating diff range extension pack", @@ -245,7 +246,6 @@ export async function setupDiffInformedQueryRun( return undefined; } - const checkoutPath = getRequiredInput("checkout_path"); const packDir = writeDiffRangeDataExtensionPack( logger, diffRanges, From ada4e83349a368bd2631e8d92ac54b63e1f30608 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Wed, 16 Sep 2026 12:37:49 +0100 Subject: [PATCH 23/47] Refactor `cleanupAndUploadOverlayBaseDatabaseToCache` querying `checkout_path` itself --- lib/entry-points.js | 10 +++++++--- src/analyze-action.ts | 7 ++++++- src/overlay/caching.ts | 11 ++++------- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/lib/entry-points.js b/lib/entry-points.js index c49550e59b..9fd643f247 100644 --- a/lib/entry-points.js +++ b/lib/entry-points.js @@ -151255,7 +151255,7 @@ async function checkOverlayBaseDatabase(codeql, config, logger, warningPrefix) { } return true; } -async function cleanupAndUploadOverlayBaseDatabaseToCache(codeql, config, logger) { +async function cleanupAndUploadOverlayBaseDatabaseToCache(codeql, config, logger, checkoutPath) { const overlayDatabaseMode = config.overlayDatabaseMode; if (overlayDatabaseMode !== "overlay-base" /* OverlayBase */) { logger.debug( @@ -151303,7 +151303,6 @@ async function cleanupAndUploadOverlayBaseDatabaseToCache(codeql, config, logger return false; } const codeQlVersion = (await codeql.getVersion()).version; - const checkoutPath = getRequiredInput("checkout_path"); const cacheSaveKey = await getCacheSaveKey( config, codeQlVersion, @@ -156685,7 +156684,12 @@ async function run({ } else { logger.info("Not uploading results"); } - await cleanupAndUploadOverlayBaseDatabaseToCache(codeql, config, logger); + await cleanupAndUploadOverlayBaseDatabaseToCache( + codeql, + config, + logger, + checkoutPath + ); databaseUploadResults = await cleanupAndUploadDatabases( repositoryNwo, codeql, diff --git a/src/analyze-action.ts b/src/analyze-action.ts index 2a64ed3c54..55803d2611 100644 --- a/src/analyze-action.ts +++ b/src/analyze-action.ts @@ -396,7 +396,12 @@ async function run({ // Possibly upload the overlay-base database to actions cache. // Note: Take care with the ordering of this call since databases may be cleaned up // at the `overlay` level. - await cleanupAndUploadOverlayBaseDatabaseToCache(codeql, config, logger); + await cleanupAndUploadOverlayBaseDatabaseToCache( + codeql, + config, + logger, + checkoutPath, + ); // Possibly upload the database bundles for remote queries. // Note: Take care with the ordering of this call since databases may be cleaned up diff --git a/src/overlay/caching.ts b/src/overlay/caching.ts index c4557cd4ef..d246626780 100644 --- a/src/overlay/caching.ts +++ b/src/overlay/caching.ts @@ -3,11 +3,7 @@ import * as fs from "fs"; import * as actionsCache from "@actions/cache"; import * as semver from "semver"; -import { - getRequiredInput, - getWorkflowRunAttempt, - getWorkflowRunID, -} from "../actions-util"; +import { getWorkflowRunAttempt, getWorkflowRunID } from "../actions-util"; import { getAutomationID, listActionsCaches } from "../api-client"; import { createCacheKeyHash } from "../caching-utils"; import { type CodeQL } from "../codeql"; @@ -107,12 +103,13 @@ async function checkOverlayBaseDatabase( * Uploads the overlay-base database to the GitHub Actions cache. If conditions * for uploading are not met, the function does nothing and returns false. * - * This function uses the `checkout_path` input to determine the repository path + * This function uses the `checkoutPath` to determine the repository path * and works only when called from `analyze` or `upload-sarif`. * * @param codeql The CodeQL instance * @param config The configuration object * @param logger The logger instance + * @param checkoutPath The path at which the repository is checked out at. * @returns A promise that resolves to true if the upload was performed and * successfully completed, or false otherwise */ @@ -120,6 +117,7 @@ export async function cleanupAndUploadOverlayBaseDatabaseToCache( codeql: CodeQL, config: Config, logger: Logger, + checkoutPath: string, ): Promise { const overlayDatabaseMode = config.overlayDatabaseMode; if (overlayDatabaseMode !== OverlayDatabaseMode.OverlayBase) { @@ -180,7 +178,6 @@ export async function cleanupAndUploadOverlayBaseDatabaseToCache( } const codeQlVersion = (await codeql.getVersion()).version; - const checkoutPath = getRequiredInput("checkout_path"); const cacheSaveKey = await getCacheSaveKey( config, codeQlVersion, From 8a88af684982fdc308a6949123d2894263f2ef88 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Wed, 16 Sep 2026 12:57:20 +0100 Subject: [PATCH 24/47] Refactor `cleanupAndUploadDatabases` querying `checkout_path` itself --- lib/entry-points.js | 13 ++-- src/analyze-action.ts | 4 +- src/database-upload.test.ts | 134 +++++++++++++++++++++--------------- src/database-upload.ts | 15 ++-- 4 files changed, 95 insertions(+), 71 deletions(-) diff --git a/lib/entry-points.js b/lib/entry-points.js index 9fd643f247..3fbacc32e4 100644 --- a/lib/entry-points.js +++ b/lib/entry-points.js @@ -154172,7 +154172,8 @@ async function warnIfGoInstalledAfterInit(config, logger) { // src/database-upload.ts var fs18 = __toESM(require("fs")); -async function cleanupAndUploadDatabases(repositoryNwo, codeql, config, apiDetails, features, logger) { +async function cleanupAndUploadDatabases(action, repositoryNwo, codeql, config, apiDetails, checkoutPath) { + const logger = action.logger; if (getRequiredInput("upload-database") !== "true") { logger.debug("Database upload disabled in workflow. Skipping upload."); return []; @@ -154195,7 +154196,7 @@ async function cleanupAndUploadDatabases(repositoryNwo, codeql, config, apiDetai logger.debug("Not analyzing default branch. Skipping upload."); return []; } - const shouldUploadOverlayBase = config.overlayDatabaseMode === "overlay-base" /* OverlayBase */ && await features.getValue("upload_overlay_db_to_api" /* UploadOverlayDbToApi */, codeql); + const shouldUploadOverlayBase = config.overlayDatabaseMode === "overlay-base" /* OverlayBase */ && await action.features.getValue("upload_overlay_db_to_api" /* UploadOverlayDbToApi */, codeql); const cleanupLevel = shouldUploadOverlayBase ? "overlay" /* Overlay */ : "clear" /* Clear */; await withGroupAsync("Cleaning up databases", async () => { await codeql.databaseCleanupCluster(config, cleanupLevel); @@ -154208,9 +154209,7 @@ async function cleanupAndUploadDatabases(repositoryNwo, codeql, config, apiDetai includeDiagnostics: false }); bundledDbSize = fs18.statSync(bundledDb).size; - const commitOid = await getCommitOid( - getRequiredInput("checkout_path") - ); + const commitOid = await getCommitOid(checkoutPath); const maxAttempts = 4; let uploadDurationMs; for (let attempt = 1; attempt <= maxAttempts; attempt++) { @@ -156691,12 +156690,12 @@ async function run({ checkoutPath ); databaseUploadResults = await cleanupAndUploadDatabases( + { logger, features }, repositoryNwo, codeql, config, apiDetails, - features, - logger + checkoutPath ); const trapCacheUploadStartTime = import_perf_hooks6.performance.now(); didUploadTrapCaches = await uploadTrapCaches(codeql, config, logger); diff --git a/src/analyze-action.ts b/src/analyze-action.ts index 55803d2611..7963fa52bf 100644 --- a/src/analyze-action.ts +++ b/src/analyze-action.ts @@ -407,12 +407,12 @@ async function run({ // Note: Take care with the ordering of this call since databases may be cleaned up // at the `overlay` or `clear` level. databaseUploadResults = await cleanupAndUploadDatabases( + { logger, features }, repositoryNwo, codeql, config, apiDetails, - features, - logger, + checkoutPath, ); // Possibly upload the TRAP caches for later re-use diff --git a/src/database-upload.test.ts b/src/database-upload.test.ts index bcaf9f1c9e..b6ac5c8115 100644 --- a/src/database-upload.test.ts +++ b/src/database-upload.test.ts @@ -20,8 +20,9 @@ import { checkExpectedLogMessages, createFeatures, createTestConfig, - getRecordingLogger, - LoggedMessage, + getTestEnv, + initAllState, + RecordingLogger, setupActionsVars, setupTests, } from "./testing-utils"; @@ -90,23 +91,24 @@ test.serial( "Abort database upload if 'upload-database' input set to false", async (t) => { await withTmpDir(async (tmpDir) => { - setupActionsVars(tmpDir, tmpDir); + const env = getTestEnv(); + setupActionsVars(tmpDir, tmpDir, {}, env); sinon .stub(actionsUtil, "getRequiredInput") .withArgs("upload-database") .returns("false"); sinon.stub(gitUtils, "isAnalyzingDefaultBranch").resolves(true); - const loggedMessages: LoggedMessage[] = []; + const logger = new RecordingLogger(); await cleanupAndUploadDatabases( + initAllState({ env, logger }), testRepoName, getCodeQL(), getTestConfig(tmpDir), testApiDetails, - createFeatures([]), - getRecordingLogger(loggedMessages), + "", ); - checkExpectedLogMessages(t, loggedMessages, [ + checkExpectedLogMessages(t, logger.messages, [ "Database upload disabled in workflow. Skipping upload.", ]); }); @@ -117,7 +119,8 @@ test.serial( "Abort database upload if 'analysis-kinds: code-scanning' is not enabled", async (t) => { await withTmpDir(async (tmpDir) => { - setupActionsVars(tmpDir, tmpDir); + const env = getTestEnv(); + setupActionsVars(tmpDir, tmpDir, {}, env); sinon .stub(actionsUtil, "getRequiredInput") .withArgs("upload-database") @@ -126,8 +129,9 @@ test.serial( await mockHttpRequests(201); - const loggedMessages: LoggedMessage[] = []; + const logger = new RecordingLogger(); await cleanupAndUploadDatabases( + initAllState({ env, logger }), testRepoName, getCodeQL(), { @@ -135,10 +139,9 @@ test.serial( analysisKinds: [AnalysisKind.CodeQuality], }, testApiDetails, - createFeatures([]), - getRecordingLogger(loggedMessages), + "", ); - checkExpectedLogMessages(t, loggedMessages, [ + checkExpectedLogMessages(t, logger.messages, [ "Not uploading database because 'analysis-kinds: code-scanning' is not enabled.", ]); }); @@ -147,7 +150,8 @@ test.serial( test.serial("Abort database upload if running against GHES", async (t) => { await withTmpDir(async (tmpDir) => { - setupActionsVars(tmpDir, tmpDir); + const env = getTestEnv(); + setupActionsVars(tmpDir, tmpDir, {}, env); sinon .stub(actionsUtil, "getRequiredInput") .withArgs("upload-database") @@ -157,16 +161,16 @@ test.serial("Abort database upload if running against GHES", async (t) => { const config = getTestConfig(tmpDir); config.gitHubVersion = { type: GitHubVariant.GHES, version: "3.0" }; - const loggedMessages: LoggedMessage[] = []; + const logger = new RecordingLogger(); await cleanupAndUploadDatabases( + initAllState({ env, logger }), testRepoName, getCodeQL(), config, testApiDetails, - createFeatures([]), - getRecordingLogger(loggedMessages), + "", ); - checkExpectedLogMessages(t, loggedMessages, [ + checkExpectedLogMessages(t, logger.messages, [ "Not running against github.com or GHEC-DR. Skipping upload.", ]); }); @@ -176,23 +180,24 @@ test.serial( "Abort database upload if not analyzing default branch", async (t) => { await withTmpDir(async (tmpDir) => { - setupActionsVars(tmpDir, tmpDir); + const env = getTestEnv(); + setupActionsVars(tmpDir, tmpDir, {}, env); sinon .stub(actionsUtil, "getRequiredInput") .withArgs("upload-database") .returns("true"); sinon.stub(gitUtils, "isAnalyzingDefaultBranch").resolves(false); - const loggedMessages: LoggedMessage[] = []; + const logger = new RecordingLogger(); await cleanupAndUploadDatabases( + initAllState({ env, logger }), testRepoName, getCodeQL(), getTestConfig(tmpDir), testApiDetails, - createFeatures([]), - getRecordingLogger(loggedMessages), + "", ); - checkExpectedLogMessages(t, loggedMessages, [ + checkExpectedLogMessages(t, logger.messages, [ "Not analyzing default branch. Skipping upload.", ]); }); @@ -203,7 +208,8 @@ test.serial( "Don't crash if uploading a database fails with a non-retryable error", async (t) => { await withTmpDir(async (tmpDir) => { - setupActionsVars(tmpDir, tmpDir); + const env = getTestEnv(); + setupActionsVars(tmpDir, tmpDir, {}, env); sinon .stub(actionsUtil, "getRequiredInput") .withArgs("upload-database") @@ -212,17 +218,17 @@ test.serial( const databaseUploadSpy = await mockHttpRequests(422); - const loggedMessages: LoggedMessage[] = []; + const logger = new RecordingLogger(); await cleanupAndUploadDatabases( + initAllState({ env, logger }), testRepoName, getCodeQL(), getTestConfig(tmpDir), testApiDetails, - createFeatures([]), - getRecordingLogger(loggedMessages), + "", ); - checkExpectedLogMessages(t, loggedMessages, [ + checkExpectedLogMessages(t, logger.messages, [ "Failed to upload database for javascript: some error message", ]); @@ -236,7 +242,8 @@ test.serial( "Don't crash if uploading a database fails with a retryable error", async (t) => { await withTmpDir(async (tmpDir) => { - setupActionsVars(tmpDir, tmpDir); + const env = getTestEnv(); + setupActionsVars(tmpDir, tmpDir, {}, env); sinon .stub(actionsUtil, "getRequiredInput") .withArgs("upload-database") @@ -251,17 +258,17 @@ test.serial( .stub(global, "setTimeout") .callsFake((fn: () => void) => originalSetTimeout(fn, 0)); - const loggedMessages: LoggedMessage[] = []; + const logger = new RecordingLogger(); await cleanupAndUploadDatabases( + initAllState({ env, logger }), testRepoName, getCodeQL(), getTestConfig(tmpDir), testApiDetails, - createFeatures([]), - getRecordingLogger(loggedMessages), + "", ); - checkExpectedLogMessages(t, loggedMessages, [ + checkExpectedLogMessages(t, logger.messages, [ "Failed to upload database for javascript: some error message", ]); @@ -279,7 +286,8 @@ test.serial( test.serial("Successfully uploading a database to github.com", async (t) => { await withTmpDir(async (tmpDir) => { - setupActionsVars(tmpDir, tmpDir); + const env = getTestEnv(); + setupActionsVars(tmpDir, tmpDir, {}, env); sinon .stub(actionsUtil, "getRequiredInput") .withArgs("upload-database") @@ -288,16 +296,16 @@ test.serial("Successfully uploading a database to github.com", async (t) => { await mockHttpRequests(201); - const loggedMessages: LoggedMessage[] = []; + const logger = new RecordingLogger(); await cleanupAndUploadDatabases( + initAllState({ env, logger }), testRepoName, getCodeQL(), getTestConfig(tmpDir), testApiDetails, - createFeatures([]), - getRecordingLogger(loggedMessages), + "", ); - checkExpectedLogMessages(t, loggedMessages, [ + checkExpectedLogMessages(t, logger.messages, [ "Successfully uploaded database for javascript", ]); }); @@ -305,7 +313,8 @@ test.serial("Successfully uploading a database to github.com", async (t) => { test.serial("Successfully uploading a database to GHEC-DR", async (t) => { await withTmpDir(async (tmpDir) => { - setupActionsVars(tmpDir, tmpDir); + const env = getTestEnv(); + setupActionsVars(tmpDir, tmpDir, {}, env); sinon .stub(actionsUtil, "getRequiredInput") .withArgs("upload-database") @@ -314,8 +323,9 @@ test.serial("Successfully uploading a database to GHEC-DR", async (t) => { const databaseUploadSpy = await mockHttpRequests(201); - const loggedMessages: LoggedMessage[] = []; + const logger = new RecordingLogger(); await cleanupAndUploadDatabases( + initAllState({ env, logger }), testRepoName, getCodeQL(), getTestConfig(tmpDir), @@ -324,10 +334,9 @@ test.serial("Successfully uploading a database to GHEC-DR", async (t) => { url: "https://tenant.ghe.com", apiURL: undefined, }, - createFeatures([]), - getRecordingLogger(loggedMessages), + "", ); - checkExpectedLogMessages(t, loggedMessages, [ + checkExpectedLogMessages(t, logger.messages, [ "Successfully uploaded database for javascript", ]); t.assert( @@ -343,7 +352,8 @@ test.serial( "Records overlay and clear cleanup sizes when uploading an overlay-base database", async (t) => { await withTmpDir(async (tmpDir) => { - setupActionsVars(tmpDir, tmpDir); + const env = getTestEnv(); + setupActionsVars(tmpDir, tmpDir, {}, env); sinon .stub(actionsUtil, "getRequiredInput") .withArgs("upload-database") @@ -375,14 +385,16 @@ test.serial( const config = getTestConfig(tmpDir); config.overlayDatabaseMode = OverlayDatabaseMode.OverlayBase; - const loggedMessages: LoggedMessage[] = []; const results = await cleanupAndUploadDatabases( + initAllState({ + env, + features: createFeatures([Feature.UploadOverlayDbToApi]), + }), testRepoName, codeql, config, testApiDetails, - createFeatures([Feature.UploadOverlayDbToApi]), - getRecordingLogger(loggedMessages), + "", ); // The database should be cleaned up at the `overlay` level for the upload @@ -402,7 +414,8 @@ test.serial( "Does not measure clear cleanup size for a regular (non-overlay-base) upload", async (t) => { await withTmpDir(async (tmpDir) => { - setupActionsVars(tmpDir, tmpDir); + const env = getTestEnv(); + setupActionsVars(tmpDir, tmpDir, {}, env); sinon .stub(actionsUtil, "getRequiredInput") .withArgs("upload-database") @@ -422,12 +435,15 @@ test.serial( }); const results = await cleanupAndUploadDatabases( + initAllState({ + env, + features: createFeatures([Feature.UploadOverlayDbToApi]), + }), testRepoName, codeql, getTestConfig(tmpDir), testApiDetails, - createFeatures([Feature.UploadOverlayDbToApi]), - getRecordingLogger([]), + "", ); // A regular upload is cleaned only once, at the `clear` level. @@ -441,7 +457,8 @@ test.serial( test.serial("Does not measure clear cleanup size in debug mode", async (t) => { await withTmpDir(async (tmpDir) => { - setupActionsVars(tmpDir, tmpDir); + const env = getTestEnv(); + setupActionsVars(tmpDir, tmpDir, {}, env); sinon .stub(actionsUtil, "getRequiredInput") .withArgs("upload-database") @@ -465,12 +482,15 @@ test.serial("Does not measure clear cleanup size in debug mode", async (t) => { config.debugMode = true; const results = await cleanupAndUploadDatabases( + initAllState({ + env, + features: createFeatures([Feature.UploadOverlayDbToApi]), + }), testRepoName, codeql, config, testApiDetails, - createFeatures([Feature.UploadOverlayDbToApi]), - getRecordingLogger([]), + "", ); // In debug mode we clean up at the `overlay` level for the upload but skip @@ -486,7 +506,8 @@ test.serial( "Does not record a clear cleanup duration when the clear cleanup fails", async (t) => { await withTmpDir(async (tmpDir) => { - setupActionsVars(tmpDir, tmpDir); + const env = getTestEnv(); + setupActionsVars(tmpDir, tmpDir, {}, env); sinon .stub(actionsUtil, "getRequiredInput") .withArgs("upload-database") @@ -510,12 +531,15 @@ test.serial( config.overlayDatabaseMode = OverlayDatabaseMode.OverlayBase; const results = await cleanupAndUploadDatabases( + initAllState({ + env, + features: createFeatures([Feature.UploadOverlayDbToApi]), + }), testRepoName, codeql, config, testApiDetails, - createFeatures([Feature.UploadOverlayDbToApi]), - getRecordingLogger([]), + "", ); // When the `clear` cleanup fails, no size is measured, so we should not diff --git a/src/database-upload.ts b/src/database-upload.ts index 0189bef1e6..9e4339fd47 100644 --- a/src/database-upload.ts +++ b/src/database-upload.ts @@ -1,5 +1,6 @@ import * as fs from "fs"; +import { ActionState } from "./action-common"; import * as actionsUtil from "./actions-util"; import { AnalysisKind } from "./analyses"; import { @@ -9,7 +10,7 @@ import { } from "./api-client"; import { type CodeQL } from "./codeql"; import { Config } from "./config-utils"; -import { Feature, FeatureEnablement } from "./feature-flags"; +import { Feature } from "./feature-flags"; import * as gitUtils from "./git-utils"; import { Logger, withGroupAsync } from "./logging"; import { OverlayDatabaseMode } from "./overlay/overlay-database-mode"; @@ -45,13 +46,15 @@ export interface DatabaseUploadResult { } export async function cleanupAndUploadDatabases( + action: ActionState<["Logger", "FeatureFlags"]>, repositoryNwo: RepositoryNwo, codeql: CodeQL, config: Config, apiDetails: GitHubApiDetails, - features: FeatureEnablement, - logger: Logger, + checkoutPath: string, ): Promise { + const logger = action.logger; + if (actionsUtil.getRequiredInput("upload-database") !== "true") { logger.debug("Database upload disabled in workflow. Skipping upload."); return []; @@ -87,7 +90,7 @@ export async function cleanupAndUploadDatabases( // If config.overlayDatabaseMode is OverlayBase, then we have overlay base databases for all languages. const shouldUploadOverlayBase = config.overlayDatabaseMode === OverlayDatabaseMode.OverlayBase && - (await features.getValue(Feature.UploadOverlayDbToApi, codeql)); + (await action.features.getValue(Feature.UploadOverlayDbToApi, codeql)); const cleanupLevel = shouldUploadOverlayBase ? CleanupLevel.Overlay : CleanupLevel.Clear; @@ -110,9 +113,7 @@ export async function cleanupAndUploadDatabases( includeDiagnostics: false, }); bundledDbSize = fs.statSync(bundledDb).size; - const commitOid = await gitUtils.getCommitOid( - actionsUtil.getRequiredInput("checkout_path"), - ); + const commitOid = await gitUtils.getCommitOid(checkoutPath); // Upload with manual retry logic. We disable Octokit's built-in retries // because the request body is a ReadStream, which can only be consumed // once. From 738bd621865ef8a960c3af80dff9ddb000ff9ebc Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Fri, 18 Sep 2026 12:50:23 -0500 Subject: [PATCH 25/47] Refactor `changenotes validate` to use helper `getChangenotes` This reduces duplicate code between `assemble` and `validate`. It also has the benefit of fixing a bug in the current implementation of `validate`, where `isValidChangenoteFile` receives a relative file name where it should receive an absolute one. --- pr-checks/changelog/validate.mts | 11 ------- pr-checks/changelog/validate.test.mts | 41 +-------------------------- pr-checks/changenotes.mts | 8 ++++-- 3 files changed, 7 insertions(+), 53 deletions(-) diff --git a/pr-checks/changelog/validate.mts b/pr-checks/changelog/validate.mts index 2e28a4ab13..3c83276f38 100644 --- a/pr-checks/changelog/validate.mts +++ b/pr-checks/changelog/validate.mts @@ -119,14 +119,3 @@ export function isValidChangenoteFile(filename: string): boolean { return isValid; } - -/** - * Validates the change-note files of the given list of file paths, ignoring ".gitkeep". - * @param filepaths A list of filepaths to validate - * @returns True if all the paths are valid, false otherwise. - */ -export function isValidAllChangenoteFiles(filepaths: string[]): boolean { - return filepaths - .filter((f) => f !== ".gitkeep") - .reduce((r, filePath) => r && isValidChangenoteFile(filePath), true); -} diff --git a/pr-checks/changelog/validate.test.mts b/pr-checks/changelog/validate.test.mts index a38339d1c9..b8b1e33bb0 100644 --- a/pr-checks/changelog/validate.test.mts +++ b/pr-checks/changelog/validate.test.mts @@ -1,13 +1,10 @@ import assert from "node:assert/strict"; -import * as fs from "node:fs"; -import * as path from "node:path"; import { describe, it } from "node:test"; -import { withTmpDir, withTmpFile } from "../../src/util"; +import { withTmpFile } from "../../src/util"; import { hasValidChangenoteCategory, - isValidAllChangenoteFiles, isValidChangenoteContent, isValidChangenoteFile, isValidChangenoteFilename, @@ -187,39 +184,3 @@ await describe("isValidChangenoteFile", async () => { ); }); }); - -await describe("isValidAllChangenoteFiles", async () => { - await it("accepts list of file paths of valid change-notes", async () => { - await withTmpDir(async (tmpDir) => { - const fileName1 = path.join(tmpDir, "2026-01-01-fix-bug.md"); - const fileName2 = path.join(tmpDir, "2026-01-02-add-feature.md"); - fs.writeFileSync(fileName1, "---\ncategory: fix\n---\n- Fixed a bug\n"); - fs.writeFileSync( - fileName2, - "---\ncategory: feature\n---\n- Added a feature\n", - ); - assert.equal(isValidAllChangenoteFiles([fileName1, fileName2]), true); - }); - }); - - await it("accepts the empty list", async () => { - assert.equal(isValidAllChangenoteFiles([]), true); - }); - - await it("accepts list of .gitkeep", async () => { - assert.equal(isValidAllChangenoteFiles([".gitkeep"]), true); - }); - - await it("rejects list containing a file path to an invalid change-note", async () => { - await withTmpDir(async (tmpDir) => { - const fileName1 = path.join(tmpDir, "2026-01-01-fix-bug.md"); - const fileName2 = path.join(tmpDir, "2026-01-02-wrong-category.md"); - fs.writeFileSync(fileName1, "---\ncategory: fix\n---\n- Fixed a bug\n"); - fs.writeFileSync( - fileName2, - "---\ncategory: foobar\n---\n- Added a feature\n", - ); - assert.equal(isValidAllChangenoteFiles([fileName1, fileName2]), false); - }); - }); -}); diff --git a/pr-checks/changenotes.mts b/pr-checks/changenotes.mts index d19d2da83b..980d103a28 100755 --- a/pr-checks/changenotes.mts +++ b/pr-checks/changenotes.mts @@ -14,7 +14,7 @@ import { renderChangelog, withChangelog, } from "./changelog"; -import { isValidAllChangenoteFiles } from "./changelog/validate.mjs"; +import { isValidChangenoteFile } from "./changelog/validate.mjs"; import { CHANGENOTES_DIR } from "./config"; /** @@ -116,7 +116,11 @@ function assemble(): ExitCode { function validate(): ExitCode { try { - if (isValidAllChangenoteFiles(fs.readdirSync(CHANGENOTES_DIR))) { + const allChangenotesValid = getChangenotes().reduce( + (r, changenote) => r && isValidChangenoteFile(changenote.absolutePath), + true, + ); + if (allChangenotesValid) { console.log(`All changenotes in '${CHANGENOTES_DIR}' are valid.`); return ExitCode.Success; } From 07dc94940e1af55d7da55811119e389c5acac178 Mon Sep 17 00:00:00 2001 From: Henry Mercer Date: Tue, 22 Sep 2026 16:07:07 +0100 Subject: [PATCH 26/47] Use default state in per-language bundle tests Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- src/per-language-bundles.test.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/per-language-bundles.test.ts b/src/per-language-bundles.test.ts index b8f48512fe..0330b51a63 100644 --- a/src/per-language-bundles.test.ts +++ b/src/per-language-bundles.test.ts @@ -38,7 +38,6 @@ async function checkEligibility( [ActionsEnvVars.RUNNER_ENVIRONMENT]: "github-hosted", }), features: createFeatures([Feature.PerLanguageBundles]), - logger: getRecordingLogger([], { logToConsole: false }), ...stateOverrides, }), { ...ELIGIBLE_OPTIONS, ...overrides }, @@ -134,7 +133,6 @@ test("getPerLanguageBundleLanguage explains a disabled feature before checking e const messages: LoggedMessage[] = []; const language = await getPerLanguageBundleLanguage( initAllState({ - env: getTestEnv(), features: createFeatures([]), logger: getRecordingLogger(messages, { logToConsole: false }), }), From 06344e2ba1565124d7acef663be8ff3b6f42643f Mon Sep 17 00:00:00 2001 From: Henry Mercer Date: Tue, 22 Sep 2026 16:07:09 +0100 Subject: [PATCH 27/47] Stub nightly release listing directly Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- src/setup-codeql.test.ts | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/src/setup-codeql.test.ts b/src/setup-codeql.test.ts index c35bdb8406..6ac5bebf18 100644 --- a/src/setup-codeql.test.ts +++ b/src/setup-codeql.test.ts @@ -69,25 +69,29 @@ function stubHostedNightly(tagName: string) { available: true, foundZstdBinary: true, }); - const fetchRelease = sinon - .stub, ReturnType>() - .rejects(new Error("Unexpected API request in nightly bundle test")); - fetchRelease - .withArgs( - "https://api.github.com/repos/dsp-testing/codeql-cli-nightlies/releases?per_page=1&page=1&prerelease=true", - sinon.match({ method: "GET" }), - ) - .callsFake( - async () => - new Response(JSON.stringify([{ tag_name: tagName }]), { - headers: { "content-type": "application/json" }, - }), - ); const client = github.getOctokit("123", { - request: { fetch: fetchRelease }, + request: { + fetch: async () => { + throw new Error("Unexpected API request in nightly bundle test"); + }, + }, }); + const listReleases = sinon + .stub(client.rest.repos, "listReleases") + .rejects(new Error("Unexpected release request in nightly bundle test")); + listReleases + .withArgs({ + owner: "dsp-testing", + repo: "codeql-cli-nightlies", + per_page: 1, + page: 1, + prerelease: true, + }) + .resolves({ + data: [{ tag_name: tagName }], + } as Awaited>); sinon.stub(api, "getApiClient").value(() => client); - return fetchRelease; + return listReleases; } test.serial("parse codeql bundle url version", (t) => { From dba87a18dc3eb9d4d09a0585f4148670685519de Mon Sep 17 00:00:00 2001 From: Henry Mercer Date: Tue, 22 Sep 2026 16:07:10 +0100 Subject: [PATCH 28/47] Clarify elapsed-time helper documentation Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- src/util.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util.ts b/src/util.ts index 456cd7c3d2..d74e07fa8d 100644 --- a/src/util.ts +++ b/src/util.ts @@ -682,7 +682,7 @@ export async function bundleDb( return databaseBundlePath; } -/** Returns the elapsed milliseconds, rounded, since a `performance.now()` timestamp. */ +/** Returns the elapsed milliseconds, rounded, since `startTime` was recorded with `performance.now()`. */ export function durationMsSince(startTime: number): number { return Math.round(performance.now() - startTime); } From a9a8cd1aecbbc419b7b38acc138c3e3cd844b0f9 Mon Sep 17 00:00:00 2001 From: Henry Mercer Date: Tue, 22 Sep 2026 16:07:10 +0100 Subject: [PATCH 29/47] Explain the nightly bundle version-check exception Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- src/per-language-bundles.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/per-language-bundles.ts b/src/per-language-bundles.ts index f4e46403db..35cfa3e0f5 100644 --- a/src/per-language-bundles.ts +++ b/src/per-language-bundles.ts @@ -102,8 +102,9 @@ export async function getPerLanguageBundleLanguage( return explain("the job is not running on a GitHub-hosted runner"); } - // Check whether per-language bundles are published for the requested CLI version. - // Latest-nightly selection skips this release-version check, but not the other eligibility checks. + // If the user requested the latest nightly, skip the version check, as nightlies have shipped + // per-language bundles since https://github.com/dsp-testing/codeql-cli-nightlies/releases/tag/codeql-bundle-20260909. + // Otherwise, check the requested CLI version to determine whether per-language bundles are published. if (!isLatestNightly) { if (cliVersion === undefined) { return explain("the requested CLI version is unknown"); From f2ec2f6267210c6d22b53d32be7048187043bd34 Mon Sep 17 00:00:00 2001 From: Henry Mercer Date: Tue, 22 Sep 2026 16:23:55 +0100 Subject: [PATCH 30/47] Tweak comment for latest nightly version check Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- src/per-language-bundles.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/per-language-bundles.ts b/src/per-language-bundles.ts index 35cfa3e0f5..6f80096834 100644 --- a/src/per-language-bundles.ts +++ b/src/per-language-bundles.ts @@ -102,7 +102,7 @@ export async function getPerLanguageBundleLanguage( return explain("the job is not running on a GitHub-hosted runner"); } - // If the user requested the latest nightly, skip the version check, as nightlies have shipped + // When selecting the latest nightly, skip the version check, as nightlies have shipped // per-language bundles since https://github.com/dsp-testing/codeql-cli-nightlies/releases/tag/codeql-bundle-20260909. // Otherwise, check the requested CLI version to determine whether per-language bundles are published. if (!isLatestNightly) { From 48321b2d4823e75454e91867ded94e394d33343b Mon Sep 17 00:00:00 2001 From: Henry Mercer Date: Tue, 22 Sep 2026 16:49:21 +0100 Subject: [PATCH 31/47] Update src/per-language-bundles.ts Co-authored-by: Michael B. Gale --- src/per-language-bundles.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/per-language-bundles.ts b/src/per-language-bundles.ts index 6f80096834..acdff5c740 100644 --- a/src/per-language-bundles.ts +++ b/src/per-language-bundles.ts @@ -102,9 +102,11 @@ export async function getPerLanguageBundleLanguage( return explain("the job is not running on a GitHub-hosted runner"); } - // When selecting the latest nightly, skip the version check, as nightlies have shipped - // per-language bundles since https://github.com/dsp-testing/codeql-cli-nightlies/releases/tag/codeql-bundle-20260909. - // Otherwise, check the requested CLI version to determine whether per-language bundles are published. + // Nightly releases are identified by dates rather than versions. If + // `isLatestNightly` is `true`, the latest nightly is requested with + // `tools: nightly` and we don't yet have the corresponding tag at this point. + // Therefore, we skip the version check and don't have an equivalent. + // We can safely assume that the latest nightly will have per-language bundles. if (!isLatestNightly) { if (cliVersion === undefined) { return explain("the requested CLI version is unknown"); From 3bacfe2c5b69ecc6f63622003e4ef982bbd5da64 Mon Sep 17 00:00:00 2001 From: Henry Mercer Date: Tue, 22 Sep 2026 16:56:15 +0100 Subject: [PATCH 32/47] Remove trailing whitespace from nightly comment Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- src/per-language-bundles.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/per-language-bundles.ts b/src/per-language-bundles.ts index acdff5c740..e4468d2f34 100644 --- a/src/per-language-bundles.ts +++ b/src/per-language-bundles.ts @@ -102,8 +102,8 @@ export async function getPerLanguageBundleLanguage( return explain("the job is not running on a GitHub-hosted runner"); } - // Nightly releases are identified by dates rather than versions. If - // `isLatestNightly` is `true`, the latest nightly is requested with + // Nightly releases are identified by dates rather than versions. If + // `isLatestNightly` is `true`, the latest nightly is requested with // `tools: nightly` and we don't yet have the corresponding tag at this point. // Therefore, we skip the version check and don't have an equivalent. // We can safely assume that the latest nightly will have per-language bundles. From 53162242d5865c69ec07e928d7348f3fa2841c15 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 22 Sep 2026 17:12:09 +0000 Subject: [PATCH 33/47] Update default bundle to codeql-bundle-v2.27.1 --- lib/defaults.json | 8 ++++---- lib/entry-points.js | 4 ++-- src/defaults.json | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/defaults.json b/lib/defaults.json index e4875a8a34..e201dfd79e 100644 --- a/lib/defaults.json +++ b/lib/defaults.json @@ -1,6 +1,6 @@ { - "bundleVersion": "codeql-bundle-v2.27.0", - "cliVersion": "2.27.0", - "priorBundleVersion": "codeql-bundle-v2.26.4", - "priorCliVersion": "2.26.4" + "bundleVersion": "codeql-bundle-v2.27.1", + "cliVersion": "2.27.1", + "priorBundleVersion": "codeql-bundle-v2.27.0", + "priorCliVersion": "2.27.0" } diff --git a/lib/entry-points.js b/lib/entry-points.js index 3fbacc32e4..2340dc38e6 100644 --- a/lib/entry-points.js +++ b/lib/entry-points.js @@ -147732,8 +147732,8 @@ var path6 = __toESM(require("path")); var semver4 = __toESM(require_semver2()); // src/defaults.json -var bundleVersion = "codeql-bundle-v2.27.0"; -var cliVersion = "2.27.0"; +var bundleVersion = "codeql-bundle-v2.27.1"; +var cliVersion = "2.27.1"; // src/overlay/index.ts var fs5 = __toESM(require("fs")); diff --git a/src/defaults.json b/src/defaults.json index e4875a8a34..e201dfd79e 100644 --- a/src/defaults.json +++ b/src/defaults.json @@ -1,6 +1,6 @@ { - "bundleVersion": "codeql-bundle-v2.27.0", - "cliVersion": "2.27.0", - "priorBundleVersion": "codeql-bundle-v2.26.4", - "priorCliVersion": "2.26.4" + "bundleVersion": "codeql-bundle-v2.27.1", + "cliVersion": "2.27.1", + "priorBundleVersion": "codeql-bundle-v2.27.0", + "priorCliVersion": "2.27.0" } From 81fb67799a74354c9fabb1dbc7ee198832c892db Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 22 Sep 2026 17:12:17 +0000 Subject: [PATCH 34/47] Add changelog note --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 267b4e557e..a8880f37aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ See the [releases page](https://github.com/github/codeql-action/releases) for th ## [UNRELEASED] -No user facing changes. +- Update default CodeQL bundle version to [2.27.1](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.27.1). [#4160](https://github.com/github/codeql-action/pull/4160) ## 4.38.1 - 18 Sept 2026 From 9691115b1ca24ee0f0939d6680facb305b90635f Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Wed, 23 Sep 2026 11:09:52 +0100 Subject: [PATCH 35/47] Disable `UsePerfData` for `resolveExtractor` --- lib/entry-points.js | 1 + src/codeql.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/lib/entry-points.js b/lib/entry-points.js index 2340dc38e6..bb408af315 100644 --- a/lib/entry-points.js +++ b/lib/entry-points.js @@ -153247,6 +153247,7 @@ async function getCodeQLForCmd(logger, cmd, checkVersion) { "--format=json", `--language=${language}`, "--extractor-include-aliases", + "-J-XX:-UsePerfData", ...getExtraOptionsFromEnv(["resolve", "extractor"]) ], { diff --git a/src/codeql.ts b/src/codeql.ts index 65e73d9451..fbc119a341 100644 --- a/src/codeql.ts +++ b/src/codeql.ts @@ -937,6 +937,7 @@ async function getCodeQLForCmd( "--format=json", `--language=${language}`, "--extractor-include-aliases", + "-J-XX:-UsePerfData", ...getExtraOptionsFromEnv(["resolve", "extractor"]), ], { From 9c9e4b034d1b1fe599ec257ad3287e537edaead8 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Wed, 23 Sep 2026 13:29:25 +0100 Subject: [PATCH 36/47] Fix `getCommitOid` stubs --- src/git-utils.test.ts | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/git-utils.test.ts b/src/git-utils.test.ts index b77d40a7ec..f6a25778a8 100644 --- a/src/git-utils.test.ts +++ b/src/git-utils.test.ts @@ -29,10 +29,12 @@ test.serial( process.env["GITHUB_SHA"] = currentSha; const callback = sinon.stub(gitUtils, "getCommitOid"); - callback.withArgs("HEAD").resolves(currentSha); + callback.withArgs(sinon.match.string, "HEAD").resolves(currentSha); const actualRef = await gitUtils.getRef(); t.deepEqual(actualRef, expectedRef); + + t.true(callback.calledOnceWith(tmpDir, "HEAD")); }); }, ); @@ -48,11 +50,15 @@ test.serial( const sha = "a".repeat(40); const callback = sinon.stub(gitUtils, "getCommitOid"); - callback.withArgs("refs/remotes/pull/1/merge").resolves(sha); - callback.withArgs("HEAD").resolves(sha); + callback + .withArgs(sinon.match.string, "refs/remotes/pull/1/merge") + .resolves(sha); + callback.withArgs(sinon.match.any, "HEAD").resolves(sha); const actualRef = await gitUtils.getRef(); t.deepEqual(actualRef, expectedRef); + + t.true(callback.calledWith(tmpDir, "refs/remotes/pull/1/merge")); }); }, ); @@ -71,6 +77,9 @@ test.serial( const actualRef = await gitUtils.getRef(); t.deepEqual(actualRef, "refs/pull/1/head"); + + t.true(callback.calledOnceWith(tmpDir, "refs/pull/1/merge")); + t.true(callback.calledOnceWith(tmpDir, "HEAD")); }); }, ); @@ -92,11 +101,14 @@ test.serial( process.env["GITHUB_SHA"] = "a".repeat(40); const callback = sinon.stub(gitUtils, "getCommitOid"); - callback.withArgs("refs/pull/1/merge").resolves("b".repeat(40)); - callback.withArgs("HEAD").resolves("b".repeat(40)); + callback.withArgs(tmpDir, "refs/pull/1/merge").resolves("b".repeat(40)); + callback.withArgs(sinon.match.any, "HEAD").resolves("b".repeat(40)); const actualRef = await gitUtils.getRef(); t.deepEqual(actualRef, "refs/pull/2/merge"); + + t.true(callback.calledOnceWith(tmpDir, "refs/pull/1/merge")); + t.true(callback.calledOnceWith(tmpDir, "HEAD")); }); }, ); From 42277414c74077324e1a1eb1f3cfd58f64fbabc5 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Wed, 23 Sep 2026 13:38:53 +0100 Subject: [PATCH 37/47] Stub `getCommitOid` correctly and check calls --- src/git-utils.test.ts | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/git-utils.test.ts b/src/git-utils.test.ts index f6a25778a8..64b76590ae 100644 --- a/src/git-utils.test.ts +++ b/src/git-utils.test.ts @@ -34,6 +34,7 @@ test.serial( const actualRef = await gitUtils.getRef(); t.deepEqual(actualRef, expectedRef); + t.is(callback.callCount, 1); t.true(callback.calledOnceWith(tmpDir, "HEAD")); }); }, @@ -58,6 +59,8 @@ test.serial( const actualRef = await gitUtils.getRef(); t.deepEqual(actualRef, expectedRef); + t.is(callback.callCount, 2); + t.true(callback.calledWith(tmpDir, "HEAD")); t.true(callback.calledWith(tmpDir, "refs/remotes/pull/1/merge")); }); }, @@ -72,14 +75,18 @@ test.serial( process.env["GITHUB_SHA"] = "a".repeat(40); const callback = sinon.stub(gitUtils, "getCommitOid"); - callback.withArgs(tmpDir, "refs/pull/1/merge").resolves("a".repeat(40)); + callback + .withArgs(tmpDir, "refs/remotes/pull/1/merge") + .resolves("a".repeat(40)); callback.withArgs(tmpDir, "HEAD").resolves("b".repeat(40)); + callback.throws(new Error("Unexpected getCommitOid call in test.")); const actualRef = await gitUtils.getRef(); t.deepEqual(actualRef, "refs/pull/1/head"); - t.true(callback.calledOnceWith(tmpDir, "refs/pull/1/merge")); - t.true(callback.calledOnceWith(tmpDir, "HEAD")); + t.is(callback.callCount, 2); + t.true(callback.calledWith(tmpDir, "refs/remotes/pull/1/merge")); + t.true(callback.calledWith(tmpDir, "HEAD")); }); }, ); @@ -107,8 +114,8 @@ test.serial( const actualRef = await gitUtils.getRef(); t.deepEqual(actualRef, "refs/pull/2/merge"); - t.true(callback.calledOnceWith(tmpDir, "refs/pull/1/merge")); - t.true(callback.calledOnceWith(tmpDir, "HEAD")); + // getCommitOid shouldn't be called, because the ref should be taken from the input + t.is(callback.callCount, 0); }); }, ); From becb485c9fe880e7048de096129c6cd1a0dfb379 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 23 Sep 2026 17:54:02 +0000 Subject: [PATCH 38/47] Bump the npm-minor group across 1 directory with 3 updates Bumps the npm-minor group with 3 updates in the / directory: [js-yaml](https://github.com/nodeca/js-yaml), [eslint-plugin-jsdoc](https://github.com/gajus/eslint-plugin-jsdoc) and [yaml](https://github.com/eemeli/yaml). Updates `js-yaml` from 5.4.1 to 5.4.2 - [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md) - [Commits](https://github.com/nodeca/js-yaml/compare/5.4.1...5.4.2) Updates `eslint-plugin-jsdoc` from 64.3.8 to 64.5.2 - [Release notes](https://github.com/gajus/eslint-plugin-jsdoc/releases) - [Commits](https://github.com/gajus/eslint-plugin-jsdoc/compare/v64.3.8...v64.5.2) Updates `yaml` from 2.9.0 to 2.9.1 - [Release notes](https://github.com/eemeli/yaml/releases) - [Commits](https://github.com/eemeli/yaml/compare/v2.9.0...v2.9.1) --- updated-dependencies: - dependency-name: js-yaml dependency-version: 5.4.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: npm-minor - dependency-name: eslint-plugin-jsdoc dependency-version: 64.5.2 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: npm-minor - dependency-name: yaml dependency-version: 2.9.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: npm-minor ... Signed-off-by: dependabot[bot] --- package-lock.json | 32 +++++++++++++++++++------------- package.json | 4 ++-- pr-checks/package.json | 2 +- 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/package-lock.json b/package-lock.json index d4f189db2a..955fcf6d93 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,7 +31,7 @@ "follow-redirects": "^1.16.0", "get-folder-size": "^5.0.0", "https-proxy-agent": "^7.0.6", - "js-yaml": "^5.4.1", + "js-yaml": "^5.4.2", "jsonschema": "1.5.0", "long": "^5.3.2", "node-forge": "^1.4.0", @@ -58,7 +58,7 @@ "eslint-import-resolver-typescript": "^4.4.5", "eslint-plugin-github": "^6.1.2", "eslint-plugin-import-x": "^4.17.1", - "eslint-plugin-jsdoc": "^64.3.8", + "eslint-plugin-jsdoc": "^64.5.2", "eslint-plugin-no-async-foreach": "^0.1.1", "glob": "^13.0.6", "globals": "^17.12.0", @@ -5348,9 +5348,9 @@ } }, "node_modules/eslint-plugin-jsdoc": { - "version": "64.3.8", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-64.3.8.tgz", - "integrity": "sha512-JXLYE2BVfmbqLrrslb9/vg3URg8okW5pMnppM+3EYwvPCbuOiSXGOJWaNK208wDx6xXawkIFGtRYgFgrW23dsg==", + "version": "64.5.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-64.5.2.tgz", + "integrity": "sha512-GirLf/jpVQ/HSLVT98ztIrJ8GUlWWrrwExkofqzeIjjOxlqFtyqnpkRs30FLwEKh0xHEpgy35CU0qFn0I/Mh9w==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -5374,7 +5374,13 @@ "node": "^22.22.2 || >=24.15.0" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0" + "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0", + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/eslint-plugin-jsdoc/node_modules/debug": { @@ -7091,9 +7097,9 @@ } }, "node_modules/js-yaml": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-5.4.1.tgz", - "integrity": "sha512-28R/k+NAjeuf7+CKlTxWZVExJGwVVLwY06DgEnOMz2gEpfNkDcD7QvyiVPT0xy0XXhU8vHsd4Ot42OOPdJG7dQ==", + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-5.4.2.tgz", + "integrity": "sha512-m+aqu+LwO1O6sIopafj8HUVl5aawITwZQe/yHpMCKjaWBaA/d07B/QdMb3529REftiU+RMMHL3Vlsw3hON7vWg==", "funding": [ { "type": "github", @@ -10367,9 +10373,9 @@ } }, "node_modules/yaml": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", - "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.1.tgz", + "integrity": "sha512-3NxN8+78OdzbT7C/WjGsyfPAtJaN3FNDsWxv7Y7mcDsT/oOmgW8BpyQQFFBnvZE3j9Y2Sdz1ULFLezL7Eb2yFw==", "license": "ISC", "bin": { "yaml": "bin.mjs" @@ -10460,7 +10466,7 @@ "lite-matter": "^0.1.2", "mdast-util-from-markdown": "^2.0.3", "semver": "^7.8.5", - "yaml": "^2.9.0" + "yaml": "^2.9.1" }, "devDependencies": { "@types/node": "^20.19.43", diff --git a/package.json b/package.json index 7f31e80e93..3156038252 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "follow-redirects": "^1.16.0", "get-folder-size": "^5.0.0", "https-proxy-agent": "^7.0.6", - "js-yaml": "^5.4.1", + "js-yaml": "^5.4.2", "jsonschema": "1.5.0", "long": "^5.3.2", "node-forge": "^1.4.0", @@ -66,7 +66,7 @@ "eslint-import-resolver-typescript": "^4.4.5", "eslint-plugin-github": "^6.1.2", "eslint-plugin-import-x": "^4.17.1", - "eslint-plugin-jsdoc": "^64.3.8", + "eslint-plugin-jsdoc": "^64.5.2", "eslint-plugin-no-async-foreach": "^0.1.1", "glob": "^13.0.6", "globals": "^17.12.0", diff --git a/pr-checks/package.json b/pr-checks/package.json index 0c5091a793..58722bd0ea 100644 --- a/pr-checks/package.json +++ b/pr-checks/package.json @@ -10,7 +10,7 @@ "lite-matter": "^0.1.2", "mdast-util-from-markdown": "^2.0.3", "semver": "^7.8.5", - "yaml": "^2.9.0" + "yaml": "^2.9.1" }, "devDependencies": { "@types/node": "^20.19.43", From c87fe5756c0c0bcd5e0005d2169945cfee9a232f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 23 Sep 2026 17:55:50 +0000 Subject: [PATCH 39/47] Rebuild --- lib/entry-points.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/entry-points.js b/lib/entry-points.js index bb408af315..e89c2ab073 100644 --- a/lib/entry-points.js +++ b/lib/entry-points.js @@ -144779,6 +144779,7 @@ function doubleQuoteWhitespaceOnly(layout) { function applyForceQuotesOption(layout) { if (!layout.presenterOptions.forceQuotes) return; if (layout.isKey || layout.style !== SCALAR_STYLE.PLAIN) return; + if (layout.node.tag !== layout.presenterOptions.schema.defaultScalarTag.tagName) return; layout.style = layout.node.value.includes("\n") ? SCALAR_STYLE.DOUBLE_QUOTED : _preferredQuotedStyle(layout); } function tryLongOrMultilineAsBlock(layout) { @@ -164485,7 +164486,7 @@ tmp/lib/tmp.js: *) js-yaml/dist/js-yaml.mjs: - (*! js-yaml 5.4.1 https://github.com/nodeca/js-yaml @license MIT *) + (*! js-yaml 5.4.2 https://github.com/nodeca/js-yaml @license MIT *) long/index.js: (** From b13f5f47d5398d0fb982942ced6fdfc4e3951804 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 23 Sep 2026 17:56:05 +0000 Subject: [PATCH 40/47] Bump ruby/setup-ruby Bumps the actions-minor group with 1 update in the /.github/workflows directory: [ruby/setup-ruby](https://github.com/ruby/setup-ruby). Updates `ruby/setup-ruby` from 1.321.0 to 1.323.0 - [Release notes](https://github.com/ruby/setup-ruby/releases) - [Changelog](https://github.com/ruby/setup-ruby/blob/master/release.rb) - [Commits](https://github.com/ruby/setup-ruby/compare/95ef2b042f9d7a56d8268cba8559e2842e2ad01b...984c0c890880bbf811283d6f09c4607c62d210a4) --- updated-dependencies: - dependency-name: ruby/setup-ruby dependency-version: 1.323.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: actions-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/__rubocop-multi-language.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/__rubocop-multi-language.yml b/.github/workflows/__rubocop-multi-language.yml index c405b44fed..96f2daccab 100644 --- a/.github/workflows/__rubocop-multi-language.yml +++ b/.github/workflows/__rubocop-multi-language.yml @@ -54,7 +54,7 @@ jobs: use-all-platform-bundle: 'false' setup-kotlin: 'true' - name: Set up Ruby - uses: ruby/setup-ruby@95ef2b042f9d7a56d8268cba8559e2842e2ad01b # v1.321.0 + uses: ruby/setup-ruby@984c0c890880bbf811283d6f09c4607c62d210a4 # v1.323.0 with: ruby-version: 2.6 - name: Install Code Scanning integration From 5e4e2550b48d7f3de205c9d752eb5176bf07f6d9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 23 Sep 2026 17:57:57 +0000 Subject: [PATCH 41/47] Rebuild --- pr-checks/checks/rubocop-multi-language.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pr-checks/checks/rubocop-multi-language.yml b/pr-checks/checks/rubocop-multi-language.yml index 37c5d36e90..550bdb6cc3 100644 --- a/pr-checks/checks/rubocop-multi-language.yml +++ b/pr-checks/checks/rubocop-multi-language.yml @@ -5,7 +5,7 @@ versions: - default steps: - name: Set up Ruby - uses: ruby/setup-ruby@95ef2b042f9d7a56d8268cba8559e2842e2ad01b # v1.321.0 + uses: ruby/setup-ruby@984c0c890880bbf811283d6f09c4607c62d210a4 # v1.323.0 with: ruby-version: 2.6 - name: Install Code Scanning integration From 98af865db5041cee73c7185896319367f8c0adf2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 24 Sep 2026 10:01:43 +0000 Subject: [PATCH 42/47] Update changelog for v4.38.2 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a8880f37aa..1561188e76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ See the [releases page](https://github.com/github/codeql-action/releases) for the relevant changes to the CodeQL CLI and language packs. -## [UNRELEASED] +## 4.38.2 - 24 Sept 2026 - Update default CodeQL bundle version to [2.27.1](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.27.1). [#4160](https://github.com/github/codeql-action/pull/4160) From 8ad03a333eb88de8ad6833eda208d0fc51a9c571 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Thu, 24 Sep 2026 11:15:21 +0100 Subject: [PATCH 43/47] Trigger workflows From 37fc051b5df37f68c371ade06c68fabd20b467a4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 24 Sep 2026 10:29:11 +0000 Subject: [PATCH 44/47] Revert "Update version and changelog for v3.38.1" This reverts commit d7512d4cfe067ce977a8e216b85a59151a6ee860. --- CHANGELOG.md | 96 ++++++++++++++++++++++++++-------------------------- package.json | 2 +- 2 files changed, 49 insertions(+), 49 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 59a5385e86..b8a7189e20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,92 +2,92 @@ See the [releases page](https://github.com/github/codeql-action/releases) for the relevant changes to the CodeQL CLI and language packs. -## 3.38.1 - 18 Sept 2026 +## 4.38.1 - 18 Sept 2026 - The CodeQL Action now has experimental support for CodeQL releases for which per-language bundles are available. Per-language bundles support analysis for a single language and are therefore smaller than the combined bundles that allow analysis for all supported languages. As a result, per-language bundles take up less space on disk and are faster to download. We expect to roll this change out to everyone in the coming weeks. [#4146](https://github.com/github/codeql-action/pull/4146) -## 3.38.0 - 09 Sept 2026 +## 4.38.0 - 09 Sept 2026 - On GitHub-hosted runners, the CodeQL Action now deletes unused CodeQL bundles from the toolcache before downloading a different bundle, which frees up disk space for the analysis. We expect to roll this change out to everyone in September. [#4124](https://github.com/github/codeql-action/pull/4124) - The CodeQL Action now supports CodeQL releases that are compatible with Linux Arm64 and downloads the native `linux-arm64` CodeQL bundle when available. [#4072](https://github.com/github/codeql-action/pull/4072) - Update default CodeQL bundle version to [2.27.0](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.27.0). [#4129](https://github.com/github/codeql-action/pull/4129) -## 3.37.9 - 26 Aug 2026 +## 4.37.9 - 26 Aug 2026 - Update default CodeQL bundle version to [2.26.4](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.4). [#4106](https://github.com/github/codeql-action/pull/4106) -## 3.37.8 - 21 Aug 2026 +## 4.37.8 - 21 Aug 2026 No user facing changes. -## 3.37.7 - 13 Aug 2026 +## 4.37.7 - 13 Aug 2026 - Update default CodeQL bundle version to [2.26.3](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.3). [#4085](https://github.com/github/codeql-action/pull/4085) -## 3.37.6 - 04 Aug 2026 +## 4.37.6 - 04 Aug 2026 - Changed the default filepath for the new remote file address format that was introduced in CodeQL Action 4.37.0 / 3.37.0 to `.github/codeql-config.yml` to align it with the suggested path that is used elsewhere. [#4070](https://github.com/github/codeql-action/pull/4070) -## 3.37.5 - 03 Aug 2026 +## 4.37.5 - 03 Aug 2026 - Fixed a bug where a network error while streaming the download of the CodeQL bundle could terminate the `init` Action instead of falling back to downloading the bundle before extracting it. [#4061](https://github.com/github/codeql-action/pull/4061) -## 3.37.4 - 29 Jul 2026 +## 4.37.4 - 29 Jul 2026 - This version of the CodeQL Action adds support for the `tools` input for the `codeql-action/init` step to be specified using a `github-codeql-tools` [repository property](https://docs.github.com/en/organizations/managing-organization-settings/managing-custom-properties-for-repositories-in-your-organization). This feature will gradually be rolled out following the release of this version. Once rolled out, this allows for the CodeQL CLI version that is used in GitHub-managed workflows, such as Default Setup, to be set to a custom value. For example, customers who run into issues with rate limits when a new CodeQL CLI version is released can set the value to `toolcache` to always use the CodeQL CLI version that is available in the runner toolcache. For Advanced Setup workflows, the value provided for `tools` in the workflow definition always takes precedence unless the value of the repository property starts with `!`. [#4037](https://github.com/github/codeql-action/pull/4037) - Update default CodeQL bundle version to [2.26.2](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.2). [#4051](https://github.com/github/codeql-action/pull/4051) -## 3.37.3 - 22 Jul 2026 +## 4.37.3 - 22 Jul 2026 No user facing changes. -## 3.37.2 - 21 Jul 2026 +## 4.37.2 - 21 Jul 2026 - The new address format for the `config-file` input that was introduced in CodeQL Action 4.37.0 is now enabled by default. In addition to the format described there, the `remote=` prefix can now be used to explicitly indicate that the input refers to a remote file. All previous input formats continue to be accepted as well. [#4023](https://github.com/github/codeql-action/pull/4023) - The CodeQL Action can now make use of [configured private registries](https://docs.github.com/en/code-security/how-tos/secure-at-scale/configure-organization-security/manage-usage-and-access/giving-org-access-private-registries) in Default Setup to retrieve CodeQL configuration files from remote repositories that require authentication. This will allow customers to store their CodeQL configuration in a single repository that can then be referenced by Default Setup workflows in other repositories. We expect to roll this and other, related changes out to everyone in July. [#4007](https://github.com/github/codeql-action/pull/4007) -## 3.37.1 - 16 Jul 2026 +## 4.37.1 - 16 Jul 2026 - _Upcoming breaking change_: Add a deprecation warning for customers using CodeQL version 2.20.6 and earlier. These versions of CodeQL were discontinued on 1 July 2026 alongside GitHub Enterprise Server 3.16, and will be unsupported by the next minor release of the CodeQL Action. [#3956](https://github.com/github/codeql-action/pull/3956) - Update default CodeQL bundle version to [2.26.1](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.1). [#4019](https://github.com/github/codeql-action/pull/4019) -## 3.37.0 - 08 Jul 2026 +## 4.37.0 - 08 Jul 2026 - Update default CodeQL bundle version to [2.26.0](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.0). [#3995](https://github.com/github/codeql-action/pull/3995) - In addition to the existing input format, the `config-file` input for the `codeql-action/init` step will soon support a new `[owner/]repo[@ref][:path]` format. All components except the repository name are optional. If omitted, `owner` defaults to the same owner as the repository the analysis is running for, `ref` to `main`, and `path` to `.github/codeql-action.yaml`. Support for this format ships in this version of the CodeQL Action, but will only be enabled over the coming weeks. [#3973](https://github.com/github/codeql-action/pull/3973) -## 3.36.3 - 01 Jul 2026 +## 4.36.3 - 01 Jul 2026 No user facing changes. -## 3.36.2 - 04 Jun 2026 +## 4.36.2 - 04 Jun 2026 - Cache CodeQL CLI version information across Actions steps. [#3943](https://github.com/github/codeql-action/pull/3943) - Reduce requests while waiting for analysis processing by using exponential backoff when polling SARIF processing status. [#3937](https://github.com/github/codeql-action/pull/3937) - Update default CodeQL bundle version to [2.25.6](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.6). [#3948](https://github.com/github/codeql-action/pull/3948) -## 3.36.1 - 02 Jun 2026 +## 4.36.1 - 02 Jun 2026 No user facing changes. -## 3.36.0 - 22 May 2026 +## 4.36.0 - 22 May 2026 - _Breaking change_: Bump the minimum required CodeQL bundle version to 2.19.4. [#3894](https://github.com/github/codeql-action/pull/3894) - Add support for SHA-256 Git object IDs. [#3893](https://github.com/github/codeql-action/pull/3893) - Update default CodeQL bundle version to [2.25.5](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.5). [#3926](https://github.com/github/codeql-action/pull/3926) -## 3.35.5 - 15 May 2026 +## 4.35.5 - 15 May 2026 - We have improved how the JavaScript bundles for the CodeQL Action are generated to avoid duplication across bundles and reduce the size of the repository by around 70%. This should have no effect on the runtime behaviour of the CodeQL Action. [#3899](https://github.com/github/codeql-action/pull/3899) - For performance and accuracy reasons, [improved incremental analysis](https://github.com/github/roadmap/issues/1158) will now only be enabled on a pull request when diff-informed analysis is also enabled for that run. If diff-informed analysis is unavailable (for example, because the PR diff ranges could not be computed), the action will fall back to a full analysis. [#3791](https://github.com/github/codeql-action/pull/3791) - If multiple inputs are provided for the GitHub-internal `analysis-kinds` input, only `code-scanning` will be enabled. The `analysis-kinds` input is experimental, for GitHub-internal use only, and may change without notice at any time. [#3892](https://github.com/github/codeql-action/pull/3892) - Added an experimental change which, when running a Code Scanning analysis for a PR with [improved incremental analysis](https://github.com/github/roadmap/issues/1158) enabled, prefers CodeQL CLI versions that have a cached overlay-base database for the configured languages. This speeds up analysis for a repository when there is not yet a cached overlay-base database for the latest CLI version. We expect to roll this change out to everyone in May. [#3880](https://github.com/github/codeql-action/pull/3880) -## 3.35.4 - 07 May 2026 +## 4.35.4 - 07 May 2026 - Update default CodeQL bundle version to [2.25.4](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.4). [#3881](https://github.com/github/codeql-action/pull/3881) -## 3.35.3 - 01 May 2026 +## 4.35.3 - 01 May 2026 - _Upcoming breaking change_: Add a deprecation warning for customers using CodeQL version 2.19.3 and earlier. These versions of CodeQL were discontinued on 9 April 2026 alongside GitHub Enterprise Server 3.15, and will be unsupported by the next minor release of the CodeQL Action. [#3837](https://github.com/github/codeql-action/pull/3837) - Configurations for private registries that use Cloudsmith or GCP OIDC are now accepted. [#3850](https://github.com/github/codeql-action/pull/3850) @@ -95,7 +95,7 @@ No user facing changes. - Fixed a bug where two diagnostics produced within the same millisecond could overwrite each other on disk, causing one of them to be lost. [#3852](https://github.com/github/codeql-action/pull/3852) - Update default CodeQL bundle version to [2.25.3](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.3). [#3865](https://github.com/github/codeql-action/pull/3865) -## 3.35.2 - 15 Apr 2026 +## 4.35.2 - 15 Apr 2026 - The undocumented TRAP cache cleanup feature that could be enabled using the `CODEQL_ACTION_CLEANUP_TRAP_CACHES` environment variable is deprecated and will be removed in May 2026. If you are affected by this, we recommend disabling TRAP caching by passing the `trap-caching: false` input to the `init` Action. [#3795](https://github.com/github/codeql-action/pull/3795) - The Git version 2.36.0 requirement for improved incremental analysis now only applies to repositories that contain submodules. [#3789](https://github.com/github/codeql-action/pull/3789) @@ -103,26 +103,26 @@ No user facing changes. - Fixed a bug in the validation of OIDC configurations for private registries that was added in CodeQL Action 4.33.0 / 3.33.0. [#3807](https://github.com/github/codeql-action/pull/3807) - Update default CodeQL bundle version to [2.25.2](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.2). [#3823](https://github.com/github/codeql-action/pull/3823) -## 3.35.1 - 27 Mar 2026 +## 4.35.1 - 27 Mar 2026 - Fix incorrect minimum required Git version for [improved incremental analysis](https://github.com/github/roadmap/issues/1158): it should have been 2.36.0, not 2.11.0. [#3781](https://github.com/github/codeql-action/pull/3781) -## 3.35.0 - 27 Mar 2026 +## 4.35.0 - 27 Mar 2026 - Reduced the minimum Git version required for [improved incremental analysis](https://github.com/github/roadmap/issues/1158) from 2.38.0 to 2.11.0. [#3767](https://github.com/github/codeql-action/pull/3767) - Update default CodeQL bundle version to [2.25.1](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.1). [#3773](https://github.com/github/codeql-action/pull/3773) -## 3.34.1 - 20 Mar 2026 +## 4.34.1 - 20 Mar 2026 - Downgrade default CodeQL bundle version to [2.24.3](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.24.3) due to issues with a small percentage of Actions and JavaScript analyses. [#3762](https://github.com/github/codeql-action/pull/3762) -## 3.34.0 - 20 Mar 2026 +## 4.34.0 - 20 Mar 2026 - Added an experimental change which disables TRAP caching when [improved incremental analysis](https://github.com/github/roadmap/issues/1158) is enabled, since improved incremental analysis supersedes TRAP caching. This will improve performance and reduce Actions cache usage. We expect to roll this change out to everyone in March. [#3569](https://github.com/github/codeql-action/pull/3569) - We are rolling out improved incremental analysis to C/C++ analyses that use build mode `none`. We expect this rollout to be complete by the end of April 2026. [#3584](https://github.com/github/codeql-action/pull/3584) - Update default CodeQL bundle version to [2.25.0](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.0). [#3585](https://github.com/github/codeql-action/pull/3585) -## 3.33.0 - 16 Mar 2026 +## 4.33.0 - 16 Mar 2026 - Upcoming change: Starting April 2026, the CodeQL Action will skip collecting file coverage information on pull requests to improve analysis performance. File coverage information will still be computed on non-PR analyses. Pull request analyses will log a warning about this upcoming change. [#3562](https://github.com/github/codeql-action/pull/3562) @@ -136,11 +136,11 @@ No user facing changes. - Fixed the retry mechanism for database uploads. Previously this would fail with the error "Response body object should not be disturbed or locked". [#3564](https://github.com/github/codeql-action/pull/3564) - A warning is now emitted if the CodeQL Action detects a repository property whose name suggests that it relates to the CodeQL Action, but which is not one of the properties recognised by the current version of the CodeQL Action. [#3570](https://github.com/github/codeql-action/pull/3570) -## 3.32.6 - 05 Mar 2026 +## 4.32.6 - 05 Mar 2026 - Update default CodeQL bundle version to [2.24.3](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.24.3). [#3548](https://github.com/github/codeql-action/pull/3548) -## 3.32.5 - 02 Mar 2026 +## 4.32.5 - 02 Mar 2026 - Repositories owned by an organization can now set up the `github-codeql-disable-overlay` custom repository property to disable [improved incremental analysis for CodeQL](https://github.com/github/roadmap/issues/1158). First, create a custom repository property with the name `github-codeql-disable-overlay` and the type "True/false" in the organization's settings. Then in the repository's settings, set this property to `true` to disable improved incremental analysis. For more information, see [Managing custom properties for repositories in your organization](https://docs.github.com/en/organizations/managing-organization-settings/managing-custom-properties-for-repositories-in-your-organization). This feature is not yet available on GitHub Enterprise Server. [#3507](https://github.com/github/codeql-action/pull/3507) - Added an experimental change so that when [improved incremental analysis](https://github.com/github/roadmap/issues/1158) fails on a runner — potentially due to insufficient disk space — the failure is recorded in the Actions cache so that subsequent runs will automatically skip improved incremental analysis until something changes (e.g. a larger runner is provisioned or a new CodeQL version is released). We expect to roll this change out to everyone in March. [#3487](https://github.com/github/codeql-action/pull/3487) @@ -150,7 +150,7 @@ No user facing changes. - Added an experimental change which allows the `start-proxy` action to resolve the CodeQL CLI version from feature flags instead of using the linked CLI bundle version. We expect to roll this change out to everyone in March. [#3512](https://github.com/github/codeql-action/pull/3512) - The previously experimental changes from versions 4.32.3, 4.32.4, 3.32.3 and 3.32.4 are now enabled by default. [#3503](https://github.com/github/codeql-action/pull/3503), [#3504](https://github.com/github/codeql-action/pull/3504) -## 3.32.4 - 20 Feb 2026 +## 4.32.4 - 20 Feb 2026 - Update default CodeQL bundle version to [2.24.2](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.24.2). [#3493](https://github.com/github/codeql-action/pull/3493) - Added an experimental change which improves how certificates are generated for the authentication proxy that is used by the CodeQL Action in Default Setup when [private package registries are configured](https://docs.github.com/en/code-security/how-tos/secure-at-scale/configure-organization-security/manage-usage-and-access/giving-org-access-private-registries). This is expected to generate more widely compatible certificates and should have no impact on analyses which are working correctly already. We expect to roll this change out to everyone in February. [#3473](https://github.com/github/codeql-action/pull/3473) @@ -158,89 +158,89 @@ No user facing changes. - Added a setting which allows the CodeQL Action to enable network debugging for Java programs. This will help GitHub staff support customers with troubleshooting issues in GitHub-managed CodeQL workflows, such as Default Setup. This setting can only be enabled by GitHub staff. [#3485](https://github.com/github/codeql-action/pull/3485) - Added a setting which enables GitHub-managed workflows, such as Default Setup, to use a [nightly CodeQL CLI release](https://github.com/dsp-testing/codeql-cli-nightlies) instead of the latest, stable release that is used by default. This will help GitHub staff support customers whose analyses for a given repository or organization require early access to a change in an upcoming CodeQL CLI release. This setting can only be enabled by GitHub staff. [#3484](https://github.com/github/codeql-action/pull/3484) -## 3.32.3 - 13 Feb 2026 +## 4.32.3 - 13 Feb 2026 - Added experimental support for testing connections to [private package registries](https://docs.github.com/en/code-security/how-tos/secure-at-scale/configure-organization-security/manage-usage-and-access/giving-org-access-private-registries). This feature is not currently enabled for any analysis. In the future, it may be enabled by default for Default Setup. [#3466](https://github.com/github/codeql-action/pull/3466) -## 3.32.2 - 05 Feb 2026 +## 4.32.2 - 05 Feb 2026 - Update default CodeQL bundle version to [2.24.1](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.24.1). [#3460](https://github.com/github/codeql-action/pull/3460) -## 3.32.1 - 02 Feb 2026 +## 4.32.1 - 02 Feb 2026 - A warning is now shown in Default Setup workflow logs if a [private package registry is configured](https://docs.github.com/en/code-security/how-tos/secure-at-scale/configure-organization-security/manage-usage-and-access/giving-org-access-private-registries) using a GitHub Personal Access Token (PAT), but no username is configured. [#3422](https://github.com/github/codeql-action/pull/3422) - Fixed a bug which caused the CodeQL Action to fail when repository properties cannot successfully be retrieved. [#3421](https://github.com/github/codeql-action/pull/3421) -## 3.32.0 - 26 Jan 2026 +## 4.32.0 - 26 Jan 2026 - Update default CodeQL bundle version to [2.24.0](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.24.0). [#3425](https://github.com/github/codeql-action/pull/3425) -## 3.31.11 - 23 Jan 2026 +## 4.31.11 - 23 Jan 2026 - When running a Default Setup workflow with [Actions debugging enabled](https://docs.github.com/en/actions/how-tos/monitor-workflows/enable-debug-logging), the CodeQL Action will now use more unique names when uploading logs from the Dependabot authentication proxy as workflow artifacts. This ensures that the artifact names do not clash between multiple jobs in a build matrix. [#3409](https://github.com/github/codeql-action/pull/3409) - Improved error handling throughout the CodeQL Action. [#3415](https://github.com/github/codeql-action/pull/3415) - Added experimental support for automatically excluding [generated files](https://docs.github.com/en/repositories/working-with-files/managing-files/customizing-how-changed-files-appear-on-github) from the analysis. This feature is not currently enabled for any analysis. In the future, it may be enabled by default for some GitHub-managed analyses. [#3318](https://github.com/github/codeql-action/pull/3318) - The changelog extracts that are included with releases of the CodeQL Action are now shorter to avoid duplicated information from appearing in Dependabot PRs. [#3403](https://github.com/github/codeql-action/pull/3403) -## 3.31.10 - 12 Jan 2026 +## 4.31.10 - 12 Jan 2026 - Update default CodeQL bundle version to 2.23.9. [#3393](https://github.com/github/codeql-action/pull/3393) -## 3.31.9 - 16 Dec 2025 +## 4.31.9 - 16 Dec 2025 No user facing changes. -## 3.31.8 - 11 Dec 2025 +## 4.31.8 - 11 Dec 2025 - Update default CodeQL bundle version to 2.23.8. [#3354](https://github.com/github/codeql-action/pull/3354) -## 3.31.7 - 05 Dec 2025 +## 4.31.7 - 05 Dec 2025 - Update default CodeQL bundle version to 2.23.7. [#3343](https://github.com/github/codeql-action/pull/3343) -## 3.31.6 - 01 Dec 2025 +## 4.31.6 - 01 Dec 2025 No user facing changes. -## 3.31.5 - 24 Nov 2025 +## 4.31.5 - 24 Nov 2025 - Update default CodeQL bundle version to 2.23.6. [#3321](https://github.com/github/codeql-action/pull/3321) -## 3.31.4 - 18 Nov 2025 +## 4.31.4 - 18 Nov 2025 No user facing changes. -## 3.31.3 - 13 Nov 2025 +## 4.31.3 - 13 Nov 2025 - CodeQL Action v3 will be deprecated in December 2026. The Action now logs a warning for customers who are running v3 but could be running v4. For more information, see [Upcoming deprecation of CodeQL Action v3](https://github.blog/changelog/2025-10-28-upcoming-deprecation-of-codeql-action-v3/). - Update default CodeQL bundle version to 2.23.5. [#3288](https://github.com/github/codeql-action/pull/3288) -## 3.31.2 - 30 Oct 2025 +## 4.31.2 - 30 Oct 2025 No user facing changes. -## 3.31.1 - 30 Oct 2025 +## 4.31.1 - 30 Oct 2025 - The `add-snippets` input has been removed from the `analyze` action. This input has been deprecated since CodeQL Action 3.26.4 in August 2024 when this removal was announced. -## 3.31.0 - 24 Oct 2025 +## 4.31.0 - 24 Oct 2025 - Bump minimum CodeQL bundle version to 2.17.6. [#3223](https://github.com/github/codeql-action/pull/3223) - When SARIF files are uploaded by the `analyze` or `upload-sarif` actions, the CodeQL Action automatically performs post-processing steps to prepare the data for the upload. Previously, these post-processing steps were only performed before an upload took place. We are now changing this so that the post-processing steps will always be performed, even when the SARIF files are not uploaded. This does not change anything for the `upload-sarif` action. For `analyze`, this may affect Advanced Setup for CodeQL users who specify a value other than `always` for the `upload` input. [#3222](https://github.com/github/codeql-action/pull/3222) -## 3.30.9 - 17 Oct 2025 +## 4.30.9 - 17 Oct 2025 - Update default CodeQL bundle version to 2.23.3. [#3205](https://github.com/github/codeql-action/pull/3205) - Experimental: A new `setup-codeql` action has been added which is similar to `init`, except it only installs the CodeQL CLI and does not initialize a database. Do not use this in production as it is part of an internal experiment and subject to change at any time. [#3204](https://github.com/github/codeql-action/pull/3204) -## 3.30.8 - 10 Oct 2025 +## 4.30.8 - 10 Oct 2025 No user facing changes. -## 3.30.7 - 06 Oct 2025 +## 4.30.7 - 06 Oct 2025 +- [v4+ only] The CodeQL Action now runs on Node.js v24. [#3169](https://github.com/github/codeql-action/pull/3169) -No user facing changes. ## 3.30.6 - 02 Oct 2025 - Update default CodeQL bundle version to 2.23.2. [#3168](https://github.com/github/codeql-action/pull/3168) diff --git a/package.json b/package.json index 5596407dbd..c7ad53e2e0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codeql", - "version": "3.38.1", + "version": "4.38.1", "private": true, "description": "CodeQL action", "scripts": { From 259e857114270a23a6f641ead06b7d575701e031 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 24 Sep 2026 10:29:11 +0000 Subject: [PATCH 45/47] Revert "Rebuild" This reverts commit 39e5c2d42c3a8c0ac8d15a6f2841a7f901ca3097. --- lib/entry-points.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/entry-points.js b/lib/entry-points.js index c83cbc5216..f8a7d6e76a 100644 --- a/lib/entry-points.js +++ b/lib/entry-points.js @@ -146167,7 +146167,7 @@ function getDiffRangesJsonFilePath(env = getEnv()) { return path2.join(getTemporaryDirectory(env), PR_DIFF_RANGE_JSON_FILENAME); } function getActionVersion() { - return "3.38.1"; + return "4.38.1"; } function getWorkflowEventName(env = getEnv()) { return env.getRequired("GITHUB_EVENT_NAME" /* GITHUB_EVENT_NAME */); From aa62ed54edd57c489ac83b9fc554f0ee5084a619 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 24 Sep 2026 10:29:11 +0000 Subject: [PATCH 46/47] Update version and changelog for v3.38.2 --- CHANGELOG.md | 98 ++++++++++++++++++++++++++-------------------------- package.json | 2 +- 2 files changed, 50 insertions(+), 50 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1561188e76..34dff4a645 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,96 +2,96 @@ See the [releases page](https://github.com/github/codeql-action/releases) for the relevant changes to the CodeQL CLI and language packs. -## 4.38.2 - 24 Sept 2026 +## 3.38.2 - 24 Sept 2026 - Update default CodeQL bundle version to [2.27.1](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.27.1). [#4160](https://github.com/github/codeql-action/pull/4160) -## 4.38.1 - 18 Sept 2026 +## 3.38.1 - 18 Sept 2026 - The CodeQL Action now has experimental support for CodeQL releases for which per-language bundles are available. Per-language bundles support analysis for a single language and are therefore smaller than the combined bundles that allow analysis for all supported languages. As a result, per-language bundles take up less space on disk and are faster to download. We expect to roll this change out to everyone in the coming weeks. [#4146](https://github.com/github/codeql-action/pull/4146) -## 4.38.0 - 09 Sept 2026 +## 3.38.0 - 09 Sept 2026 - On GitHub-hosted runners, the CodeQL Action now deletes unused CodeQL bundles from the toolcache before downloading a different bundle, which frees up disk space for the analysis. We expect to roll this change out to everyone in September. [#4124](https://github.com/github/codeql-action/pull/4124) - The CodeQL Action now supports CodeQL releases that are compatible with Linux Arm64 and downloads the native `linux-arm64` CodeQL bundle when available. [#4072](https://github.com/github/codeql-action/pull/4072) - Update default CodeQL bundle version to [2.27.0](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.27.0). [#4129](https://github.com/github/codeql-action/pull/4129) -## 4.37.9 - 26 Aug 2026 +## 3.37.9 - 26 Aug 2026 - Update default CodeQL bundle version to [2.26.4](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.4). [#4106](https://github.com/github/codeql-action/pull/4106) -## 4.37.8 - 21 Aug 2026 +## 3.37.8 - 21 Aug 2026 No user facing changes. -## 4.37.7 - 13 Aug 2026 +## 3.37.7 - 13 Aug 2026 - Update default CodeQL bundle version to [2.26.3](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.3). [#4085](https://github.com/github/codeql-action/pull/4085) -## 4.37.6 - 04 Aug 2026 +## 3.37.6 - 04 Aug 2026 - Changed the default filepath for the new remote file address format that was introduced in CodeQL Action 4.37.0 / 3.37.0 to `.github/codeql-config.yml` to align it with the suggested path that is used elsewhere. [#4070](https://github.com/github/codeql-action/pull/4070) -## 4.37.5 - 03 Aug 2026 +## 3.37.5 - 03 Aug 2026 - Fixed a bug where a network error while streaming the download of the CodeQL bundle could terminate the `init` Action instead of falling back to downloading the bundle before extracting it. [#4061](https://github.com/github/codeql-action/pull/4061) -## 4.37.4 - 29 Jul 2026 +## 3.37.4 - 29 Jul 2026 - This version of the CodeQL Action adds support for the `tools` input for the `codeql-action/init` step to be specified using a `github-codeql-tools` [repository property](https://docs.github.com/en/organizations/managing-organization-settings/managing-custom-properties-for-repositories-in-your-organization). This feature will gradually be rolled out following the release of this version. Once rolled out, this allows for the CodeQL CLI version that is used in GitHub-managed workflows, such as Default Setup, to be set to a custom value. For example, customers who run into issues with rate limits when a new CodeQL CLI version is released can set the value to `toolcache` to always use the CodeQL CLI version that is available in the runner toolcache. For Advanced Setup workflows, the value provided for `tools` in the workflow definition always takes precedence unless the value of the repository property starts with `!`. [#4037](https://github.com/github/codeql-action/pull/4037) - Update default CodeQL bundle version to [2.26.2](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.2). [#4051](https://github.com/github/codeql-action/pull/4051) -## 4.37.3 - 22 Jul 2026 +## 3.37.3 - 22 Jul 2026 No user facing changes. -## 4.37.2 - 21 Jul 2026 +## 3.37.2 - 21 Jul 2026 - The new address format for the `config-file` input that was introduced in CodeQL Action 4.37.0 is now enabled by default. In addition to the format described there, the `remote=` prefix can now be used to explicitly indicate that the input refers to a remote file. All previous input formats continue to be accepted as well. [#4023](https://github.com/github/codeql-action/pull/4023) - The CodeQL Action can now make use of [configured private registries](https://docs.github.com/en/code-security/how-tos/secure-at-scale/configure-organization-security/manage-usage-and-access/giving-org-access-private-registries) in Default Setup to retrieve CodeQL configuration files from remote repositories that require authentication. This will allow customers to store their CodeQL configuration in a single repository that can then be referenced by Default Setup workflows in other repositories. We expect to roll this and other, related changes out to everyone in July. [#4007](https://github.com/github/codeql-action/pull/4007) -## 4.37.1 - 16 Jul 2026 +## 3.37.1 - 16 Jul 2026 - _Upcoming breaking change_: Add a deprecation warning for customers using CodeQL version 2.20.6 and earlier. These versions of CodeQL were discontinued on 1 July 2026 alongside GitHub Enterprise Server 3.16, and will be unsupported by the next minor release of the CodeQL Action. [#3956](https://github.com/github/codeql-action/pull/3956) - Update default CodeQL bundle version to [2.26.1](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.1). [#4019](https://github.com/github/codeql-action/pull/4019) -## 4.37.0 - 08 Jul 2026 +## 3.37.0 - 08 Jul 2026 - Update default CodeQL bundle version to [2.26.0](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.0). [#3995](https://github.com/github/codeql-action/pull/3995) - In addition to the existing input format, the `config-file` input for the `codeql-action/init` step will soon support a new `[owner/]repo[@ref][:path]` format. All components except the repository name are optional. If omitted, `owner` defaults to the same owner as the repository the analysis is running for, `ref` to `main`, and `path` to `.github/codeql-action.yaml`. Support for this format ships in this version of the CodeQL Action, but will only be enabled over the coming weeks. [#3973](https://github.com/github/codeql-action/pull/3973) -## 4.36.3 - 01 Jul 2026 +## 3.36.3 - 01 Jul 2026 No user facing changes. -## 4.36.2 - 04 Jun 2026 +## 3.36.2 - 04 Jun 2026 - Cache CodeQL CLI version information across Actions steps. [#3943](https://github.com/github/codeql-action/pull/3943) - Reduce requests while waiting for analysis processing by using exponential backoff when polling SARIF processing status. [#3937](https://github.com/github/codeql-action/pull/3937) - Update default CodeQL bundle version to [2.25.6](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.6). [#3948](https://github.com/github/codeql-action/pull/3948) -## 4.36.1 - 02 Jun 2026 +## 3.36.1 - 02 Jun 2026 No user facing changes. -## 4.36.0 - 22 May 2026 +## 3.36.0 - 22 May 2026 - _Breaking change_: Bump the minimum required CodeQL bundle version to 2.19.4. [#3894](https://github.com/github/codeql-action/pull/3894) - Add support for SHA-256 Git object IDs. [#3893](https://github.com/github/codeql-action/pull/3893) - Update default CodeQL bundle version to [2.25.5](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.5). [#3926](https://github.com/github/codeql-action/pull/3926) -## 4.35.5 - 15 May 2026 +## 3.35.5 - 15 May 2026 - We have improved how the JavaScript bundles for the CodeQL Action are generated to avoid duplication across bundles and reduce the size of the repository by around 70%. This should have no effect on the runtime behaviour of the CodeQL Action. [#3899](https://github.com/github/codeql-action/pull/3899) - For performance and accuracy reasons, [improved incremental analysis](https://github.com/github/roadmap/issues/1158) will now only be enabled on a pull request when diff-informed analysis is also enabled for that run. If diff-informed analysis is unavailable (for example, because the PR diff ranges could not be computed), the action will fall back to a full analysis. [#3791](https://github.com/github/codeql-action/pull/3791) - If multiple inputs are provided for the GitHub-internal `analysis-kinds` input, only `code-scanning` will be enabled. The `analysis-kinds` input is experimental, for GitHub-internal use only, and may change without notice at any time. [#3892](https://github.com/github/codeql-action/pull/3892) - Added an experimental change which, when running a Code Scanning analysis for a PR with [improved incremental analysis](https://github.com/github/roadmap/issues/1158) enabled, prefers CodeQL CLI versions that have a cached overlay-base database for the configured languages. This speeds up analysis for a repository when there is not yet a cached overlay-base database for the latest CLI version. We expect to roll this change out to everyone in May. [#3880](https://github.com/github/codeql-action/pull/3880) -## 4.35.4 - 07 May 2026 +## 3.35.4 - 07 May 2026 - Update default CodeQL bundle version to [2.25.4](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.4). [#3881](https://github.com/github/codeql-action/pull/3881) -## 4.35.3 - 01 May 2026 +## 3.35.3 - 01 May 2026 - _Upcoming breaking change_: Add a deprecation warning for customers using CodeQL version 2.19.3 and earlier. These versions of CodeQL were discontinued on 9 April 2026 alongside GitHub Enterprise Server 3.15, and will be unsupported by the next minor release of the CodeQL Action. [#3837](https://github.com/github/codeql-action/pull/3837) - Configurations for private registries that use Cloudsmith or GCP OIDC are now accepted. [#3850](https://github.com/github/codeql-action/pull/3850) @@ -99,7 +99,7 @@ No user facing changes. - Fixed a bug where two diagnostics produced within the same millisecond could overwrite each other on disk, causing one of them to be lost. [#3852](https://github.com/github/codeql-action/pull/3852) - Update default CodeQL bundle version to [2.25.3](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.3). [#3865](https://github.com/github/codeql-action/pull/3865) -## 4.35.2 - 15 Apr 2026 +## 3.35.2 - 15 Apr 2026 - The undocumented TRAP cache cleanup feature that could be enabled using the `CODEQL_ACTION_CLEANUP_TRAP_CACHES` environment variable is deprecated and will be removed in May 2026. If you are affected by this, we recommend disabling TRAP caching by passing the `trap-caching: false` input to the `init` Action. [#3795](https://github.com/github/codeql-action/pull/3795) - The Git version 2.36.0 requirement for improved incremental analysis now only applies to repositories that contain submodules. [#3789](https://github.com/github/codeql-action/pull/3789) @@ -107,26 +107,26 @@ No user facing changes. - Fixed a bug in the validation of OIDC configurations for private registries that was added in CodeQL Action 4.33.0 / 3.33.0. [#3807](https://github.com/github/codeql-action/pull/3807) - Update default CodeQL bundle version to [2.25.2](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.2). [#3823](https://github.com/github/codeql-action/pull/3823) -## 4.35.1 - 27 Mar 2026 +## 3.35.1 - 27 Mar 2026 - Fix incorrect minimum required Git version for [improved incremental analysis](https://github.com/github/roadmap/issues/1158): it should have been 2.36.0, not 2.11.0. [#3781](https://github.com/github/codeql-action/pull/3781) -## 4.35.0 - 27 Mar 2026 +## 3.35.0 - 27 Mar 2026 - Reduced the minimum Git version required for [improved incremental analysis](https://github.com/github/roadmap/issues/1158) from 2.38.0 to 2.11.0. [#3767](https://github.com/github/codeql-action/pull/3767) - Update default CodeQL bundle version to [2.25.1](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.1). [#3773](https://github.com/github/codeql-action/pull/3773) -## 4.34.1 - 20 Mar 2026 +## 3.34.1 - 20 Mar 2026 - Downgrade default CodeQL bundle version to [2.24.3](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.24.3) due to issues with a small percentage of Actions and JavaScript analyses. [#3762](https://github.com/github/codeql-action/pull/3762) -## 4.34.0 - 20 Mar 2026 +## 3.34.0 - 20 Mar 2026 - Added an experimental change which disables TRAP caching when [improved incremental analysis](https://github.com/github/roadmap/issues/1158) is enabled, since improved incremental analysis supersedes TRAP caching. This will improve performance and reduce Actions cache usage. We expect to roll this change out to everyone in March. [#3569](https://github.com/github/codeql-action/pull/3569) - We are rolling out improved incremental analysis to C/C++ analyses that use build mode `none`. We expect this rollout to be complete by the end of April 2026. [#3584](https://github.com/github/codeql-action/pull/3584) - Update default CodeQL bundle version to [2.25.0](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.0). [#3585](https://github.com/github/codeql-action/pull/3585) -## 4.33.0 - 16 Mar 2026 +## 3.33.0 - 16 Mar 2026 - Upcoming change: Starting April 2026, the CodeQL Action will skip collecting file coverage information on pull requests to improve analysis performance. File coverage information will still be computed on non-PR analyses. Pull request analyses will log a warning about this upcoming change. [#3562](https://github.com/github/codeql-action/pull/3562) @@ -140,11 +140,11 @@ No user facing changes. - Fixed the retry mechanism for database uploads. Previously this would fail with the error "Response body object should not be disturbed or locked". [#3564](https://github.com/github/codeql-action/pull/3564) - A warning is now emitted if the CodeQL Action detects a repository property whose name suggests that it relates to the CodeQL Action, but which is not one of the properties recognised by the current version of the CodeQL Action. [#3570](https://github.com/github/codeql-action/pull/3570) -## 4.32.6 - 05 Mar 2026 +## 3.32.6 - 05 Mar 2026 - Update default CodeQL bundle version to [2.24.3](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.24.3). [#3548](https://github.com/github/codeql-action/pull/3548) -## 4.32.5 - 02 Mar 2026 +## 3.32.5 - 02 Mar 2026 - Repositories owned by an organization can now set up the `github-codeql-disable-overlay` custom repository property to disable [improved incremental analysis for CodeQL](https://github.com/github/roadmap/issues/1158). First, create a custom repository property with the name `github-codeql-disable-overlay` and the type "True/false" in the organization's settings. Then in the repository's settings, set this property to `true` to disable improved incremental analysis. For more information, see [Managing custom properties for repositories in your organization](https://docs.github.com/en/organizations/managing-organization-settings/managing-custom-properties-for-repositories-in-your-organization). This feature is not yet available on GitHub Enterprise Server. [#3507](https://github.com/github/codeql-action/pull/3507) - Added an experimental change so that when [improved incremental analysis](https://github.com/github/roadmap/issues/1158) fails on a runner — potentially due to insufficient disk space — the failure is recorded in the Actions cache so that subsequent runs will automatically skip improved incremental analysis until something changes (e.g. a larger runner is provisioned or a new CodeQL version is released). We expect to roll this change out to everyone in March. [#3487](https://github.com/github/codeql-action/pull/3487) @@ -154,7 +154,7 @@ No user facing changes. - Added an experimental change which allows the `start-proxy` action to resolve the CodeQL CLI version from feature flags instead of using the linked CLI bundle version. We expect to roll this change out to everyone in March. [#3512](https://github.com/github/codeql-action/pull/3512) - The previously experimental changes from versions 4.32.3, 4.32.4, 3.32.3 and 3.32.4 are now enabled by default. [#3503](https://github.com/github/codeql-action/pull/3503), [#3504](https://github.com/github/codeql-action/pull/3504) -## 4.32.4 - 20 Feb 2026 +## 3.32.4 - 20 Feb 2026 - Update default CodeQL bundle version to [2.24.2](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.24.2). [#3493](https://github.com/github/codeql-action/pull/3493) - Added an experimental change which improves how certificates are generated for the authentication proxy that is used by the CodeQL Action in Default Setup when [private package registries are configured](https://docs.github.com/en/code-security/how-tos/secure-at-scale/configure-organization-security/manage-usage-and-access/giving-org-access-private-registries). This is expected to generate more widely compatible certificates and should have no impact on analyses which are working correctly already. We expect to roll this change out to everyone in February. [#3473](https://github.com/github/codeql-action/pull/3473) @@ -162,89 +162,89 @@ No user facing changes. - Added a setting which allows the CodeQL Action to enable network debugging for Java programs. This will help GitHub staff support customers with troubleshooting issues in GitHub-managed CodeQL workflows, such as Default Setup. This setting can only be enabled by GitHub staff. [#3485](https://github.com/github/codeql-action/pull/3485) - Added a setting which enables GitHub-managed workflows, such as Default Setup, to use a [nightly CodeQL CLI release](https://github.com/dsp-testing/codeql-cli-nightlies) instead of the latest, stable release that is used by default. This will help GitHub staff support customers whose analyses for a given repository or organization require early access to a change in an upcoming CodeQL CLI release. This setting can only be enabled by GitHub staff. [#3484](https://github.com/github/codeql-action/pull/3484) -## 4.32.3 - 13 Feb 2026 +## 3.32.3 - 13 Feb 2026 - Added experimental support for testing connections to [private package registries](https://docs.github.com/en/code-security/how-tos/secure-at-scale/configure-organization-security/manage-usage-and-access/giving-org-access-private-registries). This feature is not currently enabled for any analysis. In the future, it may be enabled by default for Default Setup. [#3466](https://github.com/github/codeql-action/pull/3466) -## 4.32.2 - 05 Feb 2026 +## 3.32.2 - 05 Feb 2026 - Update default CodeQL bundle version to [2.24.1](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.24.1). [#3460](https://github.com/github/codeql-action/pull/3460) -## 4.32.1 - 02 Feb 2026 +## 3.32.1 - 02 Feb 2026 - A warning is now shown in Default Setup workflow logs if a [private package registry is configured](https://docs.github.com/en/code-security/how-tos/secure-at-scale/configure-organization-security/manage-usage-and-access/giving-org-access-private-registries) using a GitHub Personal Access Token (PAT), but no username is configured. [#3422](https://github.com/github/codeql-action/pull/3422) - Fixed a bug which caused the CodeQL Action to fail when repository properties cannot successfully be retrieved. [#3421](https://github.com/github/codeql-action/pull/3421) -## 4.32.0 - 26 Jan 2026 +## 3.32.0 - 26 Jan 2026 - Update default CodeQL bundle version to [2.24.0](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.24.0). [#3425](https://github.com/github/codeql-action/pull/3425) -## 4.31.11 - 23 Jan 2026 +## 3.31.11 - 23 Jan 2026 - When running a Default Setup workflow with [Actions debugging enabled](https://docs.github.com/en/actions/how-tos/monitor-workflows/enable-debug-logging), the CodeQL Action will now use more unique names when uploading logs from the Dependabot authentication proxy as workflow artifacts. This ensures that the artifact names do not clash between multiple jobs in a build matrix. [#3409](https://github.com/github/codeql-action/pull/3409) - Improved error handling throughout the CodeQL Action. [#3415](https://github.com/github/codeql-action/pull/3415) - Added experimental support for automatically excluding [generated files](https://docs.github.com/en/repositories/working-with-files/managing-files/customizing-how-changed-files-appear-on-github) from the analysis. This feature is not currently enabled for any analysis. In the future, it may be enabled by default for some GitHub-managed analyses. [#3318](https://github.com/github/codeql-action/pull/3318) - The changelog extracts that are included with releases of the CodeQL Action are now shorter to avoid duplicated information from appearing in Dependabot PRs. [#3403](https://github.com/github/codeql-action/pull/3403) -## 4.31.10 - 12 Jan 2026 +## 3.31.10 - 12 Jan 2026 - Update default CodeQL bundle version to 2.23.9. [#3393](https://github.com/github/codeql-action/pull/3393) -## 4.31.9 - 16 Dec 2025 +## 3.31.9 - 16 Dec 2025 No user facing changes. -## 4.31.8 - 11 Dec 2025 +## 3.31.8 - 11 Dec 2025 - Update default CodeQL bundle version to 2.23.8. [#3354](https://github.com/github/codeql-action/pull/3354) -## 4.31.7 - 05 Dec 2025 +## 3.31.7 - 05 Dec 2025 - Update default CodeQL bundle version to 2.23.7. [#3343](https://github.com/github/codeql-action/pull/3343) -## 4.31.6 - 01 Dec 2025 +## 3.31.6 - 01 Dec 2025 No user facing changes. -## 4.31.5 - 24 Nov 2025 +## 3.31.5 - 24 Nov 2025 - Update default CodeQL bundle version to 2.23.6. [#3321](https://github.com/github/codeql-action/pull/3321) -## 4.31.4 - 18 Nov 2025 +## 3.31.4 - 18 Nov 2025 No user facing changes. -## 4.31.3 - 13 Nov 2025 +## 3.31.3 - 13 Nov 2025 - CodeQL Action v3 will be deprecated in December 2026. The Action now logs a warning for customers who are running v3 but could be running v4. For more information, see [Upcoming deprecation of CodeQL Action v3](https://github.blog/changelog/2025-10-28-upcoming-deprecation-of-codeql-action-v3/). - Update default CodeQL bundle version to 2.23.5. [#3288](https://github.com/github/codeql-action/pull/3288) -## 4.31.2 - 30 Oct 2025 +## 3.31.2 - 30 Oct 2025 No user facing changes. -## 4.31.1 - 30 Oct 2025 +## 3.31.1 - 30 Oct 2025 - The `add-snippets` input has been removed from the `analyze` action. This input has been deprecated since CodeQL Action 3.26.4 in August 2024 when this removal was announced. -## 4.31.0 - 24 Oct 2025 +## 3.31.0 - 24 Oct 2025 - Bump minimum CodeQL bundle version to 2.17.6. [#3223](https://github.com/github/codeql-action/pull/3223) - When SARIF files are uploaded by the `analyze` or `upload-sarif` actions, the CodeQL Action automatically performs post-processing steps to prepare the data for the upload. Previously, these post-processing steps were only performed before an upload took place. We are now changing this so that the post-processing steps will always be performed, even when the SARIF files are not uploaded. This does not change anything for the `upload-sarif` action. For `analyze`, this may affect Advanced Setup for CodeQL users who specify a value other than `always` for the `upload` input. [#3222](https://github.com/github/codeql-action/pull/3222) -## 4.30.9 - 17 Oct 2025 +## 3.30.9 - 17 Oct 2025 - Update default CodeQL bundle version to 2.23.3. [#3205](https://github.com/github/codeql-action/pull/3205) - Experimental: A new `setup-codeql` action has been added which is similar to `init`, except it only installs the CodeQL CLI and does not initialize a database. Do not use this in production as it is part of an internal experiment and subject to change at any time. [#3204](https://github.com/github/codeql-action/pull/3204) -## 4.30.8 - 10 Oct 2025 +## 3.30.8 - 10 Oct 2025 No user facing changes. -## 4.30.7 - 06 Oct 2025 +## 3.30.7 - 06 Oct 2025 -- [v4+ only] The CodeQL Action now runs on Node.js v24. [#3169](https://github.com/github/codeql-action/pull/3169) +No user facing changes. ## 3.30.6 - 02 Oct 2025 - Update default CodeQL bundle version to 2.23.2. [#3168](https://github.com/github/codeql-action/pull/3168) diff --git a/package.json b/package.json index 3156038252..c37bab23fe 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codeql", - "version": "4.38.2", + "version": "3.38.2", "private": true, "description": "CodeQL action", "scripts": { From a09a142526ba6a951b9594e82ea58f44b9c670b2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 24 Sep 2026 10:29:19 +0000 Subject: [PATCH 47/47] Rebuild --- lib/entry-points.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/entry-points.js b/lib/entry-points.js index e89c2ab073..7b84b154a0 100644 --- a/lib/entry-points.js +++ b/lib/entry-points.js @@ -146168,7 +146168,7 @@ function getDiffRangesJsonFilePath(env = getEnv()) { return path2.join(getTemporaryDirectory(env), PR_DIFF_RANGE_JSON_FILENAME); } function getActionVersion() { - return "4.38.2"; + return "3.38.2"; } function getWorkflowEventName(env = getEnv()) { return env.getRequired("GITHUB_EVENT_NAME" /* GITHUB_EVENT_NAME */);