summaryrefslogtreecommitdiff
path: root/cmd/generate/src_contribs.go
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/generate/src_contribs.go')
-rw-r--r--cmd/generate/src_contribs.go103
1 files changed, 103 insertions, 0 deletions
diff --git a/cmd/generate/src_contribs.go b/cmd/generate/src_contribs.go
new file mode 100644
index 0000000..eaff24b
--- /dev/null
+++ b/cmd/generate/src_contribs.go
@@ -0,0 +1,103 @@
+package main
+
+import (
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "os"
+ "regexp"
+ "strings"
+ "time"
+
+ "sigs.k8s.io/yaml"
+)
+
+type Contribution struct {
+ URLs []string `json:"urls"`
+ Tags []string `json:"tags"`
+ SponsoredBy string `json:"sponsored-by"`
+ Desc string `json:"desc"`
+
+ SubmittedAt time.Time `json:"submitted-at"`
+}
+
+func ReadContribs(filename string) ([]Contribution, error) {
+ bs, err := os.ReadFile(filename)
+ if err != nil {
+ return nil, err
+ }
+ var ret []Contribution
+ if err := yaml.UnmarshalStrict(bs, &ret); err != nil {
+ return nil, err
+ }
+ for i := range ret {
+ contrib := ret[i]
+ if err := contrib.Fill(); err != nil {
+ return nil, err
+ }
+ ret[i] = contrib
+ }
+ return ret, nil
+}
+
+func (c *Contribution) Fill() error {
+ var err error
+ if c.SubmittedAt.IsZero() {
+ c.SubmittedAt, err = c.getSubmittedAt()
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+var (
+ reGitHubPR = regexp.MustCompile(`^https://github.com/([^/?#]+)/([^/?#]+)/pull/([0-9]+)(?:\?[^#]*)?(?:#.*)?$`)
+ rePiperMailDate = regexp.MustCompile(`^\s*<I>([^<]+)</I>\s*$`)
+)
+
+func (c Contribution) getSubmittedAt() (time.Time, error) {
+ if m := reGitHubPR.FindStringSubmatch(c.URLs[0]); m != nil {
+ user := m[1]
+ repo := m[2]
+ prnum := m[3]
+ resp, err := http.Get("https://api.github.com/repos/" + user + "/" + repo + "/pulls/" + prnum)
+ if err != nil {
+ return time.Time{}, err
+ }
+ if resp.StatusCode != http.StatusOK {
+ return time.Time{}, fmt.Errorf("unexpected HTTP status: %v", resp.Status)
+ }
+ jsonBytes, err := io.ReadAll(resp.Body)
+ if err != nil {
+ return time.Time{}, err
+ }
+ var obj struct {
+ CreatedAt time.Time `json:"created_at"`
+ }
+ if err := json.Unmarshal(jsonBytes, &obj); err != nil {
+ return time.Time{}, err
+ }
+ return obj.CreatedAt, nil
+ }
+ if strings.Contains(c.URLs[0], "/pipermail/") {
+ resp, err := http.Get(c.URLs[0])
+ if err != nil {
+ return time.Time{}, err
+ }
+ if resp.StatusCode != http.StatusOK {
+ return time.Time{}, fmt.Errorf("unexpected HTTP status: %v", resp.Status)
+ }
+ htmlBytes, err := io.ReadAll(resp.Body)
+ if err != nil {
+ return time.Time{}, err
+ }
+ for _, line := range strings.Split(string(htmlBytes), "\n") {
+ if m := rePiperMailDate.FindStringSubmatch(line); m != nil {
+ return time.Parse(time.UnixDate, m[1])
+ }
+ }
+ }
+ return time.Time{}, fmt.Errorf("idk how to get timestamps for %q", c.URLs[0])
+}