gitea源码

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. // Copyright 2019 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package repository
  4. import (
  5. "context"
  6. "fmt"
  7. "strings"
  8. "code.gitea.io/gitea/models/db"
  9. git_model "code.gitea.io/gitea/models/git"
  10. issues_model "code.gitea.io/gitea/models/issues"
  11. repo_model "code.gitea.io/gitea/models/repo"
  12. user_model "code.gitea.io/gitea/models/user"
  13. "code.gitea.io/gitea/modules/gitrepo"
  14. "code.gitea.io/gitea/modules/log"
  15. notify_service "code.gitea.io/gitea/services/notify"
  16. )
  17. // GenerateIssueLabels generates issue labels from a template repository
  18. func GenerateIssueLabels(ctx context.Context, templateRepo, generateRepo *repo_model.Repository) error {
  19. templateLabels, err := issues_model.GetLabelsByRepoID(ctx, templateRepo.ID, "", db.ListOptions{})
  20. if err != nil {
  21. return err
  22. }
  23. // Prevent insert being called with an empty slice which would result in
  24. // err "no element on slice when insert".
  25. if len(templateLabels) == 0 {
  26. return nil
  27. }
  28. newLabels := make([]*issues_model.Label, 0, len(templateLabels))
  29. for _, templateLabel := range templateLabels {
  30. newLabels = append(newLabels, &issues_model.Label{
  31. RepoID: generateRepo.ID,
  32. Name: templateLabel.Name,
  33. Exclusive: templateLabel.Exclusive,
  34. Description: templateLabel.Description,
  35. Color: templateLabel.Color,
  36. })
  37. }
  38. return db.Insert(ctx, newLabels)
  39. }
  40. func GenerateProtectedBranch(ctx context.Context, templateRepo, generateRepo *repo_model.Repository) error {
  41. templateBranches, err := git_model.FindRepoProtectedBranchRules(ctx, templateRepo.ID)
  42. if err != nil {
  43. return err
  44. }
  45. // Prevent insert being called with an empty slice which would result in
  46. // err "no element on slice when insert".
  47. if len(templateBranches) == 0 {
  48. return nil
  49. }
  50. newBranches := make([]*git_model.ProtectedBranch, 0, len(templateBranches))
  51. for _, templateBranch := range templateBranches {
  52. templateBranch.ID = 0
  53. templateBranch.RepoID = generateRepo.ID
  54. templateBranch.UpdatedUnix = 0
  55. templateBranch.CreatedUnix = 0
  56. newBranches = append(newBranches, templateBranch)
  57. }
  58. return db.Insert(ctx, newBranches)
  59. }
  60. // GenerateRepository generates a repository from a template
  61. func GenerateRepository(ctx context.Context, doer, owner *user_model.User, templateRepo *repo_model.Repository, opts GenerateRepoOptions) (_ *repo_model.Repository, err error) {
  62. if !doer.CanCreateRepoIn(owner) {
  63. return nil, repo_model.ErrReachLimitOfRepo{
  64. Limit: owner.MaxRepoCreation,
  65. }
  66. }
  67. generateRepo := &repo_model.Repository{
  68. OwnerID: owner.ID,
  69. Owner: owner,
  70. OwnerName: owner.Name,
  71. Name: opts.Name,
  72. LowerName: strings.ToLower(opts.Name),
  73. Description: opts.Description,
  74. DefaultBranch: opts.DefaultBranch,
  75. IsPrivate: opts.Private,
  76. IsEmpty: !opts.GitContent || templateRepo.IsEmpty,
  77. IsFsckEnabled: templateRepo.IsFsckEnabled,
  78. TemplateID: templateRepo.ID,
  79. TrustModel: templateRepo.TrustModel,
  80. ObjectFormatName: templateRepo.ObjectFormatName,
  81. Status: repo_model.RepositoryBeingMigrated,
  82. }
  83. // 1 - Create the repository in the database
  84. if err := db.WithTx(ctx, func(ctx context.Context) error {
  85. return createRepositoryInDB(ctx, doer, owner, generateRepo, false)
  86. }); err != nil {
  87. return nil, err
  88. }
  89. // last - clean up the repository if something goes wrong
  90. defer func() {
  91. if err != nil {
  92. // we can not use the ctx because it maybe canceled or timeout
  93. cleanupRepository(generateRepo.ID)
  94. }
  95. }()
  96. // 2 - check whether the repository with the same storage exists
  97. isExist, err := gitrepo.IsRepositoryExist(ctx, generateRepo)
  98. if err != nil {
  99. log.Error("Unable to check if %s exists. Error: %v", generateRepo.FullName(), err)
  100. return nil, err
  101. }
  102. if isExist {
  103. // Don't return directly, we need err in defer to cleanupRepository
  104. err = repo_model.ErrRepoFilesAlreadyExist{
  105. Uname: generateRepo.OwnerName,
  106. Name: generateRepo.Name,
  107. }
  108. return nil, err
  109. }
  110. // 3 -Init git bare new repository.
  111. if err = gitrepo.InitRepository(ctx, generateRepo, generateRepo.ObjectFormatName); err != nil {
  112. return nil, fmt.Errorf("git.InitRepository: %w", err)
  113. } else if err = gitrepo.CreateDelegateHooks(ctx, generateRepo); err != nil {
  114. return nil, fmt.Errorf("createDelegateHooks: %w", err)
  115. }
  116. // 4 - Update the git repository
  117. if err = updateGitRepoAfterCreate(ctx, generateRepo); err != nil {
  118. return nil, fmt.Errorf("updateGitRepoAfterCreate: %w", err)
  119. }
  120. // 5 - generate the repository contents according to the template
  121. // Git Content
  122. if opts.GitContent && !templateRepo.IsEmpty {
  123. if err = GenerateGitContent(ctx, templateRepo, generateRepo); err != nil {
  124. return nil, err
  125. }
  126. }
  127. // Topics
  128. if opts.Topics {
  129. if err = repo_model.GenerateTopics(ctx, templateRepo, generateRepo); err != nil {
  130. return nil, err
  131. }
  132. }
  133. // Git Hooks
  134. if opts.GitHooks {
  135. if err = GenerateGitHooks(ctx, templateRepo, generateRepo); err != nil {
  136. return nil, err
  137. }
  138. }
  139. // Webhooks
  140. if opts.Webhooks {
  141. if err = GenerateWebhooks(ctx, templateRepo, generateRepo); err != nil {
  142. return nil, err
  143. }
  144. }
  145. // Avatar
  146. if opts.Avatar && len(templateRepo.Avatar) > 0 {
  147. if err = generateAvatar(ctx, templateRepo, generateRepo); err != nil {
  148. return nil, err
  149. }
  150. }
  151. // Issue Labels
  152. if opts.IssueLabels {
  153. if err = GenerateIssueLabels(ctx, templateRepo, generateRepo); err != nil {
  154. return nil, err
  155. }
  156. }
  157. if opts.ProtectedBranch {
  158. if err = GenerateProtectedBranch(ctx, templateRepo, generateRepo); err != nil {
  159. return nil, err
  160. }
  161. }
  162. // 6 - update repository status to be ready
  163. generateRepo.Status = repo_model.RepositoryReady
  164. if err = repo_model.UpdateRepositoryColsWithAutoTime(ctx, generateRepo, "status"); err != nil {
  165. return nil, fmt.Errorf("UpdateRepositoryCols: %w", err)
  166. }
  167. notify_service.CreateRepository(ctx, doer, owner, generateRepo)
  168. return generateRepo, nil
  169. }