aboutsummaryrefslogtreecommitdiffstats
path: root/models/repo_activity.go
diff options
context:
space:
mode:
authorLauris BH <lauris@nix.lv>2019-05-04 15:39:03 +0300
committerGitHub <noreply@github.com>2019-05-04 15:39:03 +0300
commit1fa96629461ac4229932b0a4526fc2f60c88ec51 (patch)
treecaa3906758c6998bb6450932393336ac57c3db19 /models/repo_activity.go
parent2933ae4e88bb954af76c4e1e67c7ab1e4892e4a4 (diff)
downloadgitea-1fa96629461ac4229932b0a4526fc2f60c88ec51.tar.gz
gitea-1fa96629461ac4229932b0a4526fc2f60c88ec51.zip
Git statistics in Activity tab (#4724)
* Initial implementation for git statistics in Activity tab * Create top user by commit count endpoint * Add UI and update src-d/go-git dependency * Add coloring * Fix typo * Move git activity stats data extraction to git module * Fix message * Add git code stats test
Diffstat (limited to 'models/repo_activity.go')
-rw-r--r--models/repo_activity.go88
1 files changed, 82 insertions, 6 deletions
diff --git a/models/repo_activity.go b/models/repo_activity.go
index c3017e8e39..fb1385a54b 100644
--- a/models/repo_activity.go
+++ b/models/repo_activity.go
@@ -6,11 +6,22 @@ package models
import (
"fmt"
+ "sort"
"time"
+ "code.gitea.io/gitea/modules/git"
+
"github.com/go-xorm/xorm"
)
+// ActivityAuthorData represents statistical git commit count data
+type ActivityAuthorData struct {
+ Name string `json:"name"`
+ Login string `json:"login"`
+ AvatarLink string `json:"avatar_link"`
+ Commits int64 `json:"commits"`
+}
+
// ActivityStats represets issue and pull request information.
type ActivityStats struct {
OpenedPRs PullRequestList
@@ -24,32 +35,97 @@ type ActivityStats struct {
UnresolvedIssues IssueList
PublishedReleases []*Release
PublishedReleaseAuthorCount int64
+ Code *git.CodeActivityStats
}
// GetActivityStats return stats for repository at given time range
-func GetActivityStats(repoID int64, timeFrom time.Time, releases, issues, prs bool) (*ActivityStats, error) {
- stats := &ActivityStats{}
+func GetActivityStats(repo *Repository, timeFrom time.Time, releases, issues, prs, code bool) (*ActivityStats, error) {
+ stats := &ActivityStats{Code: &git.CodeActivityStats{}}
if releases {
- if err := stats.FillReleases(repoID, timeFrom); err != nil {
+ if err := stats.FillReleases(repo.ID, timeFrom); err != nil {
return nil, fmt.Errorf("FillReleases: %v", err)
}
}
if prs {
- if err := stats.FillPullRequests(repoID, timeFrom); err != nil {
+ if err := stats.FillPullRequests(repo.ID, timeFrom); err != nil {
return nil, fmt.Errorf("FillPullRequests: %v", err)
}
}
if issues {
- if err := stats.FillIssues(repoID, timeFrom); err != nil {
+ if err := stats.FillIssues(repo.ID, timeFrom); err != nil {
return nil, fmt.Errorf("FillIssues: %v", err)
}
}
- if err := stats.FillUnresolvedIssues(repoID, timeFrom, issues, prs); err != nil {
+ if err := stats.FillUnresolvedIssues(repo.ID, timeFrom, issues, prs); err != nil {
return nil, fmt.Errorf("FillUnresolvedIssues: %v", err)
}
+ if code {
+ gitRepo, err := git.OpenRepository(repo.RepoPath())
+ if err != nil {
+ return nil, fmt.Errorf("OpenRepository: %v", err)
+ }
+ code, err := gitRepo.GetCodeActivityStats(timeFrom, repo.DefaultBranch)
+ if err != nil {
+ return nil, fmt.Errorf("FillFromGit: %v", err)
+ }
+ stats.Code = code
+ }
return stats, nil
}
+// GetActivityStatsTopAuthors returns top author stats for git commits for all branches
+func GetActivityStatsTopAuthors(repo *Repository, timeFrom time.Time, count int) ([]*ActivityAuthorData, error) {
+ gitRepo, err := git.OpenRepository(repo.RepoPath())
+ if err != nil {
+ return nil, fmt.Errorf("OpenRepository: %v", err)
+ }
+ code, err := gitRepo.GetCodeActivityStats(timeFrom, "")
+ if err != nil {
+ return nil, fmt.Errorf("FillFromGit: %v", err)
+ }
+ if code.Authors == nil {
+ return nil, nil
+ }
+ users := make(map[int64]*ActivityAuthorData)
+ for k, v := range code.Authors {
+ if len(k) == 0 {
+ continue
+ }
+ u, err := GetUserByEmail(k)
+ if u == nil || IsErrUserNotExist(err) {
+ continue
+ }
+ if err != nil {
+ return nil, err
+ }
+ if user, ok := users[u.ID]; !ok {
+ users[u.ID] = &ActivityAuthorData{
+ Name: u.DisplayName(),
+ Login: u.LowerName,
+ AvatarLink: u.AvatarLink(),
+ Commits: v,
+ }
+ } else {
+ user.Commits += v
+ }
+ }
+ v := make([]*ActivityAuthorData, 0)
+ for _, u := range users {
+ v = append(v, u)
+ }
+
+ sort.Slice(v[:], func(i, j int) bool {
+ return v[i].Commits < v[j].Commits
+ })
+
+ cnt := count
+ if cnt > len(v) {
+ cnt = len(v)
+ }
+
+ return v[:cnt], nil
+}
+
// ActivePRCount returns total active pull request count
func (stats *ActivityStats) ActivePRCount() int {
return stats.OpenedPRCount() + stats.MergedPRCount()