fix(ui): too many participants shown in commit avatar stacks (#38689) (#38700)

Backport #38689

Show only author and co-authors without committer, and deduplicate the
same user with multiple email addresses.

The commit list "Author" column should not show the committer. This is
somewhat misleading, and arguably showing it on the individual commit
page is sufficient and consistent with other forges.

The same user with multiple email addresses often happens when
DEFAULT_KEEP_EMAIL_PRIVATE is enabled and Gitea does not use an actual
email address by default for edits. Showing the same avatar and name
twice is not helpful then.

Ref #37594
Fix #38488

Co-authored-by: bircni <bircni@icloud.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
Brecht Van Lommel
2026-07-29 21:39:09 +02:00
committed by GitHub
parent 784d88814f
commit 9eac9bd032
8 changed files with 63 additions and 68 deletions
+19 -16
View File
@@ -52,41 +52,44 @@ func TestCommitMessageTrailer(t *testing.T) {
func TestCommitMessageParticipants(t *testing.T) {
sig := func(n, e string) *Signature { return &Signature{Name: n, Email: e} }
idt := func(n, e string, r int) *CommitIdentity { return &CommitIdentity{n, e, r} }
roleAuthor, roleCommitter, roleCoAuthor := commitIdentityRoleAuthor, commitIdentityRoleCommitter, commitIdentityRoleCoAuthor
roleAuthor, _, roleCoAuthor := commitIdentityRoleAuthor, commitIdentityRoleCommitter, commitIdentityRoleCoAuthor
type testCase struct {
name string
commit *Commit
identities []*CommitIdentity
}
t.Run("AllParticipants", func(t *testing.T) {
t.Run("AllAuthors", func(t *testing.T) {
cases := []testCase{
{
"DifferentUsers",
"CommitterExcluded",
&Commit{
Author: sig("a", "a@m.com"), Committer: sig("c", "c@m.com"),
CommitMessage: CommitMessage{MessageRaw: "CO-Authored-BY: x@m.com"},
CommitMessage: CommitMessage{MessageRaw: "CO-Authored-BY: Full Name <x@m.com>"},
},
[]*CommitIdentity{idt("a", "a@m.com", roleAuthor), idt("c", "c@m.com", roleCommitter), idt("", "x@m.com", roleCoAuthor)},
[]*CommitIdentity{idt("a", "a@m.com", roleAuthor), idt("Full Name", "x@m.com", roleCoAuthor)},
},
{
"SameUser",
"AuthorIsCoAuthor",
&Commit{
Author: sig("a", "a@m.com"), Committer: sig("a", "A@M.com"),
CommitMessage: CommitMessage{MessageRaw: "CO-Authored-BY: a@m.com"},
Author: sig("a", "a@m.com"), Committer: sig("c", "c@m.com"),
CommitMessage: CommitMessage{MessageRaw: "CO-Authored-BY: other-name <a@m.com>"},
},
[]*CommitIdentity{idt("a", "a@m.com", roleAuthor)},
},
{
"NoCommitter",
"EmptyAuthor", // synthesized commits (push feed) may have no author signature at all
&Commit{
Author: sig("a", "a@m.com"), Committer: sig("", ""),
CommitMessage: CommitMessage{MessageRaw: "Co-authored-by: Full Name <X@M.com>"},
Author: sig("", ""), Committer: sig("", ""),
CommitMessage: CommitMessage{MessageRaw: "Co-authored-by: c <c@m.com>"},
},
[]*CommitIdentity{idt("a", "a@m.com", roleAuthor), idt("Full Name", "X@M.com", roleCoAuthor)},
// but if the commit message contains co-authors, the co-authors are still parsed for "all authors"
// if it is a problem, the caller should fix the problem (provide correct "author")
[]*CommitIdentity{idt("c", "c@m.com", roleCoAuthor)},
},
}
for _, c := range cases {
assert.Equal(t, c.identities, c.commit.AllParticipantIdentities(), "case: %s", c.name)
assert.Equal(t, c.identities, c.commit.AllAuthorIdentities(), "case: %s", c.name)
}
})
t.Run("CoAuthors", func(t *testing.T) {
@@ -116,12 +119,12 @@ func TestCommitMessageParticipants(t *testing.T) {
[]*CommitIdentity{},
},
{
"CoAuthorCommitterNameWithIndex", // restore the committer co-author to the co-author list by the index with correct name
"CoAuthorNameOnlyAndDuplicate",
&Commit{
Author: sig("a", "a@m.com"), Committer: sig("c", "c@m.com"),
CommitMessage: CommitMessage{MessageRaw: "Co-authored-by: x <x@m.com>\nCo-authored-by: c-other <c@m.com>\nCo-authored-by: y <y@m.com>"},
CommitMessage: CommitMessage{MessageRaw: "Co-authored-by: b\nCo-authored-by: b\nCo-authored-by: c"},
},
[]*CommitIdentity{idt("x", "x@m.com", roleCoAuthor), idt("c-other", "c@m.com", roleCoAuthor), idt("y", "y@m.com", roleCoAuthor)},
[]*CommitIdentity{idt("b", "", roleCoAuthor), idt("c", "", roleCoAuthor)},
},
}
for _, c := range cases {