mirror of
https://github.com/go-gitea/gitea.git
synced 2026-09-21 20: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:
+22
-29
@@ -25,6 +25,7 @@ import (
|
||||
"gitea.dev/modules/git"
|
||||
"gitea.dev/modules/label"
|
||||
"gitea.dev/modules/log"
|
||||
"gitea.dev/modules/markup"
|
||||
"gitea.dev/modules/optional"
|
||||
repo_module "gitea.dev/modules/repository"
|
||||
"gitea.dev/modules/setting"
|
||||
@@ -612,6 +613,7 @@ func Edit(ctx *context.APIContext) {
|
||||
}
|
||||
|
||||
if err := updateRepoUnits(ctx, opts); err != nil {
|
||||
ctx.APIErrorAuto(err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -750,24 +752,21 @@ func updateBasicProperties(ctx *context.APIContext, opts api.EditRepoOption) err
|
||||
|
||||
// updateRepoUnits updates repo units: Issue settings, Wiki settings, PR settings
|
||||
func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error {
|
||||
owner := ctx.Repo.Owner
|
||||
repo := ctx.Repo.Repository
|
||||
|
||||
var units []repo_model.RepoUnit
|
||||
var deleteUnitTypes []unit_model.Type
|
||||
|
||||
if opts.HasIssues != nil {
|
||||
if *opts.HasIssues && opts.ExternalTracker != nil && !unit_model.TypeExternalTracker.UnitGlobalDisabled() {
|
||||
// Check that values are valid
|
||||
if !validation.IsValidURL(opts.ExternalTracker.ExternalTrackerURL) {
|
||||
err := errors.New("External tracker URL not valid")
|
||||
ctx.APIError(http.StatusUnprocessableEntity, err.Error())
|
||||
return err
|
||||
if opts.HasIssues != nil && *opts.HasIssues {
|
||||
if opts.ExternalTracker != nil && !unit_model.TypeExternalTracker.UnitGlobalDisabled() {
|
||||
if (opts.InternalTracker == nil || opts.ExternalTracker.ExternalTrackerURL != "") && !validation.IsValidURL(opts.ExternalTracker.ExternalTrackerURL) {
|
||||
return util.ErrorWrap(util.ErrUnprocessableContent, "external tracker URL not valid")
|
||||
}
|
||||
if len(opts.ExternalTracker.ExternalTrackerFormat) != 0 && !validation.IsValidExternalTrackerURLFormat(opts.ExternalTracker.ExternalTrackerFormat) {
|
||||
err := errors.New("External tracker URL format not valid")
|
||||
ctx.APIError(http.StatusUnprocessableEntity, err.Error())
|
||||
return err
|
||||
if opts.InternalTracker != nil && (opts.ExternalTracker.ExternalTrackerStyle == "" || opts.ExternalTracker.ExternalTrackerStyle == markup.IssueNameStyleNumeric) {
|
||||
return util.ErrorWrap(util.ErrUnprocessableContent, "external tracker style Numeric is only used for internal tracker")
|
||||
}
|
||||
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{
|
||||
@@ -780,8 +779,10 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error {
|
||||
ExternalTrackerRegexpPattern: opts.ExternalTracker.ExternalTrackerRegexpPattern,
|
||||
},
|
||||
})
|
||||
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeIssues)
|
||||
} else if *opts.HasIssues && opts.ExternalTracker == nil && !unit_model.TypeIssues.UnitGlobalDisabled() {
|
||||
} else {
|
||||
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeExternalTracker)
|
||||
}
|
||||
if (opts.ExternalTracker == nil || opts.InternalTracker != nil) && !unit_model.TypeIssues.UnitGlobalDisabled() {
|
||||
// Default to built-in tracker
|
||||
var config *repo_model.IssuesConfig
|
||||
|
||||
@@ -807,24 +808,20 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error {
|
||||
Type: unit_model.TypeIssues,
|
||||
Config: config,
|
||||
})
|
||||
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeExternalTracker)
|
||||
} else if !*opts.HasIssues {
|
||||
if !unit_model.TypeExternalTracker.UnitGlobalDisabled() {
|
||||
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeExternalTracker)
|
||||
}
|
||||
if !unit_model.TypeIssues.UnitGlobalDisabled() {
|
||||
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeIssues)
|
||||
}
|
||||
} else {
|
||||
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 && opts.ExternalWiki != nil && !unit_model.TypeExternalWiki.UnitGlobalDisabled() {
|
||||
// Check that values are valid
|
||||
if !validation.IsValidURL(opts.ExternalWiki.ExternalWikiURL) {
|
||||
err := errors.New("External wiki URL not valid")
|
||||
ctx.APIError(http.StatusUnprocessableEntity, "Invalid external wiki URL")
|
||||
return err
|
||||
return util.ErrorWrap(util.ErrUnprocessableContent, "external wiki URL not valid")
|
||||
}
|
||||
|
||||
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.
|
||||
if opts.AllowMergeUpdate != nil || opts.AllowRebaseUpdate != nil || opts.DefaultUpdateStyle != nil {
|
||||
if err := config.ValidateUpdateSettings(); err != nil {
|
||||
ctx.APIError(http.StatusUnprocessableEntity, err.Error())
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -977,12 +973,9 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error {
|
||||
|
||||
if len(units)+len(deleteUnitTypes) > 0 {
|
||||
if err := repo_service.UpdateRepositoryUnits(ctx, repo, units, deleteUnitTypes); err != nil {
|
||||
ctx.APIErrorInternal(err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
log.Trace("Repository advanced settings updated: %s/%s", owner.Name, repo.Name)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -96,10 +96,13 @@ func MustEnableIssues(ctx *context.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
unit, err := ctx.Repo.Repository.GetUnit(ctx, unit.TypeExternalTracker)
|
||||
unitExtTracker, err := ctx.Repo.Repository.GetUnit(ctx, unit.TypeExternalTracker)
|
||||
if err == nil {
|
||||
ctx.Redirect(unit.ExternalTrackerConfig().ExternalTrackerURL)
|
||||
return
|
||||
extURL := unitExtTracker.ExternalTrackerConfig().ExternalTrackerURL
|
||||
if extURL != "" {
|
||||
ctx.Redirect(extURL)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ import (
|
||||
"gitea.dev/modules/indexer/stats"
|
||||
"gitea.dev/modules/lfs"
|
||||
"gitea.dev/modules/log"
|
||||
"gitea.dev/modules/markup"
|
||||
"gitea.dev/modules/setting"
|
||||
"gitea.dev/modules/structs"
|
||||
"gitea.dev/modules/templates"
|
||||
@@ -570,10 +571,6 @@ func handleSettingsPostAdvanced(ctx *context.Context) {
|
||||
var units []repo_model.RepoUnit
|
||||
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 {
|
||||
repo.CloseIssuesViaCommitInAnyBranch = form.EnableCloseIssuesViaCommitInAnyBranch
|
||||
repoChanged = true
|
||||
@@ -587,8 +584,7 @@ func handleSettingsPostAdvanced(ctx *context.Context) {
|
||||
|
||||
if form.EnableWiki && form.EnableExternalWiki && !unit_model.TypeExternalWiki.UnitGlobalDisabled() {
|
||||
if !validation.IsValidURL(form.ExternalWikiURL) {
|
||||
ctx.Flash.Error(ctx.Tr("repo.settings.external_wiki_url_error"))
|
||||
ctx.Redirect(repo.Link() + "/settings")
|
||||
ctx.JSONError(ctx.Tr("repo.settings.external_wiki_url_error"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -611,19 +607,21 @@ func handleSettingsPostAdvanced(ctx *context.Context) {
|
||||
if form.DefaultWikiBranch != "" {
|
||||
if err := wiki_service.ChangeDefaultWikiBranch(ctx, repo, form.DefaultWikiBranch); err != nil {
|
||||
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 !validation.IsValidURL(form.ExternalTrackerURL) {
|
||||
ctx.Flash.Error(ctx.Tr("repo.settings.external_tracker_url_error"))
|
||||
ctx.Redirect(repo.Link() + "/settings")
|
||||
if form.EnableExternalTracker && !unit_model.TypeExternalTracker.UnitGlobalDisabled() {
|
||||
if (!form.EnableInternalTracker || form.ExternalTrackerURL != "") && !validation.IsValidURL(form.ExternalTrackerURL) {
|
||||
ctx.JSONError(ctx.Tr("repo.settings.external_tracker_url_error"))
|
||||
return
|
||||
}
|
||||
if len(form.TrackerURLFormat) != 0 && !validation.IsValidExternalTrackerURLFormat(form.TrackerURLFormat) {
|
||||
ctx.Flash.Error(ctx.Tr("repo.settings.tracker_url_format_error"))
|
||||
ctx.Redirect(repo.Link() + "/settings")
|
||||
if form.TrackerURLFormat != "" && !validation.IsValidExternalTrackerURLFormat(form.TrackerURLFormat) {
|
||||
ctx.JSONError(ctx.Tr("repo.settings.tracker_url_format_error"))
|
||||
return
|
||||
}
|
||||
if form.EnableInternalTracker && (form.TrackerIssueStyle == "" || form.TrackerIssueStyle == markup.IssueNameStyleNumeric) {
|
||||
ctx.JSONError(ctx.Tr("repo.settings.tracker_issue_style_desc"))
|
||||
return
|
||||
}
|
||||
units = append(units, newRepoUnit(repo, unit_model.TypeExternalTracker, &repo_model.ExternalTrackerConfig{
|
||||
@@ -632,21 +630,18 @@ func handleSettingsPostAdvanced(ctx *context.Context) {
|
||||
ExternalTrackerStyle: form.TrackerIssueStyle,
|
||||
ExternalTrackerRegexpPattern: form.ExternalTrackerRegexpPattern,
|
||||
}))
|
||||
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeIssues)
|
||||
} else if form.EnableIssues && !form.EnableExternalTracker && !unit_model.TypeIssues.UnitGlobalDisabled() {
|
||||
} else {
|
||||
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeExternalTracker)
|
||||
}
|
||||
|
||||
if form.EnableInternalTracker && !unit_model.TypeIssues.UnitGlobalDisabled() {
|
||||
units = append(units, newRepoUnit(repo, unit_model.TypeIssues, &repo_model.IssuesConfig{
|
||||
EnableTimetracker: form.EnableTimetracker,
|
||||
AllowOnlyContributorsToTrackTime: form.AllowOnlyContributorsToTrackTime,
|
||||
EnableDependencies: form.EnableIssueDependencies,
|
||||
}))
|
||||
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeExternalTracker)
|
||||
} else {
|
||||
if !unit_model.TypeExternalTracker.UnitGlobalDisabled() {
|
||||
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeExternalTracker)
|
||||
}
|
||||
if !unit_model.TypeIssues.UnitGlobalDisabled() {
|
||||
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeIssues)
|
||||
}
|
||||
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeIssues)
|
||||
}
|
||||
|
||||
if form.EnableProjects && !unit_model.TypeProjects.UnitGlobalDisabled() {
|
||||
@@ -689,8 +684,7 @@ func handleSettingsPostAdvanced(ctx *context.Context) {
|
||||
DefaultTargetBranch: strings.TrimSpace(form.DefaultTargetBranch),
|
||||
}
|
||||
if err := prConfig.ValidateUpdateSettings(); err != nil {
|
||||
ctx.Flash.Error(err.Error())
|
||||
ctx.Redirect(repo.Link() + "/settings")
|
||||
ctx.JSONErrorAuto(err)
|
||||
return
|
||||
}
|
||||
units = append(units, newRepoUnit(repo, unit_model.TypePullRequests, prConfig))
|
||||
@@ -699,8 +693,7 @@ func handleSettingsPostAdvanced(ctx *context.Context) {
|
||||
}
|
||||
|
||||
if len(units) == 0 {
|
||||
ctx.Flash.Error(ctx.Tr("repo.settings.update_settings_no_unit"))
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/settings")
|
||||
ctx.JSONError(ctx.Tr("repo.settings.update_settings_no_unit"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -714,10 +707,9 @@ func handleSettingsPostAdvanced(ctx *context.Context) {
|
||||
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.Redirect(ctx.Repo.RepoLink + "/settings")
|
||||
ctx.JSONRedirect("")
|
||||
}
|
||||
|
||||
func handleSettingsPostSigning(ctx *context.Context) {
|
||||
|
||||
Reference in New Issue
Block a user