-
Notifications
You must be signed in to change notification settings - Fork 0
/
context.go
148 lines (132 loc) · 3.42 KB
/
context.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"time"
"github.com/google/go-github/github"
)
type context struct {
client *github.Client
owner string
repo string
issues []github.Issue
releases []github.RepositoryRelease
}
func (c *context) LoadIssues() {
issueCacheFilename := fmt.Sprintf("cache/%s_%s_issues.cache", c.owner, c.repo)
if err := readJson(issueCacheFilename, &c.issues); err == nil {
return
}
c.issues = allIssuesInRepo(c.client, c.owner, c.repo)
writeJson(issueCacheFilename, c.issues)
}
func (c *context) LoadReleases() {
cacheFilename := fmt.Sprintf("cache/%s_%s_releases.cache", c.owner, c.repo)
if err := readJson(cacheFilename, &c.releases); err == nil {
return
}
c.releases = c.fetchReleases()
writeJson(cacheFilename, c.releases)
}
func (c *context) StartTime() time.Time {
first := time.Now()
for _, i := range c.issues {
if i.CreatedAt.Before(first) {
first = *i.CreatedAt
}
}
return first
}
func (c *context) EndTime() time.Time { return time.Now() }
func (c *context) WalkIssues(f func(issue github.Issue, isPullRequest bool)) {
for _, issue := range c.issues {
f(issue, issue.PullRequestLinks != nil)
}
}
func (c *context) WalkReleases(f func(r github.RepositoryRelease)) {
for _, r := range c.releases {
f(r)
}
}
func (c *context) fetchReleases() []github.RepositoryRelease {
opt := &github.ListOptions{
PerPage: 100,
}
var releases []github.RepositoryRelease
for i := 0; ; i++ {
rs, resp, err := c.client.Repositories.ListReleases(c.owner, c.repo, opt)
if err != nil {
fmt.Printf("error listing releases (%v)\n", err)
os.Exit(1)
}
releases = append(releases, rs...)
if resp.NextPage == 0 {
break
}
opt.Page = resp.NextPage
}
return releases
}
func allIssuesInRepo(client *github.Client, owner, repo string) []github.Issue {
rate, _, err := client.RateLimits()
if err != nil {
fmt.Printf("error fetching rate limit (%v)\n", err)
} else {
fmt.Printf("API Rate Limit: %s\n", rate)
}
opt := &github.IssueListByRepoOptions{
State: "all",
ListOptions: github.ListOptions{
PerPage: 100,
},
}
var issues []github.Issue
for i := 0; ; i++ {
is, resp, err := client.Issues.ListByRepo(owner, repo, opt)
if err != nil {
fmt.Printf("error listing issues (%v)\n", err)
os.Exit(1)
}
issues = append(issues, is...)
if resp.NextPage == 0 {
break
}
opt.ListOptions.Page = resp.NextPage
fmt.Printf("list %d issues...\n", len(issues))
}
return issues
}
func readJson(filename string, v interface{}) error {
data, err := ioutil.ReadFile(filename)
haveCachedIssue := err == nil
isUpToDate := time.Now().Sub(fileModTime(filename)) < DayDuration
if haveCachedIssue && isUpToDate {
if err := json.Unmarshal(data, v); err != nil {
return fmt.Errorf("error loading cached data from file %s (%v)", filename, err)
}
return nil
}
return fmt.Errorf("outdated cache file")
}
func writeJson(filename string, v interface{}) {
if data, err := json.Marshal(v); err != nil {
fmt.Printf("error marshaling issues (%v)\n", err)
} else if err := ioutil.WriteFile(filename, data, 0600); err != nil {
fmt.Printf("error caching issues into file (%v)\n", err)
} else {
fmt.Printf("cached issues in file %q for fast retrieval\n", filename)
}
}
func fileModTime(name string) time.Time {
f, err := os.Open(name)
if err != nil {
return time.Time{}
}
st, err := f.Stat()
if err != nil {
return time.Time{}
}
return st.ModTime()
}