123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445 |
- package service
- import (
- "context"
- "encoding/json"
- "sort"
- "go-common/app/admin/ep/saga/model"
- "go-common/app/admin/ep/saga/service/utils"
- "go-common/library/log"
- "github.com/xanzy/go-gitlab"
- )
- // QueryProjectBranchList query project commit info according to project id.
- func (s *Service) QueryProjectBranchList(c context.Context, req *model.ProjectDataReq) (resp []*gitlab.Branch, err error) {
- var (
- branch []*gitlab.Branch
- response *gitlab.Response
- branchItem []*gitlab.Branch
- )
- if branch, response, err = s.gitlab.ListProjectBranch(req.ProjectID, 1); err != nil {
- return
- }
- page := 2
- for page <= response.TotalPages {
- if branchItem, _, err = s.gitlab.ListProjectBranch(req.ProjectID, page); err != nil {
- return
- }
- branch = append(branch, branchItem...)
- page++
- }
- resp = branch
- return
- }
- // QueryBranchDiffWith ...
- func (s *Service) QueryBranchDiffWith(c context.Context, req *model.BranchDiffWithRequest) (resp []*model.BranchDiffWithResponse, err error) {
- var (
- branchDiff []*model.BranchDiffWithResponse
- )
- // 默认主分支为master
- if req.Master == "" {
- req.Master = "master"
- }
- if branchDiff, err = s.AllBranchDiffWithMaster(c, req.ProjectID, req.Master); err != nil {
- return
- }
- if req.Branch != "" {
- for _, branch := range branchDiff {
- if branch.Branch == req.Branch {
- resp = append(resp, branch)
- return
- }
- }
- }
- switch req.SortBy {
- case "update":
- sort.Slice(branchDiff, func(i, j int) bool {
- if branchDiff[i].LatestUpdateTime.After(*branchDiff[j].LatestUpdateTime) {
- return false
- }
- if branchDiff[i].LatestUpdateTime.Before(*branchDiff[j].LatestUpdateTime) {
- return true
- }
- return true
- })
- case "sync":
- sort.Slice(branchDiff, func(i, j int) bool {
- if branchDiff[i].LatestSyncTime.After(*branchDiff[j].LatestSyncTime) {
- return false
- }
- if branchDiff[i].LatestSyncTime.Before(*branchDiff[j].LatestSyncTime) {
- return true
- }
- return true
- })
- case "ahead":
- sort.Slice(branchDiff, func(i, j int) bool {
- if branchDiff[i].Ahead > branchDiff[j].Ahead {
- return true
- }
- if branchDiff[i].Ahead < branchDiff[j].Ahead {
- return false
- }
- return true
- })
- case "behind":
- sort.Slice(branchDiff, func(i, j int) bool {
- if branchDiff[i].Behind > branchDiff[j].Behind {
- return true
- }
- if branchDiff[i].Behind < branchDiff[j].Behind {
- return false
- }
- return true
- })
- }
- resp = branchDiff[:100]
- return
- }
- // AllBranchDiffWithMaster ...
- func (s *Service) AllBranchDiffWithMaster(c context.Context, project int, master string) (branchDiff []*model.BranchDiffWithResponse, err error) {
- var (
- branches map[string]*model.CommitTreeNode
- tree []*model.CommitTreeNode
- cacheKey string
- )
- log.Info("sync Branch diff start => %s", cacheKey)
- if branches, err = s.AllProjectBranchInfo(c, project); err != nil {
- return
- }
- if tree, err = s.BuildCommitTree(c, project); err != nil {
- return
- }
- for k, v := range branches {
- var (
- base *gitlab.Commit
- ahead int
- behind int
- )
- if base, _, err = s.gitlab.MergeBase(c, project, []string{k, master}); err != nil {
- return
- }
- // 计算领先commit
- ahead = s.ComputeCommitNum(v, base, &tree)
- // 计算落后commit
- behind = s.ComputeCommitNum(branches[master], base, &tree)
- log.Info("%s: ahead: %d behind:%d\n", k, ahead, behind)
- branchDiff = append(branchDiff, &model.BranchDiffWithResponse{Branch: k, Behind: behind, Ahead: ahead, LatestUpdateTime: v.CreatedAt, LatestSyncTime: base.CreatedAt})
- }
- log.Info("Redis: Save Branch Diff Info Successfully!")
- return
- }
- // ComputeCommitNum ...
- func (s *Service) ComputeCommitNum(head *model.CommitTreeNode, base *gitlab.Commit, tree *[]*model.CommitTreeNode) (num int) {
- var (
- visitedQueue []string
- commitTree = *tree
- i int
- )
- if head.CommitID == base.ID {
- return
- }
- visitedQueue = append(visitedQueue, head.CommitID)
- for i = 0; ; i++ {
- pointer := visitedQueue[i]
- if pointer == base.ID {
- break
- }
- for _, node := range commitTree {
- if node.CommitID == pointer {
- if utils.InSlice(base.ID, node.Parents) {
- visitedQueue = append(visitedQueue, base.ID)
- break
- }
- for _, p := range node.Parents {
- if !utils.InSlice(p, visitedQueue) {
- visitedQueue = append(visitedQueue, p)
- }
- }
- break
- }
- }
- if i > 999 {
- break
- }
- if i == len(visitedQueue)-1 {
- break
- }
- }
- num = i
- return
- }
- // AllMergeBase ...
- func (s *Service) AllMergeBase(c context.Context, project int, branches []string, master string) (mergeBase map[string]*gitlab.Commit, err error) {
- var base *gitlab.Commit
- mergeBase = make(map[string]*gitlab.Commit)
- for _, branch := range branches {
- if base, _, err = s.gitlab.MergeBase(c, project, []string{master, branch}); err != nil {
- return
- }
- mergeBase[branch] = base
- }
- return
- }
- //AllProjectBranchInfo 获取所有分支信息
- func (s *Service) AllProjectBranchInfo(c context.Context, projectID int) (branches map[string]*model.CommitTreeNode, err error) {
- var projectBranches []*model.StatisticsBranches
- branches = make(map[string]*model.CommitTreeNode)
- if projectBranches, err = s.dao.QueryProjectBranch(c, projectID); err != nil {
- return
- }
- for _, b := range projectBranches {
- var (
- commitInfo *model.StatisticsCommits
- commitParents []string
- )
- if commitInfo, err = s.dao.QueryCommitByID(projectID, b.CommitID); err != nil {
- log.Error("AllProjectBranchInfo QueryCommitByID err(%+v)", err)
- err = nil
- continue
- }
- if commitInfo.ParentIDs != "" {
- if err = json.Unmarshal([]byte(commitInfo.ParentIDs), &commitParents); err != nil {
- return
- }
- }
- branches[b.BranchName] = &model.CommitTreeNode{CommitID: b.CommitID, Parents: commitParents, CreatedAt: commitInfo.CreatedAt, Author: commitInfo.AuthorName}
- }
- return
- }
- // BuildCommitTree 获取到所有的Commits
- func (s *Service) BuildCommitTree(c context.Context, project int) (tree []*model.CommitTreeNode, err error) {
- var projectCommits []*model.StatisticsCommits
- tree = []*model.CommitTreeNode{}
- if projectCommits, err = s.dao.QueryProjectCommits(c, project); err != nil {
- return
- }
- for _, c := range projectCommits {
- var commitParents []string
- commitParentsString := c.ParentIDs
- if commitParentsString != "" {
- if err = json.Unmarshal([]byte(commitParentsString), &commitParents); err != nil {
- log.Error("解析commit parents报错(%+v)", err)
- }
- }
- tree = append(tree, &model.CommitTreeNode{CommitID: c.CommitID, Parents: commitParents, CreatedAt: c.CreatedAt, Author: c.AuthorName})
- }
- return
- }
- /*-------------------------------------- sync branch ----------------------------------------*/
- // SyncProjectBranch ...
- func (s *Service) SyncProjectBranch(c context.Context, projectID int) (result *model.SyncResult, err error) {
- var (
- branches []*gitlab.Branch
- resp *gitlab.Response
- projectInfo *model.ProjectInfo
- )
- result = &model.SyncResult{}
- if err = s.dao.DeleteProjectBranch(c, projectID); err != nil {
- return
- }
- if projectInfo, err = s.dao.ProjectInfoByID(projectID); err != nil {
- return
- }
- for page := 1; ; page++ {
- result.TotalPage++
- if branches, resp, err = s.gitlab.ListProjectBranch(projectID, page); err != nil {
- return
- }
- for _, branch := range branches {
- branchDB := &model.StatisticsBranches{
- ProjectID: projectID,
- ProjectName: projectInfo.Name,
- CommitID: branch.Commit.ID,
- BranchName: branch.Name,
- Protected: branch.Protected,
- Merged: branch.Merged,
- DevelopersCanPush: branch.DevelopersCanPush,
- DevelopersCanMerge: branch.DevelopersCanMerge,
- }
- if err = s.SaveDatabaseBranch(c, branchDB); err != nil {
- log.Error("Branch 存数据库报错(%+V)", err)
- err = nil
- errData := &model.FailData{
- ChildIDStr: branch.Name,
- }
- result.FailData = append(result.FailData, errData)
- continue
- }
- result.TotalNum++
- }
- if resp.NextPage == 0 {
- break
- }
- }
- return
- }
- // SaveDatabaseBranch ...
- func (s *Service) SaveDatabaseBranch(c context.Context, branchDB *model.StatisticsBranches) (err error) {
- var (
- total int
- branch *model.StatisticsBranches
- )
- if total, err = s.dao.HasBranch(c, branchDB.ProjectID, branchDB.BranchName); err != nil {
- log.Error("SaveDatabaseBranch HasBranch(%+v)", err)
- return
- }
- // found only one, so update
- if total == 1 {
- if branch, err = s.dao.QueryFirstBranch(c, branchDB.ProjectID, branchDB.BranchName); err != nil {
- log.Error("SaveDatabaseBranch QueryFirstBranch(%+v)", err)
- return
- }
- branchDB.ID = branch.ID
- if err = s.dao.UpdateBranch(c, branchDB.ProjectID, branchDB.BranchName, branchDB); err != nil {
- log.Error("SaveDatabaseBranch UpdateBranch(%+v)", err)
- return
- }
- return
- } else if total > 1 {
- // found repeated row, this situation will not exist under normal
- log.Warn("SaveDatabaseBranch Branch has more rows(%d)", total)
- return
- }
- // insert row now
- if err = s.dao.CreateBranch(c, branchDB); err != nil {
- log.Error("SaveDatabaseBranch CreateBranch(%+v)", err)
- return
- }
- return
- }
- /*-------------------------------------- agg branch ----------------------------------------*/
- // AggregateProjectBranch ...
- func (s *Service) AggregateProjectBranch(c context.Context, projectID int, master string) (err error) {
- var (
- branches map[string]*model.CommitTreeNode
- tree []*model.CommitTreeNode
- projectInfo *model.ProjectInfo
- )
- if err = s.dao.DeleteAggregateBranch(c, projectID); err != nil {
- return
- }
- if projectInfo, err = s.dao.ProjectInfoByID(projectID); err != nil {
- return
- }
- if branches, err = s.AllProjectBranchInfo(c, projectID); err != nil {
- return
- }
- if tree, err = s.BuildCommitTree(c, projectID); err != nil {
- return
- }
- for k, v := range branches {
- var (
- base *gitlab.Commit
- ahead int
- behind int
- )
- if base, _, err = s.gitlab.MergeBase(c, projectID, []string{k, master}); err != nil {
- return
- }
- // 计算领先commit
- ahead = s.ComputeCommitNum(v, base, &tree)
- // 计算落后commit
- behind = s.ComputeCommitNum(branches[master], base, &tree)
- branch := &model.AggregateBranches{
- ProjectID: projectID,
- ProjectName: projectInfo.Name,
- BranchName: k,
- BranchUserName: v.Author,
- BranchMaster: master,
- Behind: behind,
- Ahead: ahead,
- LatestUpdateTime: v.CreatedAt,
- LatestSyncTime: base.CreatedAt,
- }
- if err = s.SaveAggregateBranchDatabase(c, branch); err != nil {
- log.Error("AggregateBranch 存数据库报错(%+V)", err)
- continue
- }
- }
- return
- }
- // SaveAggregateBranchDatabase ...
- func (s *Service) SaveAggregateBranchDatabase(c context.Context, branchDB *model.AggregateBranches) (err error) {
- var (
- total int
- aggregateBranch *model.AggregateBranches
- )
- if total, err = s.dao.HasAggregateBranch(c, branchDB.ProjectID, branchDB.BranchName); err != nil {
- log.Error("SaveAggregateBranchDatabase HasAggregateBranch(%+v)", err)
- return
- }
- // found only one, so update
- if total == 1 {
- if aggregateBranch, err = s.dao.QueryFirstAggregateBranch(c, branchDB.ProjectID, branchDB.BranchName); err != nil {
- log.Error("SaveDatabaseBranch QueryFirstAggregateBranch(%+v)", err)
- return
- }
- branchDB.ID = aggregateBranch.ID
- if err = s.dao.UpdateAggregateBranch(c, branchDB.ProjectID, branchDB.BranchName, branchDB); err != nil {
- log.Error("SaveAggregateBranchDatabase UpdateAggregateBranch(%+v)", err)
- return
- }
- return
- } else if total > 1 {
- // found repeated row, this situation will not exist under normal
- log.Warn("SaveAggregateBranchDatabase AggregateBranch has more rows(%d)", total)
- return
- }
- // insert row now
- if err = s.dao.CreateAggregateBranch(c, branchDB); err != nil {
- log.Error("SaveAggregateBranchDatabase CreateAggregateBranch(%+v)", err)
- return
- }
- return
- }
|