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

update.go 6.9 kB

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