Added telemetry helper and set telemetry and configured telemetry events
This commit is contained in:
Родитель
1428650d7f
Коммит
33928dc06f
|
@ -71,7 +71,13 @@
|
|||
],
|
||||
"configuration": {
|
||||
"title": "Azure Pipelines extension configuration.",
|
||||
"properties": {}
|
||||
"properties": {
|
||||
"[azure-pipelines].configure" : {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Enable to opt-in for Configure Pipeline feature."
|
||||
}
|
||||
}
|
||||
},
|
||||
"configurationDefaults": {
|
||||
"[azure-pipelines]": {
|
||||
|
|
|
@ -3,10 +3,11 @@ import { registerCommand, IActionContext, createApiProvider } from 'vscode-azure
|
|||
import { AzureExtensionApi, AzureExtensionApiProvider } from 'vscode-azureextensionui/api';
|
||||
|
||||
import { configurePipeline } from './configure';
|
||||
import { Messages } from './messages';
|
||||
import { Messages } from './resources/messages';
|
||||
import { AzureAccountExtensionExports, extensionVariables } from './model/models';
|
||||
import { TelemetryHelper } from './helper/telemetryHelper';
|
||||
|
||||
export async function activateConfigurePipeline(context: vscode.ExtensionContext): Promise<AzureExtensionApiProvider> {
|
||||
export async function activateConfigurePipeline(): Promise<AzureExtensionApiProvider> {
|
||||
let azureAccountExtension = vscode.extensions.getExtension("ms-vscode.azure-account");
|
||||
if (!azureAccountExtension) {
|
||||
throw new Error(Messages.azureAccountExntesionUnavailable);
|
||||
|
@ -23,7 +24,8 @@ export async function activateConfigurePipeline(context: vscode.ExtensionContext
|
|||
// The commandId parameter must match the command field in package.json
|
||||
registerCommand('configure-pipeline', async (actionContext: IActionContext, node: any) => {
|
||||
// The code you place here will be executed every time your command is executed
|
||||
await configurePipeline(actionContext, node);
|
||||
let telemetryHelper = new TelemetryHelper(actionContext, 'configure', journeyId);
|
||||
await configurePipeline(telemetryHelper, node);
|
||||
});
|
||||
|
||||
return createApiProvider([<AzureExtensionApi>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { AzureResourceClient } from './azureResourceClient';
|
||||
import { Messages } from '../../messages';
|
||||
import { Messages } from '../../resources/messages';
|
||||
import { ResourceListResult, GenericResource } from 'azure-arm-resource/lib/resource/models';
|
||||
import { ServiceClientCredentials } from 'ms-rest';
|
||||
import { WebAppKind } from '../../model/models';
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { BuildDefinition, Build } from '../../model/azureDevOps';
|
||||
import { Messages } from '../../messages';
|
||||
import { Messages } from '../../resources/messages';
|
||||
import { Organization, DevOpsProject } from '../../model/models';
|
||||
import { ReservedHostNames } from '../../constants';
|
||||
import { ReservedHostNames } from '../../resources/constants';
|
||||
import { RestClient } from '../restClient';
|
||||
import { ServiceClientCredentials, UrlBasedRequestPrepareOptions } from 'ms-rest';
|
||||
import { sleepForMilliSeconds, stringCompareFunction } from "../../helper/commonHelper";
|
||||
|
|
|
@ -2,43 +2,63 @@ const uuid = require('uuid/v4');
|
|||
import { AppServiceClient } from './clients/azure/appServiceClient';
|
||||
import { AzureDevOpsClient } from './clients/devOps/azureDevOpsClient';
|
||||
import { AzureDevOpsHelper } from './helper/devOps/azureDevOpsHelper';
|
||||
import { AzureTreeItem, IActionContext } from 'vscode-azureextensionui';
|
||||
import { AzureTreeItem, UserCancelledError } from 'vscode-azureextensionui';
|
||||
import { exit } from 'process';
|
||||
import { generateDevOpsProjectName } from './helper/commonHelper';
|
||||
import { GenericResource } from 'azure-arm-resource/lib/resource/models';
|
||||
import { GraphHelper } from './helper/graphHelper';
|
||||
import { LocalGitRepoHelper } from './helper/LocalGitRepoHelper';
|
||||
import { Messages } from './messages';
|
||||
import { Messages } from './resources/messages';
|
||||
import { QuickPickItem } from 'vscode';
|
||||
import { ServiceConnectionHelper } from './helper/devOps/serviceConnectionHelper';
|
||||
import { SourceOptions, RepositoryProvider, extensionVariables, WizardInputs, WebAppKind, PipelineTemplate, QuickPickItemWithData } from './model/models';
|
||||
import { TracePoints } from './resources/tracePoints';
|
||||
import * as path from 'path';
|
||||
import * as templateHelper from './helper/templateHelper';
|
||||
import * as utils from 'util';
|
||||
import * as vscode from 'vscode';
|
||||
import { TelemetryHelper } from './helper/telemetryHelper';
|
||||
|
||||
export async function configurePipeline(actionContext: IActionContext, node: AzureTreeItem) {
|
||||
export async function configurePipeline(telemetryHelper: TelemetryHelper, node: AzureTreeItem) {
|
||||
try {
|
||||
telemetryHelper.setTelemetry(TracePoints.CommandStartTime, Date.UTC.toString());
|
||||
if (!(await extensionVariables.azureAccountExtensionApi.waitForLogin())) {
|
||||
// set telemetry
|
||||
telemetryHelper.setTelemetry(TracePoints.AzureLoginRequired, 'true');
|
||||
|
||||
let signIn = await vscode.window.showInformationMessage(Messages.azureLoginRequired, Messages.signInLabel);
|
||||
if(signIn.toLowerCase() === Messages.signInLabel.toLowerCase()) {
|
||||
if (signIn.toLowerCase() === Messages.signInLabel.toLowerCase()) {
|
||||
await vscode.commands.executeCommand("azure-account.login");
|
||||
}
|
||||
else {
|
||||
throw new Error(Messages.azureLoginRequired);
|
||||
let error = new Error(Messages.azureLoginRequired);
|
||||
extensionVariables.reporter.sendTelemetryEvent(
|
||||
TracePoints.AzureLoginFailure,
|
||||
{
|
||||
'errorMessage': error.message
|
||||
}
|
||||
);
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
var configurer = new PipelineConfigurer();
|
||||
var configurer = new PipelineConfigurer(telemetryHelper);
|
||||
await configurer.configure(node);
|
||||
}
|
||||
catch (error) {
|
||||
// log error in telemetery.
|
||||
extensionVariables.outputChannel.appendLine(error.message);
|
||||
vscode.window.showErrorMessage(error.message);
|
||||
actionContext.telemetry.properties.error = error;
|
||||
actionContext.telemetry.properties.errorMessage = error.message;
|
||||
if (error instanceof UserCancelledError) {
|
||||
telemetryHelper.setError(error);
|
||||
}
|
||||
else {
|
||||
telemetryHelper.setError(error);
|
||||
extensionVariables.outputChannel.appendLine(error.message);
|
||||
vscode.window.showErrorMessage(error.message);
|
||||
}
|
||||
}
|
||||
|
||||
telemetryHelper.setTelemetry(TracePoints.CommandEndTime, Date.UTC.toString());
|
||||
}
|
||||
|
||||
class PipelineConfigurer {
|
||||
|
@ -50,26 +70,38 @@ class PipelineConfigurer {
|
|||
private appServiceClient: AppServiceClient;
|
||||
private workspacePath: string;
|
||||
private uniqueResourceNameSuffix: string;
|
||||
private telemetryHelper: TelemetryHelper;
|
||||
|
||||
public constructor() {
|
||||
public constructor(telemetryHelper: TelemetryHelper) {
|
||||
this.inputs = new WizardInputs();
|
||||
this.inputs.azureSession = extensionVariables.azureAccountExtensionApi.sessions[0];
|
||||
this.azureDevOpsClient = new AzureDevOpsClient(this.inputs.azureSession.credentials);
|
||||
this.azureDevOpsHelper = new AzureDevOpsHelper(this.azureDevOpsClient);
|
||||
this.uniqueResourceNameSuffix = uuid().substr(0, 5);
|
||||
this.telemetryHelper = telemetryHelper;
|
||||
}
|
||||
|
||||
public async configure(node: any) {
|
||||
this.telemetryHelper.setCurrentStep('GetAllRequiredInputs');
|
||||
await this.getAllRequiredInputs(node);
|
||||
|
||||
this.telemetryHelper.setCurrentStep('CreatePreRequisites');
|
||||
await this.createPreRequisites();
|
||||
|
||||
this.telemetryHelper.setCurrentStep('CheckInPipeline');
|
||||
await this.checkInPipelineFileToRepository();
|
||||
|
||||
this.telemetryHelper.setCurrentStep('CreateAndRunPipeline');
|
||||
let queuedPipelineUrl = await vscode.window.withProgress<string>({ location: vscode.ProgressLocation.Notification, title: Messages.configuringPipelineAndDeployment }, () => {
|
||||
let pipelineName = `${this.inputs.targetResource.resource.name}.${this.uniqueResourceNameSuffix}`;
|
||||
return this.azureDevOpsHelper.createAndRunPipeline(pipelineName, this.inputs);
|
||||
});
|
||||
|
||||
this.telemetryHelper.setCurrentStep('DisplayCreatedPipeline');
|
||||
vscode.window.showInformationMessage(Messages.pipelineSetupSuccessfully, Messages.browsePipeline)
|
||||
.then((action: string) => {
|
||||
if (action && action.toLowerCase() === Messages.browsePipeline.toLowerCase()) {
|
||||
this.telemetryHelper.setTelemetry(TracePoints.ViewPipelineClicked, 'true');
|
||||
vscode.env.openExternal(vscode.Uri.parse(queuedPipelineUrl));
|
||||
}
|
||||
});
|
||||
|
@ -90,7 +122,7 @@ class PipelineConfigurer {
|
|||
if (this.inputs.isNewOrganization) {
|
||||
this.inputs.project = {
|
||||
id: "",
|
||||
name: generateDevOpsProjectName(this.inputs.sourceRepository.repositoryName)
|
||||
name: generateDevOpsProjectName(this.inputs.sourceRepository.repositoryName)
|
||||
};
|
||||
await vscode.window.withProgress(
|
||||
{
|
||||
|
@ -108,6 +140,10 @@ class PipelineConfigurer {
|
|||
})
|
||||
.then((projectId) => {
|
||||
this.inputs.project.id = projectId;
|
||||
})
|
||||
.catch((error) => {
|
||||
this.telemetryHelper.logError(TracePoints.CreateOrganizationFailure, error);
|
||||
throw error;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -119,13 +155,13 @@ class PipelineConfigurer {
|
|||
await this.createAzureRMServiceConnection();
|
||||
}
|
||||
|
||||
|
||||
private async analyzeNode(node: any): Promise<void> {
|
||||
if (node instanceof AzureTreeItem) {
|
||||
await this.extractAzureResourceFromNode(node);
|
||||
}
|
||||
else if (node && node.fsPath) {
|
||||
this.workspacePath = node.fsPath;
|
||||
this.telemetryHelper.setTelemetry(TracePoints.SourceRepoLocation, SourceOptions.CurrentWorkspace);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -143,6 +179,7 @@ class PipelineConfigurer {
|
|||
{ placeHolder: Messages.selectFolderOrRepository }
|
||||
);
|
||||
|
||||
this.telemetryHelper.setTelemetry(TracePoints.SourceRepoLocation, selectedSourceOption.label);
|
||||
switch (selectedSourceOption.label) {
|
||||
case SourceOptions.BrowseLocalMachine:
|
||||
let selectedFolder: vscode.Uri[] = await vscode.window.showOpenDialog(
|
||||
|
@ -175,6 +212,9 @@ class PipelineConfigurer {
|
|||
this.localGitRepoHelper = await LocalGitRepoHelper.GetHelperInstance(workspacePath);
|
||||
this.inputs.sourceRepository = await this.localGitRepoHelper.getGitRepoDetails(workspacePath);
|
||||
|
||||
// set telemetry
|
||||
this.telemetryHelper.setTelemetry(TracePoints.RepoProvider, this.inputs.sourceRepository.repositoryProvider);
|
||||
|
||||
if (this.inputs.sourceRepository.repositoryProvider === RepositoryProvider.AzureRepos) {
|
||||
let orgAndProjectName = AzureDevOpsHelper.getOrganizationAndProjectNameFromRepositoryUrl(this.inputs.sourceRepository.remoteUrl);
|
||||
this.inputs.organizationName = orgAndProjectName.orgnizationName;
|
||||
|
@ -229,6 +269,8 @@ class PipelineConfigurer {
|
|||
this.inputs.project = selectedProject.data;
|
||||
}
|
||||
else {
|
||||
this.telemetryHelper.setTelemetry(TracePoints.NewOrganization, 'true');
|
||||
|
||||
this.inputs.isNewOrganization = true;
|
||||
this.inputs.organizationName = await extensionVariables.ui.showInputBox({
|
||||
placeHolder: Messages.enterAzureDevOpsOrganizationName,
|
||||
|
@ -240,7 +282,7 @@ class PipelineConfigurer {
|
|||
|
||||
private async getSelectedPipeline(): Promise<void> {
|
||||
let appropriatePipelines: PipelineTemplate[] = await vscode.window.withProgress(
|
||||
{ location: vscode.ProgressLocation.Notification, title: Messages.analyzingRepo },
|
||||
{ location: vscode.ProgressLocation.Notification, title: Messages.analyzingRepo },
|
||||
() => templateHelper.analyzeRepoAndListAppropriatePipeline(this.inputs.sourceRepository.localPath)
|
||||
);
|
||||
|
||||
|
@ -248,10 +290,10 @@ class PipelineConfigurer {
|
|||
let selectedOption = await extensionVariables.ui.showQuickPick(appropriatePipelines.map((pipeline) => { return { label: pipeline.label }; }), {
|
||||
placeHolder: Messages.selectPipelineTemplate
|
||||
});
|
||||
|
||||
this.inputs.pipelineParameters.pipelineTemplate = appropriatePipelines.find((pipeline) => {
|
||||
return pipeline.label === selectedOption.label;
|
||||
});
|
||||
this.telemetryHelper.setTelemetry(TracePoints.ChosenTemplate, this.inputs.pipelineParameters.pipelineTemplate.label);
|
||||
}
|
||||
|
||||
private async getAzureResourceDetails(): Promise<void> {
|
||||
|
@ -267,7 +309,7 @@ class PipelineConfigurer {
|
|||
// show available resources and get the chosen one
|
||||
this.appServiceClient = new AppServiceClient(extensionVariables.azureAccountExtensionApi.sessions[0].credentials, this.inputs.targetResource.subscriptionId);
|
||||
let selectedResource: QuickPickItemWithData = await extensionVariables.ui.showQuickPick(
|
||||
this.appServiceClient.GetAppServices(WebAppKind.WindowsApp).then((webApps) => webApps.map(x => {return {label: x.name, data: x};})),
|
||||
this.appServiceClient.GetAppServices(WebAppKind.WindowsApp).then((webApps) => webApps.map(x => { return { label: x.name, data: x }; })),
|
||||
{ placeHolder: Messages.selectWebApp });
|
||||
this.inputs.targetResource.resource = selectedResource.data;
|
||||
}
|
||||
|
@ -277,18 +319,36 @@ class PipelineConfigurer {
|
|||
this.serviceConnectionHelper = new ServiceConnectionHelper(this.inputs.organizationName, this.inputs.project.name, this.azureDevOpsClient);
|
||||
}
|
||||
|
||||
let githubPat = await extensionVariables.ui.showInputBox({ placeHolder: Messages.enterGitHubPat, prompt: Messages.githubPatTokenHelpMessage });
|
||||
// Get GitHub PAT as an input from the user.
|
||||
let githubPat = null;
|
||||
try {
|
||||
// TO-DO Create a new helper function to time and log time for all user inputs.
|
||||
// Log the time taken by the user to enter GitHub PAT
|
||||
this.telemetryHelper.setTelemetry(TracePoints.GitHubPatStartTime, Date.UTC.toString());
|
||||
githubPat = await extensionVariables.ui.showInputBox({ placeHolder: Messages.enterGitHubPat, prompt: Messages.githubPatTokenHelpMessage });
|
||||
this.telemetryHelper.setTelemetry(TracePoints.GitHubPatEndTime, Date.UTC.toString());
|
||||
}
|
||||
catch (error) {
|
||||
// This logs when the user cancels the operation.
|
||||
this.telemetryHelper.setTelemetry(TracePoints.GitHubPatEndTime, Date.UTC.toString());
|
||||
throw error;
|
||||
}
|
||||
|
||||
// Create GitHub service connection in Azure DevOps
|
||||
await vscode.window.withProgress(
|
||||
{
|
||||
location: vscode.ProgressLocation.Notification,
|
||||
title: Messages.creatingGitHubServiceConnection
|
||||
},
|
||||
() => {
|
||||
let serviceConnectionName = `${this.inputs.sourceRepository.repositoryName}-${this.uniqueResourceNameSuffix}`;
|
||||
return this.serviceConnectionHelper.createGitHubServiceConnection(serviceConnectionName, githubPat)
|
||||
.then((serviceConnectionId) => {
|
||||
this.inputs.sourceRepository.serviceConnectionId = serviceConnectionId;
|
||||
});
|
||||
async () => {
|
||||
try {
|
||||
let serviceConnectionName = `${this.inputs.sourceRepository.repositoryName}-${this.uniqueResourceNameSuffix}`;
|
||||
this.inputs.sourceRepository.serviceConnectionId = await this.serviceConnectionHelper.createGitHubServiceConnection(serviceConnectionName, githubPat);
|
||||
}
|
||||
catch (error) {
|
||||
this.telemetryHelper.logError(TracePoints.GitHubServiceConnectionError, error);
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -303,14 +363,18 @@ class PipelineConfigurer {
|
|||
location: vscode.ProgressLocation.Notification,
|
||||
title: utils.format(Messages.creatingAzureServiceConnection, this.inputs.targetResource.subscriptionId)
|
||||
},
|
||||
() => {
|
||||
let scope = this.inputs.targetResource.resource.id;
|
||||
let aadAppName = GraphHelper.generateAadApplicationName(this.inputs.organizationName, this.inputs.project.name);
|
||||
return GraphHelper.createSpnAndAssignRole(this.inputs.azureSession, aadAppName, scope)
|
||||
.then((aadApp) => {
|
||||
async () => {
|
||||
try {
|
||||
let scope = this.inputs.targetResource.resource.id;
|
||||
let aadAppName = GraphHelper.generateAadApplicationName(this.inputs.organizationName, this.inputs.project.name);
|
||||
let aadApp = await GraphHelper.createSpnAndAssignRole(this.inputs.azureSession, aadAppName, scope);
|
||||
let serviceConnectionName = `${this.inputs.targetResource.resource.name}-${this.uniqueResourceNameSuffix}`;
|
||||
return this.serviceConnectionHelper.createAzureServiceConnection(serviceConnectionName, this.inputs.azureSession.tenantId, this.inputs.targetResource.subscriptionId, scope, aadApp);
|
||||
});
|
||||
}
|
||||
catch (error) {
|
||||
this.telemetryHelper.logError(TracePoints.AzureServiceConnectionCreateFailure, error);
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -324,13 +388,20 @@ class PipelineConfigurer {
|
|||
let commitOrDiscard = await vscode.window.showInformationMessage(Messages.modifyAndCommitFile, Messages.commitAndPush, Messages.discardPipeline);
|
||||
if (commitOrDiscard.toLowerCase() === Messages.commitAndPush.toLowerCase()) {
|
||||
await vscode.window.withProgress({ location: vscode.ProgressLocation.Notification, title: Messages.configuringPipelineAndDeployment }, async (progress) => {
|
||||
// handle when the branch is not upto date with remote branch and push fails
|
||||
let commitDetails = await this.localGitRepoHelper.commitAndPushPipelineFile(this.inputs.pipelineParameters.pipelineFilePath);
|
||||
this.inputs.sourceRepository.branch = commitDetails.branch;
|
||||
this.inputs.sourceRepository.commitId = commitDetails.commitId;
|
||||
try {
|
||||
// handle when the branch is not upto date with remote branch and push fails
|
||||
let commitDetails = await this.localGitRepoHelper.commitAndPushPipelineFile(this.inputs.pipelineParameters.pipelineFilePath);
|
||||
this.inputs.sourceRepository.branch = commitDetails.branch;
|
||||
this.inputs.sourceRepository.commitId = commitDetails.commitId;
|
||||
}
|
||||
catch (error) {
|
||||
this.telemetryHelper.logError(TracePoints.CheckInPipelineFailure, error);
|
||||
throw (error);
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
this.telemetryHelper.setTelemetry(TracePoints.PipelineDiscarded, 'true');
|
||||
throw new Error(Messages.operationCancelled);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ import { AzureDevOpsHelper } from './devOps/azureDevOpsHelper';
|
|||
import { BranchSummary } from 'simple-git/typings/response';
|
||||
import { GitHubProvider } from './gitHubHelper';
|
||||
import { GitRepositoryParameters, RepositoryProvider } from '../model/models';
|
||||
import { Messages } from '../messages';
|
||||
import { Messages } from '../resources/messages';
|
||||
import * as fs from 'fs';
|
||||
import * as git from 'simple-git/promise';
|
||||
import * as path from 'path';
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { AzureDevOpsClient } from '../../clients/devOps/azureDevOpsClient';
|
||||
import { BuildDefinition, BuildDefinitionRepositoryProperties, Build } from '../../model/azureDevOps';
|
||||
import { Messages } from '../../messages';
|
||||
import { Messages } from '../../resources/messages';
|
||||
import { WizardInputs, RepositoryProvider } from '../../model/models';
|
||||
import * as util from 'util';
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { AadApplication } from '../../model/models';
|
||||
import { AzureDevOpsClient } from '../../clients/devOps/azureDevOpsClient';
|
||||
import { Messages } from '../../messages';
|
||||
import { Messages } from '../../resources/messages';
|
||||
import { ServiceConnectionClient } from '../../clients/devOps/serviceConnectionClient';
|
||||
import * as util from 'util';
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ const uuid = require('uuid/v1');
|
|||
import { AzureEnvironment } from 'ms-rest-azure';
|
||||
import { AzureSession, Token, AadApplication } from '../model/models';
|
||||
import { generateRandomPassword } from './commonHelper';
|
||||
import { Messages } from '../messages';
|
||||
import { Messages } from '../resources/messages';
|
||||
import { RestClient } from '../clients/restClient';
|
||||
import { TokenCredentials, UrlBasedRequestPrepareOptions, ServiceClientCredentials } from 'ms-rest';
|
||||
import { TokenResponse, MemoryCache, AuthenticationContext } from 'adal-node';
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
import { IActionContext, ITelemetryReporter } from "vscode-azureextensionui";
|
||||
|
||||
import { extensionVariables } from "../model/models";
|
||||
import { TracePoints } from "../resources/tracePoints";
|
||||
|
||||
const uuid = require('uuid/v4');
|
||||
|
||||
export class TelemetryHelper {
|
||||
private actionContext: IActionContext;
|
||||
private telemetryReporter: ITelemetryReporter;
|
||||
private journeyId: string;
|
||||
private command: string;
|
||||
constructor(actionContext: IActionContext, command: string) {
|
||||
this.actionContext = actionContext;
|
||||
this.telemetryReporter = extensionVariables.reporter;
|
||||
this.journeyId = uuid();
|
||||
this.command = command;
|
||||
this.setTelemetry(TracePoints.Command, command);
|
||||
this.setTelemetry(TracePoints.JourneyId, this.journeyId);
|
||||
}
|
||||
|
||||
public setTelemetry(key: string, value: string) {
|
||||
if (key) {
|
||||
this.actionContext.telemetry.properties[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public setError(error: Error) {
|
||||
this.actionContext.telemetry.properties.error = error.stack;
|
||||
this.actionContext.telemetry.properties.errorMessage = error.message;
|
||||
}
|
||||
|
||||
public setResult(result: 'Succeeded' | 'Failed' | 'Canceled', error?: Error, currentStep?: string) {
|
||||
this.actionContext.telemetry.properties.result = result;
|
||||
if (result === "Failed" && error) {
|
||||
this.setError(error);
|
||||
}
|
||||
else if(result === 'Canceled' && currentStep) {
|
||||
this.setCurrentStep(currentStep);
|
||||
}
|
||||
}
|
||||
|
||||
public setCurrentStep(stepName: string) {
|
||||
this.actionContext.telemetry.properties.cancelStep = stepName;
|
||||
}
|
||||
|
||||
public logError(tracePoint: string, error: Error) {
|
||||
this.telemetryReporter.sendTelemetryEvent(
|
||||
tracePoint,
|
||||
{
|
||||
'journeyId': this.journeyId,
|
||||
'command': this.command,
|
||||
'error': `Error: ${error.name}, Error.Message: ${error.message}, Error.Stack: ${error.stack}`
|
||||
});
|
||||
}
|
||||
|
||||
public logData(tracePoint: string, data: string) {
|
||||
this.telemetryReporter.sendTelemetryEvent(
|
||||
tracePoint,
|
||||
{
|
||||
'journeyId': this.journeyId,
|
||||
'command': this.command,
|
||||
'data': data
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
export class TracePoints {
|
||||
// Combined telemetry trace points
|
||||
public static telemetryKey: string = '';
|
||||
public static CurrentFunction: string = 'currentFunction';
|
||||
public static RepoProvider: string = 'repoProvider';
|
||||
public static AzureLoginRequired: string = 'azureLoginRequired';
|
||||
public static Command: string = 'command';
|
||||
public static JourneyId: string = 'journeyId';
|
||||
public static EntryPoint: string = 'entryPoint';
|
||||
public static SourceRepoLocation: string = 'sourceRepoLocation';
|
||||
public static NewOrganization: string = 'newOrganization';
|
||||
public static ChosenTemplate: string = 'chosenTemplate';
|
||||
public static PipelineDiscarded: string = 'pipelineDiscarded';
|
||||
public static ViewPipelineClicked: string = 'viewPipelineClicked';
|
||||
public static GitHubPatStartTime = 'gitHubPatStartTime';
|
||||
public static GitHubPatEndTime = 'gitHubPatEndTime';
|
||||
public static CommandStartTime = 'commandStartTime';
|
||||
public static CommandEndTime = 'commandEndTime';
|
||||
public static OrganizationListDuration = 'organizationListDuration';
|
||||
public static OrganizationListCount = 'organizationListCount';
|
||||
public static ProjectListDuration = 'projectListDuration';
|
||||
public static ProjectListCount = 'projectListCount';
|
||||
public static AzureResourceListDuration = 'azureResourceListDuration';
|
||||
public static AzureResourceListCount = 'azureResourceListCount';
|
||||
|
||||
|
||||
|
||||
// Failure trace points
|
||||
public static AzureLoginFailure = 'azureLoginFailure';
|
||||
public static AzureServiceConnectionCreateFailure = 'AzureServiceConnectionCreateFailure';
|
||||
public static CheckInPipelineFailure = 'checkInPipelineFailure';
|
||||
public static CreateOrganizationFailure = 'createOrganizationFailure';
|
||||
public static GitHubServiceConnectionError = 'gitHubServiceConnectionError';
|
||||
}
|
|
@ -19,9 +19,24 @@ let perfStats = {
|
|||
loadEndTime: undefined
|
||||
};
|
||||
|
||||
const configurePipelineEnabled: boolean = vscode.workspace.getConfiguration('[azure-pipelines]', null).get('configure') ? true : false;
|
||||
|
||||
export async function activate(context: vscode.ExtensionContext) {
|
||||
logger.log('Extension has been activated!', 'ExtensionActivated');
|
||||
setTelemetryReporter(context);
|
||||
|
||||
await callWithTelemetryAndErrorHandling('azurePipelines.activate', async (activateContext: IActionContext) => {
|
||||
activateContext.telemetry.properties['configurePipelineEnabled'] = `${configurePipelineEnabled}`;
|
||||
await activateYmlContributor(context, activateContext);
|
||||
if (configurePipelineEnabled) {
|
||||
await activateConfigurePipeline();
|
||||
}
|
||||
});
|
||||
|
||||
return schemacontributor.schemaContributor;
|
||||
}
|
||||
|
||||
function setTelemetryReporter(context: vscode.ExtensionContext) {
|
||||
// Register ui extension variables is required to be done for telemetry to start flowing for extension activation and other events.
|
||||
// It also facilitates registering command and called events telemetry.
|
||||
extensionVariables.reporter = createTelemetryReporter(context);
|
||||
|
@ -30,51 +45,54 @@ export async function activate(context: vscode.ExtensionContext) {
|
|||
extensionVariables.context = context;
|
||||
extensionVariables.ui = new AzureUserInput(context.globalState);
|
||||
registerUIExtensionVariables(extensionVariables);
|
||||
}
|
||||
|
||||
await callWithTelemetryAndErrorHandling('azurePipelines.activate', async (activateContext: IActionContext) => {
|
||||
async function activateYmlContributor(context: vscode.ExtensionContext, activateContext: IActionContext) {
|
||||
if (activateContext) {
|
||||
activateContext.telemetry.properties.isActivationEvent = 'true';
|
||||
activateContext.telemetry.measurements.mainFileLoad = (perfStats.loadEndTime - perfStats.loadStartTime) / 1000;
|
||||
}
|
||||
|
||||
const serverOptions: languageclient.ServerOptions = getServerOptions(context);
|
||||
const clientOptions: languageclient.LanguageClientOptions = getClientOptions();
|
||||
const client = new languageclient.LanguageClient('azure-pipelines', 'Azure Pipelines Support', serverOptions, clientOptions);
|
||||
const serverOptions: languageclient.ServerOptions = getServerOptions(context);
|
||||
const clientOptions: languageclient.LanguageClientOptions = getClientOptions();
|
||||
const client = new languageclient.LanguageClient('azure-pipelines', 'Azure Pipelines Support', serverOptions, clientOptions);
|
||||
|
||||
const schemaAssociationService: schemaassociationservice.ISchemaAssociationService = new schemaassociationservice.SchemaAssociationService(context.extensionPath);
|
||||
const schemaAssociationService: schemaassociationservice.ISchemaAssociationService = new schemaassociationservice.SchemaAssociationService(context.extensionPath);
|
||||
|
||||
const disposable = client.start();
|
||||
context.subscriptions.push(disposable);
|
||||
const disposable = client.start();
|
||||
context.subscriptions.push(disposable);
|
||||
|
||||
const initialSchemaAssociations: schemaassociationservice.ISchemaAssociations = schemaAssociationService.getSchemaAssociation();
|
||||
const initialSchemaAssociations: schemaassociationservice.ISchemaAssociations = schemaAssociationService.getSchemaAssociation();
|
||||
|
||||
await client.onReady().then(() => {
|
||||
//logger.log(`${JSON.stringify(initialSchemaAssociations)}`, 'SendInitialSchemaAssociation');
|
||||
client.sendNotification(schemaassociationservice.SchemaAssociationNotification.type, initialSchemaAssociations);
|
||||
await client.onReady().then(() => {
|
||||
//logger.log(`${JSON.stringify(initialSchemaAssociations)}`, 'SendInitialSchemaAssociation');
|
||||
client.sendNotification(schemaassociationservice.SchemaAssociationNotification.type, initialSchemaAssociations);
|
||||
|
||||
// TODO: Should we get rid of these events and handle other events like Ctrl + Space? See when this event gets fired and send updated schema on that event.
|
||||
client.onRequest(schemacontributor.CUSTOM_SCHEMA_REQUEST, (resource: any) => {
|
||||
//logger.log('Custom schema request. Resource: ' + JSON.stringify(resource), 'CustomSchemaRequest');
|
||||
// TODO: Should we get rid of these events and handle other events like Ctrl + Space? See when this event gets fired and send updated schema on that event.
|
||||
client.onRequest(schemacontributor.CUSTOM_SCHEMA_REQUEST, (resource: any) => {
|
||||
//logger.log('Custom schema request. Resource: ' + JSON.stringify(resource), 'CustomSchemaRequest');
|
||||
|
||||
// TODO: Can this return the location of the new schema file?
|
||||
return schemacontributor.schemaContributor.requestCustomSchema(resource); // TODO: Have a single instance for the extension but dont return a global from this namespace.
|
||||
});
|
||||
// TODO: Can this return the location of the new schema file?
|
||||
return schemacontributor.schemaContributor.requestCustomSchema(resource); // TODO: Have a single instance for the extension but dont return a global from this namespace.
|
||||
});
|
||||
|
||||
// TODO: Can we get rid of this? Never seems to happen.
|
||||
client.onRequest(schemacontributor.CUSTOM_CONTENT_REQUEST, (uri: any) => {
|
||||
//logger.log('Custom content request.', 'CustomContentRequest');
|
||||
// TODO: Can we get rid of this? Never seems to happen.
|
||||
client.onRequest(schemacontributor.CUSTOM_CONTENT_REQUEST, (uri: any) => {
|
||||
//logger.log('Custom content request.', 'CustomContentRequest');
|
||||
|
||||
return schemacontributor.schemaContributor.requestCustomSchemaContent(uri);
|
||||
});
|
||||
}).catch((reason) => {
|
||||
return schemacontributor.schemaContributor.requestCustomSchemaContent(uri);
|
||||
});
|
||||
})
|
||||
.catch((reason) => {
|
||||
logger.log(JSON.stringify(reason), 'ClientOnReadyError');
|
||||
if (activateContext) {
|
||||
activateContext.errorHandling.suppressDisplay = true;
|
||||
}
|
||||
extensionVariables.reporter.sendTelemetryEvent('extension.languageserver.onReadyError', { 'reason': JSON.stringify(reason) });
|
||||
});
|
||||
|
||||
// TODO: Can we get rid of this since it's set in package.json?
|
||||
vscode.languages.setLanguageConfiguration('azure-pipelines', { wordPattern: /("(?:[^\\\"]*(?:\\.)?)*"?)|[^\s{}\[\],:]+/ });
|
||||
await activateConfigurePipeline(context);
|
||||
});
|
||||
|
||||
return schemacontributor.schemaContributor;
|
||||
// TODO: Can we get rid of this since it's set in package.json?
|
||||
vscode.languages.setLanguageConfiguration('azure-pipelines', { wordPattern: /("(?:[^\\\"]*(?:\\.)?)*"?)|[^\s{}\[\],:]+/ });
|
||||
}
|
||||
|
||||
function getServerOptions(context: vscode.ExtensionContext): languageclient.ServerOptions {
|
||||
|
|
Загрузка…
Ссылка в новой задаче