mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-02 01:25:39 -05:00
Port updates for removing EULA acceptance checkbox from Arc deployments (#12409)
* controller dropdown field to SQL MIAA and Postgres deployment. (#12217) * saving first draft * throw if no controllers * cleanup * bug fixes * bug fixes and caching controller access * pr comments and bug fixes. * fixes * fixes * comment fix * remove debug prints * comment fixes * remove debug logs * inputValueTransformer returns string|Promise * PR feedback * pr fixes * remove _ from protected fields * anonymous to full methods * small fixes (cherry picked from commit9cf80113fc) * fix option sources (#12387) (cherry picked from commitfca8b85a72) * Remove azdata eula acceptance from arc deployments (#12292) * saving to switch tasks * activate to exports in extApi * working version - cleanup pending * improve messages * apply pr feedback from a different review * remove unneeded strings * redo apiService * remove async from getVersionFromOutput * remove _ prefix from protected fields * error message fix * throw specif errors from azdata extension * arrow methods to regular methods * pr feedback * expand azdata extension api * pr feedback * remove unused var * pr feedback (cherry picked from commitba44a2f02e) Co-authored-by: Arvind Ranasaria <ranasaria@outlook.com>
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as azdataExt from 'azdata-ext';
|
||||
import * as fs from 'fs';
|
||||
import * as os from 'os';
|
||||
import { SemVer } from 'semver';
|
||||
import * as vscode from 'vscode';
|
||||
@@ -13,7 +14,6 @@ import Logger from './common/logger';
|
||||
import { getErrorMessage, searchForCmd } from './common/utils';
|
||||
import { azdataAcceptEulaKey, azdataConfigSection, azdataFound, azdataHostname, azdataInstallKey, azdataReleaseJson, azdataUpdateKey, azdataUri, debugConfigKey, eulaAccepted, eulaUrl, microsoftPrivacyStatementUrl } from './constants';
|
||||
import * as loc from './localizedConstants';
|
||||
import * as fs from 'fs';
|
||||
|
||||
const enum AzdataDeployOption {
|
||||
dontPrompt = 'dontPrompt',
|
||||
@@ -24,9 +24,6 @@ const enum AzdataDeployOption {
|
||||
* Interface for an object to interact with the azdata tool installed on the box.
|
||||
*/
|
||||
export interface IAzdataTool extends azdataExt.IAzdataApi {
|
||||
path: string,
|
||||
cachedVersion: SemVer
|
||||
|
||||
/**
|
||||
* Executes azdata with the specified arguments (e.g. --version) and returns the result
|
||||
* @param args The args to pass to azdata
|
||||
@@ -39,9 +36,26 @@ export interface IAzdataTool extends azdataExt.IAzdataApi {
|
||||
* An object to interact with the azdata tool installed on the box.
|
||||
*/
|
||||
export class AzdataTool implements IAzdataTool {
|
||||
public cachedVersion: SemVer;
|
||||
constructor(public path: string, version: string) {
|
||||
this.cachedVersion = new SemVer(version);
|
||||
|
||||
private _semVersion: SemVer;
|
||||
constructor(private _path: string, version: string) {
|
||||
this._semVersion = new SemVer(version);
|
||||
}
|
||||
|
||||
/**
|
||||
* The semVersion corresponding to this installation of azdata. version() method should have been run
|
||||
* before fetching this value to ensure that correct value is returned. This is almost always correct unless
|
||||
* Azdata has gotten reinstalled in the background after this IAzdataApi object was constructed.
|
||||
*/
|
||||
public getSemVersion() {
|
||||
return this._semVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* gets the path where azdata tool is installed
|
||||
*/
|
||||
public getPath() {
|
||||
return this._path;
|
||||
}
|
||||
|
||||
public arc = {
|
||||
@@ -110,8 +124,8 @@ export class AzdataTool implements IAzdataTool {
|
||||
* It also updates the cachedVersion property based on the return value from the tool.
|
||||
*/
|
||||
public async version(): Promise<azdataExt.AzdataOutput<string>> {
|
||||
const output = await executeAzdataCommand(`"${this.path}"`, ['--version']);
|
||||
this.cachedVersion = new SemVer(parseVersion(output.stdout));
|
||||
const output = await executeAzdataCommand(`"${this._path}"`, ['--version']);
|
||||
this._semVersion = new SemVer(parseVersion(output.stdout));
|
||||
return {
|
||||
logs: [],
|
||||
stdout: output.stdout.split(os.EOL),
|
||||
@@ -122,7 +136,7 @@ export class AzdataTool implements IAzdataTool {
|
||||
|
||||
public async executeCommand<R>(args: string[], additionalEnvVars?: { [key: string]: string }): Promise<azdataExt.AzdataOutput<R>> {
|
||||
try {
|
||||
const output = JSON.parse((await executeAzdataCommand(`"${this.path}"`, args.concat(['--output', 'json']), additionalEnvVars)).stdout);
|
||||
const output = JSON.parse((await executeAzdataCommand(`"${this._path}"`, args.concat(['--output', 'json']), additionalEnvVars)).stdout);
|
||||
return {
|
||||
logs: <string[]>output.log,
|
||||
stdout: <string[]>output.stdout,
|
||||
@@ -136,12 +150,12 @@ export class AzdataTool implements IAzdataTool {
|
||||
// to get the correct stderr out. The actual value we get is something like
|
||||
// ERROR: { stderr: '...' }
|
||||
// so we also need to trim off the start that isn't a valid JSON blob
|
||||
err.stderr = JSON.parse(err.stderr.substring(err.stderr.indexOf('{'))).stderr;
|
||||
err.stderr = JSON.parse(err.stderr.substring(err.stderr.indexOf('{'), err.stderr.indexOf('}') + 1)).stderr;
|
||||
} catch (err) {
|
||||
// it means this was probably some other generic error (such as command not being found)
|
||||
// check if azdata still exists if it does then rethrow the original error if not then emit a new specific error.
|
||||
try {
|
||||
await fs.promises.access(this.path);
|
||||
await fs.promises.access(this._path);
|
||||
//this.path exists
|
||||
throw err; // rethrow the error
|
||||
} catch (e) {
|
||||
@@ -176,7 +190,7 @@ export async function findAzdata(): Promise<IAzdataTool> {
|
||||
try {
|
||||
const azdata = await findSpecificAzdata();
|
||||
await vscode.commands.executeCommand('setContext', azdataFound, true); // save a context key that azdata was found so that command for installing azdata is no longer available in commandPalette and that for updating it is.
|
||||
Logger.log(loc.foundExistingAzdata(azdata.path, azdata.cachedVersion.raw));
|
||||
Logger.log(loc.foundExistingAzdata(azdata.getPath(), azdata.getSemVersion().raw));
|
||||
return azdata;
|
||||
} catch (err) {
|
||||
Logger.log(loc.couldNotFindAzdata(err));
|
||||
@@ -262,12 +276,12 @@ export async function checkAndInstallAzdata(userRequested: boolean = false): Pro
|
||||
*/
|
||||
export async function checkAndUpdateAzdata(currentAzdata?: IAzdataTool, userRequested: boolean = false): Promise<boolean> {
|
||||
if (currentAzdata !== undefined) {
|
||||
const newVersion = await discoverLatestAvailableAzdataVersion();
|
||||
if (newVersion.compare(currentAzdata.cachedVersion) === 1) {
|
||||
Logger.log(loc.foundAzdataVersionToUpdateTo(newVersion.raw, currentAzdata.cachedVersion.raw));
|
||||
return await promptToUpdateAzdata(newVersion.raw, userRequested);
|
||||
const newSemVersion = await discoverLatestAvailableAzdataVersion();
|
||||
if (newSemVersion.compare(currentAzdata.getSemVersion()) === 1) {
|
||||
Logger.log(loc.foundAzdataVersionToUpdateTo(newSemVersion.raw, currentAzdata.getSemVersion().raw));
|
||||
return await promptToUpdateAzdata(newSemVersion.raw, userRequested);
|
||||
} else {
|
||||
Logger.log(loc.currentlyInstalledVersionIsLatest(currentAzdata.cachedVersion.raw));
|
||||
Logger.log(loc.currentlyInstalledVersionIsLatest(currentAzdata.getSemVersion().raw));
|
||||
}
|
||||
} else {
|
||||
Logger.log(loc.updateCheckSkipped);
|
||||
|
||||
@@ -12,7 +12,6 @@ import * as loc from './localizedConstants';
|
||||
|
||||
let localAzdata: IAzdataTool | undefined = undefined;
|
||||
let eulaAccepted: boolean = false;
|
||||
|
||||
export async function activate(context: vscode.ExtensionContext): Promise<azdataExt.IExtension> {
|
||||
vscode.commands.registerCommand('azdata.acceptEula', async () => {
|
||||
eulaAccepted = await promptForEula(context.globalState, true /* userRequested */);
|
||||
@@ -59,26 +58,27 @@ export async function activate(context: vscode.ExtensionContext): Promise<azdata
|
||||
});
|
||||
|
||||
return {
|
||||
isEulaAccepted: () => !!context.globalState.get<boolean>(constants.eulaAccepted),
|
||||
azdata: {
|
||||
arc: {
|
||||
dc: {
|
||||
create: async (namespace: string, name: string, connectivityMode: string, resourceGroup: string, location: string, subscription: string, profileName?: string, storageClass?: string) => {
|
||||
await throwIfNoAzdataOrEulaNotAccepted();
|
||||
throwIfNoAzdataOrEulaNotAccepted();
|
||||
return localAzdata!.arc.dc.create(namespace, name, connectivityMode, resourceGroup, location, subscription, profileName, storageClass);
|
||||
},
|
||||
endpoint: {
|
||||
list: async () => {
|
||||
await throwIfNoAzdataOrEulaNotAccepted();
|
||||
throwIfNoAzdataOrEulaNotAccepted();
|
||||
return localAzdata!.arc.dc.endpoint.list();
|
||||
}
|
||||
},
|
||||
config: {
|
||||
list: async () => {
|
||||
await throwIfNoAzdataOrEulaNotAccepted();
|
||||
throwIfNoAzdataOrEulaNotAccepted();
|
||||
return localAzdata!.arc.dc.config.list();
|
||||
},
|
||||
show: async () => {
|
||||
await throwIfNoAzdataOrEulaNotAccepted();
|
||||
throwIfNoAzdataOrEulaNotAccepted();
|
||||
return localAzdata!.arc.dc.config.show();
|
||||
}
|
||||
}
|
||||
@@ -86,11 +86,11 @@ export async function activate(context: vscode.ExtensionContext): Promise<azdata
|
||||
postgres: {
|
||||
server: {
|
||||
list: async () => {
|
||||
await throwIfNoAzdataOrEulaNotAccepted();
|
||||
throwIfNoAzdataOrEulaNotAccepted();
|
||||
return localAzdata!.arc.postgres.server.list();
|
||||
},
|
||||
show: async (name: string) => {
|
||||
await throwIfNoAzdataOrEulaNotAccepted();
|
||||
throwIfNoAzdataOrEulaNotAccepted();
|
||||
return localAzdata!.arc.postgres.server.show(name);
|
||||
}
|
||||
}
|
||||
@@ -98,41 +98,53 @@ export async function activate(context: vscode.ExtensionContext): Promise<azdata
|
||||
sql: {
|
||||
mi: {
|
||||
delete: async (name: string) => {
|
||||
await throwIfNoAzdataOrEulaNotAccepted();
|
||||
throwIfNoAzdataOrEulaNotAccepted();
|
||||
return localAzdata!.arc.sql.mi.delete(name);
|
||||
},
|
||||
list: async () => {
|
||||
await throwIfNoAzdataOrEulaNotAccepted();
|
||||
throwIfNoAzdataOrEulaNotAccepted();
|
||||
return localAzdata!.arc.sql.mi.list();
|
||||
},
|
||||
show: async (name: string) => {
|
||||
await throwIfNoAzdataOrEulaNotAccepted();
|
||||
throwIfNoAzdataOrEulaNotAccepted();
|
||||
return localAzdata!.arc.sql.mi.show(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
getPath: () => {
|
||||
throwIfNoAzdata();
|
||||
return localAzdata!.getPath();
|
||||
},
|
||||
login: async (endpoint: string, username: string, password: string) => {
|
||||
await throwIfNoAzdataOrEulaNotAccepted();
|
||||
throwIfNoAzdataOrEulaNotAccepted();
|
||||
return localAzdata!.login(endpoint, username, password);
|
||||
},
|
||||
getSemVersion: () => {
|
||||
throwIfNoAzdata();
|
||||
return localAzdata!.getSemVersion();
|
||||
},
|
||||
version: async () => {
|
||||
await throwIfNoAzdataOrEulaNotAccepted();
|
||||
throwIfNoAzdata();
|
||||
return localAzdata!.version();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async function throwIfNoAzdataOrEulaNotAccepted(): Promise<void> {
|
||||
if (!localAzdata) {
|
||||
Logger.log(loc.noAzdata);
|
||||
throw new Error(loc.noAzdata);
|
||||
}
|
||||
function throwIfNoAzdataOrEulaNotAccepted(): void {
|
||||
throwIfNoAzdata();
|
||||
if (!eulaAccepted) {
|
||||
Logger.log(loc.eulaNotAccepted);
|
||||
throw new Error(loc.eulaNotAccepted);
|
||||
}
|
||||
}
|
||||
|
||||
function throwIfNoAzdata() {
|
||||
if (!localAzdata) {
|
||||
Logger.log(loc.noAzdata);
|
||||
throw new Error(loc.noAzdata);
|
||||
}
|
||||
}
|
||||
|
||||
export function deactivate(): void { }
|
||||
|
||||
@@ -23,7 +23,7 @@ export const decline = localize('azdata.decline', "Decline");
|
||||
export const doNotAskAgain = localize('azdata.doNotAskAgain', "Don't Ask Again");
|
||||
export const askLater = localize('azdata.askLater', "Ask Later");
|
||||
export const downloadingTo = (name: string, location: string): string => localize('azdata.downloadingTo', "Downloading {0} to {1}", name, location);
|
||||
export const executingCommand = (command: string, args: string[]): string => localize('azdata.executingCommand', "Executing command \"{0} {1}\"", command, args?.join(' '));
|
||||
export const executingCommand = (command: string, args: string[]): string => localize('azdata.executingCommand', "Executing command: '{0} {1}'", command, args?.join(' '));
|
||||
export const stdoutOutput = (stdout: string): string => localize('azdata.stdoutOutput', "stdout: {0}", stdout);
|
||||
export const stderrOutput = (stderr: string): string => localize('azdata.stderrOutput', "stderr: {0}", stderr);
|
||||
export const checkingLatestAzdataVersion = localize('azdata.checkingLatestAzdataVersion', "Checking for latest available version of azdata");
|
||||
@@ -56,11 +56,11 @@ export const userRequestedInstall = localize('azdata.userRequestedInstall', "Use
|
||||
export const userRequestedUpdate = localize('azdata.userRequestedUpdate', "User requested to update Azure Data CLI using 'Azure Data CLI: Check for Update' command");
|
||||
export const userRequestedAcceptEula = localize('azdata.acceptEula', "User requested to be prompted for accepting EULA by invoking 'Azure Data CLI: Accept EULA' command");
|
||||
export const updateCheckSkipped = localize('azdata.updateCheckSkipped', "No check for new Azure Data CLI version availability performed as Azure Data CLI was not found to be installed");
|
||||
export const eulaNotAccepted = localize('azdata.eulaNotAccepted', "Microsoft Privacy statement and Azure Data CLI license terms have not been accepted, [accept the EULA](command:azdata.acceptEula) to use the features that require it.");
|
||||
export const eulaNotAccepted = localize('azdata.eulaNotAccepted', "Microsoft Privacy statement and Azure Data CLI license terms have not been accepted. Execute the command: [Azure Data CLI: Accept EULA](command:azdata.acceptEula) to accept EULA to enable the features that requires Azure Data CLI.");
|
||||
export const installManually = (expectedVersion: string, instructionsUrl: string) => localize('azdata.installManually', "Azure Data CLI is not installed. Version: {0} needs to be installed or some features may not work. Please install it manually using these [instructions]({1}). Restart ADS when installation is done.", expectedVersion, instructionsUrl);
|
||||
export const installCorrectVersionManually = (currentVersion: string, expectedVersion: string, instructionsUrl: string) => localize('azdata.installCorrectVersionManually', "Azure Data CLI version: {0} is installed, version: {1} needs to be installed or some features may not work. Please uninstall the current version and then install the correct version manually using these [instructions]({2}). Restart ADS when installation is done.", currentVersion, expectedVersion, instructionsUrl);
|
||||
export const promptForEula = (privacyStatementUrl: string, eulaUrl: string) => localize('azdata.promptForEula', "It is required to accept the [Microsoft Privacy Statement]({0}) and the [Azure Data CLI license terms]({1}) to use this extension. Declining this will result in some features not working.", privacyStatementUrl, eulaUrl);
|
||||
export const promptForEulaLog = (privacyStatementUrl: string, eulaUrl: string) => promptLog(promptForEula(privacyStatementUrl, eulaUrl));
|
||||
export const userResponseToEulaPrompt = (response: string | undefined) => localize('azdata.promptForEulaResponse', "User response to Eula prompt: {0}", response);
|
||||
export const eulaAcceptedStateOnStartup = (eulaAccepted: boolean) => localize('azdata.eulaAcceptedStateOnStartup', "eulaAccepted state on startup: {0}", eulaAccepted);
|
||||
export const eulaAcceptedStateUpdated = (eulaAccepted: boolean) => localize('azdata.eulaAcceptedStateUpdated', "Updated 'eulaAccepted' state to: {0}", eulaAccepted);
|
||||
export const userResponseToEulaPrompt = (response: string | undefined) => localize('azdata.promptForEulaResponse', "User response to EULA prompt: {0}", response);
|
||||
export const eulaAcceptedStateOnStartup = (eulaAccepted: boolean) => localize('azdata.eulaAcceptedStateOnStartup', "'EULA Accepted' state on startup: {0}", eulaAccepted);
|
||||
export const eulaAcceptedStateUpdated = (eulaAccepted: boolean) => localize('azdata.eulaAcceptedStateUpdated', "Updated 'EULA Accepted' state to: {0}", eulaAccepted);
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as path from 'path';
|
||||
import { SemVer } from 'semver';
|
||||
import * as should from 'should';
|
||||
import * as sinon from 'sinon';
|
||||
import * as vscode from 'vscode';
|
||||
@@ -12,10 +11,10 @@ import * as azdata from '../azdata';
|
||||
import * as childProcess from '../common/childProcess';
|
||||
import { HttpClient } from '../common/httpClient';
|
||||
import * as utils from '../common/utils';
|
||||
import * as loc from '../localizedConstants';
|
||||
import * as constants from '../constants';
|
||||
import * as loc from '../localizedConstants';
|
||||
|
||||
const oldAzdataMock = <azdata.AzdataTool>{ path: '/path/to/azdata', cachedVersion: new SemVer('0.0.0') };
|
||||
const oldAzdataMock = new azdata.AzdataTool('/path/to/azdata', '0.0.0');
|
||||
const releaseJson = {
|
||||
win32: {
|
||||
'version': '9999.999.999',
|
||||
|
||||
14
extensions/azdata/src/typings/azdata-ext.d.ts
vendored
14
extensions/azdata/src/typings/azdata-ext.d.ts
vendored
@@ -4,6 +4,8 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
declare module 'azdata-ext' {
|
||||
import { SemVer } from 'semver';
|
||||
|
||||
/**
|
||||
* Covers defining what the azdata extension exports to other extensions
|
||||
*
|
||||
@@ -80,7 +82,7 @@ declare module 'azdata-ext' {
|
||||
location: string, // "eastus2euap",
|
||||
resourceGroup: string, // "my-rg",
|
||||
subscription: string, // "a5082b29-8c6e-4bc5-8ddd-8ef39dfebc39"
|
||||
},
|
||||
},
|
||||
controller: {
|
||||
'enableBilling': string, // "True"
|
||||
'logs.rotation.days': string, // "7"
|
||||
@@ -224,12 +226,20 @@ declare module 'azdata-ext' {
|
||||
show(name: string): Promise<AzdataOutput<SqlMiShowResult>>
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
getPath(): string,
|
||||
login(endpoint: string, username: string, password: string): Promise<AzdataOutput<any>>,
|
||||
/**
|
||||
* The semVersion corresponding to this installation of azdata. version() method should have been run
|
||||
* before fetching this value to ensure that correct value is returned. This is almost always correct unless
|
||||
* Azdata has gotten reinstalled in the background after this IAzdataApi object was constructed.
|
||||
*/
|
||||
getSemVersion(): SemVer,
|
||||
version(): Promise<AzdataOutput<string>>
|
||||
}
|
||||
|
||||
export interface IExtension {
|
||||
azdata: IAzdataApi;
|
||||
isEulaAccepted(): boolean;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user