1
1
mirror of https://github.com/go-gitea/gitea synced 2025-07-22 18:28:37 +00:00

Use CloseIssue and ReopenIssue instead of ChangeStatus (#32467)

The behaviors of closing issues and reopening issues are very different.
So splitting it into two different functions makes it easier to
maintain.

- [x] Split ChangeIssueStatus into CloseIssue and ReopenIssue both at
the service layer and model layer
- [x] Rename `isClosed` to `CloseOrReopen` to make it more readable.
- [x] Add transactions for ReopenIssue and CloseIssue

---------

Co-authored-by: Zettat123 <zettat123@gmail.com>
This commit is contained in:
Lunny Xiao
2024-12-24 23:38:30 -08:00
committed by GitHub
parent f44712f22b
commit 5feb1a6bff
11 changed files with 167 additions and 95 deletions

View File

@@ -733,7 +733,7 @@ func CreateIssue(ctx *context.APIContext) {
}
if form.Closed {
if err := issue_service.ChangeStatus(ctx, issue, ctx.Doer, "", true); err != nil {
if err := issue_service.CloseIssue(ctx, issue, ctx.Doer, ""); err != nil {
if issues_model.IsErrDependenciesLeft(err) {
ctx.Error(http.StatusPreconditionFailed, "DependenciesLeft", "cannot close this issue because it still has open dependencies")
return
@@ -912,27 +912,11 @@ func EditIssue(ctx *context.APIContext) {
}
}
var isClosed bool
switch state := api.StateType(*form.State); state {
case api.StateOpen:
isClosed = false
case api.StateClosed:
isClosed = true
default:
ctx.Error(http.StatusPreconditionFailed, "UnknownIssueStateError", fmt.Sprintf("unknown state: %s", state))
state := api.StateType(*form.State)
closeOrReopenIssue(ctx, issue, state)
if ctx.Written() {
return
}
if issue.IsClosed != isClosed {
if err := issue_service.ChangeStatus(ctx, issue, ctx.Doer, "", isClosed); err != nil {
if issues_model.IsErrDependenciesLeft(err) {
ctx.Error(http.StatusPreconditionFailed, "DependenciesLeft", "cannot close this issue because it still has open dependencies")
return
}
ctx.Error(http.StatusInternalServerError, "ChangeStatus", err)
return
}
}
}
// Refetch from database to assign some automatic values
@@ -1055,3 +1039,26 @@ func UpdateIssueDeadline(ctx *context.APIContext) {
ctx.JSON(http.StatusCreated, api.IssueDeadline{Deadline: deadlineUnix.AsTimePtr()})
}
func closeOrReopenIssue(ctx *context.APIContext, issue *issues_model.Issue, state api.StateType) {
if state != api.StateOpen && state != api.StateClosed {
ctx.Error(http.StatusPreconditionFailed, "UnknownIssueStateError", fmt.Sprintf("unknown state: %s", state))
return
}
if state == api.StateClosed && !issue.IsClosed {
if err := issue_service.CloseIssue(ctx, issue, ctx.Doer, ""); err != nil {
if issues_model.IsErrDependenciesLeft(err) {
ctx.Error(http.StatusPreconditionFailed, "DependenciesLeft", "cannot close this issue or pull request because it still has open dependencies")
return
}
ctx.Error(http.StatusInternalServerError, "CloseIssue", err)
return
}
} else if state == api.StateOpen && issue.IsClosed {
if err := issue_service.ReopenIssue(ctx, issue, ctx.Doer, ""); err != nil {
ctx.Error(http.StatusInternalServerError, "ReopenIssue", err)
return
}
}
}

View File

@@ -728,27 +728,11 @@ func EditPullRequest(ctx *context.APIContext) {
return
}
var isClosed bool
switch state := api.StateType(*form.State); state {
case api.StateOpen:
isClosed = false
case api.StateClosed:
isClosed = true
default:
ctx.Error(http.StatusPreconditionFailed, "UnknownPRStateError", fmt.Sprintf("unknown state: %s", state))
state := api.StateType(*form.State)
closeOrReopenIssue(ctx, issue, state)
if ctx.Written() {
return
}
if issue.IsClosed != isClosed {
if err := issue_service.ChangeStatus(ctx, issue, ctx.Doer, "", isClosed); err != nil {
if issues_model.IsErrDependenciesLeft(err) {
ctx.Error(http.StatusPreconditionFailed, "DependenciesLeft", "cannot close this pull request because it still has open dependencies")
return
}
ctx.Error(http.StatusInternalServerError, "ChangeStatus", err)
return
}
}
}
// change pull target branch

View File

@@ -154,25 +154,28 @@ func NewComment(ctx *context.Context) {
if pr != nil {
ctx.Flash.Info(ctx.Tr("repo.pulls.open_unmerged_pull_exists", pr.Index))
} else {
isClosed := form.Status == "close"
if err := issue_service.ChangeStatus(ctx, issue, ctx.Doer, "", isClosed); err != nil {
log.Error("ChangeStatus: %v", err)
if issues_model.IsErrDependenciesLeft(err) {
if issue.IsPull {
ctx.JSONError(ctx.Tr("repo.issues.dependency.pr_close_blocked"))
} else {
ctx.JSONError(ctx.Tr("repo.issues.dependency.issue_close_blocked"))
if form.Status == "close" && !issue.IsClosed {
if err := issue_service.CloseIssue(ctx, issue, ctx.Doer, ""); err != nil {
log.Error("CloseIssue: %v", err)
if issues_model.IsErrDependenciesLeft(err) {
if issue.IsPull {
ctx.JSONError(ctx.Tr("repo.issues.dependency.pr_close_blocked"))
} else {
ctx.JSONError(ctx.Tr("repo.issues.dependency.issue_close_blocked"))
}
return
}
return
} else {
if err := stopTimerIfAvailable(ctx, ctx.Doer, issue); err != nil {
ctx.ServerError("stopTimerIfAvailable", err)
return
}
log.Trace("Issue [%d] status changed to closed: %v", issue.ID, issue.IsClosed)
}
} else {
if err := stopTimerIfAvailable(ctx, ctx.Doer, issue); err != nil {
ctx.ServerError("CreateOrStopIssueStopwatch", err)
return
} else if form.Status == "reopen" && issue.IsClosed {
if err := issue_service.ReopenIssue(ctx, issue, ctx.Doer, ""); err != nil {
log.Error("ReopenIssue: %v", err)
}
log.Trace("Issue [%d] status changed to closed: %v", issue.ID, issue.IsClosed)
}
}
}

View File

@@ -418,14 +418,11 @@ func UpdateIssueStatus(ctx *context.Context) {
return
}
var isClosed bool
switch action := ctx.FormString("action"); action {
case "open":
isClosed = false
case "close":
isClosed = true
default:
action := ctx.FormString("action")
if action != "open" && action != "close" {
log.Warn("Unrecognized action: %s", action)
ctx.JSONOK()
return
}
if _, err := issues.LoadRepositories(ctx); err != nil {
@@ -441,15 +438,20 @@ func UpdateIssueStatus(ctx *context.Context) {
if issue.IsPull && issue.PullRequest.HasMerged {
continue
}
if issue.IsClosed != isClosed {
if err := issue_service.ChangeStatus(ctx, issue, ctx.Doer, "", isClosed); err != nil {
if action == "close" && !issue.IsClosed {
if err := issue_service.CloseIssue(ctx, issue, ctx.Doer, ""); err != nil {
if issues_model.IsErrDependenciesLeft(err) {
ctx.JSON(http.StatusPreconditionFailed, map[string]any{
"error": ctx.Tr("repo.issues.dependency.issue_batch_close_blocked", issue.Index),
})
return
}
ctx.ServerError("ChangeStatus", err)
ctx.ServerError("CloseIssue", err)
return
}
} else if action == "open" && issue.IsClosed {
if err := issue_service.ReopenIssue(ctx, issue, ctx.Doer, ""); err != nil {
ctx.ServerError("ReopenIssue", err)
return
}
}