-
-
Notifications
You must be signed in to change notification settings - Fork 150
/
coauthors.go
134 lines (110 loc) · 3.36 KB
/
coauthors.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
package main
import (
"bufio"
"fmt"
"github.com/remotemobprogramming/mob/v5/say"
"os"
"path"
"regexp"
"sort"
"strings"
)
// Author is a coauthor "Full Name <email>"
type Author = string
func collectCoauthorsFromWipCommits(file *os.File) []Author {
// Here we parse the SQUASH_MSG file for the list of authors on
// the WIP branch. If this technique later turns out to be
// problematic, an alternative would be to instead fetch the
// authors' list from the git log, using e.g.:
//
// silentgit("log", fmt.Sprintf("%s..", currentBaseBranch), "--reverse", "--pretty=format:%an <%ae>")
//
// For details and background, see https://github.com/remotemobprogramming/mob/issues/81
coauthors := parseCoauthors(file)
say.Debug("Parsed coauthors")
say.Debug(strings.Join(coauthors, ","))
coauthors = removeElementsContaining(coauthors, gitUserEmail())
say.Debug("Parsed coauthors without committer")
say.Debug(strings.Join(coauthors, ","))
coauthors = removeDuplicateValues(coauthors)
say.Debug("Unique coauthors without committer")
say.Debug(strings.Join(coauthors, ","))
sortByLength(coauthors)
say.Debug("Sorted unique coauthors without committer")
say.Debug(strings.Join(coauthors, ","))
return coauthors
}
func parseCoauthors(file *os.File) []Author {
var coauthors []Author
authorOrCoauthorMatcher := regexp.MustCompile("(?i).*(author)+.+<+.*>+")
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
if authorOrCoauthorMatcher.MatchString(line) {
author := stripToAuthor(line)
coauthors = append(coauthors, author)
}
}
return coauthors
}
func stripToAuthor(line string) Author {
return strings.TrimSpace(strings.Join(strings.Split(line, ":")[1:], ""))
}
func sortByLength(slice []string) {
sort.Slice(slice, func(i, j int) bool {
return len(slice[i]) < len(slice[j])
})
}
func removeElementsContaining(slice []string, containsFilter string) []string {
var result []string
for _, entry := range slice {
if !strings.Contains(entry, containsFilter) {
result = append(result, entry)
}
}
return result
}
func removeDuplicateValues(slice []string) []string {
var result []string
keys := make(map[string]bool)
for _, entry := range slice {
if _, value := keys[entry]; !value {
keys[entry] = true
result = append(result, entry)
}
}
return result
}
func appendCoauthorsToSquashMsg(gitDir string) error {
squashMsgPath := path.Join(gitDir, "SQUASH_MSG")
say.Debug("opening " + squashMsgPath)
file, err := os.OpenFile(squashMsgPath, os.O_APPEND|os.O_RDWR, 0644)
if err != nil {
if os.IsNotExist(err) {
say.Debug(squashMsgPath + " does not exist")
// No wip commits, nothing to squash, this isn't really an error
return nil
}
return err
}
defer file.Close()
// read from repo/.git/SQUASH_MSG
coauthors := collectCoauthorsFromWipCommits(file)
if len(coauthors) > 0 {
coauthorSuffix := createCommitMessage(coauthors)
// append to repo/.git/SQUASH_MSG
writer := bufio.NewWriter(file)
writer.WriteString(coauthorSuffix)
err = writer.Flush()
}
return err
}
func createCommitMessage(coauthors []Author) string {
commitMessage := "\n\n"
commitMessage += "# automatically added all co-authors from WIP commits\n"
commitMessage += "# add missing co-authors manually\n"
for _, coauthor := range coauthors {
commitMessage += fmt.Sprintf("Co-authored-by: %s\n", coauthor)
}
return commitMessage
}