You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. // Copyright 2019 The Gitea Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package repository
  5. import (
  6. "container/list"
  7. "fmt"
  8. "time"
  9. "code.gitea.io/gitea/models"
  10. "code.gitea.io/gitea/modules/git"
  11. "code.gitea.io/gitea/modules/log"
  12. api "code.gitea.io/gitea/modules/structs"
  13. )
  14. // PushCommit represents a commit in a push operation.
  15. type PushCommit struct {
  16. Sha1 string
  17. Message string
  18. AuthorEmail string
  19. AuthorName string
  20. CommitterEmail string
  21. CommitterName string
  22. Timestamp time.Time
  23. }
  24. // PushCommits represents list of commits in a push operation.
  25. type PushCommits struct {
  26. Len int
  27. Commits []*PushCommit
  28. CompareURL string
  29. avatars map[string]string
  30. emailUsers map[string]*models.User
  31. }
  32. // NewPushCommits creates a new PushCommits object.
  33. func NewPushCommits() *PushCommits {
  34. return &PushCommits{
  35. avatars: make(map[string]string),
  36. emailUsers: make(map[string]*models.User),
  37. }
  38. }
  39. // ToAPIPayloadCommits converts a PushCommits object to
  40. // api.PayloadCommit format.
  41. func (pc *PushCommits) ToAPIPayloadCommits(repoPath, repoLink string) ([]*api.PayloadCommit, error) {
  42. commits := make([]*api.PayloadCommit, len(pc.Commits))
  43. if pc.emailUsers == nil {
  44. pc.emailUsers = make(map[string]*models.User)
  45. }
  46. var err error
  47. for i, commit := range pc.Commits {
  48. authorUsername := ""
  49. author, ok := pc.emailUsers[commit.AuthorEmail]
  50. if !ok {
  51. author, err = models.GetUserByEmail(commit.AuthorEmail)
  52. if err == nil {
  53. authorUsername = author.Name
  54. pc.emailUsers[commit.AuthorEmail] = author
  55. }
  56. } else {
  57. authorUsername = author.Name
  58. }
  59. committerUsername := ""
  60. committer, ok := pc.emailUsers[commit.CommitterEmail]
  61. if !ok {
  62. committer, err = models.GetUserByEmail(commit.CommitterEmail)
  63. if err == nil {
  64. // TODO: check errors other than email not found.
  65. committerUsername = committer.Name
  66. pc.emailUsers[commit.CommitterEmail] = committer
  67. }
  68. } else {
  69. committerUsername = committer.Name
  70. }
  71. fileStatus, err := git.GetCommitFileStatus(repoPath, commit.Sha1)
  72. if err != nil {
  73. return nil, fmt.Errorf("FileStatus [commit_sha1: %s]: %v", commit.Sha1, err)
  74. }
  75. commits[i] = &api.PayloadCommit{
  76. ID: commit.Sha1,
  77. Message: commit.Message,
  78. URL: fmt.Sprintf("%s/commit/%s", repoLink, commit.Sha1),
  79. Author: &api.PayloadUser{
  80. Name: commit.AuthorName,
  81. Email: commit.AuthorEmail,
  82. UserName: authorUsername,
  83. },
  84. Committer: &api.PayloadUser{
  85. Name: commit.CommitterName,
  86. Email: commit.CommitterEmail,
  87. UserName: committerUsername,
  88. },
  89. Added: fileStatus.Added,
  90. Removed: fileStatus.Removed,
  91. Modified: fileStatus.Modified,
  92. Timestamp: commit.Timestamp,
  93. }
  94. }
  95. return commits, nil
  96. }
  97. // AvatarLink tries to match user in database with e-mail
  98. // in order to show custom avatar, and falls back to general avatar link.
  99. func (pc *PushCommits) AvatarLink(email string) string {
  100. if pc.avatars == nil {
  101. pc.avatars = make(map[string]string)
  102. }
  103. avatar, ok := pc.avatars[email]
  104. if ok {
  105. return avatar
  106. }
  107. u, ok := pc.emailUsers[email]
  108. if !ok {
  109. var err error
  110. u, err = models.GetUserByEmail(email)
  111. if err != nil {
  112. pc.avatars[email] = models.AvatarLink(email)
  113. if !models.IsErrUserNotExist(err) {
  114. log.Error("GetUserByEmail: %v", err)
  115. return ""
  116. }
  117. } else {
  118. pc.emailUsers[email] = u
  119. }
  120. }
  121. if u != nil {
  122. pc.avatars[email] = u.RelAvatarLink()
  123. }
  124. return pc.avatars[email]
  125. }
  126. // CommitToPushCommit transforms a git.Commit to PushCommit type.
  127. func CommitToPushCommit(commit *git.Commit) *PushCommit {
  128. return &PushCommit{
  129. Sha1: commit.ID.String(),
  130. Message: commit.Message(),
  131. AuthorEmail: commit.Author.Email,
  132. AuthorName: commit.Author.Name,
  133. CommitterEmail: commit.Committer.Email,
  134. CommitterName: commit.Committer.Name,
  135. Timestamp: commit.Author.When,
  136. }
  137. }
  138. // ListToPushCommits transforms a list.List to PushCommits type.
  139. func ListToPushCommits(l *list.List) *PushCommits {
  140. var commits []*PushCommit
  141. var actEmail string
  142. for e := l.Front(); e != nil; e = e.Next() {
  143. commit := e.Value.(*git.Commit)
  144. if actEmail == "" {
  145. actEmail = commit.Committer.Email
  146. }
  147. commits = append(commits, CommitToPushCommit(commit))
  148. }
  149. return &PushCommits{l.Len(), commits, "", make(map[string]string), make(map[string]*models.User)}
  150. }