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 ( 4e3a59...78b6ed )
by Fedir
03:41
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 1
	closedIssues := github.GetRepositoryClosedIssues(rKey, tmpFolder, debug)
142 1
	topContributorsFollowers, totalContributors := github.GetRepositoryContributors(rKey, tmpFolder, debug)
143 1
	totalTags := github.GetRepositoryTagsNumber(rKey, tmpFolder, debug)
144 1
	activeForkersPercentage := github.GetActiveForkersPercentage(totalContributors, repositoryData.Forks)
145 1
	issueByDay := github.GetIssueByDay(closedIssues+repositoryData.OpenIssues, repositoryAge)
146 1
	closedIssuesPercentage := github.GetClosedIssuesPercentage(repositoryData.OpenIssues, int(closedIssues))
147 1
	contributionStatistics := github.GetContributionStatistics(rKey, tmpFolder, debug)
148 1
	commitsByDay := github.GetCommitsByDay(contributionStatistics.TotalCommits, repositoryAge)
149 1
	ghProjectData := []string{
150
		repositoryData.FullName,
151
		fmt.Sprintf("https://github.com/%s", repositoryData.FullName),
152
		fmt.Sprintf("%s", repositoryData.Language),
153
		fmt.Sprintf("%s", func(a string) string {
154 1
			if a == "" {
155 1
				a = "[Account removed]"
156
			}
157 1
			return a
158
		}(authorLogin)),
159
		fmt.Sprintf("%s", func(l string) string {
160 1
			if l == "" {
161 1
				l = "[Unknown]"
162
			}
163 1
			return l
164
		}(repositoryData.License.SPDXID)),
165
		fmt.Sprintf("%d", authorFollowers),
166
		fmt.Sprintf("%d", topContributorsFollowers),
167
		fmt.Sprintf("%d/%02d", repositoryData.CreatedAt.Year(), repositoryData.CreatedAt.Month()),
168
		fmt.Sprintf("%d", repositoryAge),
169
		fmt.Sprintf("%d", contributionStatistics.TotalCommits),
170
		fmt.Sprintf("%d", contributionStatistics.TotalAdditions),
171
		fmt.Sprintf("%d", contributionStatistics.TotalDeletions),
172
		fmt.Sprintf("%d", contributionStatistics.TotalCodeChanges),
173
		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...
174
		fmt.Sprintf("%.4f", commitsByDay),
175
		fmt.Sprintf("%d", contributionStatistics.MediumCommitSize),
176
		fmt.Sprintf("%d", totalTags),
177
		fmt.Sprintf("%d", repositoryData.Watchers),
178
		fmt.Sprintf("%d", repositoryData.Forks),
179
		fmt.Sprintf("%d", totalContributors),
180
		fmt.Sprintf("%.2f", activeForkersPercentage),
181
		fmt.Sprintf("%d", repositoryData.OpenIssues),
182
		fmt.Sprintf("%d", closedIssues+repositoryData.OpenIssues),
183
		fmt.Sprintf("%.4f", issueByDay),
184
		fmt.Sprintf("%.2f", closedIssuesPercentage),
185
		"0",
186
	}
187 1
	dataChan <- ghProjectData
188
}
189
190
func clearHTTPCacheFolder(tmpFolderPath string, dryRun bool) error {
191
	d, err := os.Open(tmpFolderPath)
192
	if err != nil {
193
		log.Fatalf("Could not open %s", tmpFolderPath)
194
	}
195
	defer d.Close()
196
	names, err := d.Readdirnames(-1)
197
	if err != nil {
198
		log.Fatalf("Could not read from %s", tmpFolderPath)
199
	}
200
	for _, name := range names {
201
		fp := filepath.Join(tmpFolderPath, name)
202
		if dryRun {
203
			fmt.Printf("Deleted %s\n", fp)
204
		} else {
205
			err = os.RemoveAll(fp)
206
			if err != nil {
207
				log.Fatalf("Could not remove %s", fp)
208
			}
209
			fmt.Printf("Deleted %s\n", fp)
210
		}
211
	}
212
	return nil
213
}
214
215
func checkAndPrintRateLimit() {
216
	type RateLimits struct {
217
		Resources struct {
218
			Core struct {
219
				Limit     int `json:"limit"`
220
				Remaining int `json:"remaining"`
221
				Reset     int `json:"reset"`
222
			} `json:"core"`
223
			Search struct {
224
				Limit     int `json:"limit"`
225
				Remaining int `json:"remaining"`
226
				Reset     int `json:"reset"`
227
			} `json:"search"`
228
			GraphQL struct {
229
				Limit     int `json:"limit"`
230
				Remaining int `json:"remaining"`
231
				Reset     int `json:"reset"`
232
			} `json:"graphql"`
233
		} `json:"resources"`
234
		Rate struct {
235
			Limit     int `json:"limit"`
236
			Remaining int `json:"remaining"`
237
			Reset     int `json:"reset"`
238
		} `json:"rate"`
239
	}
240
	url := "https://api.github.com/rate_limit"
241
	resp, statusCode, err := httpcache.MakeHTTPRequest(url)
242
	if err != nil {
243
		log.Fatalf("Error during checking rate limit : %d %v#", statusCode, err)
244
	}
245
	jsonResponse, _, _ := httpcache.ReadResp(resp)
246
	rateLimits := RateLimits{}
247
	json.Unmarshal(jsonResponse, &rateLimits)
248
	fmt.Printf("Core: %d/%d (reset in %d minutes)\n", rateLimits.Resources.Core.Remaining, rateLimits.Resources.Core.Limit, timing.GetRelativeTime(rateLimits.Resources.Core.Reset))
249
	fmt.Printf("Search: %d/%d (reset in %d minutes)\n", rateLimits.Resources.Search.Remaining, rateLimits.Resources.Search.Limit, timing.GetRelativeTime(rateLimits.Resources.Search.Reset))
250
	fmt.Printf("GraphQL: %d/%d (reset in %d minutes)\n", rateLimits.Resources.GraphQL.Remaining, rateLimits.Resources.GraphQL.Limit, timing.GetRelativeTime(rateLimits.Resources.GraphQL.Reset))
251
	fmt.Printf("Rate: %d/%d (reset in %d minutes)\n", rateLimits.Rate.Remaining, rateLimits.Rate.Limit, timing.GetRelativeTime(rateLimits.Rate.Reset))
252
}
253
254
func writeCsv(csvFilePath string, headers []string, ghData [][]string) {
255 1
	file, err := os.Create(csvFilePath)
256 1
	if err != nil {
257
		log.Fatal("Cannot create file", err)
258
	}
259 1
	defer file.Close()
260 1
	writer := csv.NewWriter(file)
261 1
	defer writer.Flush()
262 1
	err = writer.Write(headers)
263 1
	if err != nil {
264
		log.Fatal("Cannot write to file", err)
265
	}
266 1
	for _, value := range ghData {
267 1
		err := writer.Write(value)
268 1
		if err != nil {
269
			log.Fatal("Cannot write to file", err)
270
		}
271
	}
272
}
273