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.

github.calculateReturningContributors   C
last analyzed

Complexity

Conditions 11

Size

Total Lines 21
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 11
eloc 15
nop 2
dl 0
loc 21
rs 5.4
c 0
b 0
f 0

How to fix   Complexity   

Complexity

Complex classes like github.calculateReturningContributors often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

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
package github
6
7
import (
8
	"encoding/json"
9
	"fmt"
10
11
	"github.com/fedir/ghstat/httpcache"
12
)
13
14
// StatsContributor contains statistical data for contribution
15
type StatsContributor struct {
16
	Author struct {
17
		Login string `json:"login"`
18
	} `json:"author"`
19
	TotalCommits int `json:"total"`
20
	Weeks        []struct {
21
		Week      int `json:"w"`
22
		Additions int `json:"a"`
23
		Deletions int `json:"d"`
24
		Commits   int `json:"c"`
25
	} `json:"weeks"`
26
}
27
28
// ContributionStatistics contains multiple statistics about contribution into the repository
29
type ContributionStatistics struct {
30
	TotalCommits              int
31
	TotalAdditions            int
32
	TotalDeletions            int
33
	TotalCodeChanges          int
34
	MediumCommitSize          int
35
	AverageContributionPeriod int
36
	ReturningContributors     int
37
}
38
39
// GetContributionStatistics gets detailsed statistics about contributors of the repository
40
func GetContributionStatistics(repoKey string, tmpFolder string, debug bool) ContributionStatistics {
41
	url := "https://api.github.com/repos/" + repoKey + "/stats/contributors"
42
	fullResp := httpcache.MakeCachedHTTPRequest(url, tmpFolder, debug)
43
	jsonResponse, _, _ := httpcache.ReadResp(fullResp)
44
	cs := extractContributionStatisticsFromJSON(jsonResponse, debug)
45
	if debug {
46
		fmt.Printf("ACP for %s: %d days\n", repoKey, cs.AverageContributionPeriod)
47
		fmt.Printf("RC for %s: %d\n", repoKey, cs.ReturningContributors)
48
	}
49
	return cs
50
}
51
52
// GetCommitsByDay calculates the rate of commits by day of the repository
53
func GetCommitsByDay(totalCommits int, repositoryAge int) float64 {
54
	var commitsByDay float64
55
	totalCommitsFloat := float64(totalCommits)
56
	repositoryAgeFloat := float64(repositoryAge)
57
	if totalCommitsFloat != 0 && repositoryAgeFloat != 0 {
58
		commitsByDay = totalCommitsFloat / repositoryAgeFloat
59
	} else {
60
		commitsByDay = 0
61
	}
62
	return commitsByDay
63
}
64
65
func extractContributionStatisticsFromJSON(jsonResponse []byte, debug bool) ContributionStatistics {
66
	var cs ContributionStatistics
67
	cs.TotalCommits = 0
68
	cs.TotalAdditions = 0
69
	cs.TotalDeletions = 0
70
	cs.TotalCodeChanges = 0
71
	contributionStatistics := make([]StatsContributor, 0)
72
	json.Unmarshal(jsonResponse, &contributionStatistics)
73
	for _, c := range contributionStatistics {
74
		cs.TotalCommits += c.TotalCommits
75
		for _, cw := range c.Weeks {
76
			cs.TotalAdditions += cw.Additions
77
			cs.TotalDeletions += cw.Deletions
78
			cs.TotalCodeChanges += cw.Additions
79
			cs.TotalCodeChanges += cw.Deletions
80
		}
81
	}
82
	cs.MediumCommitSize = calculateMediumCommitSize(cs.TotalCommits, cs.TotalCodeChanges)
83
	cs.AverageContributionPeriod = calculateAverageContributionPeriod(contributionStatistics, debug)
84
	cs.ReturningContributors = calculateReturningContributors(contributionStatistics, debug)
85
	return cs
86
}
87
88
func calculateMediumCommitSize(totalCommits int, totalCodeChanges int) int {
89
	return int(float64(totalCodeChanges) / float64(totalCommits))
90
}
91
92
func calculateAverageContributionPeriod(cs []StatsContributor, debug bool) int {
93
	type contributorContibutionPeriod struct {
94
		first  int
95
		last   int
96
		period int
97
	}
98
	acp := 0
99
	totalAcp := 0
100
	nContirbutors := len(cs)
101
	for _, c := range cs {
102
		ccp := contributorContibutionPeriod{
103
			first:  0,
104
			last:   0,
105
			period: 0,
106
		}
107
		for _, cw := range c.Weeks {
108
			if cw.Additions > 0 || cw.Commits > 0 || cw.Deletions > 0 {
109
				if ccp.first == 0 {
110
					ccp.first = cw.Week
111
				} else if cw.Week < ccp.first {
112
					ccp.first = cw.Week
113
				}
114
				if cw.Week > ccp.last {
115
					ccp.last = cw.Week
116
				}
117
			}
118
		}
119
		ccp.period = (ccp.last - ccp.first) / 86400
120
		totalAcp += ccp.period
121
		if debug {
122
			fmt.Printf("%s, %d, %d, %d\n", c.Author, ccp.first, ccp.last, ccp.period)
123
		}
124
	}
125
	acp = int(float64(totalAcp) / float64(nContirbutors))
126
	return acp
127
}
128
129
func calculateReturningContributors(cs []StatsContributor, debug bool) int {
130
	rc := 0
131
	for _, c := range cs {
132
		contributions := 0
133
		for _, cw := range c.Weeks {
134
			if cw.Additions > 0 || cw.Commits > 0 || cw.Deletions > 0 {
135
				contributions++
136
			}
137
		}
138
		if contributions > 4 {
139
			rc++
140
			if debug {
141
				fmt.Printf("%s is returning contributor and has %d weeks of contribution\n", c.Author, contributions)
142
			}
143
		} else {
144
			if debug {
145
				fmt.Printf("%s is onetime contributor and has %d week(s) of contribution\n", c.Author, contributions)
146
			}
147
		}
148
	}
149
	return rc
150
}
151