in backend/plugins/dora/tasks/deployment_commits_generator.go [62:214]
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
noneSkippedResult := []string{devops.RESULT_FAILURE, devops.RESULT_SUCCESS}
var clauses = []dal.Clause{
dal.Select(
`
pc.*,
p.name as pipeline_name,
p.result,
p.status,
p.duration_sec,
p.queued_duration_sec,
p.started_date,
p.created_date,
p.finished_date,
p.environment,
p.cicd_scope_id,
p.original_status,
p.original_result,
EXISTS(SELECT 1 FROM cicd_tasks t WHERE t.pipeline_id = p.id AND t.environment = ? AND t.result IN ?) as has_testing_tasks,
EXISTS(SELECT 1 FROM cicd_tasks t WHERE t.pipeline_id = p.id AND t.environment = ? AND t.result IN ?) as has_staging_tasks,
EXISTS( SELECT 1 FROM cicd_tasks t WHERE t.pipeline_id = p.id AND t.environment = ? AND t.result IN ?) as has_production_tasks
`,
devops.TESTING, noneSkippedResult,
devops.STAGING, noneSkippedResult,
devops.PRODUCTION, noneSkippedResult,
),
dal.From("cicd_pipeline_commits pc"),
dal.Join("LEFT JOIN cicd_pipelines p ON (p.id = pc.pipeline_id)"),
dal.Where(
`
p.result IN ? AND (
p.type = ? OR EXISTS(SELECT 1 FROM cicd_tasks t WHERE t.pipeline_id = p.id AND t.type = ? AND t.result IN ?)
)
`,
noneSkippedResult,
devops.DEPLOYMENT,
devops.DEPLOYMENT,
noneSkippedResult,
),
}
if data.Options.ScopeId != nil {
clauses = append(clauses, dal.Where(`p.cicd_scope_id = ?`, data.Options.ScopeId))
// Clear previous results from the project
deleteSql := `DELETE FROM cicd_deployment_commits WHERE cicd_scope_id = ? and subtask_name = ?;`
err := db.Exec(deleteSql, data.Options.ScopeId, DORAGenerateDeploymentCommits)
if err != nil {
return errors.Default.Wrap(err, "error deleting previous cicd_deployment_commits")
}
} else {
clauses = append(clauses,
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 = ?`, data.Options.ProjectName),
)
// Clear previous results from the project
deleteSql := `DELETE FROM cicd_deployment_commits
WHERE cicd_scope_id IN (
SELECT cicd_scope_id
FROM (
SELECT cdc.cicd_scope_id
FROM cicd_deployment_commits cdc
LEFT JOIN project_mapping pm ON (pm.table = 'cicd_scopes' AND pm.row_id = cdc.cicd_scope_id)
WHERE pm.project_name = ?
) AS subquery
) AND subtask_name = ?;`
err := db.Exec(deleteSql, data.Options.ProjectName, DORAGenerateDeploymentCommits)
if err != nil {
return errors.Default.Wrap(err, "error deleting previous cicd_deployment_commits")
}
}
cursor, err := db.Cursor(clauses...)
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,
DisplayTitle: pipelineCommit.DisplayTitle,
Url: pipelineCommit.Url,
Result: pipelineCommit.Result,
OriginalStatus: pipelineCommit.OriginalStatus,
OriginalResult: pipelineCommit.OriginalResult,
Status: pipelineCommit.Status,
Environment: pipelineCommit.Environment,
TaskDatesInfo: devops.TaskDatesInfo{
CreatedDate: *pipelineCommit.CreatedDate,
StartedDate: pipelineCommit.StartedDate,
FinishedDate: pipelineCommit.FinishedDate,
},
DurationSec: pipelineCommit.DurationSec,
QueuedDurationSec: pipelineCommit.QueuedDurationSec,
CommitSha: pipelineCommit.CommitSha,
RefName: pipelineCommit.Branch,
RepoId: pipelineCommit.RepoId,
RepoUrl: pipelineCommit.RepoUrl,
}
if domainDeployCommit.TaskDatesInfo.StartedDate == nil {
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
}
}
domainDeployCommit.SubtaskName = DORAGenerateDeploymentCommits
return []interface{}{domainDeployCommit}, nil
},
})
if err != nil {
return err
}
return enricher.Execute()
}