summaryrefslogtreecommitdiff
path: root/cmd
diff options
context:
space:
mode:
authorLuke T. Shumaker <lukeshu@lukeshu.com>2024-06-10 11:31:53 -0600
committerLuke T. Shumaker <lukeshu@lukeshu.com>2024-06-10 11:31:53 -0600
commit290354461422fff8c05ef9ce37ba154641e3f8fc (patch)
tree505e4faa4d6fba1e7d0b4addbda39a4e5beb26fd /cmd
parent81c8d44fba88dbb049c48363d6b7697224b98a2e (diff)
imworkingon: Fuss with forge precedenceHEADmain
Diffstat (limited to 'cmd')
-rw-r--r--cmd/generate/forge_forgejo.go21
-rw-r--r--cmd/generate/forge_gerrit.go32
-rw-r--r--cmd/generate/forge_github.go95
-rw-r--r--cmd/generate/forge_part_git.go80
-rw-r--r--cmd/generate/forge_part_pipermail.go (renamed from cmd/generate/forge_pipermail.go)18
-rw-r--r--cmd/generate/mailstuff/jwz.md4
-rw-r--r--cmd/generate/src_contribs.go51
7 files changed, 177 insertions, 124 deletions
diff --git a/cmd/generate/forge_forgejo.go b/cmd/generate/forge_forgejo.go
index 62234b9..84988f2 100644
--- a/cmd/generate/forge_forgejo.go
+++ b/cmd/generate/forge_forgejo.go
@@ -15,10 +15,10 @@ type Forgejo struct {
var _ Forge = Forgejo{}
func (f Forgejo) FetchStatus(urls []string) (string, error) {
- for _, u := range urls {
+ return fetchPerURLStatus(urls, func(u string) (string, error) {
m := reForgejoPR.FindStringSubmatch(u)
if m == nil || m[1] != f.Authority {
- continue
+ return "", nil
}
authority := m[1]
user := m[2]
@@ -49,15 +49,14 @@ func (f Forgejo) FetchStatus(urls []string) (string, error) {
}
return ret, nil
- }
- return "", nil
+ })
}
func (f Forgejo) FetchSubmittedAt(urls []string) (time.Time, error) {
- for _, u := range urls {
+ return fetchPerURLSubmittedAt(urls, func(u string) (time.Time, error) {
m := reForgejoPR.FindStringSubmatch(u)
if m == nil || m[1] != f.Authority {
- continue
+ return time.Time{}, nil
}
authority := m[1]
user := m[2]
@@ -73,15 +72,14 @@ func (f Forgejo) FetchSubmittedAt(urls []string) (time.Time, error) {
return time.Time{}, err
}
return obj.CreatedAt, nil
- }
- return time.Time{}, nil
+ })
}
func (f Forgejo) FetchLastUpdated(urls []string) (time.Time, User, error) {
- for _, u := range urls {
+ return fetchPerURLLastUpdated(urls, func(u string) (time.Time, User, error) {
m := reForgejoPR.FindStringSubmatch(u)
if m == nil || m[1] != f.Authority {
- continue
+ return time.Time{}, User{}, nil
}
authority := m[1]
user := m[2]
@@ -181,6 +179,5 @@ func (f Forgejo) FetchLastUpdated(urls []string) (time.Time, User, error) {
}
return retUpdatedAt, retUser, nil
- }
- return time.Time{}, User{}, nil
+ })
}
diff --git a/cmd/generate/forge_gerrit.go b/cmd/generate/forge_gerrit.go
index 1e6e073..31f2256 100644
--- a/cmd/generate/forge_gerrit.go
+++ b/cmd/generate/forge_gerrit.go
@@ -62,15 +62,10 @@ var _ Forge = Gerrit{}
var reGoogleGerritCL = regexp.MustCompile(`https://([a-z]+-review\.googlesource\.com)/c/([^?#]+)/\+/([0-9]+)(?:\?[^#]*)?(?:#.*)?$`)
func (Gerrit) FetchStatus(urls []string) (string, error) {
- for _, u := range urls {
- if reGitHubPR.MatchString(u) {
- return "", nil
- }
- }
- for _, u := range urls {
+ return fetchPerURLStatus(urls, func(u string) (string, error) {
m := reGoogleGerritCL.FindStringSubmatch(u)
if m == nil {
- continue
+ return "", nil
}
authority := m[1]
projectID := m[2]
@@ -93,20 +88,15 @@ func (Gerrit) FetchStatus(urls []string) (string, error) {
case "ABANDONED":
return "closed", nil
}
- }
- return "", nil
+ return "", nil
+ })
}
func (Gerrit) FetchSubmittedAt(urls []string) (time.Time, error) {
- for _, u := range urls {
- if reGitHubPR.MatchString(u) {
- return time.Time{}, nil
- }
- }
- for _, u := range urls {
+ return fetchPerURLSubmittedAt(urls, func(u string) (time.Time, error) {
m := reGoogleGerritCL.FindStringSubmatch(u)
if m == nil {
- continue
+ return time.Time{}, nil
}
authority := m[1]
projectID := m[2]
@@ -121,15 +111,14 @@ func (Gerrit) FetchSubmittedAt(urls []string) (time.Time, error) {
return time.Time{}, err
}
return obj.Created.Val, nil
- }
- return time.Time{}, nil
+ })
}
func (Gerrit) FetchLastUpdated(urls []string) (time.Time, User, error) {
- for _, u := range urls {
+ return fetchPerURLLastUpdated(urls, func(u string) (time.Time, User, error) {
m := reGoogleGerritCL.FindStringSubmatch(u)
if m == nil {
- continue
+ return time.Time{}, User{}, nil
}
authority := m[1]
projectID := m[2]
@@ -165,6 +154,5 @@ func (Gerrit) FetchLastUpdated(urls []string) (time.Time, User, error) {
}
}
return retUpdatedAt, retUser, nil
- }
- return time.Time{}, User{}, nil
+ })
}
diff --git a/cmd/generate/forge_github.go b/cmd/generate/forge_github.go
index d29e3f7..9f475a3 100644
--- a/cmd/generate/forge_github.go
+++ b/cmd/generate/forge_github.go
@@ -7,10 +7,7 @@ import (
"time"
)
-var (
- reGitHubPR = regexp.MustCompile(`^https://github\.com/([^/?#]+)/([^/?#]+)/pull/([0-9]+)(?:\?[^#]*)?(?:#.*)?$`)
- reGitHubCommit = regexp.MustCompile(`^https://github\.com/([^/?#]+)/([^/?#]+)/commit/([0-9a-f]+)(?:\?[^#]*)?(?:#.*)?$`)
-)
+var reGitHubPR = regexp.MustCompile(`^https://github\.com/([^/?#]+)/([^/?#]+)/pull/([0-9]+)(?:\?[^#]*)?(?:#.*)?$`)
func githubPagination(i int) url.Values {
params := make(url.Values)
@@ -23,11 +20,15 @@ type GitHub struct{}
var _ Forge = GitHub{}
func (GitHub) FetchStatus(urls []string) (string, error) {
- // PR
for _, u := range urls {
+ if reGoogleGerritCL.MatchString(u) {
+ return "", nil
+ }
+ }
+ return fetchPerURLStatus(urls, func(u string) (string, error) {
m := reGitHubPR.FindStringSubmatch(u)
if m == nil {
- continue
+ return "", nil
}
user := m[1]
repo := m[2]
@@ -57,40 +58,14 @@ func (GitHub) FetchStatus(urls []string) (string, error) {
}
return ret, nil
- }
- // Commits from a non-PR
- var gitURL string
- var gitCommits []string
- for _, u := range urls {
- if m := reGitHubCommit.FindStringSubmatch(u); m != nil {
- user := m[1]
- repo := m[2]
- hash := m[3]
-
- gitURL = "https://github.com/" + user + "/" + repo
- gitCommits = append(gitCommits, hash)
- }
- }
- if len(gitCommits) > 0 {
- ret := statusMerged
- tag, err := getGitTagThatContainsAll(gitURL, gitCommits...)
- if err != nil {
- return "", err
- }
- if tag != "" {
- ret = fmt.Sprintf(statusReleasedFmt, tag)
- }
- return ret, nil
- }
- // Nope
- return "", nil
+ })
}
func (GitHub) FetchSubmittedAt(urls []string) (time.Time, error) {
- for _, u := range urls {
+ return fetchPerURLSubmittedAt(urls, func(u string) (time.Time, error) {
m := reGitHubPR.FindStringSubmatch(u)
if m == nil {
- continue
+ return time.Time{}, nil
}
user := m[1]
repo := m[2]
@@ -105,16 +80,19 @@ func (GitHub) FetchSubmittedAt(urls []string) (time.Time, error) {
return time.Time{}, err
}
return obj.CreatedAt, nil
- }
- return time.Time{}, nil
+ })
}
func (GitHub) FetchLastUpdated(urls []string) (time.Time, User, error) {
- // PR
for _, u := range urls {
+ if reGoogleGerritCL.MatchString(u) {
+ return time.Time{}, User{}, nil
+ }
+ }
+ return fetchPerURLLastUpdated(urls, func(u string) (time.Time, User, error) {
m := reGitHubPR.FindStringSubmatch(u)
if m == nil {
- continue
+ return time.Time{}, User{}, nil
}
user := m[1]
repo := m[2]
@@ -213,42 +191,5 @@ func (GitHub) FetchLastUpdated(urls []string) (time.Time, User, error) {
}
return retUpdatedAt, retUser, nil
- }
- // Commits from a non-PR
- {
- var ret time.Time
- for _, u := range urls {
- if m := reGitHubCommit.FindStringSubmatch(u); m != nil {
- user := m[1]
- repo := m[2]
- hash := m[3]
-
- urlStr := "https://api.github.com/repos/" + user + "/" + repo + "/commits/" + hash
- var obj struct {
- Commit struct {
- Author struct {
- Date time.Time `json:"date"`
- } `json:"author"`
- Committer struct {
- Date time.Time `json:"date"`
- } `json:"committer"`
- } `json:"commit"`
- }
- if err := httpGetJSON(urlStr, nil, &obj); err != nil {
- return time.Time{}, User{}, err
- }
- if obj.Commit.Author.Date.After(ret) {
- ret = obj.Commit.Author.Date
- }
- if obj.Commit.Committer.Date.After(ret) {
- ret = obj.Commit.Committer.Date
- }
- }
- }
- if ret.IsZero() {
- return time.Time{}, User{}, nil
- }
- }
- // Nope
- return time.Time{}, User{}, nil
+ })
}
diff --git a/cmd/generate/forge_part_git.go b/cmd/generate/forge_part_git.go
new file mode 100644
index 0000000..5288286
--- /dev/null
+++ b/cmd/generate/forge_part_git.go
@@ -0,0 +1,80 @@
+package main
+
+import (
+ "fmt"
+ "regexp"
+ "time"
+)
+
+var reGitHubCommit = regexp.MustCompile(`^https://github\.com/([^/?#]+)/([^/?#]+)/commit/([0-9a-f]+)(?:\?[^#]*)?(?:#.*)?$`)
+
+type PartGit struct{}
+
+var _ Forge = PartGit{}
+
+func (PartGit) FetchStatus(urls []string) (string, error) {
+ var gitURL string
+ var gitCommits []string
+ for _, u := range urls {
+ if m := reGitHubCommit.FindStringSubmatch(u); m != nil {
+ user := m[1]
+ repo := m[2]
+ hash := m[3]
+
+ gitURL = "https://github.com/" + user + "/" + repo
+ gitCommits = append(gitCommits, hash)
+ }
+ }
+ if len(gitCommits) == 0 {
+ return "", nil
+ }
+ ret := statusMerged
+ tag, err := getGitTagThatContainsAll(gitURL, gitCommits...)
+ if err != nil {
+ return "", err
+ }
+ if tag != "" {
+ ret = fmt.Sprintf(statusReleasedFmt, tag)
+ }
+ return ret, nil
+}
+
+func (PartGit) FetchSubmittedAt(urls []string) (time.Time, error) {
+ return time.Time{}, nil
+}
+
+func (PartGit) FetchLastUpdated(urls []string) (time.Time, User, error) {
+ var ret time.Time
+ for _, u := range urls {
+ if m := reGitHubCommit.FindStringSubmatch(u); m != nil {
+ user := m[1]
+ repo := m[2]
+ hash := m[3]
+
+ urlStr := "https://api.github.com/repos/" + user + "/" + repo + "/commits/" + hash
+ var obj struct {
+ Commit struct {
+ Author struct {
+ Date time.Time `json:"date"`
+ } `json:"author"`
+ Committer struct {
+ Date time.Time `json:"date"`
+ } `json:"committer"`
+ } `json:"commit"`
+ }
+ if err := httpGetJSON(urlStr, nil, &obj); err != nil {
+ return time.Time{}, User{}, err
+ }
+ if obj.Commit.Author.Date.After(ret) {
+ ret = obj.Commit.Author.Date
+ }
+ if obj.Commit.Committer.Date.After(ret) {
+ ret = obj.Commit.Committer.Date
+ }
+ }
+ }
+ if ret.IsZero() {
+ return time.Time{}, User{}, nil
+ }
+ return time.Time{}, User{}, nil
+}
diff --git a/cmd/generate/forge_pipermail.go b/cmd/generate/forge_part_pipermail.go
index ccc58f0..af6a009 100644
--- a/cmd/generate/forge_pipermail.go
+++ b/cmd/generate/forge_part_pipermail.go
@@ -21,15 +21,15 @@ var (
rePiperMailReply = regexp.MustCompile(`^\s*<LINK REL="made" HREF="(.*)">\s*$`)
)
-type PiperMail struct{}
+type PartPiperMail struct{}
-var _ Forge = PiperMail{}
+var _ Forge = PartPiperMail{}
-func (PiperMail) FetchStatus(urls []string) (string, error) {
+func (PartPiperMail) FetchStatus(urls []string) (string, error) {
return "", nil
}
-func (PiperMail) FetchSubmittedAt(urls []string) (time.Time, error) {
+func (PartPiperMail) FetchSubmittedAt(urls []string) (time.Time, error) {
for _, u := range urls {
if !rePiperMailMessage.MatchString(u) {
continue
@@ -47,7 +47,7 @@ func (PiperMail) FetchSubmittedAt(urls []string) (time.Time, error) {
return time.Time{}, nil
}
-func (PiperMail) nextMonth(ym string) string {
+func (PartPiperMail) nextMonth(ym string) string {
yStr, mStr, ok := strings.Cut(ym, "-")
if !ok {
panic(fmt.Errorf("invalid year-month: %q", ym))
@@ -83,7 +83,7 @@ func (PiperMail) nextMonth(ym string) string {
}
}
-func (p PiperMail) threadLen(thread *mailstuff.ThreadedMessage) int {
+func (p PartPiperMail) threadLen(thread *mailstuff.ThreadedMessage) int {
if thread == nil {
return 0
}
@@ -98,7 +98,7 @@ func (p PiperMail) threadLen(thread *mailstuff.ThreadedMessage) int {
return ret
}
-func (p PiperMail) FetchLastUpdated(urls []string) (time.Time, User, error) {
+func (p PartPiperMail) FetchLastUpdated(urls []string) (time.Time, User, error) {
for _, u := range urls {
m := rePiperMailMessage.FindStringSubmatch(u)
if m == nil {
@@ -134,7 +134,7 @@ func (p PiperMail) FetchLastUpdated(urls []string) (time.Time, User, error) {
mboxGzStr, err := httpGet(uBase+ym+".txt.gz", nil)
if err != nil {
- if (ym == uYM || !errors.Is(err, os.ErrNotExist)) {
+ if ym == uYM || !errors.Is(err, os.ErrNotExist) {
return time.Time{}, User{}, fmt.Errorf("could not fetch mbox for %s: %w", ym, err)
}
break
@@ -149,7 +149,7 @@ func (p PiperMail) FetchLastUpdated(urls []string) (time.Time, User, error) {
return time.Time{}, User{}, fmt.Errorf("could not parse mbox: %w", err)
}
if err := gzReader.Close(); err != nil {
- return time.Time{}, User{}, fmt.Errorf("close gz: %w", err)
+ return time.Time{}, User{}, fmt.Errorf("close gz: %w", err)
}
mbox = append(mbox, _mbox...)
_, messages := mailstuff.ThreadMessages(mbox)
diff --git a/cmd/generate/mailstuff/jwz.md b/cmd/generate/mailstuff/jwz.md
index 54f0a45..91e03f5 100644
--- a/cmd/generate/mailstuff/jwz.md
+++ b/cmd/generate/mailstuff/jwz.md
@@ -11,11 +11,11 @@ feedback valuable.
You write that the algorithm in RFC 5256 is merely a "restating" of
your algorithm, but I noticed 3 (minor) differences:
-
+
1. In your step 1.C, the RFC says to check whether this would create a
loop, and if it would to skip creating the link; your version only
says to perform this check in step 1.B.
-
+
2. The RFC says to sort the messages by date between your steps 4 and
5; that is: when grouping by subject, containers in the root set
should be processed in date-order (you do not specify an order),
diff --git a/cmd/generate/src_contribs.go b/cmd/generate/src_contribs.go
index 39bc04b..5694156 100644
--- a/cmd/generate/src_contribs.go
+++ b/cmd/generate/src_contribs.go
@@ -108,15 +108,31 @@ type Forge interface {
}
var forges = []Forge{
+ // precedence only matters for .FetchStatus.
+
// highest precedence
- Gerrit{}, // must be higher than GitHub because of golang
+ Gerrit{},
GitHub{},
GitLab{},
Forgejo{"codeberg.org"},
- PiperMail{},
+ PartPiperMail{},
+ PartGit{},
// lowest precedence
}
+func fetchPerURLStatus(urls []string, perURL func(string) (string, error)) (string, error) {
+ for _, u := range urls {
+ status, err := perURL(u)
+ if err != nil {
+ return "", err
+ }
+ if status != "" {
+ return status, nil
+ }
+ }
+ return "", nil
+}
+
func (c Contribution) fetchStatus() (string, error) {
for _, forge := range forges {
status, err := forge.FetchStatus(c.URLs)
@@ -130,6 +146,20 @@ func (c Contribution) fetchStatus() (string, error) {
return "", fmt.Errorf("idk how to get status for %q", c.URLs[0])
}
+func fetchPerURLSubmittedAt(urls []string, perURL func(string) (time.Time, error)) (time.Time, error) {
+ var ret time.Time
+ for _, u := range urls {
+ submittedAt, err := perURL(u)
+ if err != nil {
+ return time.Time{}, err
+ }
+ if !submittedAt.IsZero() && (ret.IsZero() || submittedAt.Before(ret)) {
+ ret = submittedAt
+ }
+ }
+ return ret, nil
+}
+
func (c Contribution) fetchSubmittedAt() (time.Time, error) {
var ret time.Time
for _, forge := range forges {
@@ -155,6 +185,23 @@ func withinOneSecond(a, b time.Time) bool {
return d <= time.Second
}
+func fetchPerURLLastUpdated(urls []string, perURL func(string) (time.Time, User, error)) (time.Time, User, error) {
+ var ret struct {
+ time.Time
+ User
+ }
+ for _, u := range urls {
+ updatedAt, updatedBy, err := perURL(u)
+ if err != nil {
+ return time.Time{}, User{}, err
+ }
+ if !updatedAt.IsZero() && (ret.Time.IsZero() || updatedAt.After(ret.Time)) {
+ ret.Time, ret.User = updatedAt, updatedBy
+ }
+ }
+ return ret.Time, ret.User, nil
+}
+
func (c Contribution) fetchLastUpdated() (time.Time, User, error) {
var ret struct {
time.Time