選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

repo_stats.go 3.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. // Copyright 2019 The Gitea Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package git
  5. import (
  6. "bufio"
  7. "bytes"
  8. "fmt"
  9. "sort"
  10. "strconv"
  11. "strings"
  12. "time"
  13. )
  14. // CodeActivityStats represents git statistics data
  15. type CodeActivityStats struct {
  16. AuthorCount int64
  17. CommitCount int64
  18. ChangedFiles int64
  19. Additions int64
  20. Deletions int64
  21. CommitCountInAllBranches int64
  22. Authors []*CodeActivityAuthor
  23. }
  24. // CodeActivityAuthor represents git statistics data for commit authors
  25. type CodeActivityAuthor struct {
  26. Name string
  27. Email string
  28. Commits int64
  29. }
  30. // GetCodeActivityStats returns code statistics for acitivity page
  31. func (repo *Repository) GetCodeActivityStats(fromTime time.Time, branch string) (*CodeActivityStats, error) {
  32. stats := &CodeActivityStats{}
  33. since := fromTime.Format(time.RFC3339)
  34. stdout, err := NewCommand("rev-list", "--count", "--no-merges", "--branches=*", "--date=iso", fmt.Sprintf("--since='%s'", since)).RunInDirBytes(repo.Path)
  35. if err != nil {
  36. return nil, err
  37. }
  38. c, err := strconv.ParseInt(strings.TrimSpace(string(stdout)), 10, 64)
  39. if err != nil {
  40. return nil, err
  41. }
  42. stats.CommitCountInAllBranches = c
  43. args := []string{"log", "--numstat", "--no-merges", "--pretty=format:---%n%h%n%an%n%ae%n", "--date=iso", fmt.Sprintf("--since='%s'", since)}
  44. if len(branch) == 0 {
  45. args = append(args, "--branches=*")
  46. } else {
  47. args = append(args, "--first-parent", branch)
  48. }
  49. stdout, err = NewCommand(args...).RunInDirBytes(repo.Path)
  50. if err != nil {
  51. return nil, err
  52. }
  53. scanner := bufio.NewScanner(bytes.NewReader(stdout))
  54. scanner.Split(bufio.ScanLines)
  55. stats.CommitCount = 0
  56. stats.Additions = 0
  57. stats.Deletions = 0
  58. authors := make(map[string]*CodeActivityAuthor)
  59. files := make(map[string]bool)
  60. var author string
  61. p := 0
  62. for scanner.Scan() {
  63. l := strings.TrimSpace(scanner.Text())
  64. if l == "---" {
  65. p = 1
  66. } else if p == 0 {
  67. continue
  68. } else {
  69. p++
  70. }
  71. if p > 4 && len(l) == 0 {
  72. continue
  73. }
  74. switch p {
  75. case 1: // Separator
  76. case 2: // Commit sha-1
  77. stats.CommitCount++
  78. case 3: // Author
  79. author = l
  80. case 4: // E-mail
  81. email := strings.ToLower(l)
  82. if _, ok := authors[email]; !ok {
  83. authors[email] = &CodeActivityAuthor{
  84. Name: author,
  85. Email: email,
  86. Commits: 0,
  87. }
  88. }
  89. authors[email].Commits++
  90. default: // Changed file
  91. if parts := strings.Fields(l); len(parts) >= 3 {
  92. if parts[0] != "-" {
  93. if c, err := strconv.ParseInt(strings.TrimSpace(parts[0]), 10, 64); err == nil {
  94. stats.Additions += c
  95. }
  96. }
  97. if parts[1] != "-" {
  98. if c, err := strconv.ParseInt(strings.TrimSpace(parts[1]), 10, 64); err == nil {
  99. stats.Deletions += c
  100. }
  101. }
  102. if _, ok := files[parts[2]]; !ok {
  103. files[parts[2]] = true
  104. }
  105. }
  106. }
  107. }
  108. a := make([]*CodeActivityAuthor, 0, len(authors))
  109. for _, v := range authors {
  110. a = append(a, v)
  111. }
  112. // Sort authors descending depending on commit count
  113. sort.Slice(a, func(i, j int) bool {
  114. return a[i].Commits > a[j].Commits
  115. })
  116. stats.AuthorCount = int64(len(authors))
  117. stats.ChangedFiles = int64(len(files))
  118. stats.Authors = a
  119. return stats, nil
  120. }