go-common/app/admin/ep/saga/service/pipeline.go
2019-04-22 18:49:16 +08:00

839 lines
24 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package service
import (
"context"
"fmt"
"strings"
"time"
"go-common/app/admin/ep/saga/conf"
"go-common/app/admin/ep/saga/model"
"go-common/app/admin/ep/saga/service/utils"
"go-common/app/admin/ep/saga/service/wechat"
"go-common/library/cache/memcache"
"go-common/library/log"
"github.com/xanzy/go-gitlab"
)
const (
_gitHTTP = "http://git.bilibili.co/"
_gitSSH = "git@git-test.bilibili.co:"
_gitSSHTail = ".git"
_manualJob = "manual"
_androidScheduleJob = "daily branch check"
_iosScheduleJob = "daily:on-schedule"
)
// QueryTeamPipeline query pipeline info according to team.
func (s *Service) QueryTeamPipeline(c context.Context, req *model.TeamDataRequest) (resp *model.PipelineDataResp, err error) {
var (
projectInfo []*model.ProjectInfo
reqProject = &model.ProjectInfoRequest{}
data []*model.PipelineDataTime
queryDes string
total int
succNum int
key string
keyNotExist bool
)
if len(req.Department) <= 0 && len(req.Business) <= 0 {
log.Warn("query department and business are empty!")
return
}
//get pipeline info from mc
key = "saga_admin_" + req.Department + "_" + req.Business + "_" + model.KeyTypeConst[3]
if resp, err = s.dao.GetPipeline(c, key); err != nil {
if err == memcache.ErrNotFound {
keyNotExist = true
} else {
return
}
} else {
return
}
log.Info("sync team pipeline start => type= %d, Department= %s, Business= %s", req.QueryType, req.Department, req.Business)
//query team projects
reqProject.Department = req.Department
reqProject.Business = req.Business
if _, projectInfo, err = s.dao.QueryProjectInfo(false, reqProject); err != nil {
return
}
if len(projectInfo) <= 0 {
log.Warn("Found no project!")
return
}
if data, total, succNum, err = s.QueryTeamPipelineByTime(projectInfo, model.LastWeekPerDay); err != nil {
return
}
successScale := succNum * 100 / total
queryDes = req.Department + " " + req.Business + " " + "pipeline上一周每天数量"
resp = &model.PipelineDataResp{
Department: req.Department,
Business: req.Business,
QueryDes: queryDes,
Total: total,
SuccessNum: succNum,
SuccessScale: successScale,
Data: data,
}
//set pipeline info to mc
if keyNotExist {
if err = s.dao.SetPipeline(c, key, resp); err != nil {
return
}
}
log.Info("sync team pipeline end")
return
}
// QueryTeamPipelineByTime ...
func (s *Service) QueryTeamPipelineByTime(projectInfo []*model.ProjectInfo, queryType int) (resp []*model.PipelineDataTime, allNum, succNum int, err error) {
var (
layout = "2006-01-02"
since time.Time
until time.Time
total int
success int
count int
)
if queryType == model.LastWeekPerDay {
count = model.DayNumPerWeek
} else {
log.Warn("Query Type is not in range!")
return
}
year, month, day := time.Now().Date()
weekDay := (int)(time.Now().Weekday())
today := time.Date(year, month, day, 0, 0, 0, 0, time.Local)
for i := 0; i < count; i++ {
since = today.AddDate(0, 0, -weekDay-i)
until = today.AddDate(0, 0, -weekDay-i+1)
totalAll := 0
successAll := 0
//log.Info("== start query from: %v, to: %v", since, until)
for _, project := range projectInfo {
if total, success, err = s.QueryProjectPipeline(project.ProjectID, "success", since, until); err != nil {
return
}
totalAll = totalAll + total
successAll = successAll + success
}
perData := &model.PipelineDataTime{
TotalItem: totalAll,
SuccessItem: successAll,
StartTime: since.Format(layout),
EndTime: until.Format(layout),
}
resp = append(resp, perData)
allNum = allNum + totalAll
succNum = succNum + successAll
}
return
}
// QueryProjectPipeline query pipeline info according to project id.
func (s *Service) QueryProjectPipeline(projectID int, state string, since, until time.Time) (totalNum, stateNum int, err error) {
var (
pipelineList gitlab.PipelineList
pipeline *gitlab.Pipeline
resp *gitlab.Response
startQuery bool
)
if _, resp, err = s.gitlab.ListProjectPipelines(1, projectID, ""); err != nil {
return
}
page := 1
for page <= resp.TotalPages {
if !startQuery {
if pipelineList, _, err = s.gitlab.ListProjectPipelines(page, projectID, ""); err != nil {
return
}
if page == 1 && len(pipelineList) <= 0 {
return
}
if pipeline, _, err = s.gitlab.GetPipeline(projectID, pipelineList[0].ID); err != nil {
return
}
if pipeline.CreatedAt.After(until) {
page++
continue
} else {
startQuery = true
page--
continue
}
}
if pipelineList, _, err = s.gitlab.ListProjectPipelines(page, projectID, ""); err != nil {
return
}
for _, v := range pipelineList {
if pipeline, _, err = s.gitlab.GetPipeline(projectID, v.ID); err != nil {
return
}
createTime := pipeline.CreatedAt
//year, month, day := createTime.Date()
//log.Info("index: %d createTime: %d, month: %d, day: %d", k, year, month, day)
if createTime.After(since) && createTime.Before(until) {
totalNum = totalNum + 1
if pipeline.Status == state {
stateNum = stateNum + 1
}
}
if createTime.Before(since) {
return
}
}
page++
}
return
}
// QueryProjectPipelineNew ...
func (s *Service) QueryProjectPipelineNew(c context.Context, req *model.PipelineDataReq) (resp *model.PipelineDataAvgResp, err error) {
var (
data []*model.PipelineDataAvg
queryDes string
total int
totalStatus int
avgDurationTime float64
avgPendingTime float64
avgRunningTime float64
)
log.Info("QuerySingleProjectData Type: %d", req.Type)
switch req.Type {
case model.LastYearPerMonth:
queryDes = model.LastYearPerMonthNote
case model.LastMonthPerDay:
queryDes = model.LastMonthPerDayNote
case model.LastYearPerDay:
queryDes = model.LastYearPerDayNote
default:
log.Warn("QueryProjectCommit Type is not in range")
return
}
queryDes = req.ProjectName + " pipeline " + req.State + " " + queryDes
if data, total, totalStatus, avgDurationTime, avgPendingTime, avgRunningTime, err = s.QueryProjectByTimeNew(c, req, req.Type); err != nil {
return
}
resp = &model.PipelineDataAvgResp{
ProjectName: req.ProjectName,
QueryDes: queryDes,
Status: req.State,
Total: total,
TotalStatus: totalStatus,
AvgDurationTime: avgDurationTime,
AvgPendingTime: avgPendingTime,
AvgRunningTime: avgRunningTime,
Data: data,
}
return
}
// QueryProjectByTimeNew ...
func (s *Service) QueryProjectByTimeNew(c context.Context, req *model.PipelineDataReq, queryType int) (resp []*model.PipelineDataAvg, allNum, allStatusNum int, avgDurationTime, avgPendingTime, avgRunningTime float64, err error) {
var (
layout = "2006-01-02"
since time.Time
until time.Time
count int
pendingTimeListAll []float64
runningTimeListAll []float64
durationTimeListAll []float64
pipelineTime *model.PipelineTime
perData *model.PipelineDataAvg
avgTotalTime float64
totalNum int
statusNum int
)
year, month, day := time.Now().Date()
thisMonth := time.Date(year, month, day, 0, 0, 0, 0, time.Local)
if queryType == model.LastYearPerMonth {
count = model.MonthNumPerYear
} else if queryType == model.LastMonthPerDay {
//_, _, count = thisMonth.AddDate(0, 0, -1).Date()
count = model.DayNumPerMonth
} else if queryType == model.LastYearPerDay {
count = model.DayNumPerYear
}
for i := count; i >= 1; i-- {
if queryType == model.LastYearPerMonth {
since = thisMonth.AddDate(0, -i, 0)
until = thisMonth.AddDate(0, -i+1, 0)
} else if queryType == model.LastMonthPerDay {
since = thisMonth.AddDate(0, 0, -i)
until = thisMonth.AddDate(0, 0, -i+1)
} else if queryType == model.LastYearPerDay {
since = thisMonth.AddDate(0, 0, -i)
until = thisMonth.AddDate(0, 0, -i+1)
}
/*if totalNum, statusNum, pipelineTime, err = s.QueryProjectPipelines(c, req, since, until); err != nil {
log.Error("QueryProjectPipelines err%+v", err)
return
}*/
if totalNum, statusNum, pipelineTime, err = s.QueryPipelinesFromDB(c, req, since, until); err != nil {
log.Error("QueryPipelinesFromDB err%+v", err)
return
}
avgTotalTime = utils.CalAverageTime(req.StatisticsType, pipelineTime.DurationList)
avgPendingTime = utils.CalAverageTime(req.StatisticsType, pipelineTime.PendingList)
avgRunningTime = utils.CalAverageTime(req.StatisticsType, pipelineTime.RunningList)
perData = &model.PipelineDataAvg{
TotalItem: totalNum,
TotalStatusItem: statusNum,
AvgDurationTime: avgTotalTime,
AvgPendingTime: avgPendingTime,
AvgRunningTime: avgRunningTime,
MaxDurationTime: pipelineTime.DurationMax,
MinDurationTime: pipelineTime.DurationMin,
MaxPendingTime: pipelineTime.PendingMax,
MinPendingTime: pipelineTime.PendingMin,
MaxRunningTime: pipelineTime.RunningMax,
MinRunningTime: pipelineTime.RunningMin,
StartTime: since.Format(layout),
EndTime: until.Format(layout),
}
resp = append(resp, perData)
allNum = allNum + totalNum
allStatusNum = allStatusNum + statusNum
pendingTimeListAll = utils.CombineSlice(pendingTimeListAll, pipelineTime.PendingList)
runningTimeListAll = utils.CombineSlice(runningTimeListAll, pipelineTime.RunningList)
durationTimeListAll = utils.CombineSlice(durationTimeListAll, pipelineTime.DurationList)
}
avgDurationTime = utils.CalAverageTime(req.StatisticsType, durationTimeListAll)
avgPendingTime = utils.CalAverageTime(req.StatisticsType, pendingTimeListAll)
avgRunningTime = utils.CalAverageTime(req.StatisticsType, runningTimeListAll)
log.Info("avgDurationTime: %v, avgPendingTime: %v, avgRunningTime: %v", avgDurationTime, avgPendingTime, avgRunningTime)
return
}
// QueryProjectPipelines ...
func (s *Service) QueryProjectPipelines(c context.Context, req *model.PipelineDataReq, since, until time.Time) (totalNum, statusNum int, pipelineTime *model.PipelineTime, err error) {
var (
pipelineList gitlab.PipelineList
pipeline *gitlab.Pipeline
resp *gitlab.Response
startQuery bool
meetTime bool
projectID = req.ProjectID
pendingTime float64
runningTime float64
totalTime float64
)
pipelineTime = &model.PipelineTime{}
opt := &gitlab.ListProjectPipelinesOptions{}
if _, resp, err = s.gitlab.ListProjectPipelines(1, projectID, ""); err != nil {
log.Error("ListProjectPipelines err: %+v", err)
return
}
page := 1
for page <= resp.TotalPages {
opt.ListOptions.Page = page
if !startQuery && (!since.IsZero() || !until.IsZero()) {
if pipelineList, _, err = s.gitlab.ListProjectPipelines(page, projectID, ""); err != nil {
log.Error("ListProjectPipelines err: %+v", err)
return
}
if page == 1 && len(pipelineList) <= 0 {
return
}
if pipeline, _, err = s.gitlab.GetPipeline(projectID, pipelineList[0].ID); err != nil {
return
}
if pipeline.CreatedAt.After(until) {
page++
continue
} else {
startQuery = true
page--
continue
}
}
// start query
if pipelineList, _, err = s.gitlab.ListProjectPipelines(page, projectID, ""); err != nil {
return
}
meetTime = true
for _, v := range pipelineList {
if pipeline, _, err = s.gitlab.GetPipeline(projectID, v.ID); err != nil {
return
}
createTime := pipeline.CreatedAt
if !since.IsZero() || !until.IsZero() {
meetTime = createTime.After(since) && createTime.Before(until)
}
//the pipeline is we need
if meetTime {
totalNum = totalNum + 1
if req.Branch != "" && req.Branch != pipeline.Ref {
continue
} else if req.User != "" && req.User != pipeline.User.Name {
continue
} else if req.State != "" && req.State != pipeline.Status {
continue
}
statusNum = statusNum + 1
if pipeline.Status != "cancel" {
if pipeline.StartedAt == nil {
pendingTime = 0
runningTime = pipeline.FinishedAt.Sub(*pipeline.CreatedAt).Seconds()
} else {
pendingTime = pipeline.StartedAt.Sub(*pipeline.CreatedAt).Seconds()
runningTime = pipeline.FinishedAt.Sub(*pipeline.StartedAt).Seconds()
}
totalTime = pipeline.FinishedAt.Sub(*pipeline.CreatedAt).Seconds()
pipelineTime.PendingMax, pipelineTime.PendingMin = utils.CalSizeTime(pendingTime, pipelineTime.PendingMax, pipelineTime.PendingMin)
pipelineTime.RunningMax, pipelineTime.RunningMin = utils.CalSizeTime(runningTime, pipelineTime.RunningMax, pipelineTime.RunningMin)
pipelineTime.DurationMax, pipelineTime.DurationMin = utils.CalSizeTime(totalTime, pipelineTime.DurationMax, pipelineTime.DurationMin)
pipelineTime.PendingList = append(pipelineTime.PendingList, pendingTime)
pipelineTime.RunningList = append(pipelineTime.RunningList, runningTime)
pipelineTime.DurationList = append(pipelineTime.DurationList, totalTime)
}
}
// time is over, so return
if (!since.IsZero() || !until.IsZero()) && createTime.Before(since) {
return
}
}
page++
}
return
}
// QueryPipelinesFromDB ...
func (s *Service) QueryPipelinesFromDB(c context.Context, req *model.PipelineDataReq, since, until time.Time) (totalNum, statusNum int, pipelineTime *model.PipelineTime, err error) {
var (
fmtLayout = `%d-%d-%d 00:00:00`
pipelines []*model.StatisticsPipeline
projectID = req.ProjectID
pendingTime float64
runningTime float64
totalTime float64
)
pipelineTime = &model.PipelineTime{}
sinceStr := fmt.Sprintf(fmtLayout, since.Year(), since.Month(), since.Day())
untilStr := fmt.Sprintf(fmtLayout, until.Year(), until.Month(), until.Day())
if totalNum, statusNum, pipelines, err = s.dao.QueryPipelinesByTime(projectID, req, sinceStr, untilStr); err != nil {
return
}
for _, pipeline := range pipelines {
if pipeline.Status == model.StatusCancel {
continue
}
if pipeline.FinishedAt == nil {
continue
}
if pipeline.StartedAt == nil {
pendingTime = 0
runningTime = pipeline.FinishedAt.Sub(*pipeline.CreatedAt).Seconds()
} else {
pendingTime = pipeline.StartedAt.Sub(*pipeline.CreatedAt).Seconds()
runningTime = pipeline.FinishedAt.Sub(*pipeline.StartedAt).Seconds()
}
totalTime = pipeline.FinishedAt.Sub(*pipeline.CreatedAt).Seconds()
pipelineTime.PendingMax, pipelineTime.PendingMin = utils.CalSizeTime(pendingTime, pipelineTime.PendingMax, pipelineTime.PendingMin)
pipelineTime.RunningMax, pipelineTime.RunningMin = utils.CalSizeTime(runningTime, pipelineTime.RunningMax, pipelineTime.RunningMin)
pipelineTime.DurationMax, pipelineTime.DurationMin = utils.CalSizeTime(totalTime, pipelineTime.DurationMax, pipelineTime.DurationMin)
pipelineTime.PendingList = append(pipelineTime.PendingList, pendingTime)
pipelineTime.RunningList = append(pipelineTime.RunningList, runningTime)
pipelineTime.DurationList = append(pipelineTime.DurationList, totalTime)
}
return
}
//alertProjectPipelineProc cron func
func (s *Service) alertProjectPipelineProc() {
for _, alert := range conf.Conf.Property.Git.AlertPipeline {
projectId := alert.ProjectID
runningTimeout := alert.RunningTimeout
runningRate := alert.RunningRate
runningThreshold := alert.RunningThreshold
pendingTimeout := alert.PendingTimeout
pendingThreshold := alert.PendingThreshold
go func() {
var err error
if err = s.PipelineAlert(context.TODO(), projectId, runningTimeout, runningThreshold, runningRate, gitlab.Running); err != nil {
log.Error("PipelineAlert Running (%+v)", err)
}
if err = s.PipelineAlert(context.TODO(), projectId, pendingTimeout, pendingThreshold, 0, gitlab.Pending); err != nil {
log.Error("PipelineAlert Pending (%+v)", err)
}
}()
}
}
//PipelineAlert ...
func (s *Service) PipelineAlert(c context.Context, projectID, timeout, threshold, rate int, status gitlab.BuildStateValue) (err error) {
var (
layout = "2006-01-02 15:04:05"
pipeline *gitlab.Pipeline
timeoutNum int
message string
pipelineurl string
durationTime float64
pipelineSUM int
timeoutPipeline string
pipelineList gitlab.PipelineList
resp *gitlab.Response
projectInfo *model.ProjectInfo
userlist = conf.Conf.Property.Git.UserList
w = wechat.New(s.dao)
sendMessage = false
)
if projectInfo, err = s.dao.ProjectInfoByID(projectID); err != nil {
return
}
repo := projectInfo.Repo
if len(repo) > len(_gitSSH) {
repo = repo[len(_gitSSH) : len(repo)-len(_gitSSHTail)]
repo = _gitHTTP + repo
}
timeNow := time.Now().Format(layout)
message = fmt.Sprintf("[SAGA]Pipeline 告警 %v\n项目%s\n", timeNow, repo)
for page := 1; ; page++ {
if pipelineList, resp, err = s.git.ListProjectPipelines(page, projectID, status); err != nil {
return
}
for _, item := range pipelineList {
pipelineSUM += 1
if pipeline, _, err = s.git.GetPipeline(projectID, item.ID); err != nil {
return
}
if status == gitlab.Pending {
durationTime = pipeline.UpdatedAt.Sub(*pipeline.CreatedAt).Minutes()
} else if status == gitlab.Running {
//此处时间计算换成job
if durationTime, err = s.PipelineRunningTime(projectID, item.ID); err != nil {
return
}
}
if int(durationTime) >= timeout {
timeoutNum += 1
pipelineurl = fmt.Sprintf("%d. %s/pipelines/%d (%vmin)\n", timeoutNum, repo, pipeline.ID, int(durationTime))
timeoutPipeline += pipelineurl
}
}
if resp.NextPage == 0 {
break
}
}
if timeoutPipeline != "" {
message += fmt.Sprintf(`列表(url|%s时间):%s%s`, status, "\n", timeoutPipeline)
}
if pipelineSUM > 0 {
message += fmt.Sprintf(`状态:%s 总数为%d个`, status, pipelineSUM)
}
if status == gitlab.Pending {
var alertMessage string
message += fmt.Sprintf(`%s告警`, "\n")
if pipelineSUM >= threshold {
alertMessage = fmt.Sprintf(`[ 数量(%d>=警戒值(%d ]`, pipelineSUM, threshold)
sendMessage = true
}
message += alertMessage
if timeoutNum >= 1 {
if alertMessage != "" {
message = message[:strings.LastIndex(message, " ]")] + fmt.Sprintf(`%s时间>=警戒值(%d ]`, status, timeout)
} else {
message += fmt.Sprintf(`[ %s时间>=警戒值(%d ]`, status, timeout)
}
sendMessage = true
}
}
if status == gitlab.Running && timeoutNum >= threshold {
sendMessage = true
message += fmt.Sprintf(`,时间>%dmin为%d个%s告警[ 数量(%d>=警戒值(%d) ]`, timeout, timeoutNum, "\n", timeoutNum, threshold)
if timeoutNum*100/pipelineSUM >= rate {
message = message[:strings.LastIndex(message, " ]")] + fmt.Sprintf(`,比例(%v%s>=警戒值%d%s ]`, timeoutNum*100/pipelineSUM, "%", rate, "%")
}
}
if sendMessage {
return w.PushMsg(c, userlist, message)
}
return
}
//PipelineRunningTime ...
func (s *Service) PipelineRunningTime(projectID, pipelineID int) (durationTime float64, err error) {
var jobList []*gitlab.Job
if jobList, _, err = s.git.ListPipelineJobs(nil, projectID, pipelineID); err != nil {
return
}
for _, job := range jobList {
if job.Status != _manualJob && job.Name != _androidScheduleJob && job.Name != _iosScheduleJob {
if job.FinishedAt != nil && job.StartedAt != nil {
durationTime += job.FinishedAt.Sub(*job.StartedAt).Minutes()
} else if job.StartedAt != nil {
durationTime += time.Since(*job.StartedAt).Minutes()
}
}
}
return
}
/*-------------------------------------- sync pipeline ----------------------------------------*/
// SyncProjectPipelines ...
func (s *Service) SyncProjectPipelines(projectID int) (result *model.SyncResult, err error) {
var (
//syncAllTime = conf.Conf.Property.SyncData.SyncAllTime
syncAllTime = false
since *time.Time
until *time.Time
projectInfo *model.ProjectInfo
)
if projectInfo, err = s.dao.ProjectInfoByID(projectID); err != nil {
return
}
if !syncAllTime {
since, until = utils.CalSyncTime()
log.Info("sync project id(%d), name(%s) pipeline, time since: %v, until: %v", projectID, projectInfo.Name, since, until)
if result, err = s.SyncProjectPipelinesByTime(projectID, projectInfo.Name, *since, *until); err != nil {
return
}
} else {
log.Info("sync project id(%d), name(%s) pipeline", projectID, projectInfo.Name)
if result, err = s.SyncProjectAllPipelines(projectID, projectInfo.Name); err != nil {
return
}
}
return
}
// SyncProjectPipelinesByTime ...
func (s *Service) SyncProjectPipelinesByTime(projectID int, projectName string, since, until time.Time) (result *model.SyncResult, err error) {
var (
pipelines gitlab.PipelineList
pipeline *gitlab.Pipeline
resp *gitlab.Response
startQuery bool
)
result = &model.SyncResult{}
if _, resp, err = s.gitlab.ListProjectPipelines(1, projectID, ""); err != nil {
return
}
page := 1
for page <= resp.TotalPages {
result.TotalPage++
if !startQuery {
if pipelines, resp, err = s.gitlab.ListProjectPipelines(page, projectID, ""); err != nil {
return
}
if page == 1 && len(pipelines) <= 0 {
return
}
if pipeline, _, err = s.gitlab.GetPipeline(projectID, pipelines[0].ID); err != nil {
return
}
if pipeline.CreatedAt.After(until) {
page++
continue
} else {
startQuery = true
page--
continue
}
}
// start query
if pipelines, _, err = s.gitlab.ListProjectPipelines(page, projectID, ""); err != nil {
return
}
for _, v := range pipelines {
if pipeline, _, err = s.gitlab.GetPipeline(projectID, v.ID); err != nil {
return
}
createTime := pipeline.CreatedAt
if createTime.After(since) && createTime.Before(until) {
if err = s.structureDBPipeline(projectID, projectName, pipeline); err != nil {
log.Error("pipeline Save Database err: projectID(%d), PipelineID(%d)", projectID, pipeline.ID)
err = nil
errData := &model.FailData{
ChildID: pipeline.ID,
}
result.FailData = append(result.FailData, errData)
continue
}
result.TotalNum++
}
if createTime.Before(since) {
return
}
}
page++
}
return
}
// SyncProjectAllPipelines ...
func (s *Service) SyncProjectAllPipelines(projectID int, projectName string) (result *model.SyncResult, err error) {
var (
pipelines gitlab.PipelineList
pipeline *gitlab.Pipeline
resp *gitlab.Response
)
result = &model.SyncResult{}
for page := 1; ; page++ {
result.TotalPage++
if pipelines, resp, err = s.gitlab.ListProjectPipelines(page, projectID, ""); err != nil {
return
}
for _, v := range pipelines {
if pipeline, _, err = s.gitlab.GetPipeline(projectID, v.ID); err != nil {
return
}
if err = s.structureDBPipeline(projectID, projectName, pipeline); err != nil {
log.Error("pipeline Save Database err: projectID(%d), PipelineID(%d)", projectID, pipeline.ID)
err = nil
errData := &model.FailData{
ChildID: pipeline.ID,
}
result.FailData = append(result.FailData, errData)
continue
}
result.TotalNum++
}
if resp.NextPage == 0 {
break
}
}
return
}
// structureDBPipeline ...
func (s *Service) structureDBPipeline(projectID int, projectName string, pipeline *gitlab.Pipeline) (err error) {
statisticPipeline := &model.StatisticsPipeline{
PipelineID: pipeline.ID,
ProjectID: projectID,
ProjectName: projectName,
Status: pipeline.Status,
Ref: pipeline.Ref,
Tag: pipeline.Tag,
User: pipeline.User.Name,
CreatedAt: pipeline.CreatedAt,
UpdatedAt: pipeline.UpdatedAt,
StartedAt: pipeline.StartedAt,
FinishedAt: pipeline.FinishedAt,
CommittedAt: pipeline.CommittedAt,
Coverage: pipeline.Coverage,
Duration: pipeline.Duration,
DurationTime: 0,
}
return s.SaveDatabasePipeline(statisticPipeline)
}
// SaveDatabasePipeline ...
func (s *Service) SaveDatabasePipeline(pipelineDB *model.StatisticsPipeline) (err error) {
var total int
if total, err = s.dao.HasPipeline(pipelineDB.ProjectID, pipelineDB.PipelineID); err != nil {
log.Error("SaveDatabasePipeline HasPipeline(%+v)", err)
return
}
// found only one, so update
if total == 1 {
if err = s.dao.UpdatePipeline(pipelineDB.ProjectID, pipelineDB.PipelineID, pipelineDB); err != nil {
log.Error("SaveDatabasePipeline UpdatePipeline err(%+v)", err)
return
}
return
} else if total > 1 {
// found repeated row, this situation will not exist under normal
log.Warn("SaveDatabasePipeline pipeline has more rows(%d)", total)
return
}
// insert row now
if err = s.dao.CreatePipeline(pipelineDB); err != nil {
log.Error("SaveDatabasePipeline CreatePipeline err(%+v)", err)
return
}
return
}