Skip to content

Instantly share code, notes, and snippets.

@donatj
Created May 10, 2016 16:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save donatj/29876b0dc19dd11ebc2f09a632fe0b1b to your computer and use it in GitHub Desktop.
Save donatj/29876b0dc19dd11ebc2f09a632fe0b1b to your computer and use it in GitHub Desktop.
Find issues between two release branches
package main
import (
"flag"
"fmt"
"log"
"regexp"
"sort"
"strconv"
"strings"
"github.com/google/go-github/github"
"github.com/mcuadros/go-version"
)
type branchSort []github.Branch
func (a branchSort) Len() int { return len(a) }
func (a branchSort) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a branchSort) Less(i, j int) bool {
left := (*a[i].Name)[8:]
right := (*a[j].Name)[8:]
return version.Compare(left, right, "<")
}
var (
username = flag.String("user", "", "Username to authenticate with")
password = flag.String("pass", "", "password or token to authenticate with")
owner = flag.String("owner", "capdig", "repo owner")
repo = flag.String("repo", "myon", "repo")
)
type issuePrAssoc struct {
Issue *github.Issue
PullRequests map[int]*github.PullRequest
}
type issueMap map[int]issuePrAssoc
func init() {
flag.Parse()
}
func main() {
tp := github.BasicAuthTransport{
Username: *username,
Password: *password,
}
client := github.NewClient(tp.Client())
bq, err := getReleaseBranches(client, *owner, *repo)
if err != nil {
log.Fatal(err)
}
start := bq[len(bq)-2]
end := bq[len(bq)-1]
mergeCommits, err := getMergeCommitsBetween(
client, *owner, *repo,
end.Commit,
start.Commit)
if err != nil {
log.Fatal(err)
}
issues, err := getIssueMap(
client, *owner, *repo,
mergeCommits)
if err != nil {
log.Fatal(err)
}
// output
fmt.Printf("%s…%s\n", *start.Name, *end.Name)
if v, ok := issues[-1]; ok {
fmt.Printf("No Issue:\n")
for _, pr := range v.PullRequests {
fmt.Printf("\t#%d: %s\n", *pr.Number, *pr.Title)
}
}
for issueNumber, prNumbers := range issues {
if issueNumber == -1 {
continue
} else {
fmt.Printf("Issue: #%d: %s\n", issueNumber, *prNumbers.Issue.Title)
}
for _, pr := range prNumbers.PullRequests {
fmt.Printf("\t#%d: %s\n", *pr.Number, *pr.Title)
}
}
}
func getIssueMap(client *github.Client, owner, repo string, commits []github.RepositoryCommit) (issueMap, error) {
issues := make(issueMap)
for _, mc := range commits {
m := *mc.Commit.Message
r := regexp.MustCompile(`Merge pull request #(\d+)`)
matches := r.FindAllStringSubmatch(m, -1)
prNumber, err := strconv.Atoi(matches[0][1])
if err != nil {
return nil, err
}
pullreq, _, err := client.PullRequests.Get(owner, repo, prNumber)
if err != nil {
return nil, err
}
r2 := regexp.MustCompile(`connects? \\?#(\d+)`)
matches = r2.FindAllStringSubmatch(*pullreq.Body, -1)
for _, match := range matches {
issueNum, err := strconv.Atoi(match[1])
if err != nil {
return nil, err
}
if _, ok := issues[issueNum]; !ok {
issue, _, err := client.Issues.Get(owner, repo, issueNum)
if err != nil {
return nil, err
}
issues[issueNum] = issuePrAssoc{
Issue: issue,
PullRequests: make(map[int]*github.PullRequest),
}
}
issues[issueNum].PullRequests[prNumber] = pullreq
}
if len(matches) == 0 {
if _, ok := issues[-1]; !ok {
issues[-1] = issuePrAssoc{
PullRequests: make(map[int]*github.PullRequest),
}
}
issues[-1].PullRequests[prNumber] = pullreq
}
}
return issues, nil
}
func getMergeCommitsBetween(client *github.Client, owner, repo string, startc, endc *github.Commit) ([]github.RepositoryCommit, error) {
end := *endc.SHA
start := *startc.SHA
mergeCommits := []github.RepositoryCommit{}
page := 1
outer:
for {
commits, resp, err := client.Repositories.ListCommits(owner, repo, &github.CommitsListOptions{
SHA: start,
ListOptions: github.ListOptions{
PerPage: 100,
Page: page,
},
})
if err != nil {
return nil, err
}
for _, cc := range commits {
if cc.Commit != nil && cc.Commit.Message != nil && strings.Contains(*cc.Commit.Message, "Merge pull request #") {
mergeCommits = append(mergeCommits, cc)
}
if *cc.SHA == end {
break outer
}
}
if resp.NextPage == 0 {
break
}
page = resp.NextPage
}
return mergeCommits, nil
}
func getReleaseBranches(client *github.Client, owner, repo string) (branchSort, error) {
brs := []github.Branch{}
page := 1
for {
branch, resp, err := client.Repositories.ListBranches(owner, repo, &github.ListOptions{PerPage: 100, Page: page})
if err != nil {
return nil, err
}
brs = append(brs, branch...)
if resp.NextPage == 0 {
break
}
page = resp.NextPage
}
bq := branchSort{}
for _, br := range brs {
if strings.HasPrefix(*br.Name, "release/") {
bq = append(bq, br)
}
}
sort.Sort(bq)
return bq, nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment