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.

176 lines
4.5 KiB

10 years ago
10 years ago
10 years ago
  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/log"
  12. )
  13. // UpdateTask defines an UpdateTask
  14. type UpdateTask struct {
  15. ID int64 `xorm:"pk autoincr"`
  16. UUID string `xorm:"index"`
  17. RefName string
  18. OldCommitID string
  19. NewCommitID string
  20. }
  21. // AddUpdateTask adds an UpdateTask
  22. func AddUpdateTask(task *UpdateTask) error {
  23. _, err := x.Insert(task)
  24. return err
  25. }
  26. // GetUpdateTaskByUUID returns update task by given UUID.
  27. func GetUpdateTaskByUUID(uuid string) (*UpdateTask, error) {
  28. task := &UpdateTask{
  29. UUID: uuid,
  30. }
  31. has, err := x.Get(task)
  32. if err != nil {
  33. return nil, err
  34. } else if !has {
  35. return nil, ErrUpdateTaskNotExist{uuid}
  36. }
  37. return task, nil
  38. }
  39. // DeleteUpdateTaskByUUID deletes an UpdateTask from the database
  40. func DeleteUpdateTaskByUUID(uuid string) error {
  41. _, err := x.Delete(&UpdateTask{UUID: uuid})
  42. return err
  43. }
  44. // CommitToPushCommit transforms a git.Commit to PushCommit type.
  45. func CommitToPushCommit(commit *git.Commit) *PushCommit {
  46. return &PushCommit{
  47. Sha1: commit.ID.String(),
  48. Message: commit.Message(),
  49. AuthorEmail: commit.Author.Email,
  50. AuthorName: commit.Author.Name,
  51. CommitterEmail: commit.Committer.Email,
  52. CommitterName: commit.Committer.Name,
  53. Timestamp: commit.Author.When,
  54. }
  55. }
  56. // ListToPushCommits transforms a list.List to PushCommits type.
  57. func ListToPushCommits(l *list.List) *PushCommits {
  58. var commits []*PushCommit
  59. var actEmail string
  60. for e := l.Front(); e != nil; e = e.Next() {
  61. commit := e.Value.(*git.Commit)
  62. if actEmail == "" {
  63. actEmail = commit.Committer.Email
  64. }
  65. commits = append(commits, CommitToPushCommit(commit))
  66. }
  67. return &PushCommits{l.Len(), commits, "", nil}
  68. }
  69. // PushUpdateOptions defines the push update options
  70. type PushUpdateOptions struct {
  71. PusherID int64
  72. PusherName string
  73. RepoUserName string
  74. RepoName string
  75. RefFullName string
  76. OldCommitID string
  77. NewCommitID string
  78. }
  79. // PushUpdate must be called for any push actions in order to
  80. // generates necessary push action history feeds.
  81. func PushUpdate(opts PushUpdateOptions) (err error) {
  82. isNewRef := opts.OldCommitID == git.EmptySHA
  83. isDelRef := opts.NewCommitID == git.EmptySHA
  84. if isNewRef && isDelRef {
  85. return fmt.Errorf("Old and new revisions are both %s", git.EmptySHA)
  86. }
  87. repoPath := RepoPath(opts.RepoUserName, opts.RepoName)
  88. gitUpdate := exec.Command("git", "update-server-info")
  89. gitUpdate.Dir = repoPath
  90. if err = gitUpdate.Run(); err != nil {
  91. return fmt.Errorf("Fail to call 'git update-server-info': %v", err)
  92. }
  93. if isDelRef {
  94. log.GitLogger.Info("Reference '%s' has been deleted from '%s/%s' by %s",
  95. opts.RefFullName, opts.RepoUserName, opts.RepoName, opts.PusherName)
  96. return nil
  97. }
  98. gitRepo, err := git.OpenRepository(repoPath)
  99. if err != nil {
  100. return fmt.Errorf("OpenRepository: %v", err)
  101. }
  102. owner, err := GetUserByName(opts.RepoUserName)
  103. if err != nil {
  104. return fmt.Errorf("GetUserByName: %v", err)
  105. }
  106. repo, err := GetRepositoryByName(owner.ID, opts.RepoName)
  107. if err != nil {
  108. return fmt.Errorf("GetRepositoryByName: %v", err)
  109. }
  110. // Push tags.
  111. if strings.HasPrefix(opts.RefFullName, git.TagPrefix) {
  112. if err := CommitRepoAction(CommitRepoActionOptions{
  113. PusherName: opts.PusherName,
  114. RepoOwnerID: owner.ID,
  115. RepoName: repo.Name,
  116. RefFullName: opts.RefFullName,
  117. OldCommitID: opts.OldCommitID,
  118. NewCommitID: opts.NewCommitID,
  119. Commits: &PushCommits{},
  120. }); err != nil {
  121. return fmt.Errorf("CommitRepoAction (tag): %v", err)
  122. }
  123. return nil
  124. }
  125. newCommit, err := gitRepo.GetCommit(opts.NewCommitID)
  126. if err != nil {
  127. return fmt.Errorf("gitRepo.GetCommit: %v", err)
  128. }
  129. // Push new branch.
  130. var l *list.List
  131. if isNewRef {
  132. l, err = newCommit.CommitsBeforeLimit(10)
  133. if err != nil {
  134. return fmt.Errorf("newCommit.CommitsBeforeLimit: %v", err)
  135. }
  136. } else {
  137. l, err = newCommit.CommitsBeforeUntil(opts.OldCommitID)
  138. if err != nil {
  139. return fmt.Errorf("newCommit.CommitsBeforeUntil: %v", err)
  140. }
  141. }
  142. if err := CommitRepoAction(CommitRepoActionOptions{
  143. PusherName: opts.PusherName,
  144. RepoOwnerID: owner.ID,
  145. RepoName: repo.Name,
  146. RefFullName: opts.RefFullName,
  147. OldCommitID: opts.OldCommitID,
  148. NewCommitID: opts.NewCommitID,
  149. Commits: ListToPushCommits(l),
  150. }); err != nil {
  151. return fmt.Errorf("CommitRepoAction (branch): %v", err)
  152. }
  153. return nil
  154. }