You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

227 lines
4.7 KiB
Go

package handlers
import (
"git.blob42.xyz/blob42/hugobot/v3/feeds"
"git.blob42.xyz/blob42/hugobot/v3/github"
"git.blob42.xyz/blob42/hugobot/v3/posts"
"git.blob42.xyz/blob42/hugobot/v3/static"
"git.blob42.xyz/blob42/hugobot/v3/utils"
"context"
"fmt"
"log"
"regexp"
"strconv"
"strings"
"time"
githubApi "github.com/google/go-github/github"
)
var (
ReBIP = regexp.MustCompile(`bips?[\s-]*(?P<bipId>[0-9]+)`)
ReBOLT = regexp.MustCompile(`bolt?[\s-]*(?P<boltId>[0-9]+)`)
ReSLIP = regexp.MustCompile(`slips?[\s-]*(?P<slipId>[0-9]+)`)
)
const (
BIPLink = "https://github.com/bitcoin/bips/blob/master/bip-%04d.mediawiki"
SLIPLink = "https://github.com/satoshilabs/slips/blob/master/slip-%04d.md"
)
const (
BOLT = 73738971
BIP = 14531737
SLIP = 50844973
)
var RFCTypes = map[int64]string{
BIP: "bip",
BOLT: "bolt",
SLIP: "slip",
}
type RFCUpdate struct {
RFCID int64 `json:"rfcid"`
RFCType string `json:"rfc_type"` //bip bolt slip
RFCNumber int `json:"rfc_number"` // (bip/bolt/slip id)
Issue *github.Issue `json:"issue"`
RFCLink string `json:"rfc_link"`
}
type RFCHandler struct {
ctx context.Context
ghClient *githubApi.Client
}
func (handler RFCHandler) Handle(feed feeds.Feed) error {
posts, err := handler.FetchSince(feed.Url, feed.LastRefresh)
if err != nil {
return err
}
if posts == nil {
log.Printf("No new posts in feed <%s>", feed.Name)
}
for _, p := range posts {
// Since RFCs are based on github issues, we use their id as unique
// id in the local sqlite db
err := p.WriteWithShortId(feed.FeedID, p.JsonData["rfcid"])
if err != nil {
return err
}
}
return nil
}
func (handler RFCHandler) FetchSince(url string, after time.Time) ([]*posts.Post, error) {
var results []*posts.Post
log.Printf("Fetching RFC %s since %v", url, after)
owner, repo := github.ParseOwnerRepo(url)
project, resp, err := handler.ghClient.Repositories.Get(handler.ctx, owner, repo)
github.RespMiddleware(resp)
if err != nil {
return nil, err
}
//All Issues
var allIssues []*githubApi.Issue
listIssueOptions := &githubApi.IssueListByRepoOptions{
Since: after,
State: "all",
ListOptions: githubApi.ListOptions{PerPage: 100},
}
for {
issues, resp, err := handler.ghClient.Issues.ListByRepo(
handler.ctx, owner, repo, listIssueOptions)
if err != nil {
return nil, err
}
allIssues = append(allIssues, issues...)
if resp.NextPage == 0 {
break
}
listIssueOptions.Page = resp.NextPage
}
for iIndex, issue := range allIssues {
var pr *githubApi.PullRequest
// base rfc object
rfc := RFCUpdate{
RFCID: issue.GetID(),
RFCType: RFCTypes[*project.ID],
Issue: &github.Issue{
Title: issue.GetTitle(),
URL: issue.GetURL(),
Number: issue.GetNumber(),
State: issue.GetState(),
Updated: issue.GetUpdatedAt(),
Created: issue.GetCreatedAt(),
Comments: issue.GetComments(),
HtmlURL: issue.GetHTMLURL(),
},
}
if issue.IsPullRequest() {
log.Printf("parsing %s. Progress %d/%d\n", url, iIndex+1, len(allIssues))
pr, resp, err = handler.ghClient.PullRequests.Get(
handler.ctx, owner, repo, issue.GetNumber(),
)
//github.RespMiddleware(resp)
if err != nil {
return nil, err
}
rfc.Issue.IsPR = issue.IsPullRequest()
rfc.Issue.Merged = *pr.Merged
if rfc.Issue.Merged {
rfc.Issue.MergedAt = *pr.MergedAt
}
}
// If is open and is not new (update) mark as update
if rfc.Issue.Created != rfc.Issue.Updated &&
!rfc.Issue.Merged &&
rfc.Issue.State == "open" {
rfc.Issue.IsUpdate = true
}
rfc.RFCNumber, err = GetRFCNumber(issue.GetTitle())
if err != nil {
return nil, err
}
if rfc.RFCNumber != -1 {
switch rfc.RFCType {
case RFCTypes[BIP]:
rfc.RFCLink = fmt.Sprintf(BIPLink, rfc.RFCNumber)
case RFCTypes[SLIP]:
rfc.RFCLink = fmt.Sprintf(SLIPLink, rfc.RFCNumber)
case RFCTypes[BOLT]:
rfc.RFCLink = static.BoltMap[rfc.RFCNumber]
}
}
post := &posts.Post{}
post.Title = rfc.Issue.Title
post.Link = rfc.Issue.URL
post.Published = rfc.Issue.Created
post.Updated = rfc.Issue.Updated
post.JsonData = utils.StructToJsonMap(rfc)
results = append(results, post)
}
return results, nil
}
func NewRFCHandler() FormatHandler {
ctxb := context.Background()
client := github.Auth(ctxb)
return RFCHandler{
ctx: ctxb,
ghClient: client,
}
}
func GetRFCNumber(title string) (int, error) {
// Detect BIP
for _, re := range []*regexp.Regexp{ReBIP, ReBOLT, ReSLIP} {
matches := re.FindStringSubmatch(strings.ToLower(title))
if matches != nil {
res, err := strconv.Atoi(matches[1])
if err != nil {
return -1, err
}
return res, nil
}
}
return -1, nil
}