3131 GithubUsernameRegex = regexp .MustCompile (`^[A-Za-z0-9-]{3,39}$` )
3232)
3333
34+ // Note: we use | and ||| as placeholders for inline and fenced code, then swap to backticks at render time.
35+ const MissingCoAuthorsMessage = `
36+
37+ One or more co-authors of this pull request were not found. You must specify co-authors in commit message trailer via:
38+
39+ |||
40+ Co-authored-by: name <email>
41+ |||
42+
43+ Supported |Co-authored-by:| formats include:
44+
45+ 1) |Anything <[email protected] >| - it will locate your GitHub user by |id| part. 46+ 2) |Anything <[email protected] >| - it will locate your GitHub user by |login| part. 47+ 3) |Anything <public-email>| - it will locate your GitHub user by |public-email| part. Note that this email must be made public on Github.
48+ 4) |Anything <other-email>| - it will locate your GitHub user by |other-email| part but only if that email was used before for any other CLA as a main commit author.
49+ 5) |login <any-valid-email>| - it will locate your GitHub user by |login| part, note that |login| part must be at least 3 characters long.
50+
51+ Please update your commit message(s) by doing |git commit --amend| and then |git push [--force]| and then request re-running CLA check via commenting on this pull request:
52+
53+ |||
54+ /easycla
55+ |||
56+
57+ `
58+
3459const (
3560 help = "https://help.github.com/en/github/committing-changes-to-your-project/why-are-my-commits-linked-to-the-wrong-user"
3661 unknown = "Unknown"
@@ -351,17 +376,22 @@ func ExpandWithCoAuthors(
351376 pr int ,
352377 installationID int64 ,
353378 commitAuthors * []* UserCommitSummary ,
354- ) {
379+ ) bool {
355380 f := logrus.Fields {
356381 "functionName" : "github.github_repository.ExpandWithCoAuthors" ,
357382 "pr" : pr ,
358383 }
359384 coAuthors := GetCoAuthorsFromCommit (ctx , commit )
360385 log .WithFields (f ).Debugf ("co-authors found: %s" , coAuthors )
386+ missing := false
361387 for _ , coAuthor := range coAuthors {
362- summary := GetCoAuthorCommits (ctx , client , usersService , coAuthor , commit , pr , installationID )
388+ summary , found := GetCoAuthorCommits (ctx , client , usersService , coAuthor , commit , pr , installationID )
363389 * commitAuthors = append (* commitAuthors , summary )
390+ if ! missing && ! found {
391+ missing = true
392+ }
364393 }
394+ return missing
365395}
366396
367397// IsValidGitHubUsername checks if the provided username is a valid GitHub username.
@@ -387,7 +417,7 @@ func GetCoAuthorCommits(
387417 commit * github.RepositoryCommit ,
388418 pr int ,
389419 installationID int64 ,
390- ) * UserCommitSummary {
420+ ) ( * UserCommitSummary , bool ) {
391421 f := logrus.Fields {
392422 "functionName" : "github.github_repository.GetCoAuthorCommits" ,
393423 "pr" : pr ,
@@ -409,6 +439,7 @@ func GetCoAuthorCommits(
409439 cacheKey := [2 ]string {lName , email }
410440 if cachedUser , ok := GithubUserCache .Get (cacheKey ); ok {
411441 log .WithFields (f ).Debugf ("GitHub user found in cache for name/email: %s/%s: %+v" , name , email , cachedUser )
442+ found := false
412443 var summary * UserCommitSummary
413444 if cachedUser != nil {
414445 summary = & UserCommitSummary {
@@ -417,6 +448,7 @@ func GetCoAuthorCommits(
417448 Affiliated : false ,
418449 Authorized : false ,
419450 }
451+ found = cachedUser .ID != nil
420452 } else {
421453 summary = & UserCommitSummary {
422454 SHA : utils .StringValue (commit .SHA ),
@@ -431,7 +463,7 @@ func GetCoAuthorCommits(
431463 }
432464 }
433465 log .WithFields (f ).Debugf ("PR: %d, %+v (from cache)" , pr , summary )
434- return summary
466+ return summary , found
435467 }
436468
437469 log .WithFields (f ).Debugf ("Getting co-author details: %+v" , coAuthor )
@@ -528,12 +560,14 @@ func GetCoAuthorCommits(
528560 log .WithFields (f ).Debugf ("Co-author: %v, user: %+v" , coAuthor , user )
529561
530562 var summary * UserCommitSummary
563+ found := false
531564 if user != nil {
532565 if user .Login != nil {
533566 login = * user .Login
534567 }
535568 if user .ID != nil {
536569 githubID = * user .ID
570+ found = true
537571 }
538572 if user .Name == nil || (user .Name != nil && strings .TrimSpace (* user .Name ) == "" ) {
539573 user .Name = & name
@@ -565,10 +599,10 @@ func GetCoAuthorCommits(
565599 }
566600
567601 GithubUserCache .Set (cacheKey , user )
568- return summary
602+ return summary , found
569603}
570604
571- func GetPullRequestCommitAuthors (ctx context.Context , usersService users.Service , installationID int64 , pullRequestID int , owner , repo string , withCoAuthors bool ) ([]* UserCommitSummary , * string , error ) {
605+ func GetPullRequestCommitAuthors (ctx context.Context , usersService users.Service , installationID int64 , pullRequestID int , owner , repo string , withCoAuthors bool ) ([]* UserCommitSummary , * string , bool , error ) {
572606 f := logrus.Fields {
573607 "functionName" : "github.github_repository.GetPullRequestCommitAuthors" ,
574608 "pullRequestID" : pullRequestID ,
@@ -579,21 +613,22 @@ func GetPullRequestCommitAuthors(ctx context.Context, usersService users.Service
579613 client , err := NewGithubAppClient (installationID )
580614 if err != nil {
581615 log .WithFields (f ).WithError (err ).Warn ("unable to create Github client" )
582- return nil , nil , err
616+ return nil , nil , false , err
583617 }
584618
585619 commits , resp , comErr := client .PullRequests .ListCommits (ctx , owner , repo , pullRequestID , & github.ListOptions {})
586620 if comErr != nil {
587621 log .WithFields (f ).WithError (comErr ).Warnf ("problem listing commits for repo: %s/%s pull request: %d" , owner , repo , pullRequestID )
588- return nil , nil , comErr
622+ return nil , nil , false , comErr
589623 }
590624 if resp .StatusCode != http .StatusOK {
591625 msg := fmt .Sprintf ("unexpected status code: %d - expected: %d" , resp .StatusCode , http .StatusOK )
592626 log .WithFields (f ).Warn (msg )
593- return nil , nil , errors .New (msg )
627+ return nil , nil , false , errors .New (msg )
594628 }
595629
596630 log .WithFields (f ).Debugf ("found %d commits for pull request: %d" , len (commits ), pullRequestID )
631+ anyMissing := false
597632 for _ , commit := range commits {
598633 log .WithFields (f ).Debugf ("loaded commit: %+v" , commit )
599634 commitAuthor := ""
@@ -623,7 +658,10 @@ func GetPullRequestCommitAuthors(ctx context.Context, usersService users.Service
623658 Authorized : false ,
624659 })
625660 if withCoAuthors {
626- ExpandWithCoAuthors (ctx , client , usersService , commit , pullRequestID , installationID , & userCommitSummary )
661+ missing := ExpandWithCoAuthors (ctx , client , usersService , commit , pullRequestID , installationID , & userCommitSummary )
662+ if ! anyMissing && missing {
663+ anyMissing = true
664+ }
627665 }
628666 }
629667
@@ -636,10 +674,10 @@ func GetPullRequestCommitAuthors(ctx context.Context, usersService users.Service
636674 // }
637675 // log.WithFields(f).Debugf("user commit summary: %+v", *summary)
638676 //}
639- return userCommitSummary , latestCommitSHA , nil
677+ return userCommitSummary , latestCommitSHA , anyMissing , nil
640678}
641679
642- func UpdatePullRequest (ctx context.Context , installationID int64 , pullRequestID int , owner , repo string , repoID * int64 , latestSHA string , signed []* UserCommitSummary , missing []* UserCommitSummary , CLABaseAPIURL , CLALandingPage , CLALogoURL string ) error {
680+ func UpdatePullRequest (ctx context.Context , installationID int64 , pullRequestID int , owner , repo string , repoID * int64 , latestSHA string , signed []* UserCommitSummary , missing []* UserCommitSummary , anyMissing bool , CLABaseAPIURL , CLALandingPage , CLALogoURL string ) error {
643681 f := logrus.Fields {
644682 "functionName" : "github.github_repository.UpdatePullRequest" ,
645683 "installationID" : installationID ,
@@ -670,7 +708,7 @@ func UpdatePullRequest(ctx context.Context, installationID int64, pullRequestID
670708 return failedErr
671709 }
672710
673- body := assembleCLAComment (ctx , int (installationID ), pullRequestID , repoID , signed , missing , CLABaseAPIURL , CLALogoURL , CLALandingPage )
711+ body := assembleCLAComment (ctx , int (installationID ), pullRequestID , repoID , signed , missing , anyMissing , CLABaseAPIURL , CLALogoURL , CLALandingPage )
674712
675713 if len (missing ) == 0 {
676714 // All contributors are passing
@@ -701,7 +739,7 @@ func UpdatePullRequest(ctx context.Context, installationID int64, pullRequestID
701739 // If we have previously succeeded, then we also need to update the comment (pass => fail)
702740 log .WithFields (f ).Debugf ("Found previously succeeeded checks - updating the CLA comment in the PR : %d" , pullRequestID )
703741 // Generate a new comment with all the failed CLA info
704- failedComment := assembleCLAComment (ctx , int (installationID ), pullRequestID , repoID , signed , missing , CLABaseAPIURL , CLALogoURL , CLALandingPage )
742+ failedComment := assembleCLAComment (ctx , int (installationID ), pullRequestID , repoID , signed , missing , anyMissing , CLABaseAPIURL , CLALogoURL , CLALandingPage )
705743 previousSucceededComment .Body = & failedComment
706744 _ , _ , err = client .Issues .EditComment (ctx , owner , repo , * previousSucceededComment .ID , previousSucceededComment )
707745 if err != nil {
@@ -818,7 +856,7 @@ func assembleCLAStatus(authorName string, signed bool) (string, string) {
818856 return authorName , "Missing CLA Authorization."
819857}
820858
821- func assembleCLAComment (ctx context.Context , installationID , pullRequestID int , repositoryID * int64 , signed , missing []* UserCommitSummary , apiBaseURL , CLALogoURL , CLALandingPage string ) string {
859+ func assembleCLAComment (ctx context.Context , installationID , pullRequestID int , repositoryID * int64 , signed , missing []* UserCommitSummary , anyMissing bool , apiBaseURL , CLALogoURL , CLALandingPage string ) string {
822860 f := logrus.Fields {
823861 "functionName" : "github.github_repository.assembleCLAComment" ,
824862 utils .XREQUESTID : ctx .Value (utils .XREQUESTID ),
@@ -838,13 +876,13 @@ func assembleCLAComment(ctx context.Context, installationID, pullRequestID int,
838876
839877 log .WithFields (f ).Debug ("Building CLAComment body " )
840878 signURL := getFullSignURL (repositoryType , strconv .Itoa (installationID ), strconv .Itoa (int (* repositoryID )), strconv .Itoa (pullRequestID ), apiBaseURL )
841- commentBody := getCommentBody (repositoryType , signURL , signed , missing )
879+ commentBody := getCommentBody (repositoryType , signURL , signed , missing , anyMissing )
842880 allSigned := len (missing ) == 0
843881 badge := getCommentBadge (allSigned , signURL , missingID , false , CLALandingPage , CLALogoURL )
844882 return fmt .Sprintf ("%s<br >%s" , badge , commentBody )
845883}
846884
847- func getCommentBody (repositoryType , signURL string , signed , missing []* UserCommitSummary ) string {
885+ func getCommentBody (repositoryType , signURL string , signed , missing []* UserCommitSummary , anyMissing bool ) string {
848886 f := logrus.Fields {
849887 "functionName" : "github.github_repository:getCommentBody" ,
850888 "repositoryType" : repositoryType ,
@@ -916,6 +954,10 @@ func getCommentBody(repositoryType, signURL string, signed, missing []*UserCommi
916954 text = "<br>The committers listed above are authorized under a signed CLA."
917955 }
918956
957+ if anyMissing {
958+ committersComment .WriteString (strings .ReplaceAll (MissingCoAuthorsMessage , "|" , "`" ))
959+ log .WithFields (f ).Debug ("some co-authors are missing for this PR, added the missing co-author message" )
960+ }
919961 return fmt .Sprintf ("%s%s" , committersComment .String (), text )
920962}
921963
0 commit comments