Merge branch 'microsoft:master' into ross/devcontainer.json
This commit is contained in:
Коммит
42823f3aa5
17
CHANGELOG.md
17
CHANGELOG.md
|
@ -2,6 +2,23 @@
|
|||
|
||||
All notable changes to the "Azure Api Management VS Code" extension will be documented in this file.
|
||||
|
||||
## [1.0.8 - 2023-09-12]
|
||||
|
||||
- Fixed loading API Management instances when expanding an Azure subscription
|
||||
|
||||
## [1.0.7 - 2023-09-08]
|
||||
|
||||
- Update api-version to 2019-12-01
|
||||
- Fix issue with policy debugging
|
||||
|
||||
## [1.0.6 - 2023-05-06]
|
||||
|
||||
- Overridding fevents version to move off a vulnerable package
|
||||
|
||||
## [1.0.5 - 2022-06-24]
|
||||
|
||||
- Enable Authorizations in Consumption Sku
|
||||
|
||||
## [1.0.4 - 2022-06-05]
|
||||
|
||||
- Update to latest API Management devops resource kit
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -2,7 +2,7 @@
|
|||
"name": "vscode-apimanagement",
|
||||
"displayName": "Azure API Management",
|
||||
"description": "An Azure API Management extension for Visual Studio Code.",
|
||||
"version": "1.0.6",
|
||||
"version": "1.0.8",
|
||||
"publisher": "ms-azuretools",
|
||||
"icon": "resources/apim-icon-newone.png",
|
||||
"aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217",
|
||||
|
@ -820,7 +820,7 @@
|
|||
"webpack-profile": "webpack --profile --json --mode production > webpack-stats.json && echo Use http://webpack.github.io/analyse to analyze the stats"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@azure/ms-rest-js": "^2.2.0",
|
||||
"@azure/ms-rest-js": "^2.7.0",
|
||||
"@types/fs-extra": "^4.0.3",
|
||||
"@types/gulp": "^4.0.6",
|
||||
"@types/mocha": "^5.2.6",
|
||||
|
|
|
@ -6,7 +6,22 @@
|
|||
import { HttpOperationResponse, ServiceClient } from "@azure/ms-rest-js";
|
||||
import { TokenCredentialsBase } from "@azure/ms-rest-nodeauth";
|
||||
import { createGenericClient } from "vscode-azureextensionui";
|
||||
import { IApimServiceContract, IAuthorizationAccessPolicyContract, IAuthorizationAccessPolicyPropertiesContract, IAuthorizationContract, IAuthorizationLoginLinkRequest, IAuthorizationLoginLinkResponse, IAuthorizationPropertiesContract, IAuthorizationProviderContract, IAuthorizationProviderPropertiesContract, IGatewayApiContract, IGatewayContract, IMasterSubscription, ITokenStoreIdentityProviderContract } from "./contracts";
|
||||
import * as Constants from "../../constants";
|
||||
import {
|
||||
IApimServiceContract,
|
||||
IAuthorizationAccessPolicyContract,
|
||||
IAuthorizationAccessPolicyPropertiesContract,
|
||||
IAuthorizationContract,
|
||||
IAuthorizationLoginLinkRequest,
|
||||
IAuthorizationLoginLinkResponse,
|
||||
IAuthorizationPropertiesContract,
|
||||
IAuthorizationProviderContract,
|
||||
IAuthorizationProviderPropertiesContract,
|
||||
IGatewayApiContract,
|
||||
IGatewayContract,
|
||||
IMasterSubscriptionsSecrets,
|
||||
ITokenStoreIdentityProviderContract
|
||||
} from "./contracts";
|
||||
|
||||
export class ApimService {
|
||||
public baseUrl: string;
|
||||
|
@ -15,7 +30,6 @@ export class ApimService {
|
|||
public subscriptionId: string;
|
||||
public resourceGroup: string;
|
||||
public serviceName: string;
|
||||
private readonly apiVersion: string = "2018-06-01-preview";
|
||||
private readonly authorizationProviderApiVersion: string = "2021-12-01-preview";
|
||||
|
||||
constructor(credentials: TokenCredentialsBase, endPointUrl: string, subscriptionId: string, resourceGroup: string, serviceName: string) {
|
||||
|
@ -31,7 +45,7 @@ export class ApimService {
|
|||
const client: ServiceClient = await createGenericClient(this.credentials);
|
||||
const result: HttpOperationResponse = await client.sendRequest({
|
||||
method: "GET",
|
||||
url: `${this.baseUrl}/gateways?api-version=${this.apiVersion}&$top=100`
|
||||
url: `${this.baseUrl}/gateways?api-version=${Constants.apimApiVersion}&$top=100`
|
||||
});
|
||||
// tslint:disable-next-line: no-unsafe-any
|
||||
return <IGatewayContract[]>(result.parsedBody.value);
|
||||
|
@ -41,7 +55,7 @@ export class ApimService {
|
|||
const client: ServiceClient = await createGenericClient(this.credentials);
|
||||
const result: HttpOperationResponse = await client.sendRequest({
|
||||
method: "GET",
|
||||
url: `${this.baseUrl}/gateways/${gatewayName}/apis?api-version=${this.apiVersion}&$top=100`
|
||||
url: `${this.baseUrl}/gateways/${gatewayName}/apis?api-version=${Constants.apimApiVersion}&$top=100`
|
||||
});
|
||||
// tslint:disable-next-line: no-unsafe-any
|
||||
return <IGatewayApiContract[]>(result.parsedBody.value);
|
||||
|
@ -51,7 +65,7 @@ export class ApimService {
|
|||
const client: ServiceClient = await createGenericClient(this.credentials);
|
||||
const result: HttpOperationResponse = await client.sendRequest({
|
||||
method: "PUT",
|
||||
url: `${this.baseUrl}/gateways/${gatewayName}/apis/${apiName}?api-version=${this.apiVersion}`
|
||||
url: `${this.baseUrl}/gateways/${gatewayName}/apis/${apiName}?api-version=${Constants.apimApiVersion}`
|
||||
});
|
||||
// tslint:disable-next-line: no-unsafe-any
|
||||
return <IGatewayApiContract>(result.parsedBody);
|
||||
|
@ -61,7 +75,7 @@ export class ApimService {
|
|||
const client: ServiceClient = await createGenericClient(this.credentials);
|
||||
await client.sendRequest({
|
||||
method: "DELETE",
|
||||
url: `${this.baseUrl}/gateways/${gatewayName}/apis/${apiName}?api-version=${this.apiVersion}`
|
||||
url: `${this.baseUrl}/gateways/${gatewayName}/apis/${apiName}?api-version=${Constants.apimApiVersion}`
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -72,7 +86,7 @@ export class ApimService {
|
|||
const client: ServiceClient = await createGenericClient(this.credentials);
|
||||
const result: HttpOperationResponse = await client.sendRequest({
|
||||
method: "POST",
|
||||
url: `https://management.azure.com/subscriptions/${this.subscriptionId}/resourceGroups/${this.resourceGroup}/providers/Microsoft.ApiManagement/service/${this.serviceName}/gateways/${gatewayName}/token?api-version=2018-06-01-preview`,
|
||||
url: `https://management.azure.com/subscriptions/${this.subscriptionId}/resourceGroups/${this.resourceGroup}/providers/Microsoft.ApiManagement/service/${this.serviceName}/gateways/${gatewayName}/token?api-version=${Constants.apimApiVersion}`,
|
||||
body: {
|
||||
keyType: keyType,
|
||||
expiry: expiryDate
|
||||
|
@ -82,12 +96,13 @@ export class ApimService {
|
|||
return result.parsedBody.value;
|
||||
}
|
||||
|
||||
public async getSubscriptionMasterkey(): Promise<IMasterSubscription> {
|
||||
public async getSubscriptionMasterkey(): Promise<IMasterSubscriptionsSecrets> {
|
||||
const client: ServiceClient = await createGenericClient(this.credentials);
|
||||
const result: HttpOperationResponse = await client.sendRequest({
|
||||
method: "GET",
|
||||
url: `${this.baseUrl}/subscriptions/master?api-version=${this.apiVersion}`
|
||||
method: "POST",
|
||||
url: `${this.baseUrl}/subscriptions/master/listSecrets?api-version=${Constants.apimApiVersion}`
|
||||
});
|
||||
|
||||
// tslint:disable-next-line: no-unsafe-any
|
||||
return result.parsedBody;
|
||||
}
|
||||
|
@ -241,7 +256,7 @@ export class ApimService {
|
|||
return undefined;
|
||||
}
|
||||
|
||||
// tslint:disable-next-line: no-unsafe-any
|
||||
// tslint:disable-next-line: no-unsafe-any
|
||||
return <IAuthorizationProviderContract>(result.parsedBody);
|
||||
}
|
||||
|
||||
|
@ -260,7 +275,7 @@ export class ApimService {
|
|||
const client: ServiceClient = await createGenericClient(this.credentials);
|
||||
const result: HttpOperationResponse = await client.sendRequest({
|
||||
method: "GET",
|
||||
url: `${this.baseUrl}?api-version=${this.apiVersion}`
|
||||
url: `${this.baseUrl}?api-version=${Constants.apimApiVersion}`
|
||||
});
|
||||
// tslint:disable-next-line:no-any
|
||||
return <IApimServiceContract>(result.parsedBody);
|
||||
|
@ -270,10 +285,10 @@ export class ApimService {
|
|||
const client: ServiceClient = await createGenericClient(this.credentials);
|
||||
const result: HttpOperationResponse = await client.sendRequest({
|
||||
method: "PATCH",
|
||||
url: `${this.baseUrl}?api-version=${this.apiVersion}`,
|
||||
body: { identity : { type: "systemassigned" } }
|
||||
url: `${this.baseUrl}?api-version=${Constants.apimApiVersion}`,
|
||||
body: { identity: { type: "systemassigned" } }
|
||||
});
|
||||
// tslint:disable-next-line:no-any
|
||||
// tslint:disable-next-line:no-any
|
||||
return <IApimServiceContract>(result.parsedBody);
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,21 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
export interface IArmResource {
|
||||
id: string;
|
||||
// tslint:disable-next-line: no-reserved-keywords
|
||||
type: string;
|
||||
name: string;
|
||||
// tslint:disable-next-line:no-any
|
||||
properties: any;
|
||||
}
|
||||
|
||||
export interface IPaged<T> {
|
||||
value: T[];
|
||||
count: number;
|
||||
nextLink?: string;
|
||||
}
|
||||
|
||||
export interface IApimServiceContract {
|
||||
id: string;
|
||||
name: string;
|
||||
|
@ -49,11 +64,16 @@ export interface IGatewayTokenList {
|
|||
}
|
||||
|
||||
export interface IMasterSubscription {
|
||||
id : string;
|
||||
name : string;
|
||||
id: string;
|
||||
name: string;
|
||||
properties: ISubscriptionProperty;
|
||||
}
|
||||
|
||||
export interface IMasterSubscriptionsSecrets {
|
||||
primaryKey: string;
|
||||
secondaryKey: string;
|
||||
}
|
||||
|
||||
export interface ISubscriptionProperty {
|
||||
displayName: string;
|
||||
primaryKey: string;
|
||||
|
|
|
@ -62,7 +62,7 @@ function getManagementUrl(root: IOperationTreeRoot): string {
|
|||
|
||||
async function getDebugGatewayAddressUrl(node: ApiOperationTreeItem): Promise<string> {
|
||||
// tslint:disable-next-line: prefer-template
|
||||
const gatewayUrl : string | undefined = ext.context.globalState.get(node.root.serviceName + gatewayHostName);
|
||||
const gatewayUrl: string | undefined = ext.context.globalState.get(node.root.serviceName + gatewayHostName);
|
||||
if (gatewayUrl !== undefined) {
|
||||
return `wss://${gatewayUrl}/debug-0123456789abcdef`;
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ async function getDebugGatewayAddressUrl(node: ApiOperationTreeItem): Promise<st
|
|||
let gatewayHostNameUl = "";
|
||||
if (hostNameConfigs.length > 1) {
|
||||
const allHostNames = hostNameConfigs.filter((s) => (s.type === "Proxy"));
|
||||
const pick = await ext.ui.showQuickPick(allHostNames.map((s) => { return {label: s.hostName, gateway: s}; }), { canPickMany: false});
|
||||
const pick = await ext.ui.showQuickPick(allHostNames.map((s) => { return { label: s.hostName, gateway: s }; }), { canPickMany: false });
|
||||
gatewayHostNameUl = `wss://${pick.gateway.hostName}/debug-0123456789abcdef`;
|
||||
} else {
|
||||
gatewayHostNameUl = `wss://${hostNameConfigs[0].hostName}/debug-0123456789abcdef`;
|
||||
|
|
|
@ -95,7 +95,7 @@ function getDockerRunCommand(token: string, confEndpoint: string, gatewayName: s
|
|||
}
|
||||
|
||||
function getConfigEndpointUrl(node: GatewayTreeItem): string {
|
||||
return `"https://${node!.root.serviceName}.management.azure-api.net/subscriptions/${node!.root.subscriptionId}/resourceGroups/${node!.root.resourceGroupName}/providers/Microsoft.ApiManagement/service/${node!.root.serviceName}?api-version=2018-06-01-preview"`;
|
||||
return `"https://${node!.root.serviceName}.management.azure-api.net/subscriptions/${node!.root.subscriptionId}/resourceGroups/${node!.root.resourceGroupName}/providers/Microsoft.ApiManagement/service/${node!.root.serviceName}?api-version=${Constants.apimApiVersion}"`;
|
||||
}
|
||||
|
||||
function generateDeploymentYaml(gatewayName: string, gatewayToken: string, gatewayEndpoint: string): string {
|
||||
|
|
|
@ -63,7 +63,7 @@ async function extract(node: ApiTreeItem | ServiceTreeItem, apiName?: string): P
|
|||
},
|
||||
async () => {
|
||||
await azUtils.checkAzInstalled();
|
||||
await dotnetUtils.checkDotnetInstalled();
|
||||
await dotnetUtils.validateDotnetInstalled();
|
||||
await runExtractor(configFile, subscriptionId);
|
||||
}
|
||||
).then(
|
||||
|
@ -104,20 +104,16 @@ async function runExtractor(filePath: string, subscriptionId: string): Promise<v
|
|||
subscriptionId
|
||||
);
|
||||
|
||||
if (await dotnetUtils.checkDotnetVersionInstalled("2.1")) {
|
||||
await cpUtils.executeCommand(
|
||||
ext.outputChannel,
|
||||
workingFolderPath,
|
||||
'dotnet',
|
||||
'apimtemplate.dll',
|
||||
'extract',
|
||||
'--extractorConfig',
|
||||
`"${filePath}"`
|
||||
);
|
||||
} else {
|
||||
window.showInformationMessage(localize("dotnetNotInstalled", ".NET framework 2.1 not installed. Please go to 'https://aka.ms/dotnet-core-applaunch?framework=Microsoft.NETCore.App&framework_version=2.1.0&arch=x64&rid=win10-x64' to download"));
|
||||
throw new Error();
|
||||
}
|
||||
await dotnetUtils.validateDotnetInstalled();
|
||||
await cpUtils.executeCommand(
|
||||
ext.outputChannel,
|
||||
workingFolderPath,
|
||||
'dotnet',
|
||||
'apimtemplate.dll',
|
||||
'extract',
|
||||
'--extractorConfig',
|
||||
`"${filePath}"`
|
||||
);
|
||||
}
|
||||
|
||||
async function askFolder(): Promise<Uri[]> {
|
||||
|
|
|
@ -30,7 +30,7 @@ export enum HttpTriggerDirectionContract {
|
|||
export const HttpTriggerAuthLevelAdmin = "admin";
|
||||
export const FunctionAppKeyLength = 40;
|
||||
export const webAppApiVersion20190801 = "2019-08-01";
|
||||
export const apimApiVersion = "2019-01-01";
|
||||
export const apimApiVersion = "2019-12-01";
|
||||
export const maxTokenValidTimeSpan = 29;
|
||||
export const gatewayHostName = "CustomerHostName";
|
||||
|
||||
|
|
|
@ -7,6 +7,8 @@ import * as request from 'request-promise-native';
|
|||
import * as vscode from 'vscode';
|
||||
import { Breakpoint, Handles, InitializedEvent, Logger, logger, LoggingDebugSession, OutputEvent, Scope, StackFrame, StoppedEvent, TerminatedEvent, Thread, ThreadEvent, Variable } from 'vscode-debugadapter';
|
||||
import { DebugProtocol } from 'vscode-debugprotocol';
|
||||
import { IArmResource, IMasterSubscriptionsSecrets, IPaged } from "../azure/apim/contracts";
|
||||
import * as Constants from "../constants";
|
||||
import { localize } from "../localize";
|
||||
import { createTemporaryFile } from "../utils/fsUtil";
|
||||
import { getBearerToken } from '../utils/requestUtil';
|
||||
|
@ -387,9 +389,9 @@ export class ApimDebugSession extends LoggingDebugSession {
|
|||
}
|
||||
|
||||
private async getMasterSubscriptionKey(managementAddress: string, credential?: TokenCredentialsBase, managementAuth?: string) {
|
||||
const resourceUrl = `${managementAddress}/subscriptions/master?api-version=2019-01-01`;
|
||||
const resourceUrl = `${managementAddress}/subscriptions/master/listSecrets?api-version=${Constants.apimApiVersion}`;
|
||||
const authToken = managementAuth ? managementAuth : await getBearerToken(resourceUrl, "GET", credential!);
|
||||
const subscription: IApimSubscription = await request.get(resourceUrl, {
|
||||
const subscription: IMasterSubscriptionsSecrets = await request.post(resourceUrl, {
|
||||
headers: {
|
||||
Authorization: authToken
|
||||
},
|
||||
|
@ -404,13 +406,13 @@ export class ApimDebugSession extends LoggingDebugSession {
|
|||
}
|
||||
});
|
||||
|
||||
return subscription.properties.primaryKey;
|
||||
return subscription.primaryKey;
|
||||
}
|
||||
|
||||
private async getAvailablePolicies(managementAddress: string, credential?: TokenCredentialsBase, managementAuth?: string) {
|
||||
const resourceUrl = `${managementAddress}/policysnippets?api-version=2019-01-01`;
|
||||
const resourceUrl = `${managementAddress}/policyDescriptions?api-version=${Constants.apimApiVersion}`;
|
||||
const authToken = managementAuth ? managementAuth : await getBearerToken(resourceUrl, "GET", credential!);
|
||||
const snippets: IPolicySnippet[] = await request.get(resourceUrl, {
|
||||
const policyDescriptions: IPaged<IArmResource> = await request.get(resourceUrl, {
|
||||
headers: {
|
||||
Authorization: authToken
|
||||
},
|
||||
|
@ -425,19 +427,7 @@ export class ApimDebugSession extends LoggingDebugSession {
|
|||
}
|
||||
});
|
||||
|
||||
const allPolicies: string[] = [];
|
||||
let index = 0;
|
||||
for (const snippet of snippets) {
|
||||
if (snippet.content !== undefined && snippet.content !== "") {
|
||||
const idx = /[\s>/]/.exec(snippet.content)!.index;
|
||||
allPolicies[index] = snippet.content.substring(1, idx);
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// tslint:disable-next-line: no-unnecessary-local-variable
|
||||
//const allPolicies = snippets.filter(s => s.content !== undefined).map(s => s.content.substring(1, /[\s>/]/.exec(s.content)!.index));
|
||||
return allPolicies;
|
||||
return policyDescriptions.value.map(p => p.name);
|
||||
}
|
||||
|
||||
private findThreadByUiId(id: number): [UiRequest, UiThread] | null {
|
||||
|
@ -515,14 +505,3 @@ export class ApimDebugSession extends LoggingDebugSession {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface IApimSubscription {
|
||||
properties: {
|
||||
primaryKey: string;
|
||||
secondaryKey: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface IPolicySnippet {
|
||||
content: string;
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ export class DebuggerConnection extends EventEmitter {
|
|||
|
||||
public async attach(address: string, key: string, stopOnEntry: boolean) {
|
||||
let connection: WebSocket;
|
||||
return new Promise((resolve, reject) => {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
connection = new WebSocket(`${address}?key=${key}`)
|
||||
.on('error', e => {
|
||||
if (this.connection == null || this.connection === connection) {
|
||||
|
|
|
@ -6,6 +6,7 @@ import { TokenCredentialsBase } from "@azure/ms-rest-nodeauth";
|
|||
import * as path from 'path';
|
||||
import * as request from 'request-promise-native';
|
||||
import { Source } from 'vscode-debugadapter';
|
||||
import * as Constants from "../constants";
|
||||
import { getBearerToken } from '../utils/requestUtil';
|
||||
import { StackFrameScopeContract } from './debuggerConnection';
|
||||
import { PolicyLocation, PolicyMap, PolicyMapper } from './policyMapper';
|
||||
|
@ -143,9 +144,9 @@ export class PolicySource {
|
|||
|
||||
private getPolicyUrl(scopeId: string): string {
|
||||
if (scopeId === StackFrameScopeContract.tenant) {
|
||||
return `${this.managementAddress}/policies/policy?api-version=2019-01-01&format=xml-raw`;
|
||||
return `${this.managementAddress}/policies/policy?api-version=${Constants.apimApiVersion}&format=xml-raw`;
|
||||
} else {
|
||||
return `${this.managementAddress}/${scopeId}/policies/policy?api-version=2019-01-01&format=xml-raw`;
|
||||
return `${this.managementAddress}/${scopeId}/policies/policy?api-version=${Constants.apimApiVersion}&format=xml-raw`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import { HttpOperationResponse, RequestPrepareOptions, ServiceClient } from "@az
|
|||
import { ProgressLocation, window } from "vscode";
|
||||
import { appendExtensionUserAgent, createGenericClient } from "vscode-azureextensionui";
|
||||
import { openApiAcceptHeader, openApiExport, openApiSchema, showSavePromptConfigKey, swaggerAcceptHeader, swaggerExport, swaggerSchema } from "../../../constants";
|
||||
import * as Constants from "../../../constants";
|
||||
import { localize } from "../../../localize";
|
||||
import { IOpenApiImportObject } from "../../../openApi/OpenApiImportObject";
|
||||
import { OpenApiParser } from "../../../openApi/OpenApiParser";
|
||||
|
@ -117,7 +118,7 @@ export class OpenApiEditor extends Editor<ApiTreeItem> {
|
|||
|
||||
private buildAPIExportUrl(context: ApiTreeItem, exportFormat: string) : string {
|
||||
let url = `${context.root.environment.resourceManagerEndpointUrl}/subscriptions/${context.root.subscriptionId}/resourceGroups/${context.root.resourceGroupName}/providers/Microsoft.ApiManagement/service/${context.root.serviceName}/apis/${context.root.apiName}`;
|
||||
url = `${url}?export=true&format=${exportFormat}&api-version=2019-01-01`;
|
||||
url = `${url}?export=true&format=${exportFormat}&api-version=${Constants.apimApiVersion}`;
|
||||
return url;
|
||||
}
|
||||
|
||||
|
|
|
@ -84,7 +84,7 @@ export class OperationConsole {
|
|||
const apimService = new ApimService(root.credentials, root.environment.resourceManagerEndpointUrl, root.subscriptionId, root.resourceGroupName, root.serviceName);
|
||||
const masterSubscription = await apimService.getSubscriptionMasterkey();
|
||||
headers.forEach(header => {
|
||||
requestSummary += `${header}: ${masterSubscription.properties.primaryKey}\n`;
|
||||
requestSummary += `${header}: ${masterSubscription.primaryKey}\n`;
|
||||
});
|
||||
requestSummary += "Ocp-Apim-Trace: true\n";
|
||||
if (consoleOperation.request.body) {
|
||||
|
|
|
@ -19,46 +19,48 @@ export namespace dotnetUtils {
|
|||
}
|
||||
}
|
||||
|
||||
export async function validateDotnetInstalled(actionContext: IActionContext): Promise<void> {
|
||||
if (!await isDotnetInstalled()) {
|
||||
const message: string = localize('dotnetNotInstalled', 'You must have the .NET CLI installed to perform this operation.');
|
||||
export async function validateDotnetInstalled(actionContext?: IActionContext, minVersion: string = "2.1"): Promise<void> {
|
||||
if (!await isDotnetInstalled() || !await checkDotnetVersionInstalled(minVersion)) {
|
||||
const message: string = localize('dotnetNotInstalled', 'You must have the .NET CLI {0} or older installed to perform this operation.', minVersion);
|
||||
|
||||
if (!actionContext.errorHandling.suppressDisplay) {
|
||||
if (!actionContext || !actionContext.errorHandling.suppressDisplay) {
|
||||
// don't wait
|
||||
vscode.window.showErrorMessage(message, DialogResponses.learnMore).then(async (result) => {
|
||||
if (result === DialogResponses.learnMore) {
|
||||
await openUrl('https://aka.ms/AA4ac70');
|
||||
}
|
||||
});
|
||||
actionContext.errorHandling.suppressDisplay = true;
|
||||
}
|
||||
|
||||
throw new Error(message);
|
||||
}
|
||||
}
|
||||
|
||||
export async function checkDotnetInstalled(): Promise<void> {
|
||||
if (!await isDotnetInstalled()) {
|
||||
const message: string = localize('dotnetNotInstalled', 'You must have a .NET Core SDK v2.1.x CLI installed to perform this operation.');
|
||||
|
||||
// don't wait
|
||||
vscode.window.showErrorMessage(message, DialogResponses.learnMore).then(async (result) => {
|
||||
if (result === DialogResponses.learnMore) {
|
||||
await openUrl('https://aka.ms/AA4ac70');
|
||||
if (actionContext) {
|
||||
actionContext.errorHandling.suppressDisplay = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
throw new Error(message);
|
||||
}
|
||||
}
|
||||
|
||||
export async function checkDotnetVersionInstalled(targetVersion: string): Promise<boolean> {
|
||||
const response = await cpUtils.executeCommand(undefined, undefined, 'dotnet', '--list-sdks');
|
||||
const versions = response.split(/\r?\n/);
|
||||
for (const version of versions) {
|
||||
if (version.startsWith(targetVersion)) {
|
||||
return true;
|
||||
function compareVersion(version1: string, version2: string): number {
|
||||
const v1 = version1.split('.').map(parseInt);
|
||||
const v2 = version2.split('.').map(parseInt);
|
||||
for (let i = 0; i < Math.min(v1.length, v2.length); i++) {
|
||||
if (v1[i] > v2[i]) { return 1; }
|
||||
if (v1[i] < v2[i]) { return -1; }
|
||||
}
|
||||
return v1.length === v2.length ? 0 : (v1.length < v2.length ? -1 : 1);
|
||||
}
|
||||
|
||||
async function checkDotnetVersionInstalled(minVersion: string): Promise<boolean> {
|
||||
try {
|
||||
const response = await cpUtils.executeCommand(undefined, undefined, 'dotnet', '--list-runtimes');
|
||||
const versions = response.split(/\r?\n/);
|
||||
for (const version of versions) {
|
||||
const versionNumber = version.split(' ')[1];
|
||||
if (compareVersion(versionNumber, minVersion) >= 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче