diff --git a/extensions/azdata/package.json b/extensions/azdata/package.json index 492f2bda33..de5cdb2689 100644 --- a/extensions/azdata/package.json +++ b/extensions/azdata/package.json @@ -71,6 +71,19 @@ "%azdata.update.prompt.description%" ], "description": "%azdata.update.description%" + }, + "azdata.requiredUpdate": { + "type": "string", + "default": "prompt", + "enum": [ + "dontPrompt", + "prompt" + ], + "enumDescriptions": [ + "%azdata.update.dontPrompt.description%", + "%azdata.update.prompt.description%" + ], + "description": "%azdata.requiredUpdate.description%" } } } diff --git a/extensions/azdata/package.nls.json b/extensions/azdata/package.nls.json index 534be0098f..e209128666 100644 --- a/extensions/azdata/package.nls.json +++ b/extensions/azdata/package.nls.json @@ -18,7 +18,8 @@ "azdata.install.prompt.description": "The user will be prompted for installation of the Azure Data CLI", "azdata.install.dontPrompt.description": "The user will not be prompted for installation of the Azure Data CLI", - "azdata.update.description": "Choose how update of Azure Data CLI tool is done", + "azdata.update.description": "Choose whether you will be prompted when an update of the Azure Data CLI is available.", + "azdata.requiredUpdate.description": "Choose whether you will be prompted when a required update of the Azure Data CLI is available.", "azdata.update.prompt.description": "The user will be prompted for update of the Azure Data CLI", "azdata.update.dontPrompt.description": "The user will not be prompted for update of the Azure Data CLI" } diff --git a/extensions/azdata/src/azdata.ts b/extensions/azdata/src/azdata.ts index 31c5631222..6f83bab06a 100644 --- a/extensions/azdata/src/azdata.ts +++ b/extensions/azdata/src/azdata.ts @@ -14,7 +14,7 @@ import { executeCommand, executeSudoCommand, ExitCodeError, ProcessOutput } from import { HttpClient } from './common/httpClient'; import Logger from './common/logger'; import { getErrorMessage, NoAzdataError, searchForCmd } from './common/utils'; -import { azdataAcceptEulaKey, azdataConfigSection, azdataFound, azdataInstallKey, azdataUpdateKey, debugConfigKey, eulaAccepted, eulaUrl, microsoftPrivacyStatementUrl } from './constants'; +import { azdataAcceptEulaKey, azdataConfigSection, azdataFound, azdataInstallKey, azdataUpdateKey, azdatarequiredUpdateKey, debugConfigKey, eulaAccepted, eulaUrl, microsoftPrivacyStatementUrl } from './constants'; import * as loc from './localizedConstants'; /** @@ -320,31 +320,43 @@ export async function installAzdata(): Promise { /** * Updates the azdata using os appropriate method */ -export async function updateAzdata(): Promise { - Logger.show(); - Logger.log(loc.updatingAzdata); - await vscode.window.withProgress( - { - location: vscode.ProgressLocation.Notification, - title: loc.updatingAzdata, - cancellable: false - }, - async (_progress, _token): Promise => { - switch (process.platform) { - case 'win32': - await downloadAndInstallAzdataWin32(); - break; - case 'darwin': - await updateAzdataDarwin(); - break; - case 'linux': - await installAzdataLinux(); - break; - default: - throw new Error(loc.platformUnsupported(process.platform)); +async function updateAzdata(version: string): Promise { + try { + Logger.show(); + Logger.log(loc.updatingAzdata); + await vscode.window.withProgress( + { + location: vscode.ProgressLocation.Notification, + title: loc.updatingAzdata, + cancellable: false + }, + async (_progress, _token): Promise => { + switch (process.platform) { + case 'win32': + await downloadAndInstallAzdataWin32(); + break; + case 'darwin': + await updateAzdataDarwin(); + break; + case 'linux': + await installAzdataLinux(); + break; + default: + throw new Error(loc.platformUnsupported(process.platform)); + } } + ); + vscode.window.showInformationMessage(loc.azdataUpdated(version)); + Logger.log(loc.azdataUpdated(version)); + return true; + } catch (err) { + // Windows: 1602 is User cancelling installation/update - not unexpected so don't display + if (!(err instanceof ExitCodeError) || err.code !== 1602) { + vscode.window.showWarningMessage(loc.updateError(err)); + Logger.log(loc.updateError(err)); } - ); + } + return false; } /** @@ -453,24 +465,25 @@ async function promptToInstallAzdata(userRequested: boolean = false): Promise { if (required) { let response: string | undefined = loc.yes; - - const responses = [loc.yes, loc.no]; + const config = getConfig(azdatarequiredUpdateKey); + if (userRequested) { + Logger.show(); + Logger.log(loc.userRequestedUpdate); + } + if (config === AzdataDeployOption.dontPrompt && !userRequested) { + Logger.log(loc.skipRequiredUpdate(config)); + return false; + } + const responses = userRequested + ? [loc.yes, loc.no] + : [loc.yes, loc.askLater, loc.doNotAskAgain]; Logger.log(loc.promptForRequiredAzdataUpdateLog(MIN_AZDATA_VERSION.raw, newVersion)); response = await vscode.window.showInformationMessage(loc.promptForRequiredAzdataUpdate(MIN_AZDATA_VERSION.raw, newVersion), ...responses); Logger.log(loc.userResponseToUpdatePrompt(response)); - if (response === loc.yes) { - try { - await updateAzdata(); - vscode.window.showInformationMessage(loc.azdataUpdated(newVersion)); - Logger.log(loc.azdataUpdated(newVersion)); - return true; - } catch (err) { - // Windows: 1602 is User cancelling installation/update - not unexpected so don't display - if (!(err instanceof ExitCodeError) || err.code !== 1602) { - vscode.window.showWarningMessage(loc.updateError(err)); - Logger.log(loc.updateError(err)); - } - } + if (response === loc.doNotAskAgain) { + await setConfig(azdatarequiredUpdateKey, AzdataDeployOption.dontPrompt); + } else if (response === loc.yes) { + return updateAzdata(newVersion); } else { vscode.window.showWarningMessage(loc.missingRequiredVersion(MIN_AZDATA_VERSION.raw)); } @@ -496,25 +509,12 @@ async function promptToUpdateAzdata(newVersion: string, userRequested: boolean = if (response === loc.doNotAskAgain) { await setConfig(azdataUpdateKey, AzdataDeployOption.dontPrompt); } else if (response === loc.yes) { - try { - await updateAzdata(); - vscode.window.showInformationMessage(loc.azdataUpdated(newVersion)); - Logger.log(loc.azdataUpdated(newVersion)); - return true; - } catch (err) { - // Windows: 1602 is User cancelling installation/update - not unexpected so don't display - if (!(err instanceof ExitCodeError) || err.code !== 1602) { - vscode.window.showWarningMessage(loc.updateError(err)); - Logger.log(loc.updateError(err)); - } - } + return updateAzdata(newVersion); } } return false; } - - /** * Returns true if Eula has been accepted. * diff --git a/extensions/azdata/src/constants.ts b/extensions/azdata/src/constants.ts index 643f551e26..cb83d42bbd 100644 --- a/extensions/azdata/src/constants.ts +++ b/extensions/azdata/src/constants.ts @@ -8,6 +8,7 @@ export const azdataConfigSection: string = 'azdata'; export const azdataAcceptEulaKey: string = 'acceptEula'; export const azdataInstallKey: string = 'install'; export const azdataUpdateKey: string = 'update'; +export const azdatarequiredUpdateKey: string = 'requiredUpdate'; export const debugConfigKey = 'logDebugInfo'; diff --git a/extensions/azdata/src/localizedConstants.ts b/extensions/azdata/src/localizedConstants.ts index 1775d991b4..68c8193600 100644 --- a/extensions/azdata/src/localizedConstants.ts +++ b/extensions/azdata/src/localizedConstants.ts @@ -5,7 +5,7 @@ import * as nls from 'vscode-nls'; import { getErrorMessage } from './common/utils'; -import { azdataConfigSection, azdataInstallKey, azdataUpdateKey } from './constants'; +import { azdataConfigSection, azdataInstallKey, azdataUpdateKey, azdatarequiredUpdateKey } from './constants'; const localize = nls.loadMessageBundle(); export const azdata = localize('azdata.azdata', "Azure Data CLI"); @@ -42,7 +42,7 @@ export const promptForRequiredAzdataUpdate = (requiredVersion: string, latestVer export const requiredVersionNotAvailable = (requiredVersion: string, currentVersion: string): string => localize('azdata.requiredVersionNotAvailable', "This extension requires Azure Data CLI >= {0} to be installed, but the current version available is only {1}. Install the correct version manually from [here](https://docs.microsoft.com/sql/azdata/install/deploy-install-azdata) and then restart Azure Data Studio.", requiredVersion, currentVersion); export const promptForAzdataUpdateLog = (version: string): string => promptLog(promptForAzdataUpdate(version)); export const promptForRequiredAzdataUpdateLog = (requiredVersion: string, latestVersion: string): string => promptLog(promptForRequiredAzdataUpdate(requiredVersion, latestVersion)); -export const missingRequiredVersion = (requiredVersion: string): string => localize('azdata.missingRequiredVersion', "Azure Data CLI >= {0} is required for this extension to function, some features may not work correctly until that version or higher is installed.", requiredVersion); +export const missingRequiredVersion = (requiredVersion: string): string => localize('azdata.missingRequiredVersion', "Azure Data CLI >= {0} is required for this feature. Run the 'Azure Data CLI: Check for Update' command to install this and then try again.", requiredVersion); export const downloadError = localize('azdata.downloadError', "Error while downloading"); export const installError = (err: any): string => localize('azdata.installError', "Error installing Azure Data CLI: {0}", err.message ?? err); export const updateError = (err: any): string => localize('azdata.updateError', "Error updating Azure Data CLI: {0}", err.message ?? err); @@ -53,6 +53,7 @@ export const noAzdata = localize('azdata.noAzdata', "No Azure Data CLI is availa export const noAzdataWithLink = localize('azdata.noAzdataWithLink', "No Azure Data CLI is available, [install the Azure Data CLI](command:azdata.install) to enable the features that require it."); export const skipInstall = (config: string): string => localize('azdata.skipInstall', "Skipping installation of Azure Data CLI, since the operation was not user requested and config option: {0}.{1} is {2}", azdataConfigSection, azdataInstallKey, config); export const skipUpdate = (config: string): string => localize('azdata.skipUpdate', "Skipping update of Azure Data CLI, since the operation was not user requested and config option: {0}.{1} is {2}", azdataConfigSection, azdataUpdateKey, config); +export const skipRequiredUpdate = (config: string): string => localize('azdata.skipRequiredUpdate', "Skipping required update of Azure Data CLI, since the operation was not user requested and config option: {0}.{1} is {2}", azdataConfigSection, azdatarequiredUpdateKey, config); export const noReleaseVersion = (platform: string, releaseInfo: string): string => localize('azdata.noReleaseVersion', "No release version available for platform '{0}'\nRelease info: ${1}", platform, releaseInfo); export const noDownloadLink = (platform: string, releaseInfo: string): string => localize('azdata.noDownloadLink', "No download link available for platform '{0}'\nRelease info: ${1}", platform, releaseInfo); export const failedToParseReleaseInfo = (url: string, fileContents: string, err: any): string => localize('azdata.failedToParseReleaseInfo', "Failed to parse the JSON of contents at: {0}.\nFile contents:\n{1}\nError: {2}", url, fileContents, getErrorMessage(err));