diff --git a/Wire.go b/Wire.go index ba26cd71da..acf2880732 100644 --- a/Wire.go +++ b/Wire.go @@ -224,6 +224,8 @@ func InitializeApp() (*App, error) { pipeline.GetDeploymentServiceTypeConfig, pipeline.NewPipelineBuilderImpl, wire.Bind(new(pipeline.PipelineBuilder), new(*pipeline.PipelineBuilderImpl)), + pipeline.NewCiPipelineConfigServiceImpl, + wire.Bind(new(pipeline.CiPipelineConfigService), new(*pipeline.CiPipelineConfigServiceImpl)), util5.NewLoggingMiddlewareImpl, wire.Bind(new(util5.LoggingMiddleware), new(*util5.LoggingMiddlewareImpl)), pipeline2.NewPipelineRestHandlerImpl, diff --git a/pkg/pipeline/BuildPipelineConfigService.go b/pkg/pipeline/BuildPipelineConfigService.go index 107f62e7dc..b4ab223131 100644 --- a/pkg/pipeline/BuildPipelineConfigService.go +++ b/pkg/pipeline/BuildPipelineConfigService.go @@ -19,8 +19,8 @@ package pipeline import ( "encoding/json" - "errors" "fmt" + "github.com/caarlos0/env" bean2 "github.com/devtron-labs/devtron/api/bean" "github.com/devtron-labs/devtron/internal/sql/repository" app2 "github.com/devtron-labs/devtron/internal/sql/repository/app" @@ -31,11 +31,15 @@ import ( "github.com/devtron-labs/devtron/pkg/attributes" "github.com/devtron-labs/devtron/pkg/bean" bean3 "github.com/devtron-labs/devtron/pkg/pipeline/bean" + "github.com/devtron-labs/devtron/pkg/pipeline/history" resourceGroup2 "github.com/devtron-labs/devtron/pkg/resourceGroup" "github.com/devtron-labs/devtron/pkg/sql" + util2 "github.com/devtron-labs/devtron/util" + "github.com/devtron-labs/devtron/util/rbac" "github.com/go-pg/pg" - errors2 "github.com/juju/errors" + "github.com/juju/errors" "go.opentelemetry.io/otel" + "go.uber.org/zap" "sort" "strings" "time" @@ -101,6 +105,78 @@ type CiPipelineConfigService interface { GetExternalCiByEnvironment(request resourceGroup2.ResourceGroupingRequest) (ciConfig []*bean.ExternalCiConfig, err error) DeleteCiPipeline(request *bean.CiPatchRequest) (*bean.CiPipeline, error) } + +type CiPipelineConfigServiceImpl struct { + logger *zap.SugaredLogger + ciTemplateService CiTemplateService + materialRepo pipelineConfig.MaterialRepository + ciPipelineRepository pipelineConfig.CiPipelineRepository + ciConfig *CiCdConfig + attributesService attributes.AttributesService + ciWorkflowRepository pipelineConfig.CiWorkflowRepository + appWorkflowRepository appWorkflow.AppWorkflowRepository + pipelineStageService PipelineStageService + pipelineRepository pipelineConfig.PipelineRepository + appRepo app2.AppRepository + dockerArtifactStoreRepository dockerRegistryRepository.DockerArtifactStoreRepository + ciCdPipelineOrchestrator CiCdPipelineOrchestrator + ciTemplateOverrideRepository pipelineConfig.CiTemplateOverrideRepository + CiTemplateHistoryService history.CiTemplateHistoryService + securityConfig *SecurityConfig + ecrConfig *EcrConfig + ciPipelineMaterialRepository pipelineConfig.CiPipelineMaterialRepository + resourceGroupService resourceGroup2.ResourceGroupService + enforcerUtil rbac.EnforcerUtil +} + +func NewCiPipelineConfigServiceImpl(logger *zap.SugaredLogger, + ciCdPipelineOrchestrator CiCdPipelineOrchestrator, + dockerArtifactStoreRepository dockerRegistryRepository.DockerArtifactStoreRepository, + materialRepo pipelineConfig.MaterialRepository, + pipelineGroupRepo app2.AppRepository, + pipelineRepository pipelineConfig.PipelineRepository, + ciPipelineRepository pipelineConfig.CiPipelineRepository, + ecrConfig *EcrConfig, + appWorkflowRepository appWorkflow.AppWorkflowRepository, + ciConfig *CiCdConfig, + attributesService attributes.AttributesService, + pipelineStageService PipelineStageService, + ciPipelineMaterialRepository pipelineConfig.CiPipelineMaterialRepository, + ciTemplateService CiTemplateService, + ciTemplateOverrideRepository pipelineConfig.CiTemplateOverrideRepository, + CiTemplateHistoryService history.CiTemplateHistoryService, + enforcerUtil rbac.EnforcerUtil, + ciWorkflowRepository pipelineConfig.CiWorkflowRepository, + resourceGroupService resourceGroup2.ResourceGroupService) *CiPipelineConfigServiceImpl { + securityConfig := &SecurityConfig{} + err := env.Parse(securityConfig) + if err != nil { + logger.Errorw("error in parsing securityConfig,setting ForceSecurityScanning to default value", "defaultValue", securityConfig.ForceSecurityScanning, "err", err) + } + return &CiPipelineConfigServiceImpl{ + logger: logger, + ciCdPipelineOrchestrator: ciCdPipelineOrchestrator, + dockerArtifactStoreRepository: dockerArtifactStoreRepository, + materialRepo: materialRepo, + appRepo: pipelineGroupRepo, + pipelineRepository: pipelineRepository, + ciPipelineRepository: ciPipelineRepository, + ecrConfig: ecrConfig, + appWorkflowRepository: appWorkflowRepository, + ciConfig: ciConfig, + attributesService: attributesService, + pipelineStageService: pipelineStageService, + ciPipelineMaterialRepository: ciPipelineMaterialRepository, + ciTemplateService: ciTemplateService, + ciTemplateOverrideRepository: ciTemplateOverrideRepository, + CiTemplateHistoryService: CiTemplateHistoryService, + enforcerUtil: enforcerUtil, + ciWorkflowRepository: ciWorkflowRepository, + resourceGroupService: resourceGroupService, + securityConfig: securityConfig, + } +} + type CiMaterialConfigService interface { //CreateMaterialsForApp : Delegating the request to ciCdPipelineOrchestrator for Material creation CreateMaterialsForApp(request *bean.CreateMaterialDTO) (*bean.CreateMaterialDTO, error) @@ -114,6 +190,7 @@ type CiMaterialConfigService interface { //GetMaterialsForAppId : Retrieve material for given appId GetMaterialsForAppId(appId int) []*bean.GitMaterial } + type AppArtifactManager interface { //RetrieveArtifactsByCDPipeline : RetrieveArtifactsByCDPipeline returns all the artifacts for the cd pipeline (pre / deploy / post) RetrieveArtifactsByCDPipeline(pipeline *pipelineConfig.Pipeline, stage bean2.WorkflowType) (*bean.CiArtifactResponse, error) @@ -122,7 +199,350 @@ type AppArtifactManager interface { FetchArtifactForRollback(cdPipelineId, appId, offset, limit int) (bean.CiArtifactResponse, error) } -func (impl *PipelineBuilderImpl) GetCiPipeline(appId int) (ciConfig *bean.CiConfigRequest, err error) { +func (impl *CiPipelineConfigServiceImpl) getCiTemplateVariablesByAppIds(appIds []int) (map[int]*bean.CiConfigRequest, error) { + ciConfigMap := make(map[int]*bean.CiConfigRequest) + ciTemplateMap, err := impl.ciTemplateService.FindByAppIds(appIds) + if err != nil && !errors.IsNotFound(err) { + impl.logger.Errorw("error in fetching ci pipeline", "appIds", appIds, "err", err) + return nil, err + } + if errors.IsNotFound(err) { + impl.logger.Debugw("no ci pipeline exists", "appIds", appIds, "err", err) + err = &util.ApiError{Code: "404", HttpStatusCode: 200, UserMessage: "no ci pipeline exists"} + return nil, err + } + gitMaterialsMap := make(map[int][]*pipelineConfig.GitMaterial) + allGitMaterials, err := impl.materialRepo.FindByAppIds(appIds) + if err != nil && err != pg.ErrNoRows { + impl.logger.Errorw("error in fetching git materials", "appIds", appIds, "err", err) + return nil, err + } + if err == pg.ErrNoRows { + impl.logger.Debugw(" no git materials exists", "appIds", appIds, "err", err) + err = &util.ApiError{Code: "404", HttpStatusCode: 200, UserMessage: "no git materials exists"} + return nil, err + } + for _, gitMaterial := range allGitMaterials { + gitMaterialsMap[gitMaterial.AppId] = append(gitMaterialsMap[gitMaterial.AppId], gitMaterial) + } + for _, ciTemplate := range ciTemplateMap { + template := ciTemplate.CiTemplate + var materials []bean.Material + gitMaterials := gitMaterialsMap[ciTemplate.CiTemplate.AppId] + for _, g := range gitMaterials { + m := bean.Material{ + GitMaterialId: g.Id, + MaterialName: g.Name[strings.Index(g.Name, "-")+1:], + } + materials = append(materials, m) + } + + var regHost string + dockerRegistry := template.DockerRegistry + if dockerRegistry != nil { + regHost, err = dockerRegistry.GetRegistryLocation() + if err != nil { + impl.logger.Errorw("invalid reg url", "err", err) + return nil, err + } + } + ciConfig := &bean.CiConfigRequest{ + Id: template.Id, + AppId: template.AppId, + AppName: template.App.AppName, + DockerRepository: template.DockerRepository, + DockerRegistryUrl: regHost, + CiBuildConfig: ciTemplate.CiBuildConfig, + Version: template.Version, + CiTemplateName: template.TemplateName, + Materials: materials, + //UpdatedOn: template.UpdatedOn, + //UpdatedBy: template.UpdatedBy, + //CreatedBy: template.CreatedBy, + //CreatedOn: template.CreatedOn, + } + if dockerRegistry != nil { + ciConfig.DockerRegistry = dockerRegistry.Id + } + ciConfigMap[template.AppId] = ciConfig + } + return ciConfigMap, err +} + +func (impl *CiPipelineConfigServiceImpl) getDefaultArtifactStore(id string) (store *dockerRegistryRepository.DockerArtifactStore, err error) { + if id == "" { + impl.logger.Debugw("docker repo is empty adding default repo") + store, err = impl.dockerArtifactStoreRepository.FindActiveDefaultStore() + + } else { + store, err = impl.dockerArtifactStoreRepository.FindOne(id) + } + return +} + +func (impl *CiPipelineConfigServiceImpl) patchCiPipelineUpdateSource(baseCiConfig *bean.CiConfigRequest, modifiedCiPipeline *bean.CiPipeline) (ciConfig *bean.CiConfigRequest, err error) { + + pipeline, err := impl.ciPipelineRepository.FindById(modifiedCiPipeline.Id) + if err != nil { + impl.logger.Errorw("error in fetching pipeline", "id", modifiedCiPipeline.Id, "err", err) + return nil, err + } + + cannotUpdate := false + for _, material := range pipeline.CiPipelineMaterials { + if material.ScmId != "" { + cannotUpdate = true + } + } + + if cannotUpdate { + //scm plugin material change scm object + //material.ScmName + return nil, fmt.Errorf("update of plugin scm material not supported") + } else { + modifiedCiPipeline.ScanEnabled = baseCiConfig.ScanEnabled + modifiedCiPipeline, err = impl.ciCdPipelineOrchestrator.PatchMaterialValue(modifiedCiPipeline, baseCiConfig.UserId, pipeline) + if err != nil { + return nil, err + } + baseCiConfig.CiPipelines = append(baseCiConfig.CiPipelines, modifiedCiPipeline) + return baseCiConfig, err + } + +} + +func (impl *CiPipelineConfigServiceImpl) addpipelineToTemplate(createRequest *bean.CiConfigRequest) (resp *bean.CiConfigRequest, err error) { + + if createRequest.AppWorkflowId == 0 { + // create workflow + wf := &appWorkflow.AppWorkflow{ + Name: fmt.Sprintf("wf-%d-%s", createRequest.AppId, util2.Generate(4)), + AppId: createRequest.AppId, + Active: true, + AuditLog: sql.AuditLog{ + CreatedOn: time.Now(), + UpdatedOn: time.Now(), + CreatedBy: createRequest.UserId, + UpdatedBy: createRequest.UserId, + }, + } + savedAppWf, err := impl.appWorkflowRepository.SaveAppWorkflow(wf) + if err != nil { + impl.logger.Errorw("err", err) + return nil, err + } + // workflow creation ends + createRequest.AppWorkflowId = savedAppWf.Id + } + //single ci in same wf validation + workflowMapping, err := impl.appWorkflowRepository.FindWFCIMappingByWorkflowId(createRequest.AppWorkflowId) + if err != nil && err != pg.ErrNoRows { + impl.logger.Errorw("error in fetching workflow mapping for ci validation", "err", err) + return nil, err + } + if len(workflowMapping) > 0 { + return nil, &util.ApiError{ + InternalMessage: "pipeline already exists", + UserDetailMessage: fmt.Sprintf("pipeline already exists in workflow"), + UserMessage: fmt.Sprintf("pipeline already exists in workflow")} + } + + //pipeline name validation + var pipelineNames []string + for _, pipeline := range createRequest.CiPipelines { + pipelineNames = append(pipelineNames, pipeline.Name) + } + if err != nil { + impl.logger.Errorw("error in creating pipeline group", "err", err) + return nil, err + } + createRequest, err = impl.ciCdPipelineOrchestrator.CreateCiConf(createRequest, createRequest.Id) + if err != nil { + return nil, err + } + return createRequest, err +} + +func (impl *CiPipelineConfigServiceImpl) buildResponses() []bean.ResponseSchemaObject { + responseSchemaObjects := make([]bean.ResponseSchemaObject, 0) + schema := make(map[string]interface{}) + schema["code"] = &bean.SchemaObject{Description: "http status code", DataType: "integer", Example: "200,400,401", Optional: false} + schema["result"] = &bean.SchemaObject{Description: "api response", DataType: "string", Example: "url", Optional: true} + schema["status"] = &bean.SchemaObject{Description: "api response status", DataType: "string", Example: "url", Optional: true} + + error := make(map[string]interface{}) + error["code"] = &bean.SchemaObject{Description: "http status code", DataType: "integer", Example: "200,400,401", Optional: true} + error["userMessage"] = &bean.SchemaObject{Description: "api error user message", DataType: "string", Example: "message", Optional: true} + schema["error"] = &bean.SchemaObject{Description: "api error", DataType: "object", Example: "{}", Optional: true, Child: error} + description200 := bean.ResponseDescriptionSchemaObject{ + Description: "success http api response", + ExampleValue: bean.ExampleValueDto{ + Code: 200, + Result: "api response result", + }, + Schema: schema, + } + response200 := bean.ResponseSchemaObject{ + Description: description200, + Code: "200", + } + badReq := bean.ErrorDto{ + Code: 400, + UserMessage: "Bad request", + } + description400 := bean.ResponseDescriptionSchemaObject{ + Description: "bad http request api response", + ExampleValue: bean.ExampleValueDto{ + Code: 400, + Errors: []bean.ErrorDto{badReq}, + }, + Schema: schema, + } + + response400 := bean.ResponseSchemaObject{ + Description: description400, + Code: "400", + } + description401 := bean.ResponseDescriptionSchemaObject{ + Description: "unauthorized http api response", + ExampleValue: bean.ExampleValueDto{ + Code: 401, + Result: "Unauthorized", + }, + Schema: schema, + } + response401 := bean.ResponseSchemaObject{ + Description: description401, + Code: "401", + } + responseSchemaObjects = append(responseSchemaObjects, response200) + responseSchemaObjects = append(responseSchemaObjects, response400) + responseSchemaObjects = append(responseSchemaObjects, response401) + return responseSchemaObjects +} + +func (impl *CiPipelineConfigServiceImpl) buildPayloadOption() []bean.PayloadOptionObject { + payloadOption := make([]bean.PayloadOptionObject, 0) + payloadOption = append(payloadOption, bean.PayloadOptionObject{ + Key: "dockerImage", + PayloadKey: []string{"dockerImage"}, + Label: "Container image tag", + Mandatory: true, + }) + + payloadOption = append(payloadOption, bean.PayloadOptionObject{ + Key: "commitHash", + PayloadKey: []string{"ciProjectDetails.commitHash"}, + Label: "Commit hash", + Mandatory: false, + }) + payloadOption = append(payloadOption, bean.PayloadOptionObject{ + Key: "message", + PayloadKey: []string{"ciProjectDetails.message"}, + Label: "Commit message", + Mandatory: false, + }) + payloadOption = append(payloadOption, bean.PayloadOptionObject{ + Key: "author", + PayloadKey: []string{"ciProjectDetails.author"}, + Label: "Author", + Mandatory: false, + }) + payloadOption = append(payloadOption, bean.PayloadOptionObject{ + Key: "commitTime", + PayloadKey: []string{"ciProjectDetails.commitTime"}, + Label: "Date & time of commit", + Mandatory: false, + }) + return payloadOption +} + +func (impl *CiPipelineConfigServiceImpl) buildExternalCiWebhookSchema() map[string]interface{} { + schema := make(map[string]interface{}) + schema["dockerImage"] = &bean.SchemaObject{Description: "docker image created for your application (Eg. quay.io/devtron/test:da3ba325-161-467)", DataType: "String", Example: "test-docker-repo/test:b150cc81-5-20", Optional: false} + //schema["digest"] = &bean.SchemaObject{Description: "docker image sha1 digest", DataType: "String", Example: "sha256:94180dead8336237430e848ef8145f060b51", Optional: true} + //schema["materialType"] = &bean.SchemaObject{Description: "git", DataType: "String", Example: "git", Optional: true} + + ciProjectDetails := make([]map[string]interface{}, 0) + ciProjectDetail := make(map[string]interface{}) + ciProjectDetail["commitHash"] = &bean.SchemaObject{Description: "Hash of git commit used to build the image (Eg. 4bd84gba5ebdd6b1937ffd6c0734c2ad52ede782)", DataType: "String", Example: "dg46f67559dbsdfdfdfdsfba47901caf47f8b7e", Optional: true} + ciProjectDetail["commitTime"] = &bean.SchemaObject{Description: "Time at which the code was committed to git (Eg. 2022-11-12T12:12:00)", DataType: "String", Example: "2022-11-12T12:12:00", Optional: true} + ciProjectDetail["message"] = &bean.SchemaObject{Description: "Message provided during code commit (Eg. This is a sample commit message)", DataType: "String", Example: "commit message", Optional: true} + ciProjectDetail["author"] = &bean.SchemaObject{Description: "Name or email id of the user who has done git commit (Eg. John Doe, johndoe@company.com)", DataType: "String", Example: "Devtron User", Optional: true} + ciProjectDetails = append(ciProjectDetails, ciProjectDetail) + + schema["ciProjectDetails"] = &bean.SchemaObject{Description: "Git commit details used to build the image", DataType: "Array", Example: "[{}]", Optional: true, Child: ciProjectDetails} + return schema +} + +func (impl *CiPipelineConfigServiceImpl) getCiTemplateVariables(appId int) (ciConfig *bean.CiConfigRequest, err error) { + ciTemplateBean, err := impl.ciTemplateService.FindByAppId(appId) + if err != nil && !errors.IsNotFound(err) { + impl.logger.Errorw("error in fetching ci pipeline", "appId", appId, "err", err) + return nil, err + } + if errors.IsNotFound(err) { + impl.logger.Debugw("no ci pipeline exists", "appId", appId, "err", err) + err = &util.ApiError{Code: "404", HttpStatusCode: 200, UserMessage: "no ci pipeline exists"} + return nil, err + } + template := ciTemplateBean.CiTemplate + + gitMaterials, err := impl.materialRepo.FindByAppId(appId) + if err != nil && err != pg.ErrNoRows { + impl.logger.Errorw("error in fetching git materials", "appId", appId, "err", err) + return nil, err + } + if err == pg.ErrNoRows { + impl.logger.Debugw(" no git materials exists", "appId", appId, "err", err) + err = &util.ApiError{Code: "404", HttpStatusCode: 200, UserMessage: "no git materials exists"} + return nil, err + } + + var materials []bean.Material + for _, g := range gitMaterials { + m := bean.Material{ + GitMaterialId: g.Id, + MaterialName: g.Name[strings.Index(g.Name, "-")+1:], + } + materials = append(materials, m) + } + + var regHost string + var templateDockerRegistryId string + dockerRegistry := template.DockerRegistry + if dockerRegistry != nil { + regHost, err = dockerRegistry.GetRegistryLocation() + if err != nil { + impl.logger.Errorw("invalid reg url", "err", err) + return nil, err + } + templateDockerRegistryId = dockerRegistry.Id + } + ciConfig = &bean.CiConfigRequest{ + Id: template.Id, + AppId: template.AppId, + AppName: template.App.AppName, + DockerRepository: template.DockerRepository, + DockerRegistryUrl: regHost, + CiBuildConfig: ciTemplateBean.CiBuildConfig, + Version: template.Version, + CiTemplateName: template.TemplateName, + Materials: materials, + UpdatedOn: template.UpdatedOn, + UpdatedBy: template.UpdatedBy, + CreatedBy: template.CreatedBy, + CreatedOn: template.CreatedOn, + CiGitMaterialId: template.GitMaterialId, + DockerRegistry: templateDockerRegistryId, + } + if dockerRegistry != nil { + ciConfig.DockerRegistry = dockerRegistry.Id + } + return ciConfig, err +} + +func (impl *CiPipelineConfigServiceImpl) GetCiPipeline(appId int) (ciConfig *bean.CiConfigRequest, err error) { ciConfig, err = impl.getCiTemplateVariables(appId) if err != nil { impl.logger.Debugw("error in fetching ci pipeline", "appId", appId, "err", err) @@ -274,7 +694,7 @@ func (impl *PipelineBuilderImpl) GetCiPipeline(appId int) (ciConfig *bean.CiConf return ciConfig, err } -func (impl *PipelineBuilderImpl) GetCiPipelineById(pipelineId int) (ciPipeline *bean.CiPipeline, err error) { +func (impl *CiPipelineConfigServiceImpl) GetCiPipelineById(pipelineId int) (ciPipeline *bean.CiPipeline, err error) { pipeline, err := impl.ciPipelineRepository.FindById(pipelineId) if err != nil && !util.IsErrNoRows(err) { impl.logger.Errorw("error in fetching ci pipeline", "pipelineId", pipelineId, "err", err) @@ -414,7 +834,7 @@ func (impl *PipelineBuilderImpl) GetCiPipelineById(pipelineId int) (ciPipeline * return ciPipeline, err } -func (impl *PipelineBuilderImpl) GetTriggerViewCiPipeline(appId int) (*bean.TriggerViewCiConfig, error) { +func (impl *CiPipelineConfigServiceImpl) GetTriggerViewCiPipeline(appId int) (*bean.TriggerViewCiConfig, error) { triggerViewCiConfig := &bean.TriggerViewCiConfig{} @@ -500,7 +920,7 @@ func (impl *PipelineBuilderImpl) GetTriggerViewCiPipeline(appId int) (*bean.Trig return triggerViewCiConfig, nil } -func (impl *PipelineBuilderImpl) GetExternalCi(appId int) (ciConfig []*bean.ExternalCiConfig, err error) { +func (impl *CiPipelineConfigServiceImpl) GetExternalCi(appId int) (ciConfig []*bean.ExternalCiConfig, err error) { externalCiPipelines, err := impl.ciPipelineRepository.FindExternalCiByAppId(appId) if err != nil && !util.IsErrNoRows(err) { impl.logger.Errorw("error in fetching external ci", "appId", appId, "err", err) @@ -626,7 +1046,7 @@ func (impl *PipelineBuilderImpl) GetExternalCi(appId int) (ciConfig []*bean.Exte return externalCiConfigs, err } -func (impl *PipelineBuilderImpl) GetExternalCiById(appId int, externalCiId int) (ciConfig *bean.ExternalCiConfig, err error) { +func (impl *CiPipelineConfigServiceImpl) GetExternalCiById(appId int, externalCiId int) (ciConfig *bean.ExternalCiConfig, err error) { externalCiPipeline, err := impl.ciPipelineRepository.FindExternalCiById(externalCiId) if err != nil && !util.IsErrNoRows(err) { @@ -706,7 +1126,7 @@ func (impl *PipelineBuilderImpl) GetExternalCiById(appId int, externalCiId int) return externalCiConfig, err } -func (impl PipelineBuilderImpl) UpdateCiTemplate(updateRequest *bean.CiConfigRequest) (*bean.CiConfigRequest, error) { +func (impl *CiPipelineConfigServiceImpl) UpdateCiTemplate(updateRequest *bean.CiConfigRequest) (*bean.CiConfigRequest, error) { originalCiConf, err := impl.getCiTemplateVariables(updateRequest.AppId) if err != nil { impl.logger.Errorw("error in fetching original ciCdConfig for update", "appId", updateRequest.Id, "err", err) @@ -845,7 +1265,7 @@ func (impl PipelineBuilderImpl) UpdateCiTemplate(updateRequest *bean.CiConfigReq return originalCiConf, nil } -func (impl *PipelineBuilderImpl) PatchCiPipeline(request *bean.CiPatchRequest) (ciConfig *bean.CiConfigRequest, err error) { +func (impl *CiPipelineConfigServiceImpl) PatchCiPipeline(request *bean.CiPatchRequest) (ciConfig *bean.CiConfigRequest, err error) { ciConfig, err = impl.getCiTemplateVariables(request.AppId) if err != nil { impl.logger.Errorw("err in fetching template for pipeline patch, ", "err", err, "appId", request.AppId) @@ -906,7 +1326,7 @@ func (impl *PipelineBuilderImpl) PatchCiPipeline(request *bean.CiPatchRequest) ( } -func (impl PipelineBuilderImpl) CreateCiPipeline(createRequest *bean.CiConfigRequest) (*bean.PipelineCreateResponse, error) { +func (impl *CiPipelineConfigServiceImpl) CreateCiPipeline(createRequest *bean.CiConfigRequest) (*bean.PipelineCreateResponse, error) { impl.logger.Debugw("pipeline create request received", "req", createRequest) //-----------fetch data @@ -1016,7 +1436,7 @@ func (impl PipelineBuilderImpl) CreateCiPipeline(createRequest *bean.CiConfigReq return createRes, nil } -func (impl *PipelineBuilderImpl) GetCiPipelineMin(appId int, envIds []int) ([]*bean.CiPipelineMin, error) { +func (impl *CiPipelineConfigServiceImpl) GetCiPipelineMin(appId int, envIds []int) ([]*bean.CiPipelineMin, error) { pipelines := make([]*pipelineConfig.CiPipeline, 0) var err error if len(envIds) > 0 { @@ -1072,7 +1492,7 @@ func (impl *PipelineBuilderImpl) GetCiPipelineMin(appId int, envIds []int) ([]*b return ciPipelineResp, err } -func (impl *PipelineBuilderImpl) PatchRegexCiPipeline(request *bean.CiRegexPatchRequest) (err error) { +func (impl *CiPipelineConfigServiceImpl) PatchRegexCiPipeline(request *bean.CiRegexPatchRequest) (err error) { var materials []*pipelineConfig.CiPipelineMaterial for _, material := range request.CiPipelineMaterial { materialDbObject, err := impl.ciPipelineMaterialRepository.GetById(material.Id) @@ -1125,7 +1545,7 @@ func (impl *PipelineBuilderImpl) PatchRegexCiPipeline(request *bean.CiRegexPatch return nil } -func (impl PipelineBuilderImpl) GetCiPipelineByEnvironment(request resourceGroup2.ResourceGroupingRequest) ([]*bean.CiConfigRequest, error) { +func (impl *CiPipelineConfigServiceImpl) GetCiPipelineByEnvironment(request resourceGroup2.ResourceGroupingRequest) ([]*bean.CiConfigRequest, error) { ciPipelinesConfigByApps := make([]*bean.CiConfigRequest, 0) _, span := otel.Tracer("orchestrator").Start(request.Ctx, "ciHandler.ResourceGroupingCiPipelinesAuthorization") var cdPipelines []*pipelineConfig.Pipeline @@ -1325,7 +1745,7 @@ func (impl PipelineBuilderImpl) GetCiPipelineByEnvironment(request resourceGroup return ciPipelinesConfigByApps, err } -func (impl PipelineBuilderImpl) GetCiPipelineByEnvironmentMin(request resourceGroup2.ResourceGroupingRequest) ([]*bean.CiPipelineMinResponse, error) { +func (impl *CiPipelineConfigServiceImpl) GetCiPipelineByEnvironmentMin(request resourceGroup2.ResourceGroupingRequest) ([]*bean.CiPipelineMinResponse, error) { results := make([]*bean.CiPipelineMinResponse, 0) var cdPipelines []*pipelineConfig.Pipeline var err error @@ -1409,7 +1829,7 @@ func (impl PipelineBuilderImpl) GetCiPipelineByEnvironmentMin(request resourceGr return results, err } -func (impl PipelineBuilderImpl) GetExternalCiByEnvironment(request resourceGroup2.ResourceGroupingRequest) (ciConfig []*bean.ExternalCiConfig, err error) { +func (impl *CiPipelineConfigServiceImpl) GetExternalCiByEnvironment(request resourceGroup2.ResourceGroupingRequest) (ciConfig []*bean.ExternalCiConfig, err error) { _, span := otel.Tracer("orchestrator").Start(request.Ctx, "ciHandler.authorizationExternalCiForResourceGrouping") externalCiConfigs := make([]*bean.ExternalCiConfig, 0) var cdPipelines []*pipelineConfig.Pipeline @@ -1577,7 +1997,7 @@ func (impl PipelineBuilderImpl) GetExternalCiByEnvironment(request resourceGroup return externalCiConfigs, err } -func (impl *PipelineBuilderImpl) DeleteCiPipeline(request *bean.CiPatchRequest) (*bean.CiPipeline, error) { +func (impl *CiPipelineConfigServiceImpl) DeleteCiPipeline(request *bean.CiPatchRequest) (*bean.CiPipeline, error) { ciPipelineId := request.CiPipeline.Id //wf validation workflowMapping, err := impl.appWorkflowRepository.FindWFCDMappingByCIPipelineId(ciPipelineId) @@ -1680,7 +2100,7 @@ func (impl *PipelineBuilderImpl) DeleteMaterial(request *bean.UpdateMaterialDTO) //pipelines are present, in this case we will check if this material is used in docker config //if it is used, then we won't delete ciTemplateBean, err := impl.ciTemplateService.FindByAppId(request.AppId) - if err != nil && err == errors2.NotFoundf(err.Error()) { + if err != nil && err == errors.NotFoundf(err.Error()) { impl.logger.Errorw("err in getting docker registry", "appId", request.AppId, "err", err) return err } @@ -1780,7 +2200,7 @@ func (impl *PipelineBuilderImpl) GetMaterialsForAppId(appId int) []*bean.GitMate } ciTemplateBean, err := impl.ciTemplateService.FindByAppId(appId) - if err != nil && err != errors2.NotFoundf(err.Error()) { + if err != nil && err != errors.NotFoundf(err.Error()) { impl.logger.Errorw("err in getting ci-template", "appId", appId, "err", err) } diff --git a/pkg/pipeline/PipelineBuilder.go b/pkg/pipeline/PipelineBuilder.go index e401f89062..69a4a7d2da 100644 --- a/pkg/pipeline/PipelineBuilder.go +++ b/pkg/pipeline/PipelineBuilder.go @@ -217,6 +217,7 @@ type PipelineBuilderImpl struct { imageTaggingService ImageTaggingService variableEntityMappingService variables.VariableEntityMappingService variableTemplateParser parsers.VariableTemplateParser + CiPipelineConfigService } func NewPipelineBuilderImpl(logger *zap.SugaredLogger, @@ -273,7 +274,8 @@ func NewPipelineBuilderImpl(logger *zap.SugaredLogger, attributesRepository repository.AttributesRepository, imageTaggingService ImageTaggingService, variableEntityMappingService variables.VariableEntityMappingService, - variableTemplateParser parsers.VariableTemplateParser) *PipelineBuilderImpl { + variableTemplateParser parsers.VariableTemplateParser, + ciPipelineConfigService CiPipelineConfigService) *PipelineBuilderImpl { securityConfig := &SecurityConfig{} err := env.Parse(securityConfig) @@ -345,6 +347,7 @@ func NewPipelineBuilderImpl(logger *zap.SugaredLogger, imageTaggingService: imageTaggingService, variableEntityMappingService: variableEntityMappingService, variableTemplateParser: variableTemplateParser, + CiPipelineConfigService: ciPipelineConfigService, } } @@ -531,154 +534,6 @@ func (impl *PipelineBuilderImpl) FindAppsByTeamName(teamName string) ([]AppBean, return appsRes, err } -func (impl *PipelineBuilderImpl) getDefaultArtifactStore(id string) (store *dockerRegistryRepository.DockerArtifactStore, err error) { - if id == "" { - impl.logger.Debugw("docker repo is empty adding default repo") - store, err = impl.dockerArtifactStoreRepository.FindActiveDefaultStore() - - } else { - store, err = impl.dockerArtifactStoreRepository.FindOne(id) - } - return -} - -func (impl *PipelineBuilderImpl) getCiTemplateVariables(appId int) (ciConfig *bean.CiConfigRequest, err error) { - ciTemplateBean, err := impl.ciTemplateService.FindByAppId(appId) - if err != nil && !errors.IsNotFound(err) { - impl.logger.Errorw("error in fetching ci pipeline", "appId", appId, "err", err) - return nil, err - } - if errors.IsNotFound(err) { - impl.logger.Debugw("no ci pipeline exists", "appId", appId, "err", err) - err = &util.ApiError{Code: "404", HttpStatusCode: 200, UserMessage: "no ci pipeline exists"} - return nil, err - } - template := ciTemplateBean.CiTemplate - - gitMaterials, err := impl.materialRepo.FindByAppId(appId) - if err != nil && err != pg.ErrNoRows { - impl.logger.Errorw("error in fetching git materials", "appId", appId, "err", err) - return nil, err - } - if err == pg.ErrNoRows { - impl.logger.Debugw(" no git materials exists", "appId", appId, "err", err) - err = &util.ApiError{Code: "404", HttpStatusCode: 200, UserMessage: "no git materials exists"} - return nil, err - } - - var materials []bean.Material - for _, g := range gitMaterials { - m := bean.Material{ - GitMaterialId: g.Id, - MaterialName: g.Name[strings.Index(g.Name, "-")+1:], - } - materials = append(materials, m) - } - - var regHost string - var templateDockerRegistryId string - dockerRegistry := template.DockerRegistry - if dockerRegistry != nil { - regHost, err = dockerRegistry.GetRegistryLocation() - if err != nil { - impl.logger.Errorw("invalid reg url", "err", err) - return nil, err - } - templateDockerRegistryId = dockerRegistry.Id - } - ciConfig = &bean.CiConfigRequest{ - Id: template.Id, - AppId: template.AppId, - AppName: template.App.AppName, - DockerRepository: template.DockerRepository, - DockerRegistryUrl: regHost, - CiBuildConfig: ciTemplateBean.CiBuildConfig, - Version: template.Version, - CiTemplateName: template.TemplateName, - Materials: materials, - UpdatedOn: template.UpdatedOn, - UpdatedBy: template.UpdatedBy, - CreatedBy: template.CreatedBy, - CreatedOn: template.CreatedOn, - CiGitMaterialId: template.GitMaterialId, - DockerRegistry: templateDockerRegistryId, - } - if dockerRegistry != nil { - ciConfig.DockerRegistry = dockerRegistry.Id - } - return ciConfig, err -} - -func (impl *PipelineBuilderImpl) getCiTemplateVariablesByAppIds(appIds []int) (map[int]*bean.CiConfigRequest, error) { - ciConfigMap := make(map[int]*bean.CiConfigRequest) - ciTemplateMap, err := impl.ciTemplateService.FindByAppIds(appIds) - if err != nil && !errors.IsNotFound(err) { - impl.logger.Errorw("error in fetching ci pipeline", "appIds", appIds, "err", err) - return nil, err - } - if errors.IsNotFound(err) { - impl.logger.Debugw("no ci pipeline exists", "appIds", appIds, "err", err) - err = &util.ApiError{Code: "404", HttpStatusCode: 200, UserMessage: "no ci pipeline exists"} - return nil, err - } - gitMaterialsMap := make(map[int][]*pipelineConfig.GitMaterial) - allGitMaterials, err := impl.materialRepo.FindByAppIds(appIds) - if err != nil && err != pg.ErrNoRows { - impl.logger.Errorw("error in fetching git materials", "appIds", appIds, "err", err) - return nil, err - } - if err == pg.ErrNoRows { - impl.logger.Debugw(" no git materials exists", "appIds", appIds, "err", err) - err = &util.ApiError{Code: "404", HttpStatusCode: 200, UserMessage: "no git materials exists"} - return nil, err - } - for _, gitMaterial := range allGitMaterials { - gitMaterialsMap[gitMaterial.AppId] = append(gitMaterialsMap[gitMaterial.AppId], gitMaterial) - } - for _, ciTemplate := range ciTemplateMap { - template := ciTemplate.CiTemplate - var materials []bean.Material - gitMaterials := gitMaterialsMap[ciTemplate.CiTemplate.AppId] - for _, g := range gitMaterials { - m := bean.Material{ - GitMaterialId: g.Id, - MaterialName: g.Name[strings.Index(g.Name, "-")+1:], - } - materials = append(materials, m) - } - - var regHost string - dockerRegistry := template.DockerRegistry - if dockerRegistry != nil { - regHost, err = dockerRegistry.GetRegistryLocation() - if err != nil { - impl.logger.Errorw("invalid reg url", "err", err) - return nil, err - } - } - ciConfig := &bean.CiConfigRequest{ - Id: template.Id, - AppId: template.AppId, - AppName: template.App.AppName, - DockerRepository: template.DockerRepository, - DockerRegistryUrl: regHost, - CiBuildConfig: ciTemplate.CiBuildConfig, - Version: template.Version, - CiTemplateName: template.TemplateName, - Materials: materials, - //UpdatedOn: template.UpdatedOn, - //UpdatedBy: template.UpdatedBy, - //CreatedBy: template.CreatedBy, - //CreatedOn: template.CreatedOn, - } - if dockerRegistry != nil { - ciConfig.DockerRegistry = dockerRegistry.Id - } - ciConfigMap[template.AppId] = ciConfig - } - return ciConfigMap, err -} - func (impl *PipelineBuilderImpl) getGitMaterialsForApp(appId int) ([]*bean.GitMaterial, error) { materials, err := impl.materialRepo.FindByAppId(appId) if err != nil { @@ -724,58 +579,6 @@ func (impl *PipelineBuilderImpl) getGitMaterialsForApp(appId int) ([]*bean.GitMa return gitMaterials, nil } -func (impl *PipelineBuilderImpl) addpipelineToTemplate(createRequest *bean.CiConfigRequest) (resp *bean.CiConfigRequest, err error) { - - if createRequest.AppWorkflowId == 0 { - // create workflow - wf := &appWorkflow.AppWorkflow{ - Name: fmt.Sprintf("wf-%d-%s", createRequest.AppId, util2.Generate(4)), - AppId: createRequest.AppId, - Active: true, - AuditLog: sql.AuditLog{ - CreatedOn: time.Now(), - UpdatedOn: time.Now(), - CreatedBy: createRequest.UserId, - UpdatedBy: createRequest.UserId, - }, - } - savedAppWf, err := impl.appWorkflowRepository.SaveAppWorkflow(wf) - if err != nil { - impl.logger.Errorw("err", err) - return nil, err - } - // workflow creation ends - createRequest.AppWorkflowId = savedAppWf.Id - } - //single ci in same wf validation - workflowMapping, err := impl.appWorkflowRepository.FindWFCIMappingByWorkflowId(createRequest.AppWorkflowId) - if err != nil && err != pg.ErrNoRows { - impl.logger.Errorw("error in fetching workflow mapping for ci validation", "err", err) - return nil, err - } - if len(workflowMapping) > 0 { - return nil, &util.ApiError{ - InternalMessage: "pipeline already exists", - UserDetailMessage: fmt.Sprintf("pipeline already exists in workflow"), - UserMessage: fmt.Sprintf("pipeline already exists in workflow")} - } - - //pipeline name validation - var pipelineNames []string - for _, pipeline := range createRequest.CiPipelines { - pipelineNames = append(pipelineNames, pipeline.Name) - } - if err != nil { - impl.logger.Errorw("error in creating pipeline group", "err", err) - return nil, err - } - createRequest, err = impl.ciCdPipelineOrchestrator.CreateCiConf(createRequest, createRequest.Id) - if err != nil { - return nil, err - } - return createRequest, err -} - func getPatchStatus(err error) bean.CiPatchStatus { if err != nil { if err.Error() == string(bean.CI_PATCH_NOT_AUTHORIZED_MESSAGE) { @@ -793,37 +596,6 @@ func getPatchMessage(err error) bean.CiPatchMessage { return "" } -func (impl *PipelineBuilderImpl) patchCiPipelineUpdateSource(baseCiConfig *bean.CiConfigRequest, modifiedCiPipeline *bean.CiPipeline) (ciConfig *bean.CiConfigRequest, err error) { - - pipeline, err := impl.ciPipelineRepository.FindById(modifiedCiPipeline.Id) - if err != nil { - impl.logger.Errorw("error in fetching pipeline", "id", modifiedCiPipeline.Id, "err", err) - return nil, err - } - - cannotUpdate := false - for _, material := range pipeline.CiPipelineMaterials { - if material.ScmId != "" { - cannotUpdate = true - } - } - - if cannotUpdate { - //scm plugin material change scm object - //material.ScmName - return nil, fmt.Errorf("update of plugin scm material not supported") - } else { - modifiedCiPipeline.ScanEnabled = baseCiConfig.ScanEnabled - modifiedCiPipeline, err = impl.ciCdPipelineOrchestrator.PatchMaterialValue(modifiedCiPipeline, baseCiConfig.UserId, pipeline) - if err != nil { - return nil, err - } - baseCiConfig.CiPipelines = append(baseCiConfig.CiPipelines, modifiedCiPipeline) - return baseCiConfig, err - } - -} - func (impl *PipelineBuilderImpl) ValidateCDPipelineRequest(pipelineCreateRequest *bean.CdPipelines, isGitOpsConfigured, haveAtleastOneGitOps bool) (bool, error) { if isGitOpsConfigured == false && haveAtleastOneGitOps { @@ -1835,118 +1607,6 @@ func (impl *PipelineBuilderImpl) BulkDeleteCdPipelines(impactedPipelines []*pipe } -func (impl *PipelineBuilderImpl) buildExternalCiWebhookSchema() map[string]interface{} { - schema := make(map[string]interface{}) - schema["dockerImage"] = &bean.SchemaObject{Description: "docker image created for your application (Eg. quay.io/devtron/test:da3ba325-161-467)", DataType: "String", Example: "test-docker-repo/test:b150cc81-5-20", Optional: false} - //schema["digest"] = &bean.SchemaObject{Description: "docker image sha1 digest", DataType: "String", Example: "sha256:94180dead8336237430e848ef8145f060b51", Optional: true} - //schema["materialType"] = &bean.SchemaObject{Description: "git", DataType: "String", Example: "git", Optional: true} - - ciProjectDetails := make([]map[string]interface{}, 0) - ciProjectDetail := make(map[string]interface{}) - ciProjectDetail["commitHash"] = &bean.SchemaObject{Description: "Hash of git commit used to build the image (Eg. 4bd84gba5ebdd6b1937ffd6c0734c2ad52ede782)", DataType: "String", Example: "dg46f67559dbsdfdfdfdsfba47901caf47f8b7e", Optional: true} - ciProjectDetail["commitTime"] = &bean.SchemaObject{Description: "Time at which the code was committed to git (Eg. 2022-11-12T12:12:00)", DataType: "String", Example: "2022-11-12T12:12:00", Optional: true} - ciProjectDetail["message"] = &bean.SchemaObject{Description: "Message provided during code commit (Eg. This is a sample commit message)", DataType: "String", Example: "commit message", Optional: true} - ciProjectDetail["author"] = &bean.SchemaObject{Description: "Name or email id of the user who has done git commit (Eg. John Doe, johndoe@company.com)", DataType: "String", Example: "Devtron User", Optional: true} - ciProjectDetails = append(ciProjectDetails, ciProjectDetail) - - schema["ciProjectDetails"] = &bean.SchemaObject{Description: "Git commit details used to build the image", DataType: "Array", Example: "[{}]", Optional: true, Child: ciProjectDetails} - return schema -} - -func (impl *PipelineBuilderImpl) buildPayloadOption() []bean.PayloadOptionObject { - payloadOption := make([]bean.PayloadOptionObject, 0) - payloadOption = append(payloadOption, bean.PayloadOptionObject{ - Key: "dockerImage", - PayloadKey: []string{"dockerImage"}, - Label: "Container image tag", - Mandatory: true, - }) - - payloadOption = append(payloadOption, bean.PayloadOptionObject{ - Key: "commitHash", - PayloadKey: []string{"ciProjectDetails.commitHash"}, - Label: "Commit hash", - Mandatory: false, - }) - payloadOption = append(payloadOption, bean.PayloadOptionObject{ - Key: "message", - PayloadKey: []string{"ciProjectDetails.message"}, - Label: "Commit message", - Mandatory: false, - }) - payloadOption = append(payloadOption, bean.PayloadOptionObject{ - Key: "author", - PayloadKey: []string{"ciProjectDetails.author"}, - Label: "Author", - Mandatory: false, - }) - payloadOption = append(payloadOption, bean.PayloadOptionObject{ - Key: "commitTime", - PayloadKey: []string{"ciProjectDetails.commitTime"}, - Label: "Date & time of commit", - Mandatory: false, - }) - return payloadOption -} - -func (impl *PipelineBuilderImpl) buildResponses() []bean.ResponseSchemaObject { - responseSchemaObjects := make([]bean.ResponseSchemaObject, 0) - schema := make(map[string]interface{}) - schema["code"] = &bean.SchemaObject{Description: "http status code", DataType: "integer", Example: "200,400,401", Optional: false} - schema["result"] = &bean.SchemaObject{Description: "api response", DataType: "string", Example: "url", Optional: true} - schema["status"] = &bean.SchemaObject{Description: "api response status", DataType: "string", Example: "url", Optional: true} - - error := make(map[string]interface{}) - error["code"] = &bean.SchemaObject{Description: "http status code", DataType: "integer", Example: "200,400,401", Optional: true} - error["userMessage"] = &bean.SchemaObject{Description: "api error user message", DataType: "string", Example: "message", Optional: true} - schema["error"] = &bean.SchemaObject{Description: "api error", DataType: "object", Example: "{}", Optional: true, Child: error} - description200 := bean.ResponseDescriptionSchemaObject{ - Description: "success http api response", - ExampleValue: bean.ExampleValueDto{ - Code: 200, - Result: "api response result", - }, - Schema: schema, - } - response200 := bean.ResponseSchemaObject{ - Description: description200, - Code: "200", - } - badReq := bean.ErrorDto{ - Code: 400, - UserMessage: "Bad request", - } - description400 := bean.ResponseDescriptionSchemaObject{ - Description: "bad http request api response", - ExampleValue: bean.ExampleValueDto{ - Code: 400, - Errors: []bean.ErrorDto{badReq}, - }, - Schema: schema, - } - - response400 := bean.ResponseSchemaObject{ - Description: description400, - Code: "400", - } - description401 := bean.ResponseDescriptionSchemaObject{ - Description: "unauthorized http api response", - ExampleValue: bean.ExampleValueDto{ - Code: 401, - Result: "Unauthorized", - }, - Schema: schema, - } - response401 := bean.ResponseSchemaObject{ - Description: description401, - Code: "401", - } - responseSchemaObjects = append(responseSchemaObjects, response200) - responseSchemaObjects = append(responseSchemaObjects, response400) - responseSchemaObjects = append(responseSchemaObjects, response401) - return responseSchemaObjects -} - func checkAppReleaseNotExist(err error) bool { // RELEASE_NOT_EXIST check for helm App and NOT_FOUND check for argo app return strings.Contains(err.Error(), bean.NOT_FOUND) || strings.Contains(err.Error(), bean.RELEASE_NOT_EXIST) diff --git a/wire_gen.go b/wire_gen.go index 210fd0a157..44ca4f53dc 100644 --- a/wire_gen.go +++ b/wire_gen.go @@ -482,7 +482,8 @@ func InitializeApp() (*App, error) { chartDeploymentServiceImpl := util.NewChartDeploymentServiceImpl(sugaredLogger, repositoryServiceClientImpl) imageTaggingRepositoryImpl := repository13.NewImageTaggingRepositoryImpl(db) imageTaggingServiceImpl := pipeline.NewImageTaggingServiceImpl(imageTaggingRepositoryImpl, ciPipelineRepositoryImpl, pipelineRepositoryImpl, environmentRepositoryImpl, sugaredLogger) - pipelineBuilderImpl := pipeline.NewPipelineBuilderImpl(sugaredLogger, ciCdPipelineOrchestratorImpl, dockerArtifactStoreRepositoryImpl, materialRepositoryImpl, appRepositoryImpl, pipelineRepositoryImpl, propertiesConfigServiceImpl, ciTemplateRepositoryImpl, ciPipelineRepositoryImpl, applicationServiceClientImpl, chartRepositoryImpl, ciArtifactRepositoryImpl, ecrConfig, envConfigOverrideRepositoryImpl, environmentRepositoryImpl, clusterRepositoryImpl, pipelineConfigRepositoryImpl, utilMergeUtil, appWorkflowRepositoryImpl, ciCdConfig, cdWorkflowRepositoryImpl, appServiceImpl, imageScanResultRepositoryImpl, argoK8sClientImpl, gitFactory, attributesServiceImpl, acdAuthConfig, gitOpsConfigRepositoryImpl, pipelineStrategyHistoryServiceImpl, prePostCiScriptHistoryServiceImpl, prePostCdScriptHistoryServiceImpl, deploymentTemplateHistoryServiceImpl, appLevelMetricsRepositoryImpl, pipelineStageServiceImpl, chartRefRepositoryImpl, chartTemplateServiceImpl, chartServiceImpl, helmAppServiceImpl, deploymentGroupRepositoryImpl, ciPipelineMaterialRepositoryImpl, userServiceImpl, ciTemplateServiceImpl, ciTemplateOverrideRepositoryImpl, gitMaterialHistoryServiceImpl, ciTemplateHistoryServiceImpl, ciPipelineHistoryServiceImpl, globalStrategyMetadataRepositoryImpl, globalStrategyMetadataChartRefMappingRepositoryImpl, pipelineDeploymentServiceTypeConfig, appStatusRepositoryImpl, workflowDagExecutorImpl, enforcerUtilImpl, argoUserServiceImpl, ciWorkflowRepositoryImpl, resourceGroupServiceImpl, chartDeploymentServiceImpl, k8sUtil, attributesRepositoryImpl, imageTaggingServiceImpl, variableEntityMappingServiceImpl, variableTemplateParserImpl) + ciPipelineConfigServiceImpl := pipeline.NewCiPipelineConfigServiceImpl(sugaredLogger, ciCdPipelineOrchestratorImpl, dockerArtifactStoreRepositoryImpl, materialRepositoryImpl, appRepositoryImpl, pipelineRepositoryImpl, ciPipelineRepositoryImpl, ecrConfig, appWorkflowRepositoryImpl, ciCdConfig, attributesServiceImpl, pipelineStageServiceImpl, ciPipelineMaterialRepositoryImpl, ciTemplateServiceImpl, ciTemplateOverrideRepositoryImpl, ciTemplateHistoryServiceImpl, enforcerUtilImpl, ciWorkflowRepositoryImpl, resourceGroupServiceImpl) + pipelineBuilderImpl := pipeline.NewPipelineBuilderImpl(sugaredLogger, ciCdPipelineOrchestratorImpl, dockerArtifactStoreRepositoryImpl, materialRepositoryImpl, appRepositoryImpl, pipelineRepositoryImpl, propertiesConfigServiceImpl, ciTemplateRepositoryImpl, ciPipelineRepositoryImpl, applicationServiceClientImpl, chartRepositoryImpl, ciArtifactRepositoryImpl, ecrConfig, envConfigOverrideRepositoryImpl, environmentRepositoryImpl, clusterRepositoryImpl, pipelineConfigRepositoryImpl, utilMergeUtil, appWorkflowRepositoryImpl, ciCdConfig, cdWorkflowRepositoryImpl, appServiceImpl, imageScanResultRepositoryImpl, argoK8sClientImpl, gitFactory, attributesServiceImpl, acdAuthConfig, gitOpsConfigRepositoryImpl, pipelineStrategyHistoryServiceImpl, prePostCiScriptHistoryServiceImpl, prePostCdScriptHistoryServiceImpl, deploymentTemplateHistoryServiceImpl, appLevelMetricsRepositoryImpl, pipelineStageServiceImpl, chartRefRepositoryImpl, chartTemplateServiceImpl, chartServiceImpl, helmAppServiceImpl, deploymentGroupRepositoryImpl, ciPipelineMaterialRepositoryImpl, userServiceImpl, ciTemplateServiceImpl, ciTemplateOverrideRepositoryImpl, gitMaterialHistoryServiceImpl, ciTemplateHistoryServiceImpl, ciPipelineHistoryServiceImpl, globalStrategyMetadataRepositoryImpl, globalStrategyMetadataChartRefMappingRepositoryImpl, pipelineDeploymentServiceTypeConfig, appStatusRepositoryImpl, workflowDagExecutorImpl, enforcerUtilImpl, argoUserServiceImpl, ciWorkflowRepositoryImpl, resourceGroupServiceImpl, chartDeploymentServiceImpl, k8sUtil, attributesRepositoryImpl, imageTaggingServiceImpl, variableEntityMappingServiceImpl, variableTemplateParserImpl, ciPipelineConfigServiceImpl) dbMigrationServiceImpl := pipeline.NewDbMogrationService(sugaredLogger, dbMigrationConfigRepositoryImpl) ciServiceImpl := pipeline.NewCiServiceImpl(sugaredLogger, workflowServiceImpl, ciPipelineMaterialRepositoryImpl, ciWorkflowRepositoryImpl, eventRESTClientImpl, eventSimpleFactoryImpl, mergeUtil, ciPipelineRepositoryImpl, prePostCiScriptHistoryServiceImpl, pipelineStageServiceImpl, userServiceImpl, ciTemplateServiceImpl, appCrudOperationServiceImpl, environmentRepositoryImpl, appRepositoryImpl, variableSnapshotHistoryServiceImpl) ciLogServiceImpl, err := pipeline.NewCiLogServiceImpl(sugaredLogger, ciServiceImpl, k8sUtil)