in backend/plugins/dora/tasks/deployment_commits_generator.go [56:165]
func GenerateDeploymentCommits(taskCtx plugin.SubTaskContext) errors.Error {
db := taskCtx.GetDal()
data := taskCtx.GetData().(*DoraTaskData)
// select all cicd_pipeline_commits from all "Deployments" in the project
// Note that failed records shall be included as well
cursor, err := db.Cursor(
dal.Select(
`
pc.*, p.name as pipeline_name,
p.result,
p.status,
p.duration_sec,
p.created_date,
p.finished_date,
p.environment,
p.cicd_scope_id,
EXISTS(SELECT 1 FROM cicd_tasks t WHERE t.pipeline_id = p.id AND t.environment = ?)
as has_testing_tasks,
EXISTS(SELECT 1 FROM cicd_tasks t WHERE t.pipeline_id = p.id AND t.environment = ?)
as has_staging_tasks,
EXISTS( SELECT 1 FROM cicd_tasks t WHERE t.pipeline_id = p.id AND t.environment = ?)
as has_production_tasks
`,
devops.TESTING,
devops.STAGING,
devops.PRODUCTION,
),
dal.From("cicd_pipeline_commits pc"),
dal.Join("LEFT JOIN cicd_pipelines p ON (p.id = pc.pipeline_id)"),
dal.Join("LEFT JOIN project_mapping pm ON (pm.table = 'cicd_scopes' AND pm.row_id = p.cicd_scope_id)"),
dal.Where(
`
pm.project_name = ? AND (
p.type = ? OR EXISTS(
SELECT 1 FROM cicd_tasks t WHERE t.pipeline_id = p.id AND t.type = ?
)
)
`,
data.Options.ProjectName,
devops.DEPLOYMENT,
devops.DEPLOYMENT,
),
)
if err != nil {
return err
}
defer cursor.Close()
enricher, err := api.NewDataConverter(api.DataConverterArgs{
RawDataSubTaskArgs: api.RawDataSubTaskArgs{
Ctx: taskCtx,
Params: DoraApiParams{
ProjectName: data.Options.ProjectName,
},
Table: "cicd_pipeline_commits",
},
InputRowType: reflect.TypeOf(pipelineCommitEx{}),
Input: cursor,
Convert: func(inputRow interface{}) ([]interface{}, errors.Error) {
pipelineCommit := inputRow.(*pipelineCommitEx)
domainDeployCommit := &devops.CicdDeploymentCommit{
DomainEntity: domainlayer.DomainEntity{
Id: fmt.Sprintf("%s:%s", pipelineCommit.PipelineId, pipelineCommit.RepoUrl),
},
CicdScopeId: pipelineCommit.CicdScopeId,
CicdDeploymentId: pipelineCommit.PipelineId,
Name: pipelineCommit.PipelineName,
Result: pipelineCommit.Result,
Status: pipelineCommit.Status,
Environment: pipelineCommit.Environment,
CreatedDate: *pipelineCommit.CreatedDate,
FinishedDate: pipelineCommit.FinishedDate,
DurationSec: pipelineCommit.DurationSec,
CommitSha: pipelineCommit.CommitSha,
RefName: pipelineCommit.Branch,
RepoId: pipelineCommit.RepoId,
RepoUrl: pipelineCommit.RepoUrl,
}
if pipelineCommit.FinishedDate != nil && pipelineCommit.DurationSec != nil {
s := pipelineCommit.FinishedDate.Add(-time.Duration(*pipelineCommit.DurationSec) * time.Second)
domainDeployCommit.StartedDate = &s
}
// it is tricky when Environment was declared on the cicd_tasks level
// lets talk common sense and assume that one pipeline can only be deployed to one environment
// so if the pipeline has both staging and production tasks, we will treat it as a production pipeline
// and if it has staging tasks without production tasks, we will treat it as a staging pipeline
// and then a testing pipeline
// lastly, we will leave Environment empty if any of the above measures didn't work out
// However, there is another catch, what if one deployed multiple TESTING(STAGING or PRODUCTION)
// environments? e.g. testing1, testing2, etc., Does it matter?
if pipelineCommit.Environment == "" {
if pipelineCommit.HasProductionTasks {
domainDeployCommit.Environment = devops.PRODUCTION
} else if pipelineCommit.HasStagingTasks {
domainDeployCommit.Environment = devops.STAGING
} else if pipelineCommit.HasTestingTasks {
domainDeployCommit.Environment = devops.TESTING
}
}
return []interface{}{domainDeployCommit}, nil
},
})
if err != nil {
return err
}
return enricher.Execute()
}