1
0
mirror of https://github.com/go-gitea/gitea.git synced 2024-12-04 14:46:57 -05:00

Make commit trailer parsing public and add parameterized tests

This commit is contained in:
Kemal Zebari 2024-05-13 22:35:17 -07:00
parent 25a9f121b5
commit 8e3209b09a
3 changed files with 81 additions and 29 deletions

View File

@ -0,0 +1,42 @@
// Copyright 2024 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package util
import (
"errors"
"net/mail"
"strings"
)
var ErrInvalidCommitTrailerValueSyntax = errors.New("syntax error occurred while parsing a commit trailer value")
// ParseCommitTrailerValueWithAuthor parses a commit trailer value that contains author data.
// Note that it only parses the value and does not consider the trailer key i.e. we just
// parse something like the following:
//
// Foo Bar <foobar@example.com>
func ParseCommitTrailerValueWithAuthor(value string) (name, email string, err error) {
value = strings.TrimSpace(value)
if !strings.HasSuffix(value, ">") {
return "", "", ErrInvalidCommitTrailerValueSyntax
}
closedBracketIdx := len(value) - 1
openBracketIdx := strings.LastIndex(value, "<")
if openBracketIdx == -1 {
return "", "", ErrInvalidCommitTrailerValueSyntax
}
email = value[openBracketIdx+1 : closedBracketIdx]
if _, err := mail.ParseAddress(email); err != nil {
return "", "", ErrInvalidCommitTrailerValueSyntax
}
name = strings.TrimSpace(value[:openBracketIdx])
if len(name) == 0 {
return "", "", ErrInvalidCommitTrailerValueSyntax
}
return name, email, nil
}

View File

@ -0,0 +1,37 @@
package util
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestParseCommitTrailerValueWithAuthor(t *testing.T) {
cases := []struct {
input string
shouldBeError bool
expectedName string
expectedEmail string
}{
{"Foo Bar <foobar@example.com", true, "", ""},
{"Foo Bar foobar@example.com>", true, "", ""},
{"Foo Bar <>", true, "", ""},
{"Foo Bar <invalid-email-address>", true, "", ""},
{"<foobar@example.com>", true, "", ""},
{" <foobar@example.com>", true, "", ""},
{"Foo Bar <foobar@example.com>", false, "Foo Bar", "foobar@example.com"},
{" Foo Bar <foobar@example.com>", false, "Foo Bar", "foobar@example.com"},
// Account for edge case where name contains an open bracket.
{" Foo < Bar <foobar@example.com>", false, "Foo < Bar", "foobar@example.com"},
}
for n, c := range cases {
name, email, err := ParseCommitTrailerValueWithAuthor(c.input)
if c.shouldBeError {
assert.Error(t, err, "case %d should be a syntax error", n)
} else {
assert.Equal(t, c.expectedName, name, "case %d should have correct name", n)
assert.Equal(t, c.expectedEmail, email, "case %d should have correct email", n)
}
}
}

View File

@ -8,7 +8,6 @@ import (
"context"
"errors"
"fmt"
"net/mail"
"os"
"strconv"
"strings"
@ -24,6 +23,7 @@ import (
"code.gitea.io/gitea/modules/graceful"
"code.gitea.io/gitea/modules/log"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/util"
)
const (
@ -159,7 +159,7 @@ func getExtendedCommitStats(repo *git.Repository, revision string /*, limit int
// There should be an empty line before we read the commit stats line.
break
}
coAuthorName, coAuthorEmail, err := parseCoAuthorTrailerValue(line)
coAuthorName, coAuthorEmail, err := util.ParseCommitTrailerValueWithAuthor(line)
if err != nil {
continue
}
@ -220,33 +220,6 @@ func getExtendedCommitStats(repo *git.Repository, revision string /*, limit int
return extendedCommitStats, nil
}
var errSyntax = errors.New("syntax error occurred")
func parseCoAuthorTrailerValue(value string) (name, email string, err error) {
value = strings.TrimSpace(value)
if !strings.HasSuffix(value, ">") {
return "", "", errSyntax
}
closedBracketIdx := len(value) - 1
openBracketIdx := strings.LastIndex(value, "<")
if openBracketIdx == -1 {
return "", "", errSyntax
}
email = value[openBracketIdx+1 : closedBracketIdx]
if _, err := mail.ParseAddress(email); err != nil {
return "", "", err
}
name = strings.TrimSpace(value[:openBracketIdx])
if len(name) == 0 {
return "", "", errSyntax
}
return name, email, nil
}
func generateContributorStats(genDone chan struct{}, cache cache.StringCache, cacheKey string, repo *repo_model.Repository, revision string) {
ctx := graceful.GetManager().HammerContext()