Added browsed pipeline and combined with configure pipeline.
This commit is contained in:
Родитель
e6a15fe9d4
Коммит
274a9f92f0
11
package.json
11
package.json
|
@ -96,6 +96,11 @@
|
|||
"command": "configure-pipeline",
|
||||
"title": "Configure Pipeline",
|
||||
"category": "Azure Pipelines"
|
||||
},
|
||||
{
|
||||
"command": "browse-pipeline",
|
||||
"title": "Browse Pipeline",
|
||||
"category": "Azure Pipelines"
|
||||
}
|
||||
],
|
||||
"menus": {
|
||||
|
@ -105,6 +110,12 @@
|
|||
"group": "Azure Pipelines",
|
||||
"when": "explorerResourceIsFolder == true"
|
||||
}
|
||||
],
|
||||
"commandPalette": [
|
||||
{
|
||||
"command": "browse-pipeline",
|
||||
"when": "never"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import * as vscode from 'vscode';
|
||||
import { registerCommand, IActionContext, createApiProvider } from 'vscode-azureextensionui';
|
||||
import { registerCommand, IActionContext, createApiProvider, AzureTreeItem } from 'vscode-azureextensionui';
|
||||
import { AzureExtensionApi, AzureExtensionApiProvider } from 'vscode-azureextensionui/api';
|
||||
|
||||
import { browsePipeline } from './browse';
|
||||
import { configurePipeline } from './configure';
|
||||
import { Messages } from './resources/messages';
|
||||
import { AzureAccountExtensionExports, extensionVariables } from './model/models';
|
||||
|
@ -28,9 +29,16 @@ export async function activateConfigurePipeline(): Promise<AzureExtensionApiProv
|
|||
await configurePipeline(node);
|
||||
});
|
||||
|
||||
registerCommand('browse-pipeline', async (actionContext: IActionContext, node: AzureTreeItem) => {
|
||||
// The code you place here will be executed every time your command is executed
|
||||
telemetryHelper.initialize(actionContext, 'browse-pipeline');
|
||||
await browsePipeline(node);
|
||||
});
|
||||
|
||||
return createApiProvider([<AzureExtensionApi>
|
||||
{
|
||||
configurePipelineApi: configurePipeline,
|
||||
browsePipeline: browsePipeline,
|
||||
apiVersion: "0.0.1"
|
||||
}]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
import * as vscode from 'vscode';
|
||||
import { AzureTreeItem, UserCancelledError } from 'vscode-azureextensionui';
|
||||
|
||||
import { AppServiceClient, ScmTypes } from './clients/azure/appServiceClient';
|
||||
import { getSubscriptionSession } from './helper/azureSessionHelper';
|
||||
import { ControlProvider } from './helper/controlProvider';
|
||||
import { AzureSession, ParsedAzureResourceId, extensionVariables } from './model/models';
|
||||
import * as constants from './resources/constants';
|
||||
import { Messages } from './resources/messages';
|
||||
import { telemetryHelper, Result } from './helper/telemetryHelper';
|
||||
import { TelemetryKeys } from './resources/telemetryKeys';
|
||||
|
||||
export async function browsePipeline(node: AzureTreeItem): Promise<void> {
|
||||
await telemetryHelper.executeFunctionWithTimeTelemetry(async () => {
|
||||
try {
|
||||
if (!!node && !!node.fullId) {
|
||||
let parsedAzureResourceId: ParsedAzureResourceId = new ParsedAzureResourceId(node.fullId);
|
||||
let session: AzureSession = getSubscriptionSession(parsedAzureResourceId.subscriptionId);
|
||||
let appServiceClient = new AppServiceClient(session.credentials, parsedAzureResourceId.subscriptionId);
|
||||
let siteConfig = await appServiceClient.getAppServiceConfig(node.fullId);
|
||||
telemetryHelper.setTelemetry(TelemetryKeys.ScmType, siteConfig.scmType);
|
||||
let controlProvider = new ControlProvider();
|
||||
|
||||
if (siteConfig.scmType.toLowerCase() === ScmTypes.VSTSRM.toLowerCase()) {
|
||||
let pipelineUrl = await appServiceClient.getVstsPipelineUrl(node.fullId);
|
||||
vscode.env.openExternal(vscode.Uri.parse(pipelineUrl));
|
||||
telemetryHelper.setTelemetry(TelemetryKeys.BrowsedExistingPipeline, 'true');
|
||||
}
|
||||
else if (siteConfig.scmType === '' || siteConfig.scmType.toLowerCase() === ScmTypes.NONE.toLowerCase()) {
|
||||
let result = await controlProvider.showInformationBox(
|
||||
constants.BrowseNotAvailableConfigurePipeline,
|
||||
Messages.browseNotAvailableConfigurePipeline,
|
||||
'Configure Pipeline');
|
||||
|
||||
if (result === 'Configure Pipeline') {
|
||||
vscode.commands.executeCommand('configure-pipeline', node);
|
||||
telemetryHelper.setTelemetry(TelemetryKeys.ClickedConfigurePipeline, 'true');
|
||||
}
|
||||
}
|
||||
else {
|
||||
let result = await controlProvider.showInformationBox(constants.DeploymentResourceAlreadyConfigured, Messages.deploymentCenterAlreadyConfigured, constants.BrowseDeploymentSource);
|
||||
if (result === constants.BrowseDeploymentSource) {
|
||||
let deploymentCenterUrl: string = await appServiceClient.getDeploymentCenterUrl(node.fullId);
|
||||
await vscode.env.openExternal(vscode.Uri.parse(deploymentCenterUrl));
|
||||
telemetryHelper.setTelemetry(TelemetryKeys.BrowsedDeploymentCenter, 'true');
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new Error(Messages.didNotRecieveAzureResourceNodeToProcess);
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
if (!(error instanceof UserCancelledError)) {
|
||||
extensionVariables.outputChannel.appendLine(error.message);
|
||||
vscode.window.showErrorMessage(error.message);
|
||||
telemetryHelper.setResult(Result.Failed, error);
|
||||
}
|
||||
else {
|
||||
telemetryHelper.setResult(Result.Canceled, error);
|
||||
}
|
||||
}
|
||||
}, TelemetryKeys.CommandExecutionDuration);
|
||||
}
|
|
@ -6,7 +6,6 @@ import { ServiceClientCredentials } from 'ms-rest';
|
|||
|
||||
import { AzureResourceClient } from './azureResourceClient';
|
||||
import { WebAppKind, ParsedAzureResourceId } from '../../model/models';
|
||||
import * as Constants from '../../resources/constants';
|
||||
import {Messages} from '../../resources/messages';
|
||||
|
||||
export class AppServiceClient extends AzureResourceClient {
|
||||
|
@ -48,7 +47,7 @@ export class AppServiceClient extends AzureResourceClient {
|
|||
}
|
||||
|
||||
public async getVstsPipelineUrl(resourceId: string): Promise<string> {
|
||||
let metadata = await this.getSiteMetadata(resourceId);
|
||||
let metadata = await this.getAppServiceMetadata(resourceId);
|
||||
if (metadata.properties['VSTSRM_BuildDefinitionWebAccessUrl']) {
|
||||
return metadata.properties['VSTSRM_BuildDefinitionWebAccessUrl'];
|
||||
}
|
||||
|
@ -63,7 +62,7 @@ export class AppServiceClient extends AzureResourceClient {
|
|||
|
||||
public async updateScmType(resourceId: string): Promise<SiteConfigResource> {
|
||||
let siteConfig = await this.getAppServiceConfig(resourceId);
|
||||
siteConfig.scmType = Constants.VstsRmScmType;
|
||||
siteConfig.scmType = ScmTypes.VSTSRM;
|
||||
let parsedResourceId: ParsedAzureResourceId = new ParsedAzureResourceId(resourceId);
|
||||
return this.webSiteManagementClient.webApps.updateConfiguration(parsedResourceId.resourceGroup, parsedResourceId.resourceName, siteConfig);
|
||||
}
|
||||
|
@ -73,12 +72,12 @@ export class AppServiceClient extends AzureResourceClient {
|
|||
return this.webSiteManagementClient.webApps.updateConfiguration(parsedResourceId.resourceGroup, parsedResourceId.resourceName, siteConfig);
|
||||
}
|
||||
|
||||
public async getSiteMetadata(resourceId: string): Promise<StringDictionary> {
|
||||
public async getAppServiceMetadata(resourceId: string): Promise<StringDictionary> {
|
||||
let parsedResourceId: ParsedAzureResourceId = new ParsedAzureResourceId(resourceId);
|
||||
return this.webSiteManagementClient.webApps.listMetadata(parsedResourceId.resourceGroup, parsedResourceId.resourceName);
|
||||
}
|
||||
|
||||
public async updateSiteMetadata(resourceId: string, metadata: StringDictionary): Promise<StringDictionary> {
|
||||
public async updateAppServiceMetadata(resourceId: string, metadata: StringDictionary): Promise<StringDictionary> {
|
||||
let parsedResourceId: ParsedAzureResourceId = new ParsedAzureResourceId(resourceId);
|
||||
return this.webSiteManagementClient.webApps.updateMetadata(parsedResourceId.resourceGroup, parsedResourceId.resourceName, metadata);
|
||||
}
|
||||
|
@ -112,6 +111,11 @@ export class AppServiceClient extends AzureResourceClient {
|
|||
}
|
||||
}
|
||||
|
||||
export enum ScmTypes {
|
||||
VSTSRM = 'VSTSRM',
|
||||
NONE = 'NONE'
|
||||
}
|
||||
|
||||
interface DeploymentMessage {
|
||||
type: string;
|
||||
message: string;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
const uuid = require('uuid/v4');
|
||||
import { AppServiceClient } from './clients/azure/appServiceClient';
|
||||
import { AppServiceClient, ScmTypes } from './clients/azure/appServiceClient';
|
||||
import { AzureDevOpsClient } from './clients/devOps/azureDevOpsClient';
|
||||
import { AzureDevOpsHelper } from './helper/devOps/azureDevOpsHelper';
|
||||
import { AzureTreeItem, UserCancelledError } from 'vscode-azureextensionui';
|
||||
import { AzureTreeItem, UserCancelledError, AzureParentTreeItem, SubscriptionTreeItemBase } from 'vscode-azureextensionui';
|
||||
import { generateDevOpsProjectName, generateDevOpsOrganizationName } from './helper/commonHelper';
|
||||
import { GenericResource } from 'azure-arm-resource/lib/resource/models';
|
||||
import { GraphHelper } from './helper/graphHelper';
|
||||
|
@ -170,7 +170,7 @@ class PipelineConfigurer {
|
|||
}
|
||||
|
||||
private async analyzeNode(node: any): Promise<void> {
|
||||
if (node instanceof AzureTreeItem) {
|
||||
if (!!node && !!node.fullId) {
|
||||
await this.extractAzureResourceFromNode(node);
|
||||
}
|
||||
else if (node && node.fsPath) {
|
||||
|
@ -359,7 +359,7 @@ class PipelineConfigurer {
|
|||
private async validateIfPipelineCanBeSetupOnResource(resourceId: string): Promise<void> {
|
||||
// Check for SCM type, if its value is set then a pipeline is already setup.
|
||||
let siteConfig = await this.appServiceClient.getAppServiceConfig(resourceId);
|
||||
if (siteConfig.scmType && siteConfig.scmType.toLowerCase() === 'vstsrm') {
|
||||
if (siteConfig.scmType && siteConfig.scmType.toLowerCase() === ScmTypes.VSTSRM.toLowerCase()) {
|
||||
// if pipeline is already setup, the ask the user if we should continue.
|
||||
telemetryHelper.setTelemetry(TelemetryKeys.PipelineAlreadyConfigured, 'true');
|
||||
telemetryHelper.setTelemetry(TelemetryKeys.ScmType, siteConfig.scmType);
|
||||
|
@ -369,17 +369,18 @@ class PipelineConfigurer {
|
|||
Messages.pipelineAlreadyConfigured,
|
||||
constants.BrowsePipeline);
|
||||
if (browsePipeline) {
|
||||
vscode.commands.executeCommand('browse-pipeline', { fullId: resourceId });
|
||||
let existingPipelineUrl = await this.appServiceClient.getVstsPipelineUrl(resourceId);
|
||||
telemetryHelper.setTelemetry(TelemetryKeys.BrowsedExistingPipeline, 'true');
|
||||
vscode.env.openExternal(vscode.Uri.parse(existingPipelineUrl));
|
||||
throw new UserCancelledError();
|
||||
}
|
||||
}
|
||||
else if (siteConfig.scmType && siteConfig.scmType.toLowerCase() !== '' && siteConfig.scmType.toLowerCase() !== 'none') {
|
||||
else if (siteConfig.scmType && siteConfig.scmType !== '' && siteConfig.scmType.toLowerCase() !== ScmTypes.NONE.toLowerCase()) {
|
||||
let result = await this.controlProvider.showInformationBox(constants.DeploymentResourceAlreadyConfigured, Messages.deploymentCenterAlreadyConfigured, constants.BrowseDeploymentSource);
|
||||
if (result === constants.BrowseDeploymentSource) {
|
||||
let deploymentCenterUrl: string = await this.appServiceClient.getDeploymentCenterUrl(resourceId);
|
||||
telemetryHelper.setTelemetry(TelemetryKeys.OpenedDeploymentCenter, 'true');
|
||||
telemetryHelper.setTelemetry(TelemetryKeys.BrowsedDeploymentCenter, 'true');
|
||||
await vscode.env.openExternal(vscode.Uri.parse(deploymentCenterUrl));
|
||||
throw new UserCancelledError();
|
||||
}
|
||||
|
@ -496,7 +497,7 @@ class PipelineConfigurer {
|
|||
private async updateScmType(queuedPipeline: Build) {
|
||||
await this.appServiceClient.updateScmType(this.inputs.targetResource.resource.id);
|
||||
|
||||
let metadata = await this.appServiceClient.getSiteMetadata(this.inputs.targetResource.resource.id);
|
||||
let metadata = await this.appServiceClient.getAppServiceMetadata(this.inputs.targetResource.resource.id);
|
||||
let organizationId = await this.azureDevOpsClient.getOrganizationIdFromName(this.inputs.organizationName);
|
||||
metadata["properties"] = {
|
||||
"VSTSRM_ProjectId": `${this.inputs.project.id}`,
|
||||
|
@ -506,7 +507,7 @@ class PipelineConfigurer {
|
|||
"VSTSRM_ConfiguredCDEndPoint": `${queuedPipeline.definition._links.web.href}`,
|
||||
"VSTSRM_ReleaseDefinitionId": `${queuedPipeline.definition.id}`
|
||||
};
|
||||
await this.appServiceClient.updateSiteMetadata(this.inputs.targetResource.resource.id, metadata);
|
||||
await this.appServiceClient.updateAppServiceMetadata(this.inputs.targetResource.resource.id, metadata);
|
||||
await this.appServiceClient.publishDeploymentToAppService(
|
||||
this.inputs.targetResource.resource.id,
|
||||
queuedPipeline.definition._links.web.href,
|
||||
|
|
|
@ -124,7 +124,7 @@ export class QuickPickItemWithData implements QuickPickItem {
|
|||
|
||||
export class ParsedAzureResourceId {
|
||||
public resourceId: string;
|
||||
public subscription: string;
|
||||
public subscriptionId: string;
|
||||
public resourceGroup: string;
|
||||
public resourceType: string;
|
||||
public resourceProvider: string;
|
||||
|
@ -148,7 +148,7 @@ export class ParsedAzureResourceId {
|
|||
for (let i = 0; i < parts.length; i++) {
|
||||
switch (i) {
|
||||
case 1:
|
||||
this.subscription = parts[1];
|
||||
this.subscriptionId = parts[1];
|
||||
break;
|
||||
case 3:
|
||||
this.resourceGroup = parts[3];
|
||||
|
@ -189,4 +189,4 @@ export interface AadApplication {
|
|||
export interface GitBranchDetails {
|
||||
remoteName: string;
|
||||
branch: string;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -147,4 +147,5 @@ export const VstsRmScmType = 'VSTSRM';
|
|||
export const DeploymentResourceAlreadyConfigured = 'DeploymentResourceAlreadyConfigured';
|
||||
export const PipelineAlreadyConfigure = 'PipelineAlreadyConfigure';
|
||||
export const BrowseDeploymentSource = 'BrowseDeploymentSource';
|
||||
export const BrowsePipeline = 'BrowsePipeline';
|
||||
export const BrowsePipeline = 'BrowsePipeline';
|
||||
export const BrowseNotAvailableConfigurePipeline = 'BrowseNotAvailableConfigurePipeline';
|
||||
|
|
|
@ -52,10 +52,13 @@ export class Messages {
|
|||
public static azureServicePrincipalFailedMessage: string =`Failed while creating Azure service principal.`;
|
||||
public static roleAssignmentFailedMessage: string =`Failed while role assignement.`;
|
||||
public static waitForAzureSignIn: string =`Waiting for Azure sign-in...`;
|
||||
public static invalidAzureResourceId: string = 'Azure Resource Id: %s, could not be parsed correctly. Kindly verify if the Id is correct.'
|
||||
public static invalidAzureResourceId: string = 'Azure Resource Id: %s, could not be parsed correctly. Kindly verify if the Id is correct.';
|
||||
public static userCancelledExcecption = 'User cancelled the action';
|
||||
public static deploymentCenterAlreadyConfigured = 'Deployment source of type: %s is already setup for your web app, you can view more by browsing to deployment center.';
|
||||
public static pipelineAlreadyConfigured = 'Pipeline is already setup for your web app.';
|
||||
public static cannotFindPipelineUrlInMetaDataException = 'We were unable to find pipeline url for the app service. This can be caused due to corrupt/invalida metadata of site. You can open deployment center for more information.'
|
||||
public static cannotFindPipelineUrlInMetaDataException = 'We were unable to find pipeline url for the app service. This can be caused due to corrupt/invalida metadata of site. You can open deployment center for more information.';
|
||||
public static cannotFindOrganizationWithName = 'Unable to find organization with name: %s';
|
||||
public static browseNotAvailableConfigurePipeline = 'Pipeline is not setup on the Azure resource. You can configure pipeline on the resource by click on the below button.';
|
||||
public static didNotRecieveAzureResourceNodeToProcess = 'Unable to browse pipeline as the selected item is not a valid Azure Resource node. Kindly select a valid Azure Resource.';
|
||||
|
||||
}
|
||||
|
|
|
@ -12,8 +12,9 @@ export class TelemetryKeys {
|
|||
public static GitFolderExists: string = 'gitFolderExists';
|
||||
public static PipelineAlreadyConfigured: string = 'pipelineAlreadyConfigured';
|
||||
public static ScmType: string = 'scmType';
|
||||
public static OpenedDeploymentCenter = 'openedDeploymentCenter';
|
||||
public static BrowsedDeploymentCenter = 'openedDeploymentCenter';
|
||||
public static BrowsedExistingPipeline = 'browsedExistingPipeline';
|
||||
public static ClickedConfigurePipeline = 'ClickedConfigurePipeline';
|
||||
|
||||
// Durations
|
||||
public static ExtensionActivationDuration = 'extensionActivationDuration';
|
||||
|
@ -25,4 +26,4 @@ export class TelemetryKeys {
|
|||
public static ProjectListCount = 'ProjectListCount';
|
||||
public static WebAppListCount = 'WebAppListCount';
|
||||
public static PipelineTempateListCount = 'pipelineTempateListCount';
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче