这是一份通过gitlab events api 进行用户代码量统计的go语言实现的代码
代码实现
main函数
func main() {
client, err := gitlab_cli.NewGitLabClient("https://xxxx/api/v4", "xxxx", "")
if err != nil {
fmt.Println(err.Error())
}
collect := gitlab_cli.NewCollectCodeCounts(client)
collect.RunWithMaster()
collect.PrintData()
}
gitlab cli
package gitlab_cli
import (
"github.com/xanzy/go-gitlab"
)
type Client struct {
gitlab *gitlab.Client
token string
url string
user string
}
func NewGitLabClient(url string, token string, user string) (*Client, error) {
gitlabCli := Client{url: url, token: token, user: user}
err := gitlabCli.init()
return &gitlabCli, err
}
func (g *Client) init() error {
git, err := gitlab.NewClient(g.token, gitlab.WithBaseURL(g.url))
g.gitlab = git
return err
}
func (g *Client) GetUsers(page int, perPage int) ([]*gitlab.User, error) {
users, _, err := g.gitlab.Users.ListUsers(&gitlab.ListUsersOptions{
ListOptions: gitlab.ListOptions{
Page: page,
PerPage: perPage,
},
})
return users, err
}
主要逻辑
package gitlab_cli
import (
"encoding/csv"
"encoding/json"
"fmt"
"github.com/xanzy/go-gitlab"
"os"
"strings"
"sync"
)
type UserData struct {
CommitId map[string]struct{}
ProjectCount map[int]*ProjectCount
UserName string
Additions int
Deletions int
Total int
}
type CollectCodeCounts struct {
gitlab *Client
data []UserData
sync.Mutex
}
func (c *CollectCodeCounts) PrintData() {
data, err := json.Marshal(&c.data)
if err != nil {
fmt.Println(err)
}
err = os.WriteFile("codeCount.json", data, os.ModePerm)
if err != nil {
fmt.Println(err)
}
f, err := os.Create("codeCount.csv")
if err != nil {
panic(err)
}
_, _ = f.WriteString("\xEF\xBB\xBF")
writer := csv.NewWriter(f)
header := []string{"用户名", "项目名称", "新增总行数", "删除总行数", "代码总行数", "总提交次数", "备注"}
if err := writer.Write(header); err != nil {
fmt.Println(err.Error())
}
for _, d := range c.data {
var csvRow []string
projectStr := ""
for _, p := range d.ProjectCount {
projectStr += fmt.Sprintf("%v %v %v %v %v\n", p.Name, p.Additions, p.Deletions, p.Total, len(p.CommitId))
}
csvRow = append(csvRow, d.UserName, projectStr, fmt.Sprintf("%v", d.Additions), fmt.Sprintf("%v", d.Deletions), fmt.Sprintf("%v", d.Total), fmt.Sprintf("%v", len(d.CommitId)))
if err := writer.Write(csvRow); err != nil {
fmt.Println(err.Error())
}
}
writer.Flush()
}
func NewCollectCodeCounts(gitlab *Client) *CollectCodeCounts {
return &CollectCodeCounts{
gitlab: gitlab,
data: make([]UserData, 0),
Mutex: sync.Mutex{},
}
}
func (c *CollectCodeCounts) RunWithMaster() {
page := 1
perPage := 100
wg := sync.WaitGroup{}
runChan := make(chan struct{}, 200)
endFlag := false
for {
user, err := c.gitlab.GetUsers(page, perPage)
if err != nil {
fmt.Println(err.Error())
}
if len(user) <= 0 {
endFlag = true
break
}
page += 1
for i := range user {
runChan <- struct{}{}
wg.Add(1)
go c.runWithMaster(user[i], &wg, runChan)
}
}
for {
if endFlag == true {
break
}
}
wg.Wait()
}
type ProjectCount struct {
Additions int
Deletions int
Total int
Name string
Id int
CommitId []CommitData
}
func (c *CollectCodeCounts) runWithMaster(user *gitlab.User, wg *sync.WaitGroup, runChan chan struct{}) {
defer func() {
<-runChan
wg.Done()
}()
timeAfter, err := gitlab.ParseISOTime("2023-06-03")
if err != nil {
fmt.Println(err)
}
beforeAfter, err := gitlab.ParseISOTime("2023-06-10")
if err != nil {
fmt.Println(err)
}
userData := UserData{
CommitId: map[string]struct{}{},
ProjectCount: map[int]*ProjectCount{},
UserName: user.Name,
Additions: 0,
Deletions: 0,
Total: 0,
}
page := 0
action := gitlab.EventTypeValue("pushed")
for {
events, response, err := c.gitlab.gitlab.Users.ListUserContributionEvents(user.ID, &gitlab.ListContributionEventsOptions{
ListOptions: gitlab.ListOptions{
Page: page,
PerPage: 100,
},
After: &timeAfter,
Before: &beforeAfter,
Action: &action,
})
if err != nil {
fmt.Println(err.Error())
break
}
for i := range events {
//if !strings.Contains(events[i].PushData.Ref, "master") {
// continue
//}
if events[i].PushData.Action == "created" {
continue
}
if strings.HasPrefix(events[i].PushData.CommitTitle, "Merge ") {
continue
}
if events[i].PushData.CommitTo == "" {
continue
}
result, err := c.handleEvent(events[i])
if err != nil {
continue
}
// 总计总行数
if _, ok := userData.CommitId[result.Id]; !ok {
userData.CommitId[result.Id] = struct{}{}
userData.Additions += result.Additions
userData.Deletions += result.Deletions
userData.Total += result.Total
fmt.Println(result)
// 按照项目统计
if _, okk := userData.ProjectCount[result.ProjectId]; !okk {
data := ProjectCount{
Additions: result.Additions,
Deletions: result.Deletions,
Total: result.Total,
Name: result.ProjectName,
Id: result.ProjectId,
CommitId: []CommitData{result},
}
project, _, err := c.gitlab.gitlab.Projects.GetProject(result.ProjectId, &gitlab.GetProjectOptions{})
if err == nil {
data.Name = project.Name
}
userData.ProjectCount[result.ProjectId] = &data
} else {
data := userData.ProjectCount[result.ProjectId]
data.Additions += result.Additions
data.Deletions += result.Deletions
data.Total += result.Total
data.CommitId = append(data.CommitId, result)
}
}
}
if response.TotalPages <= page {
break
}
page += 1
}
if userData.Total == 0 {
return
}
c.Lock()
c.data = append(c.data, userData)
c.Unlock()
}
type CommitData struct {
Id string
Additions int
Ref string
Deletions int
Total int
ProjectId int
ProjectName string
}
func (c *CollectCodeCounts) handleEvent(event *gitlab.ContributionEvent) (CommitData, error) {
commit, _, err := c.gitlab.gitlab.Commits.GetCommit(event.ProjectID, event.PushData.CommitTo)
if err != nil {
fmt.Println(err)
return CommitData{}, err
}
return CommitData{
Id: commit.ID,
Additions: commit.Stats.Additions,
Deletions: commit.Stats.Deletions,
Total: commit.Stats.Total,
ProjectId: commit.ProjectID,
Ref: event.PushData.Ref,
}, nil
}