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.

repo_generate.go 6.2 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. // Copyright 2019 The Gitea 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. "fmt"
  7. "os"
  8. "path/filepath"
  9. "strconv"
  10. "strings"
  11. "time"
  12. "code.gitea.io/gitea/modules/git"
  13. "code.gitea.io/gitea/modules/log"
  14. "github.com/unknwon/com"
  15. )
  16. // GenerateRepoOptions contains the template units to generate
  17. type GenerateRepoOptions struct {
  18. Name string
  19. Description string
  20. Private bool
  21. GitContent bool
  22. Topics bool
  23. GitHooks bool
  24. Webhooks bool
  25. Avatar bool
  26. IssueLabels bool
  27. }
  28. // IsValid checks whether at least one option is chosen for generation
  29. func (gro GenerateRepoOptions) IsValid() bool {
  30. return gro.GitContent || gro.Topics || gro.GitHooks || gro.Webhooks || gro.Avatar || gro.IssueLabels // or other items as they are added
  31. }
  32. // generateRepository initializes repository from template
  33. func generateRepository(e Engine, repo, templateRepo *Repository) (err error) {
  34. tmpDir := filepath.Join(os.TempDir(), "gitea-"+repo.Name+"-"+com.ToStr(time.Now().Nanosecond()))
  35. if err := os.MkdirAll(tmpDir, os.ModePerm); err != nil {
  36. return fmt.Errorf("Failed to create dir %s: %v", tmpDir, err)
  37. }
  38. defer func() {
  39. if err := os.RemoveAll(tmpDir); err != nil {
  40. log.Error("RemoveAll: %v", err)
  41. }
  42. }()
  43. if err = generateRepoCommit(e, repo, templateRepo, tmpDir); err != nil {
  44. return fmt.Errorf("generateRepoCommit: %v", err)
  45. }
  46. // re-fetch repo
  47. if repo, err = getRepositoryByID(e, repo.ID); err != nil {
  48. return fmt.Errorf("getRepositoryByID: %v", err)
  49. }
  50. repo.DefaultBranch = "master"
  51. if err = updateRepository(e, repo, false); err != nil {
  52. return fmt.Errorf("updateRepository: %v", err)
  53. }
  54. return nil
  55. }
  56. // GenerateRepository generates a repository from a template
  57. func GenerateRepository(ctx DBContext, doer, owner *User, templateRepo *Repository, opts GenerateRepoOptions) (_ *Repository, err error) {
  58. generateRepo := &Repository{
  59. OwnerID: owner.ID,
  60. Owner: owner,
  61. Name: opts.Name,
  62. LowerName: strings.ToLower(opts.Name),
  63. Description: opts.Description,
  64. IsPrivate: opts.Private,
  65. IsEmpty: !opts.GitContent || templateRepo.IsEmpty,
  66. IsFsckEnabled: templateRepo.IsFsckEnabled,
  67. TemplateID: templateRepo.ID,
  68. }
  69. if err = createRepository(ctx.e, doer, owner, generateRepo); err != nil {
  70. return nil, err
  71. }
  72. repoPath := RepoPath(owner.Name, generateRepo.Name)
  73. if err = checkInitRepository(repoPath); err != nil {
  74. return generateRepo, err
  75. }
  76. return generateRepo, nil
  77. }
  78. // GenerateGitContent generates git content from a template repository
  79. func GenerateGitContent(ctx DBContext, templateRepo, generateRepo *Repository) error {
  80. if err := generateRepository(ctx.e, generateRepo, templateRepo); err != nil {
  81. return err
  82. }
  83. if err := generateRepo.updateSize(ctx.e); err != nil {
  84. return fmt.Errorf("failed to update size for repository: %v", err)
  85. }
  86. if err := copyLFS(ctx.e, generateRepo, templateRepo); err != nil {
  87. return fmt.Errorf("failed to copy LFS: %v", err)
  88. }
  89. return nil
  90. }
  91. // GenerateTopics generates topics from a template repository
  92. func GenerateTopics(ctx DBContext, templateRepo, generateRepo *Repository) error {
  93. for _, topic := range templateRepo.Topics {
  94. if _, err := addTopicByNameToRepo(ctx.e, generateRepo.ID, topic); err != nil {
  95. return err
  96. }
  97. }
  98. return nil
  99. }
  100. // GenerateGitHooks generates git hooks from a template repository
  101. func GenerateGitHooks(ctx DBContext, templateRepo, generateRepo *Repository) error {
  102. generateGitRepo, err := git.OpenRepository(generateRepo.repoPath(ctx.e))
  103. if err != nil {
  104. return err
  105. }
  106. defer generateGitRepo.Close()
  107. templateGitRepo, err := git.OpenRepository(templateRepo.repoPath(ctx.e))
  108. if err != nil {
  109. return err
  110. }
  111. defer templateGitRepo.Close()
  112. templateHooks, err := templateGitRepo.Hooks()
  113. if err != nil {
  114. return err
  115. }
  116. for _, templateHook := range templateHooks {
  117. generateHook, err := generateGitRepo.GetHook(templateHook.Name())
  118. if err != nil {
  119. return err
  120. }
  121. generateHook.Content = templateHook.Content
  122. if err := generateHook.Update(); err != nil {
  123. return err
  124. }
  125. }
  126. return nil
  127. }
  128. // GenerateWebhooks generates webhooks from a template repository
  129. func GenerateWebhooks(ctx DBContext, templateRepo, generateRepo *Repository) error {
  130. templateWebhooks, err := GetWebhooksByRepoID(templateRepo.ID)
  131. if err != nil {
  132. return err
  133. }
  134. for _, templateWebhook := range templateWebhooks {
  135. generateWebhook := &Webhook{
  136. RepoID: generateRepo.ID,
  137. URL: templateWebhook.URL,
  138. HTTPMethod: templateWebhook.HTTPMethod,
  139. ContentType: templateWebhook.ContentType,
  140. Secret: templateWebhook.Secret,
  141. HookEvent: templateWebhook.HookEvent,
  142. IsActive: templateWebhook.IsActive,
  143. HookTaskType: templateWebhook.HookTaskType,
  144. OrgID: templateWebhook.OrgID,
  145. Events: templateWebhook.Events,
  146. Meta: templateWebhook.Meta,
  147. }
  148. if err := createWebhook(ctx.e, generateWebhook); err != nil {
  149. return err
  150. }
  151. }
  152. return nil
  153. }
  154. // GenerateAvatar generates the avatar from a template repository
  155. func GenerateAvatar(ctx DBContext, templateRepo, generateRepo *Repository) error {
  156. generateRepo.Avatar = strings.Replace(templateRepo.Avatar, strconv.FormatInt(templateRepo.ID, 10), strconv.FormatInt(generateRepo.ID, 10), 1)
  157. if err := com.Copy(templateRepo.CustomAvatarPath(), generateRepo.CustomAvatarPath()); err != nil {
  158. return err
  159. }
  160. return updateRepositoryCols(ctx.e, generateRepo, "avatar")
  161. }
  162. // GenerateIssueLabels generates issue labels from a template repository
  163. func GenerateIssueLabels(ctx DBContext, templateRepo, generateRepo *Repository) error {
  164. templateLabels, err := getLabelsByRepoID(ctx.e, templateRepo.ID, "")
  165. if err != nil {
  166. return err
  167. }
  168. for _, templateLabel := range templateLabels {
  169. generateLabel := &Label{
  170. RepoID: generateRepo.ID,
  171. Name: templateLabel.Name,
  172. Description: templateLabel.Description,
  173. Color: templateLabel.Color,
  174. }
  175. if err := newLabel(ctx.e, generateLabel); err != nil {
  176. return err
  177. }
  178. }
  179. return nil
  180. }