mirror of
https://github.com/go-gitea/gitea.git
synced 2026-08-26 02:03:28 +00:00
fix(git): parse co-author trailers that are not RFC 5322 addresses (#39076)
Bot co-authors like `dependabot[bot]` render as one long string with the email inside the name, and never get truncated, so they overflow the column. Co-author idents are parsed with `net/mail`, but a git ident isn't an email address. `mail.ParseAddress` rejects the whole value when the name holds characters RFC 5322 reserves, like a `[bot]` suffix or a comma, so the error branch keeps the raw trailer as the display name and throws the address away. No address means no `mailto:` link, and the anchor is what `.avatar-stack-names` truncates. So parse the angle-addr ourselves when `net/mail` won't take it. Splitting on the last `<` is safe because git strips angle brackets from idents. The bare-name branch gets the class too. Fixes https://github.com/go-gitea/gitea/issues/38949
This commit is contained in:
@@ -171,16 +171,24 @@ func (c *Commit) AllAuthorIdentities() []*CommitIdentity {
|
|||||||
|
|
||||||
addAuthor(c.Author.Name, c.Author.Email, commitIdentityRoleAuthor)
|
addAuthor(c.Author.Name, c.Author.Email, commitIdentityRoleAuthor)
|
||||||
for _, coAuthorValue := range trailerCoAuthors {
|
for _, coAuthorValue := range trailerCoAuthors {
|
||||||
addr, err := mail.ParseAddress(coAuthorValue)
|
coAuthorName, coAuthorEmail := parseCommitIdentityValue(coAuthorValue)
|
||||||
coAuthorName, coAuthorEmail := coAuthorValue, ""
|
|
||||||
if err == nil {
|
|
||||||
coAuthorName, coAuthorEmail = addr.Name, addr.Address
|
|
||||||
}
|
|
||||||
addAuthor(coAuthorName, coAuthorEmail, commitIdentityRoleCoAuthor)
|
addAuthor(coAuthorName, coAuthorEmail, commitIdentityRoleCoAuthor)
|
||||||
}
|
}
|
||||||
return c.allAuthors
|
return c.allAuthors
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Git identities are not RFC 5322 addresses: net/mail rejects names like "dependabot[bot]", so fall back to the angle-addr.
|
||||||
|
func parseCommitIdentityValue(value string) (name, email string) {
|
||||||
|
if addr, err := mail.ParseAddress(value); err == nil {
|
||||||
|
return addr.Name, addr.Address
|
||||||
|
}
|
||||||
|
begin, end := strings.LastIndex(value, "<"), strings.LastIndex(value, ">")
|
||||||
|
if begin == -1 || end < begin {
|
||||||
|
return value, ""
|
||||||
|
}
|
||||||
|
return strings.TrimSpace(value[:begin]), strings.TrimSpace(value[begin+1 : end])
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Commit) CoAuthorIdentities() (coAuthors []*CommitIdentity) {
|
func (c *Commit) CoAuthorIdentities() (coAuthors []*CommitIdentity) {
|
||||||
all := c.AllAuthorIdentities()
|
all := c.AllAuthorIdentities()
|
||||||
if len(all) == 0 {
|
if len(all) == 0 {
|
||||||
|
|||||||
@@ -126,6 +126,17 @@ func TestCommitMessageParticipants(t *testing.T) {
|
|||||||
},
|
},
|
||||||
[]*CommitIdentity{idt("b", "", roleCoAuthor), idt("c", "", roleCoAuthor)},
|
[]*CommitIdentity{idt("b", "", roleCoAuthor), idt("c", "", roleCoAuthor)},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"CoAuthorNameNotAnEmailAddress", // names net/mail rejects, e.g. bots and names with a comma
|
||||||
|
&Commit{
|
||||||
|
Author: sig("a", "a@m.com"), Committer: sig("c", "c@m.com"),
|
||||||
|
CommitMessage: CommitMessage{MessageRaw: "Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>\nCo-authored-by: Smith, John <j@m.com>"},
|
||||||
|
},
|
||||||
|
[]*CommitIdentity{
|
||||||
|
idt("dependabot[bot]", "49699333+dependabot[bot]@users.noreply.github.com", roleCoAuthor),
|
||||||
|
idt("Smith, John", "j@m.com", roleCoAuthor),
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, c := range cases {
|
for _, c := range cases {
|
||||||
assert.Equal(t, c.identities, c.commit.CoAuthorIdentities(), "case: %s", c.name)
|
assert.Equal(t, c.identities, c.commit.CoAuthorIdentities(), "case: %s", c.name)
|
||||||
|
|||||||
@@ -419,7 +419,7 @@ func (ut *RenderUtils) participantNameLink(data *user_model.AvatarStackData, par
|
|||||||
if participant.GitIdentity.Email != "" {
|
if participant.GitIdentity.Email != "" {
|
||||||
return htmlutil.HTMLFormat(`<a class="muted" href="mailto:%s">%s</a>`, participant.GitIdentity.Email, participant.GitIdentity.Name)
|
return htmlutil.HTMLFormat(`<a class="muted" href="mailto:%s">%s</a>`, participant.GitIdentity.Email, participant.GitIdentity.Name)
|
||||||
}
|
}
|
||||||
return template.HTML(template.HTMLEscapeString(participant.GitIdentity.Name))
|
return htmlutil.HTMLFormat(`<span class="avatar-stack-name">%s</span>`, participant.GitIdentity.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ut *RenderUtils) participantPopupRow(data *user_model.AvatarStackData, participant *user_model.CommitParticipant) template.HTML {
|
func (ut *RenderUtils) participantPopupRow(data *user_model.AvatarStackData, participant *user_model.CommitParticipant) template.HTML {
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ img.ui.avatar,
|
|||||||
}
|
}
|
||||||
|
|
||||||
.avatar-stack-names > a.muted,
|
.avatar-stack-names > a.muted,
|
||||||
|
.avatar-stack-names > .avatar-stack-name,
|
||||||
.avatar-stack-names > .avatar-stack-popup-trigger {
|
.avatar-stack-names > .avatar-stack-popup-trigger {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
|
|||||||
Reference in New Issue
Block a user