diff --git a/.github/workflows/__rubocop-multi-language.yml b/.github/workflows/__rubocop-multi-language.yml index c405b44fe..96f2dacca 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 diff --git a/CHANGELOG.md b/CHANGELOG.md index 267b4e557..a8880f37a 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 diff --git a/lib/defaults.json b/lib/defaults.json index e4875a8a3..e201dfd79 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 fb6a8b6e2..727360efc 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) { @@ -147750,8 +147751,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")); @@ -153267,6 +153268,7 @@ async function getCodeQLForCmd(logger, cmd, checkVersion) { "--format=json", `--language=${language}`, "--extractor-include-aliases", + "-J-XX:-UsePerfData", ...getExtraOptionsFromEnv(["resolve", "extractor"]) ], { @@ -164517,7 +164519,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: (** diff --git a/package-lock.json b/package-lock.json index d4f189db2..955fcf6d9 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 7f31e80e9..315603825 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/changelog/validate.mts b/pr-checks/changelog/validate.mts index 2e28a4ab1..3c83276f3 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 a38339d1c..b8b1e33bb 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 d19d2da83..980d103a2 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; } diff --git a/pr-checks/checks/rubocop-multi-language.yml b/pr-checks/checks/rubocop-multi-language.yml index 37c5d36e9..550bdb6cc 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 diff --git a/pr-checks/package.json b/pr-checks/package.json index 0c5091a79..58722bd0e 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", diff --git a/src/codeql.ts b/src/codeql.ts index 2dfc65996..a4da8ad68 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"]), ], { diff --git a/src/defaults.json b/src/defaults.json index e4875a8a3..e201dfd79 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" } diff --git a/src/git-utils.test.ts b/src/git-utils.test.ts index b77d40a7e..64b76590a 100644 --- a/src/git-utils.test.ts +++ b/src/git-utils.test.ts @@ -29,10 +29,13 @@ 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.is(callback.callCount, 1); + t.true(callback.calledOnceWith(tmpDir, "HEAD")); }); }, ); @@ -48,11 +51,17 @@ 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.is(callback.callCount, 2); + t.true(callback.calledWith(tmpDir, "HEAD")); + t.true(callback.calledWith(tmpDir, "refs/remotes/pull/1/merge")); }); }, ); @@ -66,11 +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.is(callback.callCount, 2); + t.true(callback.calledWith(tmpDir, "refs/remotes/pull/1/merge")); + t.true(callback.calledWith(tmpDir, "HEAD")); }); }, ); @@ -92,11 +108,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"); + + // getCommitOid shouldn't be called, because the ref should be taken from the input + t.is(callback.callCount, 0); }); }, ); diff --git a/src/per-language-bundles.test.ts b/src/per-language-bundles.test.ts index b8f48512f..0330b51a6 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 }), }), diff --git a/src/per-language-bundles.ts b/src/per-language-bundles.ts index f4e46403d..e4468d2f3 100644 --- a/src/per-language-bundles.ts +++ b/src/per-language-bundles.ts @@ -102,8 +102,11 @@ 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. + // 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"); diff --git a/src/setup-codeql.test.ts b/src/setup-codeql.test.ts index c35bdb840..6ac5bebf1 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) => { diff --git a/src/util.ts b/src/util.ts index be67a111b..49a69f035 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); }