Skip to content

Commit daf581f

Browse files
wxiaoguangsilverwindclaude
authored
Add tests for pull request's content_version in API (#37044)
Co-authored-by: silverwind <me@silverwind.io> Co-authored-by: Claude (Opus 4.6) <noreply@anthropic.com>
1 parent 9bb0aa1 commit daf581f

5 files changed

Lines changed: 72 additions & 9 deletions

File tree

modules/structs/issue.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,8 @@ type Issue struct {
8080
PullRequest *PullRequestMeta `json:"pull_request"`
8181
Repo *RepositoryMeta `json:"repository"`
8282

83-
PinOrder int `json:"pin_order"`
83+
PinOrder int `json:"pin_order"`
84+
// The version of the issue content for optimistic locking
8485
ContentVersion int `json:"content_version"`
8586
}
8687

@@ -115,7 +116,8 @@ type EditIssueOption struct {
115116
// swagger:strfmt date-time
116117
Deadline *time.Time `json:"due_date"`
117118
RemoveDeadline *bool `json:"unset_due_date"`
118-
ContentVersion *int `json:"content_version"`
119+
// The current version of the issue content to detect conflicts during editing
120+
ContentVersion *int `json:"content_version"`
119121
}
120122

121123
// EditDeadlineOption options for creating a deadline

modules/structs/pull.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,8 @@ type PullRequest struct {
9090
Closed *time.Time `json:"closed_at"`
9191

9292
// The pin order for the pull request
93-
PinOrder int `json:"pin_order"`
93+
PinOrder int `json:"pin_order"`
94+
// The version of the pull request content for optimistic locking
9495
ContentVersion int `json:"content_version"`
9596
}
9697

@@ -169,7 +170,8 @@ type EditPullRequestOption struct {
169170
RemoveDeadline *bool `json:"unset_due_date"`
170171
// Whether to allow maintainer edits
171172
AllowMaintainerEdit *bool `json:"allow_maintainer_edit"`
172-
ContentVersion *int `json:"content_version"`
173+
// The current version of the pull request content to detect conflicts during editing
174+
ContentVersion *int `json:"content_version"`
173175
}
174176

175177
// ChangedFile store information about files affected by the pull request

templates/swagger/v1_json.tmpl

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/integration/api_issue_test.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -472,8 +472,7 @@ func testAPIIssueContentVersion(t *testing.T) {
472472

473473
req := NewRequest(t, "GET", urlStr).AddTokenAuth(token)
474474
resp := MakeRequest(t, req, http.StatusOK)
475-
var before api.Issue
476-
DecodeJSON(t, resp, &before)
475+
before := DecodeJSON(t, resp, &api.Issue{})
477476
req = NewRequestWithJSON(t, "PATCH", urlStr, api.EditIssueOption{
478477
Body: new("updated body with correct version"),
479478
ContentVersion: new(before.ContentVersion),

tests/integration/api_pull_test.go

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -457,9 +457,8 @@ func TestAPIEditPull(t *testing.T) {
457457
Base: "master",
458458
Title: title,
459459
}).AddTokenAuth(token)
460-
apiPull := new(api.PullRequest)
461460
resp := MakeRequest(t, req, http.StatusCreated)
462-
DecodeJSON(t, resp, apiPull)
461+
apiPull := DecodeJSON(t, resp, &api.PullRequest{})
463462
assert.Equal(t, "master", apiPull.Base.Name)
464463

465464
newTitle := "edit a this pr"
@@ -470,8 +469,9 @@ func TestAPIEditPull(t *testing.T) {
470469
Body: &newBody,
471470
}).AddTokenAuth(token)
472471
resp = MakeRequest(t, req, http.StatusCreated)
473-
DecodeJSON(t, resp, apiPull)
472+
apiPull = DecodeJSON(t, resp, &api.PullRequest{})
474473
assert.Equal(t, "feature/1", apiPull.Base.Name)
474+
475475
// check comment history
476476
pull := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: apiPull.ID})
477477
err := pull.LoadIssue(t.Context())
@@ -483,6 +483,62 @@ func TestAPIEditPull(t *testing.T) {
483483
Base: "not-exist",
484484
}).AddTokenAuth(token)
485485
MakeRequest(t, req, http.StatusNotFound)
486+
487+
t.Run("PullContentVersion", func(t *testing.T) {
488+
testAPIPullContentVersion(t, pull.ID)
489+
})
490+
}
491+
492+
func testAPIPullContentVersion(t *testing.T, pullID int64) {
493+
pull := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: pullID})
494+
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: pull.BaseRepoID})
495+
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
496+
497+
session := loginUser(t, owner.Name)
498+
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
499+
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d", owner.Name, repo.Name, pull.Index)
500+
501+
t.Run("ResponseIncludesContentVersion", func(t *testing.T) {
502+
defer tests.PrintCurrentTest(t)()
503+
504+
req := NewRequest(t, "GET", urlStr).AddTokenAuth(token)
505+
resp := MakeRequest(t, req, http.StatusOK)
506+
apiPull := DecodeJSON(t, resp, &api.PullRequest{})
507+
assert.GreaterOrEqual(t, apiPull.ContentVersion, 0)
508+
})
509+
510+
t.Run("EditWithCorrectVersion", func(t *testing.T) {
511+
defer tests.PrintCurrentTest(t)()
512+
513+
req := NewRequest(t, "GET", urlStr).AddTokenAuth(token)
514+
resp := MakeRequest(t, req, http.StatusOK)
515+
before := DecodeJSON(t, resp, &api.PullRequest{})
516+
req = NewRequestWithJSON(t, "PATCH", urlStr, api.EditPullRequestOption{
517+
Body: new("updated body with correct version"),
518+
ContentVersion: new(before.ContentVersion),
519+
}).AddTokenAuth(token)
520+
resp = MakeRequest(t, req, http.StatusCreated)
521+
after := DecodeJSON(t, resp, &api.PullRequest{})
522+
assert.Equal(t, "updated body with correct version", after.Body)
523+
assert.Greater(t, after.ContentVersion, before.ContentVersion)
524+
})
525+
526+
t.Run("EditWithWrongVersion", func(t *testing.T) {
527+
defer tests.PrintCurrentTest(t)()
528+
req := NewRequestWithJSON(t, "PATCH", urlStr, api.EditPullRequestOption{
529+
Body: new("should fail"),
530+
ContentVersion: new(99999),
531+
}).AddTokenAuth(token)
532+
MakeRequest(t, req, http.StatusConflict)
533+
})
534+
535+
t.Run("EditWithoutVersion", func(t *testing.T) {
536+
defer tests.PrintCurrentTest(t)()
537+
req := NewRequestWithJSON(t, "PATCH", urlStr, api.EditPullRequestOption{
538+
Body: new("edit without version succeeds"),
539+
}).AddTokenAuth(token)
540+
MakeRequest(t, req, http.StatusCreated)
541+
})
486542
}
487543

488544
func doAPIGetPullFiles(ctx APITestContext, pr *api.PullRequest, callback func(*testing.T, []*api.ChangedFile)) func(*testing.T) {

0 commit comments

Comments
 (0)