changelog/service/github.go
jolheiser 3d93c3a0cd
All checks were successful
goreleaser / goreleaser (push) Successful in 2m19s
Use issue list API instead of search (#78)
This PR changes to using the GH issue list API rather than search, as for some reason the search results started missing several PRs...

Reviewed-on: #78
Co-authored-by: jolheiser <john.olheiser@gmail.com>
Co-committed-by: jolheiser <john.olheiser@gmail.com>
2023-07-20 10:08:48 +00:00

195 lines
4.0 KiB
Go

// Copyright 2020 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package service
import (
"context"
"errors"
"fmt"
"net/http"
"os"
"strconv"
"strings"
"time"
"github.com/google/go-github/v50/github"
"golang.org/x/oauth2"
)
// GitHub defines a GitHub service
type GitHub struct {
Milestone string
GitTag string
Token string
Repo string
Issues bool
client *github.Client
}
// OwnerRepo splits owner/repo
func (gh *GitHub) OwnerRepo() (string, string) {
parts := strings.Split(gh.Repo, "/")
if len(parts) < 2 {
return parts[0], ""
}
return parts[0], parts[1]
}
// Generate returns a GitHub changelog
func (gh *GitHub) Generate() (string, []Entry, error) {
owner, repo := gh.OwnerRepo()
ctx := context.Background()
gh.initClient(ctx)
tagURL := fmt.Sprintf("## [%s](https://github.com/%s/releases/tag/%s) - %s", gh.Milestone, gh.Repo, gh.GitTag, time.Now().Format("2006-01-02"))
prs := make([]Entry, 0)
milestoneNum, err := gh.milestoneNum(ctx)
if err != nil {
return "", nil, err
}
p := 1
perPage := 100
for {
result, _, err := gh.client.Issues.ListByRepo(ctx, owner, repo, &github.IssueListByRepoOptions{
Milestone: strconv.Itoa(milestoneNum),
State: "closed",
ListOptions: github.ListOptions{
Page: p,
PerPage: perPage,
},
})
if err != nil {
return "", nil, err
}
p++
isPull := !(gh.Issues)
for _, pr := range result {
if pr.IsPullRequest() == isPull {
p := Entry{
Title: CleanTitle(pr.GetTitle()),
Index: int64(pr.GetNumber()),
}
labels := make([]Label, len(pr.Labels))
for idx, lbl := range pr.Labels {
labels[idx] = Label{
Name: lbl.GetName(),
}
}
p.Labels = labels
prs = append(prs, p)
}
}
if len(result) != perPage {
break
}
}
return tagURL, prs, nil
}
// Contributors returns a list of contributors from GitHub
func (gh *GitHub) Contributors() (ContributorList, error) {
ctx := context.Background()
owner, repo := gh.OwnerRepo()
gh.initClient(ctx)
contributorsMap := make(map[string]bool)
milestoneNum, err := gh.milestoneNum(ctx)
if err != nil {
return nil, err
}
p := 1
perPage := 100
for {
result, _, err := gh.client.Issues.ListByRepo(ctx, owner, repo, &github.IssueListByRepoOptions{
Milestone: strconv.Itoa(milestoneNum),
State: "closed",
ListOptions: github.ListOptions{
Page: p,
PerPage: perPage,
},
})
if err != nil {
return nil, err
}
p++
for _, pr := range result {
contributorsMap[pr.GetUser().GetLogin()] = true
}
if len(result) != perPage {
break
}
}
contributors := make(ContributorList, 0, len(contributorsMap))
for contributor := range contributorsMap {
contributors = append(contributors, Contributor{
Name: contributor,
Profile: fmt.Sprintf("https://github.com/%s", contributor),
})
}
return contributors, nil
}
func (gh *GitHub) initClient(ctx context.Context) {
token := gh.Token
if envToken, ok := os.LookupEnv("CHANGELOG_GITHUB_TOKEN"); ok && token == "" {
token = envToken
}
cl := http.DefaultClient
if token != "" {
ts := oauth2.StaticTokenSource(
&oauth2.Token{AccessToken: token},
)
cl = oauth2.NewClient(ctx, ts)
}
gh.client = github.NewClient(cl)
}
func (gh *GitHub) milestoneNum(ctx context.Context) (int, error) {
owner, repo := gh.OwnerRepo()
p := 1
perPage := 100
for {
milestones, _, err := gh.client.Issues.ListMilestones(ctx, owner, repo, &github.MilestoneListOptions{
State: "all",
ListOptions: github.ListOptions{
Page: p,
PerPage: perPage,
},
Sort: "due_on",
Direction: "desc",
})
if err != nil {
return 0, err
}
p++
for _, milestone := range milestones {
if strings.EqualFold(milestone.GetTitle(), gh.Milestone) {
return milestone.GetNumber(), nil
}
}
if len(milestones) != perPage {
break
}
}
return 0, errors.New("no milestone found")
}