新增:合并请求commit列表和变更文件列表

This commit is contained in:
yystopf 2022-12-01 16:59:07 +08:00
parent 3019b5ca6e
commit 5be1baac4b
3 changed files with 240 additions and 0 deletions

View File

@ -0,0 +1,8 @@
package git
import gitea_git "code.gitea.io/gitea/modules/git"
func GetDiffFileOnlyName(repo *gitea_git.Repository, base, head string) (string, error) {
stdout, _, err := gitea_git.NewCommand(repo.Ctx, "diff", "--name-only", base, head).RunStdString(&gitea_git.RunOpts{Dir: repo.Path})
return stdout, err
}

View File

@ -84,6 +84,8 @@ func Routers() *web.Route {
m.Group("/pulls", func() {
m.Group("/{index}", func() {
m.Combo("").Get(repo.GetPullRequest)
m.Get("/commits", context.RepoRef(), repo.GetPullCommits)
m.Get("/files", context.RepoRef(), repo.GetPullFiles)
})
}, mustAllowPulls, reqRepoReader(unit_model.TypeCode), context.ReferencesGitRepo())
m.Group("/releases", func() {

View File

@ -2,10 +2,21 @@ package repo
import (
"net/http"
"strings"
asymkey_model "code.gitea.io/gitea/models/asymkey"
git_model "code.gitea.io/gitea/models/git"
issues_model "code.gitea.io/gitea/models/issues"
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/services/gitdiff"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitlink.org.cn/Gitlink/gitea_hat.git/modules/convert"
hat_git "code.gitlink.org.cn/Gitlink/gitea_hat.git/modules/git"
)
func GetPullRequest(ctx *context.APIContext) {
@ -34,3 +45,222 @@ func GetPullRequest(ctx *context.APIContext) {
}
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.ParamsInt64(":index"))
if err != nil {
if issues_model.IsErrPullRequestNotExist(err) {
ctx.NotFound()
} else {
ctx.Error(http.StatusInternalServerError, "GetPullRequestByIndex", err)
}
return
}
issue := pull.Issue
if issue == nil {
ctx.NotFound("issue is not present.")
return
}
gitRepo := ctx.Repo.GitRepo
var commits []*git.Commit
var prInfo *git.CompareInfo
if pull.HasMerged {
var baseCommit string
if pull.MergeBase == "" {
var commitSHA, parentCommit string
commitSHA, err := gitRepo.GetRefCommitID(pull.GetGitRefName())
if err != nil {
commitSHA, err := gitRepo.ReadPatchCommit(pull.Index)
if err == nil {
if err := gitRepo.SetReference(pull.GetGitRefName(), 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 = git.NewCommand(ctx, "rev-list", "-1", "--skip=1", commitSHA).RunStdString(&git.RunOpts{Dir: gitRepo.Path})
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 = gitRepo.GetCompareInfo(gitRepo.Path, baseCommit, pull.GetGitRefName(), false, false)
} else {
prInfo, err = gitRepo.GetCompareInfo(gitRepo.Path, pull.MergeBase, pull.GetGitRefName(), false, false)
}
if err != nil {
ctx.Error(http.StatusInternalServerError, "GetCompareInfo", err)
return
}
ctx.Data["Username"] = ctx.Repo.Owner.Name
ctx.Data["Reponame"] = ctx.Repo.Repository.Name
commits = prInfo.Commits
userCommits := user_model.ValidateCommitsWithEmails(commits)
signCommits := asymkey_model.ParseCommitsWithSignature(userCommits, ctx.Repo.Repository.GetTrustModel(),
func(user *user_model.User) (bool, error) {
return repo_model.IsOwnerMemberCollaborator(ctx.Repo.Repository, user.ID)
})
signStatusCommits := git_model.ParseCommitsWithStatus(signCommits, ctx.Repo.Repository)
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) {
pull, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
if err != nil {
if issues_model.IsErrPullRequestNotExist(err) {
ctx.NotFound()
} else {
ctx.Error(http.StatusInternalServerError, "GetPullRequestByIndex", err)
}
return
}
issue := pull.Issue
if issue == nil {
ctx.NotFound("issue is not present.")
return
}
gitRepo := ctx.Repo.GitRepo
var prInfo *git.CompareInfo
if pull.HasMerged {
var baseCommit string
if pull.MergeBase == "" {
var commitSHA, parentCommit string
commitSHA, err := gitRepo.GetRefCommitID(pull.GetGitRefName())
if err != nil {
commitSHA, err := gitRepo.ReadPatchCommit(pull.Index)
if err == nil {
if err := gitRepo.SetReference(pull.GetGitRefName(), 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 = git.NewCommand(ctx, "rev-list", "-1", "--skip=1", commitSHA).RunStdString(&git.RunOpts{Dir: gitRepo.Path})
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 = gitRepo.GetCompareInfo(gitRepo.Path, baseCommit, pull.GetGitRefName(), false, false)
} else {
prInfo, err = gitRepo.GetCompareInfo(gitRepo.Path, pull.MergeBase, pull.GetGitRefName(), false, false)
}
if err != nil {
ctx.Error(http.StatusInternalServerError, "GetCompareInfo", err)
return
}
headCommitID, err := gitRepo.GetRefCommitID(pull.GetGitRefName())
if err != nil {
ctx.Error(http.StatusInternalServerError, "GetRefCommitID", err)
return
}
startCommitID := prInfo.MergeBase
endCommitID := headCommitID
ctx.Data["WhitespaceBehavior"] = ""
diff := &gitdiff.Diff{Files: make([]*gitdiff.DiffFile, 0)}
if ctx.Params("not-need-files") == "true" || ctx.Params("only-file-name") == "true" {
shortstatArgs := []string{startCommitID + "..." + endCommitID}
if len(startCommitID) == 0 || startCommitID == git.EmptySHA {
shortstatArgs = []string{git.EmptyTreeSHA, endCommitID}
}
diff.NumFiles, diff.TotalAddition, diff.TotalDeletion, err = git.GetDiffShortStat(ctx, gitRepo.Path, shortstatArgs...)
if err != nil && strings.Contains(err.Error(), "no merge base") {
// git >= 2.28 now returns an error if base and head have become unrelated.
// previously it would return the results of git diff --shortstat base head so let's try that...
shortstatArgs = []string{startCommitID, endCommitID}
diff.NumFiles, diff.TotalAddition, diff.TotalDeletion, _ = git.GetDiffShortStat(ctx, gitRepo.Path, shortstatArgs...)
}
if ctx.Params("only-file-name") == "true" {
var diffString string
var err error
if len(startCommitID) == 0 || startCommitID == git.EmptySHA {
diffString, err = hat_git.GetDiffFileOnlyName(ctx.Repo.GitRepo, git.EmptyTreeSHA, headCommitID)
} else {
diffString, err = hat_git.GetDiffFileOnlyName(ctx.Repo.GitRepo, startCommitID, headCommitID)
}
if err == nil {
for _, fileName := range strings.Split(diffString, "\n") {
if fileName != "" {
diff.Files = append(diff.Files, &gitdiff.DiffFile{
Name: fileName,
})
}
}
}
}
} else {
diff, err = gitdiff.GetDiff(gitRepo, &gitdiff.DiffOptions{
BeforeCommitID: startCommitID,
AfterCommitID: endCommitID,
SkipTo: ctx.FormString("skip-to"),
MaxLines: setting.Git.MaxGitDiffLines,
MaxLineCharacters: setting.Git.MaxGitDiffLineCharacters,
MaxFiles: setting.Git.MaxGitDiffFiles,
WhitespaceBehavior: ctx.Data["WhitespaceBehavior"].(string)})
if err != nil {
ctx.ServerError("GetDiffRangeWithWhitespaceBehavior", err)
return
}
if err = diff.LoadComments(ctx, issue, ctx.Doer); err != nil {
ctx.ServerError("LoadComments", err)
return
}
}
fileDiff := struct {
*gitdiff.Diff
LatestSha string
}{
Diff: diff,
LatestSha: endCommitID,
}
ctx.JSON(http.StatusOK, fileDiff)
}