From 7692e5c1fcee7b26abefd618e898a9619d0cd375 Mon Sep 17 00:00:00 2001 From: Worasit D Date: Sat, 8 Jul 2023 00:12:28 +0700 Subject: [PATCH 1/6] frontend azure --- frontend/src/clients/pipelineApis.ts | 12 +++++- .../PipelineSetup/PipelineSetup.tsx | 6 +++ frontend/src/models/pipeline.ts | 1 + .../pipelineConfig/azurePipelinesConfig.tsx | 42 +++++++++++++++++++ .../utils/pipelineConfig/pipelineConfig.tsx | 17 ++++++++ 5 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 frontend/src/utils/pipelineConfig/azurePipelinesConfig.tsx diff --git a/frontend/src/clients/pipelineApis.ts b/frontend/src/clients/pipelineApis.ts index 01fafa01..67a3e9f5 100644 --- a/frontend/src/clients/pipelineApis.ts +++ b/frontend/src/clients/pipelineApis.ts @@ -75,14 +75,24 @@ export interface GithubActions extends BasePipeline { type: PipelineTool.GITHUB_ACTIONS; } +export interface AzurePipelines extends BasePipeline { + type: PipelineTool.AZURE_PIPELINES; +} + export interface BambooDeployedPipeline extends BasePipeline { type: PipelineTool.BAMBOO_DEPLOYMENT; } -export type Pipeline = JenkinsPipeline | BambooPipeline | GithubActions | BambooDeployedPipeline; +export type Pipeline = + | JenkinsPipeline + | BambooPipeline + | GithubActions + | AzurePipelines + | BambooDeployedPipeline; export type PipelineVerification = | Omit | Omit | Omit + | Omit | Omit; diff --git a/frontend/src/components/PipelineSetup/PipelineSetup.tsx b/frontend/src/components/PipelineSetup/PipelineSetup.tsx index 3f2e992a..8e7ec0ad 100644 --- a/frontend/src/components/PipelineSetup/PipelineSetup.tsx +++ b/frontend/src/components/PipelineSetup/PipelineSetup.tsx @@ -1,4 +1,5 @@ import { + AzurePipelines, BambooDeployedPipeline, BambooPipeline, GithubActions, @@ -20,12 +21,14 @@ const { Item, useForm } = Form; type JenkinsFormValues = Omit; type BambooFormValues = Omit; type GithubActionsFormValues = Omit; +type AzurePipelinesFormValues = Omit; type BambooDeployedFormValues = Omit; export type FormValues = | JenkinsFormValues | BambooFormValues | GithubActionsFormValues + | AzurePipelinesFormValues | BambooDeployedFormValues; const groupTitleStyles = css({ fontWeight: "bold", display: "inline-block", marginBottom: 12 }); @@ -145,6 +148,9 @@ const PipelineSetup: FC<{ + diff --git a/frontend/src/models/pipeline.ts b/frontend/src/models/pipeline.ts index d91b287a..9a3e4e12 100644 --- a/frontend/src/models/pipeline.ts +++ b/frontend/src/models/pipeline.ts @@ -3,5 +3,6 @@ export enum PipelineTool { JENKINS = "JENKINS", GITHUB_ACTIONS = "GITHUB_ACTIONS", BAMBOO_DEPLOYMENT = "BAMBOO_DEPLOYMENT", + AZURE_PIPELINES = "AZURE_PIPELINES", BUDDY = "BUDDY", } diff --git a/frontend/src/utils/pipelineConfig/azurePipelinesConfig.tsx b/frontend/src/utils/pipelineConfig/azurePipelinesConfig.tsx new file mode 100644 index 00000000..35f6fcbf --- /dev/null +++ b/frontend/src/utils/pipelineConfig/azurePipelinesConfig.tsx @@ -0,0 +1,42 @@ +import React from "react"; + +import { InfoCircleOutlined } from "@ant-design/icons"; +import { PipelineConfig } from "./jenkinsConfig"; + +export const AZURE_PIPELINES_CONFIG: PipelineConfig[] = [ + { + gutter: 24, + children: [ + { + span: 16, + name: "url", + label: "Project URL", + placeholder: "e.g: https://dev.azure.com/JetstarAirways/Raven", + tooltip: { + icon: , + title: + 'URL of the project. Please ensure the URL is complete and including the organization/project name. e.g. "https://dev.azure.com/{organization}/{project}"', + }, + rules: [{ required: true, whitespace: true, message: "Please input the project URL." }], + }, + ], + }, + { + gutter: 24, + children: [ + { + span: 8, + name: "credential", + type: "password", + label: "Personal Access Token", + tooltip: { + icon: , + title: + "The PAT (Personal Access Token) will be used to invoke Azure Pipeline APIs to fetch pipeline run status. Tokens can be narrowly scoped to allow only the read access to project and pipeline. Don't know how to manage tokens? Go to: https://learn.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate", + }, + + rules: [{ required: true, whitespace: true, message: "Please input access token." }], + }, + ], + }, +]; diff --git a/frontend/src/utils/pipelineConfig/pipelineConfig.tsx b/frontend/src/utils/pipelineConfig/pipelineConfig.tsx index 310d9eb3..a7ea22fa 100644 --- a/frontend/src/utils/pipelineConfig/pipelineConfig.tsx +++ b/frontend/src/utils/pipelineConfig/pipelineConfig.tsx @@ -5,11 +5,13 @@ import { GITHUB_ACTIONS_CONFIG } from "./githubActionsConfig"; import { BAMBOO_DEPLOYED_PIPELINE_CONFIG } from "./bambooDeployedConfig"; import { BUDDY_CONFIG } from "./buddyConfig"; import { PipelineTool } from "../../models/pipeline"; +import { AZURE_PIPELINES_CONFIG } from "./azurePipelinesConfig"; export const PIPELINE_CONFIG = { [PipelineTool.JENKINS]: JENKINS_PIPELINE_CONFIG, [PipelineTool.BAMBOO]: BAMBOO_PIPELINE_CONFIG, [PipelineTool.GITHUB_ACTIONS]: GITHUB_ACTIONS_CONFIG, + [PipelineTool.AZURE_PIPELINES]: AZURE_PIPELINES_CONFIG, [PipelineTool.BAMBOO_DEPLOYMENT]: BAMBOO_DEPLOYED_PIPELINE_CONFIG, [PipelineTool.BUDDY]: BUDDY_CONFIG, }; @@ -47,6 +49,21 @@ export const PIPELINE_TYPE_NOTE = { ), + [PipelineTool.AZURE_PIPELINES]: ( +
+ Note: Deployment data is collected from pipelines execution history. All you have to provide + here is the URL of your Azure Pipeline and we can find all associated pipeline executions for + you automatically. Struggle with the terms? More details please refer to:{" "} + + https://azure.microsoft.com/en-us/products/devops/pipelines + +
+ ), [PipelineTool.BAMBOO_DEPLOYMENT]: (
Note: Deployment data is ought to be collected from Bamboo "Build Plans" and/or From 0347de4544770452388b4b2069fc3fb51112cb19 Mon Sep 17 00:00:00 2001 From: worasit Date: Sat, 8 Jul 2023 00:54:25 +0700 Subject: [PATCH 2/6] drafted azure pipeline service --- .../project/domain/model/PipelineType.kt | 2 +- .../AzurePipelinesPipelineService.kt | 31 ++++++++++++++ .../service/factory/PipelineServiceFactory.kt | 5 ++- .../rest/vo/request/AzurePipelinesRequest.kt | 41 +++++++++++++++++++ .../metrik/project/rest/vo/request/Request.kt | 10 +++-- 5 files changed, 83 insertions(+), 6 deletions(-) create mode 100644 backend/src/main/kotlin/metrik/project/domain/service/azurepipelines/AzurePipelinesPipelineService.kt create mode 100644 backend/src/main/kotlin/metrik/project/rest/vo/request/AzurePipelinesRequest.kt diff --git a/backend/src/main/kotlin/metrik/project/domain/model/PipelineType.kt b/backend/src/main/kotlin/metrik/project/domain/model/PipelineType.kt index 197cc4b3..94c4a11b 100644 --- a/backend/src/main/kotlin/metrik/project/domain/model/PipelineType.kt +++ b/backend/src/main/kotlin/metrik/project/domain/model/PipelineType.kt @@ -1,5 +1,5 @@ package metrik.project.domain.model enum class PipelineType { - JENKINS, BAMBOO, BAMBOO_DEPLOYMENT, GITHUB_ACTIONS, BUDDY, NOT_SUPPORTED + JENKINS, BAMBOO, BAMBOO_DEPLOYMENT, GITHUB_ACTIONS, AZURE_PIPELINES, BUDDY, NOT_SUPPORTED } diff --git a/backend/src/main/kotlin/metrik/project/domain/service/azurepipelines/AzurePipelinesPipelineService.kt b/backend/src/main/kotlin/metrik/project/domain/service/azurepipelines/AzurePipelinesPipelineService.kt new file mode 100644 index 00000000..3b032fde --- /dev/null +++ b/backend/src/main/kotlin/metrik/project/domain/service/azurepipelines/AzurePipelinesPipelineService.kt @@ -0,0 +1,31 @@ +package metrik.project.domain.service.azurepipelines + +import metrik.project.domain.model.Execution +import metrik.project.domain.model.PipelineConfiguration +import metrik.project.domain.service.PipelineService +import metrik.project.rest.vo.response.SyncProgress +import org.slf4j.LoggerFactory +import org.springframework.stereotype.Service + +@Service("azurePipelinesPipelineService") +class AzurePipelinesPipelineService : PipelineService { + private var logger = LoggerFactory.getLogger(javaClass.name) + override fun syncBuildsProgressively( + pipeline: PipelineConfiguration, + emitCb: (SyncProgress) -> Unit + ): List { + TODO("Not yet implemented") + } + + override fun verifyPipelineConfiguration(pipeline: PipelineConfiguration) { + logger.info( + "Started verification for Azure Pipelines [name: ${pipeline.name}, url: ${pipeline.url}, " + + "type: ${pipeline.type}]" + ) + + } + + override fun getStagesSortedByName(pipelineId: String): List { + TODO("Not yet implemented") + } +} \ No newline at end of file diff --git a/backend/src/main/kotlin/metrik/project/domain/service/factory/PipelineServiceFactory.kt b/backend/src/main/kotlin/metrik/project/domain/service/factory/PipelineServiceFactory.kt index bd431603..5dca8055 100644 --- a/backend/src/main/kotlin/metrik/project/domain/service/factory/PipelineServiceFactory.kt +++ b/backend/src/main/kotlin/metrik/project/domain/service/factory/PipelineServiceFactory.kt @@ -5,6 +5,7 @@ import metrik.project.domain.service.PipelineService import metrik.project.domain.service.buddy.BuddyPipelineService import org.springframework.beans.factory.annotation.Autowired import org.springframework.stereotype.Component +import java.nio.channels.Pipe @Component class PipelineServiceFactory( @@ -13,7 +14,8 @@ class PipelineServiceFactory( @Autowired private val githubActionsPipelineService: PipelineService, @Autowired private val bambooDeploymentPipelineService: PipelineService, @Autowired private val buddyPipelineService: BuddyPipelineService, - @Autowired private val noopPipelineService: PipelineService + @Autowired private val noopPipelineService: PipelineService, + @Autowired private val azurePipelinesPipelineService: PipelineService ) { fun getService(pipelineType: PipelineType): PipelineService { return when (pipelineType) { @@ -21,6 +23,7 @@ class PipelineServiceFactory( PipelineType.BAMBOO -> this.bambooPipelineService PipelineType.GITHUB_ACTIONS -> this.githubActionsPipelineService PipelineType.BAMBOO_DEPLOYMENT -> this.bambooDeploymentPipelineService + PipelineType.AZURE_PIPELINES -> this.azurePipelinesPipelineService PipelineType.BUDDY -> this.buddyPipelineService else -> this.noopPipelineService } diff --git a/backend/src/main/kotlin/metrik/project/rest/vo/request/AzurePipelinesRequest.kt b/backend/src/main/kotlin/metrik/project/rest/vo/request/AzurePipelinesRequest.kt new file mode 100644 index 00000000..b2ce1c9a --- /dev/null +++ b/backend/src/main/kotlin/metrik/project/rest/vo/request/AzurePipelinesRequest.kt @@ -0,0 +1,41 @@ +package metrik.project.rest.vo.request + +import metrik.project.domain.model.PipelineConfiguration +import metrik.project.domain.model.PipelineType +import java.net.URL +import javax.validation.constraints.NotBlank + +class AzurePipelinesPipelineRequest( + @field:NotBlank(message = "Name cannot be empty") val name: String, + @field:NotBlank(message = "Credential cannot be empty") val credential: String, + url: String +) : PipelineRequest(url, PipelineType.AZURE_PIPELINES.toString()) { + override fun toPipeline(projectId: String, pipelineId: String) = PipelineConfiguration( + id = pipelineId, + projectId = projectId, + name = name, + username = null, + credential = credential, + url = toGithubActionsUrl(url), + type = PipelineType.valueOf(type) + ) + + private fun toGithubActionsUrl(url: String) = + URL(url).path.split("/").let { "$apiRepo/${it[it.size - ownerIndex]}/${it.last()}" } + + private companion object { + const val ownerIndex = 2 + const val apiRepo = "https://api.github.com/repos" + } +} + +class AzurePipelinesVerificationRequest( + @field:NotBlank(message = "Credential cannot be null or empty") val credential: String, + url: String +) : PipelineVerificationRequest(url, PipelineType.AZURE_PIPELINES.toString()) { + override fun toPipeline() = PipelineConfiguration( + credential = credential, + url = url, + type = PipelineType.valueOf(type) + ) +} diff --git a/backend/src/main/kotlin/metrik/project/rest/vo/request/Request.kt b/backend/src/main/kotlin/metrik/project/rest/vo/request/Request.kt index 9c117e0b..c03dc481 100644 --- a/backend/src/main/kotlin/metrik/project/rest/vo/request/Request.kt +++ b/backend/src/main/kotlin/metrik/project/rest/vo/request/Request.kt @@ -29,14 +29,15 @@ data class UpdateProjectRequest( JsonSubTypes.Type(value = BambooDeploymentPipelineRequest::class, name = "BAMBOO_DEPLOYMENT"), JsonSubTypes.Type(value = JenkinsPipelineRequest::class, name = "JENKINS"), JsonSubTypes.Type(value = GithubActionsPipelineRequest::class, name = "GITHUB_ACTIONS"), + JsonSubTypes.Type(value = AzurePipelinesPipelineRequest::class, name = "AZURE_PIPELINES"), JsonSubTypes.Type(value = BuddyPipelineRequest::class, name = "BUDDY") ) abstract class PipelineRequest( @field:NotBlank(message = "URL cannot be empty") val url: String, @field:EnumConstraint( - acceptedValues = ["JENKINS", "BAMBOO", "BAMBOO_DEPLOYMENT", "GITHUB_ACTIONS", "BUDDY"], - message = "Allowed types: JENKINS, BAMBOO, BAMBOO_DEPLOYMENT, GITHUB_ACTIONS, BUDDY" + acceptedValues = ["JENKINS", "BAMBOO", "BAMBOO_DEPLOYMENT", "GITHUB_ACTIONS", "AZURE_PIPELINES", "BUDDY"], + message = "Allowed types: JENKINS, BAMBOO, BAMBOO_DEPLOYMENT, GITHUB_ACTIONS, AZURE_PIPELINES, BUDDY" ) var type: String ) { @@ -53,14 +54,15 @@ abstract class PipelineRequest( JsonSubTypes.Type(value = BambooDeploymentVerificationRequest::class, name = "BAMBOO_DEPLOYMENT"), JsonSubTypes.Type(value = JenkinsVerificationRequest::class, name = "JENKINS"), JsonSubTypes.Type(value = GithubActionsVerificationRequest::class, name = "GITHUB_ACTIONS"), + JsonSubTypes.Type(value = AzurePipelinesVerificationRequest::class, name = "AZURE_PIPELINES"), JsonSubTypes.Type(value = BuddyVerificationRequest::class, name = "BUDDY"), ) abstract class PipelineVerificationRequest( @field:NotBlank(message = "URL cannot be empty") val url: String, @field:EnumConstraint( - acceptedValues = ["JENKINS", "BAMBOO", "BAMBOO_DEPLOYMENT", "GITHUB_ACTIONS", "BUDDY"], - message = "Allowed types: JENKINS, BAMBOO, BAMBOO_DEPLOYMENT, GITHUB_ACTIONS, BUDDY" + acceptedValues = ["JENKINS", "BAMBOO", "BAMBOO_DEPLOYMENT", "GITHUB_ACTIONS", "AZURE_PIPELINES", "BUDDY"], + message = "Allowed types: JENKINS, BAMBOO, BAMBOO_DEPLOYMENT, GITHUB_ACTIONS, AZURE_PIPELINES, BUDDY" ) val type: String, ) { From 6d047e7052686c5372d87c5acf685fbe40b93c2f Mon Sep 17 00:00:00 2001 From: worasit Date: Sat, 8 Jul 2023 01:04:54 +0700 Subject: [PATCH 3/6] updated placeholder --- frontend/src/utils/pipelineConfig/azurePipelinesConfig.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/utils/pipelineConfig/azurePipelinesConfig.tsx b/frontend/src/utils/pipelineConfig/azurePipelinesConfig.tsx index 35f6fcbf..b954b00f 100644 --- a/frontend/src/utils/pipelineConfig/azurePipelinesConfig.tsx +++ b/frontend/src/utils/pipelineConfig/azurePipelinesConfig.tsx @@ -11,7 +11,7 @@ export const AZURE_PIPELINES_CONFIG: PipelineConfig[] = [ span: 16, name: "url", label: "Project URL", - placeholder: "e.g: https://dev.azure.com/JetstarAirways/Raven", + placeholder: "e.g: https://dev.azure.com/organization/project", tooltip: { icon: , title: From 9a597501ce234aa4bc7ed61ccc5f1233adb7de65 Mon Sep 17 00:00:00 2001 From: worasit Date: Sat, 8 Jul 2023 02:18:34 +0700 Subject: [PATCH 4/6] completed verify pipeline endpoint --- .../AzurePipelinesPipelineService.kt | 30 +++++++++++++- .../azure/feign/AzureFeignClient.kt | 40 +++++++++++++++++++ .../response/MultiplePipelineResponse.kt | 32 +++++++++++++++ 3 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 backend/src/main/kotlin/metrik/project/infrastructure/azure/feign/AzureFeignClient.kt create mode 100644 backend/src/main/kotlin/metrik/project/infrastructure/azure/feign/response/MultiplePipelineResponse.kt diff --git a/backend/src/main/kotlin/metrik/project/domain/service/azurepipelines/AzurePipelinesPipelineService.kt b/backend/src/main/kotlin/metrik/project/domain/service/azurepipelines/AzurePipelinesPipelineService.kt index 3b032fde..b8dca66e 100644 --- a/backend/src/main/kotlin/metrik/project/domain/service/azurepipelines/AzurePipelinesPipelineService.kt +++ b/backend/src/main/kotlin/metrik/project/domain/service/azurepipelines/AzurePipelinesPipelineService.kt @@ -1,14 +1,20 @@ package metrik.project.domain.service.azurepipelines +import feign.FeignException +import feign.codec.DecodeException import metrik.project.domain.model.Execution import metrik.project.domain.model.PipelineConfiguration import metrik.project.domain.service.PipelineService +import metrik.project.domain.service.githubactions.GithubActionsPipelineService +import metrik.project.exception.PipelineConfigVerifyException +import metrik.project.infrastructure.azure.feign.AzureFeignClient import metrik.project.rest.vo.response.SyncProgress import org.slf4j.LoggerFactory import org.springframework.stereotype.Service +import java.net.URL @Service("azurePipelinesPipelineService") -class AzurePipelinesPipelineService : PipelineService { +class AzurePipelinesPipelineService(private val azureFeignClient: AzureFeignClient) : PipelineService { private var logger = LoggerFactory.getLogger(javaClass.name) override fun syncBuildsProgressively( pipeline: PipelineConfiguration, @@ -23,9 +29,31 @@ class AzurePipelinesPipelineService : PipelineService { "type: ${pipeline.type}]" ) + try { + val (organization, project) = getOrganizationProjectFromUrl(pipeline.url) + azureFeignClient.retrieveMultiplePipelines(pipeline.credential, organization, project) + ?: throw PipelineConfigVerifyException("Verify failed") + } catch (ex: FeignException.FeignServerException) { + throw PipelineConfigVerifyException("Verify website unavailable") + } catch (ex: FeignException.FeignClientException) { + throw PipelineConfigVerifyException("Verify failed") + } catch (ex: FeignException) { + throw PipelineConfigVerifyException("Verify failed") + } } override fun getStagesSortedByName(pipelineId: String): List { TODO("Not yet implemented") } + + private fun getOrganizationProjectFromUrl(url: String): Pair { + val components = URL(url).path.split("/") + val organization = components[components.size - organizationIndex] + val project = components.last() + return Pair(organization, project) + } + + private companion object { + const val organizationIndex = 2 + } } \ No newline at end of file diff --git a/backend/src/main/kotlin/metrik/project/infrastructure/azure/feign/AzureFeignClient.kt b/backend/src/main/kotlin/metrik/project/infrastructure/azure/feign/AzureFeignClient.kt new file mode 100644 index 00000000..8c86f6a1 --- /dev/null +++ b/backend/src/main/kotlin/metrik/project/infrastructure/azure/feign/AzureFeignClient.kt @@ -0,0 +1,40 @@ +package metrik.project.infrastructure.azure.feign + +import feign.Headers +import feign.RequestInterceptor +import feign.RequestTemplate +import metrik.project.infrastructure.azure.feign.response.MultiplePipelineResponse +import metrik.project.infrastructure.github.feign.response.BranchResponse +import metrik.project.infrastructure.github.feign.response.CommitResponse +import metrik.project.infrastructure.github.feign.response.MultipleRunResponse +import metrik.project.infrastructure.github.feign.response.SingleRunResponse +import org.springframework.cloud.openfeign.FeignClient +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.RequestHeader +import org.springframework.web.bind.annotation.RequestParam +import java.util.Base64 + +@FeignClient( + value = "azure-api", + url = "https://dev.azure.com/", + configuration = [AzureFeignClientConfiguration::class] +) +interface AzureFeignClient { + @GetMapping("{organization}/{project}/_apis/pipelines?api-version=6.1-preview.1") + @Headers("Content-Type: application/json") + fun retrieveMultiplePipelines( + @RequestHeader("credential") credential: String, + @PathVariable("organization") organization: String, + @PathVariable("project") project: String, + ): MultiplePipelineResponse? +} + +class AzureFeignClientConfiguration : RequestInterceptor { + override fun apply(template: RequestTemplate?) { + val pat = template!!.headers()["credential"]!!.first() + val encode = Base64.getEncoder().encodeToString("dora:$pat".encodeToByteArray()) + template.header("Authorization", "Basic $encode") + template.removeHeader("credential") + } +} diff --git a/backend/src/main/kotlin/metrik/project/infrastructure/azure/feign/response/MultiplePipelineResponse.kt b/backend/src/main/kotlin/metrik/project/infrastructure/azure/feign/response/MultiplePipelineResponse.kt new file mode 100644 index 00000000..221ef6d7 --- /dev/null +++ b/backend/src/main/kotlin/metrik/project/infrastructure/azure/feign/response/MultiplePipelineResponse.kt @@ -0,0 +1,32 @@ +package metrik.project.infrastructure.azure.feign.response + +import com.fasterxml.jackson.databind.PropertyNamingStrategy +import com.fasterxml.jackson.databind.annotation.JsonNaming + +@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy::class) +data class MultiplePipelineResponse( + val count: Int, + val value: List +) + +data class Value( + val _links: Links, + val folder: String, + val id: Int, + val name: String, + val revision: Int, + val url: String +) + +data class Links( + val self: Self, + val web: Web +) + +data class Self( + val href: String +) + +data class Web( + val href: String +) \ No newline at end of file From 26f949a3384f5719729a9f103e82d6d46167ce04 Mon Sep 17 00:00:00 2001 From: worasit Date: Sat, 8 Jul 2023 02:37:04 +0700 Subject: [PATCH 5/6] bring back name to allow create button --- .../utils/pipelineConfig/azurePipelinesConfig.tsx | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/frontend/src/utils/pipelineConfig/azurePipelinesConfig.tsx b/frontend/src/utils/pipelineConfig/azurePipelinesConfig.tsx index b954b00f..b011235a 100644 --- a/frontend/src/utils/pipelineConfig/azurePipelinesConfig.tsx +++ b/frontend/src/utils/pipelineConfig/azurePipelinesConfig.tsx @@ -7,6 +7,18 @@ export const AZURE_PIPELINES_CONFIG: PipelineConfig[] = [ { gutter: 24, children: [ + { + span: 8, + name: "name", + label: "Project Name", + rules: [ + { + required: true, + whitespace: true, + message: "Please input name of your project on Azure Pipeline.", + }, + ], + }, { span: 16, name: "url", From 16a70431d86996de497ae8e11ba314097a5f65d1 Mon Sep 17 00:00:00 2001 From: worasit Date: Sat, 8 Jul 2023 03:09:05 +0700 Subject: [PATCH 6/6] Completed getPipeline stages --- .../azurepipelines/AzurePipelinesPipelineService.kt | 13 +++++++++++-- .../rest/vo/request/AzurePipelinesRequest.kt | 10 +--------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/backend/src/main/kotlin/metrik/project/domain/service/azurepipelines/AzurePipelinesPipelineService.kt b/backend/src/main/kotlin/metrik/project/domain/service/azurepipelines/AzurePipelinesPipelineService.kt index b8dca66e..450b18b9 100644 --- a/backend/src/main/kotlin/metrik/project/domain/service/azurepipelines/AzurePipelinesPipelineService.kt +++ b/backend/src/main/kotlin/metrik/project/domain/service/azurepipelines/AzurePipelinesPipelineService.kt @@ -4,6 +4,7 @@ import feign.FeignException import feign.codec.DecodeException import metrik.project.domain.model.Execution import metrik.project.domain.model.PipelineConfiguration +import metrik.project.domain.repository.BuildRepository import metrik.project.domain.service.PipelineService import metrik.project.domain.service.githubactions.GithubActionsPipelineService import metrik.project.exception.PipelineConfigVerifyException @@ -14,7 +15,10 @@ import org.springframework.stereotype.Service import java.net.URL @Service("azurePipelinesPipelineService") -class AzurePipelinesPipelineService(private val azureFeignClient: AzureFeignClient) : PipelineService { +class AzurePipelinesPipelineService( + private val azureFeignClient: AzureFeignClient, + private val buildRepository: BuildRepository, +) : PipelineService { private var logger = LoggerFactory.getLogger(javaClass.name) override fun syncBuildsProgressively( pipeline: PipelineConfiguration, @@ -43,7 +47,12 @@ class AzurePipelinesPipelineService(private val azureFeignClient: AzureFeignClie } override fun getStagesSortedByName(pipelineId: String): List { - TODO("Not yet implemented") + return buildRepository.getAllBuilds(pipelineId) + .flatMap { it.stages } + .map { it.name } + .distinct() + .sortedBy { it.uppercase() } + .toList() } private fun getOrganizationProjectFromUrl(url: String): Pair { diff --git a/backend/src/main/kotlin/metrik/project/rest/vo/request/AzurePipelinesRequest.kt b/backend/src/main/kotlin/metrik/project/rest/vo/request/AzurePipelinesRequest.kt index b2ce1c9a..8338b5cb 100644 --- a/backend/src/main/kotlin/metrik/project/rest/vo/request/AzurePipelinesRequest.kt +++ b/backend/src/main/kotlin/metrik/project/rest/vo/request/AzurePipelinesRequest.kt @@ -16,17 +16,9 @@ class AzurePipelinesPipelineRequest( name = name, username = null, credential = credential, - url = toGithubActionsUrl(url), + url = url, type = PipelineType.valueOf(type) ) - - private fun toGithubActionsUrl(url: String) = - URL(url).path.split("/").let { "$apiRepo/${it[it.size - ownerIndex]}/${it.last()}" } - - private companion object { - const val ownerIndex = 2 - const val apiRepo = "https://api.github.com/repos" - } } class AzurePipelinesVerificationRequest(