mirror of
				https://codeberg.org/forgejo/forgejo.git
				synced 2025-10-27 12:31:02 +00:00 
			
		
		
		
	* feat: extend issue template for yaml * feat: support yaml template * feat: render form to markdown * feat: support yaml template for pr * chore: rename to Fields * feat: template unmarshal * feat: split template * feat: render to markdown * feat: use full name as template file name * chore: remove useless file * feat: use dropdown of fomantic ui * feat: update input style * docs: more comments * fix: render text without render * chore: fix lint error * fix: support use description as about in markdown * fix: add field class in form * chore: generate swagger * feat: validate template * feat: support is_nummber and regex * test: fix broken unit tests * fix: ignore empty body of md template * fix: make multiple easymde editors work in one page * feat: better UI * fix: js error in pr form * chore: generate swagger * feat: support regex validation * chore: generate swagger * fix: refresh each markdown editor * chore: give up required validation * fix: correct issue template candidates * fix: correct checkboxes style * chore: ignore .hugo_build.lock in docs * docs: separate out a new doc for merge templates * docs: introduce syntax of yaml template * feat: show a alert for invalid templates * test: add case for a valid template * fix: correct attributes of required checkbox * fix: add class not-under-easymde for dropzone * fix: use more back-quotes * chore: remove translation in zh-CN * fix EasyMDE statusbar margin * fix: remove repeated blocks * fix: reuse regex for quotes Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
		
			
				
	
	
		
			125 lines
		
	
	
	
		
			3.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			125 lines
		
	
	
	
		
			3.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright 2022 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 template
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"io"
 | |
| 	"path/filepath"
 | |
| 	"strconv"
 | |
| 
 | |
| 	"code.gitea.io/gitea/modules/git"
 | |
| 	"code.gitea.io/gitea/modules/markup/markdown"
 | |
| 	"code.gitea.io/gitea/modules/setting"
 | |
| 	api "code.gitea.io/gitea/modules/structs"
 | |
| 
 | |
| 	"gopkg.in/yaml.v2"
 | |
| )
 | |
| 
 | |
| // CouldBe indicates a file with the filename could be a template,
 | |
| // it is a low cost check before further processing.
 | |
| func CouldBe(filename string) bool {
 | |
| 	it := &api.IssueTemplate{
 | |
| 		FileName: filename,
 | |
| 	}
 | |
| 	return it.Type() != ""
 | |
| }
 | |
| 
 | |
| // Unmarshal parses out a valid template from the content
 | |
| func Unmarshal(filename string, content []byte) (*api.IssueTemplate, error) {
 | |
| 	it, err := unmarshal(filename, content)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	if err := Validate(it); err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	return it, nil
 | |
| }
 | |
| 
 | |
| // UnmarshalFromEntry parses out a valid template from the blob in entry
 | |
| func UnmarshalFromEntry(entry *git.TreeEntry, dir string) (*api.IssueTemplate, error) {
 | |
| 	return unmarshalFromEntry(entry, filepath.Join(dir, entry.Name()))
 | |
| }
 | |
| 
 | |
| // UnmarshalFromCommit parses out a valid template from the commit
 | |
| func UnmarshalFromCommit(commit *git.Commit, filename string) (*api.IssueTemplate, error) {
 | |
| 	entry, err := commit.GetTreeEntryByPath(filename)
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("get entry for %q: %w", filename, err)
 | |
| 	}
 | |
| 	return unmarshalFromEntry(entry, filename)
 | |
| }
 | |
| 
 | |
| // UnmarshalFromRepo parses out a valid template from the head commit of the branch
 | |
| func UnmarshalFromRepo(repo *git.Repository, branch, filename string) (*api.IssueTemplate, error) {
 | |
| 	commit, err := repo.GetBranchCommit(branch)
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("get commit on branch %q: %w", branch, err)
 | |
| 	}
 | |
| 
 | |
| 	return UnmarshalFromCommit(commit, filename)
 | |
| }
 | |
| 
 | |
| func unmarshalFromEntry(entry *git.TreeEntry, filename string) (*api.IssueTemplate, error) {
 | |
| 	if size := entry.Blob().Size(); size > setting.UI.MaxDisplayFileSize {
 | |
| 		return nil, fmt.Errorf("too large: %v > MaxDisplayFileSize", size)
 | |
| 	}
 | |
| 
 | |
| 	r, err := entry.Blob().DataAsync()
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("data async: %w", err)
 | |
| 	}
 | |
| 	defer r.Close()
 | |
| 
 | |
| 	content, err := io.ReadAll(r)
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("read all: %w", err)
 | |
| 	}
 | |
| 
 | |
| 	return Unmarshal(filename, content)
 | |
| }
 | |
| 
 | |
| func unmarshal(filename string, content []byte) (*api.IssueTemplate, error) {
 | |
| 	it := &api.IssueTemplate{
 | |
| 		FileName: filename,
 | |
| 	}
 | |
| 
 | |
| 	// Compatible with treating description as about
 | |
| 	compatibleTemplate := &struct {
 | |
| 		About string `yaml:"description"`
 | |
| 	}{}
 | |
| 
 | |
| 	if typ := it.Type(); typ == api.IssueTemplateTypeMarkdown {
 | |
| 		templateBody, err := markdown.ExtractMetadata(string(content), it)
 | |
| 		if err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 		it.Content = templateBody
 | |
| 		if it.About == "" {
 | |
| 			if _, err := markdown.ExtractMetadata(string(content), compatibleTemplate); err == nil && compatibleTemplate.About != "" {
 | |
| 				it.About = compatibleTemplate.About
 | |
| 			}
 | |
| 		}
 | |
| 	} else if typ == api.IssueTemplateTypeYaml {
 | |
| 		if err := yaml.Unmarshal(content, it); err != nil {
 | |
| 			return nil, fmt.Errorf("yaml unmarshal: %w", err)
 | |
| 		}
 | |
| 		if it.About == "" {
 | |
| 			if err := yaml.Unmarshal(content, compatibleTemplate); err == nil && compatibleTemplate.About != "" {
 | |
| 				it.About = compatibleTemplate.About
 | |
| 			}
 | |
| 		}
 | |
| 		for i, v := range it.Fields {
 | |
| 			if v.ID == "" {
 | |
| 				v.ID = strconv.Itoa(i)
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return it, nil
 | |
| }
 |