aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/git
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/git')
-rw-r--r--pkg/git/git.go91
-rw-r--r--pkg/git/git_test.go48
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
+`