GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( 85ea38...bc55d4 )
by Fedir
02:18
created
Severity
1
// Copyright 2018 Fedir RYKHTIK. All rights reserved.
2
// Use of this source code is governed by the GNU GPL 3.0
3
// license that can be found in the LICENSE file.
4
5
// ghstat - statistical multi-criteria decision-making comparator for Github's projects.
6
package main
7
8
import (
9
	"encoding/csv"
10
	"encoding/json"
11
	"flag"
12
	"fmt"
13
	"log"
14
	"os"
15
	"path/filepath"
16
	"strings"
17
	"time"
18
19
	"github.com/fedir/ghstat/github"
20
	"github.com/fedir/ghstat/httpcache"
21
	"github.com/fedir/ghstat/timing"
22
)
23
24
func main() {
25
	var (
26
		clearHTTPCache         = flag.Bool("cc", false, "Clear HTTP cache")
27
		clearHTTPCacheDryRun   = flag.Bool("ccdr", false, "Clear HTTP cache (dry run)")
28
		debug                  = flag.Bool("d", false, "Debug mode")
29
		resultFileSavePath     = flag.String("f", "", "File path where result CSV file will be saved")
30
		rateLimitCheck         = flag.Bool("l", false, "Rate limit check")
31
		repositoriesKeysManual = flag.String("r", "", "Repositories keys")
32
		tmpFolder              = flag.String("t", "test_data", "Clear HTTP cache (dry run)")
33
		repositoriesKeys       = []string{}
34
	)
35
	flag.Parse()
36
	if *clearHTTPCache || *clearHTTPCacheDryRun {
37
		clearHTTPCacheFolder(*tmpFolder, *clearHTTPCacheDryRun)
38
		os.Exit(0)
39
	}
40
	if *rateLimitCheck {
41
		checkAndPrintRateLimit()
42
		os.Exit(0)
43
	}
44
	if *rateLimitCheck {
45
		checkAndPrintRateLimit()
46
		os.Exit(0)
47
	}
48
	if *repositoriesKeysManual != "" {
49
		repositoriesKeys = strings.Split(*repositoriesKeysManual, ",")
50
	} else {
51
		repositoriesKeys = []string{
52
			"astaxie/beego",
53
			"gohugoio/hugo",
54
			"gin-gonic/gin",
55
			"labstack/echo",
56
			"revel/revel",
57
			"gobuffalo/buffalo",
58
			"go-chi/chi",
59
			"kataras/iris",
60
			"zenazn/goji",
61
		}
62
	}
63
	csvFilePath := ""
64
	if *resultFileSavePath != "" {
65
		csvFilePath = *resultFileSavePath
66
	} else {
67
		csvFilePath = "result.csv"
68
	}
69
	var ghData = [][]string{}
70
	headers := []string{
71
		"Name",
72
		"URL",
73
		"Author",
74
		"Author's followers",
75
		"Top 10 contributors followers",
76
		"Created at",
77
		"Age in days",
78
		"Total commits",
79
		"Total additions",
80
		"Total deletions",
81
		"Total code changes",
82
		"Last commit date",
83
		"Commits/day",
84
		"Medium commit size",
85
		"Stargazers",
86
		"Forks",
87
		"Contributors",
88
		"Active forkers, %",
89
		"Open issues",
90
		"Total issues",
91
		"Issue/day",
92
		"Closed issues, %",
93
		"Place",
94
	}
95
	ghDataColumnIndexes := map[string]int{
96
		"nameColumn":                       0,
97
		"authorsFollowersColumn":           3,
98
		"top10ContributorsFollowersColumn": 4,
99
		"totalAdditionsColumn":             8,
100
		"ageColumn":                        6,
101
		"totalCommitsColumn":               7,
102
		"totalDeletionsColumn":             9,
103
		"totalCodeChangesColumn":           10,
104
		"lastCommitDateColumn":             11,
105
		"commitsByDayColumn":               12,
106
		"mediCommitSizeColumn":             13,
107
		"stargazersColumn":                 14,
108
		"activeForkersColumn":              17,
109
		"issuesByDayColumn":                20,
110
		"closedIssuesPercentageColumn":     21,
111
		"totalPointsColumnIndex":           22,
112
	}
113
	dataChan := make(chan []string, len(repositoriesKeys))
114
	for _, rKey := range repositoriesKeys {
115
		go fillRepositoryStatistics(rKey, *tmpFolder, *debug, dataChan)
116
	}
117
	for range repositoriesKeys {
118
		ghData = append(ghData, <-dataChan)
119
	}
120
	greetings := rateGhData(ghData, ghDataColumnIndexes)
121
	fmt.Println(greetings)
122
	writeCsv(csvFilePath, headers, ghData)
123
}
124
125
func fillRepositoryStatistics(rKey string, tmpFolder string, debug bool, dataChan chan []string) {
126
	repositoryData := github.GetRepositoryStatistics(rKey, tmpFolder, debug)
127
	repositoryAge := int(time.Since(repositoryData.CreatedAt).Seconds() / 86400)
128
	authorLogin, lastCommitDate := github.GetRepositoryCommitsData(rKey, tmpFolder, debug)
129
	authorFollowers := 0
130
	if authorLogin != "" {
131
		authorFollowers = github.GetUserFollowers(authorLogin, tmpFolder, debug)
132
	}
133
	closedIssues := github.GetRepositoryClosedIssues(rKey, tmpFolder, debug)
134
	topContributorsFollowers, totalContributors := github.GetRepositoryContributors(rKey, tmpFolder, debug)
135
	activeForkersPercentage := github.GetActiveForkersPercentage(totalContributors, repositoryData.Forks)
136
	issueByDay := github.GetIssueByDay(closedIssues+repositoryData.OpenIssues, repositoryAge)
137
	closedIssuesPercentage := github.GetClosedIssuesPercentage(repositoryData.OpenIssues, int(closedIssues))
138
	contributionStatistics := github.GetContributionStatistics(rKey, tmpFolder, debug)
139
	commitsByDay := github.GetCommitsByDay(contributionStatistics.TotalCommits, repositoryAge)
140
	ghProjectData := []string{
141
		repositoryData.FullName,
142
		fmt.Sprintf("https://github.com/%s", repositoryData.FullName),
143
		fmt.Sprintf("%s", func(a string) string {
144
			if a == "" {
145
				a = "[Account removed]"
146
			}
147
			return a
148
		}(authorLogin)),
149
		fmt.Sprintf("%d", authorFollowers),
150
		fmt.Sprintf("%d", topContributorsFollowers),
151
		fmt.Sprintf("%d/%02d", repositoryData.CreatedAt.Year(), repositoryData.CreatedAt.Month()),
152
		fmt.Sprintf("%d", repositoryAge),
153
		fmt.Sprintf("%d", contributionStatistics.TotalCommits),
154
		fmt.Sprintf("%d", contributionStatistics.TotalAdditions),
155
		fmt.Sprintf("%d", contributionStatistics.TotalDeletions),
156
		fmt.Sprintf("%d", contributionStatistics.TotalCodeChanges),
157
		fmt.Sprintf(lastCommitDate.Format("2006-01-02 15:04:05")),
0 ignored issues
show
can't check non-constant format in call to Sprintf
Loading history...
158
		fmt.Sprintf("%.4f", commitsByDay),
159
		fmt.Sprintf("%d", contributionStatistics.MediumCommitSize),
160
		fmt.Sprintf("%d", repositoryData.Watchers),
161
		fmt.Sprintf("%d", repositoryData.Forks),
162
		fmt.Sprintf("%d", totalContributors),
163
		fmt.Sprintf("%.2f", activeForkersPercentage),
164
		fmt.Sprintf("%d", repositoryData.OpenIssues),
165
		fmt.Sprintf("%d", closedIssues+repositoryData.OpenIssues),
166
		fmt.Sprintf("%.4f", issueByDay),
167
		fmt.Sprintf("%.2f", closedIssuesPercentage),
168
		"0",
169
	}
170
	dataChan <- ghProjectData
171
}
172
173
func clearHTTPCacheFolder(tmpFolderPath string, dryRun bool) error {
174
	d, err := os.Open(tmpFolderPath)
175
	if err != nil {
176
		log.Fatalf("Could not open %s", tmpFolderPath)
177
	}
178
	defer d.Close()
179
	names, err := d.Readdirnames(-1)
180
	if err != nil {
181
		log.Fatalf("Could not read from %s", tmpFolderPath)
182
	}
183
	for _, name := range names {
184
		fp := filepath.Join(tmpFolderPath, name)
185
		if dryRun {
186
			fmt.Printf("Deleted %s\n", fp)
187
		} else {
188
			err = os.RemoveAll(fp)
189
			if err != nil {
190
				log.Fatalf("Could not remove %s", fp)
191
			}
192
			fmt.Printf("Deleted %s\n", fp)
193
		}
194
	}
195
	return nil
196
}
197
198
func checkAndPrintRateLimit() {
199
	type RateLimits struct {
200
		Resources struct {
201
			Core struct {
202
				Limit     int `json:"limit"`
203
				Remaining int `json:"remaining"`
204
				Reset     int `json:"reset"`
205
			} `json:"core"`
206
			Search struct {
207
				Limit     int `json:"limit"`
208
				Remaining int `json:"remaining"`
209
				Reset     int `json:"reset"`
210
			} `json:"search"`
211
			GraphQL struct {
212
				Limit     int `json:"limit"`
213
				Remaining int `json:"remaining"`
214
				Reset     int `json:"reset"`
215
			} `json:"graphql"`
216
		} `json:"resources"`
217
		Rate struct {
218
			Limit     int `json:"limit"`
219
			Remaining int `json:"remaining"`
220
			Reset     int `json:"reset"`
221
		} `json:"rate"`
222
	}
223
	url := "https://api.github.com/rate_limit"
224
	resp, statusCode, err := httpcache.MakeHTTPRequest(url)
225
	if err != nil {
226
		log.Fatalf("Error during checking rate limit : %d %v#", statusCode, err)
227
	}
228
	jsonResponse, _, _ := httpcache.ReadResp(resp)
229
	rateLimits := RateLimits{}
230
	json.Unmarshal(jsonResponse, &rateLimits)
231
	fmt.Printf("Core: %d/%d (reset in %d minutes)\n", rateLimits.Resources.Core.Remaining, rateLimits.Resources.Core.Limit, timing.GetRelativeTime(rateLimits.Resources.Core.Reset))
232
	fmt.Printf("Search: %d/%d (reset in %d minutes)\n", rateLimits.Resources.Search.Remaining, rateLimits.Resources.Search.Limit, timing.GetRelativeTime(rateLimits.Resources.Search.Reset))
233
	fmt.Printf("GraphQL: %d/%d (reset in %d minutes)\n", rateLimits.Resources.GraphQL.Remaining, rateLimits.Resources.GraphQL.Limit, timing.GetRelativeTime(rateLimits.Resources.GraphQL.Reset))
234
	fmt.Printf("Rate: %d/%d (reset in %d minutes)\n", rateLimits.Rate.Remaining, rateLimits.Rate.Limit, timing.GetRelativeTime(rateLimits.Rate.Reset))
235
}
236
237
func writeCsv(csvFilePath string, headers []string, ghData [][]string) {
238
	file, err := os.Create(csvFilePath)
239
	if err != nil {
240
		log.Fatal("Cannot create file", err)
241
	}
242
	defer file.Close()
243
	writer := csv.NewWriter(file)
244
	defer writer.Flush()
245
	err = writer.Write(headers)
246
	if err != nil {
247
		log.Fatal("Cannot write to file", err)
248
	}
249
	for _, value := range ghData {
250
		err := writer.Write(value)
251
		if err != nil {
252
			log.Fatal("Cannot write to file", err)
253
		}
254
	}
255
}
256