From 4a81e5296b192c0f125558bf669c9def878b95e2 Mon Sep 17 00:00:00 2001 From: Kanika Pasrija Date: Fri, 20 Mar 2020 13:59:11 +0530 Subject: [PATCH 1/8] template service - template dropdown --- .../clients/TemplateServiceClient.ts | 18 +++++++ src/configure/clients/restClient.ts | 17 +++++++ src/configure/configure.ts | 48 ++++++++++++++----- src/configure/model/models.ts | 48 ++++++++++++------- src/configure/model/templateModels.ts | 8 +++- 5 files changed, 110 insertions(+), 29 deletions(-) create mode 100644 src/configure/clients/TemplateServiceClient.ts diff --git a/src/configure/clients/TemplateServiceClient.ts b/src/configure/clients/TemplateServiceClient.ts new file mode 100644 index 00000000..faa71486 --- /dev/null +++ b/src/configure/clients/TemplateServiceClient.ts @@ -0,0 +1,18 @@ +import { RepoInfo } from "../model/models"; +import { RestClient } from "./restClient"; + +export class TemplateServiceClient { + private restClient: RestClient; + + public constructor() { + this.restClient = new RestClient(); + } + + public async getTemplates(body: RepoInfo): Promise { + return this.restClient.sendServiceRequest( + 'https://ts21.azurewebsites.net/Templates', + 'POST', + '2019-05-01', + body); + } +} \ No newline at end of file diff --git a/src/configure/clients/restClient.ts b/src/configure/clients/restClient.ts index b9bb1e6a..9c32b808 100644 --- a/src/configure/clients/restClient.ts +++ b/src/configure/clients/restClient.ts @@ -19,4 +19,21 @@ export class RestClient extends ServiceClient { }); }); } + + public sendServiceRequest(url: string, httpMethod: string, apiVersion: string, body?: any): Promise { + return this.sendRequest( + { + url: url, + method: httpMethod, + headers: { + "Content-Type": "application/json; charset=utf-8" + }, + queryParameters: { + 'api-version': apiVersion + }, + body: body, + deserializationMapper: null, + serializationMapper: null + }); + } } \ No newline at end of file diff --git a/src/configure/configure.ts b/src/configure/configure.ts index 5b845d12..4c5b10e6 100644 --- a/src/configure/configure.ts +++ b/src/configure/configure.ts @@ -5,6 +5,7 @@ import { AzureTreeItem, UserCancelledError } from 'vscode-azureextensionui'; const uuid = require('uuid/v4'); import { AppServiceClient } from './clients/azure/appServiceClient'; import { AzureResourceClient } from './clients/azure/azureResourceClient'; +import { TemplateServiceClient } from './clients/TemplateServiceClient'; import { Configurer } from './configurers/configurerBase'; import { ConfigurerFactory } from './configurers/configurerFactory'; import { AssetHandler } from './helper/AssetHandler'; @@ -17,7 +18,7 @@ import { LocalGitRepoHelper } from './helper/LocalGitRepoHelper'; import { Result, telemetryHelper } from './helper/telemetryHelper'; import * as templateHelper from './helper/templateHelper'; import { TemplateParameterHelper } from './helper/templateParameterHelper'; -import { extensionVariables, GitBranchDetails, GitRepositoryParameters, MustacheContext, ParsedAzureResourceId, QuickPickItemWithData, RepositoryAnalysisApplicationSettings, RepositoryProvider, SourceOptions, TargetKind, TargetResourceType, WizardInputs } from './model/models'; +import { extensionVariables, GitBranchDetails, GitRepositoryParameters, MustacheContext, ParsedAzureResourceId, QuickPickItemWithData, RepositoryAnalysisApplicationSettings, RepositoryProvider, SourceOptions, TargetKind, TargetResourceType, WizardInputs} from './model/models'; import { PipelineTemplate, TemplateAssetType } from './model/templateModels'; import * as constants from './resources/constants'; import { Messages } from './resources/messages'; @@ -412,15 +413,40 @@ class Orchestrator { //var repoAnalysisHelper = new RepoAnalysisHelper(this.inputs.azureSession); var repoAnalysisResult = null; //await repoAnalysisHelper.getRepositoryAnalysis(this.inputs.sourceRepository); + var templateServiceEnabled = false; - let appropriatePipelines: PipelineTemplate[] = await vscode.window.withProgress( - { location: vscode.ProgressLocation.Notification, title: Messages.analyzingRepo }, - () => templateHelper.analyzeRepoAndListAppropriatePipeline( - this.inputs.sourceRepository.localPath, - this.inputs.sourceRepository.repositoryProvider, - repoAnalysisResult, - this.inputs.pipelineConfiguration.params[constants.TargetResource]) - ); + //calling RepoAnalysis service + var repoDetails = { + "applicationSettingsList": [ + { + "language": "Docker", + "buildTargetName": "Dockerfile", + "deployTargetName": "Azure:AKS", + "workingDirectory": "wddddddddddddd" + } + ] + }; + + let serviceClient = new TemplateServiceClient(); + var appropriatePipelines; + if (templateServiceEnabled) { + appropriatePipelines = await serviceClient.getTemplates(repoDetails); + //sorting array weightwise + appropriatePipelines = appropriatePipelines.sort((a, b) => { + if (a.templateWeight > b.templateWeight) { return 1; } + else { return -1; } + }); + } + else { + appropriatePipelines = await vscode.window.withProgress( + { location: vscode.ProgressLocation.Notification, title: Messages.analyzingRepo }, + () => templateHelper.analyzeRepoAndListAppropriatePipeline( + this.inputs.sourceRepository.localPath, + this.inputs.sourceRepository.repositoryProvider, + repoAnalysisResult, + this.inputs.pipelineConfiguration.params[constants.TargetResource]) + ); + } // TO:DO- Get applicable pipelines for the repo type and azure target type if target already selected if (appropriatePipelines.length > 1) { @@ -429,12 +455,12 @@ class Orchestrator { appropriatePipelines.map((pipeline) => { return { label: pipeline.label }; }), { placeHolder: Messages.selectPipelineTemplate }, TelemetryKeys.PipelineTempateListCount); - this.inputs.pipelineConfiguration.template = appropriatePipelines.find((pipeline) => { + this.inputs.pipelineConfiguration.templateInfo = appropriatePipelines.find((pipeline) => { return pipeline.label === selectedOption.label; }); } else { - this.inputs.pipelineConfiguration.template = appropriatePipelines[0]; + this.inputs.pipelineConfiguration.templateInfo = appropriatePipelines[0]; } //If RepoAnalysis is disabled or didn't provided response related to language of selected template diff --git a/src/configure/model/models.ts b/src/configure/model/models.ts index 93e9c2e5..8e81c813 100644 --- a/src/configure/model/models.ts +++ b/src/configure/model/models.ts @@ -2,10 +2,11 @@ import { SubscriptionModels } from 'azure-arm-resource'; import { GenericResource } from 'azure-arm-resource/lib/resource/models'; import { ServiceClientCredentials } from 'ms-rest'; import { AzureEnvironment } from 'ms-rest-azure'; +import { Dictionary } from 'underscore'; import { ExtensionContext, OutputChannel, QuickPickItem, workspace } from 'vscode'; import { IAzureUserInput, ITelemetryReporter, UIExtensionVariables } from 'vscode-azureextensionui'; import { Messages } from '../resources/messages'; -import { PipelineTemplate } from './templateModels'; +import { PipelineTemplate, TemplateInfo } from './templateModels'; class ExtensionVariables implements UIExtensionVariables { public azureAccountExtensionApi: AzureAccountExtensionExports; @@ -23,6 +24,18 @@ class ExtensionVariables implements UIExtensionVariables { let extensionVariables = new ExtensionVariables(); export { extensionVariables }; +export class ApplicationSettings { + language: string; + buildTargetName: string; + deployTargetName: string; + workingDirectory: string; + settings?: Dictionary; +} + +export class RepoInfo { + applicationSettingsList: ApplicationSettings[]; +} + export class WizardInputs { organizationName: string; project: DevOpsProject; @@ -82,6 +95,7 @@ export class AzureSession { export class PipelineConfiguration { filePath: string; template: PipelineTemplate; + templateInfo: TemplateInfo; workingDirectory: string; params: { [key: string]: any } = {}; assets: { [key: string]: any } = {}; @@ -140,26 +154,26 @@ export class ParsedAzureResourceId { for (let i = 0; i < parts.length; i++) { switch (i) { case 1: - this.subscriptionId = parts[i]; - break; + this.subscriptionId = parts[i]; + break; case 3: - this.resourceGroup = parts[i]; - break; + this.resourceGroup = parts[i]; + break; case 5: - this.resourceProvider = parts[i]; - break; + this.resourceProvider = parts[i]; + break; case 6: - this.resourceType = parts[i]; - break; + this.resourceType = parts[i]; + break; case 7: - this.resourceName = parts[i]; - break; + this.resourceName = parts[i]; + break; case 8: - this.childResourceType = parts[i]; - break; + this.childResourceType = parts[i]; + break; case 9: - this.childResource = parts[i]; - break; + this.childResource = parts[i]; + break; } } } @@ -175,9 +189,9 @@ export class RepositoryDetails { id: string; type: string; defaultbranch: string; - authorizationInfo:{ + authorizationInfo: { scheme: string; - parameters:{ + parameters: { accesstoken: string; } }; diff --git a/src/configure/model/templateModels.ts b/src/configure/model/templateModels.ts index e3f6c5ba..e2ab7e9c 100644 --- a/src/configure/model/templateModels.ts +++ b/src/configure/model/templateModels.ts @@ -12,12 +12,18 @@ export interface PipelineTemplate { // this should be removed as we will have endpoints/secrets as assets and not a first class property azureConnectionType?: AzureConnectionType; } +export interface TemplateInfo { + templateId: string; + workingDirectory: string; + templateWeight: number; + description: string; +} export interface TemplateParameter { name: string; displayName: string; type: TemplateParameterType; - dataSourceId? : string; + dataSourceId?: string; defaultValue?: any; options?: { key: string, value: any }[]; } From 80564dadf15c0cf355a80e86c6e321ea9ac78fb8 Mon Sep 17 00:00:00 2001 From: Kanika Pasrija Date: Fri, 20 Mar 2020 14:09:29 +0530 Subject: [PATCH 2/8] feature flag condition --- src/configure/configure.ts | 47 +++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/src/configure/configure.ts b/src/configure/configure.ts index 4c5b10e6..80856264 100644 --- a/src/configure/configure.ts +++ b/src/configure/configure.ts @@ -18,7 +18,7 @@ import { LocalGitRepoHelper } from './helper/LocalGitRepoHelper'; import { Result, telemetryHelper } from './helper/telemetryHelper'; import * as templateHelper from './helper/templateHelper'; import { TemplateParameterHelper } from './helper/templateParameterHelper'; -import { extensionVariables, GitBranchDetails, GitRepositoryParameters, MustacheContext, ParsedAzureResourceId, QuickPickItemWithData, RepositoryAnalysisApplicationSettings, RepositoryProvider, SourceOptions, TargetKind, TargetResourceType, WizardInputs} from './model/models'; +import { extensionVariables, GitBranchDetails, GitRepositoryParameters, MustacheContext, ParsedAzureResourceId, QuickPickItemWithData, RepositoryAnalysisApplicationSettings, RepositoryProvider, SourceOptions, TargetKind, TargetResourceType, WizardInputs } from './model/models'; import { PipelineTemplate, TemplateAssetType } from './model/templateModels'; import * as constants from './resources/constants'; import { Messages } from './resources/messages'; @@ -425,7 +425,7 @@ class Orchestrator { "workingDirectory": "wddddddddddddd" } ] - }; + }; let serviceClient = new TemplateServiceClient(); var appropriatePipelines; @@ -436,6 +436,21 @@ class Orchestrator { if (a.templateWeight > b.templateWeight) { return 1; } else { return -1; } }); + + // TO:DO- Get applicable pipelines for the repo type and azure target type if target already selected + if (appropriatePipelines.length > 1) { + let selectedOption = await this.controlProvider.showQuickPick( + constants.SelectPipelineTemplate, + appropriatePipelines.map((pipeline) => { return { label: pipeline.label }; }), + { placeHolder: Messages.selectPipelineTemplate }, + TelemetryKeys.PipelineTempateListCount); + this.inputs.pipelineConfiguration.templateInfo = appropriatePipelines.find((pipeline) => { + return pipeline.label === selectedOption.label; + }); + } + else { + this.inputs.pipelineConfiguration.templateInfo = appropriatePipelines[0]; + } } else { appropriatePipelines = await vscode.window.withProgress( @@ -446,21 +461,21 @@ class Orchestrator { repoAnalysisResult, this.inputs.pipelineConfiguration.params[constants.TargetResource]) ); - } - // TO:DO- Get applicable pipelines for the repo type and azure target type if target already selected - if (appropriatePipelines.length > 1) { - let selectedOption = await this.controlProvider.showQuickPick( - constants.SelectPipelineTemplate, - appropriatePipelines.map((pipeline) => { return { label: pipeline.label }; }), - { placeHolder: Messages.selectPipelineTemplate }, - TelemetryKeys.PipelineTempateListCount); - this.inputs.pipelineConfiguration.templateInfo = appropriatePipelines.find((pipeline) => { - return pipeline.label === selectedOption.label; - }); - } - else { - this.inputs.pipelineConfiguration.templateInfo = appropriatePipelines[0]; + // TO:DO- Get applicable pipelines for the repo type and azure target type if target already selected + if (appropriatePipelines.length > 1) { + let selectedOption = await this.controlProvider.showQuickPick( + constants.SelectPipelineTemplate, + appropriatePipelines.map((pipeline) => { return { label: pipeline.label }; }), + { placeHolder: Messages.selectPipelineTemplate }, + TelemetryKeys.PipelineTempateListCount); + this.inputs.pipelineConfiguration.template = appropriatePipelines.find((pipeline) => { + return pipeline.label === selectedOption.label; + }); + } + else { + this.inputs.pipelineConfiguration.template = appropriatePipelines[0]; + } } //If RepoAnalysis is disabled or didn't provided response related to language of selected template From 2afc23d0b3c283ba0a3e6985c3443aa54ba43fd5 Mon Sep 17 00:00:00 2001 From: Kanika Pasrija Date: Tue, 24 Mar 2020 16:01:28 +0530 Subject: [PATCH 3/8] PR review changes --- .../{ => github}/TemplateServiceClient.ts | 3 +- src/configure/configure.ts | 81 +++----- src/configure/helper/templateHelper.ts | 186 ++++++++++-------- src/configure/model/models.ts | 18 +- src/configure/model/templateModels.ts | 2 +- 5 files changed, 142 insertions(+), 148 deletions(-) rename src/configure/clients/{ => github}/TemplateServiceClient.ts (73%) diff --git a/src/configure/clients/TemplateServiceClient.ts b/src/configure/clients/github/TemplateServiceClient.ts similarity index 73% rename from src/configure/clients/TemplateServiceClient.ts rename to src/configure/clients/github/TemplateServiceClient.ts index faa71486..6f4eac64 100644 --- a/src/configure/clients/TemplateServiceClient.ts +++ b/src/configure/clients/github/TemplateServiceClient.ts @@ -1,4 +1,5 @@ import { RepoInfo } from "../model/models"; +import { PipelineTemplateMetadata } from "../model/templateModels"; import { RestClient } from "./restClient"; export class TemplateServiceClient { @@ -8,7 +9,7 @@ export class TemplateServiceClient { this.restClient = new RestClient(); } - public async getTemplates(body: RepoInfo): Promise { + public async getTemplates(body: RepoInfo): Promise { return this.restClient.sendServiceRequest( 'https://ts21.azurewebsites.net/Templates', 'POST', diff --git a/src/configure/configure.ts b/src/configure/configure.ts index 80856264..35fabcc4 100644 --- a/src/configure/configure.ts +++ b/src/configure/configure.ts @@ -5,7 +5,7 @@ import { AzureTreeItem, UserCancelledError } from 'vscode-azureextensionui'; const uuid = require('uuid/v4'); import { AppServiceClient } from './clients/azure/appServiceClient'; import { AzureResourceClient } from './clients/azure/azureResourceClient'; -import { TemplateServiceClient } from './clients/TemplateServiceClient'; +import { TemplateServiceClient } from './clients/github/TemplateServiceClient'; import { Configurer } from './configurers/configurerBase'; import { ConfigurerFactory } from './configurers/configurerFactory'; import { AssetHandler } from './helper/AssetHandler'; @@ -413,66 +413,43 @@ class Orchestrator { //var repoAnalysisHelper = new RepoAnalysisHelper(this.inputs.azureSession); var repoAnalysisResult = null; //await repoAnalysisHelper.getRepositoryAnalysis(this.inputs.sourceRepository); - var templateServiceEnabled = false; - - //calling RepoAnalysis service - var repoDetails = { - "applicationSettingsList": [ - { - "language": "Docker", - "buildTargetName": "Dockerfile", - "deployTargetName": "Azure:AKS", - "workingDirectory": "wddddddddddddd" - } - ] - }; - - let serviceClient = new TemplateServiceClient(); - var appropriatePipelines; - if (templateServiceEnabled) { - appropriatePipelines = await serviceClient.getTemplates(repoDetails); - //sorting array weightwise - appropriatePipelines = appropriatePipelines.sort((a, b) => { - if (a.templateWeight > b.templateWeight) { return 1; } - else { return -1; } - }); - - // TO:DO- Get applicable pipelines for the repo type and azure target type if target already selected - if (appropriatePipelines.length > 1) { - let selectedOption = await this.controlProvider.showQuickPick( - constants.SelectPipelineTemplate, - appropriatePipelines.map((pipeline) => { return { label: pipeline.label }; }), - { placeHolder: Messages.selectPipelineTemplate }, - TelemetryKeys.PipelineTempateListCount); + extensionVariables.templateServiceEnabled = false; + + //abc + let appropriatePipelines; + // TO:DO- Get applicable pipelines for the repo type and azure target type if target already selected + + appropriatePipelines = await vscode.window.withProgress( + { location: vscode.ProgressLocation.Notification, title: Messages.analyzingRepo }, + () => templateHelper.analyzeRepoAndListAppropriatePipeline( + this.inputs.sourceRepository.localPath, + this.inputs.sourceRepository.repositoryProvider, + repoAnalysisResult, + this.inputs.pipelineConfiguration.params[constants.TargetResource]) + ); + + // TO:DO- Get applicable pipelines for the repo type and azure target type if target already selected + if (appropriatePipelines.length > 1) { + let selectedOption = await this.controlProvider.showQuickPick( + constants.SelectPipelineTemplate, + appropriatePipelines.map((pipeline) => { return { label: pipeline.label }; }), + { placeHolder: Messages.selectPipelineTemplate }, + TelemetryKeys.PipelineTempateListCount); + if (extensionVariables.templateServiceEnabled) { this.inputs.pipelineConfiguration.templateInfo = appropriatePipelines.find((pipeline) => { return pipeline.label === selectedOption.label; }); } else { - this.inputs.pipelineConfiguration.templateInfo = appropriatePipelines[0]; - } - } - else { - appropriatePipelines = await vscode.window.withProgress( - { location: vscode.ProgressLocation.Notification, title: Messages.analyzingRepo }, - () => templateHelper.analyzeRepoAndListAppropriatePipeline( - this.inputs.sourceRepository.localPath, - this.inputs.sourceRepository.repositoryProvider, - repoAnalysisResult, - this.inputs.pipelineConfiguration.params[constants.TargetResource]) - ); - - // TO:DO- Get applicable pipelines for the repo type and azure target type if target already selected - if (appropriatePipelines.length > 1) { - let selectedOption = await this.controlProvider.showQuickPick( - constants.SelectPipelineTemplate, - appropriatePipelines.map((pipeline) => { return { label: pipeline.label }; }), - { placeHolder: Messages.selectPipelineTemplate }, - TelemetryKeys.PipelineTempateListCount); this.inputs.pipelineConfiguration.template = appropriatePipelines.find((pipeline) => { return pipeline.label === selectedOption.label; }); } + } + else { + if (extensionVariables.templateServiceEnabled) { + this.inputs.pipelineConfiguration.templateInfo = appropriatePipelines[0]; + } else { this.inputs.pipelineConfiguration.template = appropriatePipelines[0]; } diff --git a/src/configure/helper/templateHelper.ts b/src/configure/helper/templateHelper.ts index 910ba11e..44597c58 100644 --- a/src/configure/helper/templateHelper.ts +++ b/src/configure/helper/templateHelper.ts @@ -4,109 +4,137 @@ import * as Mustache from 'mustache'; import * as path from 'path'; import * as Q from 'q'; import { AzureConnectionType, extensionVariables, MustacheContext, RepositoryAnalysisParameters, RepositoryProvider, SupportedLanguage, TargetKind, TargetResourceType } from '../model/models'; -import { PipelineTemplate, PreDefinedDataSourceIds, TemplateAssetType, TemplateParameterType } from '../model/templateModels'; +import { PipelineTemplate, PreDefinedDataSourceIds, TemplateAssetType, TemplateParameterType, PipelineTemplateMetadata } from '../model/templateModels'; import { PipelineTemplateLabels, RepoAnalysisConstants } from '../resources/constants'; import { Messages } from '../resources/messages'; import { TracePoints } from '../resources/tracePoints'; import { MustacheHelper } from './mustacheHelper'; import { telemetryHelper } from './telemetryHelper'; +import { TemplateServiceClient } from '../clients/github/TemplateServiceClient'; -export async function analyzeRepoAndListAppropriatePipeline(repoPath: string, repositoryProvider: RepositoryProvider, repoAnalysisParameters: RepositoryAnalysisParameters, targetResource?: GenericResource): Promise { - let localRepoAnalysisResult = await analyzeRepo(repoPath); - let analysisResult = localRepoAnalysisResult; +export async function analyzeRepoAndListAppropriatePipeline(repoPath: string, repositoryProvider: RepositoryProvider, repoAnalysisParameters: RepositoryAnalysisParameters, targetResource?: GenericResource): Promise { + + if(extensionVariables.templateServiceEnabled){ + let templateResult: PipelineTemplateMetadata[] = []; - //If Repo analysis fails then we'll go with the basic existing analysis - if (repositoryProvider === RepositoryProvider.Github && !!repoAnalysisParameters && !!repoAnalysisParameters.repositoryAnalysisApplicationSettingsList) { - analysisResult = new AnalysisResult(); - repoAnalysisParameters.repositoryAnalysisApplicationSettingsList.forEach((settings) => { - analysisResult.languages.push(settings.language); + //calling repo analysis service + var repoDetails = { + "applicationSettingsList": [ + { + "language": "Docker", + "buildTargetName": "Dockerfile", + "deployTargetName": "Azure:AKS", + "workingDirectory": "wddddddddddddd" + } + ] + }; - //Check if Azure:Functions is value of any deployTargetName property - analysisResult.isFunctionApp = - analysisResult.isFunctionApp || settings.deployTargetName === RepoAnalysisConstants.AzureFunctions ? true : false; + let serviceClient = new TemplateServiceClient(); + templateResult = await serviceClient.getTemplates(repoDetails); + templateResult = templateResult.sort((a, b) => { + if (a.templateWeight > b.templateWeight) { return 1; } + else { return -1; } }); + return templateResult; + } + else{ + let localRepoAnalysisResult = await analyzeRepo(repoPath); + let analysisResult = localRepoAnalysisResult; - //Languages not supported by RepoAnalysisService should be considered and taken from LocalRepoAnalysis - localRepoAnalysisResult.languages.forEach((language) => { - if (analysisResult.languages.indexOf(language) === -1) { - analysisResult.languages.push(language); - } - }); + //If Repo analysis fails then we'll go with the basic existing analysis + if (repositoryProvider === RepositoryProvider.Github && !!repoAnalysisParameters && !!repoAnalysisParameters.repositoryAnalysisApplicationSettingsList) { + analysisResult = new AnalysisResult(); + repoAnalysisParameters.repositoryAnalysisApplicationSettingsList.forEach((settings) => { + analysisResult.languages.push(settings.language); - if (analysisResult.languages.length === 0) { - analysisResult.languages.push(SupportedLanguage.NONE); - } - } - - let templateList: { [key: string]: PipelineTemplate[] } = {}; - switch (repositoryProvider) { - case RepositoryProvider.AzureRepos: - templateList = azurePipelineTemplates; - break; - case RepositoryProvider.Github: - templateList = extensionVariables.enableGitHubWorkflow ? githubWorklowTemplates : azurePipelineTemplates; - break; - default: - throw new Error(Messages.cannotIdentifyRespositoryDetails); - } + //Check if Azure:Functions is value of any deployTargetName property + analysisResult.isFunctionApp = + analysisResult.isFunctionApp || settings.deployTargetName === RepoAnalysisConstants.AzureFunctions ? true : false; + }); - let templateResult: PipelineTemplate[] = []; - analysisResult.languages.forEach((language) => { - switch (language) { - case SupportedLanguage.DOCKER: - if (templateList[SupportedLanguage.DOCKER] && templateList[SupportedLanguage.DOCKER].length > 0) { - templateResult = templateResult.concat(templateList[SupportedLanguage.DOCKER]); + //Languages not supported by RepoAnalysisService should be considered and taken from LocalRepoAnalysis + localRepoAnalysisResult.languages.forEach((language) => { + if (analysisResult.languages.indexOf(language) === -1) { + analysisResult.languages.push(language); } - break; - case SupportedLanguage.NODE: - if (templateList[SupportedLanguage.NODE] && templateList[SupportedLanguage.NODE].length > 0) { - templateResult = templateResult.concat(templateList[SupportedLanguage.NODE]); - } - break; - case SupportedLanguage.PYTHON: - if (templateList[SupportedLanguage.PYTHON] && templateList[SupportedLanguage.PYTHON].length > 0) { - templateResult = templateResult.concat(templateList[SupportedLanguage.PYTHON]); - } - break; - case SupportedLanguage.DOTNETCORE: - if (templateList[SupportedLanguage.DOTNETCORE] && templateList[SupportedLanguage.DOTNETCORE].length > 0) { - templateResult = templateResult.concat(templateList[SupportedLanguage.DOTNETCORE]); - } - break; - case SupportedLanguage.NONE: - if (templateList[SupportedLanguage.NONE] && templateList[SupportedLanguage.NONE].length > 0) { - templateResult = templateResult.concat(templateList[SupportedLanguage.NONE]); - } - break; - default: - break; - } - }); + }); - if (templateResult.length < 1 && templateList[SupportedLanguage.NONE] && templateList[SupportedLanguage.NONE].length > 0) { - templateResult = templateList[SupportedLanguage.NONE]; - } + if (analysisResult.languages.length === 0) { + analysisResult.languages.push(SupportedLanguage.NONE); + } + } - if (analysisResult.isFunctionApp) { + let templateList: { [key: string]: PipelineTemplate[] } = {}; switch (repositoryProvider) { case RepositoryProvider.AzureRepos: - templateResult = azurePipelineTargetBasedTemplates[AzureTarget.FunctionApp].concat(templateResult); + templateList = azurePipelineTemplates; break; case RepositoryProvider.Github: - templateResult = extensionVariables.enableGitHubWorkflow ? githubWorkflowTargetBasedTemplates[AzureTarget.FunctionApp].concat(templateResult) : azurePipelineTargetBasedTemplates[AzureTarget.FunctionApp].concat(templateResult); + templateList = extensionVariables.enableGitHubWorkflow ? githubWorklowTemplates : azurePipelineTemplates; break; default: - break; + throw new Error(Messages.cannotIdentifyRespositoryDetails); } - } - templateResult = targetResource && !!targetResource.type ? templateResult.filter((template) => !template.targetType || template.targetType.toLowerCase() === targetResource.type.toLowerCase()) : templateResult; - templateResult = targetResource && !!targetResource.kind ? templateResult.filter((template) => !template.targetKind || template.targetKind.toLowerCase() === targetResource.kind.toLowerCase()) : templateResult; - templateResult = templateResult.filter((pipelineTemplate) => pipelineTemplate.enabled); + let templateResult: PipelineTemplate[] = []; + analysisResult.languages.forEach((language) => { + switch (language) { + case SupportedLanguage.DOCKER: + if (templateList[SupportedLanguage.DOCKER] && templateList[SupportedLanguage.DOCKER].length > 0) { + templateResult = templateResult.concat(templateList[SupportedLanguage.DOCKER]); + } + break; + case SupportedLanguage.NODE: + if (templateList[SupportedLanguage.NODE] && templateList[SupportedLanguage.NODE].length > 0) { + templateResult = templateResult.concat(templateList[SupportedLanguage.NODE]); + } + break; + case SupportedLanguage.PYTHON: + if (templateList[SupportedLanguage.PYTHON] && templateList[SupportedLanguage.PYTHON].length > 0) { + templateResult = templateResult.concat(templateList[SupportedLanguage.PYTHON]); + } + break; + case SupportedLanguage.DOTNETCORE: + if (templateList[SupportedLanguage.DOTNETCORE] && templateList[SupportedLanguage.DOTNETCORE].length > 0) { + templateResult = templateResult.concat(templateList[SupportedLanguage.DOTNETCORE]); + } + break; + case SupportedLanguage.NONE: + if (templateList[SupportedLanguage.NONE] && templateList[SupportedLanguage.NONE].length > 0) { + templateResult = templateResult.concat(templateList[SupportedLanguage.NONE]); + } + break; + default: + break; + } + }); - // remove duplicate named template: - templateResult = removeDuplicates(templateResult); - return templateResult; + if (templateResult.length < 1 && templateList[SupportedLanguage.NONE] && templateList[SupportedLanguage.NONE].length > 0) { + templateResult = templateList[SupportedLanguage.NONE]; + } + + if (analysisResult.isFunctionApp) { + switch (repositoryProvider) { + case RepositoryProvider.AzureRepos: + templateResult = azurePipelineTargetBasedTemplates[AzureTarget.FunctionApp].concat(templateResult); + break; + case RepositoryProvider.Github: + templateResult = extensionVariables.enableGitHubWorkflow ? githubWorkflowTargetBasedTemplates[AzureTarget.FunctionApp].concat(templateResult) : azurePipelineTargetBasedTemplates[AzureTarget.FunctionApp].concat(templateResult); + break; + default: + break; + } + } + + templateResult = targetResource && !!targetResource.type ? templateResult.filter((template) => !template.targetType || template.targetType.toLowerCase() === targetResource.type.toLowerCase()) : templateResult; + templateResult = targetResource && !!targetResource.kind ? templateResult.filter((template) => !template.targetKind || template.targetKind.toLowerCase() === targetResource.kind.toLowerCase()) : templateResult; + templateResult = templateResult.filter((pipelineTemplate) => pipelineTemplate.enabled); + + // remove duplicate named template: + templateResult = removeDuplicates(templateResult); + return templateResult; + } + } export function getPipelineTemplatesForAllWebAppKind(repositoryProvider: RepositoryProvider, label: string, language: string, targetKind: TargetKind): PipelineTemplate[] { diff --git a/src/configure/model/models.ts b/src/configure/model/models.ts index 8e81c813..0f75de44 100644 --- a/src/configure/model/models.ts +++ b/src/configure/model/models.ts @@ -2,11 +2,10 @@ import { SubscriptionModels } from 'azure-arm-resource'; import { GenericResource } from 'azure-arm-resource/lib/resource/models'; import { ServiceClientCredentials } from 'ms-rest'; import { AzureEnvironment } from 'ms-rest-azure'; -import { Dictionary } from 'underscore'; import { ExtensionContext, OutputChannel, QuickPickItem, workspace } from 'vscode'; import { IAzureUserInput, ITelemetryReporter, UIExtensionVariables } from 'vscode-azureextensionui'; import { Messages } from '../resources/messages'; -import { PipelineTemplate, TemplateInfo } from './templateModels'; +import { PipelineTemplate, PipelineTemplateMetadata } from './templateModels'; class ExtensionVariables implements UIExtensionVariables { public azureAccountExtensionApi: AzureAccountExtensionExports; @@ -15,6 +14,7 @@ class ExtensionVariables implements UIExtensionVariables { public reporter: ITelemetryReporter; public ui: IAzureUserInput; public enableGitHubWorkflow: boolean; + public templateServiceEnabled: boolean; constructor() { this.enableGitHubWorkflow = !workspace.getConfiguration().get('deployToAzure.UseAzurePipelinesForGithub'); @@ -24,18 +24,6 @@ class ExtensionVariables implements UIExtensionVariables { let extensionVariables = new ExtensionVariables(); export { extensionVariables }; -export class ApplicationSettings { - language: string; - buildTargetName: string; - deployTargetName: string; - workingDirectory: string; - settings?: Dictionary; -} - -export class RepoInfo { - applicationSettingsList: ApplicationSettings[]; -} - export class WizardInputs { organizationName: string; project: DevOpsProject; @@ -95,7 +83,7 @@ export class AzureSession { export class PipelineConfiguration { filePath: string; template: PipelineTemplate; - templateInfo: TemplateInfo; + templateInfo: PipelineTemplateMetadata; workingDirectory: string; params: { [key: string]: any } = {}; assets: { [key: string]: any } = {}; diff --git a/src/configure/model/templateModels.ts b/src/configure/model/templateModels.ts index e2ab7e9c..ee7e50ec 100644 --- a/src/configure/model/templateModels.ts +++ b/src/configure/model/templateModels.ts @@ -12,7 +12,7 @@ export interface PipelineTemplate { // this should be removed as we will have endpoints/secrets as assets and not a first class property azureConnectionType?: AzureConnectionType; } -export interface TemplateInfo { +export interface PipelineTemplateMetadata { templateId: string; workingDirectory: string; templateWeight: number; From 2161f92b04f271aac5e367c8339867d5bc43187d Mon Sep 17 00:00:00 2001 From: Kanika Pasrija Date: Thu, 26 Mar 2020 12:24:07 +0530 Subject: [PATCH 4/8] small changes --- .../clients/github/TemplateServiceClient.ts | 8 +- src/configure/clients/restClient.ts | 2 +- src/configure/configure.ts | 45 +++- src/configure/helper/templateHelper.ts | 203 +++++++++--------- 4 files changed, 137 insertions(+), 121 deletions(-) diff --git a/src/configure/clients/github/TemplateServiceClient.ts b/src/configure/clients/github/TemplateServiceClient.ts index 6f4eac64..7ada06a0 100644 --- a/src/configure/clients/github/TemplateServiceClient.ts +++ b/src/configure/clients/github/TemplateServiceClient.ts @@ -1,6 +1,6 @@ -import { RepoInfo } from "../model/models"; -import { PipelineTemplateMetadata } from "../model/templateModels"; -import { RestClient } from "./restClient"; +import { RepoInfo } from "../../model/models"; +import { PipelineTemplateMetadata } from "../../model/templateModels"; +import { RestClient } from "../restClient"; export class TemplateServiceClient { private restClient: RestClient; @@ -10,7 +10,7 @@ export class TemplateServiceClient { } public async getTemplates(body: RepoInfo): Promise { - return this.restClient.sendServiceRequest( + return this.restClient.sendRequest2( 'https://ts21.azurewebsites.net/Templates', 'POST', '2019-05-01', diff --git a/src/configure/clients/restClient.ts b/src/configure/clients/restClient.ts index 9c32b808..3264690a 100644 --- a/src/configure/clients/restClient.ts +++ b/src/configure/clients/restClient.ts @@ -20,7 +20,7 @@ export class RestClient extends ServiceClient { }); } - public sendServiceRequest(url: string, httpMethod: string, apiVersion: string, body?: any): Promise { + public sendRequest2(url: string, httpMethod: string, apiVersion: string, body?: any): Promise { return this.sendRequest( { url: url, diff --git a/src/configure/configure.ts b/src/configure/configure.ts index 35fabcc4..5aa001b4 100644 --- a/src/configure/configure.ts +++ b/src/configure/configure.ts @@ -19,7 +19,7 @@ import { Result, telemetryHelper } from './helper/telemetryHelper'; import * as templateHelper from './helper/templateHelper'; import { TemplateParameterHelper } from './helper/templateParameterHelper'; import { extensionVariables, GitBranchDetails, GitRepositoryParameters, MustacheContext, ParsedAzureResourceId, QuickPickItemWithData, RepositoryAnalysisApplicationSettings, RepositoryProvider, SourceOptions, TargetKind, TargetResourceType, WizardInputs } from './model/models'; -import { PipelineTemplate, TemplateAssetType } from './model/templateModels'; +import { TemplateAssetType } from './model/templateModels'; import * as constants from './resources/constants'; import { Messages } from './resources/messages'; import { TelemetryKeys } from './resources/telemetryKeys'; @@ -413,20 +413,43 @@ class Orchestrator { //var repoAnalysisHelper = new RepoAnalysisHelper(this.inputs.azureSession); var repoAnalysisResult = null; //await repoAnalysisHelper.getRepositoryAnalysis(this.inputs.sourceRepository); - extensionVariables.templateServiceEnabled = false; + extensionVariables.templateServiceEnabled = true; - //abc let appropriatePipelines; // TO:DO- Get applicable pipelines for the repo type and azure target type if target already selected - appropriatePipelines = await vscode.window.withProgress( - { location: vscode.ProgressLocation.Notification, title: Messages.analyzingRepo }, - () => templateHelper.analyzeRepoAndListAppropriatePipeline( - this.inputs.sourceRepository.localPath, - this.inputs.sourceRepository.repositoryProvider, - repoAnalysisResult, - this.inputs.pipelineConfiguration.params[constants.TargetResource]) - ); + if (extensionVariables.templateServiceEnabled) { + repoAnalysisResult = { + "applicationSettingsList": [ + { + "language": "Docker", + "buildTargetName": "Dockerfile", + "deployTargetName": "Azure:AKS", + "workingDirectory": "wddddddddddddd" + } + ] + }; + + appropriatePipelines = appropriatePipelines = await vscode.window.withProgress( + { location: vscode.ProgressLocation.Notification, title: Messages.analyzingRepo }, + () => templateHelper.analyzeRepoAndListAppropriatePipeline2( + this.inputs.sourceRepository.localPath, + this.inputs.sourceRepository.repositoryProvider, + repoAnalysisResult, + this.inputs.pipelineConfiguration.params[constants.TargetResource]) + ); + } + else { + appropriatePipelines = appropriatePipelines = await vscode.window.withProgress( + { location: vscode.ProgressLocation.Notification, title: Messages.analyzingRepo }, + () => templateHelper.analyzeRepoAndListAppropriatePipeline( + this.inputs.sourceRepository.localPath, + this.inputs.sourceRepository.repositoryProvider, + repoAnalysisResult, + this.inputs.pipelineConfiguration.params[constants.TargetResource]) + ); + } + // TO:DO- Get applicable pipelines for the repo type and azure target type if target already selected if (appropriatePipelines.length > 1) { diff --git a/src/configure/helper/templateHelper.ts b/src/configure/helper/templateHelper.ts index 44597c58..63b1794d 100644 --- a/src/configure/helper/templateHelper.ts +++ b/src/configure/helper/templateHelper.ts @@ -3,140 +3,133 @@ import * as fs from 'fs'; import * as Mustache from 'mustache'; import * as path from 'path'; import * as Q from 'q'; +import { TemplateServiceClient } from '../clients/github/TemplateServiceClient'; import { AzureConnectionType, extensionVariables, MustacheContext, RepositoryAnalysisParameters, RepositoryProvider, SupportedLanguage, TargetKind, TargetResourceType } from '../model/models'; -import { PipelineTemplate, PreDefinedDataSourceIds, TemplateAssetType, TemplateParameterType, PipelineTemplateMetadata } from '../model/templateModels'; +import { PipelineTemplate, PipelineTemplateMetadata, PreDefinedDataSourceIds, TemplateAssetType, TemplateParameterType } from '../model/templateModels'; import { PipelineTemplateLabels, RepoAnalysisConstants } from '../resources/constants'; import { Messages } from '../resources/messages'; import { TracePoints } from '../resources/tracePoints'; import { MustacheHelper } from './mustacheHelper'; import { telemetryHelper } from './telemetryHelper'; -import { TemplateServiceClient } from '../clients/github/TemplateServiceClient'; -export async function analyzeRepoAndListAppropriatePipeline(repoPath: string, repositoryProvider: RepositoryProvider, repoAnalysisParameters: RepositoryAnalysisParameters, targetResource?: GenericResource): Promise { - - if(extensionVariables.templateServiceEnabled){ - let templateResult: PipelineTemplateMetadata[] = []; +export async function mergingRepoAnalysisResults(repoPath: string, repositoryProvider: RepositoryProvider, repoAnalysisParameters: RepositoryAnalysisParameters): Promise { + let localRepoAnalysisResult = await analyzeRepo(repoPath); + let analysisResult = localRepoAnalysisResult; - //calling repo analysis service - var repoDetails = { - "applicationSettingsList": [ - { - "language": "Docker", - "buildTargetName": "Dockerfile", - "deployTargetName": "Azure:AKS", - "workingDirectory": "wddddddddddddd" - } - ] - }; + //If Repo analysis fails then we'll go with the basic existing analysis + if (repositoryProvider === RepositoryProvider.Github && !!repoAnalysisParameters && !!repoAnalysisParameters.repositoryAnalysisApplicationSettingsList) { + analysisResult = new AnalysisResult(); + repoAnalysisParameters.repositoryAnalysisApplicationSettingsList.forEach((settings) => { + analysisResult.languages.push(settings.language); - let serviceClient = new TemplateServiceClient(); - templateResult = await serviceClient.getTemplates(repoDetails); - templateResult = templateResult.sort((a, b) => { - if (a.templateWeight > b.templateWeight) { return 1; } - else { return -1; } + //Check if Azure:Functions is value of any deployTargetName property + analysisResult.isFunctionApp = + analysisResult.isFunctionApp || settings.deployTargetName === RepoAnalysisConstants.AzureFunctions ? true : false; }); - return templateResult; - } - else{ - let localRepoAnalysisResult = await analyzeRepo(repoPath); - let analysisResult = localRepoAnalysisResult; - //If Repo analysis fails then we'll go with the basic existing analysis - if (repositoryProvider === RepositoryProvider.Github && !!repoAnalysisParameters && !!repoAnalysisParameters.repositoryAnalysisApplicationSettingsList) { - analysisResult = new AnalysisResult(); - repoAnalysisParameters.repositoryAnalysisApplicationSettingsList.forEach((settings) => { - analysisResult.languages.push(settings.language); + //Languages not supported by RepoAnalysisService should be considered and taken from LocalRepoAnalysis + localRepoAnalysisResult.languages.forEach((language) => { + if (analysisResult.languages.indexOf(language) === -1) { + analysisResult.languages.push(language); + } + }); - //Check if Azure:Functions is value of any deployTargetName property - analysisResult.isFunctionApp = - analysisResult.isFunctionApp || settings.deployTargetName === RepoAnalysisConstants.AzureFunctions ? true : false; - }); + if (analysisResult.languages.length === 0) { + analysisResult.languages.push(SupportedLanguage.NONE); + } + } + return analysisResult; +} +export async function analyzeRepoAndListAppropriatePipeline(repoPath: string, repositoryProvider: RepositoryProvider, repoAnalysisParameters: RepositoryAnalysisParameters, targetResource?: GenericResource): Promise { - //Languages not supported by RepoAnalysisService should be considered and taken from LocalRepoAnalysis - localRepoAnalysisResult.languages.forEach((language) => { - if (analysisResult.languages.indexOf(language) === -1) { - analysisResult.languages.push(language); - } - }); + let analysisResult = await mergingRepoAnalysisResults(repoPath, repositoryProvider, repoAnalysisParameters); - if (analysisResult.languages.length === 0) { - analysisResult.languages.push(SupportedLanguage.NONE); - } + let templateList: { [key: string]: PipelineTemplate[] } = {}; + switch (repositoryProvider) { + case RepositoryProvider.AzureRepos: + templateList = azurePipelineTemplates; + break; + case RepositoryProvider.Github: + templateList = extensionVariables.enableGitHubWorkflow ? githubWorklowTemplates : azurePipelineTemplates; + break; + default: + throw new Error(Messages.cannotIdentifyRespositoryDetails); + } + + + let templateResult: PipelineTemplate[] = []; + analysisResult.languages.forEach((language) => { + switch (language) { + case SupportedLanguage.DOCKER: + if (templateList[SupportedLanguage.DOCKER] && templateList[SupportedLanguage.DOCKER].length > 0) { + templateResult = templateResult.concat(templateList[SupportedLanguage.DOCKER]); + } + break; + case SupportedLanguage.NODE: + if (templateList[SupportedLanguage.NODE] && templateList[SupportedLanguage.NODE].length > 0) { + templateResult = templateResult.concat(templateList[SupportedLanguage.NODE]); + } + break; + case SupportedLanguage.PYTHON: + if (templateList[SupportedLanguage.PYTHON] && templateList[SupportedLanguage.PYTHON].length > 0) { + templateResult = templateResult.concat(templateList[SupportedLanguage.PYTHON]); + } + break; + case SupportedLanguage.DOTNETCORE: + if (templateList[SupportedLanguage.DOTNETCORE] && templateList[SupportedLanguage.DOTNETCORE].length > 0) { + templateResult = templateResult.concat(templateList[SupportedLanguage.DOTNETCORE]); + } + break; + case SupportedLanguage.NONE: + if (templateList[SupportedLanguage.NONE] && templateList[SupportedLanguage.NONE].length > 0) { + templateResult = templateResult.concat(templateList[SupportedLanguage.NONE]); + } + break; + default: + break; } + }); + + if (templateResult.length < 1 && templateList[SupportedLanguage.NONE] && templateList[SupportedLanguage.NONE].length > 0) { + templateResult = templateList[SupportedLanguage.NONE]; + } - let templateList: { [key: string]: PipelineTemplate[] } = {}; + if (analysisResult.isFunctionApp) { switch (repositoryProvider) { case RepositoryProvider.AzureRepos: - templateList = azurePipelineTemplates; + templateResult = azurePipelineTargetBasedTemplates[AzureTarget.FunctionApp].concat(templateResult); break; case RepositoryProvider.Github: - templateList = extensionVariables.enableGitHubWorkflow ? githubWorklowTemplates : azurePipelineTemplates; + templateResult = extensionVariables.enableGitHubWorkflow ? githubWorkflowTargetBasedTemplates[AzureTarget.FunctionApp].concat(templateResult) : azurePipelineTargetBasedTemplates[AzureTarget.FunctionApp].concat(templateResult); break; default: - throw new Error(Messages.cannotIdentifyRespositoryDetails); + break; } + } - let templateResult: PipelineTemplate[] = []; - analysisResult.languages.forEach((language) => { - switch (language) { - case SupportedLanguage.DOCKER: - if (templateList[SupportedLanguage.DOCKER] && templateList[SupportedLanguage.DOCKER].length > 0) { - templateResult = templateResult.concat(templateList[SupportedLanguage.DOCKER]); - } - break; - case SupportedLanguage.NODE: - if (templateList[SupportedLanguage.NODE] && templateList[SupportedLanguage.NODE].length > 0) { - templateResult = templateResult.concat(templateList[SupportedLanguage.NODE]); - } - break; - case SupportedLanguage.PYTHON: - if (templateList[SupportedLanguage.PYTHON] && templateList[SupportedLanguage.PYTHON].length > 0) { - templateResult = templateResult.concat(templateList[SupportedLanguage.PYTHON]); - } - break; - case SupportedLanguage.DOTNETCORE: - if (templateList[SupportedLanguage.DOTNETCORE] && templateList[SupportedLanguage.DOTNETCORE].length > 0) { - templateResult = templateResult.concat(templateList[SupportedLanguage.DOTNETCORE]); - } - break; - case SupportedLanguage.NONE: - if (templateList[SupportedLanguage.NONE] && templateList[SupportedLanguage.NONE].length > 0) { - templateResult = templateResult.concat(templateList[SupportedLanguage.NONE]); - } - break; - default: - break; - } - }); + templateResult = targetResource && !!targetResource.type ? templateResult.filter((template) => !template.targetType || template.targetType.toLowerCase() === targetResource.type.toLowerCase()) : templateResult; + templateResult = targetResource && !!targetResource.kind ? templateResult.filter((template) => !template.targetKind || template.targetKind.toLowerCase() === targetResource.kind.toLowerCase()) : templateResult; + templateResult = templateResult.filter((pipelineTemplate) => pipelineTemplate.enabled); - if (templateResult.length < 1 && templateList[SupportedLanguage.NONE] && templateList[SupportedLanguage.NONE].length > 0) { - templateResult = templateList[SupportedLanguage.NONE]; - } + // remove duplicate named template: + templateResult = removeDuplicates(templateResult); + return templateResult; - if (analysisResult.isFunctionApp) { - switch (repositoryProvider) { - case RepositoryProvider.AzureRepos: - templateResult = azurePipelineTargetBasedTemplates[AzureTarget.FunctionApp].concat(templateResult); - break; - case RepositoryProvider.Github: - templateResult = extensionVariables.enableGitHubWorkflow ? githubWorkflowTargetBasedTemplates[AzureTarget.FunctionApp].concat(templateResult) : azurePipelineTargetBasedTemplates[AzureTarget.FunctionApp].concat(templateResult); - break; - default: - break; - } - } +} - templateResult = targetResource && !!targetResource.type ? templateResult.filter((template) => !template.targetType || template.targetType.toLowerCase() === targetResource.type.toLowerCase()) : templateResult; - templateResult = targetResource && !!targetResource.kind ? templateResult.filter((template) => !template.targetKind || template.targetKind.toLowerCase() === targetResource.kind.toLowerCase()) : templateResult; - templateResult = templateResult.filter((pipelineTemplate) => pipelineTemplate.enabled); +export async function analyzeRepoAndListAppropriatePipeline2(repoPath: string, repositoryProvider: RepositoryProvider, repoAnalysisParameters: RepositoryAnalysisParameters, targetResource?: GenericResource): Promise { - // remove duplicate named template: - templateResult = removeDuplicates(templateResult); - return templateResult; - } - -} + //TO:DO - Merge local repo analysis (Some changes in the definition of AnalysisResult required) + let templateResult: PipelineTemplateMetadata[] = []; + let serviceClient = new TemplateServiceClient(); + templateResult = await serviceClient.getTemplates(repoAnalysisParameters); + templateResult = templateResult.sort((a, b) => { + if (a.templateWeight > b.templateWeight) { return 1; } + else { return -1; } + }); + return templateResult; +} export function getPipelineTemplatesForAllWebAppKind(repositoryProvider: RepositoryProvider, label: string, language: string, targetKind: TargetKind): PipelineTemplate[] { let pipelineTemplates: PipelineTemplate[] = []; From 1d344794b65cbab4294d5441e9ef12df4f979686 Mon Sep 17 00:00:00 2001 From: Kanika Pasrija Date: Mon, 30 Mar 2020 14:29:50 +0530 Subject: [PATCH 5/8] small corrections and lint updates --- src/configure/clients/github/TemplateServiceClient.ts | 4 ++-- src/configure/configure.ts | 1 - src/configure/configurers/configurerFactory.ts | 6 +++--- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/configure/clients/github/TemplateServiceClient.ts b/src/configure/clients/github/TemplateServiceClient.ts index 7ada06a0..ae9d3bda 100644 --- a/src/configure/clients/github/TemplateServiceClient.ts +++ b/src/configure/clients/github/TemplateServiceClient.ts @@ -1,4 +1,4 @@ -import { RepoInfo } from "../../model/models"; +import { RepositoryAnalysisParameters } from "../../model/models"; import { PipelineTemplateMetadata } from "../../model/templateModels"; import { RestClient } from "../restClient"; @@ -9,7 +9,7 @@ export class TemplateServiceClient { this.restClient = new RestClient(); } - public async getTemplates(body: RepoInfo): Promise { + public async getTemplates(body: RepositoryAnalysisParameters): Promise { return this.restClient.sendRequest2( 'https://ts21.azurewebsites.net/Templates', 'POST', diff --git a/src/configure/configure.ts b/src/configure/configure.ts index 5aa001b4..06b00db8 100644 --- a/src/configure/configure.ts +++ b/src/configure/configure.ts @@ -5,7 +5,6 @@ import { AzureTreeItem, UserCancelledError } from 'vscode-azureextensionui'; const uuid = require('uuid/v4'); import { AppServiceClient } from './clients/azure/appServiceClient'; import { AzureResourceClient } from './clients/azure/azureResourceClient'; -import { TemplateServiceClient } from './clients/github/TemplateServiceClient'; import { Configurer } from './configurers/configurerBase'; import { ConfigurerFactory } from './configurers/configurerFactory'; import { AssetHandler } from './helper/AssetHandler'; diff --git a/src/configure/configurers/configurerFactory.ts b/src/configure/configurers/configurerFactory.ts index fb9d207f..2b595308 100644 --- a/src/configure/configurers/configurerFactory.ts +++ b/src/configure/configurers/configurerFactory.ts @@ -1,8 +1,8 @@ -import { Configurer } from './configurerBase'; import { GitHubWorkflowConfigurer } from '../configurers/githubWorkflowConfigurer'; -import { AzurePipelineConfigurer } from './azurePipelineConfigurer'; -import { GitRepositoryParameters, RepositoryProvider, AzureSession, extensionVariables } from '../model/models'; +import { AzureSession, extensionVariables, GitRepositoryParameters, RepositoryProvider } from '../model/models'; import { Messages } from '../resources/messages'; +import { AzurePipelineConfigurer } from './azurePipelineConfigurer'; +import { Configurer } from './configurerBase'; export class ConfigurerFactory { public static GetConfigurer(sourceRepositoryDetails: GitRepositoryParameters, azureSession: AzureSession, subscriptionId: string): Configurer { From 8803423a4809b2c782d00e1759482ba07d420508 Mon Sep 17 00:00:00 2001 From: Kanika Pasrija Date: Mon, 30 Mar 2020 14:37:25 +0530 Subject: [PATCH 6/8] adding label property and updating telemetry --- src/configure/configure.ts | 7 ++++++- src/configure/model/templateModels.ts | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/configure/configure.ts b/src/configure/configure.ts index 06b00db8..dc69bf8b 100644 --- a/src/configure/configure.ts +++ b/src/configure/configure.ts @@ -490,7 +490,12 @@ class Orchestrator { }); } - telemetryHelper.setTelemetry(TelemetryKeys.ChosenTemplate, this.inputs.pipelineConfiguration.template.label); + if (extensionVariables.templateServiceEnabled) { + telemetryHelper.setTelemetry(TelemetryKeys.ChosenTemplate, this.inputs.pipelineConfiguration.templateInfo.label); + } + else { + telemetryHelper.setTelemetry(TelemetryKeys.ChosenTemplate, this.inputs.pipelineConfiguration.template.label); + } } private async checkInPipelineFileToRepository(pipelineConfigurer: Configurer): Promise { diff --git a/src/configure/model/templateModels.ts b/src/configure/model/templateModels.ts index ee7e50ec..09935c9b 100644 --- a/src/configure/model/templateModels.ts +++ b/src/configure/model/templateModels.ts @@ -14,6 +14,7 @@ export interface PipelineTemplate { } export interface PipelineTemplateMetadata { templateId: string; + label: string; workingDirectory: string; templateWeight: number; description: string; From 114b71301d3933f1365bd56f304d4b01d44c0caa Mon Sep 17 00:00:00 2001 From: Kanika Pasrija Date: Mon, 6 Apr 2020 15:58:03 +0530 Subject: [PATCH 7/8] getting template by Id --- .../clients/github/TemplateServiceClient.ts | 11 ++++- src/configure/configure.ts | 13 +++++- src/configure/helper/templateHelper.ts | 9 ++++ src/configure/model/DataSource.ts | 9 ++++ src/configure/model/InputDescriptor.ts | 42 +++++++++++++++++++ src/configure/model/InputGroup.ts | 6 +++ src/configure/model/PipelineTemplateNew.ts | 11 +++++ src/configure/model/models.ts | 2 + 8 files changed, 101 insertions(+), 2 deletions(-) create mode 100644 src/configure/model/DataSource.ts create mode 100644 src/configure/model/InputDescriptor.ts create mode 100644 src/configure/model/InputGroup.ts create mode 100644 src/configure/model/PipelineTemplateNew.ts diff --git a/src/configure/clients/github/TemplateServiceClient.ts b/src/configure/clients/github/TemplateServiceClient.ts index ae9d3bda..49eab16d 100644 --- a/src/configure/clients/github/TemplateServiceClient.ts +++ b/src/configure/clients/github/TemplateServiceClient.ts @@ -1,6 +1,7 @@ import { RepositoryAnalysisParameters } from "../../model/models"; import { PipelineTemplateMetadata } from "../../model/templateModels"; import { RestClient } from "../restClient"; +import { PipelineTemplateNew } from "../../model/PipelineTemplateNew"; export class TemplateServiceClient { private restClient: RestClient; @@ -11,9 +12,17 @@ export class TemplateServiceClient { public async getTemplates(body: RepositoryAnalysisParameters): Promise { return this.restClient.sendRequest2( - 'https://ts21.azurewebsites.net/Templates', + 'https://tswithouthmac.azurewebsites.net/Templates', 'POST', '2019-05-01', body); } + + public async getTemplateById(templateId: string): Promise { + return this.restClient.sendRequest2( + 'https://tswithouthmac.azurewebsites.net/Templates/' + templateId + '/parameters', + 'GET', + '2019-05-01', + null); + } } \ No newline at end of file diff --git a/src/configure/configure.ts b/src/configure/configure.ts index dc69bf8b..c46c69b8 100644 --- a/src/configure/configure.ts +++ b/src/configure/configure.ts @@ -18,7 +18,7 @@ import { Result, telemetryHelper } from './helper/telemetryHelper'; import * as templateHelper from './helper/templateHelper'; import { TemplateParameterHelper } from './helper/templateParameterHelper'; import { extensionVariables, GitBranchDetails, GitRepositoryParameters, MustacheContext, ParsedAzureResourceId, QuickPickItemWithData, RepositoryAnalysisApplicationSettings, RepositoryProvider, SourceOptions, TargetKind, TargetResourceType, WizardInputs } from './model/models'; -import { TemplateAssetType } from './model/templateModels'; +import { TemplateAssetType, PipelineTemplateMetadata } from './model/templateModels'; import * as constants from './resources/constants'; import { Messages } from './resources/messages'; import { TelemetryKeys } from './resources/telemetryKeys'; @@ -112,6 +112,12 @@ class Orchestrator { } } + private async processingTemplate(template: PipelineTemplateMetadata) { + + //getting the template + this.inputs.pipelineConfiguration.templateNew = await templateHelper.getTemplate(template.templateId); + } + private async getInputs(node: any): Promise { let resourceNode = await this.analyzeNode(node); @@ -120,6 +126,11 @@ class Orchestrator { await this.getAzureSession(); await this.getSelectedPipeline(); + //process the template + if (extensionVariables.templateServiceEnabled) { + await this.processingTemplate(this.inputs.pipelineConfiguration.templateInfo); + } + if (this.inputs.pipelineConfiguration.template.label === "Containerized application to AKS") { // try to see if node corresponds to any parameter of selected pipeline. if (resourceNode) { diff --git a/src/configure/helper/templateHelper.ts b/src/configure/helper/templateHelper.ts index 63b1794d..c0df2494 100644 --- a/src/configure/helper/templateHelper.ts +++ b/src/configure/helper/templateHelper.ts @@ -5,6 +5,7 @@ import * as path from 'path'; import * as Q from 'q'; import { TemplateServiceClient } from '../clients/github/TemplateServiceClient'; import { AzureConnectionType, extensionVariables, MustacheContext, RepositoryAnalysisParameters, RepositoryProvider, SupportedLanguage, TargetKind, TargetResourceType } from '../model/models'; +import { PipelineTemplateNew } from '../model/PipelineTemplateNew'; import { PipelineTemplate, PipelineTemplateMetadata, PreDefinedDataSourceIds, TemplateAssetType, TemplateParameterType } from '../model/templateModels'; import { PipelineTemplateLabels, RepoAnalysisConstants } from '../resources/constants'; import { Messages } from '../resources/messages'; @@ -12,6 +13,14 @@ import { TracePoints } from '../resources/tracePoints'; import { MustacheHelper } from './mustacheHelper'; import { telemetryHelper } from './telemetryHelper'; +export async function getTemplate(templateId: string): Promise { + + let serviceClient = new TemplateServiceClient(); + let template: PipelineTemplateNew; + template = await serviceClient.getTemplateById(templateId); + return template; +} + export async function mergingRepoAnalysisResults(repoPath: string, repositoryProvider: RepositoryProvider, repoAnalysisParameters: RepositoryAnalysisParameters): Promise { let localRepoAnalysisResult = await analyzeRepo(repoPath); let analysisResult = localRepoAnalysisResult; diff --git a/src/configure/model/DataSource.ts b/src/configure/model/DataSource.ts new file mode 100644 index 00000000..fee840c5 --- /dev/null +++ b/src/configure/model/DataSource.ts @@ -0,0 +1,9 @@ +export interface DataSource { + + Id: string; + EndpointUrlStem: string; + HttpMethod: string; + RequestBody: string; + ResultSelector: string; + ResultTemplate: string; +} \ No newline at end of file diff --git a/src/configure/model/InputDescriptor.ts b/src/configure/model/InputDescriptor.ts new file mode 100644 index 00000000..f2f773c9 --- /dev/null +++ b/src/configure/model/InputDescriptor.ts @@ -0,0 +1,42 @@ +export enum InputMode { + + None = 0, + TextBox = 10, + PasswordBox = 20, + Combo = 30, + CheckBox = 40, + AzureSubscription = 50, + TenantId = 60, + AadAccessToken = 70, + RadioButtons = 80, + VirtualMachineSizeControl = 90 +} + +export enum InputDataType { + + String = 0, + SecureString = 1, + Int = 2, + Bool = 3, + Authorization = 4 +} + +export interface InputDescriptor { + + name: string; + groupId: string; + isRequired: boolean; + sublabel: string; + properties: { key: string, value: any }[]; + inputMode: InputMode; + dataSourceId: string; + defaultValue: string; + staticValidation: { key: string, value: any }[]; + dynamicValidations: { key: string, value: any }[]; + visibleRule: string; + id: string; + description: string; + type: InputDataType; + possibleValues: { key: string, value: any }[]; + value: any; +} \ No newline at end of file diff --git a/src/configure/model/InputGroup.ts b/src/configure/model/InputGroup.ts new file mode 100644 index 00000000..f04723fa --- /dev/null +++ b/src/configure/model/InputGroup.ts @@ -0,0 +1,6 @@ +export interface InputGroup { + + id: string; + name: string; + properties: { key: string, value: any }[]; +} \ No newline at end of file diff --git a/src/configure/model/PipelineTemplateNew.ts b/src/configure/model/PipelineTemplateNew.ts new file mode 100644 index 00000000..8704c851 --- /dev/null +++ b/src/configure/model/PipelineTemplateNew.ts @@ -0,0 +1,11 @@ +import { DataSource } from "./DataSource"; +import { InputDescriptor } from "./InputDescriptor"; +import { InputGroup } from "./InputGroup"; + +export class PipelineTemplateNew { + + groups: InputGroup[]; + dataSources: DataSource[]; + inputs: InputDescriptor[]; + attributes: { key: string, value: any }[]; +} \ No newline at end of file diff --git a/src/configure/model/models.ts b/src/configure/model/models.ts index 0f75de44..7def3cba 100644 --- a/src/configure/model/models.ts +++ b/src/configure/model/models.ts @@ -6,6 +6,7 @@ import { ExtensionContext, OutputChannel, QuickPickItem, workspace } from 'vscod import { IAzureUserInput, ITelemetryReporter, UIExtensionVariables } from 'vscode-azureextensionui'; import { Messages } from '../resources/messages'; import { PipelineTemplate, PipelineTemplateMetadata } from './templateModels'; +import { PipelineTemplateNew } from './PipelineTemplateNew'; class ExtensionVariables implements UIExtensionVariables { public azureAccountExtensionApi: AzureAccountExtensionExports; @@ -83,6 +84,7 @@ export class AzureSession { export class PipelineConfiguration { filePath: string; template: PipelineTemplate; + templateNew: PipelineTemplateNew; templateInfo: PipelineTemplateMetadata; workingDirectory: string; params: { [key: string]: any } = {}; From 5305ac3d7965049ee2cb05e3a3608a31e0976ba5 Mon Sep 17 00:00:00 2001 From: Kanika Pasrija Date: Tue, 7 Apr 2020 11:31:34 +0530 Subject: [PATCH 8/8] TS Lint corrections --- src/configure/configure.ts | 2 +- src/configure/model/models.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/configure/configure.ts b/src/configure/configure.ts index 601ba789..acfabef8 100644 --- a/src/configure/configure.ts +++ b/src/configure/configure.ts @@ -18,7 +18,7 @@ import { Result, telemetryHelper } from './helper/telemetryHelper'; import * as templateHelper from './helper/templateHelper'; import { TemplateParameterHelper } from './helper/templateParameterHelper'; import { extensionVariables, GitBranchDetails, GitRepositoryParameters, MustacheContext, ParsedAzureResourceId, QuickPickItemWithData, RepositoryAnalysisApplicationSettings, RepositoryProvider, SourceOptions, TargetKind, TargetResourceType, WizardInputs } from './model/models'; -import { TemplateAssetType, PipelineTemplateMetadata } from './model/templateModels'; +import { PipelineTemplateMetadata, TemplateAssetType } from './model/templateModels'; import * as constants from './resources/constants'; import { Messages } from './resources/messages'; import { TelemetryKeys } from './resources/telemetryKeys'; diff --git a/src/configure/model/models.ts b/src/configure/model/models.ts index 7def3cba..26eaaae6 100644 --- a/src/configure/model/models.ts +++ b/src/configure/model/models.ts @@ -5,8 +5,8 @@ import { AzureEnvironment } from 'ms-rest-azure'; import { ExtensionContext, OutputChannel, QuickPickItem, workspace } from 'vscode'; import { IAzureUserInput, ITelemetryReporter, UIExtensionVariables } from 'vscode-azureextensionui'; import { Messages } from '../resources/messages'; -import { PipelineTemplate, PipelineTemplateMetadata } from './templateModels'; import { PipelineTemplateNew } from './PipelineTemplateNew'; +import { PipelineTemplate, PipelineTemplateMetadata } from './templateModels'; class ExtensionVariables implements UIExtensionVariables { public azureAccountExtensionApi: AzureAccountExtensionExports;