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.

336 lines
8.3 KiB

  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. "strings"
  9. "time"
  10. "code.gitea.io/gitea/modules/git"
  11. "code.gitea.io/gitea/modules/timeutil"
  12. )
  13. // env keys for git hooks need
  14. const (
  15. EnvRepoName = "GITEA_REPO_NAME"
  16. EnvRepoUsername = "GITEA_REPO_USER_NAME"
  17. EnvRepoIsWiki = "GITEA_REPO_IS_WIKI"
  18. EnvPusherName = "GITEA_PUSHER_NAME"
  19. EnvPusherEmail = "GITEA_PUSHER_EMAIL"
  20. EnvPusherID = "GITEA_PUSHER_ID"
  21. EnvKeyID = "GITEA_KEY_ID"
  22. EnvIsDeployKey = "GITEA_IS_DEPLOY_KEY"
  23. EnvIsInternal = "GITEA_INTERNAL_PUSH"
  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, "", make(map[string]string), make(map[string]*User)}
  49. }
  50. // PushUpdateAddDeleteTags updates a number of added and delete tags
  51. func PushUpdateAddDeleteTags(repo *Repository, gitRepo *git.Repository, addTags, delTags []string) error {
  52. sess := x.NewSession()
  53. defer sess.Close()
  54. if err := sess.Begin(); err != nil {
  55. return fmt.Errorf("Unable to begin sess in PushUpdateDeleteTags: %v", err)
  56. }
  57. if err := pushUpdateDeleteTags(sess, repo, delTags); err != nil {
  58. return err
  59. }
  60. if err := pushUpdateAddTags(sess, repo, gitRepo, addTags); err != nil {
  61. return err
  62. }
  63. return sess.Commit()
  64. }
  65. // PushUpdateDeleteTags updates a number of delete tags
  66. func PushUpdateDeleteTags(repo *Repository, tags []string) error {
  67. sess := x.NewSession()
  68. defer sess.Close()
  69. if err := sess.Begin(); err != nil {
  70. return fmt.Errorf("Unable to begin sess in PushUpdateDeleteTags: %v", err)
  71. }
  72. if err := pushUpdateDeleteTags(sess, repo, tags); err != nil {
  73. return err
  74. }
  75. return sess.Commit()
  76. }
  77. func pushUpdateDeleteTags(e Engine, repo *Repository, tags []string) error {
  78. if len(tags) == 0 {
  79. return nil
  80. }
  81. lowerTags := make([]string, 0, len(tags))
  82. for _, tag := range tags {
  83. lowerTags = append(lowerTags, strings.ToLower(tag))
  84. }
  85. if _, err := e.
  86. Where("repo_id = ? AND is_tag = ?", repo.ID, true).
  87. In("lower_tag_name", lowerTags).
  88. Delete(new(Release)); err != nil {
  89. return fmt.Errorf("Delete: %v", err)
  90. }
  91. if _, err := e.
  92. Where("repo_id = ? AND is_tag = ?", repo.ID, false).
  93. In("lower_tag_name", lowerTags).
  94. Cols("is_draft", "num_commits", "sha1").
  95. Update(&Release{
  96. IsDraft: true,
  97. }); err != nil {
  98. return fmt.Errorf("Update: %v", err)
  99. }
  100. return nil
  101. }
  102. // PushUpdateDeleteTag must be called for any push actions to delete tag
  103. func PushUpdateDeleteTag(repo *Repository, tagName string) error {
  104. rel, err := GetRelease(repo.ID, tagName)
  105. if err != nil {
  106. if IsErrReleaseNotExist(err) {
  107. return nil
  108. }
  109. return fmt.Errorf("GetRelease: %v", err)
  110. }
  111. if rel.IsTag {
  112. if _, err = x.ID(rel.ID).Delete(new(Release)); err != nil {
  113. return fmt.Errorf("Delete: %v", err)
  114. }
  115. } else {
  116. rel.IsDraft = true
  117. rel.NumCommits = 0
  118. rel.Sha1 = ""
  119. if _, err = x.ID(rel.ID).AllCols().Update(rel); err != nil {
  120. return fmt.Errorf("Update: %v", err)
  121. }
  122. }
  123. return nil
  124. }
  125. // PushUpdateAddTags updates a number of add tags
  126. func PushUpdateAddTags(repo *Repository, gitRepo *git.Repository, tags []string) error {
  127. sess := x.NewSession()
  128. defer sess.Close()
  129. if err := sess.Begin(); err != nil {
  130. return fmt.Errorf("Unable to begin sess in PushUpdateAddTags: %v", err)
  131. }
  132. if err := pushUpdateAddTags(sess, repo, gitRepo, tags); err != nil {
  133. return err
  134. }
  135. return sess.Commit()
  136. }
  137. func pushUpdateAddTags(e Engine, repo *Repository, gitRepo *git.Repository, tags []string) error {
  138. if len(tags) == 0 {
  139. return nil
  140. }
  141. lowerTags := make([]string, 0, len(tags))
  142. for _, tag := range tags {
  143. lowerTags = append(lowerTags, strings.ToLower(tag))
  144. }
  145. releases := make([]Release, 0, len(tags))
  146. if err := e.Where("repo_id = ?", repo.ID).
  147. In("lower_tag_name", lowerTags).Find(&releases); err != nil {
  148. return fmt.Errorf("GetRelease: %v", err)
  149. }
  150. relMap := make(map[string]*Release)
  151. for _, rel := range releases {
  152. relMap[rel.LowerTagName] = &rel
  153. }
  154. newReleases := make([]*Release, 0, len(lowerTags)-len(relMap))
  155. emailToUser := make(map[string]*User)
  156. for i, lowerTag := range lowerTags {
  157. tag, err := gitRepo.GetTag(tags[i])
  158. if err != nil {
  159. return fmt.Errorf("GetTag: %v", err)
  160. }
  161. commit, err := tag.Commit()
  162. if err != nil {
  163. return fmt.Errorf("Commit: %v", err)
  164. }
  165. sig := tag.Tagger
  166. if sig == nil {
  167. sig = commit.Author
  168. }
  169. if sig == nil {
  170. sig = commit.Committer
  171. }
  172. var author *User
  173. var createdAt = time.Unix(1, 0)
  174. if sig != nil {
  175. var ok bool
  176. author, ok = emailToUser[sig.Email]
  177. if !ok {
  178. author, err = GetUserByEmail(sig.Email)
  179. if err != nil && !IsErrUserNotExist(err) {
  180. return fmt.Errorf("GetUserByEmail: %v", err)
  181. }
  182. }
  183. createdAt = sig.When
  184. }
  185. commitsCount, err := commit.CommitsCount()
  186. if err != nil {
  187. return fmt.Errorf("CommitsCount: %v", err)
  188. }
  189. rel, has := relMap[lowerTag]
  190. if !has {
  191. rel = &Release{
  192. RepoID: repo.ID,
  193. Title: "",
  194. TagName: tags[i],
  195. LowerTagName: lowerTag,
  196. Target: "",
  197. Sha1: commit.ID.String(),
  198. NumCommits: commitsCount,
  199. Note: "",
  200. IsDraft: false,
  201. IsPrerelease: false,
  202. IsTag: true,
  203. CreatedUnix: timeutil.TimeStamp(createdAt.Unix()),
  204. }
  205. if author != nil {
  206. rel.PublisherID = author.ID
  207. }
  208. newReleases = append(newReleases, rel)
  209. } else {
  210. rel.Sha1 = commit.ID.String()
  211. rel.CreatedUnix = timeutil.TimeStamp(createdAt.Unix())
  212. rel.NumCommits = commitsCount
  213. rel.IsDraft = false
  214. if rel.IsTag && author != nil {
  215. rel.PublisherID = author.ID
  216. }
  217. if _, err = e.ID(rel.ID).AllCols().Update(rel); err != nil {
  218. return fmt.Errorf("Update: %v", err)
  219. }
  220. }
  221. }
  222. if len(newReleases) > 0 {
  223. if _, err := e.Insert(newReleases); err != nil {
  224. return fmt.Errorf("Insert: %v", err)
  225. }
  226. }
  227. return nil
  228. }
  229. // PushUpdateAddTag must be called for any push actions to add tag
  230. func PushUpdateAddTag(repo *Repository, gitRepo *git.Repository, tagName string) error {
  231. rel, err := GetRelease(repo.ID, tagName)
  232. if err != nil && !IsErrReleaseNotExist(err) {
  233. return fmt.Errorf("GetRelease: %v", err)
  234. }
  235. tag, err := gitRepo.GetTag(tagName)
  236. if err != nil {
  237. return fmt.Errorf("GetTag: %v", err)
  238. }
  239. commit, err := tag.Commit()
  240. if err != nil {
  241. return fmt.Errorf("Commit: %v", err)
  242. }
  243. sig := tag.Tagger
  244. if sig == nil {
  245. sig = commit.Author
  246. }
  247. if sig == nil {
  248. sig = commit.Committer
  249. }
  250. var author *User
  251. var createdAt = time.Unix(1, 0)
  252. if sig != nil {
  253. author, err = GetUserByEmail(sig.Email)
  254. if err != nil && !IsErrUserNotExist(err) {
  255. return fmt.Errorf("GetUserByEmail: %v", err)
  256. }
  257. createdAt = sig.When
  258. }
  259. commitsCount, err := commit.CommitsCount()
  260. if err != nil {
  261. return fmt.Errorf("CommitsCount: %v", err)
  262. }
  263. if rel == nil {
  264. rel = &Release{
  265. RepoID: repo.ID,
  266. Title: "",
  267. TagName: tagName,
  268. LowerTagName: strings.ToLower(tagName),
  269. Target: "",
  270. Sha1: commit.ID.String(),
  271. NumCommits: commitsCount,
  272. Note: "",
  273. IsDraft: false,
  274. IsPrerelease: false,
  275. IsTag: true,
  276. CreatedUnix: timeutil.TimeStamp(createdAt.Unix()),
  277. }
  278. if author != nil {
  279. rel.PublisherID = author.ID
  280. }
  281. if _, err = x.InsertOne(rel); err != nil {
  282. return fmt.Errorf("InsertOne: %v", err)
  283. }
  284. } else {
  285. rel.Sha1 = commit.ID.String()
  286. rel.CreatedUnix = timeutil.TimeStamp(createdAt.Unix())
  287. rel.NumCommits = commitsCount
  288. rel.IsDraft = false
  289. if rel.IsTag && author != nil {
  290. rel.PublisherID = author.ID
  291. }
  292. if _, err = x.ID(rel.ID).AllCols().Update(rel); err != nil {
  293. return fmt.Errorf("Update: %v", err)
  294. }
  295. }
  296. return nil
  297. }