func GenerateDeploymentCommits()

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()
}