From 1d01286f4c4503ab629fad8c5f78dd245c3245c1 Mon Sep 17 00:00:00 2001 From: Daniel Mach Date: Mon, 5 Jan 2026 18:00:26 +0100 Subject: [PATCH] Add 'allow_maintainer_edit' API option for creating a pull request (#36283) WebUI has a checkbox for enabling maintainer edits you can check right away when creating a new pull request. Also, it is possible to set `allow_maintainer_edit` in an existing pull request via API. This change enables the option while creating a new pull request via API. --------- Co-authored-by: wxiaoguang --- modules/structs/pull.go | 2 ++ routers/api/v1/repo/pull.go | 8 ++++++++ templates/swagger/v1_json.tmpl | 5 +++++ tests/integration/api_pull_test.go | 19 +++++++++++++++++-- 4 files changed, 32 insertions(+), 2 deletions(-) diff --git a/modules/structs/pull.go b/modules/structs/pull.go index 7cc58217a0..3ad2f78bd3 100644 --- a/modules/structs/pull.go +++ b/modules/structs/pull.go @@ -140,6 +140,8 @@ type CreatePullRequestOption struct { Reviewers []string `json:"reviewers"` // The list of team reviewer names TeamReviewers []string `json:"team_reviewers"` + // Whether maintainers can edit the pull request + AllowMaintainerEdit *bool `json:"allow_maintainer_edit"` } // EditPullRequestOption options when modify pull request diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go index 9b1eb3fc85..09eeefd2c7 100644 --- a/routers/api/v1/repo/pull.go +++ b/routers/api/v1/repo/pull.go @@ -25,6 +25,7 @@ import ( "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/timeutil" @@ -496,6 +497,11 @@ func CreatePullRequest(ctx *context.APIContext) { deadlineUnix = timeutil.TimeStamp(form.Deadline.Unix()) } + unitPullRequest, err := ctx.Repo.Repository.GetUnit(ctx, unit.TypePullRequests) + if err != nil { + ctx.APIErrorInternal(err) + } + prIssue := &issues_model.Issue{ RepoID: repo.ID, Title: form.Title, @@ -517,6 +523,8 @@ func CreatePullRequest(ctx *context.APIContext) { Type: issues_model.PullRequestGitea, } + pr.AllowMaintainerEdit = optional.FromPtr(form.AllowMaintainerEdit).ValueOrDefault(unitPullRequest.PullRequestsConfig().DefaultAllowMaintainerEdit) + // Get all assignee IDs assigneeIDs, err := issues_model.MakeIDsFromAPIAssigneesToAdd(ctx, form.Assignee, form.Assignees) if err != nil { diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index be6c4bdfd3..0c33227364 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -23420,6 +23420,11 @@ "description": "CreatePullRequestOption options when creating a pull request", "type": "object", "properties": { + "allow_maintainer_edit": { + "description": "Whether maintainers can edit the pull request", + "type": "boolean", + "x-go-name": "AllowMaintainerEdit" + }, "assignee": { "description": "The primary assignee username", "type": "string", diff --git a/tests/integration/api_pull_test.go b/tests/integration/api_pull_test.go index 433dce3d5e..0e1a88dcee 100644 --- a/tests/integration/api_pull_test.go +++ b/tests/integration/api_pull_test.go @@ -270,13 +270,20 @@ func TestAPICreatePullSuccess(t *testing.T) { owner11 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo11.OwnerID}) session := loginUser(t, owner11.Name) + prTitle := "test pull request title " + time.Now().String() token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository) req := NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls", owner10.Name, repo10.Name), &api.CreatePullRequestOption{ Head: owner11.Name + ":master", Base: "master", - Title: "create a failure pr", + Title: prTitle, }).AddTokenAuth(token) MakeRequest(t, req, http.StatusCreated) + + // Also test that AllowMaintainerEdit is false by default + prIssue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{Title: prTitle}) + pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{IssueID: prIssue.ID}) + assert.False(t, pr.AllowMaintainerEdit) + MakeRequest(t, req, http.StatusUnprocessableEntity) // second request should fail } @@ -290,11 +297,14 @@ func TestAPICreatePullBasePermission(t *testing.T) { user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) session := loginUser(t, user4.Name) + prTitle := "test pull request title " + time.Now().String() token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository) opts := &api.CreatePullRequestOption{ Head: repo11.OwnerName + ":master", Base: "master", - Title: "create a failure pr", + Title: prTitle, + + AllowMaintainerEdit: util.ToPointer(true), } req := NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls", owner10.Name, repo10.Name), &opts).AddTokenAuth(token) MakeRequest(t, req, http.StatusForbidden) @@ -306,6 +316,11 @@ func TestAPICreatePullBasePermission(t *testing.T) { // create again req = NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls", owner10.Name, repo10.Name), &opts).AddTokenAuth(token) MakeRequest(t, req, http.StatusCreated) + + // Also test that AllowMaintainerEdit is set to true + prIssue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{Title: prTitle}) + pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{IssueID: prIssue.ID}) + assert.True(t, pr.AllowMaintainerEdit) } func TestAPICreatePullHeadPermission(t *testing.T) {