@@ -21,6 +21,7 @@ import (
21
21
"os/user"
22
22
"path/filepath"
23
23
"regexp"
24
+ "strconv"
24
25
"strings"
25
26
"sync"
26
27
"time"
@@ -246,15 +247,19 @@ type bot struct {
246
247
// CLs that have been created/updated on Gerrit for GitHub PRs but are not yet
247
248
// reflected in the maintner corpus yet.
248
249
pendingCLs map [string ]string // GitHub owner/repo#n -> Commit message from PR
250
+
251
+ // Cache of Gerrit Account IDs to AccountInfo structs.
252
+ cachedGerritAccounts map [int ]* gerrit.AccountInfo // 1234 -> Detailed Account Info
249
253
}
250
254
251
255
func newBot (githubClient * github.Client , gerritClient * gerrit.Client ) * bot {
252
256
return & bot {
253
- githubClient : githubClient ,
254
- gerritClient : gerritClient ,
255
- importedPRs : map [string ]* maintner.GerritCL {},
256
- pendingCLs : map [string ]string {},
257
- cachedPRs : map [string ]* cachedPullRequest {},
257
+ githubClient : githubClient ,
258
+ gerritClient : gerritClient ,
259
+ importedPRs : map [string ]* maintner.GerritCL {},
260
+ pendingCLs : map [string ]string {},
261
+ cachedPRs : map [string ]* cachedPullRequest {},
262
+ cachedGerritAccounts : map [int ]* gerrit.AccountInfo {},
258
263
}
259
264
}
260
265
@@ -371,7 +376,7 @@ func prShortLink(pr *github.PullRequest) string {
371
376
// imported. If the Gerrit change associated with a PR has been merged, the PR
372
377
// is closed. Those that have no associated open or merged Gerrit changes will
373
378
// result in one being created.
374
- // b's RWMutex read-write lock must be held .
379
+ // b. RWMutex must be Lock'ed .
375
380
func (b * bot ) processPullRequest (ctx context.Context , pr * github.PullRequest ) error {
376
381
log .Printf ("Processing PR %s ..." , pr .GetHTMLURL ())
377
382
shortLink := prShortLink (pr )
@@ -428,24 +433,72 @@ func (b *bot) processPullRequest(ctx context.Context, pr *github.PullRequest) er
428
433
return nil
429
434
}
430
435
436
+ // gerritMessageAuthorID returns the Gerrit Account ID of the author of m.
437
+ func gerritMessageAuthorID (m * maintner.GerritMessage ) (int , error ) {
438
+ email := m .Author .Email ()
439
+ if strings .Index (email , "@" ) == - 1 {
440
+ return - 1 , fmt .Errorf ("message author email %q does not contain '@' character" , email )
441
+ }
442
+ i , err := strconv .Atoi (strings .Split (email , "@" )[0 ])
443
+ if err != nil {
444
+ return - 1 , fmt .Errorf ("strconv.Atoi: %v (email: %q)" , err , email )
445
+ }
446
+ return i , nil
447
+ }
448
+
449
+ // gerritMessageAuthorName returns a message author's display name. To prevent a
450
+ // thundering herd of redundant comments created by posting a different message
451
+ // via postGitHubMessageNoDup in syncGerritCommentsToGitHub, it will only return
452
+ // the correct display name for messages posted after a hard-coded date.
453
+ // b.RWMutex must be Lock'ed.
454
+ func (b * bot ) gerritMessageAuthorName (ctx context.Context , m * maintner.GerritMessage ) (string , error ) {
455
+ t := time .Date (2018 , time .November , 9 , 0 , 0 , 0 , 0 , time .UTC )
456
+ if m .Date .Before (t ) {
457
+ return m .Author .Name (), nil
458
+ }
459
+ id , err := gerritMessageAuthorID (m )
460
+ if err != nil {
461
+ return "" , fmt .Errorf ("gerritMessageAuthorID: %v" , err )
462
+ }
463
+ account := b .cachedGerritAccounts [id ]
464
+ if account != nil {
465
+ return account .Name , nil
466
+ }
467
+ ai , err := b .gerritClient .GetAccountInfo (ctx , strconv .Itoa (id ))
468
+ if err != nil {
469
+ return "" , fmt .Errorf ("b.gerritClient.GetAccountInfo: %v" , err )
470
+ }
471
+ b .cachedGerritAccounts [id ] = & ai
472
+ return ai .Name , nil
473
+ }
474
+
475
+ // b.RWMutex must be Lock'ed.
431
476
func (b * bot ) syncGerritCommentsToGitHub (ctx context.Context , pr * github.PullRequest , cl * maintner.GerritCL ) error {
432
477
if * dryRun {
433
478
log .Printf ("[dry run] would sync Gerrit comments to %v" , prShortLink (pr ))
434
479
return nil
435
480
}
436
481
repo := pr .GetBase ().GetRepo ()
437
482
for _ , m := range cl .Messages {
438
- if m .Author .Email () == cl .Owner ().Email () {
483
+ id , err := gerritMessageAuthorID (m )
484
+ if err != nil {
485
+ return fmt .Errorf ("gerritMessageAuthorID: %v" , err )
486
+ }
487
+ if id == cl .OwnerID () {
439
488
continue
440
489
}
490
+ authorName , err := b .gerritMessageAuthorName (ctx , m )
491
+ if err != nil {
492
+ return fmt .Errorf ("b.gerritMessageAuthorName: %v" , err )
493
+ }
441
494
msg := fmt .Sprintf (`Message from %s:
442
495
443
496
%s
444
497
445
498
---
446
499
Please don’t reply on this GitHub thread. Visit [golang.org/cl/%d](https://go-review.googlesource.com/c/%s/+/%d#message-%s).
447
500
After addressing review feedback, remember to [publish your drafts](https://github.com/golang/go/wiki/GerritBot#i-left-a-reply-to-a-comment-in-gerrit-but-no-one-but-me-can-see-it)!` ,
448
- m . Author . Name () , m .Message , cl .Number , cl .Project .Project (), cl .Number , m .Meta .Hash .String ())
501
+ authorName , m .Message , cl .Number , cl .Project .Project (), cl .Number , m .Meta .Hash .String ())
449
502
if err := b .postGitHubMessageNoDup (ctx , repo .GetOwner ().GetLogin (), repo .GetName (), pr .GetNumber (), msg ); err != nil {
450
503
return fmt .Errorf ("postGitHubMessageNoDup: %v" , err )
451
504
}
@@ -696,7 +749,7 @@ func reposRoot() string {
696
749
}
697
750
698
751
// getFullPR retrieves a Pull Request via GitHub’s API.
699
- // b's RWMutex read-write lock must be held .
752
+ // b. RWMutex must be Lock'ed .
700
753
func (b * bot ) getFullPR (ctx context.Context , owner , repo string , number int ) (* github.PullRequest , error ) {
701
754
shortLink := githubShortLink (owner , repo , number )
702
755
cpr := b .cachedPRs [shortLink ]
0 commit comments