diff options
Diffstat (limited to 'cmd/generate/src_contribs.go')
-rw-r--r-- | cmd/generate/src_contribs.go | 400 |
1 files changed, 0 insertions, 400 deletions
diff --git a/cmd/generate/src_contribs.go b/cmd/generate/src_contribs.go deleted file mode 100644 index 6db6764..0000000 --- a/cmd/generate/src_contribs.go +++ /dev/null @@ -1,400 +0,0 @@ -package main - -import ( - "fmt" - "net/url" - "os" - "regexp" - "strings" - "time" - - "sigs.k8s.io/yaml" -) - -type User struct { - Name string `json:"name"` - URL string `json:"url"` -} - -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"` - LastUpdatedAt time.Time `json:"last-updated-at"` - LastUpdatedBy User `json:"last-updated-by"` - Status string `json:"status"` - - StatusClass string `json:"-"` -} - -func ReadContribs(filename string) ([]Contribution, error) { - bs, err := os.ReadFile(filename) - if err != nil { - return nil, fmt.Errorf("contribs: %q: %w", filename, err) - } - var ret []Contribution - if err := yaml.UnmarshalStrict(bs, &ret); err != nil { - return nil, fmt.Errorf("contribs: %q: %w", filename, err) - } - for i := range ret { - contrib := ret[i] - if err := contrib.Fill(); err != nil { - return nil, fmt.Errorf("contribs: %q: %w", filename, err) - } - ret[i] = contrib - } - return ret, nil -} - -func (c *Contribution) Fill() error { - var err error - if c.SubmittedAt.IsZero() { - c.SubmittedAt, err = c.fetchSubmittedAt() - if err != nil { - return err - } - } - if c.LastUpdatedAt.IsZero() { - c.LastUpdatedAt, c.LastUpdatedBy, err = c.fetchLastUpdated() - if err != nil { - return err - } - } - if c.Status == "" { - c.Status, err = c.fetchStatus() - if err != nil { - return err - } - } - c.StatusClass, err = classifyStatus(c.Status) - if err != nil { - return err - } - for _, u := range c.URLs { - if m := reGoLangGerritCL.FindStringSubmatch(u); m != nil { - c.URLs = append(c.URLs, "https://golang.org/cl/"+m[1]) - } - } - return nil -} - -func classifyStatus(status string) (string, error) { - switch { - case strings.Contains(status, "released") || strings.Contains(status, "deployed"): - return "released", nil - case strings.Contains(status, "merged"): - return "merged", nil - case strings.Contains(status, "open"): - return "open", nil - case strings.Contains(status, "closed") || strings.Contains(status, "locked"): - return "closed", nil - default: - return "", fmt.Errorf("unrecognized status string: %q", status) - } -} - -var ( - reGoLangGerritCL = regexp.MustCompile(`https://go-review\.googlesource\.com/c/[^/?#]+/\+/([0-9]+)(?:\?[^#]*)?(?:#.*)?$`) - reGitHubPR = regexp.MustCompile(`^https://github\.com/([^/?#]+)/([^/?#]+)/pull/([0-9]+)(?:\?[^#]*)?(?:#.*)?$`) - reGitHubCommit = regexp.MustCompile(`^https://github\.com/([^/?#]+)/([^/?#]+)/commit/([0-9a-f]+)(?:\?[^#]*)?(?:#.*)?$`) - reGitLabMR = regexp.MustCompile(`^https://([^/]+)/([^?#]+)/-/merge_requests/([0-9]+)(?:\?[^#]*)?(?:#.*)?$`) - rePiperMailDate = regexp.MustCompile(`^\s*<I>([^<]+)</I>\s*$`) -) - -const ( - statusOpen = "open" - statusMerged = "merged, not yet in a release" - statusReleasedFmt = "merged, released in %s" -) - -func (c Contribution) fetchStatus() (string, 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 { - // State values are "open" and "closed". - State string `json:"state"` - Merged bool `json:"merged"` - MergeCommitSha string `json:"merge_commit_sha"` - } - if err := httpGetJSON(urlStr, &obj); err != nil { - return "", err - } - ret := obj.State - if obj.Merged { - ret = statusMerged - tag, err := getGitTagThatContainsAll("https://github.com/"+user+"/"+repo, obj.MergeCommitSha) - if err != nil { - return "", err - } - if tag != "" { - ret = fmt.Sprintf(statusReleasedFmt, tag) - } - } - - return ret, 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 values are "opened", "closed", "locked", and "merged". - State string `json:"state"` - MergeCommitSha string `json:"merge_commit_sha"` - SquashCommitSha string `json:"squash_commit_sha"` - } - if err := httpGetJSON(urlStr, &obj); err != nil { - return "", err - } - - ret := obj.State - if ret == "opened" { - ret = statusOpen - } - - if ret == "merged" { - ret = statusMerged - var mergeCommit string - if obj.MergeCommitSha != "" { - mergeCommit = obj.MergeCommitSha - } - if obj.SquashCommitSha != "" { - mergeCommit = obj.SquashCommitSha - } - if mergeCommit != "" { - tag, err := getGitTagThatContainsAll("https://"+authority+"/"+projectID+".git", mergeCommit) - if err != nil { - return "", err - } - if tag != "" { - ret = fmt.Sprintf(statusReleasedFmt, tag) - } - } - } - - return ret, nil - } - if len(c.URLs) > 1 { - var gitURL string - var gitCommits []string - for _, u := range c.URLs[1:] { - 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 - } - } - 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 := httpGetJSON(urlStr, &obj); err != nil { - return time.Time{}, err - } - return obj.CreatedAt, 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 { - CreatedAt time.Time `json:"created_at"` - } - if err := httpGetJSON(urlStr, &obj); err != nil { - return time.Time{}, err - } - 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(htmlStr, "\n") { - if m := rePiperMailDate.FindStringSubmatch(line); m != nil { - return time.Parse(time.UnixDate, m[1]) - } - } - } - return time.Time{}, fmt.Errorf("idk how to get created timestamp for %q", c.URLs[0]) -} - -func (c Contribution) fetchLastUpdated() (time.Time, User, error) { - if m := reGitHubPR.FindStringSubmatch(c.URLs[0]); m != nil { - user := m[1] - repo := m[2] - prnum := m[3] - - var obj struct { - UpdatedAt time.Time `json:"updated_at"` - MergedAt time.Time `json:"merged_at"` - MergedBy struct { - Login string `json:"login"` - HTMLURL string `json:"html_url"` - } `json:"merged_by"` - } - if err := httpGetJSON("https://api.github.com/repos/"+user+"/"+repo+"/pulls/"+prnum, &obj); err != nil { - return time.Time{}, User{}, err - } - - retUpdatedAt := obj.UpdatedAt - var retUser User - - if obj.MergedAt == retUpdatedAt { - retUser.Name = obj.MergedBy.Login - retUser.URL = obj.MergedBy.HTMLURL - } - if retUser == (User{}) { - // "normal" comments - var comments []struct { - UpdatedAt time.Time `json:"updated_at"` - User struct { - Login string `json:"login"` - HTMLURL string `json:"html_url"` - } `json:"user"` - } - if err := httpGetPaginatedJSON("https://api.github.com/repos/"+user+"/"+repo+"/issues/"+prnum+"/comments", &comments, githubPagination); err != nil { - return time.Time{}, User{}, err - } - for _, comment := range comments { - if comment.UpdatedAt == retUpdatedAt || comment.UpdatedAt.Add(1*time.Second) == retUpdatedAt { - retUser.Name = comment.User.Login - retUser.URL = comment.User.HTMLURL - break - } - } - } - if retUser == (User{}) { - // comments on a specific part of the diff - var reviewComments []struct { - UpdatedAt time.Time `json:"updated_at"` - User struct { - Login string `json:"login"` - HTMLURL string `json:"html_url"` - } `json:"user"` - } - if err := httpGetPaginatedJSON("https://api.github.com/repos/"+user+"/"+repo+"/pulls/"+prnum+"/comments", &reviewComments, githubPagination); err != nil { - return time.Time{}, User{}, err - } - for _, comment := range reviewComments { - if comment.UpdatedAt == retUpdatedAt { - retUser.Name = comment.User.Login - retUser.URL = comment.User.HTMLURL - break - } - } - } - if retUser == (User{}) { - var events []struct { - CreatedAt time.Time `json:"created_at"` - Actor struct { - Login string `json:"login"` - HTMLURL string `json:"html_url"` - } `json:"actor"` - } - if err := httpGetJSON("https://api.github.com/repos/"+user+"/"+repo+"/issues/"+prnum+"/events", &events); err != nil { - return time.Time{}, User{}, err - } - for _, event := range events { - if event.CreatedAt == retUpdatedAt { - retUser.Name = event.Actor.Login - retUser.URL = event.Actor.HTMLURL - break - } - } - } - - return retUpdatedAt, retUser, 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 { - UpdatedAt time.Time `json:"updated_at"` - } - if err := httpGetJSON(urlStr, &obj); err != nil { - return time.Time{}, User{}, err - } - return obj.UpdatedAt, User{}, nil - } - - var ret time.Time - if len(c.URLs) > 1 { - for _, u := range c.URLs[1:] { - 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, &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 ret, User{}, nil - } - - return time.Time{}, User{}, nil //fmt.Errorf("idk how to get updated timestamp for %q", c.URLs[0]) -} |