package main import ( "fmt" "regexp" "time" ) var reForgejoPR = regexp.MustCompile(`^https://([^/]+)/([^/?#]+)/([^/?#]+)/pulls/([0-9]+)(?:\?[^#]*)?(?:#.*)?$`) type Forgejo struct { Authority string } var _ Forge = Forgejo{} func (f Forgejo) FetchStatus(urls []string) (string, error) { return fetchPerURLStatus(urls, func(u string) (string, error) { m := reForgejoPR.FindStringSubmatch(u) if m == nil || m[1] != f.Authority { return "", nil } authority := m[1] user := m[2] repo := m[3] prnum := m[4] urlStr := "https://" + authority + "/api/v1/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, nil, &obj); err != nil { return "", err } ret := obj.State if obj.Merged { ret = statusMerged tag, err := getGitTagThatContainsAll("https://"+authority+"/"+user+"/"+repo, obj.MergeCommitSha) if err != nil { return "", err } if tag != "" { ret = fmt.Sprintf(statusReleasedFmt, tag) } } return ret, nil }) } func (f Forgejo) FetchSubmittedAt(urls []string) (time.Time, error) { return fetchPerURLSubmittedAt(urls, func(u string) (time.Time, error) { m := reForgejoPR.FindStringSubmatch(u) if m == nil || m[1] != f.Authority { return time.Time{}, nil } authority := m[1] user := m[2] repo := m[3] prnum := m[4] urlStr := "https://" + authority + "/api/v1/repos/" + user + "/" + repo + "/pulls/" + prnum var obj struct { CreatedAt time.Time `json:"created_at"` } if err := httpGetJSON(urlStr, nil, &obj); err != nil { return time.Time{}, err } return obj.CreatedAt, nil }) } func (f Forgejo) FetchLastUpdated(urls []string) (time.Time, User, error) { return fetchPerURLLastUpdated(urls, func(u string) (time.Time, User, error) { m := reForgejoPR.FindStringSubmatch(u) if m == nil || m[1] != f.Authority { return time.Time{}, User{}, nil } authority := m[1] user := m[2] repo := m[3] prnum := m[4] urlStr := "https://" + authority + "/api/v1/repos/" + user + "/" + repo + "/pulls/" + prnum var obj struct { UpdatedAt time.Time `json:"updated_at"` CreatedAt time.Time `json:"created_at"` CreatedBy struct { Login string `json:"login"` HTMLURL string `json:"html_url"` } `json:"user"` MergedAt time.Time `json:"merged_at"` MergedBy struct { Login string `json:"login"` HTMLURL string `json:"html_url"` } `json:"merged_by"` } if err := httpGetJSON(urlStr, nil, &obj); err != nil { return time.Time{}, User{}, err } retUpdatedAt := obj.UpdatedAt var retUser User if retUser == (User{}) && withinOneSecond(obj.CreatedAt, retUpdatedAt) { retUser.Name = obj.CreatedBy.Login retUser.URL = obj.CreatedBy.HTMLURL } if retUser == (User{}) && withinOneSecond(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", nil, &comments, githubPagination); err != nil { return time.Time{}, User{}, err } for _, comment := range comments { if withinOneSecond(comment.UpdatedAt, 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", nil, &reviewComments, githubPagination); err != nil { return time.Time{}, User{}, err } for _, comment := range reviewComments { if withinOneSecond(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", nil, &events); err != nil { return time.Time{}, User{}, err } for _, event := range events { if withinOneSecond(event.CreatedAt, retUpdatedAt) { retUser.Name = event.Actor.Login retUser.URL = event.Actor.HTMLURL break } } } return retUpdatedAt, retUser, nil }) }