diff options
Diffstat (limited to 'modules')
-rw-r--r-- | modules/context/repo.go | 71 | ||||
-rw-r--r-- | modules/markup/markdown/meta.go | 49 | ||||
-rw-r--r-- | modules/structs/issue.go | 17 |
3 files changed, 137 insertions, 0 deletions
diff --git a/modules/context/repo.go b/modules/context/repo.go index 4aac0c05aa..2c77361460 100644 --- a/modules/context/repo.go +++ b/modules/context/repo.go @@ -16,13 +16,27 @@ import ( "code.gitea.io/gitea/modules/cache" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/markup/markdown" "code.gitea.io/gitea/modules/setting" + api "code.gitea.io/gitea/modules/structs" "gitea.com/macaron/macaron" "github.com/editorconfig/editorconfig-core-go/v2" "github.com/unknwon/com" ) +// IssueTemplateDirCandidates issue templates directory +var IssueTemplateDirCandidates = []string{ + "ISSUE_TEMPLATE", + "issue_template", + ".gitea/ISSUE_TEMPLATE", + ".gitea/issue_template", + ".github/ISSUE_TEMPLATE", + ".github/issue_template", + ".gitlab/ISSUE_TEMPLATE", + ".gitlab/issue_template", +} + // PullRequest contains informations to make a pull request type PullRequest struct { BaseRepo *models.Repository @@ -821,3 +835,60 @@ func UnitTypes() macaron.Handler { ctx.Data["UnitTypeProjects"] = models.UnitTypeProjects } } + +// IssueTemplatesFromDefaultBranch checks for issue templates in the repo's default branch +func (ctx *Context) IssueTemplatesFromDefaultBranch() []api.IssueTemplate { + var issueTemplates []api.IssueTemplate + if ctx.Repo.Commit == nil { + var err error + ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetBranchCommit(ctx.Repo.Repository.DefaultBranch) + if err != nil { + return issueTemplates + } + } + + for _, dirName := range IssueTemplateDirCandidates { + tree, err := ctx.Repo.Commit.SubTree(dirName) + if err != nil { + continue + } + entries, err := tree.ListEntries() + if err != nil { + return issueTemplates + } + for _, entry := range entries { + if strings.HasSuffix(entry.Name(), ".md") { + if entry.Blob().Size() >= setting.UI.MaxDisplayFileSize { + log.Debug("Issue template is too large: %s", entry.Name()) + continue + } + r, err := entry.Blob().DataAsync() + if err != nil { + log.Debug("DataAsync: %v", err) + continue + } + defer r.Close() + data, err := ioutil.ReadAll(r) + if err != nil { + log.Debug("ReadAll: %v", err) + continue + } + var it api.IssueTemplate + content, err := markdown.ExtractMetadata(string(data), &it) + if err != nil { + log.Debug("ExtractMetadata: %v", err) + continue + } + it.Content = content + it.FileName = entry.Name() + if it.Valid() { + issueTemplates = append(issueTemplates, it) + } + } + } + if len(issueTemplates) > 0 { + return issueTemplates + } + } + return issueTemplates +} diff --git a/modules/markup/markdown/meta.go b/modules/markup/markdown/meta.go new file mode 100644 index 0000000000..ca95e4d26a --- /dev/null +++ b/modules/markup/markdown/meta.go @@ -0,0 +1,49 @@ +// Copyright 2020 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 markdown + +import ( + "errors" + "strings" + + "gopkg.in/yaml.v2" +) + +func isYAMLSeparator(line string) bool { + line = strings.TrimSpace(line) + for i := 0; i < len(line); i++ { + if line[i] != '-' { + return false + } + } + return len(line) > 2 +} + +// ExtractMetadata consumes a markdown file, parses YAML frontmatter, +// and returns the frontmatter metadata separated from the markdown content +func ExtractMetadata(contents string, out interface{}) (string, error) { + var front, body []string + var seps int + lines := strings.Split(contents, "\n") + for idx, line := range lines { + if seps == 2 { + front, body = lines[:idx], lines[idx:] + break + } + if isYAMLSeparator(line) { + seps++ + continue + } + } + + if len(front) == 0 && len(body) == 0 { + return "", errors.New("could not determine metadata") + } + + if err := yaml.Unmarshal([]byte(strings.Join(front, "\n")), out); err != nil { + return "", err + } + return strings.Join(body, "\n"), nil +} diff --git a/modules/structs/issue.go b/modules/structs/issue.go index dc633dedce..54b0f31d8a 100644 --- a/modules/structs/issue.go +++ b/modules/structs/issue.go @@ -5,6 +5,7 @@ package structs import ( + "strings" "time" ) @@ -119,3 +120,19 @@ type IssueDeadline struct { // swagger:strfmt date-time Deadline *time.Time `json:"due_date"` } + +// IssueTemplate represents an issue template for a repository +// swagger:model +type IssueTemplate struct { + Name string `json:"name" yaml:"name"` + Title string `json:"title" yaml:"title"` + About string `json:"about" yaml:"about"` + Labels []string `json:"labels" yaml:"labels"` + Content string `json:"content" yaml:"-"` + FileName string `json:"file_name" yaml:"-"` +} + +// Valid checks whether an IssueTemplate is considered valid, e.g. at least name and about +func (it IssueTemplate) Valid() bool { + return strings.TrimSpace(it.Name) != "" && strings.TrimSpace(it.About) != "" +} |