From fb8fccb064b159ed3378de3443fee8772b6a513d Mon Sep 17 00:00:00 2001 From: Jun Han Date: Tue, 6 Aug 2024 11:53:57 +0800 Subject: [PATCH 01/12] feat: update per API change for importing ruleset --- src/azure/ApiCenter/ApiCenterService.ts | 34 +++++++++++++++++++++---- src/azure/ApiCenter/contracts.ts | 5 ++++ src/commands/rules/deployRules.ts | 4 +-- src/commands/rules/enableRules.ts | 8 +++--- src/uiStrings.ts | 2 +- 5 files changed, 41 insertions(+), 12 deletions(-) diff --git a/src/azure/ApiCenter/ApiCenterService.ts b/src/azure/ApiCenter/ApiCenterService.ts index 82662ad5..ae277842 100644 --- a/src/azure/ApiCenter/ApiCenterService.ts +++ b/src/azure/ApiCenter/ApiCenterService.ts @@ -4,7 +4,7 @@ import { HttpOperationResponse, RequestPrepareOptions, ServiceClient } from "@az import { ISubscriptionContext } from "@microsoft/vscode-azext-utils"; import { getCredentialForToken } from "../../utils/credentialUtil"; import { APICenterRestAPIs } from "./ApiCenterRestAPIs"; -import { ApiCenter, ApiCenterApi, ApiCenterApiDeployment, ApiCenterApiVersion, ApiCenterApiVersionDefinition, ApiCenterApiVersionDefinitionExport, ApiCenterApiVersionDefinitionImport, ApiCenterEnvironment, ApiCenterRulesetConfig, ApiCenterRulesetExport, ApiCenterRulesetImport } from "./contracts"; +import { ApiCenter, ApiCenterApi, ApiCenterApiDeployment, ApiCenterApiVersion, ApiCenterApiVersionDefinition, ApiCenterApiVersionDefinitionExport, ApiCenterApiVersionDefinitionImport, ApiCenterEnvironment, ApiCenterRulesetConfig, ApiCenterRulesetExport, ApiCenterRulesetImport, ApiCenterRulesetImportResult } from "./contracts"; export class ApiCenterService { private susbcriptionContext: ISubscriptionContext; @@ -226,16 +226,40 @@ export class ApiCenterService { return response.parsedBody; } - public async importRuleset(importPayload: ApiCenterRulesetImport): Promise { + public async importRuleset(importPayload: ApiCenterRulesetImport): Promise { const creds = getCredentialForToken(await this.susbcriptionContext.credentials.getToken()); const client = new ServiceClient(creds); - const options: RequestPrepareOptions = { + let options: RequestPrepareOptions = { method: "POST", url: APICenterRestAPIs.ImportRuleset(this.susbcriptionContext.subscriptionId, this.resourceGroupName, this.apiCenterName, this.apiVersionPreview), body: importPayload }; - const response = await client.sendRequest(options); - return response; + let response = await client.sendRequest(options); + + if (response.status === 202) { + const location = response.headers.get("Location"); + + if (!location) { + return { isSuccessful: false }; + } + + options = { + method: "GET", + url: location, + }; + + const timeout = 30000; // 30 seconds in milliseconds + let startTime = Date.now(); + do { + response = await client.sendRequest(options); + if (response.parsedBody?.status === "Succeeded") { + return { isSuccessful: true }; + } + } while (Date.now() - startTime < timeout); + return { isSuccessful: false }; + } else { + return { isSuccessful: false, message: response.bodyAsText }; + } } public async exportRuleset(): Promise { diff --git a/src/azure/ApiCenter/contracts.ts b/src/azure/ApiCenter/contracts.ts index 0b5563dc..c3c36a2a 100644 --- a/src/azure/ApiCenter/contracts.ts +++ b/src/azure/ApiCenter/contracts.ts @@ -96,6 +96,11 @@ export type ApiCenterRulesetImport = { value: string; }; +export type ApiCenterRulesetImportResult = { + isSuccessful: boolean; + message?: string | null; +}; + export type ApiCenterRulesetExport = { format: string; value: string; diff --git a/src/commands/rules/deployRules.ts b/src/commands/rules/deployRules.ts index a213eee2..a7b60244 100644 --- a/src/commands/rules/deployRules.ts +++ b/src/commands/rules/deployRules.ts @@ -29,9 +29,9 @@ export async function deployRules(context: IActionContext, node: RulesTreeItem) }; const response = await apiCenterService.importRuleset(importPayload); - if (response.status === 200) { + if (response.isSuccessful) { vscode.window.showInformationMessage(vscode.l10n.t(UiStrings.RulesDeployed, node.apiCenter.name)); } else { - vscode.window.showErrorMessage(vscode.l10n.t(UiStrings.FailedToDeployRules, response.bodyAsText ?? `status code ${response.status}`)); + vscode.window.showErrorMessage(vscode.l10n.t(UiStrings.FailedToDeployRules, response.message ?? `Error: ${response.message}`)); } } diff --git a/src/commands/rules/enableRules.ts b/src/commands/rules/enableRules.ts index 39e2a556..c4f902b7 100644 --- a/src/commands/rules/enableRules.ts +++ b/src/commands/rules/enableRules.ts @@ -23,7 +23,7 @@ export async function enableRules(context: IActionContext, node: RulesTreeItem) const resourceGroupName = getResourceGroupFromId(node.apiCenter.id); const apiCenterService = new ApiCenterService(node.parent?.subscription!, resourceGroupName, node.apiCenter.name); - let response = await apiCenterService.createOrUpdateApiCenterRulesetConfig(apiCenterRulesetConfig); + const response = await apiCenterService.createOrUpdateApiCenterRulesetConfig(apiCenterRulesetConfig); if (response.status === 200) { vscode.window.showInformationMessage((vscode.l10n.t(UiStrings.RulesEnabled, node.apiCenter.name))); @@ -42,13 +42,13 @@ export async function enableRules(context: IActionContext, node: RulesTreeItem) value: content, format: "InlineZip", }; - response = await apiCenterService.importRuleset(importPayload); + const importRulesetResponse = await apiCenterService.importRuleset(importPayload); - if (response.status === 200) { + if (importRulesetResponse.isSuccessful) { vscode.window.showInformationMessage(vscode.l10n.t(UiStrings.RulesDeployed, node.apiCenter.name)); node.updateStatusToEnable(); await node.refresh(context); } else { - vscode.window.showErrorMessage(vscode.l10n.t(UiStrings.FailedToDeployRules, response.bodyAsText ?? `status code ${response.status}`)); + vscode.window.showErrorMessage(vscode.l10n.t(UiStrings.FailedToDeployRules, importRulesetResponse.message ?? `Error: ${importRulesetResponse.message}`)); } } diff --git a/src/uiStrings.ts b/src/uiStrings.ts index df19fdb0..158b57ba 100644 --- a/src/uiStrings.ts +++ b/src/uiStrings.ts @@ -107,7 +107,7 @@ export class UiStrings { static readonly FileAlreadyExists = vscode.l10n.t("The file '{0}' already exists. Please input a different name."); static readonly NoRulesFolder = vscode.l10n.t("Rules folder '{0}' is empty. No files to deploy."); static readonly RulesDeployed = vscode.l10n.t("Rules deployed to '{0}'."); - static readonly FailedToDeployRules = vscode.l10n.t("Failed to deploy rules. Error: {0}"); + static readonly FailedToDeployRules = vscode.l10n.t("Failed to deploy rules. {0}"); static readonly RulesEnabled = vscode.l10n.t("API Analysis enabled for '{0}'."); static readonly FailedToEnableRules = vscode.l10n.t("Failed to enable API Analysis. Error: {0}"); static readonly RulesFolderNotEmpty = vscode.l10n.t("The rules folder '{0}' is not empty. Do you want to overwrite the existing files?"); From cf8594ad26b50f10fcb91d2aeda4792106446962 Mon Sep 17 00:00:00 2001 From: Jun Han Date: Tue, 6 Aug 2024 12:08:44 +0800 Subject: [PATCH 02/12] test: update ut --- src/test/unit/commands/rules/enableRules.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/unit/commands/rules/enableRules.test.ts b/src/test/unit/commands/rules/enableRules.test.ts index 64166612..c5d7153d 100644 --- a/src/test/unit/commands/rules/enableRules.test.ts +++ b/src/test/unit/commands/rules/enableRules.test.ts @@ -7,7 +7,7 @@ import * as path from 'path'; import * as sinon from "sinon"; import * as vscode from "vscode"; import { ApiCenterService } from "../../../../azure/ApiCenter/ApiCenterService"; -import { ApiCenter } from "../../../../azure/ApiCenter/contracts"; +import { ApiCenter, ApiCenterRulesetImportResult } from "../../../../azure/ApiCenter/contracts"; import { enableRules } from "../../../../commands/rules/enableRules"; import { RulesTreeItem } from "../../../../tree/rules/RulesTreeItem"; @@ -34,7 +34,7 @@ describe("enableRules", () => { sandbox.stub(path, 'join').returns(__dirname); const showInformationMessage = sandbox.spy(vscode.window, "showInformationMessage"); sandbox.stub(ApiCenterService.prototype, "createOrUpdateApiCenterRulesetConfig").resolves({ status: 200 } as HttpOperationResponse); - sandbox.stub(ApiCenterService.prototype, "importRuleset").resolves({ status: 200 } as HttpOperationResponse); + sandbox.stub(ApiCenterService.prototype, "importRuleset").resolves({ isSuccessful: true } as ApiCenterRulesetImportResult); await enableRules({} as IActionContext, node); sandbox.assert.calledTwice(showInformationMessage); assert.ok(node.isEnabled); From a4a90e00dc9691d6db5fff2aa1db7de3f8c50aec Mon Sep 17 00:00:00 2001 From: Jun Han Date: Tue, 6 Aug 2024 12:41:01 +0800 Subject: [PATCH 03/12] test: basic importRuleset test --- .../azure/ApiCenter/ApiCenterService.test.ts | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/test/unit/azure/ApiCenter/ApiCenterService.test.ts diff --git a/src/test/unit/azure/ApiCenter/ApiCenterService.test.ts b/src/test/unit/azure/ApiCenter/ApiCenterService.test.ts new file mode 100644 index 00000000..74a2727a --- /dev/null +++ b/src/test/unit/azure/ApiCenter/ApiCenterService.test.ts @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +import { ISubscriptionContext } from "@microsoft/vscode-azext-utils"; +import * as sinon from "sinon"; +import { ApiCenterService } from "../../../../azure/ApiCenter/ApiCenterService"; +import { ApiCenterRulesetImport } from "../../../../azure/ApiCenter/contracts"; + +describe("ApiCenterService", () => { + let sandbox: sinon.SinonSandbox; + let subscriptionContext: ISubscriptionContext; + before(() => { + sandbox = sinon.createSandbox(); + }); + beforeEach(() => { + subscriptionContext = { + credentials: { + getToken: sandbox.stub().resolves({ token: 'fake-token' }) + } + } as unknown as ISubscriptionContext; + }); + afterEach(() => { + sandbox.restore(); + }); + it("importRuleset", async () => { + const apiCenterService = new ApiCenterService(subscriptionContext, "fakeResourceGroup", "fakeServiceName"); + + const importPayload: ApiCenterRulesetImport = { + value: "fakeValue", + format: "InlineZip", + }; + const response = await apiCenterService.importRuleset(importPayload); + console.log("response: " + JSON.stringify(response)); + }); +}); From fac838bff523aa98d3c88fae85807227d650669d Mon Sep 17 00:00:00 2001 From: Jun Han Date: Tue, 6 Aug 2024 15:27:40 +0800 Subject: [PATCH 04/12] test: update importRuleset test --- .../azure/ApiCenter/ApiCenterService.test.ts | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/src/test/unit/azure/ApiCenter/ApiCenterService.test.ts b/src/test/unit/azure/ApiCenter/ApiCenterService.test.ts index 74a2727a..8ee94b8b 100644 --- a/src/test/unit/azure/ApiCenter/ApiCenterService.test.ts +++ b/src/test/unit/azure/ApiCenter/ApiCenterService.test.ts @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. +import { HttpHeaders, HttpOperationResponse, ServiceClient } from "@azure/ms-rest-js"; import { ISubscriptionContext } from "@microsoft/vscode-azext-utils"; +import * as assert from "assert"; import * as sinon from "sinon"; import { ApiCenterService } from "../../../../azure/ApiCenter/ApiCenterService"; import { ApiCenterRulesetImport } from "../../../../azure/ApiCenter/contracts"; @@ -21,14 +23,39 @@ describe("ApiCenterService", () => { afterEach(() => { sandbox.restore(); }); - it("importRuleset", async () => { + it("importRuleset succeeded", async () => { + const mockResponse1 = { status: 202 } as HttpOperationResponse; + mockResponse1.headers = new HttpHeaders({ Location: "fakeLocation" }); + const mockResponse2 = { + status: 200, + parsedBody: { status: "Succeeded" }, + } as HttpOperationResponse; + const sendRequestStub = sandbox.stub(ServiceClient.prototype, "sendRequest"); + sendRequestStub.onFirstCall().resolves(mockResponse1); + sendRequestStub.onSecondCall().resolves(mockResponse2); + const apiCenterService = new ApiCenterService(subscriptionContext, "fakeResourceGroup", "fakeServiceName"); + const importPayload: ApiCenterRulesetImport = { + value: "fakeValue", + format: "InlineZip", + }; + + const response = await apiCenterService.importRuleset(importPayload); + + assert.strictEqual(response.isSuccessful, true); + }); + it("importRuleset failed", async () => { + sandbox.stub(ServiceClient.prototype, "sendRequest").resolves({ status: 500, bodyAsText: "error" } as HttpOperationResponse); + const apiCenterService = new ApiCenterService(subscriptionContext, "fakeResourceGroup", "fakeServiceName"); const importPayload: ApiCenterRulesetImport = { value: "fakeValue", format: "InlineZip", }; + const response = await apiCenterService.importRuleset(importPayload); - console.log("response: " + JSON.stringify(response)); + + assert.strictEqual(response.isSuccessful, false); + assert.strictEqual(response.message, "error"); }); }); From ca8020fcf9f6829b05632b876d6492311bef1827 Mon Sep 17 00:00:00 2001 From: Jun Han Date: Tue, 6 Aug 2024 16:13:54 +0800 Subject: [PATCH 05/12] feat: throw error instead of showErrorMessage to log error telemetry --- src/commands/rules/deployRules.ts | 2 +- src/commands/rules/enableRules.ts | 5 ++--- src/test/unit/commands/rules/enableRules.test.ts | 12 +++++++++--- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/commands/rules/deployRules.ts b/src/commands/rules/deployRules.ts index a7b60244..7f00e8ff 100644 --- a/src/commands/rules/deployRules.ts +++ b/src/commands/rules/deployRules.ts @@ -32,6 +32,6 @@ export async function deployRules(context: IActionContext, node: RulesTreeItem) if (response.isSuccessful) { vscode.window.showInformationMessage(vscode.l10n.t(UiStrings.RulesDeployed, node.apiCenter.name)); } else { - vscode.window.showErrorMessage(vscode.l10n.t(UiStrings.FailedToDeployRules, response.message ?? `Error: ${response.message}`)); + throw new Error(vscode.l10n.t(UiStrings.FailedToDeployRules, response.message ?? `Error: ${response.message}`)); } } diff --git a/src/commands/rules/enableRules.ts b/src/commands/rules/enableRules.ts index c4f902b7..cf6930c6 100644 --- a/src/commands/rules/enableRules.ts +++ b/src/commands/rules/enableRules.ts @@ -28,8 +28,7 @@ export async function enableRules(context: IActionContext, node: RulesTreeItem) if (response.status === 200) { vscode.window.showInformationMessage((vscode.l10n.t(UiStrings.RulesEnabled, node.apiCenter.name))); } else { - vscode.window.showErrorMessage(vscode.l10n.t(UiStrings.FailedToEnableRules, response.bodyAsText ?? `status code ${response.status}`)); - return; + throw new Error(vscode.l10n.t(UiStrings.FailedToEnableRules, response.bodyAsText ?? `status code ${response.status}`)); } // Temporary workaround to deploy default rules after enabling rules @@ -49,6 +48,6 @@ export async function enableRules(context: IActionContext, node: RulesTreeItem) node.updateStatusToEnable(); await node.refresh(context); } else { - vscode.window.showErrorMessage(vscode.l10n.t(UiStrings.FailedToDeployRules, importRulesetResponse.message ?? `Error: ${importRulesetResponse.message}`)); + throw new Error(vscode.l10n.t(UiStrings.FailedToDeployRules, importRulesetResponse.message ?? `Error: ${importRulesetResponse.message}`)); } } diff --git a/src/test/unit/commands/rules/enableRules.test.ts b/src/test/unit/commands/rules/enableRules.test.ts index c5d7153d..87d4ea7b 100644 --- a/src/test/unit/commands/rules/enableRules.test.ts +++ b/src/test/unit/commands/rules/enableRules.test.ts @@ -40,10 +40,16 @@ describe("enableRules", () => { assert.ok(node.isEnabled); }); it('enable rules with no status code 200', async () => { - const showErrorMessage = sandbox.spy(vscode.window, "showErrorMessage"); sandbox.stub(ApiCenterService.prototype, "createOrUpdateApiCenterRulesetConfig").resolves({ status: 400 } as HttpOperationResponse); - await enableRules({} as IActionContext, node); - sandbox.assert.calledOnce(showErrorMessage); + + await assert.rejects( + async () => { + await enableRules({} as IActionContext, node); + }, + { + message: "Failed to enable API Analysis. Error: status code 400", + } + ); assert.ok(!node.isEnabled); }); }); From 8a9e1f38edd804178fb9f761d7b4e16c34b58092 Mon Sep 17 00:00:00 2001 From: Jun Han Date: Wed, 7 Aug 2024 09:06:21 +0800 Subject: [PATCH 06/12] feat: update API version --- src/azure/ApiCenter/ApiCenterService.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/azure/ApiCenter/ApiCenterService.ts b/src/azure/ApiCenter/ApiCenterService.ts index ae277842..eda55390 100644 --- a/src/azure/ApiCenter/ApiCenterService.ts +++ b/src/azure/ApiCenter/ApiCenterService.ts @@ -11,7 +11,7 @@ export class ApiCenterService { private resourceGroupName: string; private apiCenterName: string; private apiVersion: string = "2023-07-01-preview"; - private apiVersionPreview: string = "2024-03-15-preview"; + private apiVersionNew: string = "2024-03-01"; constructor(susbcriptionContext: ISubscriptionContext, resourceGroupName: string, apiCenterName: string) { this.susbcriptionContext = susbcriptionContext; this.apiCenterName = apiCenterName; @@ -93,7 +93,7 @@ export class ApiCenterService { const client = new ServiceClient(creds); const options: RequestPrepareOptions = { method: "GET", - url: APICenterRestAPIs.GetRulesetConfig(this.susbcriptionContext.subscriptionId, this.resourceGroupName, this.apiCenterName, this.apiVersionPreview) + url: APICenterRestAPIs.GetRulesetConfig(this.susbcriptionContext.subscriptionId, this.resourceGroupName, this.apiCenterName, this.apiVersionNew) }; const response = await client.sendRequest(options); return response; @@ -170,7 +170,7 @@ export class ApiCenterService { const client = new ServiceClient(creds); const options: RequestPrepareOptions = { method: "PUT", - url: APICenterRestAPIs.CreateRulesetConfig(this.susbcriptionContext.subscriptionId, this.resourceGroupName, this.apiCenterName, this.apiVersionPreview), + url: APICenterRestAPIs.CreateRulesetConfig(this.susbcriptionContext.subscriptionId, this.resourceGroupName, this.apiCenterName, this.apiVersionNew), body: { properties: apiCenterRulesetConfig.properties } @@ -231,7 +231,7 @@ export class ApiCenterService { const client = new ServiceClient(creds); let options: RequestPrepareOptions = { method: "POST", - url: APICenterRestAPIs.ImportRuleset(this.susbcriptionContext.subscriptionId, this.resourceGroupName, this.apiCenterName, this.apiVersionPreview), + url: APICenterRestAPIs.ImportRuleset(this.susbcriptionContext.subscriptionId, this.resourceGroupName, this.apiCenterName, this.apiVersionNew), body: importPayload }; let response = await client.sendRequest(options); @@ -267,7 +267,7 @@ export class ApiCenterService { const client = new ServiceClient(creds); const options: RequestPrepareOptions = { method: "POST", - url: APICenterRestAPIs.ExportRuleset(this.susbcriptionContext.subscriptionId, this.resourceGroupName, this.apiCenterName, this.apiVersionPreview) + url: APICenterRestAPIs.ExportRuleset(this.susbcriptionContext.subscriptionId, this.resourceGroupName, this.apiCenterName, this.apiVersionNew) }; const response = await client.sendRequest(options); return response.parsedBody; From d07f29a18ee7e0ee4d23ba151df627b0355a9ce9 Mon Sep 17 00:00:00 2001 From: Jun Han Date: Wed, 7 Aug 2024 09:24:59 +0800 Subject: [PATCH 07/12] feat: increase timeout to 1 minute --- src/azure/ApiCenter/ApiCenterService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/azure/ApiCenter/ApiCenterService.ts b/src/azure/ApiCenter/ApiCenterService.ts index eda55390..37cd930c 100644 --- a/src/azure/ApiCenter/ApiCenterService.ts +++ b/src/azure/ApiCenter/ApiCenterService.ts @@ -248,7 +248,7 @@ export class ApiCenterService { url: location, }; - const timeout = 30000; // 30 seconds in milliseconds + const timeout = 60000; // 1 minute in milliseconds let startTime = Date.now(); do { response = await client.sendRequest(options); From dfcf1523f8fb2fdc1896131038693378b8a68ffd Mon Sep 17 00:00:00 2001 From: Jun Han Date: Wed, 7 Aug 2024 09:50:10 +0800 Subject: [PATCH 08/12] feat: show error message when import status is failed --- src/azure/ApiCenter/ApiCenterService.ts | 8 ++++++-- src/azure/ApiCenter/contracts.ts | 17 +++++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/azure/ApiCenter/ApiCenterService.ts b/src/azure/ApiCenter/ApiCenterService.ts index 37cd930c..ca2d031e 100644 --- a/src/azure/ApiCenter/ApiCenterService.ts +++ b/src/azure/ApiCenter/ApiCenterService.ts @@ -4,7 +4,7 @@ import { HttpOperationResponse, RequestPrepareOptions, ServiceClient } from "@az import { ISubscriptionContext } from "@microsoft/vscode-azext-utils"; import { getCredentialForToken } from "../../utils/credentialUtil"; import { APICenterRestAPIs } from "./ApiCenterRestAPIs"; -import { ApiCenter, ApiCenterApi, ApiCenterApiDeployment, ApiCenterApiVersion, ApiCenterApiVersionDefinition, ApiCenterApiVersionDefinitionExport, ApiCenterApiVersionDefinitionImport, ApiCenterEnvironment, ApiCenterRulesetConfig, ApiCenterRulesetExport, ApiCenterRulesetImport, ApiCenterRulesetImportResult } from "./contracts"; +import { ApiCenter, ApiCenterApi, ApiCenterApiDeployment, ApiCenterApiVersion, ApiCenterApiVersionDefinition, ApiCenterApiVersionDefinitionExport, ApiCenterApiVersionDefinitionImport, ApiCenterEnvironment, ApiCenterRulesetConfig, ApiCenterRulesetExport, ApiCenterRulesetImport, ApiCenterRulesetImportResult, ApiCenterRulesetImportStatus, ArmAsyncOperationStatus } from "./contracts"; export class ApiCenterService { private susbcriptionContext: ISubscriptionContext; @@ -252,9 +252,13 @@ export class ApiCenterService { let startTime = Date.now(); do { response = await client.sendRequest(options); - if (response.parsedBody?.status === "Succeeded") { + const responseBody: ApiCenterRulesetImportStatus = response.parsedBody; + if (responseBody?.status === ArmAsyncOperationStatus.Succeeded) { return { isSuccessful: true }; } + if (responseBody?.status === ArmAsyncOperationStatus.Failed) { + return { isSuccessful: false, message: responseBody.properties?.comment }; + } } while (Date.now() - startTime < timeout); return { isSuccessful: false }; } else { diff --git a/src/azure/ApiCenter/contracts.ts b/src/azure/ApiCenter/contracts.ts index c3c36a2a..602b1999 100644 --- a/src/azure/ApiCenter/contracts.ts +++ b/src/azure/ApiCenter/contracts.ts @@ -96,6 +96,15 @@ export type ApiCenterRulesetImport = { value: string; }; +export type ApiCenterRulesetImportStatus = { + id: string; + name: string; + status: ArmAsyncOperationStatus; + properties: { + comment?: string; + }; +}; + export type ApiCenterRulesetImportResult = { isSuccessful: boolean; message?: string | null; @@ -140,3 +149,11 @@ export enum ApiSpecExportResultFormat { inline = 'inline', link = 'link', }; + +export enum ArmAsyncOperationStatus { + NotStarted = 'NotStarted', + InProgress = 'InProgress', + Succeeded = 'Succeeded', + Failed = 'Failed', + Canceled = 'Canceled', +} From e4c9c6dc6dee39a3496a9b70eb8ecf6207086d29 Mon Sep 17 00:00:00 2001 From: Jun Han Date: Wed, 7 Aug 2024 10:22:27 +0800 Subject: [PATCH 09/12] test: add test for importRuleset failed on status check --- .../azure/ApiCenter/ApiCenterService.test.ts | 34 ++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/src/test/unit/azure/ApiCenter/ApiCenterService.test.ts b/src/test/unit/azure/ApiCenter/ApiCenterService.test.ts index 8ee94b8b..1ad659f2 100644 --- a/src/test/unit/azure/ApiCenter/ApiCenterService.test.ts +++ b/src/test/unit/azure/ApiCenter/ApiCenterService.test.ts @@ -44,7 +44,7 @@ describe("ApiCenterService", () => { assert.strictEqual(response.isSuccessful, true); }); - it("importRuleset failed", async () => { + it("importRuleset failed on first call", async () => { sandbox.stub(ServiceClient.prototype, "sendRequest").resolves({ status: 500, bodyAsText: "error" } as HttpOperationResponse); const apiCenterService = new ApiCenterService(subscriptionContext, "fakeResourceGroup", "fakeServiceName"); @@ -55,6 +55,38 @@ describe("ApiCenterService", () => { const response = await apiCenterService.importRuleset(importPayload); + assert.strictEqual(response.isSuccessful, false); + assert.strictEqual(response.message, "error"); + }); + it("importRuleset failed on status check", async () => { + const mockResponse1 = { status: 202 } as HttpOperationResponse; + mockResponse1.headers = new HttpHeaders({ Location: "fakeLocation" }); + const mockResponse2 = { + status: 202, + parsedBody: { status: "InProgress" }, + } as HttpOperationResponse; + const mockResponse3 = { + status: 400, + parsedBody: { + status: "Failed", + properties: { + comment: "error" + } + }, + } as HttpOperationResponse; + const sendRequestStub = sandbox.stub(ServiceClient.prototype, "sendRequest"); + sendRequestStub.onFirstCall().resolves(mockResponse1); + sendRequestStub.onSecondCall().resolves(mockResponse2); + sendRequestStub.onThirdCall().resolves(mockResponse3); + + const apiCenterService = new ApiCenterService(subscriptionContext, "fakeResourceGroup", "fakeServiceName"); + const importPayload: ApiCenterRulesetImport = { + value: "fakeValue", + format: "InlineZip", + }; + + const response = await apiCenterService.importRuleset(importPayload); + assert.strictEqual(response.isSuccessful, false); assert.strictEqual(response.message, "error"); }); From b00e7f2f4ed2461b1f3eaf4b82bbd846dbb4eab2 Mon Sep 17 00:00:00 2001 From: Jun Han Date: Wed, 7 Aug 2024 12:59:43 +0800 Subject: [PATCH 10/12] feat: show Progress Bar when enable/deploy rules --- src/commands/rules/deployRules.ts | 31 +++++---- src/commands/rules/enableRules.ts | 63 ++++++++++--------- .../unit/commands/rules/enableRules.test.ts | 4 +- src/uiStrings.ts | 4 +- 4 files changed, 56 insertions(+), 46 deletions(-) diff --git a/src/commands/rules/deployRules.ts b/src/commands/rules/deployRules.ts index 7f00e8ff..572c276b 100644 --- a/src/commands/rules/deployRules.ts +++ b/src/commands/rules/deployRules.ts @@ -18,20 +18,25 @@ export async function deployRules(context: IActionContext, node: RulesTreeItem) return; } - const content = (await zipFolderToBuffer(rulesFolderPath)).toString('base64'); + await vscode.window.withProgress({ + location: vscode.ProgressLocation.Notification, + title: UiStrings.DeployRules + }, async (progress, token) => { + const content = (await zipFolderToBuffer(rulesFolderPath)).toString('base64'); - const resourceGroupName = getResourceGroupFromId(node.apiCenter.id); - const apiCenterService = new ApiCenterService(node.parent?.subscription!, resourceGroupName, node.apiCenter.name); + const resourceGroupName = getResourceGroupFromId(node.apiCenter.id); + const apiCenterService = new ApiCenterService(node.parent?.subscription!, resourceGroupName, node.apiCenter.name); - const importPayload: ApiCenterRulesetImport = { - value: content, - format: "InlineZip", - }; - const response = await apiCenterService.importRuleset(importPayload); + const importPayload: ApiCenterRulesetImport = { + value: content, + format: "InlineZip", + }; + const response = await apiCenterService.importRuleset(importPayload); - if (response.isSuccessful) { - vscode.window.showInformationMessage(vscode.l10n.t(UiStrings.RulesDeployed, node.apiCenter.name)); - } else { - throw new Error(vscode.l10n.t(UiStrings.FailedToDeployRules, response.message ?? `Error: ${response.message}`)); - } + if (response.isSuccessful) { + vscode.window.showInformationMessage(vscode.l10n.t(UiStrings.RulesDeployed, node.apiCenter.name)); + } else { + throw new Error(vscode.l10n.t(UiStrings.FailedToDeployRules, response.message ? `Error: ${response.message}` : "")); + } + }); } diff --git a/src/commands/rules/enableRules.ts b/src/commands/rules/enableRules.ts index cf6930c6..1ded4027 100644 --- a/src/commands/rules/enableRules.ts +++ b/src/commands/rules/enableRules.ts @@ -20,34 +20,37 @@ const apiCenterRulesetConfig: ApiCenterRulesetConfig = { }; export async function enableRules(context: IActionContext, node: RulesTreeItem) { - const resourceGroupName = getResourceGroupFromId(node.apiCenter.id); - const apiCenterService = new ApiCenterService(node.parent?.subscription!, resourceGroupName, node.apiCenter.name); - - const response = await apiCenterService.createOrUpdateApiCenterRulesetConfig(apiCenterRulesetConfig); - - if (response.status === 200) { - vscode.window.showInformationMessage((vscode.l10n.t(UiStrings.RulesEnabled, node.apiCenter.name))); - } else { - throw new Error(vscode.l10n.t(UiStrings.FailedToEnableRules, response.bodyAsText ?? `status code ${response.status}`)); - } - - // Temporary workaround to deploy default rules after enabling rules - // In future, default rules need to be generated in control plane - const defaultRulesFolderPath = path.join(ext.context.extensionPath, 'templates', 'rules', 'default-ruleset'); - - const content = (await zipFolderToBuffer(defaultRulesFolderPath)).toString('base64'); - - const importPayload: ApiCenterRulesetImport = { - value: content, - format: "InlineZip", - }; - const importRulesetResponse = await apiCenterService.importRuleset(importPayload); - - if (importRulesetResponse.isSuccessful) { - vscode.window.showInformationMessage(vscode.l10n.t(UiStrings.RulesDeployed, node.apiCenter.name)); - node.updateStatusToEnable(); - await node.refresh(context); - } else { - throw new Error(vscode.l10n.t(UiStrings.FailedToDeployRules, importRulesetResponse.message ?? `Error: ${importRulesetResponse.message}`)); - } + await vscode.window.withProgress({ + location: vscode.ProgressLocation.Notification, + title: UiStrings.EnableRules + }, async (progress, token) => { + const resourceGroupName = getResourceGroupFromId(node.apiCenter.id); + const apiCenterService = new ApiCenterService(node.parent?.subscription!, resourceGroupName, node.apiCenter.name); + + const response = await apiCenterService.createOrUpdateApiCenterRulesetConfig(apiCenterRulesetConfig); + + if (response.status !== 200) { + throw new Error(vscode.l10n.t(UiStrings.FailedToEnableRules, response.bodyAsText ? `Error: ${response.bodyAsText}` : `Status Code: ${response.status}`)); + } + + // Temporary workaround to deploy default rules after enabling rules + // In future, default rules need to be generated in control plane + const defaultRulesFolderPath = path.join(ext.context.extensionPath, 'templates', 'rules', 'default-ruleset'); + + const content = (await zipFolderToBuffer(defaultRulesFolderPath)).toString('base64'); + + const importPayload: ApiCenterRulesetImport = { + value: content, + format: "InlineZip", + }; + const importRulesetResponse = await apiCenterService.importRuleset(importPayload); + + if (importRulesetResponse.isSuccessful) { + vscode.window.showInformationMessage(vscode.l10n.t(UiStrings.RulesEnabled, node.apiCenter.name)); + node.updateStatusToEnable(); + await node.refresh(context); + } else { + throw new Error(vscode.l10n.t(UiStrings.FailedToEnableRules, importRulesetResponse.message ? `Error: ${importRulesetResponse.message}` : "")); + } + }); } diff --git a/src/test/unit/commands/rules/enableRules.test.ts b/src/test/unit/commands/rules/enableRules.test.ts index 87d4ea7b..4603c904 100644 --- a/src/test/unit/commands/rules/enableRules.test.ts +++ b/src/test/unit/commands/rules/enableRules.test.ts @@ -36,7 +36,7 @@ describe("enableRules", () => { sandbox.stub(ApiCenterService.prototype, "createOrUpdateApiCenterRulesetConfig").resolves({ status: 200 } as HttpOperationResponse); sandbox.stub(ApiCenterService.prototype, "importRuleset").resolves({ isSuccessful: true } as ApiCenterRulesetImportResult); await enableRules({} as IActionContext, node); - sandbox.assert.calledTwice(showInformationMessage); + sandbox.assert.calledOnce(showInformationMessage); assert.ok(node.isEnabled); }); it('enable rules with no status code 200', async () => { @@ -47,7 +47,7 @@ describe("enableRules", () => { await enableRules({} as IActionContext, node); }, { - message: "Failed to enable API Analysis. Error: status code 400", + message: "Failed to enable API Analysis. Status Code: 400", } ); assert.ok(!node.isEnabled); diff --git a/src/uiStrings.ts b/src/uiStrings.ts index 158b57ba..db18ecf5 100644 --- a/src/uiStrings.ts +++ b/src/uiStrings.ts @@ -106,10 +106,12 @@ export class UiStrings { static readonly DeleteCustomFunction = vscode.l10n.t("Are you sure you want to delete '{0}'?"); static readonly FileAlreadyExists = vscode.l10n.t("The file '{0}' already exists. Please input a different name."); static readonly NoRulesFolder = vscode.l10n.t("Rules folder '{0}' is empty. No files to deploy."); + static readonly DeployRules = vscode.l10n.t("Deploying Rules..."); static readonly RulesDeployed = vscode.l10n.t("Rules deployed to '{0}'."); static readonly FailedToDeployRules = vscode.l10n.t("Failed to deploy rules. {0}"); + static readonly EnableRules = vscode.l10n.t("Enabling API Analysis..."); static readonly RulesEnabled = vscode.l10n.t("API Analysis enabled for '{0}'."); - static readonly FailedToEnableRules = vscode.l10n.t("Failed to enable API Analysis. Error: {0}"); + static readonly FailedToEnableRules = vscode.l10n.t("Failed to enable API Analysis. {0}"); static readonly RulesFolderNotEmpty = vscode.l10n.t("The rules folder '{0}' is not empty. Do you want to overwrite the existing files?"); static readonly Yes = vscode.l10n.t("Yes"); static readonly No = vscode.l10n.t("No"); From ec98cecac469e1e225ccc9959b872381980138a5 Mon Sep 17 00:00:00 2001 From: Jun Han Date: Wed, 7 Aug 2024 13:14:23 +0800 Subject: [PATCH 11/12] test: enabling rules failed when importing ruleset --- .../unit/commands/rules/enableRules.test.ts | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/test/unit/commands/rules/enableRules.test.ts b/src/test/unit/commands/rules/enableRules.test.ts index 4603c904..67a18753 100644 --- a/src/test/unit/commands/rules/enableRules.test.ts +++ b/src/test/unit/commands/rules/enableRules.test.ts @@ -30,7 +30,7 @@ describe("enableRules", () => { afterEach(() => { sandbox.restore(); }); - it('enable rules with status code 200', async () => { + it('enabling rules succeeded', async () => { sandbox.stub(path, 'join').returns(__dirname); const showInformationMessage = sandbox.spy(vscode.window, "showInformationMessage"); sandbox.stub(ApiCenterService.prototype, "createOrUpdateApiCenterRulesetConfig").resolves({ status: 200 } as HttpOperationResponse); @@ -39,15 +39,30 @@ describe("enableRules", () => { sandbox.assert.calledOnce(showInformationMessage); assert.ok(node.isEnabled); }); - it('enable rules with no status code 200', async () => { - sandbox.stub(ApiCenterService.prototype, "createOrUpdateApiCenterRulesetConfig").resolves({ status: 400 } as HttpOperationResponse); + it('enabling rules failed when creating ruleset config', async () => { + sandbox.stub(ApiCenterService.prototype, "createOrUpdateApiCenterRulesetConfig").resolves({ status: 400, bodyAsText: 'error' } as HttpOperationResponse); await assert.rejects( async () => { await enableRules({} as IActionContext, node); }, { - message: "Failed to enable API Analysis. Status Code: 400", + message: "Failed to enable API Analysis. Error: error", + } + ); + assert.ok(!node.isEnabled); + }); + it('enabling rules failed when importing ruleset', async () => { + sandbox.stub(path, 'join').returns(__dirname); + sandbox.stub(ApiCenterService.prototype, "createOrUpdateApiCenterRulesetConfig").resolves({ status: 200 } as HttpOperationResponse); + sandbox.stub(ApiCenterService.prototype, "importRuleset").resolves({ isSuccessful: false, message: 'error' } as ApiCenterRulesetImportResult); + + await assert.rejects( + async () => { + await enableRules({} as IActionContext, node); + }, + { + message: "Failed to enable API Analysis. Error: error", } ); assert.ok(!node.isEnabled); From e866f4b77311a17d6e4ffe760ec4e12222fbe459 Mon Sep 17 00:00:00 2001 From: Jun Han Date: Thu, 8 Aug 2024 13:41:38 +0800 Subject: [PATCH 12/12] feat: more updates per API change --- src/azure/ApiCenter/ApiCenterRestAPIs.ts | 8 ++++---- src/azure/ApiCenter/contracts.ts | 4 ++++ src/commands/rules/deployRules.ts | 4 ++-- src/commands/rules/enableRules.ts | 8 +++----- src/test/unit/azure/ApiCenter/ApiCenterService.test.ts | 8 ++++---- 5 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/azure/ApiCenter/ApiCenterRestAPIs.ts b/src/azure/ApiCenter/ApiCenterRestAPIs.ts index 503c6fa5..1bebb8e4 100644 --- a/src/azure/ApiCenter/ApiCenterRestAPIs.ts +++ b/src/azure/ApiCenter/ApiCenterRestAPIs.ts @@ -7,18 +7,18 @@ export const APICenterRestAPIs = { GetAPIVersions: (subscriptionId: string, resourceGroupName: string, apiCenterName: string, apiName: string, restApiVersion: string) => `https://management.azure.com/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.ApiCenter/services/${apiCenterName}/workspaces/default/apis/${apiName}/versions?api-version=${restApiVersion}`, GetAPIDeployments: (subscriptionId: string, resourceGroupName: string, apiCenterName: string, apiName: string, restApiVersion: string) => `https://management.azure.com/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.ApiCenter/services/${apiCenterName}/workspaces/default/apis/${apiName}/deployments?api-version=${restApiVersion}`, GetAPIDefinition: (subscriptionId: string, resourceGroupName: string, apiCenterName: string, apiName: string, apiVersion: string, restApiVersion: string) => `https://management.azure.com/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.ApiCenter/services/${apiCenterName}/workspaces/default/apis/${apiName}/versions/${apiVersion}/definitions?api-version=${restApiVersion}`, - GetRulesetConfig: (subscriptionId: string, resourceGroupName: string, apiCenterName: string, restApiVersion: string) => `https://management.azure.com/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.ApiCenter/services/${apiCenterName}/workspaces/default/staticAnalyzers/spectral?api-version=${restApiVersion}`, + GetRulesetConfig: (subscriptionId: string, resourceGroupName: string, apiCenterName: string, restApiVersion: string) => `https://management.azure.com/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.ApiCenter/services/${apiCenterName}/workspaces/default/analyzerConfigs/spectral-openapi?api-version=${restApiVersion}`, CreateAPI: (subscriptionId: string, resourceGroupName: string, apiCenterName: string, apiName: string, restApiVersion: string) => `https://management.azure.com/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.ApiCenter/services/${apiCenterName}/workspaces/default/apis/${apiName}?api-version=${restApiVersion}`, CreateAPIVersion: (subscriptionId: string, resourceGroupName: string, apiCenterName: string, apiName: string, apiVersion: string, restApiVersion: string) => `https://management.azure.com/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.ApiCenter/services/${apiCenterName}/workspaces/default/apis/${apiName}/versions/${apiVersion}?api-version=${restApiVersion}`, CreateAPIDeployment: (subscriptionId: string, resourceGroupName: string, apiCenterName: string, apiName: string, deploymentName: string, restApiVersion: string) => `https://management.azure.com/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.ApiCenter/services/${apiCenterName}/workspaces/default/apis/${apiName}/deployments/${deploymentName}?api-version=${restApiVersion}`, CreateAPIDefinition: (subscriptionId: string, resourceGroupName: string, apiCenterName: string, apiName: string, apiVersion: string, definationName: string, restApiVersion: string) => `https://management.azure.com/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.ApiCenter/services/${apiCenterName}/workspaces/default/apis/${apiName}/versions/${apiVersion}/definitions/${definationName}?api-version=${restApiVersion}`, - CreateRulesetConfig: (subscriptionId: string, resourceGroupName: string, apiCenterName: string, restApiVersion: string) => `https://management.azure.com/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.ApiCenter/services/${apiCenterName}/workspaces/default/staticAnalyzers/spectral?api-version=${restApiVersion}`, + CreateRulesetConfig: (subscriptionId: string, resourceGroupName: string, apiCenterName: string, restApiVersion: string) => `https://management.azure.com/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.ApiCenter/services/${apiCenterName}/workspaces/default/analyzerConfigs/spectral-openapi?api-version=${restApiVersion}`, ImportAPISpecification: (subscriptionId: string, resourceGroupName: string, apiCenterName: string, apiName: string, apiVersion: string, definationName: string, restApiVersion: string) => `https://management.azure.com/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.ApiCenter/services/${apiCenterName}/workspaces/default/apis/${apiName}/versions/${apiVersion}/definitions/${definationName}/importSpecification?api-version=${restApiVersion}`, ExportApiSpecification: (subscriptionId: string, resourceGroupName: string, apiCenterName: string, apiName: string, apiVersion: string, definationName: string, restApiVersion: string) => `https://management.azure.com/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.ApiCenter/services/${apiCenterName}/workspaces/default/apis/${apiName}/versions/${apiVersion}/definitions/${definationName}/exportSpecification?api-version=${restApiVersion}`, - ImportRuleset: (subscriptionId: string, resourceGroupName: string, apiCenterName: string, restApiVersion: string) => `https://management.azure.com/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.ApiCenter/services/${apiCenterName}/workspaces/default/staticAnalyzers/spectral/importRuleset?api-version=${restApiVersion}`, - ExportRuleset: (subscriptionId: string, resourceGroupName: string, apiCenterName: string, restApiVersion: string) => `https://management.azure.com/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.ApiCenter/services/${apiCenterName}/workspaces/default/staticAnalyzers/spectral/exportRuleset?api-version=${restApiVersion}`, + ImportRuleset: (subscriptionId: string, resourceGroupName: string, apiCenterName: string, restApiVersion: string) => `https://management.azure.com/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.ApiCenter/services/${apiCenterName}/workspaces/default/analyzerConfigs/spectral-openapi/importRuleset?api-version=${restApiVersion}`, + ExportRuleset: (subscriptionId: string, resourceGroupName: string, apiCenterName: string, restApiVersion: string) => `https://management.azure.com/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.ApiCenter/services/${apiCenterName}/workspaces/default/analyzerConfigs/spectral-openapi/exportRuleset?api-version=${restApiVersion}`, }; diff --git a/src/azure/ApiCenter/contracts.ts b/src/azure/ApiCenter/contracts.ts index 602b1999..28120d79 100644 --- a/src/azure/ApiCenter/contracts.ts +++ b/src/azure/ApiCenter/contracts.ts @@ -157,3 +157,7 @@ export enum ArmAsyncOperationStatus { Failed = 'Failed', Canceled = 'Canceled', } + +export enum ApiCenterRulesetImportFormat { + InlineZip = 'inline-zip', +}; diff --git a/src/commands/rules/deployRules.ts b/src/commands/rules/deployRules.ts index 572c276b..a687b06b 100644 --- a/src/commands/rules/deployRules.ts +++ b/src/commands/rules/deployRules.ts @@ -4,7 +4,7 @@ import { getResourceGroupFromId } from "@microsoft/vscode-azext-azureutils"; import { IActionContext } from "@microsoft/vscode-azext-utils"; import * as vscode from 'vscode'; import { ApiCenterService } from "../../azure/ApiCenter/ApiCenterService"; -import { ApiCenterRulesetImport } from "../../azure/ApiCenter/contracts"; +import { ApiCenterRulesetImport, ApiCenterRulesetImportFormat } from "../../azure/ApiCenter/contracts"; import { RulesTreeItem } from "../../tree/rules/RulesTreeItem"; import { UiStrings } from "../../uiStrings"; import { hasFiles } from "../../utils/fsUtil"; @@ -29,7 +29,7 @@ export async function deployRules(context: IActionContext, node: RulesTreeItem) const importPayload: ApiCenterRulesetImport = { value: content, - format: "InlineZip", + format: ApiCenterRulesetImportFormat.InlineZip, }; const response = await apiCenterService.importRuleset(importPayload); diff --git a/src/commands/rules/enableRules.ts b/src/commands/rules/enableRules.ts index 1ded4027..730cb9db 100644 --- a/src/commands/rules/enableRules.ts +++ b/src/commands/rules/enableRules.ts @@ -5,7 +5,7 @@ import { IActionContext } from "@microsoft/vscode-azext-utils"; import * as path from 'path'; import * as vscode from 'vscode'; import { ApiCenterService } from "../../azure/ApiCenter/ApiCenterService"; -import { ApiCenterRulesetConfig, ApiCenterRulesetImport } from "../../azure/ApiCenter/contracts"; +import { ApiCenterRulesetConfig, ApiCenterRulesetImport, ApiCenterRulesetImportFormat } from "../../azure/ApiCenter/contracts"; import { ext } from "../../extensionVariables"; import { RulesTreeItem } from "../../tree/rules/RulesTreeItem"; import { UiStrings } from "../../uiStrings"; @@ -13,9 +13,7 @@ import { zipFolderToBuffer } from "../../utils/zipUtils"; const apiCenterRulesetConfig: ApiCenterRulesetConfig = { properties: { - analyzerVersion: "1.0.0", - apiType: "rest", - lifecycleStage: "testing", + analyzerType: "spectral" } }; @@ -41,7 +39,7 @@ export async function enableRules(context: IActionContext, node: RulesTreeItem) const importPayload: ApiCenterRulesetImport = { value: content, - format: "InlineZip", + format: ApiCenterRulesetImportFormat.InlineZip, }; const importRulesetResponse = await apiCenterService.importRuleset(importPayload); diff --git a/src/test/unit/azure/ApiCenter/ApiCenterService.test.ts b/src/test/unit/azure/ApiCenter/ApiCenterService.test.ts index 1ad659f2..2e0670fe 100644 --- a/src/test/unit/azure/ApiCenter/ApiCenterService.test.ts +++ b/src/test/unit/azure/ApiCenter/ApiCenterService.test.ts @@ -5,7 +5,7 @@ import { ISubscriptionContext } from "@microsoft/vscode-azext-utils"; import * as assert from "assert"; import * as sinon from "sinon"; import { ApiCenterService } from "../../../../azure/ApiCenter/ApiCenterService"; -import { ApiCenterRulesetImport } from "../../../../azure/ApiCenter/contracts"; +import { ApiCenterRulesetImport, ApiCenterRulesetImportFormat } from "../../../../azure/ApiCenter/contracts"; describe("ApiCenterService", () => { let sandbox: sinon.SinonSandbox; @@ -37,7 +37,7 @@ describe("ApiCenterService", () => { const apiCenterService = new ApiCenterService(subscriptionContext, "fakeResourceGroup", "fakeServiceName"); const importPayload: ApiCenterRulesetImport = { value: "fakeValue", - format: "InlineZip", + format: ApiCenterRulesetImportFormat.InlineZip, }; const response = await apiCenterService.importRuleset(importPayload); @@ -50,7 +50,7 @@ describe("ApiCenterService", () => { const apiCenterService = new ApiCenterService(subscriptionContext, "fakeResourceGroup", "fakeServiceName"); const importPayload: ApiCenterRulesetImport = { value: "fakeValue", - format: "InlineZip", + format: ApiCenterRulesetImportFormat.InlineZip, }; const response = await apiCenterService.importRuleset(importPayload); @@ -82,7 +82,7 @@ describe("ApiCenterService", () => { const apiCenterService = new ApiCenterService(subscriptionContext, "fakeResourceGroup", "fakeServiceName"); const importPayload: ApiCenterRulesetImport = { value: "fakeValue", - format: "InlineZip", + format: ApiCenterRulesetImportFormat.InlineZip, }; const response = await apiCenterService.importRuleset(importPayload);