Inherit submodules from template repository content (#16237)

Fix #10316

---------

Signed-off-by: Steffen Schröter <steffen@vexar.de>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
Steffen Schröter 2025-01-01 03:55:13 +01:00 committed by GitHub
parent 92a2900a2d
commit 57eb9d0b64
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 291 additions and 137 deletions

View file

@ -9,7 +9,6 @@ import (
"context"
"fmt"
"os"
"path"
"path/filepath"
"regexp"
"strconv"
@ -123,7 +122,7 @@ func (gt *GiteaTemplate) Globs() []glob.Glob {
return gt.globs
}
func checkGiteaTemplate(tmpDir string) (*GiteaTemplate, error) {
func readGiteaTemplateFile(tmpDir string) (*GiteaTemplate, error) {
gtPath := filepath.Join(tmpDir, ".gitea", "template")
if _, err := os.Stat(gtPath); os.IsNotExist(err) {
return nil, nil
@ -136,12 +135,55 @@ func checkGiteaTemplate(tmpDir string) (*GiteaTemplate, error) {
return nil, err
}
gt := &GiteaTemplate{
Path: gtPath,
Content: content,
}
return &GiteaTemplate{Path: gtPath, Content: content}, nil
}
return gt, nil
func processGiteaTemplateFile(tmpDir string, templateRepo, generateRepo *repo_model.Repository, giteaTemplateFile *GiteaTemplate) error {
if err := util.Remove(giteaTemplateFile.Path); err != nil {
return fmt.Errorf("remove .giteatemplate: %w", err)
}
if len(giteaTemplateFile.Globs()) == 0 {
return nil // Avoid walking tree if there are no globs
}
tmpDirSlash := strings.TrimSuffix(filepath.ToSlash(tmpDir), "/") + "/"
return filepath.WalkDir(tmpDirSlash, func(path string, d os.DirEntry, walkErr error) error {
if walkErr != nil {
return walkErr
}
if d.IsDir() {
return nil
}
base := strings.TrimPrefix(filepath.ToSlash(path), tmpDirSlash)
for _, g := range giteaTemplateFile.Globs() {
if g.Match(base) {
content, err := os.ReadFile(path)
if err != nil {
return err
}
generatedContent := []byte(generateExpansion(string(content), templateRepo, generateRepo, false))
if err := os.WriteFile(path, generatedContent, 0o644); err != nil {
return err
}
substPath := filepath.FromSlash(filepath.Join(tmpDirSlash, generateExpansion(base, templateRepo, generateRepo, true)))
// Create parent subdirectories if needed or continue silently if it exists
if err = os.MkdirAll(filepath.Dir(substPath), 0o755); err != nil {
return err
}
// Substitute filename variables
if err = os.Rename(path, substPath); err != nil {
return err
}
break
}
}
return nil
}) // end: WalkDir
}
func generateRepoCommit(ctx context.Context, repo, templateRepo, generateRepo *repo_model.Repository, tmpDir string) error {
@ -167,81 +209,43 @@ func generateRepoCommit(ctx context.Context, repo, templateRepo, generateRepo *r
return fmt.Errorf("git clone: %w", err)
}
if err := util.RemoveAll(path.Join(tmpDir, ".git")); err != nil {
// Get active submodules from the template
submodules, err := git.GetTemplateSubmoduleCommits(ctx, tmpDir)
if err != nil {
return fmt.Errorf("GetTemplateSubmoduleCommits: %w", err)
}
if err = util.RemoveAll(filepath.Join(tmpDir, ".git")); err != nil {
return fmt.Errorf("remove git dir: %w", err)
}
// Variable expansion
gt, err := checkGiteaTemplate(tmpDir)
giteaTemplateFile, err := readGiteaTemplateFile(tmpDir)
if err != nil {
return fmt.Errorf("checkGiteaTemplate: %w", err)
return fmt.Errorf("readGiteaTemplateFile: %w", err)
}
if gt != nil {
if err := util.Remove(gt.Path); err != nil {
return fmt.Errorf("remove .giteatemplate: %w", err)
}
// Avoid walking tree if there are no globs
if len(gt.Globs()) > 0 {
tmpDirSlash := strings.TrimSuffix(filepath.ToSlash(tmpDir), "/") + "/"
if err := filepath.WalkDir(tmpDirSlash, func(path string, d os.DirEntry, walkErr error) error {
if walkErr != nil {
return walkErr
}
if d.IsDir() {
return nil
}
base := strings.TrimPrefix(filepath.ToSlash(path), tmpDirSlash)
for _, g := range gt.Globs() {
if g.Match(base) {
content, err := os.ReadFile(path)
if err != nil {
return err
}
if err := os.WriteFile(path,
[]byte(generateExpansion(string(content), templateRepo, generateRepo, false)),
0o644); err != nil {
return err
}
substPath := filepath.FromSlash(filepath.Join(tmpDirSlash,
generateExpansion(base, templateRepo, generateRepo, true)))
// Create parent subdirectories if needed or continue silently if it exists
if err := os.MkdirAll(filepath.Dir(substPath), 0o755); err != nil {
return err
}
// Substitute filename variables
if err := os.Rename(path, substPath); err != nil {
return err
}
break
}
}
return nil
}); err != nil {
return err
}
if giteaTemplateFile != nil {
err = processGiteaTemplateFile(tmpDir, templateRepo, generateRepo, giteaTemplateFile)
if err != nil {
return err
}
}
if err := git.InitRepository(ctx, tmpDir, false, templateRepo.ObjectFormatName); err != nil {
if err = git.InitRepository(ctx, tmpDir, false, templateRepo.ObjectFormatName); err != nil {
return err
}
repoPath := repo.RepoPath()
if stdout, _, err := git.NewCommand(ctx, "remote", "add", "origin").AddDynamicArguments(repoPath).
if stdout, _, err := git.NewCommand(ctx, "remote", "add", "origin").AddDynamicArguments(repo.RepoPath()).
RunStdString(&git.RunOpts{Dir: tmpDir, Env: env}); err != nil {
log.Error("Unable to add %v as remote origin to temporary repo to %s: stdout %s\nError: %v", repo, tmpDir, stdout, err)
return fmt.Errorf("git remote add: %w", err)
}
if err = git.AddTemplateSubmoduleIndexes(ctx, tmpDir, submodules); err != nil {
return fmt.Errorf("failed to add submodules: %v", err)
}
// set default branch based on whether it's specified in the newly generated repo or not
defaultBranch := repo.DefaultBranch
if strings.TrimSpace(defaultBranch) == "" {