diff --git a/extensions/sql-bindings/src/test/testUtils.ts b/extensions/sql-bindings/src/test/testUtils.ts index 4f01abce91..d85909ef43 100644 --- a/extensions/sql-bindings/src/test/testUtils.ts +++ b/extensions/sql-bindings/src/test/testUtils.ts @@ -23,11 +23,13 @@ export class MockVscodeMssqlIExtension implements vscodeMssql.IExtension { dacFx: vscodeMssql.IDacFxService; schemaCompare: vscodeMssql.ISchemaCompareService; azureAccountService: vscodeMssql.IAzureAccountService; + azureResourceService: vscodeMssql.IAzureResourceService; constructor() { this.dacFx = TypeMoq.Mock.ofType().object; this.schemaCompare = TypeMoq.Mock.ofType().object; this.azureAccountService = TypeMoq.Mock.ofType().object; + this.azureResourceService = TypeMoq.Mock.ofType().object; } promptForFirewallRule(_: string, __: vscodeMssql.IConnectionInfo): Promise { diff --git a/extensions/sql-database-projects/package.json b/extensions/sql-database-projects/package.json index 07aa943b5b..43a8d5d208 100644 --- a/extensions/sql-database-projects/package.json +++ b/extensions/sql-database-projects/package.json @@ -2,7 +2,7 @@ "name": "sql-database-projects", "displayName": "SQL Database Projects", "description": "Enables users to develop and publish database schemas for MSSQL Databases", - "version": "0.16.1", + "version": "0.16.2", "publisher": "Microsoft", "preview": true, "engines": { @@ -456,6 +456,7 @@ } }, "dependencies": { + "axios": "^0.27.2", "@microsoft/ads-extension-telemetry": "^1.1.5", "fast-glob": "^3.2.7", "fs-extra": "^5.0.0", @@ -464,7 +465,7 @@ "vscode-languageclient": "^5.3.0-next.1", "vscode-nls": "^4.1.2", "which": "^2.0.2", - "xml-formatter": "^2.1.0", + "xml-formatter": "2.1.0", "xmldom": "^0.6.0" }, "devDependencies": { diff --git a/extensions/sql-database-projects/src/common/constants.ts b/extensions/sql-database-projects/src/common/constants.ts index d7fb363715..42c841741e 100644 --- a/extensions/sql-database-projects/src/common/constants.ts +++ b/extensions/sql-database-projects/src/common/constants.ts @@ -149,9 +149,22 @@ export const nameMustNotBeEmpty = localize('nameMustNotBeEmpty', "Name must not // Deploy export const SqlServerName = 'SQL server'; export const AzureSqlServerName = 'Azure SQL server'; +export const SqlServerDockerImageName = 'Microsoft SQL Server'; +export const AzureSqlDbFullDockerImageName = 'Azure SQL Database emulator Full'; +export const AzureSqlDbLiteDockerImageName = 'Azure SQL Database emulator Lite'; +export const AzureSqlLogicalServerName = 'Azure SQL logical server'; export const selectPublishOption = localize('selectPublishOption', "Select where to publish the project to"); +export const defaultQuickPickItem = localize('defaultQuickPickItem', "Default - image defined as default in the container registry"); +export function dockerImagesPlaceHolder(name: string) { return localize('dockerImagesPlaceHolder', 'Use {0} on local arm64/Apple Silicon', name); } export function publishToExistingServer(name: string) { return localize('publishToExistingServer', "Publish to an existing {0}", name); } export function publishToDockerContainer(name: string) { return localize('publishToDockerContainer', "Publish to new {0} local development container", name); } +export const publishToAzureEmulator = localize('publishToAzureEmulator', "Publish to new Azure SQL Database emulator"); +export const publishToNewAzureServer = localize('publishToNewAzureServer', "Publish to new Azure SQL logical server"); +export const azureServerName = localize('azureServerName', "Azure SQL server name"); +export const azureSubscription = localize('azureSubscription', "Azure subscription"); +export const resourceGroup = localize('resourceGroup', "Resource group"); +export const azureLocation = localize('location', "Location"); +export const azureAccounts = localize('azureAccounts', "Azure accounts"); export function enterPortNumber(name: string) { return localize('enterPortNumber', "Enter {0} port number or press enter to use the default value", name); } export function serverPortNumber(name: string) { return localize('serverPortNumber', "{0} port number", name); } export function serverPassword(name: string) { return localize('serverPassword', "{0} admin password", name); } @@ -160,15 +173,18 @@ export function baseDockerImage(name: string) { return localize('baseDockerImage export const publishTo = localize('publishTo', "Publish Target"); export const enterConnectionStringEnvName = localize('enterConnectionStringEnvName', "Enter connection string environment variable name"); export const enterConnectionStringTemplate = localize('enterConnectionStringTemplate', "Enter connection string template"); +export function enterUser(name: string) { return localize('enterUser', "Enter {0} admin user name", name); } export function enterPassword(name: string) { return localize('enterPassword', "Enter {0} admin password", name); } export function confirmPassword(name: string) { return localize('confirmPassword', "Confirm {0} admin password", name); } export function selectBaseImage(name: string) { return localize('selectBaseImage', "Select the base {0} docker image", name); } +export function selectImageTag(name: string) { return localize('selectImageTag', "Select the image tag or press enter to use the default value", name); } export function invalidSQLPasswordMessage(name: string) { return localize('invalidSQLPassword', "{0} password doesn't meet the password complexity requirement. For more information see https://docs.microsoft.com/sql/relational-databases/security/password-policy", name); } export function passwordNotMatch(name: string) { return localize('passwordNotMatch', "{0} password doesn't match the confirmation password", name); } export const portMustBeNumber = localize('portMustNotBeNumber', "Port must a be number"); export const valueCannotBeEmpty = localize('valueCannotBeEmpty', "Value cannot be empty"); export const dockerImageLabelPrefix = 'source=sqldbproject'; export const dockerImageNamePrefix = 'sqldbproject'; +export const dockerImageDefaultTag = 'latest'; // Publish to Container export const eulaAgreementTemplate = localize({ key: 'eulaAgreementTemplate', comment: ['The placeholders are contents of the line and should not be translated.'] }, "I accept the {0}."); @@ -205,12 +221,16 @@ export const runningDockerMessage = localize('runningDockerMessage', "Running th export function dockerNotRunningError(error: string) { return localize('dockerNotRunningError', "Failed to verify docker. Please make sure docker is installed and running. Error: '{0}'", error || ''); } export const dockerContainerNotRunningErrorMessage = localize('dockerContainerNotRunningErrorMessage', "Docker container is not running"); export const dockerContainerFailedToRunErrorMessage = localize('dockerContainerFailedToRunErrorMessage', "Failed to run the docker container"); -export const connectingToSqlServerMessage = localize('connectingToSqlServerOnDockerMessage', "Connecting to SQL Server"); +export const connectingToSqlServerMessage = localize('connectingToSqlServerMessage', "Connecting to SQL Server"); +export const serverCreated = localize('serverCreated', "Server created"); export const deployProjectFailedMessage = localize('deployProjectFailedMessage', "Failed to open a connection to the deployed database'"); export const containerAlreadyExistForProject = localize('containerAlreadyExistForProject', "Containers already exist for this project. Do you want to delete them before deploying a new one?"); export const checkoutOutputMessage = localize('checkoutOutputMessage', "Check output pane for more details"); +export function creatingAzureSqlServer(name: string): string { return localize('creatingAzureSqlServer', "Creating Azure SQL Server '{0}' ...", name); } +export function azureSqlServerCreated(name: string): string { return localize('azureSqlServerCreated', "Azure SQL Server '{0}' created", name); } export function taskFailedError(taskName: string, err: string): string { return localize('taskFailedError.error', "Failed to complete task '{0}'. Error: {1}", taskName, err); } export function publishToContainerFailed(errorMessage: string) { return localize('publishToContainerFailed', "Failed to publish to container. {0}", errorMessage); } +export function publishToNewAzureServerFailed(errorMessage: string) { return localize('publishToNewAzureServerFailed', "Failed to publish to new Azure SQL server. {0}", errorMessage); } export function deployAppSettingUpdateFailed(appSetting: string) { return localize('deployAppSettingUpdateFailed', "Failed to update app setting '{0}'", appSetting); } export function deployAppSettingUpdating(appSetting: string) { return localize('deployAppSettingUpdating', "Updating app setting: '{0}'", appSetting); } export function connectionFailedError(error: string) { return localize('connectionFailedError', "Connection failed error: '{0}'", error); } @@ -220,7 +240,7 @@ export function retryWaitMessage(numberOfSeconds: number, name: string) { return export function retryRunMessage(attemptNumber: number, numberOfAttempts: number, name: string) { return localize('retryRunMessage', "Running operation '{2}' Attempt {0} of {1}", attemptNumber, numberOfAttempts, name); } export function retrySucceedMessage(name: string, result: string) { return localize('retrySucceedMessage', "Operation '{0}' completed successfully. Result: {1}", name, result); } export function retryFailedMessage(name: string, result: string, error: string) { return localize('retryFailedMessage', "Operation '{0}' failed. Re-trying... Current Result: {1}. Error: '{2}'", name, result, error); } -export function retryMessage(name: string, error: string) { return localize('retryMessage', "Operation '{0}' failed. Re-trying... Error: '{1}'", name, error || ''); } +export function retryMessage(name: string, error: string) { return localize('retryMessage', "Operation '{0}' failed. Re-trying... Error: '{1}' ", name, error); } // Add Database Reference dialog strings @@ -269,6 +289,8 @@ export const WorkspaceFileExtension = '.code-workspace'; export const browseEllipsisWithIcon = `$(folder) ${localize('browseEllipsis', "Browse...")}`; export const selectProjectLocation = localize('selectProjectLocation', "Select project location"); export const sdkStyleProject = localize('sdkStyleProject', 'SDK-style project (Preview)'); +export const YesRecommended = localize('yesRecommended', "Yes (Recommended)"); +export const SdkLearnMorePlaceholder = localize('sdkLearnMorePlaceholder', "Click \"Learn More\" button for more information about SDK-style projects"); export const ProjectParentDirectoryNotExistError = (location: string): string => { return localize('dataworkspace.projectParentDirectoryNotExistError', "The selected project location '{0}' does not exist or is not a directory.", location); }; export const ProjectDirectoryAlreadyExistError = (projectName: string, location: string): string => { return localize('dataworkspace.projectDirectoryAlreadyExistError', "There is already a directory named '{0}' in the selected location: '{1}'.", projectName, location); }; @@ -480,6 +502,8 @@ export const integratedAuth = 'Integrated'; export const azureMfaAuth = 'AzureMFA'; export const sqlAuth = 'SqlAuth'; +export const azureAddAccount = localize('azureAddAccount', "Add an Account..."); + // Tree item types export enum DatabaseProjectItemType { project = 'databaseProject.itemType.project', @@ -548,4 +572,5 @@ export function getTargetPlatformFromVersion(version: string): string { export enum PublishTargetType { existingServer = 'existingServer', docker = 'docker', + newAzureServer = 'newAzureServer' } diff --git a/extensions/sql-database-projects/src/common/httpClient.ts b/extensions/sql-database-projects/src/common/httpClient.ts new file mode 100644 index 0000000000..af688a7efe --- /dev/null +++ b/extensions/sql-database-projects/src/common/httpClient.ts @@ -0,0 +1,51 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as os from 'os'; +import axios, { AxiosRequestConfig } from 'axios'; + +/** + * Class includes method for making http request + */ +export class HttpClient { + private static cache: Map = new Map(); + + /** + * Makes http GET request to the given url. If useCache is set to true, returns the result from cache if exists + * @param url url to make http GET request against + * @param useCache if true and result is already cached the cached value will be returned + * @returns result of http GET request + */ + public static async getRequest(url: string, useCache = false): Promise { + + if (useCache) { + if (HttpClient.cache.has(url)) { + return HttpClient.cache.get(url); + } + } + + const config: AxiosRequestConfig = { + headers: { + 'Content-Type': 'application/json' + }, + validateStatus: () => true // Never throw + }; + const response = await axios.get(url, config); + if (response.status !== 200) { + let errorMessage: string[] = []; + errorMessage.push(response.status.toString()); + errorMessage.push(response.statusText); + if (response.data?.error) { + errorMessage.push(`${response.data?.error?.code} : ${response.data?.error?.message}`); + } + throw new Error(errorMessage.join(os.EOL)); + } + + if (useCache) { + HttpClient.cache.set(url, response.data); + } + return response.data; + } +} diff --git a/extensions/sql-database-projects/src/common/telemetry.ts b/extensions/sql-database-projects/src/common/telemetry.ts index 1fcb1af595..dce8ca152f 100644 --- a/extensions/sql-database-projects/src/common/telemetry.ts +++ b/extensions/sql-database-projects/src/common/telemetry.ts @@ -38,5 +38,7 @@ export enum TelemetryActions { finishAddSqlBinding = 'finishAddSqlBinding', createProjectFromDatabase = 'createProjectFromDatabase', updateProjectFromDatabase = 'updateProjectFromDatabase', - publishToContainer = 'publishToContainer' + publishToContainer = 'publishToContainer', + publishToNewAzureServer = 'publishToNewAzureServer', + generateProjectFromOpenApiSpec = 'generateProjectFromOpenApiSpec' } diff --git a/extensions/sql-database-projects/src/common/utils.ts b/extensions/sql-database-projects/src/common/utils.ts index ebcdae481e..9bd9936f58 100644 --- a/extensions/sql-database-projects/src/common/utils.ts +++ b/extensions/sql-database-projects/src/common/utils.ts @@ -307,6 +307,18 @@ export async function getVscodeMssqlApi(): Promise { return ext.activate(); } +export type AzureResourceServiceFactory = () => Promise; +export async function defaultAzureResourceServiceFactory(): Promise { + const vscodeMssqlApi = await getVscodeMssqlApi(); + return vscodeMssqlApi.azureResourceService; +} + +export type AzureAccountServiceFactory = () => Promise; +export async function defaultAzureAccountServiceFactory(): Promise { + const vscodeMssqlApi = await getVscodeMssqlApi(); + return vscodeMssqlApi.azureAccountService; +} + /* * Returns the default deployment options from DacFx, filtered to appropriate options for the given project. */ @@ -441,7 +453,7 @@ export async function retry( } } catch (err) { - outputChannel.appendLine(constants.retryMessage(name, err)); + outputChannel.appendLine(constants.retryMessage(name, getErrorMessage(err))); } } @@ -599,3 +611,47 @@ export function getFoldersAlongPath(startFolder: string, endFolder: string): str return folders; } + +/** + * Returns SQL version number from docker image name which is in the beginning of the image name + * @param imageName docker image name + * @returns SQL server version + */ +export function findSqlVersionInImageName(imageName: string): number | undefined { + + // Regex to find the version in the beginning of the image name + // e.g. 2017-CU16-ubuntu, 2019-latest + const regex = new RegExp('^([0-9]+)[-].+$'); + + if (regex.test(imageName)) { + const finds = regex.exec(imageName); + if (finds) { + + // 0 is the full match and 1 is the number with pattern inside the first () + return +finds[1]; + } + } + return undefined; +} + +/** + * Returns SQL version number from target platform name + * @param targetPlatform target platform + * @returns SQL server version + */ +export function findSqlVersionInTargetPlatform(targetPlatform: string): number | undefined { + + // Regex to find the version in target platform + // e.g. SQL Server 2019 + const regex = new RegExp('([0-9]+)$'); + + if (regex.test(targetPlatform)) { + const finds = regex.exec(targetPlatform); + if (finds) { + + // 0 is the full match and 1 is the number with pattern inside the first () + return +finds[1]; + } + } + return undefined; +} diff --git a/extensions/sql-database-projects/src/controllers/projectController.ts b/extensions/sql-database-projects/src/controllers/projectController.ts index 7e0658890d..6f62597416 100644 --- a/extensions/sql-database-projects/src/controllers/projectController.ts +++ b/extensions/sql-database-projects/src/controllers/projectController.ts @@ -38,16 +38,17 @@ import { TelemetryActions, TelemetryReporter, TelemetryViews } from '../common/t import { IconPathHelper } from '../common/iconHelper'; import { DashboardData, PublishData, Status } from '../models/dashboardData/dashboardData'; import { getPublishDatabaseSettings, launchPublishTargetOption } from '../dialogs/publishDatabaseQuickpick'; -import { launchPublishToDockerContainerQuickpick } from '../dialogs/deployDatabaseQuickpick'; +import { launchCreateAzureServerQuickPick, launchPublishToDockerContainerQuickpick } from '../dialogs/deployDatabaseQuickpick'; import { DeployService } from '../models/deploy/deployService'; import { GenerateProjectFromOpenApiSpecOptions, SqlTargetPlatform } from 'sqldbproj'; import { AutorestHelper } from '../tools/autorestHelper'; import { createNewProjectFromDatabaseWithQuickpick } from '../dialogs/createProjectFromDatabaseQuickpick'; import { addDatabaseReferenceQuickpick } from '../dialogs/addDatabaseReferenceQuickpick'; -import { IDeployProfile } from '../models/deploy/deployProfile'; +import { ILocalDbDeployProfile, ISqlDbDeployProfile } from '../models/deploy/deployProfile'; import { EntryType, FileProjectEntry, IDatabaseReferenceProjectEntry, SqlProjectReferenceProjectEntry } from '../models/projectEntry'; import { UpdateProjectAction, UpdateProjectDataModel } from '../models/api/updateProject'; import { targetPlatformToAssets } from '../projectProvider/projectAssets'; +import { AzureSqlClient } from '../models/deploy/azureSqlClient'; const maxTableLength = 10; @@ -75,6 +76,7 @@ export class ProjectsController { private buildInfo: DashboardData[] = []; private publishInfo: PublishData[] = []; private deployService: DeployService; + private azureSqlClient: AzureSqlClient; private autorestHelper: AutorestHelper; projFileWatchers = new Map(); @@ -82,7 +84,8 @@ export class ProjectsController { constructor(private _outputChannel: vscode.OutputChannel) { this.netCoreTool = new NetCoreTool(this._outputChannel); this.buildHelper = new BuildHelper(); - this.deployService = new DeployService(this._outputChannel); + this.azureSqlClient = new AzureSqlClient(); + this.deployService = new DeployService(this.azureSqlClient, this._outputChannel); this.autorestHelper = new AutorestHelper(this._outputChannel); } @@ -285,21 +288,58 @@ export class ProjectsController { } } + /** + * Publishes a project to a new Azure server + * @param context a treeItem in a project's hierarchy, to be used to obtain a Project or the Project itself + * @param deployProfile deploy profile + */ + public async publishToNewAzureServer(context: Project | dataworkspace.WorkspaceTreeItem, deployProfile: ISqlDbDeployProfile): Promise { + try { + TelemetryReporter.sendActionEvent(TelemetryViews.ProjectController, TelemetryActions.publishToNewAzureServer); + const project: Project = this.getProjectFromContext(context); + if (deployProfile?.deploySettings && deployProfile?.sqlDbSetting) { + void utils.showInfoMessageWithOutputChannel(constants.creatingAzureSqlServer(deployProfile?.sqlDbSetting?.serverName), this._outputChannel); + const connectionUri = await this.deployService.createNewAzureSqlServer(deployProfile); + if (connectionUri) { + deployProfile.deploySettings.connectionUri = connectionUri; + const publishResult = await this.publishOrScriptProject(project, deployProfile.deploySettings, true); + if (publishResult && publishResult.success) { + if (deployProfile.sqlDbSetting) { + + // Connecting to the deployed db to add the profile to connection viewlet + await this.deployService.getConnection(deployProfile.sqlDbSetting, true, deployProfile.sqlDbSetting.dbName); + } + void vscode.window.showInformationMessage(constants.publishProjectSucceed); + } else { + void utils.showErrorMessageWithOutputChannel(constants.publishToNewAzureServerFailed, publishResult?.errorMessage || '', this._outputChannel); + } + } else { + void utils.showErrorMessageWithOutputChannel(constants.publishToNewAzureServerFailed, constants.deployProjectFailedMessage, this._outputChannel); + } + } + } catch (error) { + void utils.showErrorMessageWithOutputChannel(constants.publishToNewAzureServerFailed, error, this._outputChannel); + TelemetryReporter.sendErrorEvent(TelemetryViews.ProjectController, TelemetryActions.publishToNewAzureServer); + } + } + /** * Publishes a project to docker container * @param context a treeItem in a project's hierarchy, to be used to obtain a Project or the Project itself * @param deployProfile */ - public async publishToDockerContainer(context: Project | dataworkspace.WorkspaceTreeItem, deployProfile: IDeployProfile): Promise { + public async publishToDockerContainer(context: Project | dataworkspace.WorkspaceTreeItem, deployProfile: ILocalDbDeployProfile): Promise { const project: Project = this.getProjectFromContext(context); try { - TelemetryReporter.sendActionEvent(TelemetryViews.ProjectController, TelemetryActions.publishToContainer); + TelemetryReporter.createActionEvent(TelemetryViews.ProjectController, TelemetryActions.publishToContainer) + .withAdditionalProperties({ dockerBaseImage: deployProfile.localDbSetting!.dockerBaseImage }) + .send(); if (deployProfile && deployProfile.deploySettings) { let connectionUri: string | undefined; if (deployProfile.localDbSetting) { void utils.showInfoMessageWithOutputChannel(constants.publishingProjectMessage, this._outputChannel); - connectionUri = await this.deployService.deploy(deployProfile, project); + connectionUri = await this.deployService.deployToContainer(deployProfile, project); if (connectionUri) { deployProfile.deploySettings.connectionUri = connectionUri; } @@ -321,7 +361,9 @@ export class ProjectsController { } } catch (error) { void utils.showErrorMessageWithOutputChannel(constants.publishToContainerFailed, error, this._outputChannel); - TelemetryReporter.sendErrorEvent(TelemetryViews.ProjectController, TelemetryActions.publishToContainer); + TelemetryReporter.createErrorEvent(TelemetryViews.ProjectController, TelemetryActions.publishToContainer) + .withAdditionalProperties({ dockerBaseImage: deployProfile.localDbSetting!.dockerBaseImage }) + .send(); } return; } @@ -367,9 +409,19 @@ export class ProjectsController { if (publishTarget === constants.PublishTargetType.docker) { const deployProfile = await launchPublishToDockerContainerQuickpick(project); - if (deployProfile?.deploySettings) { + if (deployProfile?.deploySettings && deployProfile?.localDbSetting) { await this.publishToDockerContainer(project, deployProfile); } + } else if (publishTarget === constants.PublishTargetType.newAzureServer) { + try { + const settings = await launchCreateAzureServerQuickPick(project, this.azureSqlClient); + if (settings?.deploySettings && settings?.sqlDbSetting) { + await this.publishToNewAzureServer(project, settings); + } + } catch (error) { + void utils.showErrorMessageWithOutputChannel(constants.publishToNewAzureServerFailed, error, this._outputChannel); + } + } else { let settings: IDeploySettings | undefined = await getPublishDatabaseSettings(project); diff --git a/extensions/sql-database-projects/src/dialogs/createProjectFromDatabaseQuickpick.ts b/extensions/sql-database-projects/src/dialogs/createProjectFromDatabaseQuickpick.ts index 66ca21d7db..120691f651 100644 --- a/extensions/sql-database-projects/src/dialogs/createProjectFromDatabaseQuickpick.ts +++ b/extensions/sql-database-projects/src/dialogs/createProjectFromDatabaseQuickpick.ts @@ -133,6 +133,48 @@ export async function createNewProjectFromDatabaseWithQuickpick(connectionInfo?: return undefined; } + // 5. SDK-style project or not + let sdkStyle; + const sdkLearnMoreButton: vscode.QuickInputButton = { + iconPath: new vscode.ThemeIcon('link-external'), + tooltip: constants.learnMore + }; + const quickPick = vscode.window.createQuickPick(); + quickPick.items = [{ label: constants.YesRecommended }, { label: constants.noString }]; + quickPick.title = constants.sdkStyleProject; + quickPick.ignoreFocusOut = true; + const disposables: vscode.Disposable[] = []; + + try { + quickPick.buttons = [sdkLearnMoreButton]; + quickPick.placeholder = constants.SdkLearnMorePlaceholder; + + const sdkStylePromise = new Promise((resolve) => { + disposables.push( + quickPick.onDidHide(() => { + resolve(undefined); + }), + quickPick.onDidChangeSelection((item) => { + resolve(item[0].label === constants.YesRecommended); + })); + + disposables.push(quickPick.onDidTriggerButton(async () => { + await vscode.env.openExternal(vscode.Uri.parse(constants.sdkLearnMoreUrl!)); + })); + }); + + quickPick.show(); + sdkStyle = await sdkStylePromise; + quickPick.hide(); + } finally { + disposables.forEach(d => d.dispose()); + } + + if (sdkStyle === undefined) { + // User cancelled + return; + } + return { connectionUri: connectionUri, database: selectedDatabase, @@ -140,6 +182,6 @@ export async function createNewProjectFromDatabaseWithQuickpick(connectionInfo?: filePath: projectLocation, version: '1.0.0.0', extractTarget: mapExtractTargetEnum(folderStructure), - sdkStyle: false // todo: add sdkstyle option to quickpick + sdkStyle: sdkStyle }; } diff --git a/extensions/sql-database-projects/src/dialogs/deployDatabaseQuickpick.ts b/extensions/sql-database-projects/src/dialogs/deployDatabaseQuickpick.ts index b19586d1b5..417899263e 100644 --- a/extensions/sql-database-projects/src/dialogs/deployDatabaseQuickpick.ts +++ b/extensions/sql-database-projects/src/dialogs/deployDatabaseQuickpick.ts @@ -7,11 +7,14 @@ import * as vscode from 'vscode'; import * as constants from '../common/constants'; import * as utils from '../common/utils'; import * as uiUtils from './utils'; -import { AppSettingType, DockerImageInfo, IDeployAppIntegrationProfile, IDeployProfile, ILocalDbSetting } from '../models/deploy/deployProfile'; +import { AppSettingType, DockerImageInfo, IDeployAppIntegrationProfile, ISqlDbDeployProfile, ILocalDbDeployProfile, ILocalDbSetting } from '../models/deploy/deployProfile'; import { Project } from '../models/project'; import { getPublishDatabaseSettings } from './publishDatabaseQuickpick'; import * as path from 'path'; import * as fse from 'fs-extra'; +import { AzureSqlClient } from '../models/deploy/azureSqlClient'; +import { IDeploySettings } from '../models/IDeploySettings'; +import { IAccount } from 'vscode-mssql'; /** * Create flow for Deploying a database using only VS Code-native APIs such as QuickPick @@ -112,12 +115,168 @@ async function launchEulaQuickPick(imageInfo: DockerImageInfo | undefined): Prom return false; } +export async function launchCreateAzureServerQuickPick(project: Project, azureSqlClient: AzureSqlClient): Promise { + + const name = uiUtils.getPublishServerName(project.getProjectTargetVersion()); + const accounts = await azureSqlClient.getAccounts(); + const accountOptions = accounts.map(x => x.displayInfo?.displayName || ''); + accountOptions.unshift(constants.azureAddAccount); + + let account: IAccount | undefined; + let accountOption = await vscode.window.showQuickPick( + accountOptions, + { title: constants.azureAccounts, ignoreFocusOut: true }); + + // Return when user hits escape + if (!accountOption) { + return undefined; + } + + if (accountOption === constants.azureAddAccount) { + account = await azureSqlClient.getAccount(); + } else { + account = accounts.find(x => x.displayInfo.displayName === accountOption); + } + + if (!account) { + return undefined; + } + + const sessions = await azureSqlClient.getSessions(account); + + const subscriptionName = await vscode.window.showQuickPick( + sessions.map(x => x.subscription.displayName || ''), + { title: constants.azureSubscription, ignoreFocusOut: true }); + + // Return when user hits escape + if (!subscriptionName) { + return undefined; + } + + const session = sessions.find(x => x.subscription.displayName === subscriptionName); + + if (!session?.subscription?.subscriptionId) { + return undefined; + } + + const resourceGroups = await azureSqlClient.getResourceGroups(session); + const resourceGroupName = await vscode.window.showQuickPick( + resourceGroups.map(x => x.name || ''), + { title: constants.resourceGroup, ignoreFocusOut: true }); + + // Return when user hits escape + if (!resourceGroupName) { + return undefined; + } + + const resourceGroup = resourceGroups.find(x => x.name === resourceGroupName); + + // Return resource group is invalid + if (!resourceGroup) { + return undefined; + } + + let locations = await azureSqlClient.getLocations(session); + if (resourceGroup.location) { + const defaultLocation = locations.find(x => x.name === resourceGroup.location); + if (defaultLocation) { + locations = locations.filter(x => x.name !== defaultLocation.name); + locations.unshift(defaultLocation); + } + } + + let locationName = await vscode.window.showQuickPick( + locations.map(x => x.name || ''), + { title: constants.azureLocation, ignoreFocusOut: true, placeHolder: resourceGroup?.location }); + + // Return when user hits escape + if (!locationName) { + return undefined; + } + + let serverName: string | undefined = ''; + serverName = await vscode.window.showInputBox({ + title: constants.azureServerName, + ignoreFocusOut: true, + value: serverName, + password: false + } + ); + + // Return when user hits escape + if (!serverName) { + return undefined; + } + + let user: string | undefined = ''; + user = await vscode.window.showInputBox({ + title: constants.enterUser(name), + ignoreFocusOut: true, + value: user, + password: false + } + ); + + // Return when user hits escape + if (!user) { + return undefined; + } + + let password: string | undefined = ''; + password = await vscode.window.showInputBox({ + title: constants.enterPassword(name), + ignoreFocusOut: true, + value: password, + validateInput: input => !utils.isValidSQLPassword(input) ? constants.invalidSQLPasswordMessage(name) : undefined, + password: true + } + ); + + // Return when user hits escape + if (!password) { + return undefined; + } + + let confirmPassword: string | undefined = ''; + confirmPassword = await vscode.window.showInputBox({ + title: constants.confirmPassword(name), + ignoreFocusOut: true, + value: confirmPassword, + validateInput: input => input !== password ? constants.passwordNotMatch(name) : undefined, + password: true + } + ); + + // Return when user hits escape + if (!confirmPassword) { + return undefined; + } + + let settings: IDeploySettings | undefined = await getPublishDatabaseSettings(project, false); + + return { + // TODO add tenant + deploySettings: settings, sqlDbSetting: { + tenantId: session.tenantId, + accountId: session.account.key.id, + serverName: serverName, + userName: user, + password: password, + port: 1433, + dbName: '', + session: session, + resourceGroupName: resourceGroup.name || '', + location: locationName + } + }; +} + /** * Create flow for publishing a database to docker container using only VS Code-native APIs such as QuickPick */ -export async function launchPublishToDockerContainerQuickpick(project: Project): Promise { - - const name = uiUtils.getPublishServerName(project.getProjectTargetVersion()); +export async function launchPublishToDockerContainerQuickpick(project: Project): Promise { + const target = project.getProjectTargetVersion(); + const name = uiUtils.getPublishServerName(target); let localDbSetting: ILocalDbSetting | undefined; // Deploy to docker selected let portNumber = await vscode.window.showInputBox({ @@ -163,10 +322,10 @@ export async function launchPublishToDockerContainerQuickpick(project: Project): return undefined; } - const baseImages = uiUtils.getDockerBaseImages(project.getProjectTargetVersion()); + const baseImages = uiUtils.getDockerBaseImages(target); const baseImage = await vscode.window.showQuickPick( baseImages.map(x => x.displayName), - { title: constants.selectBaseImage(name), ignoreFocusOut: true }); + { title: constants.selectBaseImage(name), ignoreFocusOut: true, placeHolder: uiUtils.getDockerImagePlaceHolder(target) }); // Return when user hits escape if (!baseImage) { @@ -174,19 +333,50 @@ export async function launchPublishToDockerContainerQuickpick(project: Project): } const imageInfo = baseImages.find(x => x.displayName === baseImage); + + if (!imageInfo) { + return undefined; + } + const eulaAccepted = await launchEulaQuickPick(imageInfo); if (!eulaAccepted) { return undefined; } + let imageTags = await uiUtils.getImageTags(imageInfo, target); + let imageTagsItems: vscode.QuickPickItem[] = imageTags.map(tag => { return { label: tag }; }); + + if (imageInfo.defaultTag) { + // move the default to be the first one in the list + const defaultIndex = imageTagsItems.findIndex(i => i.label === imageInfo.defaultTag); + if (defaultIndex > -1) { + imageTagsItems.splice(defaultIndex, 1); + } + // add default next to the default value + imageTagsItems.unshift({ label: imageInfo.defaultTag, description: constants.defaultQuickPickItem }); + } + const imageTag = await vscode.window.showQuickPick( + imageTagsItems, + { title: constants.selectImageTag(name), ignoreFocusOut: true }); + + if (!imageTag) { + return undefined; + } + + // Add the image tag if it's not the latest + let imageName = imageInfo.name; + if (imageTag && imageTag.label !== constants.dockerImageDefaultTag) { + imageName = `${imageName}:${imageTag.label}`; + } + localDbSetting = { serverName: constants.defaultLocalServerName, userName: constants.defaultLocalServerAdminName, dbName: project.projectFileName, password: password, port: +portNumber, - dockerBaseImage: imageInfo?.name || '', - dockerBaseImageEula: imageInfo?.agreementInfo?.link?.url || '' + dockerBaseImage: imageName, + dockerBaseImageEula: imageInfo.agreementInfo.link.url }; let deploySettings = await getPublishDatabaseSettings(project, false); @@ -202,7 +392,6 @@ export async function launchPublishToDockerContainerQuickpick(project: Project): // Get the database name from deploy settings localDbSetting.dbName = deploySettings.databaseName; - return { localDbSetting: localDbSetting, deploySettings: deploySettings, diff --git a/extensions/sql-database-projects/src/dialogs/publishDatabaseDialog.ts b/extensions/sql-database-projects/src/dialogs/publishDatabaseDialog.ts index 348abd17e2..9e81f65235 100644 --- a/extensions/sql-database-projects/src/dialogs/publishDatabaseDialog.ts +++ b/extensions/sql-database-projects/src/dialogs/publishDatabaseDialog.ts @@ -16,7 +16,7 @@ import { IconPathHelper } from '../common/iconHelper'; import { cssStyles } from '../common/uiConstants'; import { getAgreementDisplayText, getConnectionName, getDockerBaseImages, getPublishServerName } from './utils'; import { TelemetryActions, TelemetryReporter, TelemetryViews } from '../common/telemetry'; -import { IDeployProfile } from '../models/deploy/deployProfile'; +import { ILocalDbDeployProfile } from '../models/deploy/deployProfile'; import { Deferred } from '../common/promise'; interface DataSourceDropdownValue extends azdataType.CategoryValue { @@ -62,7 +62,7 @@ export class PublishDatabaseDialog { private toDispose: vscode.Disposable[] = []; public publish: ((proj: Project, profile: IDeploySettings) => any) | undefined; - public publishToContainer: ((proj: Project, profile: IDeployProfile) => any) | undefined; + public publishToContainer: ((proj: Project, profile: ILocalDbDeployProfile) => any) | undefined; public generateScript: ((proj: Project, profile: IDeploySettings) => any) | undefined; public readPublishProfile: ((profileUri: vscode.Uri) => any) | undefined; @@ -232,7 +232,7 @@ export class PublishDatabaseDialog { const dockerBaseImage = this.getBaseDockerImageName(); const baseImages = getDockerBaseImages(this.project.getProjectTargetVersion()); const imageInfo = baseImages.find(x => x.name === dockerBaseImage); - const settings: IDeployProfile = { + const settings: ILocalDbDeployProfile = { localDbSetting: { dbName: this.targetDatabaseName, dockerBaseImage: dockerBaseImage, diff --git a/extensions/sql-database-projects/src/dialogs/publishDatabaseQuickpick.ts b/extensions/sql-database-projects/src/dialogs/publishDatabaseQuickpick.ts index 7876944fee..40bb456245 100644 --- a/extensions/sql-database-projects/src/dialogs/publishDatabaseQuickpick.ts +++ b/extensions/sql-database-projects/src/dialogs/publishDatabaseQuickpick.ts @@ -12,6 +12,7 @@ import { getDefaultPublishDeploymentOptions, getVscodeMssqlApi } from '../common import { IConnectionInfo } from 'vscode-mssql'; import { IDeploySettings } from '../models/IDeploySettings'; import { getPublishServerName } from './utils'; +import { SqlTargetPlatform } from 'sqldbproj'; /** * Create flow for Publishing a database using only VS Code-native APIs such as QuickPick @@ -209,9 +210,18 @@ export async function getPublishDatabaseSettings(project: Project, promptForConn export async function launchPublishTargetOption(project: Project): Promise { // Show options to user for deploy to existing server or docker - const name = getPublishServerName(project.getProjectTargetVersion()); + const target = project.getProjectTargetVersion(); + const name = getPublishServerName(target); + const logicalServerName = target === constants.targetPlatformToVersion.get(SqlTargetPlatform.sqlAzure) ? constants.AzureSqlLogicalServerName : constants.SqlServerName; + + // Options list based on target + const options = target === constants.targetPlatformToVersion.get(SqlTargetPlatform.sqlAzure) ? + [constants.publishToAzureEmulator, constants.publishToNewAzureServer, constants.publishToExistingServer(logicalServerName)] : + [constants.publishToDockerContainer(name), constants.publishToExistingServer(logicalServerName)]; + + // Show the options to the user const publishOption = await vscode.window.showQuickPick( - [constants.publishToExistingServer(name), constants.publishToDockerContainer(name)], + options, { title: constants.selectPublishOption, ignoreFocusOut: true }); // Return when user hits escape @@ -219,11 +229,16 @@ export async function launchPublishTargetOption(project: Project): Promise { + let imageTags: string[] | undefined = []; + const versionToImageTags: Map = new Map(); + + try { + const imageTagsFromUrl = await HttpClient.getRequest(imageInfo?.tagsUrl, true); + if (imageTagsFromUrl?.tags) { + + // Create a map for version and tags and find the max version in the list + let defaultVersion: number = 0; + let maxVersionNumber: number = defaultVersion; + (imageTagsFromUrl.tags as string[]).forEach(imageTag => { + const version = utils.findSqlVersionInImageName(imageTag) || defaultVersion; + let tags = versionToImageTags.has(version) ? versionToImageTags.get(version) : []; + tags = tags ?? []; + tags = tags?.concat(imageTag); + versionToImageTags.set(version, tags); + maxVersionNumber = version && version > maxVersionNumber ? version : maxVersionNumber; + }); + + // Find the version maps to the target framework and default to max version in the tags + const targetVersion = utils.findSqlVersionInTargetPlatform(constants.getTargetPlatformFromVersion(target)) || maxVersionNumber; + + // Get the image tags with no version of the one that matches project platform + versionToImageTags.forEach((tags: string[], version: number) => { + if (version === defaultVersion || version >= targetVersion) { + imageTags = imageTags?.concat(tags); + } + }); + + imageTags = imageTags ?? []; + imageTags = imageTags.sort((a, b) => a.indexOf(constants.dockerImageDefaultTag) > 0 ? -1 : a.localeCompare(b)); + } + } catch (err) { + // Ignore the error. If http request fails, we just use the default tag + console.debug(`Failed to get docker image tags ${err}`); + } + + return imageTags; +} + +/** + * Returns the list of base images for given target version + * @param target + * @returns list of image info + */ export function getDockerBaseImages(target: string): DockerImageInfo[] { if (target === constants.targetPlatformToVersion.get(SqlTargetPlatform.sqlAzure)) { return [{ - name: `${constants.sqlServerDockerRegistry}/${constants.sqlServerDockerRepository}:2019-latest`, - displayName: SqlTargetPlatform.sqlServer2019, + name: `${constants.sqlServerDockerRegistry}/${constants.sqlServerDockerRepository}`, + displayName: constants.AzureSqlDbFullDockerImageName, agreementInfo: { link: { text: constants.eulaAgreementTitle, url: constants.sqlServerEulaLink, } - } + }, + tagsUrl: `https://${constants.sqlServerDockerRegistry}/v2/${constants.sqlServerDockerRepository}/tags/list`, + defaultTag: constants.dockerImageDefaultTag }, { - name: `${constants.sqlServerDockerRegistry}/${constants.azureSqlEdgeDockerRepository}:latest`, - displayName: SqlTargetPlatform.sqlEdge, + name: `${constants.sqlServerDockerRegistry}/${constants.azureSqlEdgeDockerRepository}`, + displayName: constants.AzureSqlDbLiteDockerImageName, agreementInfo: { link: { text: constants.edgeEulaAgreementTitle, url: constants.sqlServerEdgeEulaLink, } - } + }, + tagsUrl: `https://${constants.sqlServerDockerRegistry}/v2/${constants.azureSqlEdgeDockerRepository}/tags/list`, + defaultTag: constants.dockerImageDefaultTag }]; } else { return [ { - name: `${constants.sqlServerDockerRegistry}/${constants.sqlServerDockerRepository}:2017-latest`, - displayName: SqlTargetPlatform.sqlServer2017, + name: `${constants.sqlServerDockerRegistry}/${constants.sqlServerDockerRepository}`, + displayName: constants.SqlServerDockerImageName, agreementInfo: { link: { text: constants.eulaAgreementTitle, url: constants.sqlServerEulaLink, } - } + }, + tagsUrl: `https://${constants.sqlServerDockerRegistry}/v2/${constants.sqlServerDockerRepository}/tags/list`, + defaultTag: constants.dockerImageDefaultTag }, { - name: `${constants.sqlServerDockerRegistry}/${constants.sqlServerDockerRepository}:2019-latest`, - displayName: SqlTargetPlatform.sqlServer2019, - agreementInfo: { - link: { - text: constants.eulaAgreementTitle, - url: constants.sqlServerEulaLink, - } - } - }, - { - name: `${constants.sqlServerDockerRegistry}/${constants.azureSqlEdgeDockerRepository}:latest`, + name: `${constants.sqlServerDockerRegistry}/${constants.azureSqlEdgeDockerRepository}`, displayName: SqlTargetPlatform.sqlEdge, agreementInfo: { link: { text: constants.edgeEulaAgreementTitle, url: constants.sqlServerEdgeEulaLink, } - } + }, + tagsUrl: `https://${constants.sqlServerDockerRegistry}/v2/${constants.azureSqlEdgeDockerRepository}/tags/list`, + defaultTag: constants.dockerImageDefaultTag }, ]; } diff --git a/extensions/sql-database-projects/src/models/deploy/azureSqlClient.ts b/extensions/sql-database-projects/src/models/deploy/azureSqlClient.ts new file mode 100644 index 0000000000..259739c660 --- /dev/null +++ b/extensions/sql-database-projects/src/models/deploy/azureSqlClient.ts @@ -0,0 +1,67 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as utils from '../../common/utils'; +import { IAccount, IAzureAccountSession, azure } from 'vscode-mssql'; + +/** + * Client module to call Azure APIs for getting or creating resources + */ +export class AzureSqlClient { + + constructor( + private _azureAccountServiceFactory: utils.AzureAccountServiceFactory = utils.defaultAzureAccountServiceFactory, + private _azureResourceServiceFactory: utils.AzureResourceServiceFactory = utils.defaultAzureResourceServiceFactory + ) { } + + /** + * Returns existing Azure accounts + */ + public async getAccounts(): Promise { + const azureAccountService = await this._azureAccountServiceFactory(); + return await azureAccountService.getAccounts(); + } + + /** + * Prompt user to login to Azure and returns the account + * @returns Azure account that user logged in to + */ + public async getAccount(): Promise { + const azureAccountService = await this._azureAccountServiceFactory(); + return await azureAccountService.addAccount(); + } + + /** + * Returns Azure locations for given subscription + */ + public async getLocations(session: IAzureAccountSession): Promise { + const azureResourceService = await this._azureResourceServiceFactory(); + return await azureResourceService.getLocations(session); + } + + /** + * Returns Azure sessions with subscription, tenant and token for given account + */ + public async getSessions(account: IAccount): Promise { + const azureAccountService = await this._azureAccountServiceFactory(); + return await azureAccountService.getAccountSessions(account); + } + + /** + * Creates a new Azure SQL server for given subscription, resource group and location + */ + public async createOrUpdateServer(session: IAzureAccountSession, resourceGroupName: string, serverName: string, parameters: azure.sql.Server): Promise { + const azureResourceService = await this._azureResourceServiceFactory(); + return await azureResourceService.createOrUpdateServer(session, resourceGroupName, serverName, parameters); + } + + /** + * Returns Azure resource groups for given subscription + */ + public async getResourceGroups(session: IAzureAccountSession): Promise | []> { + const azureResourceService = await this._azureResourceServiceFactory(); + return await azureResourceService.getResourceGroups(session); + } +} diff --git a/extensions/sql-database-projects/src/models/deploy/deployProfile.ts b/extensions/sql-database-projects/src/models/deploy/deployProfile.ts index 1ef4d99089..70511603c5 100644 --- a/extensions/sql-database-projects/src/models/deploy/deployProfile.ts +++ b/extensions/sql-database-projects/src/models/deploy/deployProfile.ts @@ -5,39 +5,59 @@ import { IDeploySettings } from '../IDeploySettings'; import type * as azdataType from 'azdata'; +import { IAzureAccountSession } from 'vscode-mssql'; export enum AppSettingType { None, AzureFunction } -export interface IDeployProfile { +export interface ILocalDbDeployProfile { localDbSetting?: ILocalDbSetting; deploySettings?: IDeploySettings; } +export interface ISqlDbDeployProfile { + sqlDbSetting?: ISqlDbSetting; + deploySettings?: IDeploySettings; +} + export interface IDeployAppIntegrationProfile { envVariableName?: string; appSettingFile?: string; appSettingType: AppSettingType; } -export interface ILocalDbSetting { - serverName: string, - port: number, - userName: string, - password: string, - dbName: string, +export interface ISqlDbSetting extends ISqlConnectionProperties { + session: IAzureAccountSession + resourceGroupName: string, + location: string +} + +export interface ILocalDbSetting extends ISqlConnectionProperties { dockerBaseImage: string, dockerBaseImageEula: string, - connectionRetryTimeout?: number, - profileName?: string +} + +export interface ISqlConnectionProperties { + tenantId?: string, + accountId?: string + serverName: string, + userName: string, + password: string, + port: number, + dbName: string, + profileName?: string, + connectionRetryTimeout?: number } export interface DockerImageInfo { name: string, displayName: string, - agreementInfo: AgreementInfo + agreementInfo: AgreementInfo, + tagsUrl: string, + defaultTag: string } export interface AgreementInfo { link: azdataType.LinkArea; } + diff --git a/extensions/sql-database-projects/src/models/deploy/deployService.ts b/extensions/sql-database-projects/src/models/deploy/deployService.ts index b7da3499cc..1b7fe0cb0d 100644 --- a/extensions/sql-database-projects/src/models/deploy/deployService.ts +++ b/extensions/sql-database-projects/src/models/deploy/deployService.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { AppSettingType, IDeployAppIntegrationProfile, IDeployProfile, ILocalDbSetting } from './deployProfile'; +import { AppSettingType, IDeployAppIntegrationProfile, ILocalDbDeployProfile, ILocalDbSetting, ISqlConnectionProperties, ISqlDbDeployProfile } from './deployProfile'; import * as UUID from 'vscode-languageclient/lib/utils/uuid'; import { Project } from '../project'; import * as constants from '../../common/constants'; @@ -13,6 +13,8 @@ import * as vscode from 'vscode'; import { ConnectionResult } from 'azdata'; import * as templates from '../../templates/templates'; import { ShellExecutionHelper } from '../../tools/shellExecutionHelper'; +import { AzureSqlClient } from './azureSqlClient'; +import { IFireWallRuleError } from 'vscode-mssql'; interface DockerImageSpec { label: string; @@ -21,7 +23,7 @@ interface DockerImageSpec { } export class DeployService { - constructor(private _outputChannel: vscode.OutputChannel, shellExecutionHelper: ShellExecutionHelper | undefined = undefined) { + constructor(private _azureSqlClient = new AzureSqlClient(), private _outputChannel: vscode.OutputChannel, shellExecutionHelper: ShellExecutionHelper | undefined = undefined) { this._shellExecutionHelper = shellExecutionHelper ?? new ShellExecutionHelper(this._outputChannel); } @@ -50,7 +52,7 @@ export class DeployService { return undefined; } - public async updateAppSettings(profile: IDeployAppIntegrationProfile, deployProfile: IDeployProfile | undefined): Promise { + public async updateAppSettings(profile: IDeployAppIntegrationProfile, deployProfile: ILocalDbDeployProfile | undefined): Promise { // Update app settings // if (!profile.appSettingFile) { @@ -122,7 +124,37 @@ export class DeployService { return { label: imageLabel, tag: imageTag, containerName: dockerName }; } - public async deploy(profile: IDeployProfile, project: Project): Promise { + /** + * Creates a new Azure Sql server and tries to connect to the new server. If connection fails because of firewall rule, it prompts user to add firewall rule settings + * @param profile Azure Sql server settings + * @returns connection url for the new server + */ + public async createNewAzureSqlServer(profile: ISqlDbDeployProfile | undefined): Promise { + if (!profile?.sqlDbSetting) { + return undefined; + } + + this.logToOutput(constants.creatingAzureSqlServer(profile?.sqlDbSetting?.serverName)); + + // Create the server + const server = await this._azureSqlClient.createOrUpdateServer(profile.sqlDbSetting.session, profile?.sqlDbSetting.resourceGroupName, profile?.sqlDbSetting.serverName, { + location: profile?.sqlDbSetting?.location, + administratorLogin: profile?.sqlDbSetting.userName, + administratorLoginPassword: profile?.sqlDbSetting.password + }); + if (server) { + this._outputChannel.appendLine(constants.serverCreated); + profile.sqlDbSetting.serverName = server; + + this.logToOutput(constants.azureSqlServerCreated(profile?.sqlDbSetting?.serverName)); + + // Connect to the server + return await this.getConnection(profile.sqlDbSetting, false, constants.master); + } + return undefined; + } + + public async deployToContainer(profile: ILocalDbDeployProfile, project: Project): Promise { return await this.executeTask(constants.deployDbTaskName, async () => { if (!profile.localDbSetting) { return undefined; @@ -218,7 +250,7 @@ export class DeployService { } // Connects to a database - private async connectToDatabase(profile: ILocalDbSetting, saveConnectionAndPassword: boolean, database: string): Promise { + private async connectToDatabase(profile: ISqlConnectionProperties, saveConnectionAndPassword: boolean, database: string): Promise { const getAzdataApi = await utils.getAzdataApi(); const vscodeMssqlApi = getAzdataApi ? undefined : await utils.getVscodeMssqlApi(); if (getAzdataApi) { @@ -248,7 +280,7 @@ export class DeployService { encrypt: false, connectTimeout: 30, applicationName: 'SQL Database Project', - accountId: undefined, + accountId: profile.accountId, azureAccountToken: undefined, applicationIntent: undefined, attachDbFilename: undefined, @@ -272,9 +304,19 @@ export class DeployService { workstationId: undefined, profileName: profile.profileName, expiresOn: undefined, - tenantId: undefined + tenantId: profile.tenantId }; - let connectionUrl = await vscodeMssqlApi.connect(connectionProfile, saveConnectionAndPassword); + let connectionUrl = ''; + try { + connectionUrl = await vscodeMssqlApi.connect(connectionProfile, saveConnectionAndPassword); + } catch (err) { + const firewallRuleError = err; + if (firewallRuleError?.connectionUri) { + await vscodeMssqlApi.promptForFirewallRule(err.connectionUri, connectionProfile); + } else { + throw err; + } + } return connectionUrl; } else { return undefined; @@ -307,7 +349,7 @@ export class DeployService { return connectionResult ? connectionResult.connectionId : connection; } - public async getConnection(profile: ILocalDbSetting, saveConnectionAndPassword: boolean, database: string): Promise { + public async getConnection(profile: ISqlConnectionProperties, saveConnectionAndPassword: boolean, database: string): Promise { const getAzdataApi = await utils.getAzdataApi(); let connection = await utils.retry( constants.connectingToSqlServerMessage, diff --git a/extensions/sql-database-projects/src/test/deploy/azureSqlClient.test.ts b/extensions/sql-database-projects/src/test/deploy/azureSqlClient.test.ts new file mode 100644 index 0000000000..12dd504ab6 --- /dev/null +++ b/extensions/sql-database-projects/src/test/deploy/azureSqlClient.test.ts @@ -0,0 +1,109 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as should from 'should'; +import { AzureSqlClient } from '../../models/deploy/azureSqlClient'; +import { IAccount, IAzureAccountService, IAzureAccountSession, IAzureResourceService, azure } from 'vscode-mssql'; + + + +export interface TestContext { + azureAccountService: IAzureAccountService; + azureResourceService: IAzureResourceService; + accounts: IAccount[]; + session: IAzureAccountSession; + subscriptions: azure.subscription.Subscription[]; + locations: azure.subscription.Location[]; + groups: azure.resources.ResourceGroup[]; +} + +export function createContext(): TestContext { + const accounts = [{ + key: undefined!, + displayInfo: undefined!, + properties: { + tenants: [{ + id: '', + displayName: '' + }] + }, + isStale: false, + isSignedIn: true + }]; + const subscriptions: azure.subscription.Subscription[] = [{ subscriptionId: 'id1' }, { subscriptionId: 'id2' }]; + const locations: azure.subscription.Location[] = [{ id: 'id1' }, { id: 'id2' }]; + const groups: azure.resources.ResourceGroup[] = [{ id: 'id1', location: 'l1' }, { id: 'id2', location: 'l2' }]; + const session: IAzureAccountSession = { + account: accounts[0], + subscription: subscriptions[0], + tenantId: 'tenantId', + token: { + key: '', + token: '', + tokenType: '', + } + }; + return { + groups: groups, + locations: locations, + subscriptions: subscriptions, + session: session, + accounts: accounts, + azureAccountService: { + addAccount: () => Promise.resolve(accounts[0]), + getAccounts: () => Promise.resolve(accounts), + getAccountSecurityToken: () => Promise.resolve({ + key: '', + token: '', + tokenType: '' + }), + getAccountSessions: () => Promise.resolve([session]) + }, + azureResourceService: { + getLocations: () => Promise.resolve(locations), + getResourceGroups: () => Promise.resolve(groups), + createOrUpdateServer: () => Promise.resolve('new_server') + } + }; +} + +describe('Azure SQL client', function (): void { + + it('Should return accounts successfully', async function (): Promise { + const testContext = createContext(); + const azureSqlClient = new AzureSqlClient(() => Promise.resolve(testContext.azureAccountService)); + const accounts = await azureSqlClient.getAccounts(); + should(accounts.length).equal(testContext.accounts.length); + }); + + it('Should create and return new account successfully', async function (): Promise { + const testContext = createContext(); + const azureSqlClient = new AzureSqlClient(() => Promise.resolve(testContext.azureAccountService)); + const account = await azureSqlClient.getAccount(); + should(account.key).equal(testContext.accounts[0].key); + }); + + it('Should return subscriptions successfully', async function (): Promise { + const testContext = createContext(); + const azureSqlClient = new AzureSqlClient(() => Promise.resolve(testContext.azureAccountService)); + const result = await azureSqlClient.getSessions(testContext.accounts[0]); + should(result[0].subscription.id).deepEqual(testContext.subscriptions[0].id); + }); + + it('Should return locations successfully', async function (): Promise { + const testContext = createContext(); + const azureSqlClient = new AzureSqlClient(() => Promise.resolve(testContext.azureAccountService), () => Promise.resolve(testContext.azureResourceService)); + const result = await azureSqlClient.getLocations(testContext.session); + should(result.length).deepEqual(testContext.locations.length); + }); + + it('Should return resource groups successfully', async function (): Promise { + const testContext = createContext(); + const azureSqlClient = new AzureSqlClient(() => Promise.resolve(testContext.azureAccountService), () => Promise.resolve(testContext.azureResourceService)); + const result = await azureSqlClient.getResourceGroups(testContext.session); + should(result.length).deepEqual(testContext.groups.length); + should(result[0].location).deepEqual(testContext.groups[0].location); + }); +}); diff --git a/extensions/sql-database-projects/src/test/deploy/deployService.test.ts b/extensions/sql-database-projects/src/test/deploy/deployService.test.ts index fa6452de81..2ec4eb84a7 100644 --- a/extensions/sql-database-projects/src/test/deploy/deployService.test.ts +++ b/extensions/sql-database-projects/src/test/deploy/deployService.test.ts @@ -11,16 +11,18 @@ import { DeployService } from '../../models/deploy/deployService'; import { Project } from '../../models/project'; import * as vscode from 'vscode'; import * as azdata from 'azdata'; -import { AppSettingType, IDeployProfile } from '../../models/deploy/deployProfile'; +import { AppSettingType, ILocalDbDeployProfile, ISqlDbDeployProfile } from '../../models/deploy/deployProfile'; import * as UUID from 'vscode-languageclient/lib/utils/uuid'; import * as fse from 'fs-extra'; import * as path from 'path'; import * as constants from '../../common/constants'; import { ShellExecutionHelper } from '../../tools/shellExecutionHelper'; import * as TypeMoq from 'typemoq'; +import { AzureSqlClient } from '../../models/deploy/azureSqlClient'; export interface TestContext { outputChannel: vscode.OutputChannel; + azureSqlClient: TypeMoq.IMock; } export const mockConnectionResult: azdata.ConnectionResult = { @@ -47,7 +49,8 @@ export function createContext(): TestContext { show: () => { }, hide: () => { }, dispose: () => { } - } + }, + azureSqlClient: TypeMoq.Mock.ofType(AzureSqlClient) }; } @@ -68,7 +71,7 @@ describe('deploy service', function (): void { it('Should deploy a database to docker container successfully', async function (): Promise { const testContext = createContext(); - const deployProfile: IDeployProfile = { + const deployProfile: ILocalDbDeployProfile = { localDbSetting: { dbName: 'test', password: 'PLACEHOLDER', @@ -84,21 +87,21 @@ describe('deploy service', function (): void { const project1 = await Project.openProject(vscode.Uri.file(projFilePath).fsPath); const shellExecutionHelper = TypeMoq.Mock.ofType(ShellExecutionHelper); shellExecutionHelper.setup(x => x.runStreamedCommand(TypeMoq.It.isAny(), - undefined, TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve('id')); - const deployService = new DeployService(testContext.outputChannel, shellExecutionHelper.object); + undefined, TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve('id')); + const deployService = new DeployService(testContext.azureSqlClient.object, testContext.outputChannel, shellExecutionHelper.object); sandbox.stub(azdata.connection, 'connect').returns(Promise.resolve(mockConnectionResult)); sandbox.stub(azdata.connection, 'getUriForConnection').returns(Promise.resolve('connection')); sandbox.stub(vscode.window, 'showWarningMessage').returns(Promise.resolve(constants.yesString)); sandbox.stub(azdata.tasks, 'startBackgroundOperation').callThrough(); - let connection = await deployService.deploy(deployProfile, project1); + let connection = await deployService.deployToContainer(deployProfile, project1); should(connection).equals('connection'); }); it('Should fail the deploy if docker is not running', async function (): Promise { const testContext = createContext(); - const deployProfile: IDeployProfile = { + const deployProfile: ILocalDbDeployProfile = { localDbSetting: { dbName: 'test', password: 'PLACEHOLDER', @@ -114,11 +117,11 @@ describe('deploy service', function (): void { const project1 = await Project.openProject(vscode.Uri.file(projFilePath).fsPath); const shellExecutionHelper = TypeMoq.Mock.ofType(ShellExecutionHelper); shellExecutionHelper.setup(x => x.runStreamedCommand(TypeMoq.It.isAny(), - undefined, TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.reject('error')); - const deployService = new DeployService(testContext.outputChannel, shellExecutionHelper.object); + undefined, TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.reject('error')); + const deployService = new DeployService(testContext.azureSqlClient.object, testContext.outputChannel, shellExecutionHelper.object); sandbox.stub(azdata.tasks, 'startBackgroundOperation').callThrough(); - await should(deployService.deploy(deployProfile, project1)).rejected(); + await should(deployService.deployToContainer(deployProfile, project1)).rejected(); }); it('Should retry connecting to the server', async function (): Promise { @@ -136,8 +139,8 @@ describe('deploy service', function (): void { const shellExecutionHelper = TypeMoq.Mock.ofType(ShellExecutionHelper); shellExecutionHelper.setup(x => x.runStreamedCommand(TypeMoq.It.isAny(), - undefined, TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve('id')); - const deployService = new DeployService(testContext.outputChannel, shellExecutionHelper.object); + undefined, TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve('id')); + const deployService = new DeployService(testContext.azureSqlClient.object, testContext.outputChannel, shellExecutionHelper.object); let connectionStub = sandbox.stub(azdata.connection, 'connect'); connectionStub.onFirstCall().returns(Promise.resolve(mockFailedConnectionResult)); connectionStub.onSecondCall().returns(Promise.resolve(mockConnectionResult)); @@ -173,7 +176,7 @@ describe('deploy service', function (): void { const filePath = path.join(project1.projectFolderPath, 'local.settings.json'); await fse.writeFile(filePath, settingContent); - const deployProfile: IDeployProfile = { + const deployProfile: ILocalDbDeployProfile = { localDbSetting: { dbName: 'test', password: 'PLACEHOLDER', @@ -194,8 +197,8 @@ describe('deploy service', function (): void { const shellExecutionHelper = TypeMoq.Mock.ofType(ShellExecutionHelper); shellExecutionHelper.setup(x => x.runStreamedCommand(TypeMoq.It.isAny(), - undefined, TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve('id')); - const deployService = new DeployService(testContext.outputChannel, shellExecutionHelper.object); + undefined, TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve('id')); + const deployService = new DeployService(testContext.azureSqlClient.object, testContext.outputChannel, shellExecutionHelper.object); await deployService.updateAppSettings(appInteg, deployProfile); let newContent = JSON.parse(fse.readFileSync(filePath, 'utf8')); @@ -228,7 +231,7 @@ describe('deploy service', function (): void { const filePath = path.join(project1.projectFolderPath, 'local.settings.json'); await fse.writeFile(filePath, settingContent); - const deployProfile: IDeployProfile = { + const deployProfile: ILocalDbDeployProfile = { deploySettings: { connectionUri: 'connection', @@ -245,8 +248,8 @@ describe('deploy service', function (): void { }; const shellExecutionHelper = TypeMoq.Mock.ofType(ShellExecutionHelper); shellExecutionHelper.setup(x => x.runStreamedCommand(TypeMoq.It.isAny(), - undefined, TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve('id')); - const deployService = new DeployService(testContext.outputChannel, shellExecutionHelper.object); + undefined, TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve('id')); + const deployService = new DeployService(testContext.azureSqlClient.object, testContext.outputChannel, shellExecutionHelper.object); let connection = new azdata.connection.ConnectionProfile(); sandbox.stub(azdata.connection, 'getConnection').returns(Promise.resolve(connection)); @@ -260,10 +263,10 @@ describe('deploy service', function (): void { const testContext = createContext(); const shellExecutionHelper = TypeMoq.Mock.ofType(ShellExecutionHelper); shellExecutionHelper.setup(x => x.runStreamedCommand(TypeMoq.It.isAny(), - undefined, TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve(`id + undefined, TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve(`id id2 id3`)); - const deployService = new DeployService(testContext.outputChannel, shellExecutionHelper.object); + const deployService = new DeployService(testContext.azureSqlClient.object, testContext.outputChannel, shellExecutionHelper.object); const ids = await deployService.getCurrentDockerContainer('label'); await deployService.cleanDockerObjects(ids, ['docker stop', 'docker rm']); shellExecutionHelper.verify(x => x.runStreamedCommand(TypeMoq.It.isAny(), undefined, TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.exactly(7)); @@ -271,7 +274,7 @@ describe('deploy service', function (): void { it('Should create docker image info correctly', () => { const testContext = createContext(); - const deployService = new DeployService(testContext.outputChannel); + const deployService = new DeployService(testContext.azureSqlClient.object, testContext.outputChannel); const id = UUID.generateUuid().toLocaleLowerCase(); const baseImage = 'baseImage:latest'; const tag = baseImage.replace(':', '-').replace(constants.sqlServerDockerRegistry, '').replace(/[^a-zA-Z0-9_,\-]/g, '').toLocaleLowerCase(); @@ -311,4 +314,53 @@ describe('deploy service', function (): void { tag: `${constants.dockerImageNamePrefix}-${imageProjectName}-${tag}` }); }); + + it('Should create a new Azure SQL server successfully', async function (): Promise { + const testContext = createContext(); + const deployProfile: ISqlDbDeployProfile = { + sqlDbSetting: { + dbName: 'test', + password: 'PLACEHOLDER', + port: 1433, + serverName: 'localhost', + userName: 'sa', + connectionRetryTimeout: 1, + resourceGroupName: 'resourceGroups', + session: { + subscription: { + subscriptionId: 'subscriptionId', + },token: { + key: '', + token: '', + tokenType: '', + }, + tenantId: '', + account: undefined! + }, + location: 'location' + } + }; + const fullyQualifiedDomainName = 'servername'; + const shellExecutionHelper = TypeMoq.Mock.ofType(ShellExecutionHelper); + shellExecutionHelper.setup(x => x.runStreamedCommand(TypeMoq.It.isAny(), + undefined, TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve('id')); + const session = deployProfile?.sqlDbSetting?.session; + if (deployProfile?.sqlDbSetting?.session && session) { + testContext.azureSqlClient.setup(x => x.createOrUpdateServer( + session, + deployProfile.sqlDbSetting?.resourceGroupName || '', + deployProfile.sqlDbSetting?.serverName || '', + { + location: deployProfile?.sqlDbSetting?.location || '', + administratorLogin: deployProfile?.sqlDbSetting?.userName, + administratorLoginPassword: deployProfile?.sqlDbSetting?.password + })).returns(() => Promise.resolve(fullyQualifiedDomainName)); + } + sandbox.stub(azdata.connection, 'connect').returns(Promise.resolve(mockConnectionResult)); + sandbox.stub(azdata.connection, 'getUriForConnection').returns(Promise.resolve('connection')); + const deployService = new DeployService(testContext.azureSqlClient.object, testContext.outputChannel, shellExecutionHelper.object); + let connection = await deployService.createNewAzureSqlServer(deployProfile); + should(deployProfile.sqlDbSetting?.serverName).equal(fullyQualifiedDomainName); + should(connection).equals('connection'); + }); }); diff --git a/extensions/sql-database-projects/src/test/dialogs/publishDatabaseDialog.test.ts b/extensions/sql-database-projects/src/test/dialogs/publishDatabaseDialog.test.ts index 81a9bb0553..801f70d10a 100644 --- a/extensions/sql-database-projects/src/test/dialogs/publishDatabaseDialog.test.ts +++ b/extensions/sql-database-projects/src/test/dialogs/publishDatabaseDialog.test.ts @@ -18,7 +18,7 @@ import { ProjectsController } from '../../controllers/projectController'; import { IDeploySettings } from '../../models/IDeploySettings'; import { emptySqlDatabaseProjectTypeId } from '../../common/constants'; import { createContext, mockDacFxOptionsResult, TestContext } from '../testContext'; -import { IDeployProfile } from '../../models/deploy/deployProfile'; +import { ILocalDbDeployProfile } from '../../models/deploy/deployProfile'; let testContext: TestContext; describe('Publish Database Dialog', () => { @@ -112,7 +112,7 @@ describe('Publish Database Dialog', () => { should(profile).deepEqual(expectedGenScript); - const expectedContainerPublishProfile: IDeployProfile = { + const expectedContainerPublishProfile: ILocalDbDeployProfile = { localDbSetting: { dbName: 'MockDatabaseName', dockerBaseImage: '', @@ -136,7 +136,7 @@ describe('Publish Database Dialog', () => { } }; dialog.object.publishToExistingServer = false; - let deployProfile: IDeployProfile | undefined; + let deployProfile: ILocalDbDeployProfile | undefined; dialog.object.publishToContainer = (_, prof) => { deployProfile = prof; }; await dialog.object.publishClick(); diff --git a/extensions/sql-database-projects/src/test/utils.test.ts b/extensions/sql-database-projects/src/test/utils.test.ts index bbf12d383c..e45b4ea5ac 100644 --- a/extensions/sql-database-projects/src/test/utils.test.ts +++ b/extensions/sql-database-projects/src/test/utils.test.ts @@ -7,7 +7,7 @@ import * as should from 'should'; import * as path from 'path'; import * as os from 'os'; import { createDummyFileStructure } from './testUtils'; -import { exists, trimUri, removeSqlCmdVariableFormatting, formatSqlCmdVariable, isValidSqlCmdVariableName, timeConversion, validateSqlServerPortNumber, isEmptyString, detectCommandInstallation, isValidSQLPassword } from '../common/utils'; +import { exists, trimUri, removeSqlCmdVariableFormatting, formatSqlCmdVariable, isValidSqlCmdVariableName, timeConversion, validateSqlServerPortNumber, isEmptyString, detectCommandInstallation, isValidSQLPassword, findSqlVersionInImageName, findSqlVersionInTargetPlatform } from '../common/utils'; import { Uri } from 'vscode'; describe('Tests to verify utils functions', function (): void { @@ -123,5 +123,20 @@ describe('Tests to verify utils functions', function (): void { should(isValidSQLPassword('dFdf65$530')).equals(true, 'dF65$530 is valid password'); should(isValidSQLPassword('av1fgh533@')).equals(true, 'dF65$530 is valid password'); }); + + it('findSqlVersionInImageName should return the version correctly', () => { + should(findSqlVersionInImageName('2017-CU1-ubuntu')).equals(2017, 'invalid number returned for 2017-CU1-ubuntu'); + should(findSqlVersionInImageName('2019-latest')).equals(2019, 'invalid number returned for 2019-latest'); + should(findSqlVersionInImageName('latest')).equals(undefined, 'invalid number returned for latest'); + should(findSqlVersionInImageName('latest-ubuntu')).equals(undefined, 'invalid number returned for latest-ubuntu'); + should(findSqlVersionInImageName('2017-CU20-ubuntu-16.04')).equals(2017, 'invalid number returned for 2017-CU20-ubuntu-16.04'); + }); + + it('findSqlVersionInTargetPlatform should return the version correctly', () => { + should(findSqlVersionInTargetPlatform('SQL Server 2012')).equals(2012, 'invalid number returned for SQL Server 2012'); + should(findSqlVersionInTargetPlatform('SQL Server 2019')).equals(2019, 'invalid number returned for SQL Server 2019'); + should(findSqlVersionInTargetPlatform('Azure SQL Database')).equals(undefined, 'invalid number returned for Azure SQL Database'); + should(findSqlVersionInTargetPlatform('Azure Synapse Dedicated SQL Pool')).equals(undefined, 'invalid number returned for Azure Synapse Dedicated SQL Pool'); + }); }); diff --git a/extensions/sql-database-projects/yarn.lock b/extensions/sql-database-projects/yarn.lock index d3bd76a01b..b0c06b6a62 100644 --- a/extensions/sql-database-projects/yarn.lock +++ b/extensions/sql-database-projects/yarn.lock @@ -2,192 +2,225 @@ # yarn lockfile v1 -"@babel/code-frame@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.8.3.tgz#33e25903d7481181534e12ec0a25f16b6fcf419e" - integrity sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g== +"@ampproject/remapping@^2.1.0": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.1.2.tgz#4edca94973ded9630d20101cd8559cedb8d8bd34" + integrity sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg== dependencies: - "@babel/highlight" "^7.8.3" + "@jridgewell/trace-mapping" "^0.3.0" + +"@babel/code-frame@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789" + integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg== + dependencies: + "@babel/highlight" "^7.16.7" + +"@babel/compat-data@^7.16.4": + version "7.17.0" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.17.0.tgz#86850b8597ea6962089770952075dcaabb8dba34" + integrity sha512-392byTlpGWXMv4FbyWw3sAZ/FrW/DrwqLGXpy0mbyNe9Taqv1mg9yON5/o0cnr8XYCkFTZbC1eV+c+LAROgrng== "@babel/core@^7.7.5": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.9.0.tgz#ac977b538b77e132ff706f3b8a4dbad09c03c56e" - integrity sha512-kWc7L0fw1xwvI0zi8OKVBuxRVefwGOrKSQMvrQ3dW+bIIavBY3/NpXmpjMy7bQnLgwgzWQZ8TlM57YHpHNHz4w== + version "7.17.5" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.17.5.tgz#6cd2e836058c28f06a4ca8ee7ed955bbf37c8225" + integrity sha512-/BBMw4EvjmyquN5O+t5eh0+YqB3XXJkYD2cjKpYtWOfFy4lQ4UozNSmxAcWT8r2XtZs0ewG+zrfsqeR15i1ajA== dependencies: - "@babel/code-frame" "^7.8.3" - "@babel/generator" "^7.9.0" - "@babel/helper-module-transforms" "^7.9.0" - "@babel/helpers" "^7.9.0" - "@babel/parser" "^7.9.0" - "@babel/template" "^7.8.6" - "@babel/traverse" "^7.9.0" - "@babel/types" "^7.9.0" + "@ampproject/remapping" "^2.1.0" + "@babel/code-frame" "^7.16.7" + "@babel/generator" "^7.17.3" + "@babel/helper-compilation-targets" "^7.16.7" + "@babel/helper-module-transforms" "^7.16.7" + "@babel/helpers" "^7.17.2" + "@babel/parser" "^7.17.3" + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.17.3" + "@babel/types" "^7.17.0" convert-source-map "^1.7.0" debug "^4.1.0" - gensync "^1.0.0-beta.1" + gensync "^1.0.0-beta.2" json5 "^2.1.2" - lodash "^4.17.13" - resolve "^1.3.2" - semver "^5.4.1" - source-map "^0.5.0" + semver "^6.3.0" -"@babel/generator@^7.9.0", "@babel/generator@^7.9.5": - version "7.9.5" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.9.5.tgz#27f0917741acc41e6eaaced6d68f96c3fa9afaf9" - integrity sha512-GbNIxVB3ZJe3tLeDm1HSn2AhuD/mVcyLDpgtLXa5tplmWrJdF/elxB56XNqCuD6szyNkDi6wuoKXln3QeBmCHQ== +"@babel/generator@^7.17.3": + version "7.17.3" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.17.3.tgz#a2c30b0c4f89858cb87050c3ffdfd36bdf443200" + integrity sha512-+R6Dctil/MgUsZsZAkYgK+ADNSZzJRRy0TvY65T71z/CR854xHQ1EweBYXdfT+HNeN7w0cSJJEzgxZMv40pxsg== dependencies: - "@babel/types" "^7.9.5" + "@babel/types" "^7.17.0" jsesc "^2.5.1" - lodash "^4.17.13" source-map "^0.5.0" -"@babel/helper-function-name@^7.9.5": - version "7.9.5" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.9.5.tgz#2b53820d35275120e1874a82e5aabe1376920a5c" - integrity sha512-JVcQZeXM59Cd1qanDUxv9fgJpt3NeKUaqBqUEvfmQ+BCOKq2xUgaWZW2hr0dkbyJgezYuplEoh5knmrnS68efw== +"@babel/helper-compilation-targets@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz#06e66c5f299601e6c7da350049315e83209d551b" + integrity sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA== dependencies: - "@babel/helper-get-function-arity" "^7.8.3" - "@babel/template" "^7.8.3" - "@babel/types" "^7.9.5" + "@babel/compat-data" "^7.16.4" + "@babel/helper-validator-option" "^7.16.7" + browserslist "^4.17.5" + semver "^6.3.0" -"@babel/helper-get-function-arity@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz#b894b947bd004381ce63ea1db9f08547e920abd5" - integrity sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA== +"@babel/helper-environment-visitor@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz#ff484094a839bde9d89cd63cba017d7aae80ecd7" + integrity sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag== dependencies: - "@babel/types" "^7.8.3" + "@babel/types" "^7.16.7" -"@babel/helper-member-expression-to-functions@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.8.3.tgz#659b710498ea6c1d9907e0c73f206eee7dadc24c" - integrity sha512-fO4Egq88utkQFjbPrSHGmGLFqmrshs11d46WI+WZDESt7Wu7wN2G2Iu+NMMZJFDOVRHAMIkB5SNh30NtwCA7RA== +"@babel/helper-function-name@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz#f1ec51551fb1c8956bc8dd95f38523b6cf375f8f" + integrity sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA== dependencies: - "@babel/types" "^7.8.3" + "@babel/helper-get-function-arity" "^7.16.7" + "@babel/template" "^7.16.7" + "@babel/types" "^7.16.7" -"@babel/helper-module-imports@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.8.3.tgz#7fe39589b39c016331b6b8c3f441e8f0b1419498" - integrity sha512-R0Bx3jippsbAEtzkpZ/6FIiuzOURPcMjHp+Z6xPe6DtApDJx+w7UYyOLanZqO8+wKR9G10s/FmHXvxaMd9s6Kg== +"@babel/helper-get-function-arity@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz#ea08ac753117a669f1508ba06ebcc49156387419" + integrity sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw== dependencies: - "@babel/types" "^7.8.3" + "@babel/types" "^7.16.7" -"@babel/helper-module-transforms@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.9.0.tgz#43b34dfe15961918707d247327431388e9fe96e5" - integrity sha512-0FvKyu0gpPfIQ8EkxlrAydOWROdHpBmiCiRwLkUiBGhCUPRRbVD2/tm3sFr/c/GWFrQ/ffutGUAnx7V0FzT2wA== +"@babel/helper-hoist-variables@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz#86bcb19a77a509c7b77d0e22323ef588fa58c246" + integrity sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg== dependencies: - "@babel/helper-module-imports" "^7.8.3" - "@babel/helper-replace-supers" "^7.8.6" - "@babel/helper-simple-access" "^7.8.3" - "@babel/helper-split-export-declaration" "^7.8.3" - "@babel/template" "^7.8.6" - "@babel/types" "^7.9.0" - lodash "^4.17.13" + "@babel/types" "^7.16.7" -"@babel/helper-optimise-call-expression@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.8.3.tgz#7ed071813d09c75298ef4f208956006b6111ecb9" - integrity sha512-Kag20n86cbO2AvHca6EJsvqAd82gc6VMGule4HwebwMlwkpXuVqrNRj6CkCV2sKxgi9MyAUnZVnZ6lJ1/vKhHQ== +"@babel/helper-module-imports@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz#25612a8091a999704461c8a222d0efec5d091437" + integrity sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg== dependencies: - "@babel/types" "^7.8.3" + "@babel/types" "^7.16.7" -"@babel/helper-replace-supers@^7.8.6": - version "7.8.6" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.8.6.tgz#5ada744fd5ad73203bf1d67459a27dcba67effc8" - integrity sha512-PeMArdA4Sv/Wf4zXwBKPqVj7n9UF/xg6slNRtZW84FM7JpE1CbG8B612FyM4cxrf4fMAMGO0kR7voy1ForHHFA== +"@babel/helper-module-transforms@^7.16.7": + version "7.17.6" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.17.6.tgz#3c3b03cc6617e33d68ef5a27a67419ac5199ccd0" + integrity sha512-2ULmRdqoOMpdvkbT8jONrZML/XALfzxlb052bldftkicAUy8AxSCkD5trDPQcwHNmolcl7wP6ehNqMlyUw6AaA== dependencies: - "@babel/helper-member-expression-to-functions" "^7.8.3" - "@babel/helper-optimise-call-expression" "^7.8.3" - "@babel/traverse" "^7.8.6" - "@babel/types" "^7.8.6" + "@babel/helper-environment-visitor" "^7.16.7" + "@babel/helper-module-imports" "^7.16.7" + "@babel/helper-simple-access" "^7.16.7" + "@babel/helper-split-export-declaration" "^7.16.7" + "@babel/helper-validator-identifier" "^7.16.7" + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.17.3" + "@babel/types" "^7.17.0" -"@babel/helper-simple-access@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.8.3.tgz#7f8109928b4dab4654076986af575231deb639ae" - integrity sha512-VNGUDjx5cCWg4vvCTR8qQ7YJYZ+HBjxOgXEl7ounz+4Sn7+LMD3CFrCTEU6/qXKbA2nKg21CwhhBzO0RpRbdCw== +"@babel/helper-simple-access@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz#d656654b9ea08dbb9659b69d61063ccd343ff0f7" + integrity sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g== dependencies: - "@babel/template" "^7.8.3" - "@babel/types" "^7.8.3" + "@babel/types" "^7.16.7" -"@babel/helper-split-export-declaration@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz#31a9f30070f91368a7182cf05f831781065fc7a9" - integrity sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA== +"@babel/helper-split-export-declaration@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz#0b648c0c42da9d3920d85ad585f2778620b8726b" + integrity sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw== dependencies: - "@babel/types" "^7.8.3" + "@babel/types" "^7.16.7" -"@babel/helper-validator-identifier@^7.9.0", "@babel/helper-validator-identifier@^7.9.5": - version "7.9.5" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz#90977a8e6fbf6b431a7dc31752eee233bf052d80" - integrity sha512-/8arLKUFq882w4tWGj9JYzRpAlZgiWUJ+dtteNTDqrRBz9Iguck9Rn3ykuBDoUwh2TO4tSAJlrxDUOXWklJe4g== +"@babel/helper-validator-identifier@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad" + integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw== -"@babel/helpers@^7.9.0": - version "7.9.2" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.9.2.tgz#b42a81a811f1e7313b88cba8adc66b3d9ae6c09f" - integrity sha512-JwLvzlXVPjO8eU9c/wF9/zOIN7X6h8DYf7mG4CiFRZRvZNKEF5dQ3H3V+ASkHoIB3mWhatgl5ONhyqHRI6MppA== +"@babel/helper-validator-option@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz#b203ce62ce5fe153899b617c08957de860de4d23" + integrity sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ== + +"@babel/helpers@^7.17.2": + version "7.17.2" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.17.2.tgz#23f0a0746c8e287773ccd27c14be428891f63417" + integrity sha512-0Qu7RLR1dILozr/6M0xgj+DFPmi6Bnulgm9M8BVa9ZCWxDqlSnqt3cf8IDPB5m45sVXUZ0kuQAgUrdSFFH79fQ== dependencies: - "@babel/template" "^7.8.3" - "@babel/traverse" "^7.9.0" - "@babel/types" "^7.9.0" + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.17.0" + "@babel/types" "^7.17.0" -"@babel/highlight@^7.8.3": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.9.0.tgz#4e9b45ccb82b79607271b2979ad82c7b68163079" - integrity sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ== +"@babel/highlight@^7.16.7": + version "7.16.10" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.10.tgz#744f2eb81579d6eea753c227b0f570ad785aba88" + integrity sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw== dependencies: - "@babel/helper-validator-identifier" "^7.9.0" + "@babel/helper-validator-identifier" "^7.16.7" chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.7.5", "@babel/parser@^7.8.6", "@babel/parser@^7.9.0": - version "7.9.4" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.9.4.tgz#68a35e6b0319bbc014465be43828300113f2f2e8" - integrity sha512-bC49otXX6N0/VYhgOMh4gnP26E9xnDZK3TmbNpxYzzz9BQLBosQwfyOe9/cXUU3txYhTzLCbcqd5c8y/OmCjHA== +"@babel/parser@^7.16.7", "@babel/parser@^7.17.3": + version "7.17.3" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.3.tgz#b07702b982990bf6fdc1da5049a23fece4c5c3d0" + integrity sha512-7yJPvPV+ESz2IUTPbOL+YkIGyCqOyNIzdguKQuJGnH7bg1WTIifuM21YqokFt/THWh1AkCRn9IgoykTRCBVpzA== "@babel/runtime@^7.1.5": - version "7.9.6" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.9.6.tgz#a9102eb5cadedf3f31d08a9ecf294af7827ea29f" - integrity sha512-64AF1xY3OAkFHqOb9s4jpgk1Mm5vDZ4L3acHvAml+53nO1XbXLuDodsVpO4OIUsmemlUHMxNdYMNJmsvOwLrvQ== + version "7.17.2" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.2.tgz#66f68591605e59da47523c631416b18508779941" + integrity sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw== dependencies: regenerator-runtime "^0.13.4" -"@babel/template@^7.7.4", "@babel/template@^7.8.3", "@babel/template@^7.8.6": - version "7.8.6" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.8.6.tgz#86b22af15f828dfb086474f964dcc3e39c43ce2b" - integrity sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg== +"@babel/template@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.7.tgz#8d126c8701fde4d66b264b3eba3d96f07666d155" + integrity sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w== dependencies: - "@babel/code-frame" "^7.8.3" - "@babel/parser" "^7.8.6" - "@babel/types" "^7.8.6" + "@babel/code-frame" "^7.16.7" + "@babel/parser" "^7.16.7" + "@babel/types" "^7.16.7" -"@babel/traverse@^7.7.4", "@babel/traverse@^7.8.6", "@babel/traverse@^7.9.0": - version "7.9.5" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.9.5.tgz#6e7c56b44e2ac7011a948c21e283ddd9d9db97a2" - integrity sha512-c4gH3jsvSuGUezlP6rzSJ6jf8fYjLj3hsMZRx/nX0h+fmHN0w+ekubRrHPqnMec0meycA2nwCsJ7dC8IPem2FQ== +"@babel/traverse@^7.17.0", "@babel/traverse@^7.17.3": + version "7.17.3" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.17.3.tgz#0ae0f15b27d9a92ba1f2263358ea7c4e7db47b57" + integrity sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw== dependencies: - "@babel/code-frame" "^7.8.3" - "@babel/generator" "^7.9.5" - "@babel/helper-function-name" "^7.9.5" - "@babel/helper-split-export-declaration" "^7.8.3" - "@babel/parser" "^7.9.0" - "@babel/types" "^7.9.5" + "@babel/code-frame" "^7.16.7" + "@babel/generator" "^7.17.3" + "@babel/helper-environment-visitor" "^7.16.7" + "@babel/helper-function-name" "^7.16.7" + "@babel/helper-hoist-variables" "^7.16.7" + "@babel/helper-split-export-declaration" "^7.16.7" + "@babel/parser" "^7.17.3" + "@babel/types" "^7.17.0" debug "^4.1.0" globals "^11.1.0" - lodash "^4.17.13" -"@babel/types@^7.8.3", "@babel/types@^7.8.6", "@babel/types@^7.9.0", "@babel/types@^7.9.5": - version "7.9.5" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.9.5.tgz#89231f82915a8a566a703b3b20133f73da6b9444" - integrity sha512-XjnvNqenk818r5zMaba+sLQjnbda31UfUURv3ei0qPQw4u+j2jMyJ5b11y8ZHYTRSI3NnInQkkkRT4fLqqPdHg== +"@babel/types@^7.16.7", "@babel/types@^7.17.0": + version "7.17.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.17.0.tgz#a826e368bccb6b3d84acd76acad5c0d87342390b" + integrity sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw== dependencies: - "@babel/helper-validator-identifier" "^7.9.5" - lodash "^4.17.13" + "@babel/helper-validator-identifier" "^7.16.7" to-fast-properties "^2.0.0" "@istanbuljs/schema@^0.1.2": - version "0.1.2" - resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.2.tgz#26520bf09abe4a5644cd5414e37125a8954241dd" - integrity sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw== + version "0.1.3" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== + +"@jridgewell/resolve-uri@^3.0.3": + version "3.0.5" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz#68eb521368db76d040a6315cdb24bf2483037b9c" + integrity sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew== + +"@jridgewell/sourcemap-codec@^1.4.10": + version "1.4.11" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz#771a1d8d744eeb71b6adb35808e1a6c7b9b8c8ec" + integrity sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg== + +"@jridgewell/trace-mapping@^0.3.0": + version "0.3.4" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz#f6a0832dffd5b8a6aaa633b7d9f8e8e94c83a0c3" + integrity sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" "@microsoft/ads-extension-telemetry@^1.1.5": version "1.1.5" @@ -211,31 +244,31 @@ istanbul-reports "^3.0.0" mocha "^5.2.0" -"@nodelib/fs.scandir@2.1.3": - version "2.1.3" - resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz#3a582bdb53804c6ba6d146579c46e52130cf4a3b" - integrity sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw== +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== dependencies: - "@nodelib/fs.stat" "2.0.3" + "@nodelib/fs.stat" "2.0.5" run-parallel "^1.1.9" -"@nodelib/fs.stat@2.0.3", "@nodelib/fs.stat@^2.0.2": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz#34dc5f4cabbc720f4e60f75a747e7ecd6c175bd3" - integrity sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA== +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== "@nodelib/fs.walk@^1.2.3": - version "1.2.4" - resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz#011b9202a70a6366e436ca5c065844528ab04976" - integrity sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ== + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== dependencies: - "@nodelib/fs.scandir" "2.1.3" + "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@sinonjs/commons@^1", "@sinonjs/commons@^1.6.0", "@sinonjs/commons@^1.7.0", "@sinonjs/commons@^1.7.2": - version "1.8.0" - resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.0.tgz#c8d68821a854c555bba172f3b06959a0039b236d" - integrity sha512-wEj54PfsZ5jGSwMX68G8ZXFawcSglQSXqCftWX3ec8MDUzQdHgcKvw97awHbY0efQEL5iKUOAmmVtoYgmrSG4Q== +"@sinonjs/commons@^1.6.0", "@sinonjs/commons@^1.7.0", "@sinonjs/commons@^1.8.1": + version "1.8.3" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.3.tgz#3802ddd21a50a949b6721ddd72da36e67e7f1b2d" + integrity sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ== dependencies: type-detect "4.0.8" @@ -246,18 +279,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@sinonjs/formatio@^5.0.1": - version "5.0.1" - resolved "https://registry.yarnpkg.com/@sinonjs/formatio/-/formatio-5.0.1.tgz#f13e713cb3313b1ab965901b01b0828ea6b77089" - integrity sha512-KaiQ5pBf1MpS09MuA0kp6KBQt2JUOQycqVG1NZXvzeaXe5LGFqAKueIS0bw4w0P9r7KuBSVdUk5QjXsUdu2CxQ== - dependencies: - "@sinonjs/commons" "^1" - "@sinonjs/samsam" "^5.0.2" - -"@sinonjs/samsam@^5.0.2", "@sinonjs/samsam@^5.0.3": - version "5.0.3" - resolved "https://registry.yarnpkg.com/@sinonjs/samsam/-/samsam-5.0.3.tgz#86f21bdb3d52480faf0892a480c9906aa5a52938" - integrity sha512-QucHkc2uMJ0pFGjJUDP3F9dq5dx8QIaqISl9QgwLOh6P9yv877uONPGXh/OH/0zmM3tW1JjuJltAZV2l7zU+uQ== +"@sinonjs/samsam@^5.3.1": + version "5.3.1" + resolved "https://registry.yarnpkg.com/@sinonjs/samsam/-/samsam-5.3.1.tgz#375a45fe6ed4e92fca2fb920e007c48232a6507f" + integrity sha512-1Hc0b1TtyfBu8ixF/tpfSHTVWKwCBLY4QJbkgnE7HcwyvT2xArDxb4K7dMgqRm3szI+LJbzmW/s4xxEhv6hwDg== dependencies: "@sinonjs/commons" "^1.6.0" lodash.get "^4.4.2" @@ -281,21 +306,21 @@ integrity sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ== "@types/node@*": - version "16.6.0" - resolved "https://registry.yarnpkg.com/@types/node/-/node-16.6.0.tgz#0d5685f85066f94e97f19e8a67fe003c5fadacc4" - integrity sha512-OyiZPohMMjZEYqcVo/UJ04GyAxXOJEZO/FpzyXxcH4r/ArrVoXHf4MbUrkLp0Tz7/p1mMKpo5zJ6ZHl8XBNthQ== + version "17.0.21" + resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.21.tgz#864b987c0c68d07b4345845c3e63b75edd143644" + integrity sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ== "@types/sinon@^9.0.4": - version "9.0.4" - resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-9.0.4.tgz#e934f904606632287a6e7f7ab0ce3f08a0dad4b1" - integrity sha512-sJmb32asJZY6Z2u09bl0G2wglSxDlROlAejCjsnor+LzBMz17gu8IU7vKC/vWDnv9zEq2wqADHVXFjf4eE8Gdw== + version "9.0.11" + resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-9.0.11.tgz#7af202dda5253a847b511c929d8b6dda170562eb" + integrity sha512-PwP4UY33SeeVKodNE37ZlOsR9cReypbMJOhZ7BVE0lB+Hix3efCOxiJWiE5Ia+yL9Cn2Ch72EjFTRze8RZsNtg== dependencies: "@types/sinonjs__fake-timers" "*" "@types/sinonjs__fake-timers@*": - version "6.0.1" - resolved "https://registry.yarnpkg.com/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-6.0.1.tgz#681df970358c82836b42f989188d133e218c458e" - integrity sha512-yYezQwGWty8ziyYLdZjwxyMb0CZR49h8JALHGrxjQHWlqGgc8kLdHEgWrgL0uZ29DMvEVBDnHU2Wg36zKSIUtA== + version "8.1.1" + resolved "https://registry.yarnpkg.com/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.1.tgz#b49c2c70150141a15e0fa7e79cf1f92a72934ce3" + integrity sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g== "@types/which@^2.0.1": version "2.0.1" @@ -303,14 +328,14 @@ integrity sha512-Jjakcv8Roqtio6w1gr0D7y6twbhx6gGgFGF5BLwajPpnOIOxFkakFhCq+LmyyeAz7BX6ULrjBOxdKaCDy+4+dQ== "@types/xml-formatter@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@types/xml-formatter/-/xml-formatter-1.1.0.tgz#f7cde70ec33d7b044029b6b6c2f6e69d270ced63" - integrity sha512-1Z8XdMUQ3mLsAwqBzKUea2IgDeLOwvgEWevUHhcu3aF6K0KqeGPRlwEYmVy3wGiaepZdcqsiCuUbNhrU4bIJog== + version "1.2.0" + resolved "https://registry.yarnpkg.com/@types/xml-formatter/-/xml-formatter-1.2.0.tgz#f1a98b2f99f8021304d58d7cc89f73e6515da450" + integrity sha512-hTJriFFYEHKMQXP3/dTxL9f1LbqZ/f6cJ/T77znGGFtet/9+9IqHWV2j4TH3OR/HRZ2ucv/c6in0tdmYwGHdYg== "@types/xmldom@^0.1.29": - version "0.1.29" - resolved "https://registry.yarnpkg.com/@types/xmldom/-/xmldom-0.1.29.tgz#c4428b0ca86d3b881475726fd94980b38a27c381" - integrity sha1-xEKLDKhtO4gUdXJv2UmAs4onw4E= + version "0.1.31" + resolved "https://registry.yarnpkg.com/@types/xmldom/-/xmldom-0.1.31.tgz#519b647cfc66debf82cdf50e49763c8fdee553d6" + integrity sha512-bVy7s0nvaR5D1mT1a8ZkByHWNOGb6Vn4yi5TWhEdmyKlAG+08SA7Md6+jH+tYmMLueAwNeWvHHpeKrr6S4c4BA== ansi-regex@^3.0.0: version "3.0.1" @@ -356,10 +381,23 @@ async-listener@^0.6.0: semver "^5.3.0" shimmer "^1.1.0" +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= + +axios@^0.27.2: + version "0.27.2" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.27.2.tgz#207658cc8621606e586c85db4b41a750e756d972" + integrity sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ== + dependencies: + follow-redirects "^1.14.9" + form-data "^4.0.0" + balanced-match@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" - integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== brace-expansion@^1.1.7: version "1.1.11" @@ -381,11 +419,27 @@ browser-stdout@1.3.1: resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== +browserslist@^4.17.5: + version "4.20.2" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.20.2.tgz#567b41508757ecd904dab4d1c646c612cd3d4f88" + integrity sha512-CQOBCqp/9pDvDbx3xfMi+86pr4KXIf2FDkTTdeuYw8OxS9t898LA1Khq57gtufFILXpfgsSx5woNgsBgvGjpsA== + dependencies: + caniuse-lite "^1.0.30001317" + electron-to-chromium "^1.4.84" + escalade "^3.1.1" + node-releases "^2.0.2" + picocolors "^1.0.0" + callsite@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20" integrity sha1-KAOY5dZkvXQDi28JBRU+borxvCA= +caniuse-lite@^1.0.30001317: + version "1.0.30001319" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001319.tgz#eb4da4eb3ecdd409f7ba1907820061d56096e88f" + integrity sha512-xjlIAFHucBRSMUo1kb5D4LYgcN1M45qdKP++lhqowDpwJwGkpIRTt5qQqnhxjj1vHcI7nrJxWhCC1ATrCEBTcw== + chalk@^2.0.0: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" @@ -395,7 +449,7 @@ chalk@^2.0.0: escape-string-regexp "^1.0.5" supports-color "^5.3.0" -charenc@~0.0.1: +charenc@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc= @@ -426,6 +480,13 @@ color-name@1.1.3: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + commander@2.15.1: version "2.15.1" resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f" @@ -445,13 +506,13 @@ continuation-local-storage@^3.2.1: emitter-listener "^1.1.1" convert-source-map@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" - integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA== + version "1.8.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" + integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== dependencies: safe-buffer "~5.1.1" -crypt@~0.0.1: +crypt@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs= @@ -470,24 +531,17 @@ debug@^2.2.0: dependencies: ms "2.0.0" -debug@^3.1.0: - version "3.2.6" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" - integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== - dependencies: - ms "^2.1.1" - debug@^4.1.0, debug@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" - integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== + version "4.3.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" + integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== dependencies: - ms "^2.1.1" + ms "2.1.2" decache@^4.4.0: - version "4.5.1" - resolved "https://registry.yarnpkg.com/decache/-/decache-4.5.1.tgz#94a977a88a4188672c96550ec4889582ceecdf49" - integrity sha512-5J37nATc6FmOTLbcsr9qx7Nm28qQyg1SK4xyEHqM0IBkNhWFp0Sm+vKoWYHD8wq+OUEb9jLyaKFfzzd1A9hcoA== + version "4.6.1" + resolved "https://registry.yarnpkg.com/decache/-/decache-4.6.1.tgz#5928bfab97a6fcf22a65047a3d07999af36efaf0" + integrity sha512-ohApBM8u9ygepJCjgBrEZSSxPjc0T/PJkD+uNyxXPkqudyUpdXpwJYp0VISm2WrPVzASU6DZyIi6BWdyw7uJ2Q== dependencies: callsite "^1.0.0" @@ -498,6 +552,11 @@ default-require-extensions@^3.0.0: dependencies: strip-bom "^4.0.0" +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= + diagnostic-channel-publishers@^0.3.3: version "0.3.5" resolved "https://registry.yarnpkg.com/diagnostic-channel-publishers/-/diagnostic-channel-publishers-0.3.5.tgz#a84a05fd6cc1d7619fdd17791c17e540119a7536" @@ -520,6 +579,11 @@ diff@^4.0.2: resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== +electron-to-chromium@^1.4.84: + version "1.4.89" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.89.tgz#33c06592812a17a7131873f4596579084ce33ff8" + integrity sha512-z1Axg0Fu54fse8wN4fd+GAINdU5mJmLtcl6bqIcYyzNVGONcfHAeeJi88KYMQVKalhXlYuVPzKkFIU5VD0raUw== + emitter-listener@^1.0.1, emitter-listener@^1.1.1: version "1.1.2" resolved "https://registry.yarnpkg.com/emitter-listener/-/emitter-listener-1.1.2.tgz#56b140e8f6992375b3d7cb2cab1cc7432d9632e8" @@ -527,15 +591,20 @@ emitter-listener@^1.0.1, emitter-listener@^1.1.1: dependencies: shimmer "^1.2.0" +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + escape-string-regexp@1.0.5, escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= fast-glob@^3.2.7: - version "3.2.7" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.7.tgz#fd6cb7a2d7e9aa7a7846111e85a196d6b2f766a1" - integrity sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q== + version "3.2.11" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9" + integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew== dependencies: "@nodelib/fs.stat" "^2.0.2" "@nodelib/fs.walk" "^1.2.3" @@ -544,9 +613,9 @@ fast-glob@^3.2.7: micromatch "^4.0.4" fastq@^1.6.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.8.0.tgz#550e1f9f59bbc65fe185cb6a9b4d95357107f481" - integrity sha512-SMIZoZdLh/fgofivvIkmknUXyPnvxRE3DhtZ5Me3Mrsk5gyPL42F0xr51TdRXskBxHfMp+07bcYzfsYEsSQA9Q== + version "1.13.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" + integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw== dependencies: reusify "^1.0.4" @@ -557,6 +626,20 @@ fill-range@^7.0.1: dependencies: to-regex-range "^5.0.1" +follow-redirects@^1.14.9: + version "1.15.0" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.0.tgz#06441868281c86d0dda4ad8bdaead2d02dca89d4" + integrity sha512-aExlJShTV4qOUOL7yF1U5tvLCB0xQuudbf6toyYA0E/acBNw71mvjFTnLaRp50aQaYocMR0a/RMMBIHeZnGyjQ== + +form-data@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + fs-extra@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-5.0.0.tgz#414d0110cdd06705734d055652c5411260c31abd" @@ -571,10 +654,10 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= -gensync@^1.0.0-beta.1: - version "1.0.0-beta.1" - resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269" - integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg== +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== glob-parent@^5.1.2: version "5.1.2" @@ -613,9 +696,9 @@ globals@^11.1.0: integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== graceful-fs@^4.1.2, graceful-fs@^4.1.6: - version "4.2.8" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a" - integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg== + version "4.2.9" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.9.tgz#041b05df45755e587a24942279b9d113146e1c96" + integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ== growl@1.10.5: version "1.10.5" @@ -655,7 +738,7 @@ inherits@2: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== -is-buffer@~1.1.1: +is-buffer@~1.1.6: version "1.1.6" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== @@ -666,9 +749,9 @@ is-extglob@^2.1.1: integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= is-glob@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" - integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== dependencies: is-extglob "^2.1.1" @@ -693,9 +776,9 @@ istanbul-lib-coverage@^2.0.5: integrity sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA== istanbul-lib-coverage@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz#f5944a37c70b550b02a78a5c3b2055b280cec8ec" - integrity sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg== + version "3.2.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3" + integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== istanbul-lib-hook@^3.0.0: version "3.0.0" @@ -705,14 +788,11 @@ istanbul-lib-hook@^3.0.0: append-transform "^2.0.0" istanbul-lib-instrument@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.1.tgz#61f13ac2c96cfefb076fe7131156cc05907874e6" - integrity sha512-imIchxnodll7pvQBYOqUu88EufLCU56LMeFPZZM/fJZ1irYcYdqroaV+ACK1Ila8ls09iEYArp+nqyC6lW1Vfg== + version "4.0.3" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz#873c6fff897450118222774696a3f28902d77c1d" + integrity sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ== dependencies: "@babel/core" "^7.7.5" - "@babel/parser" "^7.7.5" - "@babel/template" "^7.7.4" - "@babel/traverse" "^7.7.4" "@istanbuljs/schema" "^0.1.2" istanbul-lib-coverage "^3.0.0" semver "^6.3.0" @@ -738,9 +818,9 @@ istanbul-lib-source-maps@^3.0.6: source-map "^0.6.1" istanbul-reports@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.0.2.tgz#d593210e5000683750cb09fc0644e4b6e27fd53b" - integrity sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw== + version "3.1.4" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.4.tgz#1b6f068ecbc6c331040aab5741991273e609e40c" + integrity sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw== dependencies: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" @@ -756,9 +836,9 @@ jsesc@^2.5.1: integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== json5@^2.1.2: - version "2.1.3" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43" - integrity sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA== + version "2.2.0" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3" + integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA== dependencies: minimist "^1.2.5" @@ -770,16 +850,16 @@ jsonfile@^4.0.0: graceful-fs "^4.1.6" just-extend@^4.0.2: - version "4.1.0" - resolved "https://registry.yarnpkg.com/just-extend/-/just-extend-4.1.0.tgz#7278a4027d889601640ee0ce0e5a00b992467da4" - integrity sha512-ApcjaOdVTJ7y4r08xI5wIqpvwS48Q0PBG4DJROcEkH1f8MdAiNFyFxz3xoL0LWAVwjrwPYZdVHHxhRHcx/uGLA== + version "4.2.1" + resolved "https://registry.yarnpkg.com/just-extend/-/just-extend-4.2.1.tgz#ef5e589afb61e5d66b24eca749409a8939a8c744" + integrity sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg== lodash.get@^4.4.2: version "4.4.2" resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk= -lodash@^4.16.4, lodash@^4.17.13, lodash@^4.17.4: +lodash@^4.17.15, lodash@^4.17.4: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -800,20 +880,20 @@ make-dir@^2.1.0: semver "^5.6.0" make-dir@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.0.2.tgz#04a1acbf22221e1d6ef43559f43e05a90dbb4392" - integrity sha512-rYKABKutXa6vXTXhoV18cBE7PaewPXHe/Bdq4v+ZLMhxbWApkFFplT0LcbMW+6BbjnQXzZ/sAvSE/JdguApG5w== + version "3.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" + integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== dependencies: semver "^6.0.0" md5@^2.1.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/md5/-/md5-2.2.1.tgz#53ab38d5fe3c8891ba465329ea23fac0540126f9" - integrity sha1-U6s41f48iJG6RlMp6iP6wFQBJvk= + version "2.3.0" + resolved "https://registry.yarnpkg.com/md5/-/md5-2.3.0.tgz#c3da9a6aae3a30b46b7b0c349b87b110dc3bda4f" + integrity sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g== dependencies: - charenc "~0.0.1" - crypt "~0.0.1" - is-buffer "~1.1.1" + charenc "0.0.2" + crypt "0.0.2" + is-buffer "~1.1.6" merge2@^1.3.0: version "1.4.1" @@ -828,13 +908,32 @@ micromatch@^4.0.4: braces "^3.0.1" picomatch "^2.2.3" -minimatch@3.0.4, minimatch@^3.0.4: +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.12: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +minimatch@3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== dependencies: brace-expansion "^1.1.7" +minimatch@^3.0.4: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + minimist@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" @@ -871,12 +970,12 @@ mocha-junit-reporter@^1.17.0: xml "^1.0.0" mocha-multi-reporters@^1.1.7: - version "1.1.7" - resolved "https://registry.yarnpkg.com/mocha-multi-reporters/-/mocha-multi-reporters-1.1.7.tgz#cc7f3f4d32f478520941d852abb64d9988587d82" - integrity sha1-zH8/TTL0eFIJQdhSq7ZNmYhYfYI= + version "1.5.1" + resolved "https://registry.yarnpkg.com/mocha-multi-reporters/-/mocha-multi-reporters-1.5.1.tgz#c73486bed5519e1d59c9ce39ac7a9792600e5676" + integrity sha512-Yb4QJOaGLIcmB0VY7Wif5AjvLMUFAdV57D2TWEva1Y0kU/3LjKpeRVmlMIfuO1SVbauve459kgtIizADqxMWPg== dependencies: - debug "^3.1.0" - lodash "^4.16.4" + debug "^4.1.1" + lodash "^4.17.15" mocha@^5.2.0: version "5.2.0" @@ -900,15 +999,15 @@ ms@2.0.0: resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= -ms@^2.1.1: +ms@2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -nise@^4.0.1: - version "4.0.4" - resolved "https://registry.yarnpkg.com/nise/-/nise-4.0.4.tgz#d73dea3e5731e6561992b8f570be9e363c4512dd" - integrity sha512-bTTRUNlemx6deJa+ZyoCUTRvH3liK5+N6VQZ4NIw90AgDXY6iPnsqplNFf6STcj+ePk0H/xqxnP75Lr0J0Fq3A== +nise@^4.0.4: + version "4.1.0" + resolved "https://registry.yarnpkg.com/nise/-/nise-4.1.0.tgz#8fb75a26e90b99202fa1e63f448f58efbcdedaf6" + integrity sha512-eQMEmGN/8arp0xsvGoQ+B1qvSkR73B1nWSCh7nOt5neMCtwcQVYQGdzQMhcNscktTsWB54xnlSQFzOAPJD8nXA== dependencies: "@sinonjs/commons" "^1.7.0" "@sinonjs/fake-timers" "^6.0.0" @@ -916,6 +1015,11 @@ nise@^4.0.1: just-extend "^4.0.2" path-to-regexp "^1.7.0" +node-releases@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.2.tgz#7139fe71e2f4f11b47d4d2986aaf8c48699e0c01" + integrity sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg== + once@^1.3.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -928,11 +1032,6 @@ path-is-absolute@^1.0.0: resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= -path-parse@^1.0.6: - version "1.0.7" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" - integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== - path-to-regexp@^1.7.0: version "1.8.0" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a" @@ -940,10 +1039,15 @@ path-to-regexp@^1.7.0: dependencies: isarray "0.0.1" +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + picomatch@^2.2.3: - version "2.3.0" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972" - integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw== + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== pify@^4.0.1: version "4.0.1" @@ -962,17 +1066,15 @@ promisify-child-process@^3.1.1: dependencies: "@babel/runtime" "^7.1.5" -regenerator-runtime@^0.13.4: - version "0.13.5" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz#d878a1d094b4306d10b9096484b33ebd55e26697" - integrity sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA== +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== -resolve@^1.3.2: - version "1.13.1" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.13.1.tgz#be0aa4c06acd53083505abb35f4d66932ab35d16" - integrity sha512-CxqObCX8K8YtAhOBRg+lrcdn+LK+WYOS8tSjqSFbjtrI5PnS63QPhZl4+yKfrU9tdsbMu9Anr/amegT87M9Z6w== - dependencies: - path-parse "^1.0.6" +regenerator-runtime@^0.13.4: + version "0.13.9" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" + integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== reusify@^1.0.4: version "1.0.4" @@ -987,9 +1089,11 @@ rimraf@^2.6.3: glob "^7.1.3" run-parallel@^1.1.9: - version "1.1.9" - resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.9.tgz#c9dd3a7cf9f4b2c4b6244e173a6ed866e61dd679" - integrity sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q== + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" safe-buffer@~5.1.1: version "5.1.2" @@ -1063,16 +1167,15 @@ should@^13.2.1: should-util "^1.0.0" sinon@^9.0.2: - version "9.0.2" - resolved "https://registry.yarnpkg.com/sinon/-/sinon-9.0.2.tgz#b9017e24633f4b1c98dfb6e784a5f0509f5fd85d" - integrity sha512-0uF8Q/QHkizNUmbK3LRFqx5cpTttEVXudywY9Uwzy8bTfZUhljZ7ARzSxnRHWYWtVTeh4Cw+tTb3iU21FQVO9A== + version "9.2.4" + resolved "https://registry.yarnpkg.com/sinon/-/sinon-9.2.4.tgz#e55af4d3b174a4443a8762fa8421c2976683752b" + integrity sha512-zljcULZQsJxVra28qIAL6ow1Z9tpattkCTEJR4RBP3TGc00FcttsP5pK284Nas5WjMZU5Yzy3kAIp3B3KRf5Yg== dependencies: - "@sinonjs/commons" "^1.7.2" + "@sinonjs/commons" "^1.8.1" "@sinonjs/fake-timers" "^6.0.1" - "@sinonjs/formatio" "^5.0.1" - "@sinonjs/samsam" "^5.0.3" + "@sinonjs/samsam" "^5.3.1" diff "^4.0.2" - nise "^4.0.1" + nise "^4.0.4" supports-color "^7.1.0" source-map@^0.5.0: @@ -1117,9 +1220,9 @@ supports-color@^5.3.0: has-flag "^3.0.0" supports-color@^7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1" - integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g== + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== dependencies: has-flag "^4.0.0" @@ -1155,16 +1258,16 @@ universalify@^0.1.0: integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== vscode-extension-telemetry@^0.1.6: - version "0.1.6" - resolved "https://registry.yarnpkg.com/vscode-extension-telemetry/-/vscode-extension-telemetry-0.1.6.tgz#048b70c93243413036a8315cda493b8e7342980c" - integrity sha512-rbzSg7k4NnsCdF4Lz0gI4jl3JLXR0hnlmfFgsY8CSDYhXgdoIxcre8jw5rjkobY0xhSDhbG7xCjP8zxskySJ/g== + version "0.1.7" + resolved "https://registry.yarnpkg.com/vscode-extension-telemetry/-/vscode-extension-telemetry-0.1.7.tgz#18389bc24127c89dade29cd2b71ba69a6ee6ad26" + integrity sha512-pZuZTHO9OpsrwlerOKotWBRLRYJ53DobYb7aWiRAXjlqkuqE+YJJaP+2WEy8GrLIF1EnitXTDMaTAKsmLQ5ORQ== dependencies: applicationinsights "1.7.4" -vscode-jsonrpc@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-5.0.1.tgz#9bab9c330d89f43fc8c1e8702b5c36e058a01794" - integrity sha512-JvONPptw3GAQGXlVV2utDcHx0BiY34FupW/kI6mZ5x06ER5DdPG/tXWMVHjTNULF5uKPOUUD0SaXg5QaubJL0A== +vscode-jsonrpc@6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-6.0.0.tgz#108bdb09b4400705176b957ceca9e0880e9b6d4e" + integrity sha512-wnJA4BnEjOSyFMvjZdpiOwhSq9uDoK8e/kpRJDTaMYzwlkrhG1fwDIZI94CLsLzlCK5cIbMMtFlJlfR57Lavmg== vscode-languageclient@^5.3.0-next.1: version "5.3.0-next.9" @@ -1175,17 +1278,17 @@ vscode-languageclient@^5.3.0-next.1: vscode-languageserver-protocol "^3.15.0-next.8" vscode-languageserver-protocol@^3.15.0-next.8: - version "3.15.3" - resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.15.3.tgz#3fa9a0702d742cf7883cb6182a6212fcd0a1d8bb" - integrity sha512-zrMuwHOAQRhjDSnflWdJG+O2ztMWss8GqUUB8dXLR/FPenwkiBNkMIJJYfSN6sgskvsF0rHAoBowNQfbyZnnvw== + version "3.16.0" + resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.16.0.tgz#34135b61a9091db972188a07d337406a3cdbe821" + integrity sha512-sdeUoAawceQdgIfTI+sdcwkiK2KU+2cbEYA0agzM2uqaUy2UpnnGHtWTHVEtS0ES4zHU0eMFRGN+oQgDxlD66A== dependencies: - vscode-jsonrpc "^5.0.1" - vscode-languageserver-types "3.15.1" + vscode-jsonrpc "6.0.0" + vscode-languageserver-types "3.16.0" -vscode-languageserver-types@3.15.1: - version "3.15.1" - resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.15.1.tgz#17be71d78d2f6236d414f0001ce1ef4d23e6b6de" - integrity sha512-+a9MPUQrNGRrGU630OGbYVQ+11iOIovjCkqxajPa9w57Sd5ruK8WQNsslzpa0x/QJqC8kRc2DUxWjIFwoNm4ZQ== +vscode-languageserver-types@3.16.0: + version "3.16.0" + resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.16.0.tgz#ecf393fc121ec6974b2da3efb3155644c514e247" + integrity sha512-k8luDIWJWyenLc5ToFQQMaSrqCHiLwyKPHKPQZ5zz21vM+vIVUSvsRpcbiECH4WR88K2XZqc4ScRcZ7nk/jbeA== vscode-nls@^4.1.2: version "4.1.2" @@ -1204,7 +1307,7 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= -xml-formatter@^2.1.0: +xml-formatter@2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/xml-formatter/-/xml-formatter-2.1.0.tgz#ff438be6e2195e480b7525ecd3b06652ed76f390" integrity sha512-t55v5mfpohwKvNbfd8A0FZSZI22//hqXqx3AwRx3mjZel0IEoRM2p1bvVnvNPxHqdqZ0sDjUrBqfHJNbIfE8fw== @@ -1212,9 +1315,9 @@ xml-formatter@^2.1.0: xml-parser-xo "^3.0.0" xml-parser-xo@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/xml-parser-xo/-/xml-parser-xo-3.0.0.tgz#4d46f1962e5100f228b5f73f34c61bb798430195" - integrity sha512-MPPexqXBx48m3OFMQXxo7+RYhG6o6kCGflk4q4oL3uQ0b7d5NDKjHFDwUoozOTPT3WFztT13z3R9Sn0QCTIJcQ== + version "3.2.0" + resolved "https://registry.yarnpkg.com/xml-parser-xo/-/xml-parser-xo-3.2.0.tgz#c633ab55cf1976d6b03ab4a6a85045093ac32b73" + integrity sha512-8LRU6cq+d7mVsoDaMhnkkt3CTtAs4153p49fRo+HIB3I1FD1o5CeXRjRH29sQevIfVJIcPjKSsPU/+Ujhq09Rg== xml@^1.0.0: version "1.0.1" diff --git a/extensions/types/vscode-mssql.d.ts b/extensions/types/vscode-mssql.d.ts index 7510a5c195..feb5d5ae7b 100644 --- a/extensions/types/vscode-mssql.d.ts +++ b/extensions/types/vscode-mssql.d.ts @@ -45,6 +45,11 @@ declare module 'vscode-mssql' { */ readonly azureAccountService: IAzureAccountService; + /** + * Service for accessing Azure Resources functionality + */ + readonly azureResourceService: IAzureResourceService; + /** * Prompts the user to select an existing connection or create a new one, and then returns the result * @param ignoreFocusOut Whether the quickpick prompt ignores focus out (default false) @@ -399,6 +404,13 @@ declare module 'vscode-mssql' { isSignedIn?: boolean; } + export interface IAzureAccountSession { + subscription: azure.subscription.Subscription, + tenantId: string, + account: IAccount, + token: Token + } + export interface TokenKey { /** * Account Key - uniquely identifies an account @@ -437,6 +449,38 @@ declare module 'vscode-mssql' { * Returns an access token for given user and tenant */ getAccountSecurityToken(account: IAccount, tenantId: string | undefined): Promise; + + /** + * Returns Azure subscriptions with tenant and token for each given account + */ + getAccountSessions(account: IAccount): Promise; + } + + export interface IAzureResourceService { + + /** + * Returns Azure resource groups for given subscription + * @param session Azure session + * @returns List of resource groups + */ + getResourceGroups(session: IAzureAccountSession): Promise; + + /** + * Creates or updates a Azure SQL server for given subscription, resource group and location + * @param session Azure session + * @param resourceGroupName resource group name + * @param serverName SQL server name + * @param parameters parameters for the SQL server + * @returns name of the SQL server + */ + createOrUpdateServer(session: IAzureAccountSession, resourceGroupName: string, serverName: string, parameters: azure.sql.Server): Promise; + + /** + * Returns Azure locations for given session + * @param session Azure session + * @returns List of locations + */ + getLocations(session: IAzureAccountSession): Promise; } export const enum TaskExecutionMode { @@ -725,4 +769,462 @@ declare module 'vscode-mssql' { options: { [name: string]: any }; } + + /** + * Namespace for Azure APIs + */ + export namespace azure { + + /** + * Namespace for Azure Subscriptions. Types from @azure/arm-subscriptions module + */ + export namespace subscription { + /** Location information. */ + interface Location { + /** + * The fully qualified ID of the location. For example, /subscriptions/00000000-0000-0000-0000-000000000000/locations/westus. + * NOTE: This property will not be serialized. It can only be populated by the server. + */ + readonly id?: string; + /** + * The subscription ID. + * NOTE: This property will not be serialized. It can only be populated by the server. + */ + readonly subscriptionId?: string; + /** + * The location name. + * NOTE: This property will not be serialized. It can only be populated by the server. + */ + readonly name?: string; + /** + * The display name of the location. + * NOTE: This property will not be serialized. It can only be populated by the server. + */ + readonly displayName?: string; + /** + * The latitude of the location. + * NOTE: This property will not be serialized. It can only be populated by the server. + */ + readonly latitude?: string; + /** + * The longitude of the location. + * NOTE: This property will not be serialized. It can only be populated by the server. + */ + readonly longitude?: string; + } + + /** Subscription information. */ + export interface Subscription { + /** + * The fully qualified ID for the subscription. For example, /subscriptions/00000000-0000-0000-0000-000000000000. + * NOTE: This property will not be serialized. It can only be populated by the server. + */ + readonly id?: string; + /** + * The subscription ID. + * NOTE: This property will not be serialized. It can only be populated by the server. + */ + readonly subscriptionId?: string; + /** + * The subscription display name. + * NOTE: This property will not be serialized. It can only be populated by the server. + */ + readonly displayName?: string; + /** + * The subscription state. Possible values are Enabled, Warned, PastDue, Disabled, and Deleted. + * NOTE: This property will not be serialized. It can only be populated by the server. + */ + readonly state?: SubscriptionState; + /** The subscription policies. */ + subscriptionPolicies?: SubscriptionPolicies; + /** The authorization source of the request. Valid values are one or more combinations of Legacy, RoleBased, Bypassed, Direct and Management. For example, 'Legacy, RoleBased'. */ + authorizationSource?: string; + } + + /** Defines values for SubscriptionState. */ + export type SubscriptionState = 'Enabled' | 'Warned' | 'PastDue' | 'Disabled' | 'Deleted'; + + + /** Subscription policies. */ + export interface SubscriptionPolicies { + /** + * The subscription location placement ID. The ID indicates which regions are visible for a subscription. For example, a subscription with a location placement Id of Public_2014-09-01 has access to Azure public regions. + * NOTE: This property will not be serialized. It can only be populated by the server. + */ + readonly locationPlacementId?: string; + /** + * The subscription quota ID. + * NOTE: This property will not be serialized. It can only be populated by the server. + */ + readonly quotaId?: string; + /** + * The subscription spending limit. + * NOTE: This property will not be serialized. It can only be populated by the server. + */ + readonly spendingLimit?: SpendingLimit; + } + + /** Defines values for SpendingLimit. */ + export type SpendingLimit = 'On' | 'Off' | 'CurrentPeriodOff'; + } + + /** + * Namespace for Azure resources. Types from @azure/arm-resources module + */ + export namespace resources { + export interface ResourceGroup { + /** + * The ID of the resource group. + * NOTE: This property will not be serialized. It can only be populated by the server. + */ + readonly id?: string; + /** + * The name of the resource group. + * NOTE: This property will not be serialized. It can only be populated by the server. + */ + readonly name?: string; + /** + * The type of the resource group. + * NOTE: This property will not be serialized. It can only be populated by the server. + */ + readonly type?: string; + /** The resource group properties. */ + properties?: ResourceGroupProperties; + /** The location of the resource group. It cannot be changed after the resource group has been created. It must be one of the supported Azure locations. */ + location: string; + /** The ID of the resource that manages this resource group. */ + managedBy?: string; + /** The tags attached to the resource group. */ + tags?: { + [propertyName: string]: string; + }; + } + + /** The resource group properties. */ + export interface ResourceGroupProperties { + /** + * The provisioning state. + * NOTE: This property will not be serialized. It can only be populated by the server. + */ + readonly provisioningState?: string; + } + + export interface ResourceGroup { + /** + * The ID of the resource group. + * NOTE: This property will not be serialized. It can only be populated by the server. + */ + readonly id?: string; + /** + * The name of the resource group. + * NOTE: This property will not be serialized. It can only be populated by the server. + */ + readonly name?: string; + /** + * The type of the resource group. + * NOTE: This property will not be serialized. It can only be populated by the server. + */ + readonly type?: string; + /** The resource group properties. */ + properties?: ResourceGroupProperties; + /** The location of the resource group. It cannot be changed after the resource group has been created. It must be one of the supported Azure locations. */ + location: string; + /** The ID of the resource that manages this resource group. */ + managedBy?: string; + /** The tags attached to the resource group. */ + tags?: { + [propertyName: string]: string; + }; + } + + /** The resource group properties. */ + export interface ResourceGroupProperties { + /** + * The provisioning state. + * NOTE: This property will not be serialized. It can only be populated by the server. + */ + readonly provisioningState?: string; + } + } + + /** + * Namespace for Azure SQL APIs. Types from @azure/arm-sql module + */ + export namespace sql { + + /** ARM resource. */ + export interface Resource { + /** + * Resource ID. + * NOTE: This property will not be serialized. It can only be populated by the server. + */ + readonly id?: string; + /** + * Resource name. + * NOTE: This property will not be serialized. It can only be populated by the server. + */ + readonly name?: string; + /** + * Resource type. + * NOTE: This property will not be serialized. It can only be populated by the server. + */ + readonly type?: string; + } + + /** Azure Active Directory identity configuration for a resource. */ + export interface UserIdentity { + /** + * The Azure Active Directory principal id. + * NOTE: This property will not be serialized. It can only be populated by the server. + */ + readonly principalId?: string; + /** + * The Azure Active Directory client id. + * NOTE: This property will not be serialized. It can only be populated by the server. + */ + readonly clientId?: string; + } + + /** + * Defines values for IdentityType. \ + * {@link KnownIdentityType} can be used interchangeably with IdentityType, + * this enum contains the known values that the service supports. + * ### Known values supported by the service + * **None** \ + * **SystemAssigned** \ + * **UserAssigned** \ + * **SystemAssigned,UserAssigned** + */ + export type IdentityType = string; + + /** Azure Active Directory identity configuration for a resource. */ + export interface ResourceIdentity { + /** The resource ids of the user assigned identities to use */ + userAssignedIdentities?: { + [propertyName: string]: UserIdentity; + }; + /** + * The Azure Active Directory principal id. + * NOTE: This property will not be serialized. It can only be populated by the server. + */ + readonly principalId?: string; + /** The identity type. Set this to 'SystemAssigned' in order to automatically create and assign an Azure Active Directory principal for the resource. */ + type?: IdentityType; + /** + * The Azure Active Directory tenant id. + * NOTE: This property will not be serialized. It can only be populated by the server. + */ + readonly tenantId?: string; + } + + /** ARM tracked top level resource. */ + export type TrackedResource = Resource & { + /** Resource location. */ + location: string; + /** Resource tags. */ + tags?: { + [propertyName: string]: string; + }; + }; + + /** An Azure SQL Database server. */ + export type Server = TrackedResource & { + /** The Azure Active Directory identity of the server. */ + identity?: ResourceIdentity; + /** + * Kind of sql server. This is metadata used for the Azure portal experience. + * NOTE: This property will not be serialized. It can only be populated by the server. + */ + readonly kind?: string; + /** Administrator username for the server. Once created it cannot be changed. */ + administratorLogin?: string; + /** The administrator login password (required for server creation). */ + administratorLoginPassword?: string; + /** The version of the server. */ + version?: string; + /** + * The state of the server. + * NOTE: This property will not be serialized. It can only be populated by the server. + */ + readonly state?: string; + /** + * The fully qualified domain name of the server. + * NOTE: This property will not be serialized. It can only be populated by the server. + */ + readonly fullyQualifiedDomainName?: string; + /** + * List of private endpoint connections on a server + * NOTE: This property will not be serialized. It can only be populated by the server. + */ + readonly privateEndpointConnections?: ServerPrivateEndpointConnection[]; + /** Minimal TLS version. Allowed values: '1.0', '1.1', '1.2' */ + minimalTlsVersion?: string; + /** Whether or not public endpoint access is allowed for this server. Value is optional but if passed in, must be 'Enabled' or 'Disabled' */ + publicNetworkAccess?: ServerNetworkAccessFlag; + /** + * Whether or not existing server has a workspace created and if it allows connection from workspace + * NOTE: This property will not be serialized. It can only be populated by the server. + */ + readonly workspaceFeature?: ServerWorkspaceFeature; + /** The resource id of a user assigned identity to be used by default. */ + primaryUserAssignedIdentityId?: string; + /** The Client id used for cross tenant CMK scenario */ + federatedClientId?: string; + /** A CMK URI of the key to use for encryption. */ + keyId?: string; + /** The Azure Active Directory identity of the server. */ + administrators?: ServerExternalAdministrator; + /** Whether or not to restrict outbound network access for this server. Value is optional but if passed in, must be 'Enabled' or 'Disabled' */ + restrictOutboundNetworkAccess?: ServerNetworkAccessFlag; + }; + + /** A private endpoint connection under a server */ + export interface ServerPrivateEndpointConnection { + /** + * Resource ID. + * NOTE: This property will not be serialized. It can only be populated by the server. + */ + readonly id?: string; + /** + * Private endpoint connection properties + * NOTE: This property will not be serialized. It can only be populated by the server. + */ + readonly properties?: PrivateEndpointConnectionProperties; + } + + /** + * Defines values for ServerNetworkAccessFlag. \ + * {@link KnownServerNetworkAccessFlag} can be used interchangeably with ServerNetworkAccessFlag, + * this enum contains the known values that the service supports. + * ### Known values supported by the service + * **Enabled** \ + * **Disabled** + */ + export type ServerNetworkAccessFlag = string; + + /** + * Defines values for ServerWorkspaceFeature. \ + * {@link KnownServerWorkspaceFeature} can be used interchangeably with ServerWorkspaceFeature, + * this enum contains the known values that the service supports. + * ### Known values supported by the service + * **Connected** \ + * **Disconnected** + */ + export type ServerWorkspaceFeature = string; + + /** Properties of a active directory administrator. */ + export interface ServerExternalAdministrator { + /** Type of the sever administrator. */ + administratorType?: AdministratorType; + /** Principal Type of the sever administrator. */ + principalType?: PrincipalType; + /** Login name of the server administrator. */ + login?: string; + /** SID (object ID) of the server administrator. */ + sid?: string; + /** Tenant ID of the administrator. */ + tenantId?: string; + /** Azure Active Directory only Authentication enabled. */ + azureADOnlyAuthentication?: boolean; + } + + + /** Properties of a private endpoint connection. */ + export interface PrivateEndpointConnectionProperties { + /** Private endpoint which the connection belongs to. */ + privateEndpoint?: PrivateEndpointProperty; + /** Connection state of the private endpoint connection. */ + privateLinkServiceConnectionState?: PrivateLinkServiceConnectionStateProperty; + /** + * State of the private endpoint connection. + * NOTE: This property will not be serialized. It can only be populated by the server. + */ + readonly provisioningState?: PrivateEndpointProvisioningState; + } + + /** + * Defines values for AdministratorType. \ + * {@link KnownAdministratorType} can be used interchangeably with AdministratorType, + * this enum contains the known values that the service supports. + * ### Known values supported by the service + * **ActiveDirectory** + */ + export type AdministratorType = string; + + /** + * Defines values for PrincipalType. \ + * {@link KnownPrincipalType} can be used interchangeably with PrincipalType, + * this enum contains the known values that the service supports. + * ### Known values supported by the service + * **User** \ + * **Group** \ + * **Application** + */ + export type PrincipalType = string; + + export interface PrivateEndpointProperty { + /** Resource id of the private endpoint. */ + id?: string; + } + + export interface PrivateLinkServiceConnectionStateProperty { + /** The private link service connection status. */ + status: PrivateLinkServiceConnectionStateStatus; + /** The private link service connection description. */ + description: string; + /** + * The actions required for private link service connection. + * NOTE: This property will not be serialized. It can only be populated by the server. + */ + readonly actionsRequired?: PrivateLinkServiceConnectionStateActionsRequire; + } + + /** + * Defines values for PrivateEndpointProvisioningState. \ + * {@link KnownPrivateEndpointProvisioningState} can be used interchangeably with PrivateEndpointProvisioningState, + * this enum contains the known values that the service supports. + * ### Known values supported by the service + * **Approving** \ + * **Ready** \ + * **Dropping** \ + * **Failed** \ + * **Rejecting** + */ + export type PrivateEndpointProvisioningState = string; + + /** + * Defines values for PrivateLinkServiceConnectionStateStatus. \ + * {@link KnownPrivateLinkServiceConnectionStateStatus} can be used interchangeably with PrivateLinkServiceConnectionStateStatus, + * this enum contains the known values that the service supports. + * ### Known values supported by the service + * **Approved** \ + * **Pending** \ + * **Rejected** \ + * **Disconnected** + */ + export type PrivateLinkServiceConnectionStateStatus = string; + + /** + * Defines values for PrivateLinkServiceConnectionStateActionsRequire. \ + * {@link KnownPrivateLinkServiceConnectionStateActionsRequire} can be used interchangeably with PrivateLinkServiceConnectionStateActionsRequire, + * this enum contains the known values that the service supports. + * ### Known values supported by the service + * **None** + */ + export type PrivateLinkServiceConnectionStateActionsRequire = string; + + export interface PrivateLinkServiceConnectionStateProperty { + /** The private link service connection status. */ + status: PrivateLinkServiceConnectionStateStatus; + /** The private link service connection description. */ + description: string; + /** + * The actions required for private link service connection. + * NOTE: This property will not be serialized. It can only be populated by the server. + */ + + readonly actionsRequired?: PrivateLinkServiceConnectionStateActionsRequire; + } + } + } }