aboutsummaryrefslogtreecommitdiffstats
path: root/routers/api/v1/repo/pull.go
diff options
context:
space:
mode:
Diffstat (limited to 'routers/api/v1/repo/pull.go')
-rw-r--r--routers/api/v1/repo/pull.go314
1 files changed, 170 insertions, 144 deletions
diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go
index f7fdc93f81..2c194f9253 100644
--- a/routers/api/v1/repo/pull.go
+++ b/routers/api/v1/repo/pull.go
@@ -23,6 +23,7 @@ import (
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/gitrepo"
+ "code.gitea.io/gitea/modules/graceful"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
@@ -59,6 +60,10 @@ func ListPullRequests(ctx *context.APIContext) {
// description: Name of the repo
// type: string
// required: true
+ // - name: base_branch
+ // in: query
+ // description: Filter by target base branch of the pull request
+ // type: string
// - name: state
// in: query
// description: State of pull request
@@ -69,7 +74,7 @@ func ListPullRequests(ctx *context.APIContext) {
// in: query
// description: Type of sort
// type: string
- // enum: [oldest, recentupdate, leastupdate, mostcomment, leastcomment, priority]
+ // enum: [oldest, recentupdate, recentclose, leastupdate, mostcomment, leastcomment, priority]
// - name: milestone
// in: query
// description: ID of the milestone
@@ -108,7 +113,7 @@ func ListPullRequests(ctx *context.APIContext) {
labelIDs, err := base.StringsToInt64s(ctx.FormStrings("labels"))
if err != nil {
- ctx.Error(http.StatusInternalServerError, "PullRequests", err)
+ ctx.APIErrorInternal(err)
return
}
var posterID int64
@@ -116,9 +121,9 @@ func ListPullRequests(ctx *context.APIContext) {
poster, err := user_model.GetUserByName(ctx, posterStr)
if err != nil {
if user_model.IsErrUserNotExist(err) {
- ctx.Error(http.StatusBadRequest, "Poster not found", err)
+ ctx.APIError(http.StatusBadRequest, err)
} else {
- ctx.Error(http.StatusInternalServerError, "GetUserByName", err)
+ ctx.APIErrorInternal(err)
}
return
}
@@ -132,15 +137,16 @@ func ListPullRequests(ctx *context.APIContext) {
Labels: labelIDs,
MilestoneID: ctx.FormInt64("milestone"),
PosterID: posterID,
+ BaseBranch: ctx.FormTrim("base_branch"),
})
if err != nil {
- ctx.Error(http.StatusInternalServerError, "PullRequests", err)
+ ctx.APIErrorInternal(err)
return
}
apiPrs, err := convert.ToAPIPullRequests(ctx, ctx.Repo.Repository, prs, ctx.Doer)
if err != nil {
- ctx.Error(http.StatusInternalServerError, "ToAPIPullRequests", err)
+ ctx.APIErrorInternal(err)
return
}
@@ -182,21 +188,25 @@ func GetPullRequest(ctx *context.APIContext) {
pr, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index"))
if err != nil {
if issues_model.IsErrPullRequestNotExist(err) {
- ctx.NotFound()
+ ctx.APIErrorNotFound()
} else {
- ctx.Error(http.StatusInternalServerError, "GetPullRequestByIndex", err)
+ ctx.APIErrorInternal(err)
}
return
}
if err = pr.LoadBaseRepo(ctx); err != nil {
- ctx.Error(http.StatusInternalServerError, "LoadBaseRepo", err)
+ ctx.APIErrorInternal(err)
return
}
if err = pr.LoadHeadRepo(ctx); err != nil {
- ctx.Error(http.StatusInternalServerError, "LoadHeadRepo", err)
+ ctx.APIErrorInternal(err)
return
}
+
+ // Consider API access a view for delayed checking.
+ pull_service.StartPullRequestCheckOnView(ctx, pr)
+
ctx.JSON(http.StatusOK, convert.ToAPIPullRequest(ctx, pr, ctx.Doer))
}
@@ -252,9 +262,9 @@ func GetPullRequestByBaseHead(ctx *context.APIContext) {
repo, err := repo_model.GetRepositoryByOwnerAndName(ctx, owner, name)
if err != nil {
if repo_model.IsErrRepoNotExist(err) {
- ctx.NotFound()
+ ctx.APIErrorNotFound()
} else {
- ctx.Error(http.StatusInternalServerError, "GetRepositoryByOwnerName", err)
+ ctx.APIErrorInternal(err)
}
return
}
@@ -267,21 +277,25 @@ func GetPullRequestByBaseHead(ctx *context.APIContext) {
pr, err := issues_model.GetPullRequestByBaseHeadInfo(ctx, ctx.Repo.Repository.ID, headRepoID, ctx.PathParam("base"), headBranch)
if err != nil {
if issues_model.IsErrPullRequestNotExist(err) {
- ctx.NotFound()
+ ctx.APIErrorNotFound()
} else {
- ctx.Error(http.StatusInternalServerError, "GetPullRequestByBaseHeadInfo", err)
+ ctx.APIErrorInternal(err)
}
return
}
if err = pr.LoadBaseRepo(ctx); err != nil {
- ctx.Error(http.StatusInternalServerError, "LoadBaseRepo", err)
+ ctx.APIErrorInternal(err)
return
}
if err = pr.LoadHeadRepo(ctx); err != nil {
- ctx.Error(http.StatusInternalServerError, "LoadHeadRepo", err)
+ ctx.APIErrorInternal(err)
return
}
+
+ // Consider API access a view for delayed checking.
+ pull_service.StartPullRequestCheckOnView(ctx, pr)
+
ctx.JSON(http.StatusOK, convert.ToAPIPullRequest(ctx, pr, ctx.Doer))
}
@@ -327,9 +341,9 @@ func DownloadPullDiffOrPatch(ctx *context.APIContext) {
pr, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index"))
if err != nil {
if issues_model.IsErrPullRequestNotExist(err) {
- ctx.NotFound()
+ ctx.APIErrorNotFound()
} else {
- ctx.InternalServerError(err)
+ ctx.APIErrorInternal(err)
}
return
}
@@ -343,7 +357,7 @@ func DownloadPullDiffOrPatch(ctx *context.APIContext) {
binary := ctx.FormBool("binary")
if err := pull_service.DownloadDiffOrPatch(ctx, pr, ctx, patch, binary); err != nil {
- ctx.InternalServerError(err)
+ ctx.APIErrorInternal(err)
return
}
}
@@ -388,7 +402,7 @@ func CreatePullRequest(ctx *context.APIContext) {
form := *web.GetForm(ctx).(*api.CreatePullRequestOption)
if form.Head == form.Base {
- ctx.Error(http.StatusUnprocessableEntity, "BaseHeadSame", "Invalid PullRequest: There are no changes between the head and the base")
+ ctx.APIError(http.StatusUnprocessableEntity, "Invalid PullRequest: There are no changes between the head and the base")
return
}
@@ -406,7 +420,7 @@ func CreatePullRequest(ctx *context.APIContext) {
defer closer()
if !compareResult.baseRef.IsBranch() || !compareResult.headRef.IsBranch() {
- ctx.Error(http.StatusUnprocessableEntity, "BaseHeadInvalidRefType", "Invalid PullRequest: base and head must be branches")
+ ctx.APIError(http.StatusUnprocessableEntity, "Invalid PullRequest: base and head must be branches")
return
}
@@ -417,7 +431,7 @@ func CreatePullRequest(ctx *context.APIContext) {
)
if err != nil {
if !issues_model.IsErrPullRequestNotExist(err) {
- ctx.Error(http.StatusInternalServerError, "GetUnmergedPullRequest", err)
+ ctx.APIErrorInternal(err)
return
}
} else {
@@ -429,14 +443,14 @@ func CreatePullRequest(ctx *context.APIContext) {
HeadBranch: existingPr.HeadBranch,
BaseBranch: existingPr.BaseBranch,
}
- ctx.Error(http.StatusConflict, "GetUnmergedPullRequest", err)
+ ctx.APIError(http.StatusConflict, err)
return
}
if len(form.Labels) > 0 {
labels, err := issues_model.GetLabelsInRepoByIDs(ctx, ctx.Repo.Repository.ID, form.Labels)
if err != nil {
- ctx.Error(http.StatusInternalServerError, "GetLabelsInRepoByIDs", err)
+ ctx.APIErrorInternal(err)
return
}
@@ -448,7 +462,7 @@ func CreatePullRequest(ctx *context.APIContext) {
if ctx.Repo.Owner.IsOrganization() {
orgLabels, err := issues_model.GetLabelsInOrgByIDs(ctx, ctx.Repo.Owner.ID, form.Labels)
if err != nil {
- ctx.Error(http.StatusInternalServerError, "GetLabelsInOrgByIDs", err)
+ ctx.APIErrorInternal(err)
return
}
@@ -464,9 +478,9 @@ func CreatePullRequest(ctx *context.APIContext) {
milestone, err := issues_model.GetMilestoneByRepoID(ctx, ctx.Repo.Repository.ID, form.Milestone)
if err != nil {
if issues_model.IsErrMilestoneNotExist(err) {
- ctx.NotFound()
+ ctx.APIErrorNotFound()
} else {
- ctx.Error(http.StatusInternalServerError, "GetMilestoneByRepoID", err)
+ ctx.APIErrorInternal(fmt.Errorf("GetMilestoneByRepoID: %w", err))
}
return
}
@@ -504,9 +518,9 @@ func CreatePullRequest(ctx *context.APIContext) {
assigneeIDs, err := issues_model.MakeIDsFromAPIAssigneesToAdd(ctx, form.Assignee, form.Assignees)
if err != nil {
if user_model.IsErrUserNotExist(err) {
- ctx.Error(http.StatusUnprocessableEntity, "", fmt.Sprintf("Assignee does not exist: [name: %s]", err))
+ ctx.APIError(http.StatusUnprocessableEntity, fmt.Sprintf("Assignee does not exist: [name: %s]", err))
} else {
- ctx.Error(http.StatusInternalServerError, "AddAssigneeByName", err)
+ ctx.APIErrorInternal(err)
}
return
}
@@ -514,17 +528,17 @@ func CreatePullRequest(ctx *context.APIContext) {
for _, aID := range assigneeIDs {
assignee, err := user_model.GetUserByID(ctx, aID)
if err != nil {
- ctx.Error(http.StatusInternalServerError, "GetUserByID", err)
+ ctx.APIErrorInternal(err)
return
}
valid, err := access_model.CanBeAssigned(ctx, assignee, repo, true)
if err != nil {
- ctx.Error(http.StatusInternalServerError, "canBeAssigned", err)
+ ctx.APIErrorInternal(err)
return
}
if !valid {
- ctx.Error(http.StatusUnprocessableEntity, "canBeAssigned", repo_model.ErrUserDoesNotHaveAccessToRepo{UserID: aID, RepoName: repo.Name})
+ ctx.APIError(http.StatusUnprocessableEntity, repo_model.ErrUserDoesNotHaveAccessToRepo{UserID: aID, RepoName: repo.Name})
return
}
}
@@ -543,13 +557,13 @@ func CreatePullRequest(ctx *context.APIContext) {
if err := pull_service.NewPullRequest(ctx, prOpts); err != nil {
if repo_model.IsErrUserDoesNotHaveAccessToRepo(err) {
- ctx.Error(http.StatusBadRequest, "UserDoesNotHaveAccessToRepo", err)
+ ctx.APIError(http.StatusBadRequest, err)
} else if errors.Is(err, user_model.ErrBlockedUser) {
- ctx.Error(http.StatusForbidden, "BlockedUser", err)
+ ctx.APIError(http.StatusForbidden, err)
} else if errors.Is(err, issues_model.ErrMustCollaborator) {
- ctx.Error(http.StatusForbidden, "MustCollaborator", err)
+ ctx.APIError(http.StatusForbidden, err)
} else {
- ctx.Error(http.StatusInternalServerError, "NewPullRequest", err)
+ ctx.APIErrorInternal(err)
}
return
}
@@ -606,23 +620,23 @@ func EditPullRequest(ctx *context.APIContext) {
pr, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index"))
if err != nil {
if issues_model.IsErrPullRequestNotExist(err) {
- ctx.NotFound()
+ ctx.APIErrorNotFound()
} else {
- ctx.Error(http.StatusInternalServerError, "GetPullRequestByIndex", err)
+ ctx.APIErrorInternal(err)
}
return
}
err = pr.LoadIssue(ctx)
if err != nil {
- ctx.Error(http.StatusInternalServerError, "LoadIssue", err)
+ ctx.APIErrorInternal(err)
return
}
issue := pr.Issue
issue.Repo = ctx.Repo.Repository
if err := issue.LoadAttributes(ctx); err != nil {
- ctx.Error(http.StatusInternalServerError, "LoadAttributes", err)
+ ctx.APIErrorInternal(err)
return
}
@@ -634,7 +648,7 @@ func EditPullRequest(ctx *context.APIContext) {
if len(form.Title) > 0 {
err = issue_service.ChangeTitle(ctx, issue, ctx.Doer, form.Title)
if err != nil {
- ctx.Error(http.StatusInternalServerError, "ChangeTitle", err)
+ ctx.APIErrorInternal(err)
return
}
}
@@ -642,11 +656,11 @@ func EditPullRequest(ctx *context.APIContext) {
err = issue_service.ChangeContent(ctx, issue, ctx.Doer, *form.Body, issue.ContentVersion)
if err != nil {
if errors.Is(err, issues_model.ErrIssueAlreadyChanged) {
- ctx.Error(http.StatusBadRequest, "ChangeContent", err)
+ ctx.APIError(http.StatusBadRequest, err)
return
}
- ctx.Error(http.StatusInternalServerError, "ChangeContent", err)
+ ctx.APIErrorInternal(err)
return
}
}
@@ -661,7 +675,7 @@ func EditPullRequest(ctx *context.APIContext) {
}
if err := issues_model.UpdateIssueDeadline(ctx, issue, deadlineUnix, ctx.Doer); err != nil {
- ctx.Error(http.StatusInternalServerError, "UpdateIssueDeadline", err)
+ ctx.APIErrorInternal(err)
return
}
issue.DeadlineUnix = deadlineUnix
@@ -679,11 +693,11 @@ func EditPullRequest(ctx *context.APIContext) {
err = issue_service.UpdateAssignees(ctx, issue, form.Assignee, form.Assignees, ctx.Doer)
if err != nil {
if user_model.IsErrUserNotExist(err) {
- ctx.Error(http.StatusUnprocessableEntity, "", fmt.Sprintf("Assignee does not exist: [name: %s]", err))
+ ctx.APIError(http.StatusUnprocessableEntity, fmt.Sprintf("Assignee does not exist: [name: %s]", err))
} else if errors.Is(err, user_model.ErrBlockedUser) {
- ctx.Error(http.StatusForbidden, "UpdateAssignees", err)
+ ctx.APIError(http.StatusForbidden, err)
} else {
- ctx.Error(http.StatusInternalServerError, "UpdateAssignees", err)
+ ctx.APIErrorInternal(err)
}
return
}
@@ -693,8 +707,13 @@ func EditPullRequest(ctx *context.APIContext) {
issue.MilestoneID != form.Milestone {
oldMilestoneID := issue.MilestoneID
issue.MilestoneID = form.Milestone
+ issue.Milestone, err = issues_model.GetMilestoneByRepoID(ctx, ctx.Repo.Repository.ID, form.Milestone)
+ if err != nil {
+ ctx.APIErrorInternal(err)
+ return
+ }
if err = issue_service.ChangeMilestoneAssign(ctx, issue, ctx.Doer, oldMilestoneID); err != nil {
- ctx.Error(http.StatusInternalServerError, "ChangeMilestoneAssign", err)
+ ctx.APIErrorInternal(err)
return
}
}
@@ -702,14 +721,14 @@ func EditPullRequest(ctx *context.APIContext) {
if ctx.Repo.CanWrite(unit.TypePullRequests) && form.Labels != nil {
labels, err := issues_model.GetLabelsInRepoByIDs(ctx, ctx.Repo.Repository.ID, form.Labels)
if err != nil {
- ctx.Error(http.StatusInternalServerError, "GetLabelsInRepoByIDsError", err)
+ ctx.APIErrorInternal(err)
return
}
if ctx.Repo.Owner.IsOrganization() {
orgLabels, err := issues_model.GetLabelsInOrgByIDs(ctx, ctx.Repo.Owner.ID, form.Labels)
if err != nil {
- ctx.Error(http.StatusInternalServerError, "GetLabelsInOrgByIDs", err)
+ ctx.APIErrorInternal(err)
return
}
@@ -717,14 +736,14 @@ func EditPullRequest(ctx *context.APIContext) {
}
if err = issues_model.ReplaceIssueLabels(ctx, issue, labels, ctx.Doer); err != nil {
- ctx.Error(http.StatusInternalServerError, "ReplaceLabelsError", err)
+ ctx.APIErrorInternal(err)
return
}
}
if form.State != nil {
if pr.HasMerged {
- ctx.Error(http.StatusPreconditionFailed, "MergedPRState", "cannot change state of this pull request, it was already merged")
+ ctx.APIError(http.StatusPreconditionFailed, "cannot change state of this pull request, it was already merged")
return
}
@@ -737,22 +756,22 @@ func EditPullRequest(ctx *context.APIContext) {
// change pull target branch
if !pr.HasMerged && len(form.Base) != 0 && form.Base != pr.BaseBranch {
- if !ctx.Repo.GitRepo.IsBranchExist(form.Base) {
- ctx.Error(http.StatusNotFound, "NewBaseBranchNotExist", fmt.Errorf("new base '%s' not exist", form.Base))
+ if !gitrepo.IsBranchExist(ctx, ctx.Repo.Repository, form.Base) {
+ ctx.APIError(http.StatusNotFound, fmt.Errorf("new base '%s' not exist", form.Base))
return
}
if err := pull_service.ChangeTargetBranch(ctx, pr, ctx.Doer, form.Base); err != nil {
if issues_model.IsErrPullRequestAlreadyExists(err) {
- ctx.Error(http.StatusConflict, "IsErrPullRequestAlreadyExists", err)
+ ctx.APIError(http.StatusConflict, err)
return
} else if issues_model.IsErrIssueIsClosed(err) {
- ctx.Error(http.StatusUnprocessableEntity, "IsErrIssueIsClosed", err)
+ ctx.APIError(http.StatusUnprocessableEntity, err)
return
} else if pull_service.IsErrPullRequestHasMerged(err) {
- ctx.Error(http.StatusConflict, "IsErrPullRequestHasMerged", err)
+ ctx.APIError(http.StatusConflict, err)
return
}
- ctx.InternalServerError(err)
+ ctx.APIErrorInternal(err)
return
}
notify_service.PullRequestChangeTargetBranch(ctx, ctx.Doer, pr, form.Base)
@@ -762,10 +781,10 @@ func EditPullRequest(ctx *context.APIContext) {
if form.AllowMaintainerEdit != nil {
if err := pull_service.SetAllowEdits(ctx, ctx.Doer, pr, *form.AllowMaintainerEdit); err != nil {
if errors.Is(err, pull_service.ErrUserHasNoPermissionForAction) {
- ctx.Error(http.StatusForbidden, "SetAllowEdits", fmt.Sprintf("SetAllowEdits: %s", err))
+ ctx.APIError(http.StatusForbidden, fmt.Sprintf("SetAllowEdits: %s", err))
return
}
- ctx.ServerError("SetAllowEdits", err)
+ ctx.APIErrorInternal(err)
return
}
}
@@ -774,9 +793,9 @@ func EditPullRequest(ctx *context.APIContext) {
pr, err = issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, pr.Index)
if err != nil {
if issues_model.IsErrPullRequestNotExist(err) {
- ctx.NotFound()
+ ctx.APIErrorNotFound()
} else {
- ctx.Error(http.StatusInternalServerError, "GetPullRequestByIndex", err)
+ ctx.APIErrorInternal(err)
}
return
}
@@ -818,9 +837,9 @@ func IsPullRequestMerged(ctx *context.APIContext) {
pr, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index"))
if err != nil {
if issues_model.IsErrPullRequestNotExist(err) {
- ctx.NotFound()
+ ctx.APIErrorNotFound()
} else {
- ctx.Error(http.StatusInternalServerError, "GetPullRequestByIndex", err)
+ ctx.APIErrorInternal(err)
}
return
}
@@ -828,7 +847,7 @@ func IsPullRequestMerged(ctx *context.APIContext) {
if pr.HasMerged {
ctx.Status(http.StatusNoContent)
}
- ctx.NotFound()
+ ctx.APIErrorNotFound()
}
// MergePullRequest merges a PR given an index
@@ -876,20 +895,20 @@ func MergePullRequest(ctx *context.APIContext) {
pr, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index"))
if err != nil {
if issues_model.IsErrPullRequestNotExist(err) {
- ctx.NotFound("GetPullRequestByIndex", err)
+ ctx.APIErrorNotFound("GetPullRequestByIndex", err)
} else {
- ctx.Error(http.StatusInternalServerError, "GetPullRequestByIndex", err)
+ ctx.APIErrorInternal(err)
}
return
}
if err := pr.LoadHeadRepo(ctx); err != nil {
- ctx.Error(http.StatusInternalServerError, "LoadHeadRepo", err)
+ ctx.APIErrorInternal(err)
return
}
if err := pr.LoadIssue(ctx); err != nil {
- ctx.Error(http.StatusInternalServerError, "LoadIssue", err)
+ ctx.APIErrorInternal(err)
return
}
pr.Issue.Repo = ctx.Repo.Repository
@@ -897,7 +916,7 @@ func MergePullRequest(ctx *context.APIContext) {
if ctx.IsSigned {
// Update issue-user.
if err = activities_model.SetIssueReadBy(ctx, pr.Issue.ID, ctx.Doer.ID); err != nil {
- ctx.Error(http.StatusInternalServerError, "ReadBy", err)
+ ctx.APIErrorInternal(err)
return
}
}
@@ -915,21 +934,21 @@ func MergePullRequest(ctx *context.APIContext) {
// start with merging by checking
if err := pull_service.CheckPullMergeable(ctx, ctx.Doer, &ctx.Repo.Permission, pr, mergeCheckType, form.ForceMerge); err != nil {
if errors.Is(err, pull_service.ErrIsClosed) {
- ctx.NotFound()
- } else if errors.Is(err, pull_service.ErrUserNotAllowedToMerge) {
- ctx.Error(http.StatusMethodNotAllowed, "Merge", "User not allowed to merge PR")
+ ctx.APIErrorNotFound()
+ } else if errors.Is(err, pull_service.ErrNoPermissionToMerge) {
+ ctx.APIError(http.StatusMethodNotAllowed, "User not allowed to merge PR")
} else if errors.Is(err, pull_service.ErrHasMerged) {
- ctx.Error(http.StatusMethodNotAllowed, "PR already merged", "")
+ ctx.APIError(http.StatusMethodNotAllowed, "")
} else if errors.Is(err, pull_service.ErrIsWorkInProgress) {
- ctx.Error(http.StatusMethodNotAllowed, "PR is a work in progress", "Work in progress PRs cannot be merged")
+ ctx.APIError(http.StatusMethodNotAllowed, "Work in progress PRs cannot be merged")
} else if errors.Is(err, pull_service.ErrNotMergeableState) {
- ctx.Error(http.StatusMethodNotAllowed, "PR not in mergeable state", "Please try again later")
- } else if pull_service.IsErrDisallowedToMerge(err) {
- ctx.Error(http.StatusMethodNotAllowed, "PR is not ready to be merged", err)
+ ctx.APIError(http.StatusMethodNotAllowed, "Please try again later")
+ } else if errors.Is(err, pull_service.ErrNotReadyToMerge) {
+ ctx.APIError(http.StatusMethodNotAllowed, err)
} else if asymkey_service.IsErrWontSign(err) {
- ctx.Error(http.StatusMethodNotAllowed, fmt.Sprintf("Protected branch %s requires signed commits but this merge would not be signed", pr.BaseBranch), err)
+ ctx.APIError(http.StatusMethodNotAllowed, err)
} else {
- ctx.InternalServerError(err)
+ ctx.APIErrorInternal(err)
}
return
}
@@ -938,14 +957,14 @@ func MergePullRequest(ctx *context.APIContext) {
if manuallyMerged {
if err := pull_service.MergedManually(ctx, pr, ctx.Doer, ctx.Repo.GitRepo, form.MergeCommitID); err != nil {
if pull_service.IsErrInvalidMergeStyle(err) {
- ctx.Error(http.StatusMethodNotAllowed, "Invalid merge style", fmt.Errorf("%s is not allowed an allowed merge style for this repository", repo_model.MergeStyle(form.Do)))
+ ctx.APIError(http.StatusMethodNotAllowed, fmt.Errorf("%s is not allowed an allowed merge style for this repository", repo_model.MergeStyle(form.Do)))
return
}
if strings.Contains(err.Error(), "Wrong commit ID") {
ctx.JSON(http.StatusConflict, err)
return
}
- ctx.Error(http.StatusInternalServerError, "Manually-Merged", err)
+ ctx.APIErrorInternal(err)
return
}
ctx.Status(http.StatusOK)
@@ -960,7 +979,7 @@ func MergePullRequest(ctx *context.APIContext) {
if len(message) == 0 {
message, _, err = pull_service.GetDefaultMergeMessage(ctx, ctx.Repo.GitRepo, pr, repo_model.MergeStyle(form.Do))
if err != nil {
- ctx.Error(http.StatusInternalServerError, "GetDefaultMergeMessage", err)
+ ctx.APIErrorInternal(err)
return
}
}
@@ -974,10 +993,10 @@ func MergePullRequest(ctx *context.APIContext) {
scheduled, err := automerge.ScheduleAutoMerge(ctx, ctx.Doer, pr, repo_model.MergeStyle(form.Do), message, form.DeleteBranchAfterMerge)
if err != nil {
if pull_model.IsErrAlreadyScheduledToAutoMerge(err) {
- ctx.Error(http.StatusConflict, "ScheduleAutoMerge", err)
+ ctx.APIError(http.StatusConflict, err)
return
}
- ctx.Error(http.StatusInternalServerError, "ScheduleAutoMerge", err)
+ ctx.APIErrorInternal(err)
return
} else if scheduled {
// nothing more to do ...
@@ -988,7 +1007,7 @@ func MergePullRequest(ctx *context.APIContext) {
if err := pull_service.Merge(ctx, pr, ctx.Doer, ctx.Repo.GitRepo, repo_model.MergeStyle(form.Do), form.HeadCommitID, message, false); err != nil {
if pull_service.IsErrInvalidMergeStyle(err) {
- ctx.Error(http.StatusMethodNotAllowed, "Invalid merge style", fmt.Errorf("%s is not allowed an allowed merge style for this repository", repo_model.MergeStyle(form.Do)))
+ ctx.APIError(http.StatusMethodNotAllowed, fmt.Errorf("%s is not allowed an allowed merge style for this repository", repo_model.MergeStyle(form.Do)))
} else if pull_service.IsErrMergeConflicts(err) {
conflictError := err.(pull_service.ErrMergeConflicts)
ctx.JSON(http.StatusConflict, conflictError)
@@ -999,18 +1018,18 @@ func MergePullRequest(ctx *context.APIContext) {
conflictError := err.(pull_service.ErrMergeUnrelatedHistories)
ctx.JSON(http.StatusConflict, conflictError)
} else if git.IsErrPushOutOfDate(err) {
- ctx.Error(http.StatusConflict, "Merge", "merge push out of date")
+ ctx.APIError(http.StatusConflict, "merge push out of date")
} else if pull_service.IsErrSHADoesNotMatch(err) {
- ctx.Error(http.StatusConflict, "Merge", "head out of date")
+ ctx.APIError(http.StatusConflict, "head out of date")
} else if git.IsErrPushRejected(err) {
errPushRej := err.(*git.ErrPushRejected)
if len(errPushRej.Message) == 0 {
- ctx.Error(http.StatusConflict, "Merge", "PushRejected without remote error message")
+ ctx.APIError(http.StatusConflict, "PushRejected without remote error message")
} else {
- ctx.Error(http.StatusConflict, "Merge", "PushRejected with remote message: "+errPushRej.Message)
+ ctx.APIError(http.StatusConflict, "PushRejected with remote message: "+errPushRej.Message)
}
} else {
- ctx.Error(http.StatusInternalServerError, "Merge", err)
+ ctx.APIErrorInternal(err)
}
return
}
@@ -1024,7 +1043,7 @@ func MergePullRequest(ctx *context.APIContext) {
// Don't cleanup when there are other PR's that use this branch as head branch.
exist, err := issues_model.HasUnmergedPullRequestsByHeadInfo(ctx, pr.HeadRepoID, pr.HeadBranch)
if err != nil {
- ctx.ServerError("HasUnmergedPullRequestsByHeadInfo", err)
+ ctx.APIErrorInternal(err)
return
}
if exist {
@@ -1038,7 +1057,7 @@ func MergePullRequest(ctx *context.APIContext) {
} else {
headRepo, err = gitrepo.OpenRepository(ctx, pr.HeadRepo)
if err != nil {
- ctx.ServerError(fmt.Sprintf("OpenRepository[%s]", pr.HeadRepo.FullName()), err)
+ ctx.APIErrorInternal(err)
return
}
defer headRepo.Close()
@@ -1047,13 +1066,13 @@ func MergePullRequest(ctx *context.APIContext) {
if err := repo_service.DeleteBranch(ctx, ctx.Doer, pr.HeadRepo, headRepo, pr.HeadBranch, pr); err != nil {
switch {
case git.IsErrBranchNotExist(err):
- ctx.NotFound(err)
+ ctx.APIErrorNotFound(err)
case errors.Is(err, repo_service.ErrBranchIsDefault):
- ctx.Error(http.StatusForbidden, "DefaultBranch", fmt.Errorf("can not delete default branch"))
+ ctx.APIError(http.StatusForbidden, errors.New("can not delete default branch"))
case errors.Is(err, git_model.ErrBranchIsProtected):
- ctx.Error(http.StatusForbidden, "IsProtectedBranch", fmt.Errorf("branch protected"))
+ ctx.APIError(http.StatusForbidden, errors.New("branch protected"))
default:
- ctx.Error(http.StatusInternalServerError, "DeleteBranch", err)
+ ctx.APIErrorInternal(err)
}
return
}
@@ -1092,14 +1111,14 @@ func parseCompareInfo(ctx *context.APIContext, form api.CreatePullRequestOption)
headUser, err = user_model.GetUserByName(ctx, headInfos[0])
if err != nil {
if user_model.IsErrUserNotExist(err) {
- ctx.NotFound("GetUserByName")
+ ctx.APIErrorNotFound("GetUserByName")
} else {
- ctx.Error(http.StatusInternalServerError, "GetUserByName", err)
+ ctx.APIErrorInternal(err)
}
return nil, nil
}
} else {
- ctx.NotFound()
+ ctx.APIErrorNotFound()
return nil, nil
}
@@ -1110,14 +1129,14 @@ func parseCompareInfo(ctx *context.APIContext, form api.CreatePullRequestOption)
if headRepo == nil && !isSameRepo {
err = baseRepo.GetBaseRepo(ctx)
if err != nil {
- ctx.Error(http.StatusInternalServerError, "GetBaseRepo", err)
+ ctx.APIErrorInternal(err)
return nil, nil
}
// Check if baseRepo's base repository is the same as headUser's repository.
if baseRepo.BaseRepo == nil || baseRepo.BaseRepo.OwnerID != headUser.ID {
log.Trace("parseCompareInfo[%d]: does not have fork or in same repository", baseRepo.ID)
- ctx.NotFound("GetBaseRepo")
+ ctx.APIErrorNotFound("GetBaseRepo")
return nil, nil
}
// Assign headRepo so it can be used below.
@@ -1132,7 +1151,7 @@ func parseCompareInfo(ctx *context.APIContext, form api.CreatePullRequestOption)
} else {
headGitRepo, err = gitrepo.OpenRepository(ctx, headRepo)
if err != nil {
- ctx.Error(http.StatusInternalServerError, "OpenRepository", err)
+ ctx.APIErrorInternal(err)
return nil, nil
}
closer = func() { _ = headGitRepo.Close() }
@@ -1146,13 +1165,13 @@ func parseCompareInfo(ctx *context.APIContext, form api.CreatePullRequestOption)
// user should have permission to read baseRepo's codes and pulls, NOT headRepo's
permBase, err := access_model.GetUserRepoPermission(ctx, baseRepo, ctx.Doer)
if err != nil {
- ctx.Error(http.StatusInternalServerError, "GetUserRepoPermission", err)
+ ctx.APIErrorInternal(err)
return nil, nil
}
if !permBase.CanReadIssuesOrPulls(true) || !permBase.CanRead(unit.TypeCode) {
log.Trace("Permission Denied: User %-v cannot create/read pull requests or cannot read code in Repo %-v\nUser in baseRepo has Permissions: %-+v", ctx.Doer, baseRepo, permBase)
- ctx.NotFound("Can't read pulls or can't read UnitTypeCode")
+ ctx.APIErrorNotFound("Can't read pulls or can't read UnitTypeCode")
return nil, nil
}
@@ -1160,12 +1179,12 @@ func parseCompareInfo(ctx *context.APIContext, form api.CreatePullRequestOption)
// TODO: could the logic be simplified if the headRepo is the same as the baseRepo? Need to think more about it.
permHead, err := access_model.GetUserRepoPermission(ctx, headRepo, ctx.Doer)
if err != nil {
- ctx.Error(http.StatusInternalServerError, "GetUserRepoPermission", err)
+ ctx.APIErrorInternal(err)
return nil, nil
}
if !permHead.CanRead(unit.TypeCode) {
log.Trace("Permission Denied: User: %-v cannot read code in Repo: %-v\nUser in headRepo has Permissions: %-+v", ctx.Doer, headRepo, permHead)
- ctx.NotFound("Can't read headRepo UnitTypeCode")
+ ctx.APIErrorNotFound("Can't read headRepo UnitTypeCode")
return nil, nil
}
@@ -1178,13 +1197,13 @@ func parseCompareInfo(ctx *context.APIContext, form api.CreatePullRequestOption)
headRefValid := headRef.IsBranch() || headRef.IsTag() || git.IsStringLikelyCommitID(git.ObjectFormatFromName(headRepo.ObjectFormatName), headRef.ShortName())
// Check if base&head ref are valid.
if !baseRefValid || !headRefValid {
- ctx.NotFound()
+ ctx.APIErrorNotFound()
return nil, nil
}
compareInfo, err := headGitRepo.GetCompareInfo(repo_model.RepoPath(baseRepo.Owner.Name, baseRepo.Name), baseRef.ShortName(), headRef.ShortName(), false, false)
if err != nil {
- ctx.Error(http.StatusInternalServerError, "GetCompareInfo", err)
+ ctx.APIErrorInternal(err)
return nil, nil
}
@@ -1236,34 +1255,34 @@ func UpdatePullRequest(ctx *context.APIContext) {
pr, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index"))
if err != nil {
if issues_model.IsErrPullRequestNotExist(err) {
- ctx.NotFound()
+ ctx.APIErrorNotFound()
} else {
- ctx.Error(http.StatusInternalServerError, "GetPullRequestByIndex", err)
+ ctx.APIErrorInternal(err)
}
return
}
if pr.HasMerged {
- ctx.Error(http.StatusUnprocessableEntity, "UpdatePullRequest", err)
+ ctx.APIError(http.StatusUnprocessableEntity, err)
return
}
if err = pr.LoadIssue(ctx); err != nil {
- ctx.Error(http.StatusInternalServerError, "LoadIssue", err)
+ ctx.APIErrorInternal(err)
return
}
if pr.Issue.IsClosed {
- ctx.Error(http.StatusUnprocessableEntity, "UpdatePullRequest", err)
+ ctx.APIError(http.StatusUnprocessableEntity, err)
return
}
if err = pr.LoadBaseRepo(ctx); err != nil {
- ctx.Error(http.StatusInternalServerError, "LoadBaseRepo", err)
+ ctx.APIErrorInternal(err)
return
}
if err = pr.LoadHeadRepo(ctx); err != nil {
- ctx.Error(http.StatusInternalServerError, "LoadHeadRepo", err)
+ ctx.APIErrorInternal(err)
return
}
@@ -1271,7 +1290,7 @@ func UpdatePullRequest(ctx *context.APIContext) {
allowedUpdateByMerge, allowedUpdateByRebase, err := pull_service.IsUserAllowedToUpdate(ctx, pr, ctx.Doer)
if err != nil {
- ctx.Error(http.StatusInternalServerError, "IsUserAllowedToMerge", err)
+ ctx.APIErrorInternal(err)
return
}
@@ -1283,15 +1302,15 @@ func UpdatePullRequest(ctx *context.APIContext) {
// default merge commit message
message := fmt.Sprintf("Merge branch '%s' into %s", pr.BaseBranch, pr.HeadBranch)
- if err = pull_service.Update(ctx, pr, ctx.Doer, message, rebase); err != nil {
+ if err = pull_service.Update(graceful.GetManager().ShutdownContext(), pr, ctx.Doer, message, rebase); err != nil {
if pull_service.IsErrMergeConflicts(err) {
- ctx.Error(http.StatusConflict, "Update", "merge failed because of conflict")
+ ctx.APIError(http.StatusConflict, "merge failed because of conflict")
return
} else if pull_service.IsErrRebaseConflicts(err) {
- ctx.Error(http.StatusConflict, "Update", "rebase failed because of conflict")
+ ctx.APIError(http.StatusConflict, "rebase failed because of conflict")
return
}
- ctx.Error(http.StatusInternalServerError, "pull_service.Update", err)
+ ctx.APIErrorInternal(err)
return
}
@@ -1336,37 +1355,37 @@ func CancelScheduledAutoMerge(ctx *context.APIContext) {
pull, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, pullIndex)
if err != nil {
if issues_model.IsErrPullRequestNotExist(err) {
- ctx.NotFound()
+ ctx.APIErrorNotFound()
return
}
- ctx.InternalServerError(err)
+ ctx.APIErrorInternal(err)
return
}
exist, autoMerge, err := pull_model.GetScheduledMergeByPullID(ctx, pull.ID)
if err != nil {
- ctx.InternalServerError(err)
+ ctx.APIErrorInternal(err)
return
}
if !exist {
- ctx.NotFound()
+ ctx.APIErrorNotFound()
return
}
if ctx.Doer.ID != autoMerge.DoerID {
allowed, err := access_model.IsUserRepoAdmin(ctx, ctx.Repo.Repository, ctx.Doer)
if err != nil {
- ctx.InternalServerError(err)
+ ctx.APIErrorInternal(err)
return
}
if !allowed {
- ctx.Error(http.StatusForbidden, "No permission to cancel", "user has no permission to cancel the scheduled auto merge")
+ ctx.APIError(http.StatusForbidden, "user has no permission to cancel the scheduled auto merge")
return
}
}
if err := automerge.RemoveScheduledAutoMerge(ctx, ctx.Doer, pull); err != nil {
- ctx.InternalServerError(err)
+ ctx.APIErrorInternal(err)
} else {
ctx.Status(http.StatusNoContent)
}
@@ -1421,22 +1440,22 @@ func GetPullRequestCommits(ctx *context.APIContext) {
pr, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index"))
if err != nil {
if issues_model.IsErrPullRequestNotExist(err) {
- ctx.NotFound()
+ ctx.APIErrorNotFound()
} else {
- ctx.Error(http.StatusInternalServerError, "GetPullRequestByIndex", err)
+ ctx.APIErrorInternal(err)
}
return
}
if err := pr.LoadBaseRepo(ctx); err != nil {
- ctx.InternalServerError(err)
+ ctx.APIErrorInternal(err)
return
}
var prInfo *git.CompareInfo
baseGitRepo, closer, err := gitrepo.RepositoryFromContextOrOpen(ctx, pr.BaseRepo)
if err != nil {
- ctx.ServerError("OpenRepository", err)
+ ctx.APIErrorInternal(err)
return
}
defer closer.Close()
@@ -1447,7 +1466,7 @@ func GetPullRequestCommits(ctx *context.APIContext) {
prInfo, err = baseGitRepo.GetCompareInfo(pr.BaseRepo.RepoPath(), pr.BaseBranch, pr.GetGitRefName(), false, false)
}
if err != nil {
- ctx.ServerError("GetCompareInfo", err)
+ ctx.APIErrorInternal(err)
return
}
commits := prInfo.Commits
@@ -1476,7 +1495,7 @@ func GetPullRequestCommits(ctx *context.APIContext) {
Files: files,
})
if err != nil {
- ctx.ServerError("toCommit", err)
+ ctx.APIErrorInternal(err)
return
}
apiCommits = append(apiCommits, apiCommit)
@@ -1544,20 +1563,20 @@ func GetPullRequestFiles(ctx *context.APIContext) {
pr, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index"))
if err != nil {
if issues_model.IsErrPullRequestNotExist(err) {
- ctx.NotFound()
+ ctx.APIErrorNotFound()
} else {
- ctx.Error(http.StatusInternalServerError, "GetPullRequestByIndex", err)
+ ctx.APIErrorInternal(err)
}
return
}
if err := pr.LoadBaseRepo(ctx); err != nil {
- ctx.InternalServerError(err)
+ ctx.APIErrorInternal(err)
return
}
if err := pr.LoadHeadRepo(ctx); err != nil {
- ctx.InternalServerError(err)
+ ctx.APIErrorInternal(err)
return
}
@@ -1570,13 +1589,13 @@ func GetPullRequestFiles(ctx *context.APIContext) {
prInfo, err = baseGitRepo.GetCompareInfo(pr.BaseRepo.RepoPath(), pr.BaseBranch, pr.GetGitRefName(), true, false)
}
if err != nil {
- ctx.ServerError("GetCompareInfo", err)
+ ctx.APIErrorInternal(err)
return
}
headCommitID, err := baseGitRepo.GetRefCommitID(pr.GetGitRefName())
if err != nil {
- ctx.ServerError("GetRefCommitID", err)
+ ctx.APIErrorInternal(err)
return
}
@@ -1586,7 +1605,7 @@ func GetPullRequestFiles(ctx *context.APIContext) {
maxLines := setting.Git.MaxGitDiffLines
// FIXME: If there are too many files in the repo, may cause some unpredictable issues.
- diff, err := gitdiff.GetDiff(ctx, baseGitRepo,
+ diff, err := gitdiff.GetDiffForAPI(ctx, baseGitRepo,
&gitdiff.DiffOptions{
BeforeCommitID: startCommitID,
AfterCommitID: endCommitID,
@@ -1597,13 +1616,18 @@ func GetPullRequestFiles(ctx *context.APIContext) {
WhitespaceBehavior: gitdiff.GetWhitespaceFlag(ctx.FormString("whitespace")),
})
if err != nil {
- ctx.ServerError("GetDiff", err)
+ ctx.APIErrorInternal(err)
return
}
+ diffShortStat, err := gitdiff.GetDiffShortStat(baseGitRepo, startCommitID, endCommitID)
+ if err != nil {
+ ctx.APIErrorInternal(err)
+ return
+ }
listOptions := utils.GetListOptions(ctx)
- totalNumberOfFiles := diff.NumFiles
+ totalNumberOfFiles := diffShortStat.NumFiles
totalNumberOfPages := int(math.Ceil(float64(totalNumberOfFiles) / float64(listOptions.PageSize)))
start, limit := listOptions.GetSkipTake()
@@ -1614,7 +1638,9 @@ func GetPullRequestFiles(ctx *context.APIContext) {
apiFiles := make([]*api.ChangedFile, 0, limit)
for i := start; i < start+limit; i++ {
- apiFiles = append(apiFiles, convert.ToChangedFile(diff.Files[i], pr.HeadRepo, endCommitID))
+ // refs/pull/1/head stores the HEAD commit ID, allowing all related commits to be found in the base repository.
+ // The head repository might have been deleted, so we should not rely on it here.
+ apiFiles = append(apiFiles, convert.ToChangedFile(diff.Files[i], pr.BaseRepo, endCommitID))
}
ctx.SetLinkHeader(totalNumberOfFiles, listOptions.PageSize)