@@ -277,47 +277,55 @@ func batchFetchFirstReviews(projectName string, db dal.Dal) (map[string]*code.Pu
277277// batchFetchDeployments retrieves deployment commits for all merge commits in the given project.
278278// Returns a map indexed by merge commit SHA for O(1) lookup performance.
279279//
280- // The query finds the first successful production deployment for each merge commit by:
281- // 1. Finding deployment commits that have a previous successful deployment
282- // 2. Joining with commits_diffs to find which deployment included each merge commit
283- // 3. Filtering for successful production deployments
284- // 4. Ordering by started_date to get the earliest deployment
280+ // Uses a two-phase strategy to avoid the "first deployment over-mapping" problem:
285281//
286- // The map is indexed by merge_sha (from commits_diffs), not by deployment commit_sha,
287- // because the caller needs to look up deployments by PR merge_commit_sha.
282+ // Phase 1 - Direct match: find successful PRODUCTION deployments whose commit_sha
283+ // directly equals a PR's merge_commit_sha. Safe even for the very first deployment.
284+ //
285+ // Phase 2 - Diff-based fallback: use the commits_diffs join strategy, but deliberately
286+ // skip the first deployment (prev_success_deployment_commit_id == "") to avoid over-mapping.
288287func batchFetchDeployments (projectName string , db dal.Dal ) (map [string ]* devops.CicdDeploymentCommit , errors.Error ) {
289- var results []* deploymentCommitWithMergeSha
290-
291- // Query finds the first deployment for each merge commit by using a window function
292- // to rank deployments by started_date, then filtering to keep only rank 1.
288+ deploymentMap := make (map [string ]* devops.CicdDeploymentCommit )
289+ var directResults []* devops.CicdDeploymentCommit
293290 err := db .All (
294- & results ,
291+ & directResults ,
292+ dal .Select ("dc.*" ),
293+ dal .From ("cicd_deployment_commits dc" ),
294+ dal .Join ("LEFT JOIN project_mapping pm ON pm.table = 'cicd_scopes' AND pm.row_id = dc.cicd_scope_id" ),
295+ dal .Where ("dc.environment = 'PRODUCTION'" ), // TODO: remove when multi-environment is supported
296+ dal .Where ("dc.result = ? AND pm.project_name = ?" , devops .RESULT_SUCCESS , projectName ),
297+ dal .Orderby ("dc.started_date ASC, dc.id ASC" ),
298+ )
299+ if err != nil {
300+ return nil , errors .Default .Wrap (err , "failed to batch fetch direct deployments" )
301+ }
302+ for _ , dc := range directResults {
303+ if _ , exists := deploymentMap [dc .CommitSha ]; ! exists {
304+ deploymentCopy := * dc
305+ deploymentMap [dc .CommitSha ] = & deploymentCopy
306+ }
307+ }
308+ var diffResults []* deploymentCommitWithMergeSha
309+ err = db .All (
310+ & diffResults ,
295311 dal .Select ("dc.*, cd.commit_sha as merge_sha" ),
296312 dal .From ("cicd_deployment_commits dc" ),
297313 dal .Join ("LEFT JOIN cicd_deployment_commits p ON dc.prev_success_deployment_commit_id = p.id" ),
298314 dal .Join ("INNER JOIN commits_diffs cd ON cd.new_commit_sha = dc.commit_sha AND cd.old_commit_sha = COALESCE(p.commit_sha, '')" ),
299315 dal .Join ("LEFT JOIN project_mapping pm ON pm.table = 'cicd_scopes' AND pm.row_id = dc.cicd_scope_id" ),
300316 dal .Where ("dc.prev_success_deployment_commit_id <> ''" ),
301- dal .Where ("dc.environment = 'PRODUCTION'" ), // TODO: remove this when multi-environment is supported
317+ dal .Where ("dc.environment = 'PRODUCTION'" ), // TODO: remove when multi-environment is supported
302318 dal .Where ("dc.result = ? AND pm.project_name = ?" , devops .RESULT_SUCCESS , projectName ),
303319 dal .Orderby ("cd.commit_sha, dc.started_date ASC, dc.id ASC" ),
304320 )
305-
306321 if err != nil {
307- return nil , errors .Default .Wrap (err , "failed to batch fetch deployments" )
322+ return nil , errors .Default .Wrap (err , "failed to batch fetch diff-based deployments" )
308323 }
309-
310- // Build the map indexed by merge_sha for O(1) lookup.
311- // Keep only the first deployment for each merge commit (earliest by started_date).
312- deploymentMap := make (map [string ]* devops.CicdDeploymentCommit , len (results ))
313- for _ , result := range results {
314- // Only keep the first deployment for each merge_sha
324+ for _ , result := range diffResults {
315325 if _ , exists := deploymentMap [result .MergeSha ]; ! exists {
316- // Copy the CicdDeploymentCommit without the MergeSha field
317326 deploymentCopy := result .CicdDeploymentCommit
318327 deploymentMap [result .MergeSha ] = & deploymentCopy
319328 }
320329 }
321-
322330 return deploymentMap , nil
323331}
0 commit comments