diff options
author | Luke T. Shumaker <lukeshu@lukeshu.com> | 2024-06-10 11:31:53 -0600 |
---|---|---|
committer | Luke T. Shumaker <lukeshu@lukeshu.com> | 2024-06-10 11:31:53 -0600 |
commit | 290354461422fff8c05ef9ce37ba154641e3f8fc (patch) | |
tree | 505e4faa4d6fba1e7d0b4addbda39a4e5beb26fd /cmd/generate | |
parent | 81c8d44fba88dbb049c48363d6b7697224b98a2e (diff) |
imworkingon: Fuss with forge precedence
Diffstat (limited to 'cmd/generate')
-rw-r--r-- | cmd/generate/forge_forgejo.go | 21 | ||||
-rw-r--r-- | cmd/generate/forge_gerrit.go | 32 | ||||
-rw-r--r-- | cmd/generate/forge_github.go | 95 | ||||
-rw-r--r-- | cmd/generate/forge_part_git.go | 80 | ||||
-rw-r--r-- | cmd/generate/forge_part_pipermail.go (renamed from cmd/generate/forge_pipermail.go) | 18 | ||||
-rw-r--r-- | cmd/generate/mailstuff/jwz.md | 4 | ||||
-rw-r--r-- | cmd/generate/src_contribs.go | 51 |
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 |