diff --git a/.github/min-versions.json b/.github/min-versions.json new file mode 100644 index 000000000..ea1de7336 --- /dev/null +++ b/.github/min-versions.json @@ -0,0 +1,6 @@ +{ + "comment": "This file is fetched by the AppMap extension from https://raw.githubusercontent.com/getappmap/vscode-appland/develop/.github/min-versions.json.", + + "vsCode": "1.89.0", + "extension": "0.118.2" +} diff --git a/src/extension.ts b/src/extension.ts index 74c00e7ee..fcbb9603b 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -63,6 +63,7 @@ import CommandRegistry from './commands/commandRegistry'; import AssetService from './assets/assetService'; import clearNavieAiSettings from './commands/clearNavieAiSettings'; import EnvironmentVariableService from './services/environmentVariableService'; +import { checkVersions } from './lib/checkVersions'; export async function activate(context: vscode.ExtensionContext): Promise { CommandRegistry.setContext(context).addWaitAlias({ @@ -84,6 +85,8 @@ export async function activate(context: vscode.ExtensionContext): Promise { + if (minVersions == undefined) minVersions = await fetchMinVersions(minVersionsJsonUrl); + if (minVersions == undefined) return; + + const vsCodeIsOld = + minVersions.vsCode && + semverValid(minVersions.vsCode, true) && + semverCompare(minVersions.vsCode, vscode.version, true) == 1; + const extensionIsOld = + minVersions.extension && + semverValid(minVersions.extension, true) && + semverCompare(minVersions.extension, context.extension.packageJSON.version, true) == 1; + + const clauses: string[] = []; + if (vsCodeIsOld) clauses.push(`VSCode to v${minVersions.vsCode} or higher`); + if (extensionIsOld) clauses.push(`AppMap extension to v${minVersions.extension} or higher`); + if (clauses.length > 0) { + const choice = await vscode.window.showWarningMessage( + `Update Required: Please update ${clauses.join(' and ')}.`, + 'Update Now' + ); + if (choice == 'Update Now') { + if (vsCodeIsOld) vscode.commands.executeCommand('update.checkForUpdate'); + else vscode.commands.executeCommand('workbench.extensions.action.checkForUpdates'); + } + } +} diff --git a/test/integration/lib/checkVersions.test.ts b/test/integration/lib/checkVersions.test.ts new file mode 100644 index 000000000..2834d1996 --- /dev/null +++ b/test/integration/lib/checkVersions.test.ts @@ -0,0 +1,74 @@ +import assert from 'assert'; +import * as vscode from 'vscode'; +import * as semver from 'semver'; +import { SinonSandbox, SinonStub, createSandbox } from 'sinon'; +import MockExtensionContext from '../../mocks/mockExtensionContext'; +import { checkVersions } from '../../../src/lib/checkVersions'; + +describe('Check VSCode and extension versions', () => { + let sinon: SinonSandbox; + let context: MockExtensionContext; + let showWarningMessageStub: SinonStub; + let executeCommandStub: SinonStub; + + beforeEach(() => { + sinon = createSandbox(); + context = new MockExtensionContext(); + + showWarningMessageStub = sinon.stub(vscode.window, 'showWarningMessage'); + showWarningMessageStub.resolves('Update Now' as unknown as vscode.MessageItem); + executeCommandStub = sinon.stub(vscode.commands, 'executeCommand'); + }); + + afterEach(() => { + context.dispose(); + sinon.restore(); + }); + + it('warning shown when both versions are old', async () => { + // Can't replace vscode.version + // sinon.replaceGetter(vscode, 'version', () => '1.82'); + const minVersions = { + vsCode: semver.inc(vscode.version, 'minor') ?? undefined, + extension: '0.118.2', + }; + sinon.replace(context.extension.packageJSON, 'version', '0.118.0'); + await checkVersions(context, minVersions); + assert.equal(showWarningMessageStub.callCount, 1); + assert.equal( + showWarningMessageStub.firstCall.args[0], + `Update Required: Please update VSCode to v${minVersions.vsCode} or higher` + + ` and AppMap extension to v${minVersions.extension} or higher.` + ); + assert.equal(executeCommandStub.callCount, 1); + assert.equal(executeCommandStub.firstCall.args[0], 'update.checkForUpdate'); + }); + + it('warning shown when only extension version is old', async () => { + const minVersions = { + vsCode: vscode.version, + extension: '0.118.2', + }; + sinon.replace(context.extension.packageJSON, 'version', '0.118.0'); + await checkVersions(context, minVersions); + assert.equal(showWarningMessageStub.callCount, 1); + assert.equal( + showWarningMessageStub.firstCall.args[0], + `Update Required: Please update AppMap extension to v${minVersions.extension} or higher.` + ); + assert.equal(executeCommandStub.callCount, 1); + assert.equal( + executeCommandStub.firstCall.args[0], + 'workbench.extensions.action.checkForUpdates' + ); + }); + + it('no warning when versions are up to date', async () => { + await checkVersions(context, { + vsCode: vscode.version, + extension: context.extension.packageJSON.version, + }); + assert(showWarningMessageStub.notCalled); + assert(executeCommandStub.notCalled); + }); +});