mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-11-04 12:53:43 +01:00 
			
		
		
		
	Variable expansion in repository templates (#9163)
* Start expansion Signed-off-by: jolheiser <john.olheiser@gmail.com> * _template rather than .template Signed-off-by: jolheiser <john.olheiser@gmail.com> * Use ioutil Signed-off-by: jolheiser <john.olheiser@gmail.com> * Add descriptions to mapping * Start globbing Signed-off-by: jolheiser <john.olheiser@gmail.com> * Tune globbing Signed-off-by: jolheiser <john.olheiser@gmail.com> * Re-arrange imports Signed-off-by: jolheiser <john.olheiser@gmail.com> * Don't expand git hooks Signed-off-by: jolheiser <john.olheiser@gmail.com> * Add glob tests for .giteatemplate Signed-off-by: jolheiser <john.olheiser@gmail.com> * Parse globs separately so they can be tested more easily Signed-off-by: jolheiser <john.olheiser@gmail.com> * Change template location and add docs Signed-off-by: jolheiser <john.olheiser@gmail.com> * nit Signed-off-by: jolheiser <john.olheiser@gmail.com> * Update docs/content/doc/features/gitea-directory.md Co-Authored-By: guillep2k <18600385+guillep2k@users.noreply.github.com> * Update docs/content/doc/features/gitea-directory.md Co-Authored-By: guillep2k <18600385+guillep2k@users.noreply.github.com> * Add upper-lower case match Signed-off-by: jolheiser <john.olheiser@gmail.com> * Nits Signed-off-by: jolheiser <john.olheiser@gmail.com> * Update models/repo_generate.go Co-Authored-By: guillep2k <18600385+guillep2k@users.noreply.github.com>
This commit is contained in:
		
							parent
							
								
									c9d50bcab5
								
							
						
					
					
						commit
						15a5c10d33
					
				
							
								
								
									
										56
									
								
								docs/content/doc/features/gitea-directory.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								docs/content/doc/features/gitea-directory.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,56 @@
 | 
				
			|||||||
 | 
					---
 | 
				
			||||||
 | 
					date: "2019-11-28:00:00+02:00"
 | 
				
			||||||
 | 
					title: "The .gitea Directory"
 | 
				
			||||||
 | 
					slug: "gitea-directory"
 | 
				
			||||||
 | 
					weight: 40
 | 
				
			||||||
 | 
					toc: true
 | 
				
			||||||
 | 
					draft: false
 | 
				
			||||||
 | 
					menu:
 | 
				
			||||||
 | 
					  sidebar:
 | 
				
			||||||
 | 
					    parent: "features"
 | 
				
			||||||
 | 
					    name: "The .gitea Directory"
 | 
				
			||||||
 | 
					    weight: 50
 | 
				
			||||||
 | 
					    identifier: "gitea-directory"
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# The .gitea directory
 | 
				
			||||||
 | 
					Gitea repositories can include a `.gitea` directory at their base which will store settings/configurations for certain features.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Templates
 | 
				
			||||||
 | 
					Gitea includes template repositories, and one feature implemented with them is auto-expansion of specific variables within your template files.  
 | 
				
			||||||
 | 
					To tell Gitea which files to expand, you must include a `template` file inside the `.gitea` directory of the template repository.  
 | 
				
			||||||
 | 
					Gitea uses [gobwas/glob](https://github.com/gobwas/glob) for its glob syntax. It closely resembles a traditional `.gitignore`, however there may be slight differences.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Example `.gitea/template` file  
 | 
				
			||||||
 | 
					All paths are relative to the base of the repository
 | 
				
			||||||
 | 
					```gitignore
 | 
				
			||||||
 | 
					# All .go files, anywhere in the repository
 | 
				
			||||||
 | 
					**.go
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# All text files in the text directory
 | 
				
			||||||
 | 
					text/*.txt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# A specific file
 | 
				
			||||||
 | 
					a/b/c/d.json
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Batch files in both upper or lower case can be matched
 | 
				
			||||||
 | 
					**.[bB][aA][tT]
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					**NOTE:** The `template` file will be removed from the `.gitea` directory when a repository is generated from the template.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Variable Expansion
 | 
				
			||||||
 | 
					In any file matched by the above globs, certain variables will be expanded.  
 | 
				
			||||||
 | 
					All variables must be of the form `$VAR` or `${VAR}`. To escape an expansion, use a double `$$`, such as `$$VAR` or `$${VAR}`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					| Variable             | Expands To                                          |
 | 
				
			||||||
 | 
					|----------------------|-----------------------------------------------------|
 | 
				
			||||||
 | 
					| REPO_NAME            | The name of the generated repository                |
 | 
				
			||||||
 | 
					| TEMPLATE_NAME        | The name of the template repository                 |
 | 
				
			||||||
 | 
					| REPO_DESCRIPTION     | The description of the generated repository         |
 | 
				
			||||||
 | 
					| TEMPLATE_DESCRIPTION | The description of the template repository          |
 | 
				
			||||||
 | 
					| REPO_LINK            | The URL to the generated repository                 |
 | 
				
			||||||
 | 
					| TEMPLATE_LINK        | The URL to the template repository                  |
 | 
				
			||||||
 | 
					| REPO_HTTPS_URL       | The HTTP(S) clone link for the generated repository |
 | 
				
			||||||
 | 
					| TEMPLATE_HTTPS_URL   | The HTTP(S) clone link for the template repository  |
 | 
				
			||||||
 | 
					| REPO_SSH_URL         | The SSH clone link for the generated repository     |
 | 
				
			||||||
 | 
					| TEMPLATE_SSH_URL     | The SSH clone link for the template repository      |
 | 
				
			||||||
@ -1361,54 +1361,6 @@ func prepareRepoCommit(e Engine, repo *Repository, tmpDir, repoPath string, opts
 | 
				
			|||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func generateRepoCommit(e Engine, repo, templateRepo *Repository, tmpDir string) error {
 | 
					 | 
				
			||||||
	commitTimeStr := time.Now().Format(time.RFC3339)
 | 
					 | 
				
			||||||
	authorSig := repo.Owner.NewGitSig()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Because this may call hooks we should pass in the environment
 | 
					 | 
				
			||||||
	env := append(os.Environ(),
 | 
					 | 
				
			||||||
		"GIT_AUTHOR_NAME="+authorSig.Name,
 | 
					 | 
				
			||||||
		"GIT_AUTHOR_EMAIL="+authorSig.Email,
 | 
					 | 
				
			||||||
		"GIT_AUTHOR_DATE="+commitTimeStr,
 | 
					 | 
				
			||||||
		"GIT_COMMITTER_NAME="+authorSig.Name,
 | 
					 | 
				
			||||||
		"GIT_COMMITTER_EMAIL="+authorSig.Email,
 | 
					 | 
				
			||||||
		"GIT_COMMITTER_DATE="+commitTimeStr,
 | 
					 | 
				
			||||||
	)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Clone to temporary path and do the init commit.
 | 
					 | 
				
			||||||
	templateRepoPath := templateRepo.repoPath(e)
 | 
					 | 
				
			||||||
	_, stderr, err := process.GetManager().ExecDirEnv(
 | 
					 | 
				
			||||||
		-1, "",
 | 
					 | 
				
			||||||
		fmt.Sprintf("generateRepoCommit(git clone): %s", templateRepoPath),
 | 
					 | 
				
			||||||
		env,
 | 
					 | 
				
			||||||
		git.GitExecutable, "clone", "--depth", "1", templateRepoPath, tmpDir,
 | 
					 | 
				
			||||||
	)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return fmt.Errorf("git clone: %v - %s", err, stderr)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if err := os.RemoveAll(path.Join(tmpDir, ".git")); err != nil {
 | 
					 | 
				
			||||||
		return fmt.Errorf("remove git dir: %v", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if err := git.InitRepository(tmpDir, false); err != nil {
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	repoPath := repo.repoPath(e)
 | 
					 | 
				
			||||||
	_, stderr, err = process.GetManager().ExecDirEnv(
 | 
					 | 
				
			||||||
		-1, tmpDir,
 | 
					 | 
				
			||||||
		fmt.Sprintf("generateRepoCommit(git remote add): %s", repoPath),
 | 
					 | 
				
			||||||
		env,
 | 
					 | 
				
			||||||
		git.GitExecutable, "remote", "add", "origin", repoPath,
 | 
					 | 
				
			||||||
	)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return fmt.Errorf("git remote add: %v - %s", err, stderr)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return initRepoCommit(tmpDir, repo.Owner)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func checkInitRepository(repoPath string) (err error) {
 | 
					func checkInitRepository(repoPath string) (err error) {
 | 
				
			||||||
	// Somehow the directory could exist.
 | 
						// Somehow the directory could exist.
 | 
				
			||||||
	if com.IsExist(repoPath) {
 | 
						if com.IsExist(repoPath) {
 | 
				
			||||||
 | 
				
			|||||||
@ -6,7 +6,9 @@ package models
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
 | 
						"io/ioutil"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
 | 
						"path"
 | 
				
			||||||
	"path/filepath"
 | 
						"path/filepath"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
@ -14,7 +16,10 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	"code.gitea.io/gitea/modules/git"
 | 
						"code.gitea.io/gitea/modules/git"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/log"
 | 
						"code.gitea.io/gitea/modules/log"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/process"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/util"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/gobwas/glob"
 | 
				
			||||||
	"github.com/unknwon/com"
 | 
						"github.com/unknwon/com"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -36,8 +41,148 @@ func (gro GenerateRepoOptions) IsValid() bool {
 | 
				
			|||||||
	return gro.GitContent || gro.Topics || gro.GitHooks || gro.Webhooks || gro.Avatar || gro.IssueLabels // or other items as they are added
 | 
						return gro.GitContent || gro.Topics || gro.GitHooks || gro.Webhooks || gro.Avatar || gro.IssueLabels // or other items as they are added
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GiteaTemplate holds information about a .gitea/template file
 | 
				
			||||||
 | 
					type GiteaTemplate struct {
 | 
				
			||||||
 | 
						Path    string
 | 
				
			||||||
 | 
						Content []byte
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						globs []glob.Glob
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Globs parses the .gitea/template globs or returns them if they were already parsed
 | 
				
			||||||
 | 
					func (gt GiteaTemplate) Globs() []glob.Glob {
 | 
				
			||||||
 | 
						if gt.globs != nil {
 | 
				
			||||||
 | 
							return gt.globs
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gt.globs = make([]glob.Glob, 0)
 | 
				
			||||||
 | 
						lines := strings.Split(string(util.NormalizeEOL(gt.Content)), "\n")
 | 
				
			||||||
 | 
						for _, line := range lines {
 | 
				
			||||||
 | 
							line = strings.TrimSpace(line)
 | 
				
			||||||
 | 
							if line == "" || strings.HasPrefix(line, "#") {
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							g, err := glob.Compile(line, '/')
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								log.Info("Invalid glob expression '%s' (skipped): %v", line, err)
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							gt.globs = append(gt.globs, g)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return gt.globs
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func checkGiteaTemplate(tmpDir string) (*GiteaTemplate, error) {
 | 
				
			||||||
 | 
						gtPath := filepath.Join(tmpDir, ".gitea", "template")
 | 
				
			||||||
 | 
						if _, err := os.Stat(gtPath); os.IsNotExist(err) {
 | 
				
			||||||
 | 
							return nil, nil
 | 
				
			||||||
 | 
						} else if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						content, err := ioutil.ReadFile(gtPath)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gt := &GiteaTemplate{
 | 
				
			||||||
 | 
							Path:    gtPath,
 | 
				
			||||||
 | 
							Content: content,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return gt, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func generateRepoCommit(e Engine, repo, templateRepo, generateRepo *Repository, tmpDir string) error {
 | 
				
			||||||
 | 
						commitTimeStr := time.Now().Format(time.RFC3339)
 | 
				
			||||||
 | 
						authorSig := repo.Owner.NewGitSig()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Because this may call hooks we should pass in the environment
 | 
				
			||||||
 | 
						env := append(os.Environ(),
 | 
				
			||||||
 | 
							"GIT_AUTHOR_NAME="+authorSig.Name,
 | 
				
			||||||
 | 
							"GIT_AUTHOR_EMAIL="+authorSig.Email,
 | 
				
			||||||
 | 
							"GIT_AUTHOR_DATE="+commitTimeStr,
 | 
				
			||||||
 | 
							"GIT_COMMITTER_NAME="+authorSig.Name,
 | 
				
			||||||
 | 
							"GIT_COMMITTER_EMAIL="+authorSig.Email,
 | 
				
			||||||
 | 
							"GIT_COMMITTER_DATE="+commitTimeStr,
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Clone to temporary path and do the init commit.
 | 
				
			||||||
 | 
						templateRepoPath := templateRepo.repoPath(e)
 | 
				
			||||||
 | 
						if err := git.Clone(templateRepoPath, tmpDir, git.CloneRepoOptions{
 | 
				
			||||||
 | 
							Depth: 1,
 | 
				
			||||||
 | 
						}); err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("git clone: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err := os.RemoveAll(path.Join(tmpDir, ".git")); err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("remove git dir: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Variable expansion
 | 
				
			||||||
 | 
						gt, err := checkGiteaTemplate(tmpDir)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("checkGiteaTemplate: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err := os.Remove(gt.Path); err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("remove .giteatemplate: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Avoid walking tree if there are no globs
 | 
				
			||||||
 | 
						if len(gt.Globs()) > 0 {
 | 
				
			||||||
 | 
							tmpDirSlash := strings.TrimSuffix(filepath.ToSlash(tmpDir), "/") + "/"
 | 
				
			||||||
 | 
							if err := filepath.Walk(tmpDirSlash, func(path string, info os.FileInfo, walkErr error) error {
 | 
				
			||||||
 | 
								if walkErr != nil {
 | 
				
			||||||
 | 
									return walkErr
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if info.IsDir() {
 | 
				
			||||||
 | 
									return nil
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								base := strings.TrimPrefix(filepath.ToSlash(path), tmpDirSlash)
 | 
				
			||||||
 | 
								for _, g := range gt.Globs() {
 | 
				
			||||||
 | 
									if g.Match(base) {
 | 
				
			||||||
 | 
										content, err := ioutil.ReadFile(path)
 | 
				
			||||||
 | 
										if err != nil {
 | 
				
			||||||
 | 
											return err
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										if err := ioutil.WriteFile(path,
 | 
				
			||||||
 | 
											[]byte(generateExpansion(string(content), templateRepo, generateRepo)),
 | 
				
			||||||
 | 
											0644); err != nil {
 | 
				
			||||||
 | 
											return err
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										break
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return nil
 | 
				
			||||||
 | 
							}); err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err := git.InitRepository(tmpDir, false); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						repoPath := repo.repoPath(e)
 | 
				
			||||||
 | 
						_, stderr, err := process.GetManager().ExecDirEnv(
 | 
				
			||||||
 | 
							-1, tmpDir,
 | 
				
			||||||
 | 
							fmt.Sprintf("generateRepoCommit(git remote add): %s", repoPath),
 | 
				
			||||||
 | 
							env,
 | 
				
			||||||
 | 
							git.GitExecutable, "remote", "add", "origin", repoPath,
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("git remote add: %v - %s", err, stderr)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return initRepoCommit(tmpDir, repo.Owner)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// generateRepository initializes repository from template
 | 
					// generateRepository initializes repository from template
 | 
				
			||||||
func generateRepository(e Engine, repo, templateRepo *Repository) (err error) {
 | 
					func generateRepository(e Engine, repo, templateRepo, generateRepo *Repository) (err error) {
 | 
				
			||||||
	tmpDir := filepath.Join(os.TempDir(), "gitea-"+repo.Name+"-"+com.ToStr(time.Now().Nanosecond()))
 | 
						tmpDir := filepath.Join(os.TempDir(), "gitea-"+repo.Name+"-"+com.ToStr(time.Now().Nanosecond()))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := os.MkdirAll(tmpDir, os.ModePerm); err != nil {
 | 
						if err := os.MkdirAll(tmpDir, os.ModePerm); err != nil {
 | 
				
			||||||
@ -50,7 +195,7 @@ func generateRepository(e Engine, repo, templateRepo *Repository) (err error) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}()
 | 
						}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err = generateRepoCommit(e, repo, templateRepo, tmpDir); err != nil {
 | 
						if err = generateRepoCommit(e, repo, templateRepo, generateRepo, tmpDir); err != nil {
 | 
				
			||||||
		return fmt.Errorf("generateRepoCommit: %v", err)
 | 
							return fmt.Errorf("generateRepoCommit: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -95,7 +240,7 @@ func GenerateRepository(ctx DBContext, doer, owner *User, templateRepo *Reposito
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// GenerateGitContent generates git content from a template repository
 | 
					// GenerateGitContent generates git content from a template repository
 | 
				
			||||||
func GenerateGitContent(ctx DBContext, templateRepo, generateRepo *Repository) error {
 | 
					func GenerateGitContent(ctx DBContext, templateRepo, generateRepo *Repository) error {
 | 
				
			||||||
	if err := generateRepository(ctx.e, generateRepo, templateRepo); err != nil {
 | 
						if err := generateRepository(ctx.e, generateRepo, templateRepo, generateRepo); err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -210,3 +355,36 @@ func GenerateIssueLabels(ctx DBContext, templateRepo, generateRepo *Repository)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func generateExpansion(src string, templateRepo, generateRepo *Repository) string {
 | 
				
			||||||
 | 
						return os.Expand(src, func(key string) string {
 | 
				
			||||||
 | 
							switch key {
 | 
				
			||||||
 | 
							case "REPO_NAME":
 | 
				
			||||||
 | 
								return generateRepo.Name
 | 
				
			||||||
 | 
							case "TEMPLATE_NAME":
 | 
				
			||||||
 | 
								return templateRepo.Name
 | 
				
			||||||
 | 
							case "REPO_DESCRIPTION":
 | 
				
			||||||
 | 
								return generateRepo.Description
 | 
				
			||||||
 | 
							case "TEMPLATE_DESCRIPTION":
 | 
				
			||||||
 | 
								return templateRepo.Description
 | 
				
			||||||
 | 
							case "REPO_OWNER":
 | 
				
			||||||
 | 
								return generateRepo.MustOwnerName()
 | 
				
			||||||
 | 
							case "TEMPLATE_OWNER":
 | 
				
			||||||
 | 
								return templateRepo.MustOwnerName()
 | 
				
			||||||
 | 
							case "REPO_LINK":
 | 
				
			||||||
 | 
								return generateRepo.Link()
 | 
				
			||||||
 | 
							case "TEMPLATE_LINK":
 | 
				
			||||||
 | 
								return templateRepo.Link()
 | 
				
			||||||
 | 
							case "REPO_HTTPS_URL":
 | 
				
			||||||
 | 
								return generateRepo.CloneLink().HTTPS
 | 
				
			||||||
 | 
							case "TEMPLATE_HTTPS_URL":
 | 
				
			||||||
 | 
								return templateRepo.CloneLink().HTTPS
 | 
				
			||||||
 | 
							case "REPO_SSH_URL":
 | 
				
			||||||
 | 
								return generateRepo.CloneLink().SSH
 | 
				
			||||||
 | 
							case "TEMPLATE_SSH_URL":
 | 
				
			||||||
 | 
								return templateRepo.CloneLink().SSH
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								return key
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										57
									
								
								models/repo_generate_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								models/repo_generate_test.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,57 @@
 | 
				
			|||||||
 | 
					// Copyright 2019 The Gitea Authors. All rights reserved.
 | 
				
			||||||
 | 
					// Use of this source code is governed by a MIT-style
 | 
				
			||||||
 | 
					// license that can be found in the LICENSE file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/stretchr/testify/assert"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var giteaTemplate = []byte(`
 | 
				
			||||||
 | 
					# Header
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# All .go files
 | 
				
			||||||
 | 
					**.go
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# All text files in /text/
 | 
				
			||||||
 | 
					text/*.txt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# All files in modules folders
 | 
				
			||||||
 | 
					**/modules/*
 | 
				
			||||||
 | 
					`)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestGiteaTemplate(t *testing.T) {
 | 
				
			||||||
 | 
						gt := GiteaTemplate{Content: giteaTemplate}
 | 
				
			||||||
 | 
						assert.Equal(t, len(gt.Globs()), 3)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tt := []struct {
 | 
				
			||||||
 | 
							Path  string
 | 
				
			||||||
 | 
							Match bool
 | 
				
			||||||
 | 
						}{
 | 
				
			||||||
 | 
							{Path: "main.go", Match: true},
 | 
				
			||||||
 | 
							{Path: "a/b/c/d/e.go", Match: true},
 | 
				
			||||||
 | 
							{Path: "main.txt", Match: false},
 | 
				
			||||||
 | 
							{Path: "a/b.txt", Match: false},
 | 
				
			||||||
 | 
							{Path: "text/a.txt", Match: true},
 | 
				
			||||||
 | 
							{Path: "text/b.txt", Match: true},
 | 
				
			||||||
 | 
							{Path: "text/c.json", Match: false},
 | 
				
			||||||
 | 
							{Path: "a/b/c/modules/README.md", Match: true},
 | 
				
			||||||
 | 
							{Path: "a/b/c/modules/d/README.md", Match: false},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, tc := range tt {
 | 
				
			||||||
 | 
							t.Run(tc.Path, func(t *testing.T) {
 | 
				
			||||||
 | 
								match := false
 | 
				
			||||||
 | 
								for _, g := range gt.Globs() {
 | 
				
			||||||
 | 
									if g.Match(tc.Path) {
 | 
				
			||||||
 | 
										match = true
 | 
				
			||||||
 | 
										break
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								assert.Equal(t, tc.Match, match)
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -161,6 +161,7 @@ type CloneRepoOptions struct {
 | 
				
			|||||||
	Branch     string
 | 
						Branch     string
 | 
				
			||||||
	Shared     bool
 | 
						Shared     bool
 | 
				
			||||||
	NoCheckout bool
 | 
						NoCheckout bool
 | 
				
			||||||
 | 
						Depth      int
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Clone clones original repository to target path.
 | 
					// Clone clones original repository to target path.
 | 
				
			||||||
@ -193,6 +194,9 @@ func CloneWithArgs(from, to string, args []string, opts CloneRepoOptions) (err e
 | 
				
			|||||||
	if opts.NoCheckout {
 | 
						if opts.NoCheckout {
 | 
				
			||||||
		cmd.AddArguments("--no-checkout")
 | 
							cmd.AddArguments("--no-checkout")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if opts.Depth > 0 {
 | 
				
			||||||
 | 
							cmd.AddArguments("--depth", strconv.Itoa(opts.Depth))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if len(opts.Branch) > 0 {
 | 
						if len(opts.Branch) > 0 {
 | 
				
			||||||
		cmd.AddArguments("-b", opts.Branch)
 | 
							cmd.AddArguments("-b", opts.Branch)
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user