dmitri.shuralyov.com/service/change/...

gerritapi: sort inline comments

Sort inline comments by file name and line number, so that their order
is deterministic. Previously, it was non-deterministic due to reliance
on map iteration order.

There's still a small chance for non-determinism in comment order when
there are multiple inline comments in the same file on the same line.
Leave dealing with that case for later when running into it concretely,
because it's not clear if it's something that can actually happen.
If it becomes necessary to resolve it, it should be possible to use
inline comment IDs to break the tie.
dmitshur committed 1 month ago commit 957083f7751c871f1d6ddba48c392eb3836786d8
gerritapi/gerritapi.go
@@ -336,10 +336,16 @@ func (s service) ListTimeline(ctx context.Context, repo string, id uint64, opt *
 								Body: c.Message,
 							})
 						}
 					}
 				}
+				sort.Slice(cs, func(i, j int) bool {
+					if cs[i].File == cs[j].File {
+						return cs[i].Line < cs[j].Line
+					}
+					return cs[i].File < cs[j].File
+				})
 				timeline = append(timeline, change.Review{
 					ID:        fmt.Sprint(idx), // TODO: message.ID is not uint64; e.g., "bfba753d015916303152305cee7152ea7a112fe0".
 					User:      s.gerritUser(message.Author),
 					CreatedAt: message.Date.Time,
 					Body:      body,
@@ -414,10 +420,16 @@ func (s service) ListTimeline(ctx context.Context, repo string, id uint64, opt *
 						Body: c.Message,
 					})
 				}
 			}
 		}
+		sort.Slice(cs, func(i, j int) bool {
+			if cs[i].File == cs[j].File {
+				return cs[i].Line < cs[j].Line
+			}
+			return cs[i].File < cs[j].File
+		})
 		reviewState := reviewState(labels)
 		if body == "" && len(cs) == 0 && reviewState == state.ReviewNoScore && labels != "" {
 			// Skip an empty comment that, e.g., just sets a Run-TryBot+1 label.
 			continue
 		}