Skip to content

Commit

Permalink
fix: app clone breaking if ci pipeline have same name (#4461)
Browse files Browse the repository at this point in the history
* wip: making name unique for app clone

* wip

* removing 500 code

* making pipeline name unique only for duplicate name

* making pipeline name unique only for duplicate name

* making pipeline name unique only for duplicate name

* making pipeline name unique only for duplicate name

* making pipeline name unique only for duplicate name

* wip

* removing comment

* removing app using db

* adding 400 error in create pipeline flow

* fix panic

* changing error handling
  • Loading branch information
iamayushm authored Dec 28, 2023
1 parent 51ad666 commit 6b596a8
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 124 deletions.
4 changes: 4 additions & 0 deletions api/restHandler/CoreAppRestHandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -1559,6 +1559,10 @@ func (handler CoreAppRestHandlerImpl) createWorkflows(ctx context.Context, appId
//Creating CI pipeline starts
ciPipeline, err := handler.createCiPipeline(appId, userId, workflowId, workflow.CiPipeline)
if err != nil {
if err.Error() == bean2.PIPELINE_NAME_ALREADY_EXISTS_ERROR {
handler.logger.Errorw("service err, DeleteAppWorkflow ", "err", err)
return err, http.StatusBadRequest
}
err1 := handler.appWorkflowService.DeleteAppWorkflow(workflowId, userId)
if err1 != nil {
handler.logger.Errorw("service err, DeleteAppWorkflow ")
Expand Down
5 changes: 5 additions & 0 deletions api/restHandler/app/BuildPipelineRestHandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,11 @@ func (handler PipelineConfigRestHandlerImpl) PatchCiPipelines(w http.ResponseWri
}
createResp, err := handler.pipelineBuilder.PatchCiPipeline(&patchRequest)
if err != nil {
if err.Error() == bean1.PIPELINE_NAME_ALREADY_EXISTS_ERROR {
handler.Logger.Errorw("service err, pipeline name already exist ", "err", err)
common.WriteJsonResp(w, err, nil, http.StatusBadRequest)
return
}
handler.Logger.Errorw("service err, PatchCiPipelines", "err", err, "PatchCiPipelines", patchRequest)
common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
return
Expand Down
262 changes: 139 additions & 123 deletions pkg/appClone/AppCloneService.go
Original file line number Diff line number Diff line change
Expand Up @@ -794,133 +794,149 @@ func (impl *AppCloneServiceImpl) CreateCiPipeline(req *cloneCiPipelineRequest) (
if err != nil {
return nil, err
}
for _, refCiPipeline := range refCiConfig.CiPipelines {
if refCiPipeline.Id == req.refCiPipelineId {
pipelineName := refCiPipeline.Name
if strings.HasPrefix(pipelineName, req.refAppName) {
pipelineName = strings.Replace(pipelineName, req.refAppName+"-ci-", "", 1)
}
var ciMaterilas []*bean.CiMaterial
for _, refCiMaterial := range refCiPipeline.CiMaterial {
//FIXME
gitMaterialId := req.gitMaterialMapping[refCiMaterial.GitMaterialId]
if refCiPipeline.ParentCiPipeline != 0 {
gitMaterialId = refCiMaterial.GitMaterialId
}
ciMaterial := &bean.CiMaterial{
GitMaterialId: gitMaterialId,
Id: 0,
Source: &bean.SourceTypeConfig{
Type: refCiMaterial.Source.Type,
Value: refCiMaterial.Source.Value,
Regex: refCiMaterial.Source.Regex,
},
}
ciMaterilas = append(ciMaterilas, ciMaterial)
}
var beforeDockerBuildScripts []*bean.CiScript
var afterDockerBuildScripts []*bean.CiScript

for _, script := range refCiPipeline.BeforeDockerBuildScripts {
ciScript := &bean.CiScript{
Id: 0,
Index: script.Index,
Name: script.Name,
Script: script.Script,
OutputLocation: script.OutputLocation,
}
beforeDockerBuildScripts = append(beforeDockerBuildScripts, ciScript)
}
for _, script := range refCiPipeline.AfterDockerBuildScripts {
ciScript := &bean.CiScript{
Id: 0,
Index: script.Index,
Name: script.Name,
Script: script.Script,
OutputLocation: script.OutputLocation,
}
afterDockerBuildScripts = append(afterDockerBuildScripts, ciScript)
}

//getting pre stage and post stage details
preStageDetail, postStageDetail, err := impl.pipelineStageService.GetCiPipelineStageDataDeepCopy(refCiPipeline.Id)
if err != nil {
impl.logger.Errorw("error in getting pre & post stage detail by ciPipelineId", "err", err, "ciPipelineId", refCiPipeline.Id)
return nil, err
}
ciPatchReq := &bean.CiPatchRequest{
CiPipeline: &bean.CiPipeline{
IsManual: refCiPipeline.IsManual,
DockerArgs: refCiPipeline.DockerArgs,
IsExternal: refCiPipeline.IsExternal,
ExternalCiConfig: bean.ExternalCiConfig{},
CiMaterial: ciMaterilas,
Name: pipelineName,
Id: 0,
Version: refCiPipeline.Version,
Active: refCiPipeline.Active,
Deleted: refCiPipeline.Deleted,
BeforeDockerBuild: refCiPipeline.BeforeDockerBuild,
AfterDockerBuild: refCiPipeline.AfterDockerBuild,
BeforeDockerBuildScripts: beforeDockerBuildScripts,
AfterDockerBuildScripts: afterDockerBuildScripts,
ParentCiPipeline: refCiPipeline.ParentCiPipeline,
IsDockerConfigOverridden: refCiPipeline.IsDockerConfigOverridden,
PreBuildStage: preStageDetail,
PostBuildStage: postStageDetail,
EnvironmentId: refCiPipeline.EnvironmentId,
ScanEnabled: refCiPipeline.ScanEnabled,
PipelineType: refCiPipeline.PipelineType,
},
AppId: req.appId,
Action: bean.CREATE,
AppWorkflowId: req.wfId,
UserId: req.userId,
IsCloneJob: true,
}
if refCiPipeline.EnvironmentId != 0 {
ciPatchReq.IsJob = true
}
if !refCiPipeline.IsExternal && refCiPipeline.IsDockerConfigOverridden {
//get template override
templateOverrideBean, err := impl.ciTemplateService.FindTemplateOverrideByCiPipelineId(refCiPipeline.Id)
if err != nil {
return nil, err
}
templateOverride := templateOverrideBean.CiTemplateOverride
ciBuildConfig := templateOverrideBean.CiBuildConfig
//getting new git material for this app
//gitMaterial, err := impl.materialRepository.FindByAppIdAndCheckoutPath(req.appId, templateOverride.GitMaterial.CheckoutPath)
if len(req.gitMaterialMapping) == 0 {
impl.logger.Errorw("no git materials found for the app", "appId", req.appId)
return nil, fmt.Errorf("no git materials found for the app, %d", req.appId)
}
gitMaterialId := req.gitMaterialMapping[ciBuildConfig.GitMaterialId]
buildContextGitMaterialId := req.gitMaterialMapping[ciBuildConfig.BuildContextGitMaterialId]
if gitMaterialId == 0 {
for _, id := range req.gitMaterialMapping {
gitMaterialId = id
break
}
}
if buildContextGitMaterialId == 0 {
buildContextGitMaterialId = gitMaterialId
}
ciBuildConfig.GitMaterialId = gitMaterialId
ciBuildConfig.BuildContextGitMaterialId = buildContextGitMaterialId
templateOverride.GitMaterialId = gitMaterialId
ciBuildConfig.Id = 0
ciPatchReq.CiPipeline.DockerConfigOverride = bean.DockerConfigOverride{
DockerRegistry: templateOverride.DockerRegistryId,
DockerRepository: templateOverride.DockerRepository,
CiBuildConfig: ciBuildConfig,
}
}
var refCiPipeline *bean.CiPipeline
var uniqueId int
for id, reqCiPipeline := range refCiConfig.CiPipelines {
if reqCiPipeline.Id == req.refCiPipelineId {
refCiPipeline = reqCiPipeline
uniqueId = id
break
}
}
if refCiPipeline == nil {
return nil, nil
}
pipelineName := refCiPipeline.Name
if strings.HasPrefix(pipelineName, req.refAppName) {
pipelineName = strings.Replace(pipelineName, req.refAppName+"-ci-", "", 1)
}

return impl.pipelineBuilder.PatchCiPipeline(ciPatchReq)
pipelineExists, err := impl.ciPipelineRepository.CheckIfPipelineExistsByNameAndAppId(pipelineName, req.appId)
if err != nil && err != pg.ErrNoRows {
impl.logger.Errorw("error in fetching pipeline by name, FindByName", "err", err, "patch cipipeline name", pipelineName)
return nil, err
}
if pipelineExists {
pipelineName = fmt.Sprintf("%s-%d", pipelineName, uniqueId) // making pipeline name unique
}
var ciMaterilas []*bean.CiMaterial
for _, refCiMaterial := range refCiPipeline.CiMaterial {
//FIXME
gitMaterialId := req.gitMaterialMapping[refCiMaterial.GitMaterialId]
if refCiPipeline.ParentCiPipeline != 0 {
gitMaterialId = refCiMaterial.GitMaterialId
}
ciMaterial := &bean.CiMaterial{
GitMaterialId: gitMaterialId,
Id: 0,
Source: &bean.SourceTypeConfig{
Type: refCiMaterial.Source.Type,
Value: refCiMaterial.Source.Value,
Regex: refCiMaterial.Source.Regex,
},
}
ciMaterilas = append(ciMaterilas, ciMaterial)
}
var beforeDockerBuildScripts []*bean.CiScript
var afterDockerBuildScripts []*bean.CiScript

for _, script := range refCiPipeline.BeforeDockerBuildScripts {
ciScript := &bean.CiScript{
Id: 0,
Index: script.Index,
Name: script.Name,
Script: script.Script,
OutputLocation: script.OutputLocation,
}
beforeDockerBuildScripts = append(beforeDockerBuildScripts, ciScript)
}
for _, script := range refCiPipeline.AfterDockerBuildScripts {
ciScript := &bean.CiScript{
Id: 0,
Index: script.Index,
Name: script.Name,
Script: script.Script,
OutputLocation: script.OutputLocation,
}
afterDockerBuildScripts = append(afterDockerBuildScripts, ciScript)
}

//getting pre stage and post stage details
preStageDetail, postStageDetail, err := impl.pipelineStageService.GetCiPipelineStageDataDeepCopy(refCiPipeline.Id)
if err != nil {
impl.logger.Errorw("error in getting pre & post stage detail by ciPipelineId", "err", err, "ciPipelineId", refCiPipeline.Id)
return nil, err
}
ciPatchReq := &bean.CiPatchRequest{
CiPipeline: &bean.CiPipeline{
IsManual: refCiPipeline.IsManual,
DockerArgs: refCiPipeline.DockerArgs,
IsExternal: refCiPipeline.IsExternal,
ExternalCiConfig: bean.ExternalCiConfig{},
CiMaterial: ciMaterilas,
Name: pipelineName,
Id: 0,
Version: refCiPipeline.Version,
Active: refCiPipeline.Active,
Deleted: refCiPipeline.Deleted,
BeforeDockerBuild: refCiPipeline.BeforeDockerBuild,
AfterDockerBuild: refCiPipeline.AfterDockerBuild,
BeforeDockerBuildScripts: beforeDockerBuildScripts,
AfterDockerBuildScripts: afterDockerBuildScripts,
ParentCiPipeline: refCiPipeline.ParentCiPipeline,
IsDockerConfigOverridden: refCiPipeline.IsDockerConfigOverridden,
PreBuildStage: preStageDetail,
PostBuildStage: postStageDetail,
EnvironmentId: refCiPipeline.EnvironmentId,
ScanEnabled: refCiPipeline.ScanEnabled,
PipelineType: refCiPipeline.PipelineType,
},
AppId: req.appId,
Action: bean.CREATE,
AppWorkflowId: req.wfId,
UserId: req.userId,
IsCloneJob: true,
}
if refCiPipeline.EnvironmentId != 0 {
ciPatchReq.IsJob = true
}
if !refCiPipeline.IsExternal && refCiPipeline.IsDockerConfigOverridden {
//get template override
templateOverrideBean, err := impl.ciTemplateService.FindTemplateOverrideByCiPipelineId(refCiPipeline.Id)
if err != nil {
return nil, err
}
templateOverride := templateOverrideBean.CiTemplateOverride
ciBuildConfig := templateOverrideBean.CiBuildConfig
//getting new git material for this app
//gitMaterial, err := impl.materialRepository.FindByAppIdAndCheckoutPath(req.appId, templateOverride.GitMaterial.CheckoutPath)
if len(req.gitMaterialMapping) == 0 {
impl.logger.Errorw("no git materials found for the app", "appId", req.appId)
return nil, fmt.Errorf("no git materials found for the app, %d", req.appId)
}
gitMaterialId := req.gitMaterialMapping[ciBuildConfig.GitMaterialId]
buildContextGitMaterialId := req.gitMaterialMapping[ciBuildConfig.BuildContextGitMaterialId]
if gitMaterialId == 0 {
for _, id := range req.gitMaterialMapping {
gitMaterialId = id
break
}
}
if buildContextGitMaterialId == 0 {
buildContextGitMaterialId = gitMaterialId
}
ciBuildConfig.GitMaterialId = gitMaterialId
ciBuildConfig.BuildContextGitMaterialId = buildContextGitMaterialId
templateOverride.GitMaterialId = gitMaterialId
ciBuildConfig.Id = 0
ciPatchReq.CiPipeline.DockerConfigOverride = bean.DockerConfigOverride{
DockerRegistry: templateOverride.DockerRegistryId,
DockerRepository: templateOverride.DockerRepository,
CiBuildConfig: ciBuildConfig,
}
}
return nil, fmt.Errorf("ci pipeline not found ")
return impl.pipelineBuilder.PatchCiPipeline(ciPatchReq)
}

type cloneCdPipelineRequest struct {
Expand Down
2 changes: 1 addition & 1 deletion pkg/pipeline/BuildPipelineConfigService.go
Original file line number Diff line number Diff line change
Expand Up @@ -1237,7 +1237,7 @@ func (impl *CiPipelineConfigServiceImpl) handlePipelineCreate(request *bean.CiPa

if pipelineExists {
impl.logger.Errorw("pipeline name already exist", "err", err, "patch cipipeline name", request.CiPipeline.Name)
return nil, fmt.Errorf("pipeline name already exist")
return nil, fmt.Errorf(bean3.PIPELINE_NAME_ALREADY_EXISTS_ERROR)
}

if request.IsSwitchCiPipelineRequest() {
Expand Down
2 changes: 2 additions & 0 deletions pkg/pipeline/bean/CiBuildConfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ const (
const Main = "main"
const UniquePlaceHolderForAppName = "$etron"

const PIPELINE_NAME_ALREADY_EXISTS_ERROR = "pipeline name already exist"

type CiBuildConfigBean struct {
Id int `json:"id"`
GitMaterialId int `json:"gitMaterialId,omitempty" validate:"required"`
Expand Down

0 comments on commit 6b596a8

Please sign in to comment.