mirror of
https://github.com/go-gitea/gitea.git
synced 2026-09-23 21:23:41 +09:00
enhance: improve issue-pattern capture groups and support both internal&external trackers enabled (#39354)
* Fix #39351 * Fix #17621 * Fix #34881 By the way, fix error handling bugs in `updateRepoUnits` --------- Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
+7
-3
@@ -473,9 +473,13 @@ func (repo *Repository) composeCommonMetas(ctx context.Context) map[string]strin
|
|||||||
"repo": repo.Name,
|
"repo": repo.Name,
|
||||||
}
|
}
|
||||||
|
|
||||||
unitExternalTracker, err := repo.GetUnit(ctx, unit.TypeExternalTracker)
|
unitInternalTracker, _ := repo.GetUnit(ctx, unit.TypeIssues)
|
||||||
if err == nil {
|
unitExternalTracker, _ := repo.GetUnit(ctx, unit.TypeExternalTracker)
|
||||||
metas["format"] = unitExternalTracker.ExternalTrackerConfig().ExternalTrackerFormat
|
if unitInternalTracker != nil {
|
||||||
|
metas["internalTrackerEnabled"] = "true"
|
||||||
|
}
|
||||||
|
if unitExternalTracker != nil {
|
||||||
|
metas["externalTrackerLinkFormat"] = unitExternalTracker.ExternalTrackerConfig().ExternalTrackerFormat
|
||||||
switch unitExternalTracker.ExternalTrackerConfig().ExternalTrackerStyle {
|
switch unitExternalTracker.ExternalTrackerConfig().ExternalTrackerStyle {
|
||||||
case markup.IssueNameStyleAlphanumeric:
|
case markup.IssueNameStyleAlphanumeric:
|
||||||
metas["style"] = markup.IssueNameStyleAlphanumeric
|
metas["style"] = markup.IssueNameStyleAlphanumeric
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ func TestMetas(t *testing.T) {
|
|||||||
assert.Equal(t, expectedStyle, metas["style"])
|
assert.Equal(t, expectedStyle, metas["style"])
|
||||||
assert.Equal(t, "testRepo", metas["repo"])
|
assert.Equal(t, "testRepo", metas["repo"])
|
||||||
assert.Equal(t, "testOwner", metas["user"])
|
assert.Equal(t, "testOwner", metas["user"])
|
||||||
assert.Equal(t, "https://someurl.com/{user}/{repo}/{issue}", metas["format"])
|
assert.Equal(t, "https://someurl.com/{user}/{repo}/{issue}", metas["externalTrackerLinkFormat"])
|
||||||
}
|
}
|
||||||
|
|
||||||
testSuccess(markup.IssueNameStyleNumeric)
|
testSuccess(markup.IssueNameStyleNumeric)
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ func link(href, class, contents string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var numericMetas = map[string]string{
|
var numericMetas = map[string]string{
|
||||||
"format": "https://someurl.com/{user}/{repo}/{index}",
|
"externalTrackerLinkFormat": "https://someurl.com/{user}/{repo}/{index}",
|
||||||
"user": "someUser",
|
"user": "someUser",
|
||||||
"repo": "someRepo",
|
"repo": "someRepo",
|
||||||
"style": IssueNameStyleNumeric,
|
"style": IssueNameStyleNumeric,
|
||||||
@@ -47,7 +47,7 @@ var numericMetas = map[string]string{
|
|||||||
}
|
}
|
||||||
|
|
||||||
var alphanumericMetas = map[string]string{
|
var alphanumericMetas = map[string]string{
|
||||||
"format": "https://someurl.com/{user}/{repo}/{index}",
|
"externalTrackerLinkFormat": "https://someurl.com/{user}/{repo}/{index}",
|
||||||
"user": "someUser",
|
"user": "someUser",
|
||||||
"repo": "someRepo",
|
"repo": "someRepo",
|
||||||
"style": IssueNameStyleAlphanumeric,
|
"style": IssueNameStyleAlphanumeric,
|
||||||
@@ -55,10 +55,10 @@ var alphanumericMetas = map[string]string{
|
|||||||
}
|
}
|
||||||
|
|
||||||
var regexpMetas = map[string]string{
|
var regexpMetas = map[string]string{
|
||||||
"format": "https://someurl.com/{user}/{repo}/{index}",
|
"externalTrackerLinkFormat": "https://someurl.com/{user}/{repo}/{index}",
|
||||||
"user": "someUser",
|
"user": "someUser",
|
||||||
"repo": "someRepo",
|
"repo": "someRepo",
|
||||||
"style": IssueNameStyleRegexp,
|
"style": IssueNameStyleRegexp,
|
||||||
}
|
}
|
||||||
|
|
||||||
// these values should match the TestOrgRepo const above
|
// these values should match the TestOrgRepo const above
|
||||||
@@ -219,23 +219,29 @@ func TestRender_IssueIndexPattern5(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test("abc ISSUE-123 def", "abc %s def",
|
test("abc ISSUE-123 def", "abc %s def",
|
||||||
"ISSUE-(\\d+)",
|
`ISSUE-(\d+)`,
|
||||||
[]string{"123"},
|
[]string{"123"},
|
||||||
[]string{"ISSUE-123"},
|
[]string{"ISSUE-123"},
|
||||||
)
|
)
|
||||||
|
|
||||||
test("abc (ISSUE 123) def", "abc %s def",
|
test("abc (ISSUE 123) def", "abc %s def",
|
||||||
"\\(ISSUE (\\d+)\\)",
|
`\(ISSUE (\d+)\)`,
|
||||||
[]string{"123"},
|
[]string{"123"},
|
||||||
[]string{"(ISSUE 123)"},
|
[]string{"(ISSUE 123)"},
|
||||||
)
|
)
|
||||||
|
|
||||||
test("abc ISSUE-123 def", "abc %s def",
|
test("abc ISSUE-123 def", "abc %s def",
|
||||||
"(ISSUE-(\\d+))",
|
`(ISSUE-(\d+))`,
|
||||||
[]string{"ISSUE-123"},
|
[]string{"ISSUE-123"},
|
||||||
[]string{"ISSUE-123"},
|
[]string{"ISSUE-123"},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
test("123456: TEST-123456", "%s %s",
|
||||||
|
`(\d+):|TEST-(\d+)`,
|
||||||
|
[]string{"123456", "123456"},
|
||||||
|
[]string{"123456:", "TEST-123456"},
|
||||||
|
)
|
||||||
|
|
||||||
testRenderIssueIndexPattern(t, "will not match", "will not match", NewTestRenderContext(regexpMetas))
|
testRenderIssueIndexPattern(t, "will not match", "will not match", NewTestRenderContext(regexpMetas))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -110,16 +110,23 @@ func issueIndexPatternProcessor(ctx *RenderContext, node *html.Node) {
|
|||||||
|
|
||||||
next := node.NextSibling
|
next := node.NextSibling
|
||||||
for node != nil && node != next {
|
for node != nil && node != next {
|
||||||
_, hasExtTrackFormat := ctx.RenderOptions.Metas["format"]
|
_, hasExternalTracker := ctx.RenderOptions.Metas["externalTrackerLinkFormat"]
|
||||||
|
hasInternalTracker := ctx.RenderOptions.Metas["internalTrackerEnabled"] == "true"
|
||||||
|
if !hasExternalTracker && !hasInternalTracker {
|
||||||
|
hasInternalTracker = true // legacy logic: if no tracker is enabled, fallback to internal
|
||||||
|
}
|
||||||
// Repos with external issue trackers might still need to reference local PRs
|
// Repos with external issue trackers might still need to reference local PRs
|
||||||
// We need to concern with the first one that shows up in the text, whichever it is
|
// We need to concern with the first one that shows up in the text, whichever it is
|
||||||
isNumericStyle := ctx.RenderOptions.Metas["style"] == "" || ctx.RenderOptions.Metas["style"] == IssueNameStyleNumeric
|
isNumericStyle := ctx.RenderOptions.Metas["style"] == "" || ctx.RenderOptions.Metas["style"] == IssueNameStyleNumeric
|
||||||
refNumeric := references.FindRenderizableReferenceNumeric(node.Data, hasExtTrackFormat && !isNumericStyle, crossLinkOnly)
|
prOnly := hasExternalTracker && !isNumericStyle
|
||||||
|
refNumeric := references.FindRenderizableReferenceNumeric(node.Data, prOnly, crossLinkOnly)
|
||||||
|
|
||||||
|
useExtTrackerLink := true
|
||||||
switch ctx.RenderOptions.Metas["style"] {
|
switch ctx.RenderOptions.Metas["style"] {
|
||||||
case "", IssueNameStyleNumeric:
|
case "", IssueNameStyleNumeric:
|
||||||
ref = refNumeric
|
ref = refNumeric
|
||||||
|
// when internal tracker is enabled, Numeric (#123) style should only be use for internal tracker
|
||||||
|
useExtTrackerLink = !hasInternalTracker
|
||||||
case IssueNameStyleAlphanumeric:
|
case IssueNameStyleAlphanumeric:
|
||||||
ref = references.FindRenderizableReferenceAlphanumeric(node.Data)
|
ref = references.FindRenderizableReferenceAlphanumeric(node.Data)
|
||||||
case IssueNameStyleRegexp:
|
case IssueNameStyleRegexp:
|
||||||
@@ -132,7 +139,7 @@ func issueIndexPatternProcessor(ctx *RenderContext, node *html.Node) {
|
|||||||
|
|
||||||
// Repos with external issue trackers might still need to reference local PRs
|
// Repos with external issue trackers might still need to reference local PRs
|
||||||
// We need to concern with the first one that shows up in the text, whichever it is
|
// We need to concern with the first one that shows up in the text, whichever it is
|
||||||
if hasExtTrackFormat && !isNumericStyle && refNumeric != nil {
|
if useExtTrackerLink && !isNumericStyle && refNumeric != nil {
|
||||||
// If numeric (PR) was found, and it was BEFORE the non-numeric pattern, use that
|
// If numeric (PR) was found, and it was BEFORE the non-numeric pattern, use that
|
||||||
// Allow a free-pass when non-numeric pattern wasn't found.
|
// Allow a free-pass when non-numeric pattern wasn't found.
|
||||||
if ref == nil || refNumeric.RefLocation.Start < ref.RefLocation.Start {
|
if ref == nil || refNumeric.RefLocation.Start < ref.RefLocation.Start {
|
||||||
@@ -146,10 +153,10 @@ func issueIndexPatternProcessor(ctx *RenderContext, node *html.Node) {
|
|||||||
|
|
||||||
var link *html.Node
|
var link *html.Node
|
||||||
refText := node.Data[ref.RefLocation.Start:ref.RefLocation.End]
|
refText := node.Data[ref.RefLocation.Start:ref.RefLocation.End]
|
||||||
if hasExtTrackFormat && !ref.IsPull {
|
if useExtTrackerLink && !ref.IsPull {
|
||||||
ctx.RenderOptions.Metas["index"] = ref.Issue
|
ctx.RenderOptions.Metas["index"] = ref.Issue
|
||||||
|
|
||||||
res, err := vars.ExpandCurlyBrace(ctx.RenderOptions.Metas["format"], ctx.RenderOptions.Metas)
|
res, err := vars.ExpandCurlyBrace(ctx.RenderOptions.Metas["externalTrackerLinkFormat"], ctx.RenderOptions.Metas)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// here we could just log the error and continue the rendering
|
// here we could just log the error and continue the rendering
|
||||||
log.Error("unable to expand template vars for ref %s, err: %v", ref.Issue, err)
|
log.Error("unable to expand template vars for ref %s, err: %v", ref.Issue, err)
|
||||||
@@ -183,7 +190,7 @@ func issueIndexPatternProcessor(ctx *RenderContext, node *html.Node) {
|
|||||||
|
|
||||||
// Decorate action keywords if actionable
|
// Decorate action keywords if actionable
|
||||||
var keyword *html.Node
|
var keyword *html.Node
|
||||||
if references.IsXrefActionable(ref, hasExtTrackFormat) {
|
if references.IsXrefActionable(ref, useExtTrackerLink) {
|
||||||
keyword = createKeyword(ctx, node.Data[ref.ActionLocation.Start:ref.ActionLocation.End])
|
keyword = createKeyword(ctx, node.Data[ref.ActionLocation.Start:ref.ActionLocation.End])
|
||||||
} else {
|
} else {
|
||||||
keyword = &html.Node{
|
keyword = &html.Node{
|
||||||
|
|||||||
@@ -378,9 +378,23 @@ func FindRenderizableReferenceRegexp(content string, pattern *regexp.Regexp) *Re
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
action, location := findActionKeywords([]byte(content), match[2])
|
// The external tracker pattern can use alternatives with separate capture
|
||||||
|
// groups. Pick the first group that participated in this match instead of
|
||||||
|
// assuming the first group always did.
|
||||||
|
issueStart, issueEnd := -1, -1
|
||||||
|
for i := 2; i+1 < len(match); i += 2 {
|
||||||
|
if match[i] >= 0 {
|
||||||
|
issueStart, issueEnd = match[i], match[i+1]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if issueStart < 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
action, location := findActionKeywords([]byte(content), issueStart)
|
||||||
return &RenderizableReference{
|
return &RenderizableReference{
|
||||||
Issue: content[match[2]:match[3]],
|
Issue: content[issueStart:issueEnd],
|
||||||
RefLocation: &RefSpan{Start: match[0], End: match[1]},
|
RefLocation: &RefSpan{Start: match[0], End: match[1]},
|
||||||
Action: action,
|
Action: action,
|
||||||
ActionLocation: location,
|
ActionLocation: location,
|
||||||
|
|||||||
@@ -2140,15 +2140,15 @@
|
|||||||
"repo.settings.external_wiki_url": "External Wiki URL",
|
"repo.settings.external_wiki_url": "External Wiki URL",
|
||||||
"repo.settings.external_wiki_url_error": "The external wiki URL is not a valid URL.",
|
"repo.settings.external_wiki_url_error": "The external wiki URL is not a valid URL.",
|
||||||
"repo.settings.external_wiki_url_desc": "Visitors are redirected to the external wiki URL when clicking the wiki tab.",
|
"repo.settings.external_wiki_url_desc": "Visitors are redirected to the external wiki URL when clicking the wiki tab.",
|
||||||
"repo.settings.issues_desc": "Enable Repository Issue Tracker",
|
|
||||||
"repo.settings.use_internal_issue_tracker": "Use Built-In Issue Tracker",
|
"repo.settings.use_internal_issue_tracker": "Use Built-In Issue Tracker",
|
||||||
"repo.settings.use_external_issue_tracker": "Use External Issue Tracker",
|
"repo.settings.use_external_issue_tracker": "Use External Issue Tracker",
|
||||||
"repo.settings.external_tracker_url": "External Issue Tracker URL",
|
"repo.settings.external_tracker_url": "External Issue Tracker URL",
|
||||||
"repo.settings.external_tracker_url_error": "The external issue tracker URL is not a valid URL.",
|
"repo.settings.external_tracker_url_error": "The external issue tracker URL is not a valid URL.",
|
||||||
"repo.settings.external_tracker_url_desc": "Visitors are redirected to the external issue tracker URL when clicking on the issues tab.",
|
"repo.settings.external_tracker_url_desc": "When built-in issue tracker is disabled, visitors are redirected to the external issue tracker URL when clicking on the issues tab.",
|
||||||
"repo.settings.tracker_url_format": "External Issue Tracker URL Format",
|
"repo.settings.tracker_url_format": "External Issue Tracker URL Format",
|
||||||
"repo.settings.tracker_url_format_error": "The external issue tracker URL format is not a valid URL.",
|
"repo.settings.tracker_url_format_error": "The external issue tracker URL format is not a valid URL.",
|
||||||
"repo.settings.tracker_issue_style": "External Issue Tracker Number Format",
|
"repo.settings.tracker_issue_style": "External Issue Tracker Number Format",
|
||||||
|
"repo.settings.tracker_issue_style_desc": "When the internal issue tracker is enabled, the Numeric style can only be used for the internal issue tracker.",
|
||||||
"repo.settings.tracker_issue_style.numeric": "Numeric",
|
"repo.settings.tracker_issue_style.numeric": "Numeric",
|
||||||
"repo.settings.tracker_issue_style.alphanumeric": "Alphanumeric",
|
"repo.settings.tracker_issue_style.alphanumeric": "Alphanumeric",
|
||||||
"repo.settings.tracker_issue_style.regexp": "Regular Expression",
|
"repo.settings.tracker_issue_style.regexp": "Regular Expression",
|
||||||
|
|||||||
+22
-29
@@ -25,6 +25,7 @@ import (
|
|||||||
"gitea.dev/modules/git"
|
"gitea.dev/modules/git"
|
||||||
"gitea.dev/modules/label"
|
"gitea.dev/modules/label"
|
||||||
"gitea.dev/modules/log"
|
"gitea.dev/modules/log"
|
||||||
|
"gitea.dev/modules/markup"
|
||||||
"gitea.dev/modules/optional"
|
"gitea.dev/modules/optional"
|
||||||
repo_module "gitea.dev/modules/repository"
|
repo_module "gitea.dev/modules/repository"
|
||||||
"gitea.dev/modules/setting"
|
"gitea.dev/modules/setting"
|
||||||
@@ -612,6 +613,7 @@ func Edit(ctx *context.APIContext) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err := updateRepoUnits(ctx, opts); err != nil {
|
if err := updateRepoUnits(ctx, opts); err != nil {
|
||||||
|
ctx.APIErrorAuto(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -750,24 +752,21 @@ func updateBasicProperties(ctx *context.APIContext, opts api.EditRepoOption) err
|
|||||||
|
|
||||||
// updateRepoUnits updates repo units: Issue settings, Wiki settings, PR settings
|
// updateRepoUnits updates repo units: Issue settings, Wiki settings, PR settings
|
||||||
func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error {
|
func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error {
|
||||||
owner := ctx.Repo.Owner
|
|
||||||
repo := ctx.Repo.Repository
|
repo := ctx.Repo.Repository
|
||||||
|
|
||||||
var units []repo_model.RepoUnit
|
var units []repo_model.RepoUnit
|
||||||
var deleteUnitTypes []unit_model.Type
|
var deleteUnitTypes []unit_model.Type
|
||||||
|
|
||||||
if opts.HasIssues != nil {
|
if opts.HasIssues != nil && *opts.HasIssues {
|
||||||
if *opts.HasIssues && opts.ExternalTracker != nil && !unit_model.TypeExternalTracker.UnitGlobalDisabled() {
|
if opts.ExternalTracker != nil && !unit_model.TypeExternalTracker.UnitGlobalDisabled() {
|
||||||
// Check that values are valid
|
if (opts.InternalTracker == nil || opts.ExternalTracker.ExternalTrackerURL != "") && !validation.IsValidURL(opts.ExternalTracker.ExternalTrackerURL) {
|
||||||
if !validation.IsValidURL(opts.ExternalTracker.ExternalTrackerURL) {
|
return util.ErrorWrap(util.ErrUnprocessableContent, "external tracker URL not valid")
|
||||||
err := errors.New("External tracker URL not valid")
|
|
||||||
ctx.APIError(http.StatusUnprocessableEntity, err.Error())
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
if len(opts.ExternalTracker.ExternalTrackerFormat) != 0 && !validation.IsValidExternalTrackerURLFormat(opts.ExternalTracker.ExternalTrackerFormat) {
|
if opts.InternalTracker != nil && (opts.ExternalTracker.ExternalTrackerStyle == "" || opts.ExternalTracker.ExternalTrackerStyle == markup.IssueNameStyleNumeric) {
|
||||||
err := errors.New("External tracker URL format not valid")
|
return util.ErrorWrap(util.ErrUnprocessableContent, "external tracker style Numeric is only used for internal tracker")
|
||||||
ctx.APIError(http.StatusUnprocessableEntity, err.Error())
|
}
|
||||||
return err
|
if opts.ExternalTracker.ExternalTrackerFormat != "" && !validation.IsValidExternalTrackerURLFormat(opts.ExternalTracker.ExternalTrackerFormat) {
|
||||||
|
return util.ErrorWrap(util.ErrUnprocessableContent, "External tracker URL format not valid")
|
||||||
}
|
}
|
||||||
|
|
||||||
units = append(units, repo_model.RepoUnit{
|
units = append(units, repo_model.RepoUnit{
|
||||||
@@ -780,8 +779,10 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error {
|
|||||||
ExternalTrackerRegexpPattern: opts.ExternalTracker.ExternalTrackerRegexpPattern,
|
ExternalTrackerRegexpPattern: opts.ExternalTracker.ExternalTrackerRegexpPattern,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeIssues)
|
} else {
|
||||||
} else if *opts.HasIssues && opts.ExternalTracker == nil && !unit_model.TypeIssues.UnitGlobalDisabled() {
|
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeExternalTracker)
|
||||||
|
}
|
||||||
|
if (opts.ExternalTracker == nil || opts.InternalTracker != nil) && !unit_model.TypeIssues.UnitGlobalDisabled() {
|
||||||
// Default to built-in tracker
|
// Default to built-in tracker
|
||||||
var config *repo_model.IssuesConfig
|
var config *repo_model.IssuesConfig
|
||||||
|
|
||||||
@@ -807,24 +808,20 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error {
|
|||||||
Type: unit_model.TypeIssues,
|
Type: unit_model.TypeIssues,
|
||||||
Config: config,
|
Config: config,
|
||||||
})
|
})
|
||||||
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeExternalTracker)
|
} else {
|
||||||
} else if !*opts.HasIssues {
|
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeIssues)
|
||||||
if !unit_model.TypeExternalTracker.UnitGlobalDisabled() {
|
|
||||||
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeExternalTracker)
|
|
||||||
}
|
|
||||||
if !unit_model.TypeIssues.UnitGlobalDisabled() {
|
|
||||||
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeIssues)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if opts.HasIssues != nil && !*opts.HasIssues {
|
||||||
|
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeExternalTracker)
|
||||||
|
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeIssues)
|
||||||
|
}
|
||||||
|
|
||||||
if opts.HasWiki != nil {
|
if opts.HasWiki != nil {
|
||||||
if *opts.HasWiki && opts.ExternalWiki != nil && !unit_model.TypeExternalWiki.UnitGlobalDisabled() {
|
if *opts.HasWiki && opts.ExternalWiki != nil && !unit_model.TypeExternalWiki.UnitGlobalDisabled() {
|
||||||
// Check that values are valid
|
// Check that values are valid
|
||||||
if !validation.IsValidURL(opts.ExternalWiki.ExternalWikiURL) {
|
if !validation.IsValidURL(opts.ExternalWiki.ExternalWikiURL) {
|
||||||
err := errors.New("External wiki URL not valid")
|
return util.ErrorWrap(util.ErrUnprocessableContent, "external wiki URL not valid")
|
||||||
ctx.APIError(http.StatusUnprocessableEntity, "Invalid external wiki URL")
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
units = append(units, repo_model.RepoUnit{
|
units = append(units, repo_model.RepoUnit{
|
||||||
@@ -902,7 +899,6 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error {
|
|||||||
// so unrelated PATCH calls don't reject historical configs.
|
// so unrelated PATCH calls don't reject historical configs.
|
||||||
if opts.AllowMergeUpdate != nil || opts.AllowRebaseUpdate != nil || opts.DefaultUpdateStyle != nil {
|
if opts.AllowMergeUpdate != nil || opts.AllowRebaseUpdate != nil || opts.DefaultUpdateStyle != nil {
|
||||||
if err := config.ValidateUpdateSettings(); err != nil {
|
if err := config.ValidateUpdateSettings(); err != nil {
|
||||||
ctx.APIError(http.StatusUnprocessableEntity, err.Error())
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -977,12 +973,9 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error {
|
|||||||
|
|
||||||
if len(units)+len(deleteUnitTypes) > 0 {
|
if len(units)+len(deleteUnitTypes) > 0 {
|
||||||
if err := repo_service.UpdateRepositoryUnits(ctx, repo, units, deleteUnitTypes); err != nil {
|
if err := repo_service.UpdateRepositoryUnits(ctx, repo, units, deleteUnitTypes); err != nil {
|
||||||
ctx.APIErrorInternal(err)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Trace("Repository advanced settings updated: %s/%s", owner.Name, repo.Name)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -96,10 +96,13 @@ func MustEnableIssues(ctx *context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
unit, err := ctx.Repo.Repository.GetUnit(ctx, unit.TypeExternalTracker)
|
unitExtTracker, err := ctx.Repo.Repository.GetUnit(ctx, unit.TypeExternalTracker)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
ctx.Redirect(unit.ExternalTrackerConfig().ExternalTrackerURL)
|
extURL := unitExtTracker.ExternalTrackerConfig().ExternalTrackerURL
|
||||||
return
|
if extURL != "" {
|
||||||
|
ctx.Redirect(extURL)
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import (
|
|||||||
"gitea.dev/modules/indexer/stats"
|
"gitea.dev/modules/indexer/stats"
|
||||||
"gitea.dev/modules/lfs"
|
"gitea.dev/modules/lfs"
|
||||||
"gitea.dev/modules/log"
|
"gitea.dev/modules/log"
|
||||||
|
"gitea.dev/modules/markup"
|
||||||
"gitea.dev/modules/setting"
|
"gitea.dev/modules/setting"
|
||||||
"gitea.dev/modules/structs"
|
"gitea.dev/modules/structs"
|
||||||
"gitea.dev/modules/templates"
|
"gitea.dev/modules/templates"
|
||||||
@@ -570,10 +571,6 @@ func handleSettingsPostAdvanced(ctx *context.Context) {
|
|||||||
var units []repo_model.RepoUnit
|
var units []repo_model.RepoUnit
|
||||||
var deleteUnitTypes []unit_model.Type
|
var deleteUnitTypes []unit_model.Type
|
||||||
|
|
||||||
// This section doesn't require repo_name/RepoName to be set in the form, don't show it
|
|
||||||
// as an error on the UI for this action
|
|
||||||
ctx.Data["Err_RepoName"] = nil
|
|
||||||
|
|
||||||
if repo.CloseIssuesViaCommitInAnyBranch != form.EnableCloseIssuesViaCommitInAnyBranch {
|
if repo.CloseIssuesViaCommitInAnyBranch != form.EnableCloseIssuesViaCommitInAnyBranch {
|
||||||
repo.CloseIssuesViaCommitInAnyBranch = form.EnableCloseIssuesViaCommitInAnyBranch
|
repo.CloseIssuesViaCommitInAnyBranch = form.EnableCloseIssuesViaCommitInAnyBranch
|
||||||
repoChanged = true
|
repoChanged = true
|
||||||
@@ -587,8 +584,7 @@ func handleSettingsPostAdvanced(ctx *context.Context) {
|
|||||||
|
|
||||||
if form.EnableWiki && form.EnableExternalWiki && !unit_model.TypeExternalWiki.UnitGlobalDisabled() {
|
if form.EnableWiki && form.EnableExternalWiki && !unit_model.TypeExternalWiki.UnitGlobalDisabled() {
|
||||||
if !validation.IsValidURL(form.ExternalWikiURL) {
|
if !validation.IsValidURL(form.ExternalWikiURL) {
|
||||||
ctx.Flash.Error(ctx.Tr("repo.settings.external_wiki_url_error"))
|
ctx.JSONError(ctx.Tr("repo.settings.external_wiki_url_error"))
|
||||||
ctx.Redirect(repo.Link() + "/settings")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -611,19 +607,21 @@ func handleSettingsPostAdvanced(ctx *context.Context) {
|
|||||||
if form.DefaultWikiBranch != "" {
|
if form.DefaultWikiBranch != "" {
|
||||||
if err := wiki_service.ChangeDefaultWikiBranch(ctx, repo, form.DefaultWikiBranch); err != nil {
|
if err := wiki_service.ChangeDefaultWikiBranch(ctx, repo, form.DefaultWikiBranch); err != nil {
|
||||||
log.Error("ChangeDefaultWikiBranch failed, err: %v", err)
|
log.Error("ChangeDefaultWikiBranch failed, err: %v", err)
|
||||||
ctx.Flash.Warning(ctx.Tr("repo.settings.failed_to_change_default_wiki_branch"))
|
ctx.Flash.Warning(ctx.Tr("repo.settings.failed_to_change_default_wiki_branch")) // skip the error, continue, and reload page
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if form.EnableIssues && form.EnableExternalTracker && !unit_model.TypeExternalTracker.UnitGlobalDisabled() {
|
if form.EnableExternalTracker && !unit_model.TypeExternalTracker.UnitGlobalDisabled() {
|
||||||
if !validation.IsValidURL(form.ExternalTrackerURL) {
|
if (!form.EnableInternalTracker || form.ExternalTrackerURL != "") && !validation.IsValidURL(form.ExternalTrackerURL) {
|
||||||
ctx.Flash.Error(ctx.Tr("repo.settings.external_tracker_url_error"))
|
ctx.JSONError(ctx.Tr("repo.settings.external_tracker_url_error"))
|
||||||
ctx.Redirect(repo.Link() + "/settings")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if len(form.TrackerURLFormat) != 0 && !validation.IsValidExternalTrackerURLFormat(form.TrackerURLFormat) {
|
if form.TrackerURLFormat != "" && !validation.IsValidExternalTrackerURLFormat(form.TrackerURLFormat) {
|
||||||
ctx.Flash.Error(ctx.Tr("repo.settings.tracker_url_format_error"))
|
ctx.JSONError(ctx.Tr("repo.settings.tracker_url_format_error"))
|
||||||
ctx.Redirect(repo.Link() + "/settings")
|
return
|
||||||
|
}
|
||||||
|
if form.EnableInternalTracker && (form.TrackerIssueStyle == "" || form.TrackerIssueStyle == markup.IssueNameStyleNumeric) {
|
||||||
|
ctx.JSONError(ctx.Tr("repo.settings.tracker_issue_style_desc"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
units = append(units, newRepoUnit(repo, unit_model.TypeExternalTracker, &repo_model.ExternalTrackerConfig{
|
units = append(units, newRepoUnit(repo, unit_model.TypeExternalTracker, &repo_model.ExternalTrackerConfig{
|
||||||
@@ -632,21 +630,18 @@ func handleSettingsPostAdvanced(ctx *context.Context) {
|
|||||||
ExternalTrackerStyle: form.TrackerIssueStyle,
|
ExternalTrackerStyle: form.TrackerIssueStyle,
|
||||||
ExternalTrackerRegexpPattern: form.ExternalTrackerRegexpPattern,
|
ExternalTrackerRegexpPattern: form.ExternalTrackerRegexpPattern,
|
||||||
}))
|
}))
|
||||||
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeIssues)
|
} else {
|
||||||
} else if form.EnableIssues && !form.EnableExternalTracker && !unit_model.TypeIssues.UnitGlobalDisabled() {
|
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeExternalTracker)
|
||||||
|
}
|
||||||
|
|
||||||
|
if form.EnableInternalTracker && !unit_model.TypeIssues.UnitGlobalDisabled() {
|
||||||
units = append(units, newRepoUnit(repo, unit_model.TypeIssues, &repo_model.IssuesConfig{
|
units = append(units, newRepoUnit(repo, unit_model.TypeIssues, &repo_model.IssuesConfig{
|
||||||
EnableTimetracker: form.EnableTimetracker,
|
EnableTimetracker: form.EnableTimetracker,
|
||||||
AllowOnlyContributorsToTrackTime: form.AllowOnlyContributorsToTrackTime,
|
AllowOnlyContributorsToTrackTime: form.AllowOnlyContributorsToTrackTime,
|
||||||
EnableDependencies: form.EnableIssueDependencies,
|
EnableDependencies: form.EnableIssueDependencies,
|
||||||
}))
|
}))
|
||||||
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeExternalTracker)
|
|
||||||
} else {
|
} else {
|
||||||
if !unit_model.TypeExternalTracker.UnitGlobalDisabled() {
|
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeIssues)
|
||||||
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeExternalTracker)
|
|
||||||
}
|
|
||||||
if !unit_model.TypeIssues.UnitGlobalDisabled() {
|
|
||||||
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeIssues)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if form.EnableProjects && !unit_model.TypeProjects.UnitGlobalDisabled() {
|
if form.EnableProjects && !unit_model.TypeProjects.UnitGlobalDisabled() {
|
||||||
@@ -689,8 +684,7 @@ func handleSettingsPostAdvanced(ctx *context.Context) {
|
|||||||
DefaultTargetBranch: strings.TrimSpace(form.DefaultTargetBranch),
|
DefaultTargetBranch: strings.TrimSpace(form.DefaultTargetBranch),
|
||||||
}
|
}
|
||||||
if err := prConfig.ValidateUpdateSettings(); err != nil {
|
if err := prConfig.ValidateUpdateSettings(); err != nil {
|
||||||
ctx.Flash.Error(err.Error())
|
ctx.JSONErrorAuto(err)
|
||||||
ctx.Redirect(repo.Link() + "/settings")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
units = append(units, newRepoUnit(repo, unit_model.TypePullRequests, prConfig))
|
units = append(units, newRepoUnit(repo, unit_model.TypePullRequests, prConfig))
|
||||||
@@ -699,8 +693,7 @@ func handleSettingsPostAdvanced(ctx *context.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(units) == 0 {
|
if len(units) == 0 {
|
||||||
ctx.Flash.Error(ctx.Tr("repo.settings.update_settings_no_unit"))
|
ctx.JSONError(ctx.Tr("repo.settings.update_settings_no_unit"))
|
||||||
ctx.Redirect(ctx.Repo.RepoLink + "/settings")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -714,10 +707,9 @@ func handleSettingsPostAdvanced(ctx *context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log.Trace("Repository advanced settings updated: %s/%s", ctx.Repo.Owner.Name, repo.Name)
|
|
||||||
|
|
||||||
ctx.Flash.Success(ctx.Tr("repo.settings.update_settings_success"))
|
ctx.Flash.Success(ctx.Tr("repo.settings.update_settings_success"))
|
||||||
ctx.Redirect(ctx.Repo.RepoLink + "/settings")
|
ctx.JSONRedirect("")
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleSettingsPostSigning(ctx *context.Context) {
|
func handleSettingsPostSigning(ctx *context.Context) {
|
||||||
|
|||||||
@@ -105,12 +105,12 @@ type RepoSettingForm struct {
|
|||||||
DefaultWikiBranch string
|
DefaultWikiBranch string
|
||||||
ExternalWikiURL string
|
ExternalWikiURL string
|
||||||
|
|
||||||
EnableIssues bool
|
EnableInternalTracker bool
|
||||||
EnableExternalTracker bool
|
EnableExternalTracker bool
|
||||||
ExternalTrackerURL string
|
ExternalTrackerURL string `binding:"TrimSpace"`
|
||||||
TrackerURLFormat string
|
TrackerURLFormat string `binding:"TrimSpace"`
|
||||||
TrackerIssueStyle string
|
TrackerIssueStyle string
|
||||||
ExternalTrackerRegexpPattern string
|
ExternalTrackerRegexpPattern string `binding:"TrimSpace"`
|
||||||
EnableCloseIssuesViaCommitInAnyBranch bool
|
EnableCloseIssuesViaCommitInAnyBranch bool
|
||||||
|
|
||||||
EnableProjects bool
|
EnableProjects bool
|
||||||
|
|||||||
@@ -303,7 +303,7 @@
|
|||||||
{{ctx.Locale.Tr "repo.settings.advanced_settings"}}
|
{{ctx.Locale.Tr "repo.settings.advanced_settings"}}
|
||||||
</h4>
|
</h4>
|
||||||
<div class="ui attached segment">
|
<div class="ui attached segment">
|
||||||
<form class="ui form" method="post">
|
<form class="ui form form-fetch-action" method="post">
|
||||||
<input type="hidden" name="action" value="advanced">
|
<input type="hidden" name="action" value="advanced">
|
||||||
|
|
||||||
{{$isCodeEnabled := .Repository.UnitEnabled ctx ctx.Consts.RepoUnitTypeCode}}
|
{{$isCodeEnabled := .Repository.UnitEnabled ctx ctx.Consts.RepoUnitTypeCode}}
|
||||||
@@ -357,25 +357,19 @@
|
|||||||
|
|
||||||
<div class="divider"></div>
|
<div class="divider"></div>
|
||||||
|
|
||||||
{{$isIssuesEnabled := or (.Repository.UnitEnabled ctx ctx.Consts.RepoUnitTypeIssues) (.Repository.UnitEnabled ctx ctx.Consts.RepoUnitTypeExternalTracker)}}
|
|
||||||
{{$isIssuesGlobalDisabled := ctx.Consts.RepoUnitTypeIssues.UnitGlobalDisabled}}
|
{{$isIssuesGlobalDisabled := ctx.Consts.RepoUnitTypeIssues.UnitGlobalDisabled}}
|
||||||
{{$isExternalTrackerGlobalDisabled := ctx.Consts.RepoUnitTypeExternalTracker.UnitGlobalDisabled}}
|
{{$isExternalTrackerGlobalDisabled := ctx.Consts.RepoUnitTypeExternalTracker.UnitGlobalDisabled}}
|
||||||
{{$isIssuesAndExternalGlobalDisabled := and $isIssuesGlobalDisabled $isExternalTrackerGlobalDisabled}}
|
{{$isIssuesAndExternalGlobalDisabled := and $isIssuesGlobalDisabled $isExternalTrackerGlobalDisabled}}
|
||||||
<div class="inline field">
|
<div class="field">
|
||||||
<label>{{ctx.Locale.Tr "repo.issues"}}</label>
|
<label>{{ctx.Locale.Tr "repo.issues"}}</label>
|
||||||
<div class="ui checkbox{{if $isIssuesAndExternalGlobalDisabled}} disabled{{end}}"{{if $isIssuesAndExternalGlobalDisabled}} data-tooltip-content="{{ctx.Locale.Tr "repo.unit_disabled"}}"{{end}}>
|
{{$isInternalTrackerEnabled := .Repository.UnitEnabled ctx ctx.Consts.RepoUnitTypeIssues}}
|
||||||
<input class="enable-system" name="enable_issues" type="checkbox" data-target="#issue_box" {{if $isIssuesEnabled}}checked{{end}}>
|
|
||||||
<label>{{ctx.Locale.Tr "repo.settings.issues_desc"}}</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="field {{if not $isIssuesEnabled}}disabled{{end}}" id="issue_box">
|
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<div class="ui radio checkbox{{if $isIssuesGlobalDisabled}} disabled{{end}}"{{if $isIssuesGlobalDisabled}} data-tooltip-content="{{ctx.Locale.Tr "repo.unit_disabled"}}"{{end}}>
|
<div class="ui checkbox {{if $isIssuesGlobalDisabled}}disabled{{end}}"{{if $isIssuesGlobalDisabled}} data-tooltip-content="{{ctx.Locale.Tr "repo.unit_disabled"}}"{{end}}>
|
||||||
<input class="enable-system-radio" name="enable_external_tracker" type="radio" value="false" data-context="#internal_issue_box" data-target="#external_issue_box" {{if not (.Repository.UnitEnabled ctx ctx.Consts.RepoUnitTypeExternalTracker)}}checked{{end}}>
|
<input class="enable-system" name="enable_internal_tracker" type="checkbox" data-target="#internal_issue_box" {{if $isInternalTrackerEnabled}}checked{{end}}>
|
||||||
<label>{{ctx.Locale.Tr "repo.settings.use_internal_issue_tracker"}}</label>
|
<label>{{ctx.Locale.Tr "repo.settings.use_internal_issue_tracker"}}</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="field tw-pl-4 {{if (.Repository.UnitEnabled ctx ctx.Consts.RepoUnitTypeExternalTracker)}}disabled{{end}}" id="internal_issue_box">
|
<div class="field tw-pl-4 {{if not $isInternalTrackerEnabled}}disabled{{end}}" id="internal_issue_box">
|
||||||
{{if .Repository.CanEnableTimetracker}}
|
{{if .Repository.CanEnableTimetracker}}
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<div class="ui checkbox">
|
<div class="ui checkbox">
|
||||||
@@ -401,13 +395,15 @@
|
|||||||
<label>{{ctx.Locale.Tr "repo.settings.admin_enable_close_issues_via_commit_in_any_branch"}}</label>
|
<label>{{ctx.Locale.Tr "repo.settings.admin_enable_close_issues_via_commit_in_any_branch"}}</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{{$isExternalTrackerEnabled := .Repository.UnitEnabled ctx ctx.Consts.RepoUnitTypeExternalTracker}}
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<div class="ui radio checkbox{{if $isExternalTrackerGlobalDisabled}} disabled{{end}}"{{if $isExternalTrackerGlobalDisabled}} data-tooltip-content="{{ctx.Locale.Tr "repo.unit_disabled"}}"{{end}}>
|
<div class="ui checkbox {{if $isExternalTrackerGlobalDisabled}}disabled{{end}}" {{if $isExternalTrackerGlobalDisabled}}data-tooltip-content="{{ctx.Locale.Tr "repo.unit_disabled"}}"{{end}}>
|
||||||
<input class="enable-system-radio" name="enable_external_tracker" type="radio" value="true" data-context="#internal_issue_box" data-target="#external_issue_box" {{if .Repository.UnitEnabled ctx ctx.Consts.RepoUnitTypeExternalTracker}}checked{{end}}>
|
<input class="enable-system" name="enable_external_tracker" type="checkbox" data-target="#external_issue_box" {{if $isExternalTrackerEnabled}}checked{{end}}>
|
||||||
<label>{{ctx.Locale.Tr "repo.settings.use_external_issue_tracker"}}</label>
|
<label>{{ctx.Locale.Tr "repo.settings.use_external_issue_tracker"}}</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="field tw-pl-4 {{if not (.Repository.UnitEnabled ctx ctx.Consts.RepoUnitTypeExternalTracker)}}disabled{{end}}" id="external_issue_box">
|
<div class="field tw-pl-4 {{if not $isExternalTrackerEnabled}}disabled{{end}}" id="external_issue_box">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label for="external_tracker_url">{{ctx.Locale.Tr "repo.settings.external_tracker_url"}}</label>
|
<label for="external_tracker_url">{{ctx.Locale.Tr "repo.settings.external_tracker_url"}}</label>
|
||||||
<input id="external_tracker_url" name="external_tracker_url" type="url" value="{{(.Repository.MustGetUnit ctx ctx.Consts.RepoUnitTypeExternalTracker).ExternalTrackerConfig.ExternalTrackerURL}}">
|
<input id="external_tracker_url" name="external_tracker_url" type="url" value="{{(.Repository.MustGetUnit ctx ctx.Consts.RepoUnitTypeExternalTracker).ExternalTrackerConfig.ExternalTrackerURL}}">
|
||||||
@@ -418,9 +414,12 @@
|
|||||||
<input id="tracker_url_format" name="tracker_url_format" type="url" value="{{(.Repository.MustGetUnit ctx ctx.Consts.RepoUnitTypeExternalTracker).ExternalTrackerConfig.ExternalTrackerFormat}}" placeholder="https://github.com/{user}/{repo}/issues/{index}">
|
<input id="tracker_url_format" name="tracker_url_format" type="url" value="{{(.Repository.MustGetUnit ctx ctx.Consts.RepoUnitTypeExternalTracker).ExternalTrackerConfig.ExternalTrackerFormat}}" placeholder="https://github.com/{user}/{repo}/issues/{index}">
|
||||||
<p class="help">{{ctx.Locale.Tr "repo.settings.tracker_url_format_desc"}}</p>
|
<p class="help">{{ctx.Locale.Tr "repo.settings.tracker_url_format_desc"}}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="inline fields">
|
<div class="field tw-m-0">
|
||||||
<label for="issue_style">{{ctx.Locale.Tr "repo.settings.tracker_issue_style"}}</label>
|
<label>{{ctx.Locale.Tr "repo.settings.tracker_issue_style"}}</label>
|
||||||
<div class="field">
|
<p class="help">{{ctx.Locale.Tr "repo.settings.tracker_issue_style_desc"}}</p>
|
||||||
|
</div>
|
||||||
|
<div class="flex-text-block flex-wrap tw-gap-4 tw-mb-2">
|
||||||
|
<div>
|
||||||
<div class="ui radio checkbox">
|
<div class="ui radio checkbox">
|
||||||
{{$externalTracker := (.Repository.MustGetUnit ctx ctx.Consts.RepoUnitTypeExternalTracker)}}
|
{{$externalTracker := (.Repository.MustGetUnit ctx ctx.Consts.RepoUnitTypeExternalTracker)}}
|
||||||
{{$externalTrackerStyle := $externalTracker.ExternalTrackerConfig.ExternalTrackerStyle}}
|
{{$externalTrackerStyle := $externalTracker.ExternalTrackerConfig.ExternalTrackerStyle}}
|
||||||
@@ -428,13 +427,13 @@
|
|||||||
<label>{{ctx.Locale.Tr "repo.settings.tracker_issue_style.numeric"}} <span class="ui light grey text">#1234</span></label>
|
<label>{{ctx.Locale.Tr "repo.settings.tracker_issue_style.numeric"}} <span class="ui light grey text">#1234</span></label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div>
|
||||||
<div class="ui radio checkbox">
|
<div class="ui radio checkbox">
|
||||||
<input class="js-tracker-issue-style" name="tracker_issue_style" type="radio" value="alphanumeric" {{if eq $externalTrackerStyle "alphanumeric"}}checked{{end}}>
|
<input class="js-tracker-issue-style" name="tracker_issue_style" type="radio" value="alphanumeric" {{if eq $externalTrackerStyle "alphanumeric"}}checked{{end}}>
|
||||||
<label>{{ctx.Locale.Tr "repo.settings.tracker_issue_style.alphanumeric"}} <span class="ui light grey text">ABC-123 , DEFG-234</span></label>
|
<label>{{ctx.Locale.Tr "repo.settings.tracker_issue_style.alphanumeric"}} <span class="ui light grey text">ABC-123 , DEFG-234</span></label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div>
|
||||||
<div class="ui radio checkbox">
|
<div class="ui radio checkbox">
|
||||||
<input class="js-tracker-issue-style" name="tracker_issue_style" type="radio" value="regexp" {{if eq $externalTrackerStyle "regexp"}}checked{{end}}>
|
<input class="js-tracker-issue-style" name="tracker_issue_style" type="radio" value="regexp" {{if eq $externalTrackerStyle "regexp"}}checked{{end}}>
|
||||||
<label>{{ctx.Locale.Tr "repo.settings.tracker_issue_style.regexp"}} <span class="ui light grey text">(ISSUE-\d+) , ISSUE-(\d+)</span></label>
|
<label>{{ctx.Locale.Tr "repo.settings.tracker_issue_style.regexp"}} <span class="ui light grey text">(ISSUE-\d+) , ISSUE-(\d+)</span></label>
|
||||||
|
|||||||
@@ -16,7 +16,10 @@ import (
|
|||||||
"gitea.dev/models/unittest"
|
"gitea.dev/models/unittest"
|
||||||
user_model "gitea.dev/models/user"
|
user_model "gitea.dev/models/user"
|
||||||
"gitea.dev/modules/git"
|
"gitea.dev/modules/git"
|
||||||
|
"gitea.dev/modules/setting"
|
||||||
api "gitea.dev/modules/structs"
|
api "gitea.dev/modules/structs"
|
||||||
|
"gitea.dev/modules/test"
|
||||||
|
"gitea.dev/services/migrations"
|
||||||
mirror_service "gitea.dev/services/mirror"
|
mirror_service "gitea.dev/services/mirror"
|
||||||
"gitea.dev/tests"
|
"gitea.dev/tests"
|
||||||
|
|
||||||
@@ -42,7 +45,8 @@ func getRepoEditOptionFromRepo(repo *repo_model.Repository) *api.EditRepoOption
|
|||||||
AllowOnlyContributorsToTrackTime: config.AllowOnlyContributorsToTrackTime,
|
AllowOnlyContributorsToTrackTime: config.AllowOnlyContributorsToTrackTime,
|
||||||
EnableIssueDependencies: config.EnableDependencies,
|
EnableIssueDependencies: config.EnableDependencies,
|
||||||
}
|
}
|
||||||
} else if unit, err := repo.GetUnit(ctx, unit_model.TypeExternalTracker); err == nil {
|
}
|
||||||
|
if unit, err := repo.GetUnit(ctx, unit_model.TypeExternalTracker); err == nil {
|
||||||
config := unit.ExternalTrackerConfig()
|
config := unit.ExternalTrackerConfig()
|
||||||
hasIssues = true
|
hasIssues = true
|
||||||
externalTracker = &api.ExternalTracker{
|
externalTracker = &api.ExternalTracker{
|
||||||
@@ -460,6 +464,10 @@ func TestAPIRepoEdit(t *testing.T) {
|
|||||||
|
|
||||||
require.NoError(t, mirror_service.UpdateAddress(ctx, mirror, "https://existing-user:existing-password@example.com/user2/repo1.git"))
|
require.NoError(t, mirror_service.UpdateAddress(ctx, mirror, "https://existing-user:existing-password@example.com/user2/repo1.git"))
|
||||||
|
|
||||||
|
defer migrations.Init()
|
||||||
|
defer test.MockVariableValue(&setting.Migrations.AllowedDomains, "*")()
|
||||||
|
_ = migrations.Init()
|
||||||
|
|
||||||
req = NewRequestWithJSON(t, "PATCH", fmt.Sprintf("/api/v1/repos/%s/%s", mirrorRepo.OwnerName, mirrorRepo.Name), &api.EditRepoOption{
|
req = NewRequestWithJSON(t, "PATCH", fmt.Sprintf("/api/v1/repos/%s/%s", mirrorRepo.OwnerName, mirrorRepo.Name), &api.EditRepoOption{
|
||||||
MirrorPassword: &newPassword,
|
MirrorPassword: &newPassword,
|
||||||
}).AddTokenAuth(token2)
|
}).AddTokenAuth(token2)
|
||||||
@@ -521,7 +529,7 @@ func TestAPIRepoEditPullUpdateSettingsValidation(t *testing.T) {
|
|||||||
AllowMergeUpdate: &allowMergeUpdate,
|
AllowMergeUpdate: &allowMergeUpdate,
|
||||||
AllowRebaseUpdate: &allowRebaseUpdate,
|
AllowRebaseUpdate: &allowRebaseUpdate,
|
||||||
}).AddTokenAuth(token)
|
}).AddTokenAuth(token)
|
||||||
MakeRequest(t, req, http.StatusUnprocessableEntity)
|
MakeRequest(t, req, http.StatusBadRequest)
|
||||||
|
|
||||||
allowRebaseUpdate = true
|
allowRebaseUpdate = true
|
||||||
defaultUpdateStyle := string(repo_model.UpdateStyleMerge)
|
defaultUpdateStyle := string(repo_model.UpdateStyleMerge)
|
||||||
@@ -530,5 +538,5 @@ func TestAPIRepoEditPullUpdateSettingsValidation(t *testing.T) {
|
|||||||
AllowRebaseUpdate: &allowRebaseUpdate,
|
AllowRebaseUpdate: &allowRebaseUpdate,
|
||||||
DefaultUpdateStyle: &defaultUpdateStyle,
|
DefaultUpdateStyle: &defaultUpdateStyle,
|
||||||
}).AddTokenAuth(token)
|
}).AddTokenAuth(token)
|
||||||
MakeRequest(t, req, http.StatusUnprocessableEntity)
|
MakeRequest(t, req, http.StatusBadRequest)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -443,4 +443,11 @@ export function initGlobalFetchAction() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
registerGlobalSelectorFunc('[data-fetch-url]', initFetchActionTrigger);
|
registerGlobalSelectorFunc('[data-fetch-url]', initFetchActionTrigger);
|
||||||
|
|
||||||
|
// when the page is reloaded after a fetch action, scroll to the flash message if any
|
||||||
|
const elFlashMessage = document.querySelector('.ui.message.flash-message');
|
||||||
|
if (elFlashMessage) {
|
||||||
|
window.history.scrollRestoration = 'manual';
|
||||||
|
elFlashMessage?.scrollIntoView({block: 'center'});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user