From 46fca90cfc5d7059cc2a0b0c392cbee99c9c4ff3 Mon Sep 17 00:00:00 2001
From: Lunny Xiao <xiaolunwen@gmail.com>
Date: Wed, 28 Feb 2024 21:40:36 +0800
Subject: [PATCH] Move generate from module to service (#29465)

(cherry picked from commit b5188cd55c535a588492fb4e153d646ec4f3232a)
---
 modules/repository/init.go                    | 68 ---------------
 routers/api/v1/repo/repo.go                   |  2 +-
 routers/web/repo/repo.go                      |  2 +-
 services/repository/create.go                 |  2 +-
 {modules => services}/repository/generate.go  | 15 ++--
 .../repository/generate_test.go               |  0
 services/repository/init.go                   | 83 +++++++++++++++++++
 services/repository/template.go               |  7 +-
 8 files changed, 97 insertions(+), 82 deletions(-)
 rename {modules => services}/repository/generate.go (94%)
 rename {modules => services}/repository/generate_test.go (100%)
 create mode 100644 services/repository/init.go

diff --git a/modules/repository/init.go b/modules/repository/init.go
index b90b234a73..5f500c5233 100644
--- a/modules/repository/init.go
+++ b/modules/repository/init.go
@@ -6,22 +6,18 @@ package repository
 import (
 	"context"
 	"fmt"
-	"os"
 	"path/filepath"
 	"sort"
 	"strings"
-	"time"
 
 	issues_model "code.gitea.io/gitea/models/issues"
 	repo_model "code.gitea.io/gitea/models/repo"
-	user_model "code.gitea.io/gitea/models/user"
 	"code.gitea.io/gitea/modules/git"
 	"code.gitea.io/gitea/modules/label"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/options"
 	"code.gitea.io/gitea/modules/setting"
 	"code.gitea.io/gitea/modules/util"
-	asymkey_service "code.gitea.io/gitea/services/asymkey"
 )
 
 type OptionFile struct {
@@ -124,70 +120,6 @@ func LoadRepoConfig() error {
 	return nil
 }
 
-// InitRepoCommit temporarily changes with work directory.
-func InitRepoCommit(ctx context.Context, tmpPath string, repo *repo_model.Repository, u *user_model.User, defaultBranch string) (err error) {
-	commitTimeStr := time.Now().Format(time.RFC3339)
-
-	sig := u.NewGitSig()
-	// Because this may call hooks we should pass in the environment
-	env := append(os.Environ(),
-		"GIT_AUTHOR_NAME="+sig.Name,
-		"GIT_AUTHOR_EMAIL="+sig.Email,
-		"GIT_AUTHOR_DATE="+commitTimeStr,
-		"GIT_COMMITTER_DATE="+commitTimeStr,
-	)
-	committerName := sig.Name
-	committerEmail := sig.Email
-
-	if stdout, _, err := git.NewCommand(ctx, "add", "--all").
-		SetDescription(fmt.Sprintf("initRepoCommit (git add): %s", tmpPath)).
-		RunStdString(&git.RunOpts{Dir: tmpPath}); err != nil {
-		log.Error("git add --all failed: Stdout: %s\nError: %v", stdout, err)
-		return fmt.Errorf("git add --all: %w", err)
-	}
-
-	cmd := git.NewCommand(ctx, "commit", "--message=Initial commit").
-		AddOptionFormat("--author='%s <%s>'", sig.Name, sig.Email)
-
-	sign, keyID, signer, _ := asymkey_service.SignInitialCommit(ctx, tmpPath, u)
-	if sign {
-		cmd.AddOptionFormat("-S%s", keyID)
-
-		if repo.GetTrustModel() == repo_model.CommitterTrustModel || repo.GetTrustModel() == repo_model.CollaboratorCommitterTrustModel {
-			// need to set the committer to the KeyID owner
-			committerName = signer.Name
-			committerEmail = signer.Email
-		}
-	} else {
-		cmd.AddArguments("--no-gpg-sign")
-	}
-
-	env = append(env,
-		"GIT_COMMITTER_NAME="+committerName,
-		"GIT_COMMITTER_EMAIL="+committerEmail,
-	)
-
-	if stdout, _, err := cmd.
-		SetDescription(fmt.Sprintf("initRepoCommit (git commit): %s", tmpPath)).
-		RunStdString(&git.RunOpts{Dir: tmpPath, Env: env}); err != nil {
-		log.Error("Failed to commit: %v: Stdout: %s\nError: %v", cmd.String(), stdout, err)
-		return fmt.Errorf("git commit: %w", err)
-	}
-
-	if len(defaultBranch) == 0 {
-		defaultBranch = setting.Repository.DefaultBranch
-	}
-
-	if stdout, _, err := git.NewCommand(ctx, "push", "origin").AddDynamicArguments("HEAD:" + defaultBranch).
-		SetDescription(fmt.Sprintf("initRepoCommit (git push): %s", tmpPath)).
-		RunStdString(&git.RunOpts{Dir: tmpPath, Env: InternalPushingEnvironment(u, repo)}); err != nil {
-		log.Error("Failed to push back to HEAD: Stdout: %s\nError: %v", stdout, err)
-		return fmt.Errorf("git push: %w", err)
-	}
-
-	return nil
-}
-
 func CheckInitRepository(ctx context.Context, owner, name, objectFormatName string) (err error) {
 	// Somehow the directory could exist.
 	repoPath := repo_model.RepoPath(owner, name)
diff --git a/routers/api/v1/repo/repo.go b/routers/api/v1/repo/repo.go
index 5b95cdc0c9..7b39ee950d 100644
--- a/routers/api/v1/repo/repo.go
+++ b/routers/api/v1/repo/repo.go
@@ -358,7 +358,7 @@ func Generate(ctx *context.APIContext) {
 		return
 	}
 
-	opts := repo_module.GenerateRepoOptions{
+	opts := repo_service.GenerateRepoOptions{
 		Name:            form.Name,
 		DefaultBranch:   form.DefaultBranch,
 		Description:     form.Description,
diff --git a/routers/web/repo/repo.go b/routers/web/repo/repo.go
index b2baef84b6..40510d8779 100644
--- a/routers/web/repo/repo.go
+++ b/routers/web/repo/repo.go
@@ -244,7 +244,7 @@ func CreatePost(ctx *context.Context) {
 	var repo *repo_model.Repository
 	var err error
 	if form.RepoTemplate > 0 {
-		opts := repo_module.GenerateRepoOptions{
+		opts := repo_service.GenerateRepoOptions{
 			Name:            form.RepoName,
 			Description:     form.Description,
 			Private:         form.Private,
diff --git a/services/repository/create.go b/services/repository/create.go
index c3b50ae747..9bc0b93eff 100644
--- a/services/repository/create.go
+++ b/services/repository/create.go
@@ -157,7 +157,7 @@ func initRepository(ctx context.Context, repoPath string, u *user_model.User, re
 		}
 
 		// Apply changes and commit.
-		if err = repo_module.InitRepoCommit(ctx, tmpDir, repo, u, opts.DefaultBranch); err != nil {
+		if err = initRepoCommit(ctx, tmpDir, repo, u, opts.DefaultBranch); err != nil {
 			return fmt.Errorf("initRepoCommit: %w", err)
 		}
 	}
diff --git a/modules/repository/generate.go b/services/repository/generate.go
similarity index 94%
rename from modules/repository/generate.go
rename to services/repository/generate.go
index f622383bb5..c444b60b2c 100644
--- a/modules/repository/generate.go
+++ b/services/repository/generate.go
@@ -21,6 +21,7 @@ import (
 	"code.gitea.io/gitea/modules/git"
 	"code.gitea.io/gitea/modules/gitrepo"
 	"code.gitea.io/gitea/modules/log"
+	repo_module "code.gitea.io/gitea/modules/repository"
 	"code.gitea.io/gitea/modules/util"
 
 	"github.com/gobwas/glob"
@@ -242,7 +243,7 @@ func generateRepoCommit(ctx context.Context, repo, templateRepo, generateRepo *r
 		defaultBranch = templateRepo.DefaultBranch
 	}
 
-	return InitRepoCommit(ctx, tmpDir, repo, repo.Owner, defaultBranch)
+	return initRepoCommit(ctx, tmpDir, repo, repo.Owner, defaultBranch)
 }
 
 func generateGitContent(ctx context.Context, repo, templateRepo, generateRepo *repo_model.Repository) (err error) {
@@ -292,7 +293,7 @@ func GenerateGitContent(ctx context.Context, templateRepo, generateRepo *repo_mo
 		return err
 	}
 
-	if err := UpdateRepoSize(ctx, generateRepo); err != nil {
+	if err := repo_module.UpdateRepoSize(ctx, generateRepo); err != nil {
 		return fmt.Errorf("failed to update size for repository: %w", err)
 	}
 
@@ -323,8 +324,8 @@ func (gro GenerateRepoOptions) IsValid() bool {
 		gro.IssueLabels || gro.ProtectedBranch // or other items as they are added
 }
 
-// GenerateRepository generates a repository from a template
-func GenerateRepository(ctx context.Context, doer, owner *user_model.User, templateRepo *repo_model.Repository, opts GenerateRepoOptions) (_ *repo_model.Repository, err error) {
+// generateRepository generates a repository from a template
+func generateRepository(ctx context.Context, doer, owner *user_model.User, templateRepo *repo_model.Repository, opts GenerateRepoOptions) (_ *repo_model.Repository, err error) {
 	generateRepo := &repo_model.Repository{
 		OwnerID:          owner.ID,
 		Owner:            owner,
@@ -341,7 +342,7 @@ func GenerateRepository(ctx context.Context, doer, owner *user_model.User, templ
 		ObjectFormatName: templateRepo.ObjectFormatName,
 	}
 
-	if err = CreateRepositoryByExample(ctx, doer, owner, generateRepo, false, false); err != nil {
+	if err = repo_module.CreateRepositoryByExample(ctx, doer, owner, generateRepo, false, false); err != nil {
 		return nil, err
 	}
 
@@ -358,11 +359,11 @@ func GenerateRepository(ctx context.Context, doer, owner *user_model.User, templ
 		}
 	}
 
-	if err = CheckInitRepository(ctx, owner.Name, generateRepo.Name, generateRepo.ObjectFormatName); err != nil {
+	if err = repo_module.CheckInitRepository(ctx, owner.Name, generateRepo.Name, generateRepo.ObjectFormatName); err != nil {
 		return generateRepo, err
 	}
 
-	if err = CheckDaemonExportOK(ctx, generateRepo); err != nil {
+	if err = repo_module.CheckDaemonExportOK(ctx, generateRepo); err != nil {
 		return generateRepo, fmt.Errorf("checkDaemonExportOK: %w", err)
 	}
 
diff --git a/modules/repository/generate_test.go b/services/repository/generate_test.go
similarity index 100%
rename from modules/repository/generate_test.go
rename to services/repository/generate_test.go
diff --git a/services/repository/init.go b/services/repository/init.go
new file mode 100644
index 0000000000..817fa4abd7
--- /dev/null
+++ b/services/repository/init.go
@@ -0,0 +1,83 @@
+// Copyright 2024 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package repository
+
+import (
+	"context"
+	"fmt"
+	"os"
+	"time"
+
+	repo_model "code.gitea.io/gitea/models/repo"
+	user_model "code.gitea.io/gitea/models/user"
+	"code.gitea.io/gitea/modules/git"
+	"code.gitea.io/gitea/modules/log"
+	repo_module "code.gitea.io/gitea/modules/repository"
+	"code.gitea.io/gitea/modules/setting"
+	asymkey_service "code.gitea.io/gitea/services/asymkey"
+)
+
+// initRepoCommit temporarily changes with work directory.
+func initRepoCommit(ctx context.Context, tmpPath string, repo *repo_model.Repository, u *user_model.User, defaultBranch string) (err error) {
+	commitTimeStr := time.Now().Format(time.RFC3339)
+
+	sig := u.NewGitSig()
+	// Because this may call hooks we should pass in the environment
+	env := append(os.Environ(),
+		"GIT_AUTHOR_NAME="+sig.Name,
+		"GIT_AUTHOR_EMAIL="+sig.Email,
+		"GIT_AUTHOR_DATE="+commitTimeStr,
+		"GIT_COMMITTER_DATE="+commitTimeStr,
+	)
+	committerName := sig.Name
+	committerEmail := sig.Email
+
+	if stdout, _, err := git.NewCommand(ctx, "add", "--all").
+		SetDescription(fmt.Sprintf("initRepoCommit (git add): %s", tmpPath)).
+		RunStdString(&git.RunOpts{Dir: tmpPath}); err != nil {
+		log.Error("git add --all failed: Stdout: %s\nError: %v", stdout, err)
+		return fmt.Errorf("git add --all: %w", err)
+	}
+
+	cmd := git.NewCommand(ctx, "commit", "--message=Initial commit").
+		AddOptionFormat("--author='%s <%s>'", sig.Name, sig.Email)
+
+	sign, keyID, signer, _ := asymkey_service.SignInitialCommit(ctx, tmpPath, u)
+	if sign {
+		cmd.AddOptionFormat("-S%s", keyID)
+
+		if repo.GetTrustModel() == repo_model.CommitterTrustModel || repo.GetTrustModel() == repo_model.CollaboratorCommitterTrustModel {
+			// need to set the committer to the KeyID owner
+			committerName = signer.Name
+			committerEmail = signer.Email
+		}
+	} else {
+		cmd.AddArguments("--no-gpg-sign")
+	}
+
+	env = append(env,
+		"GIT_COMMITTER_NAME="+committerName,
+		"GIT_COMMITTER_EMAIL="+committerEmail,
+	)
+
+	if stdout, _, err := cmd.
+		SetDescription(fmt.Sprintf("initRepoCommit (git commit): %s", tmpPath)).
+		RunStdString(&git.RunOpts{Dir: tmpPath, Env: env}); err != nil {
+		log.Error("Failed to commit: %v: Stdout: %s\nError: %v", cmd.String(), stdout, err)
+		return fmt.Errorf("git commit: %w", err)
+	}
+
+	if len(defaultBranch) == 0 {
+		defaultBranch = setting.Repository.DefaultBranch
+	}
+
+	if stdout, _, err := git.NewCommand(ctx, "push", "origin").AddDynamicArguments("HEAD:" + defaultBranch).
+		SetDescription(fmt.Sprintf("initRepoCommit (git push): %s", tmpPath)).
+		RunStdString(&git.RunOpts{Dir: tmpPath, Env: repo_module.InternalPushingEnvironment(u, repo)}); err != nil {
+		log.Error("Failed to push back to HEAD: Stdout: %s\nError: %v", stdout, err)
+		return fmt.Errorf("git push: %w", err)
+	}
+
+	return nil
+}
diff --git a/services/repository/template.go b/services/repository/template.go
index 06cf05026f..36a680c8e2 100644
--- a/services/repository/template.go
+++ b/services/repository/template.go
@@ -11,7 +11,6 @@ import (
 	issues_model "code.gitea.io/gitea/models/issues"
 	repo_model "code.gitea.io/gitea/models/repo"
 	user_model "code.gitea.io/gitea/models/user"
-	repo_module "code.gitea.io/gitea/modules/repository"
 	notify_service "code.gitea.io/gitea/services/notify"
 )
 
@@ -63,7 +62,7 @@ func GenerateProtectedBranch(ctx context.Context, templateRepo, generateRepo *re
 }
 
 // GenerateRepository generates a repository from a template
-func GenerateRepository(ctx context.Context, doer, owner *user_model.User, templateRepo *repo_model.Repository, opts repo_module.GenerateRepoOptions) (_ *repo_model.Repository, err error) {
+func GenerateRepository(ctx context.Context, doer, owner *user_model.User, templateRepo *repo_model.Repository, opts GenerateRepoOptions) (_ *repo_model.Repository, err error) {
 	if !doer.IsAdmin && !owner.CanCreateRepo() {
 		return nil, repo_model.ErrReachLimitOfRepo{
 			Limit: owner.MaxRepoCreation,
@@ -72,14 +71,14 @@ func GenerateRepository(ctx context.Context, doer, owner *user_model.User, templ
 
 	var generateRepo *repo_model.Repository
 	if err = db.WithTx(ctx, func(ctx context.Context) error {
-		generateRepo, err = repo_module.GenerateRepository(ctx, doer, owner, templateRepo, opts)
+		generateRepo, err = generateRepository(ctx, doer, owner, templateRepo, opts)
 		if err != nil {
 			return err
 		}
 
 		// Git Content
 		if opts.GitContent && !templateRepo.IsEmpty {
-			if err = repo_module.GenerateGitContent(ctx, templateRepo, generateRepo); err != nil {
+			if err = GenerateGitContent(ctx, templateRepo, generateRepo); err != nil {
 				return err
 			}
 		}