diff --git a/extensions/ql-vscode/CHANGELOG.md b/extensions/ql-vscode/CHANGELOG.md index 5bfed122e1d..538c1713604 100644 --- a/extensions/ql-vscode/CHANGELOG.md +++ b/extensions/ql-vscode/CHANGELOG.md @@ -2,6 +2,8 @@ ## [UNRELEASED] +- After an extension-managed CodeQL CLI update, the notification now offers to open the CLI release notes instead of the extension log. [#1095](https://github.com/github/vscode-codeql/issues/1095) + ## 1.17.8 - 17 July 2026 - Fix a bug where installing or updating the CodeQL CLI could hang indefinitely while extracting the downloaded archive. Extraction now reports an error if a file cannot be written, and aborts with a clear message if no progress is made within the download timeout (for example due to slow or networked storage, or security software). [#4455](https://github.com/github/vscode-codeql/pull/4455) diff --git a/extensions/ql-vscode/src/codeql-cli/distribution/release-notes.ts b/extensions/ql-vscode/src/codeql-cli/distribution/release-notes.ts new file mode 100644 index 00000000000..a9bde0d4259 --- /dev/null +++ b/extensions/ql-vscode/src/codeql-cli/distribution/release-notes.ts @@ -0,0 +1,18 @@ +import { env, Uri } from "vscode"; +import { showInformationMessageWithAction } from "../../common/vscode/dialog"; + +export const codeQlCliReleaseNotesUrl = + "https://github.com/github/codeql-cli-binaries/blob/main/CHANGELOG.md"; + +/** + * Offers release notes after the extension updates its managed CodeQL CLI. + */ +export async function offerCodeQlCliReleaseNotes( + updateMessage: string, +): Promise { + if ( + await showInformationMessageWithAction(updateMessage, "Show release notes") + ) { + await env.openExternal(Uri.parse(codeQlCliReleaseNotesUrl)); + } +} diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index cda8a62e0f9..925e231b00d 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -65,6 +65,7 @@ import { showBinaryChoiceDialog, showInformationMessageWithAction, } from "./common/vscode/dialog"; +import { offerCodeQlCliReleaseNotes } from "./codeql-cli/distribution/release-notes"; import { asError, assertNever, @@ -555,10 +556,9 @@ async function installOrUpdateDistributionWithProgressTitle( ); await ctx.globalState.update(shouldUpdateOnNextActivationKey, false); - void showAndLogInformationMessage( - extLogger, - `CodeQL CLI updated to version "${result.updatedRelease.name}".`, - ); + const updateMessage = `CodeQL CLI updated to version "${result.updatedRelease.name}".`; + void extLogger.log(updateMessage); + void offerCodeQlCliReleaseNotes(updateMessage); } break; default: diff --git a/extensions/ql-vscode/test/vscode-tests/no-workspace/codeql-cli/release-notes.test.ts b/extensions/ql-vscode/test/vscode-tests/no-workspace/codeql-cli/release-notes.test.ts new file mode 100644 index 00000000000..d6f27054af3 --- /dev/null +++ b/extensions/ql-vscode/test/vscode-tests/no-workspace/codeql-cli/release-notes.test.ts @@ -0,0 +1,42 @@ +import { env, Uri, window } from "vscode"; +import { + codeQlCliReleaseNotesUrl, + offerCodeQlCliReleaseNotes, +} from "../../../../src/codeql-cli/distribution/release-notes"; + +describe("offerCodeQlCliReleaseNotes", () => { + const updateMessage = 'CodeQL CLI updated to version "v2.23.0".'; + let showInformationMessageSpy: jest.SpiedFunction< + typeof window.showInformationMessage + >; + let openExternalSpy: jest.SpiedFunction; + + beforeEach(() => { + showInformationMessageSpy = jest + .spyOn(window, "showInformationMessage") + .mockResolvedValue(undefined); + openExternalSpy = jest.spyOn(env, "openExternal").mockResolvedValue(true); + }); + + it("opens the CLI changelog when the release-notes action is selected", async () => { + showInformationMessageSpy.mockImplementationOnce((...args) => + Promise.resolve(args[1]), + ); + + await offerCodeQlCliReleaseNotes(updateMessage); + + expect(showInformationMessageSpy).toHaveBeenCalledWith(updateMessage, { + title: "Show release notes", + isCloseAffordance: false, + }); + expect(openExternalSpy).toHaveBeenCalledWith( + Uri.parse(codeQlCliReleaseNotesUrl), + ); + }); + + it("does not open the changelog when the message is dismissed", async () => { + await offerCodeQlCliReleaseNotes(updateMessage); + + expect(openExternalSpy).not.toHaveBeenCalled(); + }); +});