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.

v156.go 5.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. // Copyright 2020 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package v1_14 //nolint
  4. import (
  5. "fmt"
  6. "path/filepath"
  7. "strings"
  8. "code.gitea.io/gitea/modules/git"
  9. "code.gitea.io/gitea/modules/log"
  10. "code.gitea.io/gitea/modules/setting"
  11. "xorm.io/xorm"
  12. )
  13. // Copy paste from models/repo.go because we cannot import models package
  14. func repoPath(userName, repoName string) string {
  15. return filepath.Join(userPath(userName), strings.ToLower(repoName)+".git")
  16. }
  17. func userPath(userName string) string {
  18. return filepath.Join(setting.RepoRootPath, strings.ToLower(userName))
  19. }
  20. func FixPublisherIDforTagReleases(x *xorm.Engine) error {
  21. type Release struct {
  22. ID int64
  23. RepoID int64
  24. Sha1 string
  25. TagName string
  26. PublisherID int64
  27. }
  28. type Repository struct {
  29. ID int64
  30. OwnerID int64
  31. OwnerName string
  32. Name string
  33. }
  34. type User struct {
  35. ID int64
  36. Name string
  37. Email string
  38. }
  39. const batchSize = 100
  40. sess := x.NewSession()
  41. defer sess.Close()
  42. var (
  43. repo *Repository
  44. gitRepo *git.Repository
  45. user *User
  46. )
  47. defer func() {
  48. if gitRepo != nil {
  49. gitRepo.Close()
  50. }
  51. }()
  52. for start := 0; ; start += batchSize {
  53. releases := make([]*Release, 0, batchSize)
  54. if err := sess.Begin(); err != nil {
  55. return err
  56. }
  57. if err := sess.Limit(batchSize, start).
  58. Where("publisher_id = 0 OR publisher_id is null").
  59. Asc("repo_id", "id").Where("is_tag=?", true).
  60. Find(&releases); err != nil {
  61. return err
  62. }
  63. if len(releases) == 0 {
  64. break
  65. }
  66. for _, release := range releases {
  67. if repo == nil || repo.ID != release.RepoID {
  68. if gitRepo != nil {
  69. gitRepo.Close()
  70. gitRepo = nil
  71. }
  72. repo = new(Repository)
  73. has, err := sess.ID(release.RepoID).Get(repo)
  74. if err != nil {
  75. log.Error("Error whilst loading repository[%d] for release[%d] with tag name %s. Error: %v", release.RepoID, release.ID, release.TagName, err)
  76. return err
  77. } else if !has {
  78. log.Warn("Release[%d] is orphaned and refers to non-existing repository %d", release.ID, release.RepoID)
  79. log.Warn("This release should be deleted")
  80. continue
  81. }
  82. if repo.OwnerName == "" {
  83. // v120.go migration may not have been run correctly - we'll just replicate it here
  84. // because this appears to be a common-ish problem.
  85. if _, err := sess.Exec("UPDATE repository SET owner_name = (SELECT name FROM `user` WHERE `user`.id = repository.owner_id)"); err != nil {
  86. log.Error("Error whilst updating repository[%d] owner name", repo.ID)
  87. return err
  88. }
  89. if _, err := sess.ID(release.RepoID).Get(repo); err != nil {
  90. log.Error("Error whilst loading repository[%d] for release[%d] with tag name %s. Error: %v", release.RepoID, release.ID, release.TagName, err)
  91. return err
  92. }
  93. }
  94. gitRepo, err = git.OpenRepository(git.DefaultContext, repoPath(repo.OwnerName, repo.Name))
  95. if err != nil {
  96. log.Error("Error whilst opening git repo for [%d]%s/%s. Error: %v", repo.ID, repo.OwnerName, repo.Name, err)
  97. return err
  98. }
  99. }
  100. commit, err := gitRepo.GetTagCommit(release.TagName)
  101. if err != nil {
  102. if git.IsErrNotExist(err) {
  103. log.Warn("Unable to find commit %s for Tag: %s in [%d]%s/%s. Cannot update publisher ID.", err.(git.ErrNotExist).ID, release.TagName, repo.ID, repo.OwnerName, repo.Name)
  104. continue
  105. }
  106. log.Error("Error whilst getting commit for Tag: %s in [%d]%s/%s. Error: %v", release.TagName, repo.ID, repo.OwnerName, repo.Name, err)
  107. return fmt.Errorf("GetTagCommit: %w", err)
  108. }
  109. if commit.Author.Email == "" {
  110. log.Warn("Tag: %s in Repo[%d]%s/%s does not have a tagger.", release.TagName, repo.ID, repo.OwnerName, repo.Name)
  111. commit, err = gitRepo.GetCommit(commit.ID.String())
  112. if err != nil {
  113. if git.IsErrNotExist(err) {
  114. log.Warn("Unable to find commit %s for Tag: %s in [%d]%s/%s. Cannot update publisher ID.", err.(git.ErrNotExist).ID, release.TagName, repo.ID, repo.OwnerName, repo.Name)
  115. continue
  116. }
  117. log.Error("Error whilst getting commit for Tag: %s in [%d]%s/%s. Error: %v", release.TagName, repo.ID, repo.OwnerName, repo.Name, err)
  118. return fmt.Errorf("GetCommit: %w", err)
  119. }
  120. }
  121. if commit.Author.Email == "" {
  122. log.Warn("Tag: %s in Repo[%d]%s/%s does not have a Tagger and its underlying commit does not have an Author either!", release.TagName, repo.ID, repo.OwnerName, repo.Name)
  123. continue
  124. }
  125. if user == nil || !strings.EqualFold(user.Email, commit.Author.Email) {
  126. user = new(User)
  127. _, err = sess.Where("email=?", commit.Author.Email).Get(user)
  128. if err != nil {
  129. log.Error("Error whilst getting commit author by email: %s for Tag: %s in [%d]%s/%s. Error: %v", commit.Author.Email, release.TagName, repo.ID, repo.OwnerName, repo.Name, err)
  130. return err
  131. }
  132. user.Email = commit.Author.Email
  133. }
  134. if user.ID <= 0 {
  135. continue
  136. }
  137. release.PublisherID = user.ID
  138. if _, err := sess.ID(release.ID).Cols("publisher_id").Update(release); err != nil {
  139. log.Error("Error whilst updating publisher[%d] for release[%d] with tag name %s. Error: %v", release.PublisherID, release.ID, release.TagName, err)
  140. return err
  141. }
  142. }
  143. if gitRepo != nil {
  144. gitRepo.Close()
  145. }
  146. if err := sess.Commit(); err != nil {
  147. return err
  148. }
  149. }
  150. return nil
  151. }