forked from hoop33/limo
/
github.go
141 lines (119 loc) · 3.34 KB
/
github.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
package service
import (
"fmt"
"time"
"golang.org/x/oauth2"
"github.com/google/go-github/github"
"github.com/hoop33/entrevista"
"github.com/hoop33/limo/model"
)
// Github represents the Github service
type Github struct {
}
// Login logs in to Github
func (g *Github) Login() (string, error) {
interview := createInterview()
interview.Questions = []entrevista.Question{
{
Key: "token",
Text: "Enter your GitHub API token",
Required: true,
Hidden: true,
},
}
answers, err := interview.Run()
if err != nil {
return "", err
}
return answers["token"].(string), nil
}
// GetStars returns the stars for the specified user (empty string for authenticated user)
func (g *Github) GetStars(starChan chan<- *model.StarResult, token string, user string) {
client := g.getClient(token)
// The first response will give us the correct value for the last page
currentPage := 1
lastPage := 1
for currentPage <= lastPage {
repos, response, err := client.Activity.ListStarred(user, &github.ActivityListStarredOptions{
ListOptions: github.ListOptions{
Page: currentPage,
},
})
// If we got an error, put it on the channel
if err != nil {
starChan <- &model.StarResult{
Error: err,
Star: nil,
}
} else {
// Set last page only if we didn't get an error
lastPage = response.LastPage
// Create a Star for each repository and put it on the channel
for _, repo := range repos {
star, err := model.NewStarFromGithub(repo.StarredAt, *repo.Repository)
starChan <- &model.StarResult{
Error: err,
Star: star,
}
}
}
// Go to the next page
currentPage++
}
close(starChan)
}
// GetTrending returns the trending repositories
func (g *Github) GetTrending(trendingChan chan<- *model.StarResult, token string, language string, verbose bool) {
client := g.getClient(token)
// TODO perhaps allow them to specify multiple pages?
// Might be overkill -- first page probably plenty
// TODO Make this more configurable. Sort by stars, forks, default.
// Search by number of stars, pushed, created, or whatever.
// Lots of possibilities.
q := g.getDateSearchString()
if language != "" {
q = fmt.Sprintf("language:%s %s", language, q)
}
if verbose {
fmt.Println("q =", q)
}
result, _, err := client.Search.Repositories(q, &github.SearchOptions{
Sort: "stars",
Order: "desc",
})
// If we got an error, put it on the channel
if err != nil {
trendingChan <- &model.StarResult{
Error: err,
Star: nil,
}
} else {
// Create a Star for each repository and put it on the channel
for _, repo := range result.Repositories {
star, err := model.NewStarFromGithub(nil, repo)
trendingChan <- &model.StarResult{
Error: err,
Star: star,
}
}
}
close(trendingChan)
}
func (g *Github) getDateSearchString() string {
// TODO make this configurable
// Default should be in configuration file
// and should be able to override from command line
// TODO should be able to specify whether "created" or "pushed"
date := time.Now().Add(-7 * (24 * time.Hour))
return fmt.Sprintf("created:>%s", date.Format("2006-01-02"))
}
func (g *Github) getClient(token string) *github.Client {
ts := oauth2.StaticTokenSource(
&oauth2.Token{AccessToken: token},
)
tc := oauth2.NewClient(oauth2.NoContext, ts)
return github.NewClient(tc)
}
func init() {
registerService(&Github{})
}