Issue templates directory (#11450)
* Issue templates Signed-off-by: jolheiser <john.olheiser@gmail.com> * Add some comments, appease the linter Signed-off-by: jolheiser <john.olheiser@gmail.com> * Add docs and re-use dir candidates Signed-off-by: jolheiser <john.olheiser@gmail.com> * Add default labels to issue templates Signed-off-by: jolheiser <john.olheiser@gmail.com> * Generate swagger Signed-off-by: jolheiser <john.olheiser@gmail.com> * Suggested changes Signed-off-by: jolheiser <john.olheiser@gmail.com> * Update issue.go * Suggestions Signed-off-by: jolheiser <john.olheiser@gmail.com> * Extract metadata from legacy if possible Signed-off-by: jolheiser <john.olheiser@gmail.com> Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com> Co-authored-by: techknowlogick <techknowlogick@gitea.io>
This commit is contained in:
parent
dd1a651b58
commit
26c4a049da
18 changed files with 381 additions and 17 deletions
|
@ -866,6 +866,7 @@ func RegisterRoutes(m *macaron.Macaron) {
|
|||
Delete(reqToken(), repo.DeleteTopic)
|
||||
}, reqAdmin())
|
||||
}, reqAnyRepoReader())
|
||||
m.Get("/issue_templates", context.ReferencesGitRepo(false), repo.GetIssueTemplates)
|
||||
m.Get("/languages", reqRepoReader(models.UnitTypeCode), repo.GetLanguages)
|
||||
}, repoAssignment())
|
||||
})
|
||||
|
|
|
@ -812,3 +812,28 @@ func Delete(ctx *context.APIContext) {
|
|||
log.Trace("Repository deleted: %s/%s", owner.Name, repo.Name)
|
||||
ctx.Status(http.StatusNoContent)
|
||||
}
|
||||
|
||||
// GetIssueTemplates returns the issue templates for a repository
|
||||
func GetIssueTemplates(ctx *context.APIContext) {
|
||||
// swagger:operation GET /repos/{owner}/{repo}/issue_templates repository repoGetIssueTemplates
|
||||
// ---
|
||||
// summary: Get available issue templates for a repository
|
||||
// produces:
|
||||
// - application/json
|
||||
// parameters:
|
||||
// - name: owner
|
||||
// in: path
|
||||
// description: owner of the repo
|
||||
// type: string
|
||||
// required: true
|
||||
// - name: repo
|
||||
// in: path
|
||||
// description: name of the repo
|
||||
// type: string
|
||||
// required: true
|
||||
// responses:
|
||||
// "200":
|
||||
// "$ref": "#/responses/IssueTemplates"
|
||||
|
||||
ctx.JSON(http.StatusOK, ctx.IssueTemplatesFromDefaultBranch())
|
||||
}
|
||||
|
|
|
@ -85,6 +85,13 @@ type swaggerIssueDeadline struct {
|
|||
Body api.IssueDeadline `json:"body"`
|
||||
}
|
||||
|
||||
// IssueTemplates
|
||||
// swagger:response IssueTemplates
|
||||
type swaggerIssueTemplates struct {
|
||||
// in:body
|
||||
Body []api.IssueTemplate `json:"body"`
|
||||
}
|
||||
|
||||
// StopWatch
|
||||
// swagger:response StopWatch
|
||||
type swaggerResponseStopWatch struct {
|
||||
|
|
|
@ -577,7 +577,7 @@ func CompareDiff(ctx *context.Context) {
|
|||
ctx.Data["RequireTribute"] = true
|
||||
ctx.Data["RequireSimpleMDE"] = true
|
||||
ctx.Data["PullRequestWorkInProgressPrefixes"] = setting.Repository.PullRequest.WorkInProgressPrefixes
|
||||
setTemplateIfExists(ctx, pullRequestTemplateKey, pullRequestTemplateCandidates)
|
||||
setTemplateIfExists(ctx, pullRequestTemplateKey, nil, pullRequestTemplateCandidates)
|
||||
renderAttachmentSettings(ctx)
|
||||
|
||||
ctx.Data["HasIssuesOrPullsWritePermission"] = ctx.Repo.CanWrite(models.UnitTypePullRequests)
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
|
@ -36,13 +37,15 @@ import (
|
|||
const (
|
||||
tplAttachment base.TplName = "repo/issue/view_content/attachments"
|
||||
|
||||
tplIssues base.TplName = "repo/issue/list"
|
||||
tplIssueNew base.TplName = "repo/issue/new"
|
||||
tplIssueView base.TplName = "repo/issue/view"
|
||||
tplIssues base.TplName = "repo/issue/list"
|
||||
tplIssueNew base.TplName = "repo/issue/new"
|
||||
tplIssueChoose base.TplName = "repo/issue/choose"
|
||||
tplIssueView base.TplName = "repo/issue/view"
|
||||
|
||||
tplReactions base.TplName = "repo/issue/view_content/reactions"
|
||||
|
||||
issueTemplateKey = "IssueTemplate"
|
||||
issueTemplateKey = "IssueTemplate"
|
||||
issueTemplateTitleKey = "IssueTemplateTitle"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -356,6 +359,7 @@ func Issues(ctx *context.Context) {
|
|||
}
|
||||
ctx.Data["Title"] = ctx.Tr("repo.issues")
|
||||
ctx.Data["PageIsIssueList"] = true
|
||||
ctx.Data["NewIssueChooseTemplate"] = len(ctx.IssueTemplatesFromDefaultBranch()) > 0
|
||||
}
|
||||
|
||||
issues(ctx, ctx.QueryInt64("milestone"), ctx.QueryInt64("project"), util.OptionalBoolOf(isPullList))
|
||||
|
@ -515,11 +519,41 @@ func getFileContentFromDefaultBranch(ctx *context.Context, filename string) (str
|
|||
return string(bytes), true
|
||||
}
|
||||
|
||||
func setTemplateIfExists(ctx *context.Context, ctxDataKey string, possibleFiles []string) {
|
||||
for _, filename := range possibleFiles {
|
||||
content, found := getFileContentFromDefaultBranch(ctx, filename)
|
||||
func setTemplateIfExists(ctx *context.Context, ctxDataKey string, possibleDirs []string, possibleFiles []string) {
|
||||
templateCandidates := make([]string, 0, len(possibleFiles))
|
||||
if ctx.Query("template") != "" {
|
||||
for _, dirName := range possibleDirs {
|
||||
templateCandidates = append(templateCandidates, path.Join(dirName, ctx.Query("template")))
|
||||
}
|
||||
}
|
||||
templateCandidates = append(templateCandidates, possibleFiles...) // Append files to the end because they should be fallback
|
||||
for _, filename := range templateCandidates {
|
||||
templateContent, found := getFileContentFromDefaultBranch(ctx, filename)
|
||||
if found {
|
||||
ctx.Data[ctxDataKey] = content
|
||||
var meta api.IssueTemplate
|
||||
templateBody, err := markdown.ExtractMetadata(templateContent, &meta)
|
||||
if err != nil {
|
||||
log.Debug("could not extract metadata from %s [%s]: %v", filename, ctx.Repo.Repository.FullName(), err)
|
||||
ctx.Data[ctxDataKey] = templateContent
|
||||
return
|
||||
}
|
||||
ctx.Data[issueTemplateTitleKey] = meta.Title
|
||||
ctx.Data[ctxDataKey] = templateBody
|
||||
labelIDs := make([]string, 0, len(meta.Labels))
|
||||
if repoLabels, err := models.GetLabelsByRepoID(ctx.Repo.Repository.ID, "", models.ListOptions{}); err == nil {
|
||||
for _, metaLabel := range meta.Labels {
|
||||
for _, repoLabel := range repoLabels {
|
||||
if strings.EqualFold(repoLabel.Name, metaLabel) {
|
||||
repoLabel.IsChecked = true
|
||||
labelIDs = append(labelIDs, fmt.Sprintf("%d", repoLabel.ID))
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
ctx.Data["Labels"] = repoLabels
|
||||
}
|
||||
ctx.Data["HasSelectedLabel"] = len(labelIDs) > 0
|
||||
ctx.Data["label_ids"] = strings.Join(labelIDs, ",")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -529,10 +563,13 @@ func setTemplateIfExists(ctx *context.Context, ctxDataKey string, possibleFiles
|
|||
func NewIssue(ctx *context.Context) {
|
||||
ctx.Data["Title"] = ctx.Tr("repo.issues.new")
|
||||
ctx.Data["PageIsIssueList"] = true
|
||||
ctx.Data["NewIssueChooseTemplate"] = len(ctx.IssueTemplatesFromDefaultBranch()) > 0
|
||||
ctx.Data["RequireHighlightJS"] = true
|
||||
ctx.Data["RequireSimpleMDE"] = true
|
||||
ctx.Data["RequireTribute"] = true
|
||||
ctx.Data["PullRequestWorkInProgressPrefixes"] = setting.Repository.PullRequest.WorkInProgressPrefixes
|
||||
title := ctx.Query("title")
|
||||
ctx.Data["TitleQuery"] = title
|
||||
body := ctx.Query("body")
|
||||
ctx.Data["BodyQuery"] = body
|
||||
ctx.Data["IsProjectsEnabled"] = ctx.Repo.CanRead(models.UnitTypeProjects)
|
||||
|
@ -562,10 +599,10 @@ func NewIssue(ctx *context.Context) {
|
|||
|
||||
}
|
||||
|
||||
setTemplateIfExists(ctx, issueTemplateKey, IssueTemplateCandidates)
|
||||
renderAttachmentSettings(ctx)
|
||||
|
||||
RetrieveRepoMetas(ctx, ctx.Repo.Repository, false)
|
||||
setTemplateIfExists(ctx, issueTemplateKey, context.IssueTemplateDirCandidates, IssueTemplateCandidates)
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
|
@ -575,6 +612,19 @@ func NewIssue(ctx *context.Context) {
|
|||
ctx.HTML(200, tplIssueNew)
|
||||
}
|
||||
|
||||
// NewIssueChooseTemplate render creating issue from template page
|
||||
func NewIssueChooseTemplate(ctx *context.Context) {
|
||||
ctx.Data["Title"] = ctx.Tr("repo.issues.new")
|
||||
ctx.Data["PageIsIssueList"] = true
|
||||
ctx.Data["milestone"] = ctx.QueryInt64("milestone")
|
||||
|
||||
issueTemplates := ctx.IssueTemplatesFromDefaultBranch()
|
||||
ctx.Data["NewIssueChooseTemplate"] = len(issueTemplates) > 0
|
||||
ctx.Data["IssueTemplates"] = issueTemplates
|
||||
|
||||
ctx.HTML(200, tplIssueChoose)
|
||||
}
|
||||
|
||||
// ValidateRepoMetas check and returns repository's meta informations
|
||||
func ValidateRepoMetas(ctx *context.Context, form auth.CreateIssueForm, isPull bool) ([]int64, []int64, int64, int64) {
|
||||
var (
|
||||
|
@ -676,6 +726,7 @@ func ValidateRepoMetas(ctx *context.Context, form auth.CreateIssueForm, isPull b
|
|||
func NewIssuePost(ctx *context.Context, form auth.CreateIssueForm) {
|
||||
ctx.Data["Title"] = ctx.Tr("repo.issues.new")
|
||||
ctx.Data["PageIsIssueList"] = true
|
||||
ctx.Data["NewIssueChooseTemplate"] = len(ctx.IssueTemplatesFromDefaultBranch()) > 0
|
||||
ctx.Data["RequireHighlightJS"] = true
|
||||
ctx.Data["RequireSimpleMDE"] = true
|
||||
ctx.Data["ReadOnly"] = false
|
||||
|
@ -814,6 +865,7 @@ func ViewIssue(ctx *context.Context) {
|
|||
return
|
||||
}
|
||||
ctx.Data["PageIsIssueList"] = true
|
||||
ctx.Data["NewIssueChooseTemplate"] = len(ctx.IssueTemplatesFromDefaultBranch()) > 0
|
||||
}
|
||||
|
||||
if issue.IsPull && !ctx.Repo.CanRead(models.UnitTypeIssues) {
|
||||
|
|
|
@ -264,6 +264,7 @@ func MilestoneIssuesAndPulls(ctx *context.Context) {
|
|||
ctx.Data["Milestone"] = milestone
|
||||
|
||||
issues(ctx, milestoneID, 0, util.OptionalBoolNone)
|
||||
ctx.Data["NewIssueChooseTemplate"] = len(ctx.IssueTemplatesFromDefaultBranch()) > 0
|
||||
|
||||
ctx.Data["CanWriteIssues"] = ctx.Repo.CanWriteIssuesOrPulls(false)
|
||||
ctx.Data["CanWritePulls"] = ctx.Repo.CanWriteIssuesOrPulls(true)
|
||||
|
|
|
@ -723,8 +723,11 @@ func RegisterRoutes(m *macaron.Macaron) {
|
|||
// Grouping for those endpoints that do require authentication
|
||||
m.Group("/:username/:reponame", func() {
|
||||
m.Group("/issues", func() {
|
||||
m.Combo("/new").Get(context.RepoRef(), repo.NewIssue).
|
||||
Post(bindIgnErr(auth.CreateIssueForm{}), repo.NewIssuePost)
|
||||
m.Group("/new", func() {
|
||||
m.Combo("").Get(context.RepoRef(), repo.NewIssue).
|
||||
Post(bindIgnErr(auth.CreateIssueForm{}), repo.NewIssuePost)
|
||||
m.Get("/choose", context.RepoRef(), repo.NewIssueChooseTemplate)
|
||||
})
|
||||
}, context.RepoMustNotBeArchived(), reqRepoIssueReader)
|
||||
// FIXME: should use different URLs but mostly same logic for comments of issue and pull reuqest.
|
||||
// So they can apply their own enable/disable logic on routers.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue