627 lines
18 KiB
Go
627 lines
18 KiB
Go
package repo
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"math"
|
|
"net/http"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
git_model "code.gitea.io/gitea/models/git"
|
|
issues_model "code.gitea.io/gitea/models/issues"
|
|
"code.gitea.io/gitea/models/unit"
|
|
user_model "code.gitea.io/gitea/models/user"
|
|
"code.gitea.io/gitea/routers/api/v1/utils"
|
|
"code.gitea.io/gitea/services/gitdiff"
|
|
|
|
"code.gitea.io/gitea/modules/git"
|
|
"code.gitea.io/gitea/modules/git/gitcmd"
|
|
"code.gitea.io/gitea/modules/gitrepo"
|
|
"code.gitea.io/gitea/modules/log"
|
|
"code.gitea.io/gitea/modules/setting"
|
|
gitea_api "code.gitea.io/gitea/modules/structs"
|
|
"code.gitea.io/gitea/modules/timeutil"
|
|
"code.gitea.io/gitea/modules/web"
|
|
"code.gitea.io/gitea/services/context"
|
|
gitea_convert "code.gitea.io/gitea/services/convert"
|
|
git_service "code.gitea.io/gitea/services/git"
|
|
issue_service "code.gitea.io/gitea/services/issue"
|
|
notify_service "code.gitea.io/gitea/services/notify"
|
|
pull_service "code.gitea.io/gitea/services/pull"
|
|
hat_convert "code.gitlink.org.cn/Gitlink/gitea_hat.git/modules/convert"
|
|
hat_api "code.gitlink.org.cn/Gitlink/gitea_hat.git/modules/structs"
|
|
hat_gitdiff "code.gitlink.org.cn/Gitlink/gitea_hat.git/services/gitdiff"
|
|
hat_pull_service "code.gitlink.org.cn/Gitlink/gitea_hat.git/services/pull"
|
|
)
|
|
|
|
func ChangePullRequestCloseStatus(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.APIError(http.StatusNotFound, err)
|
|
} else {
|
|
ctx.APIErrorInternal(err)
|
|
}
|
|
return
|
|
}
|
|
|
|
if err = pr.LoadBaseRepo(ctx); err != nil {
|
|
ctx.APIErrorInternal(err)
|
|
return
|
|
}
|
|
if err = pr.LoadHeadRepo(ctx); err != nil {
|
|
ctx.APIErrorInternal(err)
|
|
return
|
|
}
|
|
|
|
changeStatus := ctx.FormBool("is_closed")
|
|
if changeStatus {
|
|
_, err = issues_model.CloseIssue(ctx, pr.Issue, ctx.Doer)
|
|
if err != nil {
|
|
ctx.APIErrorInternal(err)
|
|
return
|
|
}
|
|
} else {
|
|
_, err = issues_model.ReopenIssue(ctx, pr.Issue, ctx.Doer)
|
|
if err != nil {
|
|
ctx.APIErrorInternal(err)
|
|
return
|
|
}
|
|
}
|
|
|
|
if err = hat_pull_service.CheckPullRequestBranchMergeable(ctx, pr); err != nil {
|
|
ctx.APIErrorInternal(err)
|
|
return
|
|
}
|
|
|
|
// Update Commit Divergence
|
|
divergence, err := gitrepo.GetDivergingCommits(ctx, pr.BaseRepo, pr.BaseBranch, pr.GetGitHeadRefName())
|
|
if err != nil {
|
|
ctx.APIErrorInternal(err)
|
|
return
|
|
}
|
|
pr.CommitsAhead = divergence.Ahead
|
|
pr.CommitsBehind = divergence.Behind
|
|
|
|
if _, err := pr.UpdateColsIfNotMerged(ctx, "merge_base", "status", "conflicted_files", "changed_protected_files", "base_branch", "commits_ahead", "commits_behind"); err != nil {
|
|
ctx.APIErrorInternal(err)
|
|
return
|
|
}
|
|
|
|
ctx.Status(http.StatusNoContent)
|
|
}
|
|
|
|
func CreatePrVersion(ctx *context.APIContext) {
|
|
form := web.GetForm(ctx).(*gitea_api.PullRequestPayload)
|
|
hat_pull_service.AddToTaskQueue(&issues_model.PullRequest{ID: form.PullRequest.ID}, string(form.Action))
|
|
ctx.Status(http.StatusNoContent)
|
|
}
|
|
|
|
func EditPullRequest(ctx *context.APIContext) {
|
|
form := web.GetForm(ctx).(*gitea_api.EditPullRequestOption)
|
|
pr, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index"))
|
|
if err != nil {
|
|
if issues_model.IsErrPullRequestNotExist(err) {
|
|
ctx.APIErrorNotFound()
|
|
} else {
|
|
ctx.APIErrorInternal(err)
|
|
}
|
|
return
|
|
}
|
|
|
|
err = pr.LoadIssue(ctx)
|
|
if err != nil {
|
|
ctx.APIErrorInternal(err)
|
|
return
|
|
}
|
|
issue := pr.Issue
|
|
issue.Repo = ctx.Repo.Repository
|
|
|
|
if err := issue.LoadAttributes(ctx); err != nil {
|
|
ctx.APIErrorInternal(err)
|
|
return
|
|
}
|
|
|
|
if !issue.IsPoster(ctx.Doer.ID) && !ctx.Repo.CanWrite(unit.TypePullRequests) {
|
|
ctx.Status(http.StatusForbidden)
|
|
return
|
|
}
|
|
|
|
if len(form.Title) > 0 {
|
|
err = issue_service.ChangeTitle(ctx, issue, ctx.Doer, form.Title)
|
|
if err != nil {
|
|
ctx.APIErrorInternal(err)
|
|
return
|
|
}
|
|
}
|
|
if form.Body != nil {
|
|
err = issue_service.ChangeContent(ctx, issue, ctx.Doer, *form.Body, issue.ContentVersion)
|
|
if err != nil {
|
|
if errors.Is(err, issues_model.ErrIssueAlreadyChanged) {
|
|
ctx.APIError(http.StatusBadRequest, err)
|
|
return
|
|
}
|
|
|
|
ctx.APIErrorInternal(err)
|
|
return
|
|
}
|
|
}
|
|
|
|
// Update or remove deadline if set
|
|
if form.Deadline != nil || form.RemoveDeadline != nil {
|
|
var deadlineUnix timeutil.TimeStamp
|
|
if (form.RemoveDeadline == nil || !*form.RemoveDeadline) && !form.Deadline.IsZero() {
|
|
deadline := time.Date(form.Deadline.Year(), form.Deadline.Month(), form.Deadline.Day(),
|
|
23, 59, 59, 0, form.Deadline.Location())
|
|
deadlineUnix = timeutil.TimeStamp(deadline.Unix())
|
|
}
|
|
|
|
if err := issues_model.UpdateIssueDeadline(ctx, issue, deadlineUnix, ctx.Doer); err != nil {
|
|
ctx.APIErrorInternal(err)
|
|
return
|
|
}
|
|
issue.DeadlineUnix = deadlineUnix
|
|
}
|
|
|
|
// Add/delete assignees
|
|
|
|
// Deleting is done the GitHub way (quote from their api documentation):
|
|
// https://developer.github.com/v3/issues/#edit-an-issue
|
|
// "assignees" (array): Logins for Users to assign to this issue.
|
|
// Pass one or more user logins to replace the set of assignees on this Issue.
|
|
// Send an empty array ([]) to clear all assignees from the Issue.
|
|
|
|
if ctx.Repo.CanWrite(unit.TypePullRequests) && (form.Assignees != nil || len(form.Assignee) > 0) {
|
|
err = issue_service.UpdateAssignees(ctx, issue, form.Assignee, form.Assignees, ctx.Doer)
|
|
if err != nil {
|
|
if user_model.IsErrUserNotExist(err) {
|
|
ctx.APIError(http.StatusUnprocessableEntity, fmt.Sprintf("Assignee does not exist: [name: %s]", err))
|
|
} else if errors.Is(err, user_model.ErrBlockedUser) {
|
|
ctx.APIError(http.StatusForbidden, err)
|
|
} else {
|
|
ctx.APIErrorInternal(err)
|
|
}
|
|
return
|
|
}
|
|
}
|
|
|
|
if ctx.Repo.CanWrite(unit.TypePullRequests) && form.Milestone != 0 &&
|
|
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.APIErrorInternal(err)
|
|
return
|
|
}
|
|
}
|
|
|
|
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.APIErrorInternal(err)
|
|
return
|
|
}
|
|
|
|
if ctx.Repo.Owner.IsOrganization() {
|
|
orgLabels, err := issues_model.GetLabelsInOrgByIDs(ctx, ctx.Repo.Owner.ID, form.Labels)
|
|
if err != nil {
|
|
ctx.APIErrorInternal(err)
|
|
return
|
|
}
|
|
|
|
labels = append(labels, orgLabels...)
|
|
}
|
|
|
|
if err = issues_model.ReplaceIssueLabels(ctx, issue, labels, ctx.Doer); err != nil {
|
|
ctx.APIErrorInternal(err)
|
|
return
|
|
}
|
|
}
|
|
|
|
if form.State != nil {
|
|
if pr.HasMerged {
|
|
ctx.APIError(http.StatusPreconditionFailed, "cannot change state of this pull request, it was already merged")
|
|
return
|
|
}
|
|
|
|
state := gitea_api.StateType(*form.State)
|
|
closeOrReopenIssue(ctx, issue, state)
|
|
if ctx.Written() {
|
|
return
|
|
}
|
|
}
|
|
|
|
// change pull target branch
|
|
if !pr.HasMerged && len(form.Base) != 0 && form.Base != pr.BaseBranch {
|
|
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.APIError(http.StatusConflict, err)
|
|
return
|
|
} else if issues_model.IsErrIssueIsClosed(err) {
|
|
ctx.APIError(http.StatusUnprocessableEntity, err)
|
|
return
|
|
} else if pull_service.IsErrPullRequestHasMerged(err) {
|
|
ctx.APIError(http.StatusConflict, err)
|
|
return
|
|
}
|
|
ctx.APIErrorInternal(err)
|
|
return
|
|
}
|
|
notify_service.PullRequestChangeTargetBranch(ctx, ctx.Doer, pr, form.Base)
|
|
}
|
|
|
|
// update allow edits
|
|
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.APIError(http.StatusForbidden, fmt.Sprintf("SetAllowEdits: %s", err))
|
|
return
|
|
}
|
|
ctx.APIErrorInternal(err)
|
|
return
|
|
}
|
|
}
|
|
|
|
// Refetch from database
|
|
pr, err = issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, pr.Index)
|
|
if err != nil {
|
|
if issues_model.IsErrPullRequestNotExist(err) {
|
|
ctx.APIErrorNotFound()
|
|
} else {
|
|
ctx.APIErrorInternal(err)
|
|
}
|
|
return
|
|
}
|
|
|
|
// TODO this should be 200, not 201
|
|
ctx.JSON(http.StatusCreated, gitea_convert.ToAPIPullRequest(ctx, pr, ctx.Doer))
|
|
}
|
|
|
|
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.APIErrorNotFound()
|
|
} else {
|
|
ctx.APIErrorInternal(err)
|
|
}
|
|
return
|
|
}
|
|
|
|
if err = pr.LoadBaseRepo(ctx); err != nil {
|
|
ctx.APIErrorInternal(err)
|
|
return
|
|
}
|
|
if err = pr.LoadHeadRepo(ctx); err != nil {
|
|
ctx.APIErrorInternal(err)
|
|
return
|
|
}
|
|
apiResult, err := hat_convert.ToAPIPullRequest(ctx, ctx.Repo.GitRepo, pr, ctx.Doer)
|
|
if err != nil {
|
|
ctx.APIErrorInternal(err)
|
|
return
|
|
}
|
|
ctx.JSON(http.StatusOK, apiResult)
|
|
}
|
|
|
|
type PullRequestCommit struct {
|
|
git_model.SignCommitWithStatuses
|
|
Sha string
|
|
}
|
|
|
|
func GetPullCommits(ctx *context.APIContext) {
|
|
pull, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index"))
|
|
if err != nil {
|
|
if issues_model.IsErrPullRequestNotExist(err) {
|
|
ctx.APIErrorNotFound()
|
|
} else {
|
|
ctx.APIErrorInternal(err)
|
|
}
|
|
return
|
|
}
|
|
|
|
issue := pull.Issue
|
|
if issue == nil {
|
|
ctx.APIErrorNotFound("issue is not present.")
|
|
return
|
|
}
|
|
gitRepo := ctx.Repo.GitRepo
|
|
|
|
var commits []*git.Commit
|
|
var prInfo *git_service.CompareInfo
|
|
|
|
if pull.HasMerged {
|
|
var baseCommit string
|
|
if pull.MergeBase == "" {
|
|
var commitSHA, parentCommit string
|
|
commitSHA, err := gitRepo.GetRefCommitID(pull.GetGitHeadRefName())
|
|
if err != nil {
|
|
commitSHA, err := gitRepo.ReadPatchCommit(pull.Index)
|
|
if err == nil {
|
|
if err := gitrepo.UpdateRef(ctx, ctx.Repo.Repository, pull.GetGitHeadRefName(), commitSHA); err != nil {
|
|
log.Error("Could not write head file", err)
|
|
}
|
|
} else {
|
|
log.Trace("No history file available for PR %d", pull.Index)
|
|
}
|
|
}
|
|
if commitSHA != "" {
|
|
parentCommit, _, err = gitrepo.RunCmdString(ctx, ctx.Repo.Repository,
|
|
gitcmd.NewCommand("rev-list", "-1", "--skip=1").AddDynamicArguments(commitSHA))
|
|
if err == nil {
|
|
parentCommit = strings.TrimSpace(parentCommit)
|
|
}
|
|
if err != nil || parentCommit == "" {
|
|
log.Info("No known parent commit for PR %d, error: %v", pull.Index, err)
|
|
parentCommit = commitSHA
|
|
}
|
|
}
|
|
baseCommit = parentCommit
|
|
} else {
|
|
baseCommit = pull.MergeBase
|
|
}
|
|
prInfo, err = git_service.GetCompareInfo(ctx, pull.BaseRepo, pull.BaseRepo, gitRepo, git.RefName(baseCommit), git.RefName(pull.GetGitHeadRefName()), false, false)
|
|
|
|
} else {
|
|
prInfo, err = git_service.GetCompareInfo(ctx, pull.BaseRepo, pull.BaseRepo, gitRepo, git.RefNameFromBranch(pull.BaseBranch), git.RefName(pull.GetGitHeadRefName()), false, false)
|
|
}
|
|
|
|
if err != nil {
|
|
ctx.APIErrorInternal(err)
|
|
return
|
|
}
|
|
|
|
ctx.Data["Username"] = ctx.Repo.Owner.Name
|
|
ctx.Data["Reponame"] = ctx.Repo.Repository.Name
|
|
commits = prInfo.Commits
|
|
userCommits, err := user_model.ValidateCommitsWithEmails(ctx, commits)
|
|
if err != nil {
|
|
ctx.APIErrorInternal(err)
|
|
return
|
|
}
|
|
signCommits, err := git_service.ParseCommitsWithSignature(ctx, ctx.Repo.Repository, userCommits, ctx.Repo.Repository.GetTrustModel())
|
|
if err != nil {
|
|
ctx.APIErrorInternal(err)
|
|
return
|
|
}
|
|
signStatusCommits, err := git_service.ParseCommitsWithStatus(ctx, signCommits, ctx.Repo.Repository)
|
|
if err != nil {
|
|
ctx.APIErrorInternal(err)
|
|
return
|
|
}
|
|
result := make([]PullRequestCommit, 0)
|
|
for _, commit := range signStatusCommits {
|
|
result = append(result, PullRequestCommit{
|
|
SignCommitWithStatuses: *commit,
|
|
Sha: commit.ID.String(),
|
|
})
|
|
}
|
|
|
|
ctx.JSON(http.StatusOK, result)
|
|
}
|
|
|
|
func GetPullFiles(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.APIErrorNotFound()
|
|
} else {
|
|
ctx.APIErrorInternal(err)
|
|
}
|
|
return
|
|
}
|
|
|
|
if err := pr.LoadBaseRepo(ctx); err != nil {
|
|
ctx.APIErrorInternal(err)
|
|
return
|
|
}
|
|
|
|
if err := pr.LoadHeadRepo(ctx); err != nil {
|
|
ctx.APIErrorInternal(err)
|
|
return
|
|
}
|
|
|
|
baseGitRepo := ctx.Repo.GitRepo
|
|
|
|
var prInfo *git_service.CompareInfo
|
|
if pr.HasMerged {
|
|
prInfo, err = git_service.GetCompareInfo(ctx, pr.BaseRepo, pr.BaseRepo, baseGitRepo, git.RefName(pr.MergeBase), git.RefName(pr.GetGitHeadRefName()), false, false)
|
|
} else {
|
|
prInfo, err = git_service.GetCompareInfo(ctx, pr.BaseRepo, pr.BaseRepo, baseGitRepo, git.RefNameFromBranch(pr.BaseBranch), git.RefName(pr.GetGitHeadRefName()), false, false)
|
|
}
|
|
if err != nil {
|
|
ctx.APIErrorInternal(err)
|
|
return
|
|
}
|
|
|
|
headCommitID, err := baseGitRepo.GetRefCommitID(pr.GetGitHeadRefName())
|
|
if err != nil {
|
|
ctx.APIErrorInternal(err)
|
|
return
|
|
}
|
|
|
|
startCommitID := prInfo.MergeBase
|
|
endCommitID := headCommitID
|
|
|
|
diff, err := gitdiff.GetDiffForAPI(ctx, baseGitRepo, &gitdiff.DiffOptions{
|
|
BeforeCommitID: startCommitID,
|
|
AfterCommitID: endCommitID,
|
|
SkipTo: ctx.FormString("skip-to"),
|
|
MaxLines: setting.Git.MaxGitDiffLines,
|
|
MaxLineCharacters: setting.Git.MaxGitDiffLineCharacters,
|
|
MaxFiles: -1,
|
|
WhitespaceBehavior: gitdiff.GetWhitespaceFlag(ctx.FormString("whitespace")),
|
|
})
|
|
|
|
diffShortStat, err := gitdiff.GetDiffShortStat(ctx, ctx.Repo.Repository, baseGitRepo, startCommitID, endCommitID)
|
|
if err != nil {
|
|
ctx.APIErrorInternal(err)
|
|
return
|
|
}
|
|
|
|
if err != nil {
|
|
ctx.APIErrorInternal(err)
|
|
return
|
|
}
|
|
isNew := ctx.FormString("isNew")
|
|
if isNew != "" {
|
|
listOptions := utils.GetListOptions(ctx)
|
|
|
|
totalNumberOfFiles := diffShortStat.NumFiles
|
|
totalNumberOfPages := int(math.Ceil(float64(totalNumberOfFiles) / float64(listOptions.PageSize)))
|
|
|
|
start, limit := listOptions.GetSkipTake()
|
|
|
|
limit = min(limit, totalNumberOfFiles-start)
|
|
|
|
limit = max(limit, 0)
|
|
|
|
apiFiles := make([]*hat_api.ChangedFile, 0, limit)
|
|
for i := start; i < start+limit; i++ {
|
|
apiFiles = append(apiFiles, hat_convert.ToChangedFile(diff.Files[i], ctx.Repo.Repository, headCommitID))
|
|
}
|
|
|
|
ctx.SetLinkHeader(int64(totalNumberOfFiles), listOptions.PageSize)
|
|
ctx.SetTotalCountHeader(int64(totalNumberOfFiles))
|
|
|
|
ctx.RespHeader().Set("X-Page", strconv.Itoa(listOptions.Page))
|
|
ctx.RespHeader().Set("X-PerPage", strconv.Itoa(listOptions.PageSize))
|
|
ctx.RespHeader().Set("X-PageCount", strconv.Itoa(totalNumberOfPages))
|
|
ctx.RespHeader().Set("X-HasMore", strconv.FormatBool(listOptions.Page < totalNumberOfPages))
|
|
ctx.AppendAccessControlExposeHeaders("X-Page", "X-PerPage", "X-PageCount", "X-HasMore")
|
|
ctx.JSON(http.StatusOK, struct {
|
|
Files []*hat_api.ChangedFile `json:"files"`
|
|
TotalAddition int `json:"total_addition"`
|
|
TotalDeletion int `json:"total_deletion"`
|
|
}{
|
|
Files: apiFiles,
|
|
TotalAddition: diffShortStat.TotalAddition,
|
|
TotalDeletion: diffShortStat.TotalDeletion,
|
|
})
|
|
|
|
} else {
|
|
|
|
fileDiff := struct {
|
|
*gitdiff.Diff
|
|
LatestSha string
|
|
}{
|
|
Diff: diff,
|
|
LatestSha: endCommitID,
|
|
}
|
|
|
|
ctx.JSON(http.StatusOK, fileDiff)
|
|
}
|
|
|
|
}
|
|
|
|
func GetPullFilesByPath(ctx *context.APIContext) {
|
|
path := ctx.PathParam("*")
|
|
pr, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index"))
|
|
if err != nil {
|
|
if issues_model.IsErrPullRequestNotExist(err) {
|
|
ctx.APIErrorNotFound()
|
|
} else {
|
|
ctx.APIErrorInternal(err)
|
|
}
|
|
return
|
|
}
|
|
|
|
if err := pr.LoadBaseRepo(ctx); err != nil {
|
|
ctx.APIErrorInternal(err)
|
|
return
|
|
}
|
|
|
|
if err := pr.LoadHeadRepo(ctx); err != nil {
|
|
ctx.APIErrorInternal(err)
|
|
return
|
|
}
|
|
|
|
baseGitRepo := ctx.Repo.GitRepo
|
|
|
|
var prInfo *git_service.CompareInfo
|
|
if pr.HasMerged {
|
|
prInfo, err = git_service.GetCompareInfo(ctx, pr.BaseRepo, pr.BaseRepo, baseGitRepo, git.RefName(pr.MergeBase), git.RefName(pr.GetGitHeadRefName()), false, false)
|
|
} else {
|
|
prInfo, err = git_service.GetCompareInfo(ctx, pr.BaseRepo, pr.BaseRepo, baseGitRepo, git.RefNameFromBranch(pr.BaseBranch), git.RefName(pr.GetGitHeadRefName()), false, false)
|
|
|
|
}
|
|
if err != nil {
|
|
ctx.APIErrorInternal(err)
|
|
return
|
|
}
|
|
|
|
headCommitID, err := baseGitRepo.GetRefCommitID(pr.GetGitHeadRefName())
|
|
if err != nil {
|
|
ctx.APIErrorInternal(err)
|
|
return
|
|
}
|
|
|
|
startCommitID := prInfo.MergeBase
|
|
endCommitID := headCommitID
|
|
|
|
diff, err := gitdiff.GetDiffForAPI(ctx, baseGitRepo, &gitdiff.DiffOptions{
|
|
BeforeCommitID: startCommitID,
|
|
AfterCommitID: endCommitID,
|
|
SkipTo: ctx.FormString("skip-to"),
|
|
MaxLines: setting.Git.MaxGitDiffLines,
|
|
MaxLineCharacters: setting.Git.MaxGitDiffLineCharacters,
|
|
MaxFiles: -1,
|
|
WhitespaceBehavior: gitdiff.GetWhitespaceFlag(ctx.FormString("whitespace")),
|
|
}, path)
|
|
|
|
if err != nil {
|
|
ctx.APIErrorInternal(err)
|
|
return
|
|
}
|
|
|
|
diffShortStat, err := gitdiff.GetDiffShortStat(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, startCommitID, endCommitID)
|
|
if err != nil {
|
|
ctx.APIErrorInternal(err)
|
|
return
|
|
}
|
|
|
|
fileDiff := struct {
|
|
*hat_gitdiff.Diff
|
|
LatestSha string
|
|
}{
|
|
Diff: &hat_gitdiff.Diff{Diff: diff, NumFiles: diffShortStat.NumFiles, TotalAddition: diffShortStat.TotalAddition, TotalDeletion: diffShortStat.TotalDeletion},
|
|
LatestSha: endCommitID,
|
|
}
|
|
|
|
ctx.JSON(http.StatusOK, fileDiff)
|
|
}
|
|
|
|
func closeOrReopenIssue(ctx *context.APIContext, issue *issues_model.Issue, state gitea_api.StateType) {
|
|
if state != gitea_api.StateOpen && state != gitea_api.StateClosed {
|
|
ctx.APIError(http.StatusPreconditionFailed, fmt.Sprintf("unknown state: %s", state))
|
|
return
|
|
}
|
|
|
|
if state == gitea_api.StateClosed && !issue.IsClosed {
|
|
if err := issue_service.CloseIssue(ctx, issue, ctx.Doer, ""); err != nil {
|
|
if issues_model.IsErrDependenciesLeft(err) {
|
|
ctx.APIError(http.StatusPreconditionFailed, "cannot close this issue or pull request because it still has open dependencies")
|
|
return
|
|
}
|
|
ctx.APIErrorInternal(err)
|
|
return
|
|
}
|
|
} else if state == gitea_api.StateOpen && issue.IsClosed {
|
|
if err := issue_service.ReopenIssue(ctx, issue, ctx.Doer, ""); err != nil {
|
|
ctx.APIErrorInternal(err)
|
|
return
|
|
}
|
|
}
|
|
}
|