ut.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430
  1. package service
  2. import (
  3. "context"
  4. "fmt"
  5. "strconv"
  6. "strings"
  7. "time"
  8. "go-common/app/admin/main/apm/conf"
  9. "go-common/app/admin/main/apm/model/ut"
  10. "go-common/library/log"
  11. xtime "go-common/library/time"
  12. "github.com/jinzhu/gorm"
  13. )
  14. const (
  15. _utMerge = "ut_merge"
  16. _utCommit = "ut_commit"
  17. _utpkg = "ut_pkganls"
  18. )
  19. // UtList return ut_list by merge_id or username
  20. func (s *Service) UtList(c context.Context, arg *ut.MergeReq) (mrInfs []*ut.Merge, count int, err error) {
  21. var (
  22. mtime = time.Now().Add(-time.Hour * 24 * 90)
  23. hql = fmt.Sprintf("mtime>'%s'", mtime)
  24. )
  25. if arg.MergeID != 0 {
  26. hql += fmt.Sprintf(" and merge_id=%d ", arg.MergeID)
  27. }
  28. if arg.UserName != "" {
  29. hql += fmt.Sprintf(" and username='%s' ", arg.UserName)
  30. }
  31. if arg.IsMerged != 0 {
  32. hql += fmt.Sprintf(" and is_merged='%d' ", arg.IsMerged)
  33. }
  34. if err = s.DB.Table(_utMerge).Where(hql).Count(&count).Error; err != nil {
  35. log.Error("service.UtList error(%v)", err)
  36. return
  37. }
  38. if err = s.DB.Where(hql).Offset((arg.Pn - 1) * arg.Ps).Limit(arg.Ps).Order("mtime desc").Find(&mrInfs).Error; err != nil {
  39. log.Error("service.UtList error(%v)", err)
  40. return
  41. }
  42. for _, mr := range mrInfs {
  43. var commit = &ut.Commit{}
  44. if err = s.DB.Where("merge_id=?", mr.MergeID).Order("id desc").First(commit).Error; err != nil {
  45. log.Error("service.UtList mergeID(%d) error(%v)", mr.MergeID, err)
  46. return
  47. }
  48. if err = s.DB.Select(`max(commit_id) as commit_id, substring_index(pkg,"/",5) as pkg, ROUND(AVG(coverage/100),2) as coverage, SUM(assertions) as assertions, SUM(panics) as panics, SUM(passed) as passed, ROUND(SUM(passed)/SUM(assertions)*100,2) as pass_rate, SUM(failures) as failures, MAX(mtime) as mtime`).
  49. Where(`commit_id=? and (pkg!=substring_index(pkg, "/", 5) or pkg like "go-common/library/%")`, commit.CommitID).
  50. Group(`substring_index(pkg, "/", 5)`).Find(&commit.PkgAnls).Error; err != nil {
  51. log.Error("service.UtList commitID(%s) error(%v)", commit.CommitID, err)
  52. return
  53. }
  54. mr.Commit = commit
  55. }
  56. return
  57. }
  58. // UtDetailList get ut pkganls by commit_id&pkg
  59. func (s *Service) UtDetailList(c context.Context, arg *ut.DetailReq) (utpkgs []*ut.PkgAnls, err error) {
  60. var (
  61. mtime = time.Now().Add(-time.Hour * 24 * 90)
  62. hql = fmt.Sprintf("mtime>'%s'", mtime)
  63. )
  64. if arg.CommitID != "" {
  65. hql += fmt.Sprintf(" and commit_id='%s'", arg.CommitID)
  66. }
  67. if arg.PKG != "" {
  68. hql += fmt.Sprintf(" and substring_index(pkg,'/',5)='%s' and (pkg!=substring_index(pkg,'/',5) or pkg like 'go-common/library/%%')", arg.PKG)
  69. }
  70. if err = s.dao.DB.Select("id, commit_id, merge_id, pkg, ROUND(coverage/100,2) as coverage, ROUND(passed/assertions*100,2) as pass_rate,panics,failures,skipped,passed,assertions,html_url,report_url,mtime,ctime").Where(hql).Find(&utpkgs).Error; err != nil {
  71. log.Error("service.UTDetilList commitID(%s) project(%s) error(%v)", arg.CommitID, arg.PKG, err)
  72. return
  73. }
  74. return
  75. }
  76. // UtHistoryCommit get commits history list by merge_id
  77. func (s *Service) UtHistoryCommit(c context.Context, arg *ut.HistoryCommitReq) (utcmts []*ut.Commit, count int, err error) {
  78. var (
  79. mtime = time.Now().Add(-time.Hour * 24 * 90)
  80. hql = fmt.Sprintf("mtime>'%s'", mtime)
  81. )
  82. hql += fmt.Sprintf(" and merge_id=%d", arg.MergeID)
  83. if err = s.DB.Table(_utCommit).Where(hql).Count(&count).Error; err != nil {
  84. log.Error("service.UTHistoryCommit mergeID(%d) error(%v)", arg.MergeID, err)
  85. return
  86. }
  87. if err = s.dao.DB.Where(hql).Offset((arg.Pn - 1) * arg.Ps).Limit(arg.Ps).Order("mtime desc").Find(&utcmts).Error; err != nil {
  88. log.Error("service.UTHistoryCommit mergeID(%d) error(%v)", arg.MergeID, err)
  89. return
  90. }
  91. for _, commit := range utcmts {
  92. if err = s.dao.DB.Select(`max(commit_id) as commit_id, substring_index(pkg,"/",5) as pkg, ROUND(AVG(coverage/100),2) as coverage, SUM(assertions) as assertions, SUM(panics) as panics, SUM(passed) as passed, ROUND(SUM(passed)/SUM(assertions)*100,2) as pass_rate, SUM(failures) as failures, MAX(mtime) as mtime`).
  93. Where("commit_id=? and (pkg!=substring_index(pkg,'/',5) or pkg like 'go-common/library/%')", commit.CommitID).Group(`substring_index(pkg, "/", 5)`).
  94. Order(`substring_index(pkg, "/", 5)`).Find(&commit.PkgAnls).Error; err != nil {
  95. log.Error("service.UTHistoryCommit commitID(%s) error(%v)", commit.CommitID, err)
  96. return
  97. }
  98. }
  99. for i := 0; i < len(utcmts)-1; i++ {
  100. for _, curPkg := range utcmts[i].PkgAnls {
  101. if utcmts[i+1] == nil || len(utcmts[i+1].PkgAnls) == 0 {
  102. continue
  103. }
  104. for _, prePkg := range utcmts[i+1].PkgAnls {
  105. if prePkg.PKG == curPkg.PKG {
  106. curPkg.CovChange, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", curPkg.Coverage-prePkg.Coverage), 64)
  107. }
  108. }
  109. }
  110. }
  111. return
  112. }
  113. // AddUT store ut data with a transaction
  114. func (s *Service) AddUT(c context.Context, pkg *ut.PkgAnls, files []*ut.File, request *ut.UploadRes, dataURL, reportURL, HTMLURL string) (err error) {
  115. var (
  116. tx = s.DB.Begin()
  117. // pkgCoverage float64
  118. )
  119. if err = s.AddUTMerge(c, tx, request); err != nil {
  120. tx.Rollback()
  121. return
  122. }
  123. if err = s.AddUTCommit(c, tx, request); err != nil {
  124. tx.Rollback()
  125. return
  126. }
  127. if err = s.AddUTPKG(c, tx, pkg, request, reportURL, HTMLURL, dataURL); err != nil {
  128. tx.Rollback()
  129. return
  130. }
  131. if err = s.AddUTFiles(c, tx, files); err != nil {
  132. tx.Rollback()
  133. return
  134. }
  135. tx.Commit()
  136. return
  137. }
  138. // AddUTMerge insert merge if not exist
  139. func (s *Service) AddUTMerge(c context.Context, tx *gorm.DB, request *ut.UploadRes) (err error) {
  140. var (
  141. uts = make([]*ut.Merge, 0)
  142. merge = &ut.Merge{
  143. UserName: request.UserName,
  144. MergeID: request.MergeID,
  145. }
  146. )
  147. if err = tx.Where("merge_id=?", merge.MergeID).Order("mtime desc").Find(&uts).Error; err != nil {
  148. log.Error("service.CreateUtList err(%v)", err)
  149. return
  150. }
  151. if len(uts) > 0 {
  152. return
  153. }
  154. if err = tx.Create(merge).Error; err != nil {
  155. log.Error("service.CreateUtInfo err (%v)", err)
  156. }
  157. return
  158. }
  159. // AddUTPKG if not exists pkg.commit_id then insert,otherwise,update
  160. func (s *Service) AddUTPKG(c context.Context, tx *gorm.DB, pkg *ut.PkgAnls, request *ut.UploadRes, reportURL, HTMLURL, dataURL string) (err error) {
  161. var (
  162. pkgs = make([]*ut.PkgAnls, 0)
  163. in = map[string]interface{}{
  164. "merge_id": request.MergeID,
  165. "failures": pkg.Failures,
  166. "passed": pkg.Passed,
  167. "assertions": pkg.Assertions,
  168. "panics": pkg.Panics,
  169. "skipped": pkg.Skipped,
  170. "coverage": pkg.Coverage,
  171. "html_url": HTMLURL,
  172. "report_url": reportURL,
  173. "data_url": dataURL,
  174. "mtime": xtime.Time(time.Now().Unix())}
  175. )
  176. pkg.MergeID = request.MergeID
  177. pkg.PKG = request.PKG
  178. pkg.CommitID = request.CommitID
  179. pkg.HTMLURL = HTMLURL
  180. pkg.ReportURL = reportURL
  181. pkg.DataURL = dataURL
  182. if err = tx.Where("commit_id=? and pkg=?", pkg.CommitID, pkg.PKG).Find(&pkgs).Error; err != nil {
  183. log.Error("service.CreateUtPKG query error(%v)", err)
  184. return
  185. }
  186. if len(pkgs) > 0 {
  187. log.Info("s.CreateUtPKG commit_id(%s) pkg(%+v)", pkg.CommitID, pkg)
  188. err = tx.Table(_utpkg).Where("commit_id=? and pkg=?", pkg.CommitID, pkg.PKG).Update(in).Error
  189. } else {
  190. err = tx.Create(pkg).Error
  191. }
  192. if err != nil {
  193. log.Error("service.CreateUtPKG create error(%v)", err)
  194. }
  195. return
  196. }
  197. // AddUTFiles add files in table ut_file
  198. func (s *Service) AddUTFiles(c context.Context, tx *gorm.DB, files []*ut.File) (err error) {
  199. var (
  200. recordFiles []*ut.File
  201. )
  202. if len(files) == 0 {
  203. err = fmt.Errorf("length of files is 0")
  204. log.Error("apmSvc.AddUTFiles Error(%v)", err)
  205. return
  206. }
  207. if err = tx.Where("commit_id=? and pkg=?", files[0].CommitID, files[0].PKG).Find(&recordFiles).Error; err != nil {
  208. log.Error("apmSvc.AddUTFiles Error(%v)", err)
  209. return
  210. }
  211. if len(recordFiles) > 0 {
  212. return
  213. }
  214. for _, file := range files {
  215. if err = tx.Create(file).Error; err != nil {
  216. log.Error("service.AddUTFiles create error(%v)", err)
  217. return
  218. }
  219. }
  220. return
  221. }
  222. // AddUTCommit insert commit if not exist
  223. func (s *Service) AddUTCommit(c context.Context, tx *gorm.DB, request *ut.UploadRes) (err error) {
  224. var (
  225. cts = make([]*ut.Commit, 0)
  226. ct = &ut.Commit{
  227. CommitID: request.CommitID,
  228. MergeID: request.MergeID,
  229. }
  230. )
  231. if request.Author == "" || request.Author == "null" {
  232. ct.UserName = request.UserName
  233. } else {
  234. ct.UserName = request.Author
  235. }
  236. if err = tx.Where("commit_id=?", ct.CommitID).Find(&cts).Error; err != nil {
  237. log.Error("s.CreateUtCommit query error(%v)", err)
  238. return
  239. }
  240. if len(cts) > 0 {
  241. log.Info("s.AddUTCommit(%d) update merge request", ct.MergeID)
  242. err = tx.Table(_utCommit).Where("commit_id=?", ct.CommitID).Update("merge_id", ct.MergeID).Error
  243. } else {
  244. err = tx.Create(ct).Error
  245. }
  246. if err != nil {
  247. log.Error("s.CreateUtCommit(%+v) error(%v)", ct, err)
  248. }
  249. return
  250. }
  251. // SetMerged set is_merged = 1 in ut_merge
  252. func (s *Service) SetMerged(c context.Context, mrid int64) (err error) {
  253. if err = s.dao.DB.Table(_utMerge).Where("merge_id=?", mrid).Update("is_merged", 1).Error; err != nil {
  254. log.Error("s.SetMerged error(%v)", err)
  255. return
  256. }
  257. return
  258. }
  259. // CheckUT .coverage>=30% && pass_rate=100% && increase >=0
  260. func (s *Service) CheckUT(c context.Context, cid string) (t *ut.Tyrant, err error) {
  261. var (
  262. pkgs = make([]*ut.PkgAnls, 0)
  263. )
  264. if err = s.DB.Where("commit_id=? and (pkg!=substring_index(pkg,'/',5) or pkg like 'go-common/library/%')", cid).Find(&pkgs).Error; err != nil {
  265. log.Error("s.Tyrant query by commit_id error(%v)", err)
  266. return
  267. }
  268. if len(pkgs) == 0 {
  269. err = fmt.Errorf("pkgs is none")
  270. log.Error("s.Tyrant query by commit_id error(%v)", err)
  271. return
  272. }
  273. for _, pkg := range pkgs {
  274. if t, err = s.tyrant(pkg); err != nil {
  275. return
  276. }
  277. if t.Tyrant {
  278. break
  279. }
  280. }
  281. return
  282. }
  283. // tyrant determine whether the standard is up to standard
  284. func (s *Service) tyrant(pkg *ut.PkgAnls) (t *ut.Tyrant, err error) {
  285. var (
  286. pkgs = make([]*ut.PkgAnls, 0)
  287. curCover = pkg.Coverage / 100
  288. preCover float64
  289. )
  290. if err = s.DB.Select("commit_id, coverage").Where("pkg=?", pkg.PKG).Order("coverage desc").Find(&pkgs).Error; err != nil {
  291. log.Error("s.Tyrant query by pkg error(%v)", err)
  292. return
  293. }
  294. if len(pkgs) == 0 {
  295. return
  296. } else if len(pkgs) == 1 || pkg.CommitID != pkgs[0].CommitID {
  297. preCover = pkgs[0].Coverage / 100
  298. } else if pkg.CommitID == pkgs[0].CommitID {
  299. preCover = pkgs[1].Coverage / 100
  300. }
  301. t = &ut.Tyrant{
  302. Package: pkg.PKG,
  303. Coverage: curCover,
  304. PassRate: float64(pkg.Passed) / float64(pkg.Assertions) * 100,
  305. Tyrant: curCover < float64(s.c.UTBaseLine.Coverage) || pkg.Passed != pkg.Assertions,
  306. Standard: s.c.UTBaseLine.Coverage,
  307. Increase: curCover - preCover,
  308. LastCID: pkgs[0].CommitID,
  309. }
  310. return
  311. }
  312. //QATrend give single user's coverage ,passrate and score data
  313. func (s *Service) QATrend(c context.Context, arg *ut.QATrendReq) (trend *ut.QATrendResp, err error) {
  314. var (
  315. date, group, order string
  316. details []*ut.PkgAnls
  317. where = "1=1 and (ut_pkganls.pkg!=substring_index(ut_pkganls.pkg,'/',5) or ut_pkganls.pkg like 'go-common/library/%')"
  318. )
  319. if arg.User != "" {
  320. where += fmt.Sprintf(" and ut_commit.username = '%s'", arg.User)
  321. }
  322. if arg.StartTime != 0 && arg.EndTime != 0 {
  323. where += fmt.Sprintf(" and ut_pkganls.mtime >= '%s' and ut_pkganls.mtime <= '%s'", time.Unix(arg.StartTime, 0).Format("2006-01-02 15:04:05"), time.Unix(arg.EndTime, 0).Format("2006-01-02 15:04:05"))
  324. } else {
  325. where += fmt.Sprintf(" and ut_pkganls.mtime >= '%s'", time.Now().AddDate(0, 0, -arg.LastTime))
  326. }
  327. if arg.Period == "hour" {
  328. order += "SUBSTRING(ut_pkganls.mtime,11,2) asc"
  329. } else {
  330. order += "mtime asc"
  331. }
  332. if arg.Period == "day" {
  333. group += "LEFT(ut_pkganls.mtime,10)"
  334. } else {
  335. group += fmt.Sprintf("%s(ut_pkganls.mtime)", arg.Period)
  336. }
  337. if err = s.DB.Table(_utpkg).Joins("join ut_commit on ut_pkganls.commit_id = ut_commit.commit_id").
  338. Select(`ROUND(AVG(coverage/100),2) AS coverage,ROUND(SUM(passed)/SUM(assertions)*100,2) AS pass_rate, ROUND((AVG(coverage)/100*(SUM(passed)/SUM(assertions))),2) AS score, MAX(ut_pkganls.mtime) AS mtime,GROUP_CONCAT(Distinct ut_commit.commit_id) AS cids`).
  339. Where(where).Group(group).Order(order).Find(&details).Error; err != nil {
  340. log.Error("service.QATrend find detail error(%v)", err)
  341. return
  342. }
  343. trend = &ut.QATrendResp{BaseLine: conf.Conf.UTBaseLine.Coverage}
  344. for _, detail := range details {
  345. switch arg.Period {
  346. case "hour":
  347. date = fmt.Sprintf("%d时", detail.MTime.Time().Hour())
  348. case "month":
  349. date = detail.MTime.Time().Month().String()
  350. default:
  351. date = detail.MTime.Time().Format("01-02")
  352. }
  353. trend.Dates = append(trend.Dates, date)
  354. trend.Coverages = append(trend.Coverages, detail.Coverage)
  355. trend.PassRates = append(trend.PassRates, detail.PassRate)
  356. trend.Scores = append(trend.Scores, detail.Score)
  357. trend.CommitIDs = append(trend.CommitIDs, detail.Cids)
  358. }
  359. return
  360. }
  361. //UTGernalCommit get singe or all users' general commit infos
  362. func (s *Service) UTGernalCommit(c context.Context, commits string) (cmInfos []*ut.CommitInfo, err error) {
  363. if err = s.DB.Table(_utpkg).Joins("join ut_commit on ut_pkganls.commit_id = ut_commit.commit_id").
  364. Select("ROUND(AVG(coverage/100),2) as coverage,ROUND(SUM(passed)/SUM(assertions)*100,2) as pass_rate,ut_pkganls.merge_id,ut_pkganls.commit_id,ut_pkganls.mtime").
  365. Where("ut_pkganls.commit_id in (?) and (pkg!=substring_index(ut_pkganls.pkg,'/',5)", strings.Split(commits, ",")).Group("commit_id").Order("mtime DESC").Find(&cmInfos).Error; err != nil {
  366. log.Error("service.UTGernalCommit get cmInfos error(%v)", err)
  367. return
  368. }
  369. for i, cmInfo := range cmInfos {
  370. cmInfos[i].GitlabCommit, _ = s.dao.GitLabCommits(context.Background(), cmInfo.CommitID)
  371. }
  372. return
  373. }
  374. // CommentOnMR create or modify comment on relavent merge request
  375. func (s *Service) CommentOnMR(c context.Context, projID, mrID int, msg string) (err error) {
  376. var (
  377. mr = &ut.Merge{}
  378. noteID int
  379. )
  380. if err = s.DB.Where("merge_id=?", mrID).First(mr).Error; err != nil {
  381. log.Error("apmSvc.GitReport error search ut_merge error(%v)", err)
  382. return
  383. }
  384. if mr.NoteID == 0 {
  385. if noteID, err = s.gitlab.CreateMRNote(projID, mrID, msg); err != nil {
  386. log.Error("apmSvc.GitReport error CreateMRNote error(%v)", err)
  387. return
  388. }
  389. if err = s.DB.Table(_utMerge).Where("merge_id=?", mrID).Update("note_id", noteID).Error; err != nil {
  390. log.Error("apmSvc.GitReport error update ut_merge error(%v)", err)
  391. return
  392. }
  393. } else {
  394. if err = s.gitlab.UpdateMRNote(projID, mrID, mr.NoteID, msg); err != nil {
  395. log.Error("apmSvc.GitReport error CreateMRNote error(%v)", err)
  396. return
  397. }
  398. }
  399. return
  400. }
  401. // CommitHistory .
  402. func (s *Service) CommitHistory(c context.Context, username string, times int64) (pkgs []*ut.PkgAnls, err error) {
  403. pkgs = make([]*ut.PkgAnls, 0)
  404. if err = s.DB.Table("ut_pkganls p").
  405. Select("p.merge_id, p.commit_id, group_concat( p.pkg ) AS pkg,group_concat( ROUND( p.coverage / 100, 2 ) ) AS coverages,group_concat( ROUND( p.passed / p.assertions * 100, 2 ) ) AS pass_rates,p.mtime").
  406. Joins("left join ut_commit c on c.commit_id=p.commit_id").Where(" c.username=? AND (p.pkg!=substring_index(p.pkg,'/',5) or p.pkg like 'go-common/library/%')", username).
  407. Group("p.commit_id").Order("p.mtime desc").Limit(times).Find(&pkgs).Error; err != nil {
  408. log.Error("s.CommitHistory query error(%v)", err)
  409. }
  410. return
  411. }