gitea_hat/modules/git/repo_contributors.go

164 lines
4.2 KiB
Go

package git
import (
"bufio"
"context"
"fmt"
"os"
"strconv"
"strings"
gitea_git "code.gitea.io/gitea/modules/git"
)
type RepoContributor struct {
Name string `json:"name"`
Email string `json:"email"`
Commits int `json:"commits"`
ContributionPerc string `json:"contribution_perc"`
}
func GetRepoContributors(repo *gitea_git.Repository, page, pageSize int) (int, []*RepoContributor, error) {
var total, totalContributions, skip int
var contributors []*RepoContributor
skip = (page - 1) * pageSize
stdoutReader, stdoutWriter, err := os.Pipe()
if err != nil {
return total, nil, err
}
defer func() {
_ = stdoutReader.Close()
_ = stdoutWriter.Close()
}()
cmd := gitea_git.NewCommand(repo.Ctx, "shortlog", "-sne", "--all")
stderr := new(strings.Builder)
err = cmd.Run(&gitea_git.RunOpts{
Env: []string{},
Dir: repo.Path,
Stdout: stdoutWriter,
Stderr: stderr,
PipelineFunc: func(ctx context.Context, cancel context.CancelFunc) error {
_ = stdoutWriter.Close()
scanner := bufio.NewScanner(stdoutReader)
scanner.Split(bufio.ScanLines)
var ca int
for scanner.Scan() {
l := strings.TrimSpace(scanner.Text())
commits := l[0:strings.Index(l, "\t")]
commitsInt, err := strconv.Atoi(commits)
if err != nil {
return err
}
name := l[strings.Index(l, "\t")+1 : strings.Index(l, " <")]
email := l[strings.Index(l, "<")+1 : strings.Index(l, ">")]
totalContributions += commitsInt
total++
if skip > 0 {
skip--
} else {
if ca < pageSize {
contributors = append(contributors, &RepoContributor{
Commits: commitsInt,
Name: name,
Email: email,
})
ca++
}
}
}
_ = stdoutReader.Close()
return nil
},
})
for _, cont := range contributors {
fperc := fmt.Sprintf("%.2f", float64(cont.Commits)*100/float64(totalContributions))
cont.ContributionPerc = fperc + "%"
}
return total, contributors, nil
}
func GetRepoContributorsNew(repo *gitea_git.Repository, page, pageSize int) (int, []*RepoContributor, error) {
var total, totalContributions, skip int
var contributors []*RepoContributor
var contributorInfos []*RepoContributor
contributorInfoHash := make(map[string]*RepoContributor)
skip = (page - 1) * pageSize
stdoutReader, stdoutWriter, err := os.Pipe()
if err != nil {
return total, nil, err
}
defer func() {
_ = stdoutReader.Close()
_ = stdoutWriter.Close()
}()
cmd := gitea_git.NewCommand(repo.Ctx, "shortlog", "-sne", "--all")
stderr := new(strings.Builder)
err = cmd.Run(&gitea_git.RunOpts{
Env: []string{},
Dir: repo.Path,
Stdout: stdoutWriter,
Stderr: stderr,
PipelineFunc: func(ctx context.Context, cancel context.CancelFunc) error {
_ = stdoutWriter.Close()
scanner := bufio.NewScanner(stdoutReader)
scanner.Split(bufio.ScanLines)
for scanner.Scan() {
l := strings.TrimSpace(scanner.Text())
commits := l[0:strings.Index(l, "\t")]
commitsInt, err := strconv.Atoi(commits)
if err != nil {
return err
}
name := l[strings.Index(l, "\t")+1 : strings.Index(l, " <")]
email := strings.ToLower(l[strings.Index(l, "<")+1 : strings.Index(l, ">")])
totalContributions += commitsInt
// committer is not system user
if existedContributorInfo, ok := contributorInfoHash[email]; ok {
// existed: same primary email, different committer name
existedContributorInfo.Commits += commitsInt
} else {
var newContributor = &RepoContributor{
Commits: commitsInt,
Name: name,
Email: email,
}
total++
contributorInfos = append(contributorInfos, newContributor)
contributorInfoHash[email] = newContributor
}
}
_ = stdoutReader.Close()
return nil
},
})
var ca int
for _, cont := range contributorInfos {
if skip > 0 {
skip--
} else {
if ca < pageSize {
fperc := fmt.Sprintf("%.2f", float64(cont.Commits)*100/float64(totalContributions))
contributors = append(contributors, &RepoContributor{
Commits: cont.Commits,
Name: cont.Name,
Email: cont.Email,
ContributionPerc: fperc + "%",
})
ca++
}
}
}
return total, contributors, nil
}