loading up the forgejo repo on tangled to test page performance
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge pull request 'fix(api): issue state change is not idempotent' (#4687) from earl-warren/forgejo:wip-issue-state-idempotency into forgejo

Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/4687
Reviewed-by: Michael Kriese <michael.kriese@gmx.de>
Reviewed-by: Gusted <gusted@noreply.codeberg.org>

+44 -12
+8 -5
routers/api/v1/repo/issue.go
··· 893 893 return 894 894 } 895 895 } 896 - if err := issue_service.ChangeStatus(ctx, issue, ctx.Doer, "", api.StateClosed == api.StateType(*form.State)); err != nil { 897 - if issues_model.IsErrDependenciesLeft(err) { 898 - ctx.Error(http.StatusPreconditionFailed, "DependenciesLeft", "cannot close this issue because it still has open dependencies") 896 + isClosed := api.StateClosed == api.StateType(*form.State) 897 + if issue.IsClosed != isClosed { 898 + if err := issue_service.ChangeStatus(ctx, issue, ctx.Doer, "", isClosed); err != nil { 899 + if issues_model.IsErrDependenciesLeft(err) { 900 + ctx.Error(http.StatusPreconditionFailed, "DependenciesLeft", "cannot close this issue because it still has open dependencies") 901 + return 902 + } 903 + ctx.Error(http.StatusInternalServerError, "ChangeStatus", err) 899 904 return 900 905 } 901 - ctx.Error(http.StatusInternalServerError, "ChangeStatus", err) 902 - return 903 906 } 904 907 } 905 908
+8 -5
routers/api/v1/repo/pull.go
··· 711 711 ctx.Error(http.StatusPreconditionFailed, "MergedPRState", "cannot change state of this pull request, it was already merged") 712 712 return 713 713 } 714 - if err := issue_service.ChangeStatus(ctx, issue, ctx.Doer, "", api.StateClosed == api.StateType(*form.State)); err != nil { 715 - if issues_model.IsErrDependenciesLeft(err) { 716 - ctx.Error(http.StatusPreconditionFailed, "DependenciesLeft", "cannot close this pull request because it still has open dependencies") 714 + isClosed := api.StateClosed == api.StateType(*form.State) 715 + if issue.IsClosed != isClosed { 716 + if err := issue_service.ChangeStatus(ctx, issue, ctx.Doer, "", isClosed); err != nil { 717 + if issues_model.IsErrDependenciesLeft(err) { 718 + ctx.Error(http.StatusPreconditionFailed, "DependenciesLeft", "cannot close this pull request because it still has open dependencies") 719 + return 720 + } 721 + ctx.Error(http.StatusInternalServerError, "ChangeStatus", err) 717 722 return 718 723 } 719 - ctx.Error(http.StatusInternalServerError, "ChangeStatus", err) 720 - return 721 724 } 722 725 } 723 726
+15
tests/integration/api_issue_test.go
··· 215 215 assert.Equal(t, int64(0), int64(issueAfter.DeadlineUnix)) 216 216 assert.Equal(t, body, issueAfter.Content) 217 217 assert.Equal(t, title, issueAfter.Title) 218 + 219 + // verify the idempotency of state, milestone, body and title changes 220 + req = NewRequestWithJSON(t, "PATCH", urlStr, api.EditIssueOption{ 221 + State: &issueState, 222 + Milestone: &milestone, 223 + Body: &body, 224 + Title: title, 225 + }).AddTokenAuth(token) 226 + resp = MakeRequest(t, req, http.StatusCreated) 227 + var apiIssueIdempotent api.Issue 228 + DecodeJSON(t, resp, &apiIssueIdempotent) 229 + assert.Equal(t, apiIssue.State, apiIssueIdempotent.State) 230 + assert.Equal(t, apiIssue.Milestone.Title, apiIssueIdempotent.Milestone.Title) 231 + assert.Equal(t, apiIssue.Body, apiIssueIdempotent.Body) 232 + assert.Equal(t, apiIssue.Title, apiIssueIdempotent.Title) 218 233 } 219 234 220 235 func TestAPIEditIssueAutoDate(t *testing.T) {
+13 -2
tests/integration/api_pull_test.go
··· 236 236 237 237 newTitle := "edit a this pr" 238 238 newBody := "edited body" 239 - req = NewRequestWithJSON(t, http.MethodPatch, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d", owner10.Name, repo10.Name, apiPull.Index), &api.EditPullRequestOption{ 239 + urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d", owner10.Name, repo10.Name, apiPull.Index) 240 + req = NewRequestWithJSON(t, http.MethodPatch, urlStr, &api.EditPullRequestOption{ 240 241 Base: "feature/1", 241 242 Title: newTitle, 242 243 Body: &newBody, ··· 251 252 unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: pull.Issue.ID, OldTitle: title, NewTitle: newTitle}) 252 253 unittest.AssertExistsAndLoadBean(t, &issues_model.ContentHistory{IssueID: pull.Issue.ID, ContentText: newBody, IsFirstCreated: false}) 253 254 254 - req = NewRequestWithJSON(t, http.MethodPatch, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d", owner10.Name, repo10.Name, pull.Index), &api.EditPullRequestOption{ 255 + // verify the idempotency of a state change 256 + pullState := string(apiPull.State) 257 + req = NewRequestWithJSON(t, http.MethodPatch, urlStr, &api.EditPullRequestOption{ 258 + State: &pullState, 259 + }).AddTokenAuth(token) 260 + apiPullIdempotent := new(api.PullRequest) 261 + resp = MakeRequest(t, req, http.StatusCreated) 262 + DecodeJSON(t, resp, apiPullIdempotent) 263 + assert.EqualValues(t, apiPull.State, apiPullIdempotent.State) 264 + 265 + req = NewRequestWithJSON(t, http.MethodPatch, urlStr, &api.EditPullRequestOption{ 255 266 Base: "not-exist", 256 267 }).AddTokenAuth(token) 257 268 MakeRequest(t, req, http.StatusNotFound)