diff --git a/modules/migration/release.go b/modules/migration/release.go index f92cf25e7b..e25e7e4428 100644 --- a/modules/migration/release.go +++ b/modules/migration/release.go @@ -10,9 +10,12 @@ import ( // ReleaseAsset represents a release asset type ReleaseAsset struct { - ID int64 - Name string - ContentType *string `yaml:"content_type"` + ID int64 + Name string + + // There was a field "ContentType (content_type)" because Some forges can provide that for assets, + // but we don't need it when migrating, so the field is omitted here. + Size *int DownloadCount *int `yaml:"download_count"` Created time.Time 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 c6cc16e41a..135da1278e 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/routers/web/repo/pull.go b/routers/web/repo/pull.go index ad4d3da294..7c67d614f6 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -1390,6 +1390,7 @@ func CompareAndPullRequestPost(ctx *context.Context) { AssigneeIDs: assigneeIDs, Reviewers: validateRet.Reviewers, TeamReviewers: validateRet.TeamReviewers, + ProjectID: projectID, } if err := pull_service.NewPullRequest(ctx, prOpts); err != nil { switch { @@ -1441,15 +1442,6 @@ func CompareAndPullRequestPost(ctx *context.Context) { return } - if projectID > 0 && ctx.Repo.CanWrite(unit.TypeProjects) { - if err := issues_model.IssueAssignOrRemoveProject(ctx, pullIssue, ctx.Doer, projectID, 0); err != nil { - if !errors.Is(err, util.ErrPermissionDenied) { - ctx.ServerError("IssueAssignOrRemoveProject", err) - return - } - } - } - log.Trace("Pull request created: %d/%d", repo.ID, pullIssue.ID) ctx.JSONRedirect(pullIssue.Link()) } diff --git a/services/forms/repo_form.go b/services/forms/repo_form.go index 2d33d2b42b..e4545570c8 100644 --- a/services/forms/repo_form.go +++ b/services/forms/repo_form.go @@ -405,13 +405,6 @@ func (f *NewPackagistHookForm) Validate(req *http.Request, errs binding.Errors) return middleware.Validate(errs, ctx.Data, f, ctx.Locale) } -// .___ -// | | ______ ________ __ ____ -// | |/ ___// ___/ | \_/ __ \ -// | |\___ \ \___ \| | /\ ___/ -// |___/____ >____ >____/ \___ > -// \/ \/ \/ - // CreateIssueForm form for creating issue type CreateIssueForm struct { Title string `binding:"Required;MaxSize(255)"` diff --git a/services/migrations/github.go b/services/migrations/github.go index ae7350c016..ce631dcd42 100644 --- a/services/migrations/github.go +++ b/services/migrations/github.go @@ -329,7 +329,6 @@ func (g *GithubDownloaderV3) convertGithubRelease(ctx context.Context, rel *gith r.Assets = append(r.Assets, &base.ReleaseAsset{ ID: asset.GetID(), Name: asset.GetName(), - ContentType: asset.ContentType, Size: asset.Size, DownloadCount: asset.DownloadCount, Created: asset.CreatedAt.Time, diff --git a/services/migrations/gitlab.go b/services/migrations/gitlab.go index 260fa9cd5d..cbf974af2c 100644 --- a/services/migrations/gitlab.go +++ b/services/migrations/gitlab.go @@ -316,12 +316,11 @@ func (g *GitlabDownloader) convertGitlabRelease(ctx context.Context, rel *gitlab httpClient := NewMigrationHTTPClient() - for k, asset := range rel.Assets.Links { + for _, asset := range rel.Assets.Links { assetID := asset.ID // Don't optimize this, for closure we need a local variable r.Assets = append(r.Assets, &base.ReleaseAsset{ ID: int64(asset.ID), Name: asset.Name, - ContentType: &rel.Assets.Sources[k].Format, Size: &zero, DownloadCount: &zero, DownloadFunc: func() (io.ReadCloser, error) { diff --git a/services/migrations/main_test.go b/services/migrations/main_test.go index d0ec6a3f8d..581af614f9 100644 --- a/services/migrations/main_test.go +++ b/services/migrations/main_test.go @@ -171,7 +171,6 @@ func assertReactionsEqual(t *testing.T, expected, actual []*base.Reaction) { func assertReleaseAssetEqual(t *testing.T, expected, actual *base.ReleaseAsset) { assert.Equal(t, expected.ID, actual.ID) assert.Equal(t, expected.Name, actual.Name) - assert.Equal(t, expected.ContentType, actual.ContentType) assert.Equal(t, expected.Size, actual.Size) assert.Equal(t, expected.DownloadCount, actual.DownloadCount) assertTimeEqual(t, expected.Created, actual.Created) diff --git a/services/pull/pull.go b/services/pull/pull.go index 9ed2605417..ff5c562001 100644 --- a/services/pull/pull.go +++ b/services/pull/pull.go @@ -52,6 +52,7 @@ type NewPullRequestOptions struct { AssigneeIDs []int64 Reviewers []*user_model.User TeamReviewers []*organization.Team + ProjectID int64 } // NewPullRequest creates new pull request with labels for repository. @@ -67,11 +68,13 @@ func NewPullRequest(ctx context.Context, opts *NewPullRequestOptions) error { // user should be a collaborator or a member of the organization for base repo canCreate := issue.Poster.IsAdmin || pr.Flow == issues_model.PullRequestFlowAGit + canAssignProject := canCreate if !canCreate { canCreate, err := repo_model.IsOwnerMemberCollaborator(ctx, repo, issue.Poster.ID) if err != nil { return err } + canAssignProject = canCreate if !canCreate { // or user should have write permission in the head repo @@ -85,6 +88,7 @@ func NewPullRequest(ctx context.Context, opts *NewPullRequestOptions) error { if !perm.CanWrite(unit.TypeCode) { return issues_model.ErrMustCollaborator } + canAssignProject = perm.CanWrite(unit.TypeProjects) } } @@ -117,6 +121,12 @@ func NewPullRequest(ctx context.Context, opts *NewPullRequestOptions) error { assigneeCommentMap[assigneeID] = comment } + if opts.ProjectID > 0 && canAssignProject { + if err := issues_model.IssueAssignOrRemoveProject(ctx, issue, issue.Poster, opts.ProjectID, 0); err != nil { + return err + } + } + pr.Issue = issue issue.PullRequest = pr 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) {