@@ -19,6 +19,7 @@ package pipeline
19
19
import (
20
20
"github.com/devtron-labs/devtron/internal/sql/repository/appWorkflow"
21
21
"github.com/devtron-labs/devtron/internal/sql/repository/pipelineConfig"
22
+ "github.com/devtron-labs/devtron/internal/util"
22
23
"github.com/devtron-labs/devtron/pkg/bean"
23
24
"github.com/devtron-labs/devtron/pkg/pipeline/adapter"
24
25
pipelineConfigBean "github.com/devtron-labs/devtron/pkg/pipeline/bean/CiPipeline"
@@ -28,6 +29,7 @@ import (
28
29
"github.com/go-pg/pg"
29
30
"github.com/juju/errors"
30
31
"go.uber.org/zap"
32
+ "net/http"
31
33
"time"
32
34
)
33
35
@@ -81,7 +83,12 @@ func NewBuildPipelineSwitchServiceImpl(logger *zap.SugaredLogger,
81
83
82
84
func (impl * BuildPipelineSwitchServiceImpl ) SwitchToExternalCi (tx * pg.Tx , appWorkflowMapping * appWorkflow.AppWorkflowMapping , switchFromCiPipelineId int , userId int32 ) error {
83
85
84
- err := impl .deleteCiAndItsWorkflowMappings (tx , switchFromCiPipelineId , userId )
86
+ err := impl .validateSwitchPreConditions (switchFromCiPipelineId )
87
+ if err != nil {
88
+ return err
89
+ }
90
+
91
+ err = impl .deleteCiAndItsWorkflowMappings (tx , switchFromCiPipelineId , userId )
85
92
if err != nil {
86
93
impl .logger .Errorw ("error in deleting old ci-pipeline and getting the appWorkflow mapping of that" , "err" , err , "userId" , userId )
87
94
return err
@@ -97,7 +104,7 @@ func (impl *BuildPipelineSwitchServiceImpl) SwitchToExternalCi(tx *pg.Tx, appWor
97
104
return err
98
105
}
99
106
100
- //setting new ci_pipeline_id to 0 because we dont store ci_pipeline_id if the ci_pipeline is external/webhook type.
107
+ // setting new ci_pipeline_id to 0 because we dont store ci_pipeline_id if the ci_pipeline is external/webhook type.
101
108
err = impl .pipelineRepository .UpdateOldCiPipelineIdToNewCiPipelineId (tx , switchFromCiPipelineId , 0 )
102
109
if err != nil {
103
110
impl .logger .Errorw ("error in updating pipelines ci_pipeline_ids with new ci_pipelineId" , "oldCiPipelineId" , switchFromCiPipelineId )
@@ -130,11 +137,18 @@ func (impl *BuildPipelineSwitchServiceImpl) SwitchToCiPipelineExceptExternal(req
130
137
return nil , err
131
138
}
132
139
133
- //delete old pipeline and it's appworkflow mapping
140
+ // delete old pipeline and it's appworkflow mapping
134
141
return impl .createNewPipelineAndReplaceOldPipelineLinks (request .CiPipeline , ciConfig , switchFromPipelineId , switchFromType , request .UserId )
135
142
}
136
143
137
144
func (impl * BuildPipelineSwitchServiceImpl ) createNewPipelineAndReplaceOldPipelineLinks (ciPipelineReq * bean.CiPipeline , ciConfig * bean.CiConfigRequest , switchFromPipelineId int , switchFromType pipelineConfigBean.PipelineType , userId int32 ) (* bean.CiConfigRequest , error ) {
145
+
146
+ isSelfLinkedCiPipeline := switchFromType != pipelineConfigBean .EXTERNAL && ciPipelineReq .IsLinkedCi () && ciPipelineReq .ParentCiPipeline == switchFromPipelineId
147
+ if isSelfLinkedCiPipeline {
148
+ errMsg := "cannot create linked ci pipeline from the same source"
149
+ return nil , util .NewApiError ().WithInternalMessage (errMsg ).WithUserMessage (errMsg ).WithHttpStatusCode (http .StatusBadRequest )
150
+ }
151
+
138
152
tx , err := impl .ciPipelineRepository .StartTx ()
139
153
if err != nil {
140
154
impl .logger .Errorw ("error in starting transaction" , "switchFromPipelineId" , switchFromPipelineId , "switchFromType" , switchFromType , "userId" , userId , "err" , err )
@@ -161,12 +175,21 @@ func (impl *BuildPipelineSwitchServiceImpl) createNewPipelineAndReplaceOldPipeli
161
175
return nil , err
162
176
}
163
177
164
- //we don't store ci-pipeline-id in pipeline table for external ci's
165
- if switchFromPipelineId > 0 && switchFromType != pipelineConfigBean .EXTERNAL {
166
- // ciPipeline id is being set in res object in the addpipelineToTemplate method.
167
- err = impl .pipelineRepository .UpdateOldCiPipelineIdToNewCiPipelineId (tx , switchFromPipelineId , res .CiPipelines [0 ].Id )
178
+ if switchFromPipelineId > 0 {
179
+ // get all the cd workflow mappings whose parent component is our old pipeline
180
+ cdwfmappings , err := impl .appWorkflowRepository .FindWFCDMappingsByWorkflowId (oldAppWorkflowMapping .AppWorkflowId )
181
+ if err != nil {
182
+ impl .logger .Errorw ("error in finding parent cd workflowMappings using parent component details" , "parentComponentType" , oldAppWorkflowMapping .Type , "parentComponentId" , oldAppWorkflowMapping .ComponentId , "err" , err )
183
+ return nil , err
184
+ }
185
+ pipelineIds := make ([]int , 0 , len (cdwfmappings ))
186
+ for _ , cdwfMapping := range cdwfmappings {
187
+ pipelineIds = append (pipelineIds , cdwfMapping .ComponentId )
188
+ }
189
+
190
+ err = impl .pipelineRepository .UpdateCiPipelineId (tx , pipelineIds , res .CiPipelines [0 ].Id )
168
191
if err != nil {
169
- impl .logger .Errorw ("error in updating pipelines ci_pipeline_ids with new ci_pipelineId" , "oldCiPipelineId" , switchFromPipelineId , "newCiPipelineId" , res .CiPipelines [0 ].Id )
192
+ impl .logger .Errorw ("error in updating pipelines ci_pipeline_ids with new ci_pipelineId" , "oldCiPipelineId" , switchFromPipelineId , "newCiPipelineId" , res .CiPipelines [0 ].Id , "err" , err )
170
193
return nil , err
171
194
}
172
195
}
@@ -200,30 +223,10 @@ func (impl *BuildPipelineSwitchServiceImpl) validateCiPipelineSwitch(switchFromC
200
223
// we should not check the below logic for external_ci type as builds are not built in devtron and
201
224
// linked pipelines won't be there as per current external-ci-pipeline architecture
202
225
if switchFromCiPipelineId > 0 && switchFromType != pipelineConfigBean .EXTERNAL {
203
- // old ci_pipeline should not contain any linked ci_pipelines.
204
- linkedCiPipelines , err := impl .ciPipelineRepository .FindLinkedCiCount (switchFromCiPipelineId )
226
+ err := impl .validateSwitchPreConditions (switchFromCiPipelineId )
205
227
if err != nil {
206
- return nil
207
- }
208
- if linkedCiPipelines > 0 {
209
- return errors .New (string (cannotConvertIfLinkedCiFound ))
210
- }
211
-
212
- // note: ideally we should have found any builds running on old ci_pipeline, if yes block this conversion with proper message.
213
- // but checking only latest wf for now.
214
- ciWorkflow , err := impl .ciWorkflowRepository .FindLastTriggeredWorkflow (switchFromCiPipelineId )
215
- // no build is triggered case
216
- if err == pg .ErrNoRows {
217
- return nil
218
- }
219
- if err != nil {
220
- impl .logger .Errorw ("error in finding latest ciwokflow by ciPipelineId" , "ciPipelineId" , switchFromCiPipelineId )
221
228
return err
222
229
}
223
-
224
- if ciWorkflow .InProgress () {
225
- return errors .New (string (cannotConvertIfLatestWorkflowIsInNonTerminalState ))
226
- }
227
230
}
228
231
229
232
return nil
@@ -348,3 +351,34 @@ func (impl *BuildPipelineSwitchServiceImpl) saveHistoryOfOverriddenTemplate(ciPi
348
351
func (impl * BuildPipelineSwitchServiceImpl ) updateLinkedAppWorkflowMappings (tx * pg.Tx , oldAppWorkflowMapping * appWorkflow.AppWorkflowMapping , newAppWorkflowMapping * appWorkflow.AppWorkflowMapping ) error {
349
352
return impl .appWorkflowRepository .UpdateParentComponentDetails (tx , oldAppWorkflowMapping .ComponentId , oldAppWorkflowMapping .Type , newAppWorkflowMapping .ComponentId , newAppWorkflowMapping .Type , nil )
350
353
}
354
+
355
+ func (impl * BuildPipelineSwitchServiceImpl ) validateSwitchPreConditions (switchFromCiPipelineId int ) error {
356
+
357
+ // old ci_pipeline should not contain any linked ci_pipelines.
358
+ linkedCiPipelines , err := impl .ciPipelineRepository .FindLinkedCiCount (switchFromCiPipelineId )
359
+ if err != nil {
360
+ impl .logger .Errorw ("error in finding the linkedCi count for the pipeline" , "ciPipelineId" , switchFromCiPipelineId , "err" , err )
361
+ return err
362
+ }
363
+ if linkedCiPipelines > 0 {
364
+ return errors .New (string (cannotConvertIfLinkedCiFound ))
365
+ }
366
+
367
+ // note: ideally we should have found any builds running on old ci_pipeline, if yes block this conversion with proper message.
368
+ // but checking only latest wf for now.
369
+ ciWorkflow , err := impl .ciWorkflowRepository .FindLastTriggeredWorkflow (switchFromCiPipelineId )
370
+ // no build is triggered case
371
+ if err == pg .ErrNoRows {
372
+ return nil
373
+ }
374
+ if err != nil {
375
+ impl .logger .Errorw ("error in finding latest ciwokflow by ciPipelineId" , "ciPipelineId" , switchFromCiPipelineId )
376
+ return err
377
+ }
378
+
379
+ if ciWorkflow .InProgress () {
380
+ return errors .New (string (cannotConvertIfLatestWorkflowIsInNonTerminalState ))
381
+ }
382
+
383
+ return nil
384
+ }
0 commit comments