build: Handle co-authors (ref #3744) (#8708)

The authorship script didn't pick up people who were only ever
"co-authors" of a commit, such as when they wrote stuff which was later
included in a PR by someone else, or added code during code review.

This modified the script to look closer in the commit bodies for
"Co-authored-by:"-lines and adds those found to the set of authors.
This commit is contained in:
Jakob Borg
2022-12-21 22:02:44 +01:00
committed by GitHub
parent ad0044fec8
commit 09f4d865ae
3 changed files with 51 additions and 13 deletions

View File

@@ -235,27 +235,63 @@ var excludeCommits = stringSetFromStrings([]string{
// allAuthors returns the set of authors in the git commit log, except those
// in excluded commits.
func allAuthors() map[string]string {
args := append([]string{"log", "--format=%H %ae %an"})
// Format is hash, email, name, newline, body. The body is indented with
// one space, to differentiate from the hash lines.
args := append([]string{"log", "--format=%H %ae %an%n%w(,1,1)%b"})
cmd := exec.Command("git", args...)
bs, err := cmd.Output()
if err != nil {
log.Fatal("git:", err)
}
coAuthoredPrefix := "Co-authored-by: "
names := make(map[string]string)
skipCommit := false
for _, line := range bytes.Split(bs, []byte{'\n'}) {
fields := strings.SplitN(string(line), " ", 3)
if len(fields) != 3 {
continue
}
hash, email, name := fields[0], fields[1], fields[2]
if excludeCommits.has(hash) {
if len(line) == 0 {
continue
}
if names[email] == "" {
names[email] = name
switch line[0] {
case ' ':
// Look for Co-authored-by: lines in the commit body.
if skipCommit {
continue
}
line = line[1:]
if bytes.HasPrefix(line, []byte(coAuthoredPrefix)) {
// Co-authored-by: Name Name <email@example.com>
line = line[len(coAuthoredPrefix):]
if name, email, ok := strings.Cut(string(line), "<"); ok {
name = strings.TrimSpace(name)
email = strings.Trim(strings.TrimSpace(email), "<>")
if email == "@" {
// GitHub special for users who hide their email.
continue
}
if names[email] == "" {
names[email] = name
}
}
}
default: // hash email name
fields := strings.SplitN(string(line), " ", 3)
if len(fields) != 3 {
continue
}
hash, email, name := fields[0], fields[1], fields[2]
if excludeCommits.has(hash) {
skipCommit = true
continue
}
skipCommit = false
if names[email] == "" {
names[email] = name
}
}
}