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 ( 2aed10...0cf8cc )
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 1
	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 1
	flag.Parse()
36 1
	if *clearHTTPCache || *clearHTTPCacheDryRun {
37
		clearHTTPCacheFolder(*tmpFolder, *clearHTTPCacheDryRun)
38
		os.Exit(0)
39
	}
40 1
	if *rateLimitCheck {
41
		checkAndPrintRateLimit()
42
		os.Exit(0)
43
	}
44 1
	if *rateLimitCheck {
45
		checkAndPrintRateLimit()
46
		os.Exit(0)
47
	}
48 1
	if *repositoriesKeysManual != "" {
49
		repositoriesKeys = strings.Split(*repositoriesKeysManual, ",")
50
	} else {
51 1
		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 1
	csvFilePath := ""
64 1
	if *resultFileSavePath != "" {
65
		csvFilePath = *resultFileSavePath
66
	} else {
67 1
		csvFilePath = "result.csv"
68
	}
69 1
	var ghData = [][]string{}
70 1
	headers := []string{
71
		"Name",
72
		"URL",
73
		"Author",
74
		"Language",
75
		"License",
76
		"Author's followers",
77
		"Top 10 contributors followers",
78
		"Created at",
79
		"Age in days",
80
		"Total commits",
81
		"Total additions",
82
		"Total deletions",
83
		"Total code changes",
84
		"Last commit date",
85
		"Commits/day",
86
		"Medium commit size",
87
		"Total releases",
88
		"Stargazers",
89
		"Forks",
90
		"Contributors",
91
		"Active forkers, %",
92
		"Open issues",
93
		"Total issues",
94
		"Issue/day",
95
		"Closed issues, %",
96
		"Place",
97
	}
98 1
	ghDataColumnIndexes := map[string]int{
99
		"nameColumn":                       0,
100
		"urlColumn":                        1,
101
		"authorColumn":                     2,
102
		"languageColumn":                   3,
103
		"licenseColumn":                    4,
104
		"authorsFollowersColumn":           5,
105
		"top10ContributorsFollowersColumn": 6,
106
		"ageColumn":                        8,
107
		"totalCommitsColumn":               9,
108
		"totalAdditionsColumn":             10,
109
		"totalDeletionsColumn":             11,
110
		"totalCodeChangesColumn":           12,
111
		"lastCommitDateColumn":             13,
112
		"commitsByDayColumn":               14,
113
		"mediCommitSizeColumn":             15,
114
		"totalTagsColumn":                  16,
115
		"stargazersColumn":                 17,
116
		"activeForkersColumn":              20,
117
		"issuesByDayColumn":                23,
118
		"closedIssuesPercentageColumn":     24,
119
		"totalPointsColumnIndex":           25,
120
	}
121 1
	dataChan := make(chan []string, len(repositoriesKeys))
122 1
	for _, rKey := range repositoriesKeys {
123 1
		go fillRepositoryStatistics(rKey, *tmpFolder, *debug, dataChan)
124
	}
125 1
	for range repositoriesKeys {
126 1
		ghData = append(ghData, <-dataChan)
127
	}
128 1
	greetings := rateGhData(ghData, ghDataColumnIndexes)
129 1
	fmt.Println(greetings)
130 1
	writeCsv(csvFilePath, headers, ghData)
131
}
132
133
func fillRepositoryStatistics(rKey string, tmpFolder string, debug bool, dataChan chan []string) {
134 1
	repositoryData := github.GetRepositoryStatistics(rKey, tmpFolder, debug)
135 1
	repositoryAge := int(time.Since(repositoryData.CreatedAt).Seconds() / 86400)
136 1
	authorLogin, lastCommitDate := github.GetRepositoryCommitsData(rKey, tmpFolder, debug)
137 1
	authorFollowers := 0
138 1
	if authorLogin != "" {
139 1
		authorFollowers = github.GetUserFollowers(authorLogin, tmpFolder, debug)
140
	}
141
142 1
	closedIssues := 0
143 1
	if repositoryData.HasIssues {
144 1
		closedIssues = github.GetRepositoryClosedIssues(rKey, tmpFolder, debug)
145
	}
146 1
	topContributorsFollowers, totalContributors := github.GetRepositoryContributors(rKey, tmpFolder, debug)
147 1
	totalTags := github.GetRepositoryTagsNumber(rKey, tmpFolder, debug)
148 1
	activeForkersPercentage := github.GetActiveForkersPercentage(totalContributors, repositoryData.Forks)
149 1
	issueByDay := github.GetIssueByDay(closedIssues+repositoryData.OpenIssues, repositoryAge)
150 1
	closedIssuesPercentage := github.GetClosedIssuesPercentage(repositoryData.OpenIssues, int(closedIssues))
151 1
	contributionStatistics := github.GetContributionStatistics(rKey, tmpFolder, debug)
152 1
	commitsByDay := github.GetCommitsByDay(contributionStatistics.TotalCommits, repositoryAge)
153 1
	ghProjectData := []string{
154
		repositoryData.FullName,
155
		fmt.Sprintf("https://github.com/%s", repositoryData.FullName),
156
		fmt.Sprintf("%s", repositoryData.Language),
157
		fmt.Sprintf("%s", func(a string) string {
158 1
			if a == "" {
159 1
				a = "[Account removed]"
160
			}
161 1
			return a
162
		}(authorLogin)),
163
		fmt.Sprintf("%s", func(l string) string {
164 1
			if l == "" {
165 1
				l = "[Unknown]"
166
			}
167 1
			return l
168
		}(repositoryData.License.SPDXID)),
169
		fmt.Sprintf("%d", authorFollowers),
170
		fmt.Sprintf("%d", topContributorsFollowers),
171
		fmt.Sprintf("%d/%02d", repositoryData.CreatedAt.Year(), repositoryData.CreatedAt.Month()),
172
		fmt.Sprintf("%d", repositoryAge),
173
		fmt.Sprintf("%d", contributionStatistics.TotalCommits),
174
		fmt.Sprintf("%d", contributionStatistics.TotalAdditions),
175
		fmt.Sprintf("%d", contributionStatistics.TotalDeletions),
176
		fmt.Sprintf("%d", contributionStatistics.TotalCodeChanges),
177
		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...
178
		fmt.Sprintf("%.4f", commitsByDay),
179
		fmt.Sprintf("%d", contributionStatistics.MediumCommitSize),
180
		fmt.Sprintf("%d", totalTags),
181
		fmt.Sprintf("%d", repositoryData.Watchers),
182
		fmt.Sprintf("%d", repositoryData.Forks),
183
		fmt.Sprintf("%d", totalContributors),
184
		fmt.Sprintf("%.2f", activeForkersPercentage),
185
		fmt.Sprintf("%d", repositoryData.OpenIssues),
186
		fmt.Sprintf("%d", closedIssues+repositoryData.OpenIssues),
187
		fmt.Sprintf("%.4f", issueByDay),
188
		fmt.Sprintf("%.2f", closedIssuesPercentage),
189
		"0",
190
	}
191 1
	dataChan <- ghProjectData
192
}
193
194
func clearHTTPCacheFolder(tmpFolderPath string, dryRun bool) error {
195
	d, err := os.Open(tmpFolderPath)
196
	if err != nil {
197
		log.Fatalf("Could not open %s", tmpFolderPath)
198
	}
199
	defer d.Close()
200
	names, err := d.Readdirnames(-1)
201
	if err != nil {
202
		log.Fatalf("Could not read from %s", tmpFolderPath)
203
	}
204
	for _, name := range names {
205
		fp := filepath.Join(tmpFolderPath, name)
206
		if dryRun {
207
			fmt.Printf("Deleted %s\n", fp)
208
		} else {
209
			err = os.RemoveAll(fp)
210
			if err != nil {
211
				log.Fatalf("Could not remove %s", fp)
212
			}
213
			fmt.Printf("Deleted %s\n", fp)
214
		}
215
	}
216
	return nil
217
}
218
219
func checkAndPrintRateLimit() {
220
	type RateLimits struct {
221
		Resources struct {
222
			Core struct {
223
				Limit     int `json:"limit"`
224
				Remaining int `json:"remaining"`
225
				Reset     int `json:"reset"`
226
			} `json:"core"`
227
			Search struct {
228
				Limit     int `json:"limit"`
229
				Remaining int `json:"remaining"`
230
				Reset     int `json:"reset"`
231
			} `json:"search"`
232
			GraphQL struct {
233
				Limit     int `json:"limit"`
234
				Remaining int `json:"remaining"`
235
				Reset     int `json:"reset"`
236
			} `json:"graphql"`
237
		} `json:"resources"`
238
		Rate struct {
239
			Limit     int `json:"limit"`
240
			Remaining int `json:"remaining"`
241
			Reset     int `json:"reset"`
242
		} `json:"rate"`
243
	}
244
	url := "https://api.github.com/rate_limit"
245
	resp, statusCode, err := httpcache.MakeHTTPRequest(url)
246
	if err != nil {
247
		log.Fatalf("Error during checking rate limit : %d %v#", statusCode, err)
248
	}
249
	jsonResponse, _, _ := httpcache.ReadResp(resp)
250
	rateLimits := RateLimits{}
251
	json.Unmarshal(jsonResponse, &rateLimits)
252
	fmt.Printf("Core: %d/%d (reset in %d minutes)\n", rateLimits.Resources.Core.Remaining, rateLimits.Resources.Core.Limit, timing.GetRelativeTime(rateLimits.Resources.Core.Reset))
253
	fmt.Printf("Search: %d/%d (reset in %d minutes)\n", rateLimits.Resources.Search.Remaining, rateLimits.Resources.Search.Limit, timing.GetRelativeTime(rateLimits.Resources.Search.Reset))
254
	fmt.Printf("GraphQL: %d/%d (reset in %d minutes)\n", rateLimits.Resources.GraphQL.Remaining, rateLimits.Resources.GraphQL.Limit, timing.GetRelativeTime(rateLimits.Resources.GraphQL.Reset))
255
	fmt.Printf("Rate: %d/%d (reset in %d minutes)\n", rateLimits.Rate.Remaining, rateLimits.Rate.Limit, timing.GetRelativeTime(rateLimits.Rate.Reset))
256
}
257
258
func writeCsv(csvFilePath string, headers []string, ghData [][]string) {
259 1
	file, err := os.Create(csvFilePath)
260 1
	if err != nil {
261
		log.Fatal("Cannot create file", err)
262
	}
263 1
	defer file.Close()
264 1
	writer := csv.NewWriter(file)
265 1
	defer writer.Flush()
266 1
	err = writer.Write(headers)
267 1
	if err != nil {
268
		log.Fatal("Cannot write to file", err)
269
	}
270 1
	for _, value := range ghData {
271 1
		err := writer.Write(value)
272 1
		if err != nil {
273
			log.Fatal("Cannot write to file", err)
274
		}
275
	}
276
}
277