forked from Gitlink/gitea_hat
新增:合并请求前compare接口
This commit is contained in:
parent
5be1baac4b
commit
717da8233f
|
@ -55,6 +55,7 @@ func Routers() *web.Route {
|
|||
SignInRequired: setting.Service.RequireSignInView,
|
||||
}))
|
||||
|
||||
reqRepoCodeReader := context.RequireRepoReader(unit_model.TypeCode)
|
||||
m.Group("", func() {
|
||||
m.Get("/version", misc.Version)
|
||||
m.Group("/repos", func() {
|
||||
|
@ -81,6 +82,8 @@ func Routers() *web.Route {
|
|||
m.Get("/*", repo.GetReadmeContentsByPath)
|
||||
})
|
||||
m.Get("/commits_slice", repo.GetAllCommitsSliceByTime)
|
||||
m.Get("/compare/*", repo.MustBeNotEmpty, reqRepoCodeReader,
|
||||
repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.CompareDiff)
|
||||
m.Group("/pulls", func() {
|
||||
m.Group("/{index}", func() {
|
||||
m.Combo("").Get(repo.GetPullRequest)
|
||||
|
|
|
@ -0,0 +1,480 @@
|
|||
package repo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
admin_model "code.gitea.io/gitea/models/admin"
|
||||
access_model "code.gitea.io/gitea/models/perm/access"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
unit_model "code.gitea.io/gitea/models/unit"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
gitea_git "code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/services/gitdiff"
|
||||
)
|
||||
|
||||
func PrepareComapreDiff(
|
||||
ctx *context.APIContext,
|
||||
headUser *user_model.User,
|
||||
headRepo *repo_model.Repository,
|
||||
headGitRepo *gitea_git.Repository,
|
||||
compareInfo *gitea_git.CompareInfo,
|
||||
baseBranch, headBranch string) bool {
|
||||
var (
|
||||
err error
|
||||
)
|
||||
|
||||
ctx.Data["CommitRepoLink"] = headRepo.Link()
|
||||
|
||||
headCommitID := headBranch
|
||||
if ctx.Data["HeadIsCommit"] == false {
|
||||
if ctx.Data["HeadIsTag"] == true {
|
||||
headCommitID, err = headGitRepo.GetTagCommitID(headBranch)
|
||||
} else {
|
||||
headCommitID, err = headGitRepo.GetBranchCommitID(headBranch)
|
||||
}
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "GetRefCommitID", err)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
ctx.Data["AfterCommitID"] = headCommitID
|
||||
|
||||
if headCommitID == compareInfo.MergeBase {
|
||||
ctx.Data["IsNothingToCompare"] = true
|
||||
return true
|
||||
}
|
||||
|
||||
repoPath := repo_model.RepoPath(headUser.Name, headRepo.Name)
|
||||
|
||||
gitRepo, _ := gitea_git.OpenRepository(ctx, repoPath)
|
||||
defer gitRepo.Close()
|
||||
|
||||
diff, err := gitdiff.GetDiff(gitRepo, &gitdiff.DiffOptions{
|
||||
BeforeCommitID: compareInfo.MergeBase,
|
||||
AfterCommitID: headCommitID,
|
||||
MaxLines: setting.Git.MaxGitDiffLines,
|
||||
MaxLineCharacters: setting.Git.MaxGitDiffLineCharacters,
|
||||
MaxFiles: setting.Git.MaxGitDiffFiles,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "GetDiff", err)
|
||||
return false
|
||||
}
|
||||
|
||||
if diff.NumFiles == 0 {
|
||||
ctx.Data["Diff"] = nil
|
||||
ctx.Data["DiffNotAvailable"] = true
|
||||
} else {
|
||||
ctx.Data["Diff"] = diff
|
||||
ctx.Data["DiffNotAvailable"] = false
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
type CompareCommit struct {
|
||||
*git.Commit
|
||||
Sha string
|
||||
ParentShas []string
|
||||
}
|
||||
|
||||
func CompareDiff(ctx *context.APIContext) {
|
||||
headUser, headRepo, headGitRepo, compareInfo, baseBranch, headBranch := ParseCompareInfo(ctx)
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
defer headGitRepo.Close()
|
||||
|
||||
_ = PrepareComapreDiff(ctx, headUser, headRepo, headGitRepo, compareInfo, baseBranch, headBranch)
|
||||
|
||||
result := make([]CompareCommit, 0)
|
||||
for _, commit := range compareInfo.Commits {
|
||||
compareCommit := CompareCommit{
|
||||
Commit: commit,
|
||||
Sha: commit.ID.String(),
|
||||
}
|
||||
for _, p := range commit.Parents {
|
||||
compareCommit.ParentShas = append(compareCommit.ParentShas, p.String())
|
||||
}
|
||||
result = append(result, compareCommit)
|
||||
}
|
||||
|
||||
different := struct {
|
||||
Commits []CompareCommit
|
||||
Diff interface{}
|
||||
CommitsCount int
|
||||
Latestsha string
|
||||
}{
|
||||
Commits: result,
|
||||
Diff: ctx.Context.Data["Diff"],
|
||||
}
|
||||
|
||||
different.CommitsCount = len(compareInfo.Commits)
|
||||
different.Latestsha = compareInfo.HeadCommitID
|
||||
|
||||
ctx.JSON(http.StatusOK, different)
|
||||
}
|
||||
|
||||
func ParseCompareInfo(ctx *context.APIContext) (*user_model.User, *repo_model.Repository, *gitea_git.Repository, *gitea_git.CompareInfo, string, string) {
|
||||
baseRepo := ctx.Repo.Repository
|
||||
|
||||
var (
|
||||
headUser *user_model.User
|
||||
headRepo *repo_model.Repository
|
||||
headBranch string
|
||||
isSameRepo bool
|
||||
infoPath string
|
||||
err error
|
||||
)
|
||||
|
||||
infoPath = ctx.Params("*")
|
||||
infos := strings.SplitN(infoPath, "...", 2)
|
||||
if len(infos) != 2 {
|
||||
log.Trace("ParseCompareInfo[%d]: not enough compared branches information %s", baseRepo.ID, infos)
|
||||
ctx.NotFound("CompareAndPullRequest", nil)
|
||||
return nil, nil, nil, nil, "", ""
|
||||
}
|
||||
|
||||
ctx.Data["BaseName"] = baseRepo.OwnerName
|
||||
baseBranch := infos[0]
|
||||
ctx.Data["BaseBranch"] = baseBranch
|
||||
|
||||
headInfos := strings.Split(infos[1], ":")
|
||||
if len(headInfos) == 1 {
|
||||
isSameRepo = true
|
||||
headUser = ctx.Repo.Owner
|
||||
headBranch = headInfos[0]
|
||||
} else if len(headInfos) == 2 {
|
||||
headInfosSplit := strings.Split(headInfos[0], "/")
|
||||
if len(headInfosSplit) == 1 {
|
||||
headUser, err = user_model.GetUserByName(ctx, headInfos[0])
|
||||
if err != nil {
|
||||
if user_model.IsErrUserNotExist(err) {
|
||||
ctx.NotFound("GetUserByName", nil)
|
||||
} else {
|
||||
ctx.Error(http.StatusInternalServerError, "GetUserByName", err)
|
||||
}
|
||||
return nil, nil, nil, nil, "", ""
|
||||
}
|
||||
|
||||
headBranch = headInfos[1]
|
||||
isSameRepo = headUser.ID == ctx.Repo.Owner.ID
|
||||
|
||||
if isSameRepo {
|
||||
headRepo = baseRepo
|
||||
}
|
||||
} else {
|
||||
headRepo, err = repo_model.GetRepositoryByOwnerAndName(headInfosSplit[0], headInfosSplit[1])
|
||||
if err != nil {
|
||||
if repo_model.IsErrRepoNotExist(err) {
|
||||
ctx.NotFound("GetRepositoryByOwnerAndName", nil)
|
||||
} else {
|
||||
ctx.Error(http.StatusInternalServerError, "GetRepositoryByOwnerAndName", err)
|
||||
}
|
||||
return nil, nil, nil, nil, "", ""
|
||||
}
|
||||
if err := headRepo.GetOwner(ctx); err != nil {
|
||||
if user_model.IsErrUserNotExist(err) {
|
||||
ctx.NotFound("GetOwner", nil)
|
||||
} else {
|
||||
ctx.Error(http.StatusInternalServerError, "GetOwner", err)
|
||||
}
|
||||
return nil, nil, nil, nil, "", ""
|
||||
}
|
||||
headBranch = headInfos[1]
|
||||
headUser = headRepo.Owner
|
||||
isSameRepo = headRepo.ID == ctx.Repo.Repository.ID
|
||||
}
|
||||
} else {
|
||||
ctx.NotFound("CompareAndPullRequest", nil)
|
||||
return nil, nil, nil, nil, "", ""
|
||||
}
|
||||
ctx.Data["HeadUser"] = headUser
|
||||
ctx.Data["HeadBranch"] = headBranch
|
||||
ctx.Repo.PullRequest.SameRepo = isSameRepo
|
||||
if ctx.Repo.GitRepo == nil && !baseRepo.IsEmpty {
|
||||
var err error
|
||||
ctx.Repo.GitRepo, err = git.OpenRepository(ctx, ctx.Repo.Repository.RepoPath())
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "OpenRepository", err)
|
||||
return nil, nil, nil, nil, "", ""
|
||||
}
|
||||
defer ctx.Repo.GitRepo.Close()
|
||||
}
|
||||
|
||||
baseIsCommit := ctx.Repo.GitRepo.IsCommitExist(baseBranch)
|
||||
baseIsBranch := ctx.Repo.GitRepo.IsBranchExist(baseBranch)
|
||||
baseIsTag := ctx.Repo.GitRepo.IsTagExist(baseBranch)
|
||||
if !baseIsCommit && !baseIsBranch && !baseIsTag {
|
||||
if baseCommit, _ := ctx.Repo.GitRepo.GetCommit(baseBranch); baseCommit == nil {
|
||||
ctx.NotFound("IsRefExist", nil)
|
||||
return nil, nil, nil, nil, "", ""
|
||||
} else {
|
||||
baseBranch = baseCommit.ID.String()
|
||||
ctx.Data["BaseBranch"] = baseBranch
|
||||
baseIsCommit = true
|
||||
}
|
||||
}
|
||||
ctx.Data["BaseIsCommit"] = baseIsCommit
|
||||
ctx.Data["BaseIsBranch"] = baseIsBranch
|
||||
ctx.Data["BaseIsTag"] = baseIsTag
|
||||
|
||||
var rootRepo *repo_model.Repository
|
||||
if baseRepo.IsFork {
|
||||
err = baseRepo.GetBaseRepo()
|
||||
if err != nil {
|
||||
if !repo_model.IsErrRepoNotExist(err) {
|
||||
ctx.NotFound("GetBaseRepo", nil)
|
||||
} else {
|
||||
ctx.Error(http.StatusInternalServerError, "GetBaseRepo", err)
|
||||
}
|
||||
return nil, nil, nil, nil, "", ""
|
||||
} else {
|
||||
rootRepo = baseRepo.BaseRepo
|
||||
}
|
||||
}
|
||||
|
||||
var ownForkRpo *repo_model.Repository
|
||||
if ctx.Doer != nil && baseRepo.OwnerID != ctx.Doer.ID {
|
||||
has := repo_model.HasForkedRepo(ctx.Doer.ID, baseRepo.ID)
|
||||
if has {
|
||||
ownForkRpo = repo_model.GetForkedRepo(ctx.Doer.ID, baseRepo.ID)
|
||||
ctx.Data["OwnForkRepo"] = ownForkRpo
|
||||
}
|
||||
}
|
||||
|
||||
has := headRepo != nil
|
||||
if !has && rootRepo != nil && rootRepo.OwnerID == headUser.ID {
|
||||
headRepo = rootRepo
|
||||
has = true
|
||||
}
|
||||
|
||||
if !has && ownForkRpo != nil && ownForkRpo.OwnerID == headUser.ID {
|
||||
headRepo = ownForkRpo
|
||||
has = true
|
||||
}
|
||||
|
||||
if !has {
|
||||
has = repo_model.HasForkedRepo(headUser.ID, baseRepo.ID)
|
||||
headRepo = repo_model.GetForkedRepo(headUser.ID, baseRepo.ID)
|
||||
}
|
||||
|
||||
if !has && baseRepo.IsFork {
|
||||
has = repo_model.HasForkedRepo(headUser.ID, baseRepo.ForkID)
|
||||
headRepo = repo_model.GetForkedRepo(headUser.ID, baseRepo.ForkID)
|
||||
}
|
||||
|
||||
if !isSameRepo && !has {
|
||||
ctx.Data["PageIsComparePull"] = false
|
||||
}
|
||||
|
||||
var headGitRepo *gitea_git.Repository
|
||||
if isSameRepo {
|
||||
headRepo = ctx.Repo.Repository
|
||||
headGitRepo = ctx.Repo.GitRepo
|
||||
} else if has {
|
||||
headGitRepo, err = git.OpenRepository(ctx, headRepo.RepoPath())
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "OpenRepository", err)
|
||||
return nil, nil, nil, nil, "", ""
|
||||
}
|
||||
defer headGitRepo.Close()
|
||||
}
|
||||
ctx.Data["HeadRepo"] = headRepo
|
||||
|
||||
permBase, err := access_model.GetUserRepoPermission(ctx, baseRepo, ctx.Doer)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "GetUserRepoPermission", err)
|
||||
return nil, nil, nil, nil, "", ""
|
||||
}
|
||||
|
||||
if !permBase.CanRead(unit_model.TypeCode) {
|
||||
if log.IsTrace() {
|
||||
log.Trace("Permission Denied: User: %-v cannot read code in Repo: %-v\nUser in baseRepo has Permissions: %-+v",
|
||||
ctx.Doer,
|
||||
baseRepo,
|
||||
permBase)
|
||||
}
|
||||
ctx.NotFound("permBase.CanRead", nil)
|
||||
return nil, nil, nil, nil, "", ""
|
||||
}
|
||||
|
||||
if !isSameRepo {
|
||||
permHead, err := access_model.GetUserRepoPermission(ctx, headRepo, ctx.Doer)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "GetUserRepoPermission", err)
|
||||
return nil, nil, nil, nil, "", ""
|
||||
}
|
||||
if !permHead.CanRead(unit_model.TypeCode) {
|
||||
if log.IsTrace() {
|
||||
log.Trace("Permission Denied: User: %-v cannot read code in Repo: %-v\nUser in headRepo has Permissions: %-+v",
|
||||
ctx.Doer,
|
||||
headRepo,
|
||||
permHead)
|
||||
}
|
||||
ctx.NotFound("perHead.CanRead", nil)
|
||||
return nil, nil, nil, nil, "", ""
|
||||
}
|
||||
}
|
||||
|
||||
if rootRepo != nil &&
|
||||
rootRepo.ID != headRepo.ID &&
|
||||
rootRepo.ID != baseRepo.ID {
|
||||
perm, branches, err := getBranchesForRepo(ctx, ctx.Doer, rootRepo)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "getBranchesForRepo", err)
|
||||
return nil, nil, nil, nil, "", ""
|
||||
}
|
||||
if perm {
|
||||
ctx.Data["RootRepo"] = rootRepo
|
||||
ctx.Data["RootRepoBranches"] = branches
|
||||
}
|
||||
}
|
||||
|
||||
if ownForkRpo != nil &&
|
||||
ownForkRpo.ID != headRepo.ID &&
|
||||
ownForkRpo.ID != baseRepo.ID &&
|
||||
(rootRepo == nil || ownForkRpo.ID != rootRepo.ID) {
|
||||
perm, branches, err := getBranchesForRepo(ctx, ctx.Doer, ownForkRpo)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "getBranchesForRepo", err)
|
||||
return nil, nil, nil, nil, "", ""
|
||||
}
|
||||
if perm {
|
||||
ctx.Data["OwnForkRepo"] = ownForkRpo
|
||||
ctx.Data["OwnForkRepoBranches"] = branches
|
||||
}
|
||||
}
|
||||
|
||||
headIsCommit := headGitRepo.IsCommitExist(headBranch)
|
||||
headIsBranch := headGitRepo.IsBranchExist(headBranch)
|
||||
headIsTag := headGitRepo.IsTagExist(headBranch)
|
||||
if !headIsCommit && !headIsBranch && !headIsTag {
|
||||
if headCommit, _ := headGitRepo.GetCommit(headBranch); headCommit == nil {
|
||||
ctx.NotFound("isRefExist", nil)
|
||||
return nil, nil, nil, nil, "", ""
|
||||
} else {
|
||||
headBranch = headCommit.ID.String()
|
||||
ctx.Data["HeadBranch"] = headBranch
|
||||
headIsCommit = true
|
||||
}
|
||||
}
|
||||
|
||||
ctx.Data["HeadIsCommit"] = headIsCommit
|
||||
ctx.Data["HeadIsBranch"] = headIsBranch
|
||||
ctx.Data["HeadIsTag"] = headIsTag
|
||||
|
||||
if ctx.Data["PageIsComparePull"] == nil {
|
||||
ctx.Data["PageIsComparePull"] = headIsBranch && baseIsBranch
|
||||
}
|
||||
|
||||
if ctx.Data["PageIsComparePull"] == true && !permBase.CanReadIssuesOrPulls(true) {
|
||||
if log.IsTrace() {
|
||||
log.Trace("Permission Denied: User: %-v cannot create/read pull requests in Repo: %-v\nUser in baseRepo has Permissions: %-+v",
|
||||
ctx.Doer,
|
||||
baseRepo,
|
||||
permBase)
|
||||
}
|
||||
ctx.NotFound("can not read issues or pulls", nil)
|
||||
return nil, nil, nil, nil, "", ""
|
||||
}
|
||||
|
||||
baseBranchRef := baseBranch
|
||||
if baseIsBranch {
|
||||
baseBranchRef = git.BranchPrefix + baseBranch
|
||||
} else if baseIsTag {
|
||||
baseBranchRef = git.TagPrefix + baseBranch
|
||||
}
|
||||
headBranchRef := headBranch
|
||||
if headIsBranch {
|
||||
headBranchRef = git.BranchPrefix + headBranch
|
||||
} else if headIsTag {
|
||||
headBranchRef = git.TagPrefix + headBranch
|
||||
}
|
||||
|
||||
compareInfo, err := headGitRepo.GetCompareInfo(baseRepo.RepoPath(), baseBranchRef, headBranchRef, false, false)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "GetCompareInfo", err)
|
||||
return nil, nil, nil, nil, "", ""
|
||||
}
|
||||
ctx.Data["BeforeCommitID"] = compareInfo.MergeBase
|
||||
return headUser, headRepo, headGitRepo, compareInfo, baseBranch, headBranch
|
||||
}
|
||||
|
||||
func getBranchesForRepo(ctx *context.APIContext, user *user_model.User, repo *repo_model.Repository) (bool, []string, error) {
|
||||
perm, err := access_model.GetUserRepoPermission(ctx, repo, user)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
if !perm.CanRead(unit_model.TypeCode) {
|
||||
return false, nil, nil
|
||||
}
|
||||
gitRepo, err := git.OpenRepository(ctx, repo.RepoPath())
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
defer gitRepo.Close()
|
||||
branches, _, err := gitRepo.GetBranchNames(0, 0)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
return true, branches, nil
|
||||
}
|
||||
|
||||
func MustBeNotEmpty(ctx *context.Context) {
|
||||
if ctx.Repo.Repository.IsEmpty {
|
||||
ctx.NotFound("MustBeNotEmpty", nil)
|
||||
}
|
||||
}
|
||||
|
||||
func SetEditorconfigIfExists(ctx *context.Context) {
|
||||
if ctx.Repo.Repository.IsEmpty {
|
||||
ctx.Data["Edidorconfig"] = nil
|
||||
return
|
||||
}
|
||||
ec, err := ctx.Repo.GetEditorconfig()
|
||||
|
||||
if err != nil && !git.IsErrNotExist(err) {
|
||||
description := fmt.Sprintf("Error while getting .Editconfig file: %v", err)
|
||||
if err := admin_model.CreateRepositoryNotice(description); err != nil {
|
||||
ctx.ServerError("CreateRepositoryNotice", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
ctx.Data["Editorconfig"] = ec
|
||||
}
|
||||
|
||||
// SetdiffViewStyle set diff style as render variable
|
||||
func SetDiffViewStyle(ctx *context.Context) {
|
||||
|
||||
queryStyle := ctx.Params("style")
|
||||
if !ctx.IsSigned {
|
||||
ctx.Data["IsSplitStyle"] = queryStyle == "split"
|
||||
return
|
||||
}
|
||||
|
||||
var (
|
||||
userStyle = ctx.Doer.DiffViewStyle
|
||||
style string
|
||||
)
|
||||
|
||||
if queryStyle == "unified" || queryStyle == "split" {
|
||||
style = queryStyle
|
||||
} else if userStyle == "unified" || userStyle == "split" {
|
||||
style = userStyle
|
||||
} else {
|
||||
style = "unified"
|
||||
}
|
||||
ctx.Data["IsSplitStyle"] = style == "split"
|
||||
if err := user_model.UpdateUserDiffViewStyle(ctx.Doer, style); err != nil {
|
||||
ctx.ServerError("ErrUpdateDiffViewStyle", err)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue