1// Copyright 2014 The go-github AUTHORS. All rights reserved. 2// 3// Use of this source code is governed by a BSD-style 4// license that can be found in the LICENSE file. 5 6package github 7 8import ( 9 "context" 10 "fmt" 11 "time" 12) 13 14// ContributorStats represents a contributor to a repository and their 15// weekly contributions to a given repo. 16type ContributorStats struct { 17 Author *Contributor `json:"author,omitempty"` 18 Total *int `json:"total,omitempty"` 19 Weeks []WeeklyStats `json:"weeks,omitempty"` 20} 21 22func (c ContributorStats) String() string { 23 return Stringify(c) 24} 25 26// WeeklyStats represents the number of additions, deletions and commits 27// a Contributor made in a given week. 28type WeeklyStats struct { 29 Week *Timestamp `json:"w,omitempty"` 30 Additions *int `json:"a,omitempty"` 31 Deletions *int `json:"d,omitempty"` 32 Commits *int `json:"c,omitempty"` 33} 34 35func (w WeeklyStats) String() string { 36 return Stringify(w) 37} 38 39// ListContributorsStats gets a repo's contributor list with additions, 40// deletions and commit counts. 41// 42// If this is the first time these statistics are requested for the given 43// repository, this method will return an *AcceptedError and a status code of 44// 202. This is because this is the status that GitHub returns to signify that 45// it is now computing the requested statistics. A follow up request, after a 46// delay of a second or so, should result in a successful request. 47// 48// GitHub API docs: https://developer.github.com/v3/repos/statistics/#contributors 49func (s *RepositoriesService) ListContributorsStats(ctx context.Context, owner, repo string) ([]*ContributorStats, *Response, error) { 50 u := fmt.Sprintf("repos/%v/%v/stats/contributors", owner, repo) 51 req, err := s.client.NewRequest("GET", u, nil) 52 if err != nil { 53 return nil, nil, err 54 } 55 56 var contributorStats []*ContributorStats 57 resp, err := s.client.Do(ctx, req, &contributorStats) 58 if err != nil { 59 return nil, resp, err 60 } 61 62 return contributorStats, resp, nil 63} 64 65// WeeklyCommitActivity represents the weekly commit activity for a repository. 66// The days array is a group of commits per day, starting on Sunday. 67type WeeklyCommitActivity struct { 68 Days []int `json:"days,omitempty"` 69 Total *int `json:"total,omitempty"` 70 Week *Timestamp `json:"week,omitempty"` 71} 72 73func (w WeeklyCommitActivity) String() string { 74 return Stringify(w) 75} 76 77// ListCommitActivity returns the last year of commit activity 78// grouped by week. The days array is a group of commits per day, 79// starting on Sunday. 80// 81// If this is the first time these statistics are requested for the given 82// repository, this method will return an *AcceptedError and a status code of 83// 202. This is because this is the status that GitHub returns to signify that 84// it is now computing the requested statistics. A follow up request, after a 85// delay of a second or so, should result in a successful request. 86// 87// GitHub API docs: https://developer.github.com/v3/repos/statistics/#commit-activity 88func (s *RepositoriesService) ListCommitActivity(ctx context.Context, owner, repo string) ([]*WeeklyCommitActivity, *Response, error) { 89 u := fmt.Sprintf("repos/%v/%v/stats/commit_activity", owner, repo) 90 req, err := s.client.NewRequest("GET", u, nil) 91 if err != nil { 92 return nil, nil, err 93 } 94 95 var weeklyCommitActivity []*WeeklyCommitActivity 96 resp, err := s.client.Do(ctx, req, &weeklyCommitActivity) 97 if err != nil { 98 return nil, resp, err 99 } 100 101 return weeklyCommitActivity, resp, nil 102} 103 104// ListCodeFrequency returns a weekly aggregate of the number of additions and 105// deletions pushed to a repository. Returned WeeklyStats will contain 106// additions and deletions, but not total commits. 107// 108// If this is the first time these statistics are requested for the given 109// repository, this method will return an *AcceptedError and a status code of 110// 202. This is because this is the status that GitHub returns to signify that 111// it is now computing the requested statistics. A follow up request, after a 112// delay of a second or so, should result in a successful request. 113// 114// GitHub API docs: https://developer.github.com/v3/repos/statistics/#code-frequency 115func (s *RepositoriesService) ListCodeFrequency(ctx context.Context, owner, repo string) ([]*WeeklyStats, *Response, error) { 116 u := fmt.Sprintf("repos/%v/%v/stats/code_frequency", owner, repo) 117 req, err := s.client.NewRequest("GET", u, nil) 118 if err != nil { 119 return nil, nil, err 120 } 121 122 var weeks [][]int 123 resp, err := s.client.Do(ctx, req, &weeks) 124 125 // convert int slices into WeeklyStats 126 var stats []*WeeklyStats 127 for _, week := range weeks { 128 if len(week) != 3 { 129 continue 130 } 131 stat := &WeeklyStats{ 132 Week: &Timestamp{time.Unix(int64(week[0]), 0)}, 133 Additions: Int(week[1]), 134 Deletions: Int(week[2]), 135 } 136 stats = append(stats, stat) 137 } 138 139 return stats, resp, err 140} 141 142// RepositoryParticipation is the number of commits by everyone 143// who has contributed to the repository (including the owner) 144// as well as the number of commits by the owner themself. 145type RepositoryParticipation struct { 146 All []int `json:"all,omitempty"` 147 Owner []int `json:"owner,omitempty"` 148} 149 150func (r RepositoryParticipation) String() string { 151 return Stringify(r) 152} 153 154// ListParticipation returns the total commit counts for the 'owner' 155// and total commit counts in 'all'. 'all' is everyone combined, 156// including the 'owner' in the last 52 weeks. If you’d like to get 157// the commit counts for non-owners, you can subtract 'all' from 'owner'. 158// 159// The array order is oldest week (index 0) to most recent week. 160// 161// If this is the first time these statistics are requested for the given 162// repository, this method will return an *AcceptedError and a status code of 163// 202. This is because this is the status that GitHub returns to signify that 164// it is now computing the requested statistics. A follow up request, after a 165// delay of a second or so, should result in a successful request. 166// 167// GitHub API docs: https://developer.github.com/v3/repos/statistics/#participation 168func (s *RepositoriesService) ListParticipation(ctx context.Context, owner, repo string) (*RepositoryParticipation, *Response, error) { 169 u := fmt.Sprintf("repos/%v/%v/stats/participation", owner, repo) 170 req, err := s.client.NewRequest("GET", u, nil) 171 if err != nil { 172 return nil, nil, err 173 } 174 175 participation := new(RepositoryParticipation) 176 resp, err := s.client.Do(ctx, req, participation) 177 if err != nil { 178 return nil, resp, err 179 } 180 181 return participation, resp, nil 182} 183 184// PunchCard represents the number of commits made during a given hour of a 185// day of thew eek. 186type PunchCard struct { 187 Day *int // Day of the week (0-6: =Sunday - Saturday). 188 Hour *int // Hour of day (0-23). 189 Commits *int // Number of commits. 190} 191 192// ListPunchCard returns the number of commits per hour in each day. 193// 194// If this is the first time these statistics are requested for the given 195// repository, this method will return an *AcceptedError and a status code of 196// 202. This is because this is the status that GitHub returns to signify that 197// it is now computing the requested statistics. A follow up request, after a 198// delay of a second or so, should result in a successful request. 199// 200// GitHub API docs: https://developer.github.com/v3/repos/statistics/#punch-card 201func (s *RepositoriesService) ListPunchCard(ctx context.Context, owner, repo string) ([]*PunchCard, *Response, error) { 202 u := fmt.Sprintf("repos/%v/%v/stats/punch_card", owner, repo) 203 req, err := s.client.NewRequest("GET", u, nil) 204 if err != nil { 205 return nil, nil, err 206 } 207 208 var results [][]int 209 resp, err := s.client.Do(ctx, req, &results) 210 211 // convert int slices into Punchcards 212 var cards []*PunchCard 213 for _, result := range results { 214 if len(result) != 3 { 215 continue 216 } 217 card := &PunchCard{ 218 Day: Int(result[0]), 219 Hour: Int(result[1]), 220 Commits: Int(result[2]), 221 } 222 cards = append(cards, card) 223 } 224 225 return cards, resp, err 226} 227