diff options
Diffstat (limited to 'pkg/git')
| -rw-r--r-- | pkg/git/git.go | 91 | ||||
| -rw-r--r-- | pkg/git/git_test.go | 48 |
2 files changed, 139 insertions, 0 deletions
diff --git a/pkg/git/git.go b/pkg/git/git.go index 133f6ef9b..9930b449a 100644 --- a/pkg/git/git.go +++ b/pkg/git/git.go @@ -5,9 +5,13 @@ package git import ( + "bufio" "bytes" "fmt" + "io" + "net/mail" "os" + "os/exec" "regexp" "strings" "time" @@ -125,6 +129,93 @@ func ListRecentCommits(dir, baseCommit string) ([]string, error) { return strings.Split(string(output), "\n"), nil } +type FixCommit struct { + Tag string + Title string +} + +// ExtractFixTagsFromCommits extracts fixing tags for bugs from git log. +// Given email = "user@domain.com", it searches for tags of the form "user+tag@domain.com" +// and return pairs {tag, commit title}. +func ExtractFixTagsFromCommits(dir, baseCommit, email string) ([]FixCommit, error) { + since := time.Now().Add(-time.Hour * 24 * 365).Format("01-02-2006") + cmd := exec.Command("git", "log", "--no-merges", "--since", since, baseCommit) + cmd.Dir = dir + stdout, err := cmd.StdoutPipe() + if err != nil { + return nil, err + } + if err := cmd.Start(); err != nil { + return nil, err + } + defer cmd.Wait() + return extractFixTags(stdout, email) +} + +func extractFixTags(r io.Reader, email string) ([]FixCommit, error) { + user, domain, err := splitEmail(email) + if err != nil { + return nil, err + } + var ( + s = bufio.NewScanner(r) + commits []FixCommit + commitTitle = "" + commitStart = []byte("commit ") + bodyPrefix = []byte(" ") + userBytes = []byte(user + "+") + domainBytes = []byte(domain) + ) + for s.Scan() { + ln := s.Bytes() + if bytes.HasPrefix(ln, commitStart) { + commitTitle = "" + continue + } + if !bytes.HasPrefix(ln, bodyPrefix) { + continue + } + ln = ln[len(bodyPrefix):] + if len(ln) == 0 { + continue + } + if commitTitle == "" { + commitTitle = string(ln) + continue + } + userPos := bytes.Index(ln, userBytes) + if userPos == -1 { + continue + } + domainPos := bytes.Index(ln[userPos+len(userBytes)+1:], domainBytes) + if domainPos == -1 { + continue + } + startPos := userPos + len(userBytes) + endPos := userPos + len(userBytes) + domainPos + 1 + tag := string(ln[startPos:endPos]) + commits = append(commits, FixCommit{tag, commitTitle}) + } + return commits, s.Err() +} + +func splitEmail(email string) (user, domain string, err error) { + addr, err := mail.ParseAddress(email) + if err != nil { + return "", "", err + } + at := strings.IndexByte(addr.Address, '@') + if at == -1 { + return "", "", fmt.Errorf("no @ in email address") + } + user = addr.Address[:at] + domain = addr.Address[at:] + if plus := strings.IndexByte(user, '+'); plus != -1 { + user = user[:plus] + } + return +} + // CanonicalizeCommit returns commit title that can be used when checking // if a particular commit is present in a git tree. // Some trees add prefixes to commit titles during backporting, diff --git a/pkg/git/git_test.go b/pkg/git/git_test.go index 3cc1300dd..8e23e84b2 100644 --- a/pkg/git/git_test.go +++ b/pkg/git/git_test.go @@ -4,6 +4,8 @@ package git import ( + "reflect" + "strings" "testing" ) @@ -72,3 +74,49 @@ func TestCheckBranch(t *testing.T) { } } } + +func TestExtractFixTags(t *testing.T) { + commits, err := extractFixTags(strings.NewReader(extractFixTagsInput), extractFixTagsEmail) + if err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(commits, extractFixTagsOutput) { + t.Fatalf("got : %+v\twant: %+v", commits, extractFixTagsOutput) + } +} + +const extractFixTagsEmail = "\"syzbot\" <syzbot@my.mail.com>" + +var extractFixTagsOutput = []FixCommit{ + {"8e4090902540da8c6e8f", "dashboard/app: bump max repros per bug to 10"}, + {"8e4090902540da8c6e8f", "executor: remove dead code"}, + {"a640a0fc325c29c3efcb", "executor: remove dead code"}, + {"8e4090902540da8c6e8fa640a0fc325c29c3efcb", "pkg/csource: fix string escaping bug"}, +} + +var extractFixTagsInput = ` +commit 73aba437a774237b1130837b856f3b40b3ec3bf0 (HEAD -> master, origin/master) +Author: me <foo@bar.com> +Date: Fri Dec 22 19:59:56 2017 +0100 + + dashboard/app: bump max repros per bug to 10 + + Reported-by: syzbot+8e4090902540da8c6e8f@my.mail.com + +commit 26cd53f078db858a6ccca338e13e7f4d1d291c22 +Author: me <foo@bar.com> +Date: Fri Dec 22 13:42:27 2017 +0100 + + executor: remove dead code + + Reported-by: syzbot+8e4090902540da8c6e8f@my.mail.com + Reported-by: syzbot <syzbot+a640a0fc325c29c3efcb@my.mail.com> + +commit 7b62abdb0abadbaf7b3f3a23ab4d78485fbf9059 +Author: Dmitry Vyukov <dvyukov@google.com> +Date: Fri Dec 22 11:59:09 2017 +0100 + + pkg/csource: fix string escaping bug + + Reported-and-tested-by: syzbot+8e4090902540da8c6e8fa640a0fc325c29c3efcb@my.mail.com +` |
