gitech

Форк
0
/
repo_stats.go 
151 строка · 3.9 Кб
1
// Copyright 2019 The Gitea Authors. All rights reserved.
2
// SPDX-License-Identifier: MIT
3

4
package git
5

6
import (
7
	"bufio"
8
	"context"
9
	"fmt"
10
	"os"
11
	"sort"
12
	"strconv"
13
	"strings"
14
	"time"
15

16
	"code.gitea.io/gitea/modules/container"
17
)
18

19
// CodeActivityStats represents git statistics data
20
type CodeActivityStats struct {
21
	AuthorCount              int64
22
	CommitCount              int64
23
	ChangedFiles             int64
24
	Additions                int64
25
	Deletions                int64
26
	CommitCountInAllBranches int64
27
	Authors                  []*CodeActivityAuthor
28
}
29

30
// CodeActivityAuthor represents git statistics data for commit authors
31
type CodeActivityAuthor struct {
32
	Name    string
33
	Email   string
34
	Commits int64
35
}
36

37
// GetCodeActivityStats returns code statistics for activity page
38
func (repo *Repository) GetCodeActivityStats(fromTime time.Time, branch string) (*CodeActivityStats, error) {
39
	stats := &CodeActivityStats{}
40

41
	since := fromTime.Format(time.RFC3339)
42

43
	stdout, _, runErr := NewCommand(repo.Ctx, "rev-list", "--count", "--no-merges", "--branches=*", "--date=iso").AddOptionFormat("--since='%s'", since).RunStdString(&RunOpts{Dir: repo.Path})
44
	if runErr != nil {
45
		return nil, runErr
46
	}
47

48
	c, err := strconv.ParseInt(strings.TrimSpace(stdout), 10, 64)
49
	if err != nil {
50
		return nil, err
51
	}
52
	stats.CommitCountInAllBranches = c
53

54
	stdoutReader, stdoutWriter, err := os.Pipe()
55
	if err != nil {
56
		return nil, err
57
	}
58
	defer func() {
59
		_ = stdoutReader.Close()
60
		_ = stdoutWriter.Close()
61
	}()
62

63
	gitCmd := NewCommand(repo.Ctx, "log", "--numstat", "--no-merges", "--pretty=format:---%n%h%n%aN%n%aE%n", "--date=iso").AddOptionFormat("--since='%s'", since)
64
	if len(branch) == 0 {
65
		gitCmd.AddArguments("--branches=*")
66
	} else {
67
		gitCmd.AddArguments("--first-parent").AddDynamicArguments(branch)
68
	}
69

70
	stderr := new(strings.Builder)
71
	err = gitCmd.Run(&RunOpts{
72
		Env:    []string{},
73
		Dir:    repo.Path,
74
		Stdout: stdoutWriter,
75
		Stderr: stderr,
76
		PipelineFunc: func(ctx context.Context, cancel context.CancelFunc) error {
77
			_ = stdoutWriter.Close()
78
			scanner := bufio.NewScanner(stdoutReader)
79
			scanner.Split(bufio.ScanLines)
80
			stats.CommitCount = 0
81
			stats.Additions = 0
82
			stats.Deletions = 0
83
			authors := make(map[string]*CodeActivityAuthor)
84
			files := make(container.Set[string])
85
			var author string
86
			p := 0
87
			for scanner.Scan() {
88
				l := strings.TrimSpace(scanner.Text())
89
				if l == "---" {
90
					p = 1
91
				} else if p == 0 {
92
					continue
93
				} else {
94
					p++
95
				}
96
				if p > 4 && len(l) == 0 {
97
					continue
98
				}
99
				switch p {
100
				case 1: // Separator
101
				case 2: // Commit sha-1
102
					stats.CommitCount++
103
				case 3: // Author
104
					author = l
105
				case 4: // E-mail
106
					email := strings.ToLower(l)
107
					if _, ok := authors[email]; !ok {
108
						authors[email] = &CodeActivityAuthor{Name: author, Email: email, Commits: 0}
109
					}
110
					authors[email].Commits++
111
				default: // Changed file
112
					if parts := strings.Fields(l); len(parts) >= 3 {
113
						if parts[0] != "-" {
114
							if c, err := strconv.ParseInt(strings.TrimSpace(parts[0]), 10, 64); err == nil {
115
								stats.Additions += c
116
							}
117
						}
118
						if parts[1] != "-" {
119
							if c, err := strconv.ParseInt(strings.TrimSpace(parts[1]), 10, 64); err == nil {
120
								stats.Deletions += c
121
							}
122
						}
123
						files.Add(parts[2])
124
					}
125
				}
126
			}
127
			if err = scanner.Err(); err != nil {
128
				_ = stdoutReader.Close()
129
				return fmt.Errorf("GetCodeActivityStats scan: %w", err)
130
			}
131
			a := make([]*CodeActivityAuthor, 0, len(authors))
132
			for _, v := range authors {
133
				a = append(a, v)
134
			}
135
			// Sort authors descending depending on commit count
136
			sort.Slice(a, func(i, j int) bool {
137
				return a[i].Commits > a[j].Commits
138
			})
139
			stats.AuthorCount = int64(len(authors))
140
			stats.ChangedFiles = int64(len(files))
141
			stats.Authors = a
142
			_ = stdoutReader.Close()
143
			return nil
144
		},
145
	})
146
	if err != nil {
147
		return nil, fmt.Errorf("Failed to get GetCodeActivityStats for repository.\nError: %w\nStderr: %s", err, stderr)
148
	}
149

150
	return stats, nil
151
}
152

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.