diff options
author | Luke T. Shumaker <lukeshu@lukeshu.com> | 2024-04-13 17:51:38 -0600 |
---|---|---|
committer | Luke T. Shumaker <lukeshu@lukeshu.com> | 2024-04-13 17:51:38 -0600 |
commit | 95ebab0baff6fc94ed6214b9603df9c552228b31 (patch) | |
tree | 8a14dfa1a7c5ebc83e5ca90c91668035f7b61e79 | |
parent | 816ace2436b57a709a569bfb03a17236db28f1bf (diff) |
wip
-rw-r--r-- | cmd/generate/httpcache.go | 34 | ||||
-rw-r--r-- | cmd/generate/imworkingon.html.tmpl | 46 | ||||
-rw-r--r-- | cmd/generate/main.go | 4 | ||||
-rw-r--r-- | cmd/generate/src_contribs.go | 97 | ||||
-rw-r--r-- | cmd/generate/src_tags.go | 5 | ||||
-rw-r--r-- | cmd/generate/src_upstreams.go | 7 |
6 files changed, 147 insertions, 46 deletions
diff --git a/cmd/generate/httpcache.go b/cmd/generate/httpcache.go new file mode 100644 index 0000000..7debd0a --- /dev/null +++ b/cmd/generate/httpcache.go @@ -0,0 +1,34 @@ +package main + +import ( + "encoding/json" + "fmt" + "io" + "net/http" +) + +var httpCache = map[string]string{} + +func httpGet(u string) (string, error) { + resp, err := http.Get(u) + if err != nil { + return "", err + } + if resp.StatusCode != http.StatusOK { + return "", fmt.Errorf("unexpected HTTP status: %v", resp.Status) + } + bs, err := io.ReadAll(resp.Body) + if err != nil { + return "", err + } + httpCache[u] = string(bs) + return httpCache[u], nil +} + +func httpGetJSON(u string, out any) error { + str, err := httpGet(u) + if err != nil { + return err + } + return json.Unmarshal([]byte(str), out) +} diff --git a/cmd/generate/imworkingon.html.tmpl b/cmd/generate/imworkingon.html.tmpl index 54d9431..e0ee5a5 100644 --- a/cmd/generate/imworkingon.html.tmpl +++ b/cmd/generate/imworkingon.html.tmpl @@ -47,6 +47,7 @@ } /* tags */ + article.tag { padding: 0.5em 2em; } @@ -55,9 +56,15 @@ } /* contribs */ + article.contrib { display: grid; - grid-template-columns: 25% 75%; + grid-template-columns: 25% 25% 25% 25%; + grid-template-areas: + "uname url url url" + "uname tag tag tag" + "uname submitted status ." + "udesc desc desc desc"; padding: 0; overflow: hidden; } @@ -65,34 +72,44 @@ padding: 0.5em; } article.contrib div.contrib-upstream-name { - grid-row: 1 / 3; - grid-column: 1; - text-align: center; + grid-area: uname; + background-color: #DDDDFF; border-right: solid 1px #8D8DA6; + + text-align: center; font-weight: bold; padding-top: 1em; } article.contrib div.contrib-upstream-desc { - grid-row: 3; - grid-column: 1; + grid-area: udesc; + background-color: #DDDDFF; border-top: solid 1px #8D8DA6; border-right: solid 1px #8D8DA6; } article.contrib div.contrib-urls { - grid-row: 1; - grid-column: 2; + grid-area: url; padding-bottom: 0; } article.contrib div.contrib-tags { - grid-row: 2; - grid-column: 2; + grid-area: tag; padding-top: 0; } + article.contrib div.contrib-submitted { + grid-area: submitted; + background-color: #DDDDFF; + border-top: solid 1px #8D8DA6; + border-right: solid 1px #8D8DA6; + } + article.contrib div.contrib-status { + grid-area: status; + background-color: #DDDDFF; + border-top: solid 1px #8D8DA6; + border-right: solid 1px #8D8DA6; + } article.contrib div.contrib-desc { - grid-row: 3; - grid-column: 2; + grid-area: desc; border-top: solid 1px #8D8DA6; } </style> @@ -110,7 +127,7 @@ </section> <section id="contribs"> <h1>... by contributing...</h1> - {{- range $contrib := .Contributions }} + {{- range $contrib := .Contribs }} {{ $upstream := $contrib | getUpstream }} <article class="contrib"> <div class="contrib-upstream-name"><a href="{{ index $upstream.URLs 0 }}">{{ $upstream.Name }}</a></div> @@ -125,7 +142,8 @@ <a href="#tag-{{ $tag }}">#{{ $tag }}</a> {{/* */}} {{- end }} </div> - <div class="contrib-submitted-at">{{ $contrib.SubmittedAt }}</div> + <div class="contrib-submitted">Submitted: {{ $contrib.SubmittedAt.Format "2006-01-02" }}</div> + <div class="contrib-status">Status: {{ $contrib.Status }}</div> <div class="contrib-desc">{{ $contrib.Desc | md2html }}</div> </article> {{- end }} diff --git a/cmd/generate/main.go b/cmd/generate/main.go index ce5ce0d..cee0f2e 100644 --- a/cmd/generate/main.go +++ b/cmd/generate/main.go @@ -39,7 +39,7 @@ func mainWithError() error { if err != nil { return err } - tags, err := ReadUpstreams("tags.yml") + tags, err := ReadTags("tags.yml") if err != nil { return err } @@ -77,7 +77,7 @@ func mainWithError() error { }); err != nil { return err } - if err := os.WriteFile("plan.html", out.Bytes(), 0666); err != nil { + if err := os.WriteFile("imworkingon.html", out.Bytes(), 0666); err != nil { return err } return nil diff --git a/cmd/generate/src_contribs.go b/cmd/generate/src_contribs.go index eaff24b..b08e18d 100644 --- a/cmd/generate/src_contribs.go +++ b/cmd/generate/src_contribs.go @@ -1,10 +1,8 @@ package main import ( - "encoding/json" "fmt" - "io" - "net/http" + "net/url" "os" "regexp" "strings" @@ -20,21 +18,22 @@ type Contribution struct { Desc string `json:"desc"` SubmittedAt time.Time `json:"submitted-at"` + Status string `json:"status"` } func ReadContribs(filename string) ([]Contribution, error) { bs, err := os.ReadFile(filename) if err != nil { - return nil, err + return nil, fmt.Errorf("contribs: %q: %w", filename, err) } var ret []Contribution if err := yaml.UnmarshalStrict(bs, &ret); err != nil { - return nil, err + return nil, fmt.Errorf("contribs: %q: %w", filename, err) } for i := range ret { contrib := ret[i] if err := contrib.Fill(); err != nil { - return nil, err + return nil, fmt.Errorf("contribs: %q: %w", filename, err) } ret[i] = contrib } @@ -44,7 +43,13 @@ func ReadContribs(filename string) ([]Contribution, error) { func (c *Contribution) Fill() error { var err error if c.SubmittedAt.IsZero() { - c.SubmittedAt, err = c.getSubmittedAt() + c.SubmittedAt, err = c.fetchSubmittedAt() + if err != nil { + return err + } + } + if c.Status == "" { + c.Status, err = c.fetchStatus() if err != nil { return err } @@ -54,46 +59,88 @@ func (c *Contribution) Fill() error { var ( reGitHubPR = regexp.MustCompile(`^https://github.com/([^/?#]+)/([^/?#]+)/pull/([0-9]+)(?:\?[^#]*)?(?:#.*)?$`) + reGitLabMR = regexp.MustCompile(`^https://([^/]+)/([^?#]+)/-/merge_requests/([0-9]+)(?:\?[^#]*)?(?:#.*)?$`) rePiperMailDate = regexp.MustCompile(`^\s*<I>([^<]+)</I>\s*$`) ) -func (c Contribution) getSubmittedAt() (time.Time, error) { +func (c Contribution) fetchStatus() (string, 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 + + urlStr := "https://api.github.com/repos/" + user + "/" + repo + "/pulls/" + prnum + + var obj struct { + State string `json:"state"` } - if resp.StatusCode != http.StatusOK { - return time.Time{}, fmt.Errorf("unexpected HTTP status: %v", resp.Status) + if err := httpGetJSON(urlStr, &obj); err != nil { + return "", err } - jsonBytes, err := io.ReadAll(resp.Body) - if err != nil { - return time.Time{}, err + return obj.State, nil + } + if m := reGitLabMR.FindStringSubmatch(c.URLs[0]); m != nil { + authority := m[1] + projectID := m[2] + mrnum := m[3] + + urlStr := "https://" + authority + "/api/v4/projects/" + url.QueryEscape(projectID) + "/merge_requests/" + mrnum + + var obj struct { + State string `json:"state"` } + if err := httpGetJSON(urlStr, &obj); err != nil { + return "", err + } + return obj.State, nil + } + if len(c.URLs) > 1 { + for _, u := range c.URLs[1:] { + if strings.Contains(u, "/commit/") { + return "merged", nil + } + } + } + return "", fmt.Errorf("idk how to get status for %q", c.URLs[0]) +} + +func (c Contribution) fetchSubmittedAt() (time.Time, error) { + if m := reGitHubPR.FindStringSubmatch(c.URLs[0]); m != nil { + user := m[1] + repo := m[2] + prnum := m[3] + + urlStr := "https://api.github.com/repos/" + user + "/" + repo + "/pulls/" + prnum + var obj struct { CreatedAt time.Time `json:"created_at"` } - if err := json.Unmarshal(jsonBytes, &obj); err != nil { + if err := httpGetJSON(urlStr, &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 m := reGitLabMR.FindStringSubmatch(c.URLs[0]); m != nil { + authority := m[1] + projectID := m[2] + mrnum := m[3] + + urlStr := "https://" + authority + "/api/v4/projects/" + url.QueryEscape(projectID) + "/merge_requests/" + mrnum + + var obj struct { + CreatedAt time.Time `json:"created_at"` } - if resp.StatusCode != http.StatusOK { - return time.Time{}, fmt.Errorf("unexpected HTTP status: %v", resp.Status) + if err := httpGetJSON(urlStr, &obj); err != nil { + return time.Time{}, err } - htmlBytes, err := io.ReadAll(resp.Body) + return obj.CreatedAt, nil + } + if strings.Contains(c.URLs[0], "/pipermail/") { + htmlStr, err := httpGet(c.URLs[0]) if err != nil { return time.Time{}, err } - for _, line := range strings.Split(string(htmlBytes), "\n") { + for _, line := range strings.Split(htmlStr, "\n") { if m := rePiperMailDate.FindStringSubmatch(line); m != nil { return time.Parse(time.UnixDate, m[1]) } diff --git a/cmd/generate/src_tags.go b/cmd/generate/src_tags.go index 497f37e..8dcf554 100644 --- a/cmd/generate/src_tags.go +++ b/cmd/generate/src_tags.go @@ -1,6 +1,7 @@ package main import ( + "fmt" "os" "sigs.k8s.io/yaml" @@ -14,11 +15,11 @@ type TagInfo struct { func ReadTags(filename string) (map[string]TagInfo, error) { bs, err := os.ReadFile(filename) if err != nil { - return nil, err + return nil, fmt.Errorf("tags: %q: %w", filename, err) } var ret map[string]TagInfo if err := yaml.UnmarshalStrict(bs, &ret); err != nil { - return nil, err + return nil, fmt.Errorf("tags: %q: %w", filename, err) } return ret, nil } diff --git a/cmd/generate/src_upstreams.go b/cmd/generate/src_upstreams.go index 1ea7750..791df1b 100644 --- a/cmd/generate/src_upstreams.go +++ b/cmd/generate/src_upstreams.go @@ -2,6 +2,7 @@ package main import ( _ "embed" + "fmt" "net/url" "os" "path" @@ -18,16 +19,16 @@ type Upstream struct { func ReadUpstreams(filename string) ([]Upstream, error) { bs, err := os.ReadFile(filename) if err != nil { - return nil, err + return nil, fmt.Errorf("upstreams: %q: %w", filename, err) } var ret []Upstream if err := yaml.UnmarshalStrict(bs, &ret); err != nil { - return []Upstream{}, err + return nil, fmt.Errorf("upstreams: %q: %w", filename, err) } for i := range ret { upstream := ret[i] if err := upstream.Fill(); err != nil { - return nil, err + return nil, fmt.Errorf("upstreams: %q: %w", filename, err) } ret[i] = upstream } |