Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. // Copyright 2014 The Gogs 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 models
  5. import (
  6. "container/list"
  7. "fmt"
  8. "os/exec"
  9. "strings"
  10. "time"
  11. "code.gitea.io/git"
  12. "code.gitea.io/gitea/modules/cache"
  13. "code.gitea.io/gitea/modules/log"
  14. "code.gitea.io/gitea/modules/util"
  15. )
  16. // env keys for git hooks need
  17. const (
  18. EnvRepoName = "GITEA_REPO_NAME"
  19. EnvRepoUsername = "GITEA_REPO_USER_NAME"
  20. EnvRepoIsWiki = "GITEA_REPO_IS_WIKI"
  21. EnvPusherName = "GITEA_PUSHER_NAME"
  22. EnvPusherEmail = "GITEA_PUSHER_EMAIL"
  23. EnvPusherID = "GITEA_PUSHER_ID"
  24. )
  25. // CommitToPushCommit transforms a git.Commit to PushCommit type.
  26. func CommitToPushCommit(commit *git.Commit) *PushCommit {
  27. return &PushCommit{
  28. Sha1: commit.ID.String(),
  29. Message: commit.Message(),
  30. AuthorEmail: commit.Author.Email,
  31. AuthorName: commit.Author.Name,
  32. CommitterEmail: commit.Committer.Email,
  33. CommitterName: commit.Committer.Name,
  34. Timestamp: commit.Author.When,
  35. }
  36. }
  37. // ListToPushCommits transforms a list.List to PushCommits type.
  38. func ListToPushCommits(l *list.List) *PushCommits {
  39. var commits []*PushCommit
  40. var actEmail string
  41. for e := l.Front(); e != nil; e = e.Next() {
  42. commit := e.Value.(*git.Commit)
  43. if actEmail == "" {
  44. actEmail = commit.Committer.Email
  45. }
  46. commits = append(commits, CommitToPushCommit(commit))
  47. }
  48. return &PushCommits{l.Len(), commits, "", nil}
  49. }
  50. // PushUpdateOptions defines the push update options
  51. type PushUpdateOptions struct {
  52. PusherID int64
  53. PusherName string
  54. RepoUserName string
  55. RepoName string
  56. RefFullName string
  57. OldCommitID string
  58. NewCommitID string
  59. }
  60. // PushUpdate must be called for any push actions in order to
  61. // generates necessary push action history feeds.
  62. func PushUpdate(branch string, opt PushUpdateOptions) error {
  63. repo, err := pushUpdate(opt)
  64. if err != nil {
  65. return err
  66. }
  67. pusher, err := GetUserByID(opt.PusherID)
  68. if err != nil {
  69. return err
  70. }
  71. log.Trace("TriggerTask '%s/%s' by %s", repo.Name, branch, pusher.Name)
  72. go AddTestPullRequestTask(pusher, repo.ID, branch, true)
  73. return nil
  74. }
  75. func pushUpdateDeleteTag(repo *Repository, gitRepo *git.Repository, tagName string) error {
  76. rel, err := GetRelease(repo.ID, tagName)
  77. if err != nil {
  78. if IsErrReleaseNotExist(err) {
  79. return nil
  80. }
  81. return fmt.Errorf("GetRelease: %v", err)
  82. }
  83. if rel.IsTag {
  84. if _, err = x.ID(rel.ID).Delete(new(Release)); err != nil {
  85. return fmt.Errorf("Delete: %v", err)
  86. }
  87. } else {
  88. rel.IsDraft = true
  89. rel.NumCommits = 0
  90. rel.Sha1 = ""
  91. if _, err = x.ID(rel.ID).AllCols().Update(rel); err != nil {
  92. return fmt.Errorf("Update: %v", err)
  93. }
  94. }
  95. return nil
  96. }
  97. func pushUpdateAddTag(repo *Repository, gitRepo *git.Repository, tagName string) error {
  98. rel, err := GetRelease(repo.ID, tagName)
  99. if err != nil && !IsErrReleaseNotExist(err) {
  100. return fmt.Errorf("GetRelease: %v", err)
  101. }
  102. tag, err := gitRepo.GetTag(tagName)
  103. if err != nil {
  104. return fmt.Errorf("GetTag: %v", err)
  105. }
  106. commit, err := tag.Commit()
  107. if err != nil {
  108. return fmt.Errorf("Commit: %v", err)
  109. }
  110. sig := tag.Tagger
  111. if sig == nil {
  112. sig = commit.Author
  113. }
  114. if sig == nil {
  115. sig = commit.Committer
  116. }
  117. var author *User
  118. var createdAt = time.Unix(1, 0)
  119. if sig != nil {
  120. author, err = GetUserByEmail(sig.Email)
  121. if err != nil && !IsErrUserNotExist(err) {
  122. return fmt.Errorf("GetUserByEmail: %v", err)
  123. }
  124. createdAt = sig.When
  125. }
  126. commitsCount, err := commit.CommitsCount()
  127. if err != nil {
  128. return fmt.Errorf("CommitsCount: %v", err)
  129. }
  130. if rel == nil {
  131. rel = &Release{
  132. RepoID: repo.ID,
  133. Title: "",
  134. TagName: tagName,
  135. LowerTagName: strings.ToLower(tagName),
  136. Target: "",
  137. Sha1: commit.ID.String(),
  138. NumCommits: commitsCount,
  139. Note: "",
  140. IsDraft: false,
  141. IsPrerelease: false,
  142. IsTag: true,
  143. CreatedUnix: util.TimeStamp(createdAt.Unix()),
  144. }
  145. if author != nil {
  146. rel.PublisherID = author.ID
  147. }
  148. if _, err = x.InsertOne(rel); err != nil {
  149. return fmt.Errorf("InsertOne: %v", err)
  150. }
  151. } else {
  152. rel.Sha1 = commit.ID.String()
  153. rel.CreatedUnix = util.TimeStamp(createdAt.Unix())
  154. rel.NumCommits = commitsCount
  155. rel.IsDraft = false
  156. if rel.IsTag && author != nil {
  157. rel.PublisherID = author.ID
  158. }
  159. if _, err = x.ID(rel.ID).AllCols().Update(rel); err != nil {
  160. return fmt.Errorf("Update: %v", err)
  161. }
  162. }
  163. return nil
  164. }
  165. func pushUpdate(opts PushUpdateOptions) (repo *Repository, err error) {
  166. isNewRef := opts.OldCommitID == git.EmptySHA
  167. isDelRef := opts.NewCommitID == git.EmptySHA
  168. if isNewRef && isDelRef {
  169. return nil, fmt.Errorf("Old and new revisions are both %s", git.EmptySHA)
  170. }
  171. repoPath := RepoPath(opts.RepoUserName, opts.RepoName)
  172. gitUpdate := exec.Command("git", "update-server-info")
  173. gitUpdate.Dir = repoPath
  174. if err = gitUpdate.Run(); err != nil {
  175. return nil, fmt.Errorf("Failed to call 'git update-server-info': %v", err)
  176. }
  177. owner, err := GetUserByName(opts.RepoUserName)
  178. if err != nil {
  179. return nil, fmt.Errorf("GetUserByName: %v", err)
  180. }
  181. repo, err = GetRepositoryByName(owner.ID, opts.RepoName)
  182. if err != nil {
  183. return nil, fmt.Errorf("GetRepositoryByName: %v", err)
  184. }
  185. gitRepo, err := git.OpenRepository(repoPath)
  186. if err != nil {
  187. return nil, fmt.Errorf("OpenRepository: %v", err)
  188. }
  189. if err = repo.UpdateSize(); err != nil {
  190. log.Error(4, "Failed to update size for repository: %v", err)
  191. }
  192. var commits = &PushCommits{}
  193. if strings.HasPrefix(opts.RefFullName, git.TagPrefix) {
  194. // If is tag reference
  195. tagName := opts.RefFullName[len(git.TagPrefix):]
  196. if isDelRef {
  197. err = pushUpdateDeleteTag(repo, gitRepo, tagName)
  198. if err != nil {
  199. return nil, fmt.Errorf("pushUpdateDeleteTag: %v", err)
  200. }
  201. } else {
  202. // Clear cache for tag commit count
  203. cache.Remove(repo.GetCommitsCountCacheKey(tagName, true))
  204. err = pushUpdateAddTag(repo, gitRepo, tagName)
  205. if err != nil {
  206. return nil, fmt.Errorf("pushUpdateAddTag: %v", err)
  207. }
  208. }
  209. } else if !isDelRef {
  210. // If is branch reference
  211. // Clear cache for branch commit count
  212. cache.Remove(repo.GetCommitsCountCacheKey(opts.RefFullName[len(git.BranchPrefix):], true))
  213. newCommit, err := gitRepo.GetCommit(opts.NewCommitID)
  214. if err != nil {
  215. return nil, fmt.Errorf("gitRepo.GetCommit: %v", err)
  216. }
  217. // Push new branch.
  218. var l *list.List
  219. if isNewRef {
  220. l, err = newCommit.CommitsBeforeLimit(10)
  221. if err != nil {
  222. return nil, fmt.Errorf("newCommit.CommitsBeforeLimit: %v", err)
  223. }
  224. } else {
  225. l, err = newCommit.CommitsBeforeUntil(opts.OldCommitID)
  226. if err != nil {
  227. return nil, fmt.Errorf("newCommit.CommitsBeforeUntil: %v", err)
  228. }
  229. }
  230. commits = ListToPushCommits(l)
  231. }
  232. if opts.RefFullName == git.BranchPrefix+repo.DefaultBranch {
  233. UpdateRepoIndexer(repo)
  234. }
  235. if err := CommitRepoAction(CommitRepoActionOptions{
  236. PusherName: opts.PusherName,
  237. RepoOwnerID: owner.ID,
  238. RepoName: repo.Name,
  239. RefFullName: opts.RefFullName,
  240. OldCommitID: opts.OldCommitID,
  241. NewCommitID: opts.NewCommitID,
  242. Commits: commits,
  243. }); err != nil {
  244. return nil, fmt.Errorf("CommitRepoAction: %v", err)
  245. }
  246. return repo, nil
  247. }