diff --git a/models/pull.go b/models/pull.go
index fe18765fc0..5ac1126314 100644
--- a/models/pull.go
+++ b/models/pull.go
@@ -1144,8 +1144,7 @@ func (pr *PullRequest) UpdatePatch() (err error) {
defer func() {
headGitRepo.RemoveRemote(tmpRemote)
}()
- remoteBranch := "remotes/" + tmpRemote + "/" + pr.BaseBranch
- pr.MergeBase, err = headGitRepo.GetMergeBase(remoteBranch, pr.HeadBranch)
+ pr.MergeBase, err = headGitRepo.GetMergeBase(tmpRemote, pr.BaseBranch, pr.HeadBranch)
if err != nil {
return fmt.Errorf("GetMergeBase: %v", err)
} else if err = pr.Update(); err != nil {
diff --git a/modules/git/repo_commit.go b/modules/git/repo_commit.go
index b631f9341e..501ea88e40 100644
--- a/modules/git/repo_commit.go
+++ b/modules/git/repo_commit.go
@@ -27,6 +27,16 @@ func (repo *Repository) GetRefCommitID(name string) (string, error) {
return ref.Hash().String(), nil
}
+// IsCommitExist returns true if given commit exists in current repository.
+func (repo *Repository) IsCommitExist(name string) bool {
+ hash := plumbing.NewHash(name)
+ _, err := repo.gogitRepo.CommitObject(hash)
+ if err != nil {
+ return false
+ }
+ return true
+}
+
// GetBranchCommitID returns last commit ID string of given branch.
func (repo *Repository) GetBranchCommitID(name string) (string, error) {
return repo.GetRefCommitID(BranchPrefix + name)
diff --git a/modules/git/repo_pull.go b/modules/git/repo_compare.go
similarity index 55%
rename from modules/git/repo_pull.go
rename to modules/git/repo_compare.go
index 65c5414551..e7a1d72a85 100644
--- a/modules/git/repo_pull.go
+++ b/modules/git/repo_compare.go
@@ -1,4 +1,5 @@
// Copyright 2015 The Gogs Authors. All rights reserved.
+// Copyright 2019 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
@@ -14,55 +15,66 @@ import (
"time"
)
-// PullRequestInfo represents needed information for a pull request.
-type PullRequestInfo struct {
+// CompareInfo represents needed information for comparing references.
+type CompareInfo struct {
MergeBase string
Commits *list.List
NumFiles int
}
// GetMergeBase checks and returns merge base of two branches.
-func (repo *Repository) GetMergeBase(base, head string) (string, error) {
+func (repo *Repository) GetMergeBase(tmpRemote string, base, head string) (string, error) {
+ if tmpRemote == "" {
+ tmpRemote = "origin"
+ }
+
+ if tmpRemote != "origin" {
+ tmpBaseName := "refs/remotes/" + tmpRemote + "/tmp_" + base
+ // Fetch commit into a temporary branch in order to be able to handle commits and tags
+ _, err := NewCommand("fetch", tmpRemote, base+":"+tmpBaseName).RunInDir(repo.Path)
+ if err == nil {
+ base = tmpBaseName
+ }
+ }
+
stdout, err := NewCommand("merge-base", base, head).RunInDir(repo.Path)
return strings.TrimSpace(stdout), err
}
-// GetPullRequestInfo generates and returns pull request information
-// between base and head branches of repositories.
-func (repo *Repository) GetPullRequestInfo(basePath, baseBranch, headBranch string) (_ *PullRequestInfo, err error) {
- var remoteBranch string
+// GetCompareInfo generates and returns compare information between base and head branches of repositories.
+func (repo *Repository) GetCompareInfo(basePath, baseBranch, headBranch string) (_ *CompareInfo, err error) {
+ var (
+ remoteBranch string
+ tmpRemote string
+ )
// We don't need a temporary remote for same repository.
if repo.Path != basePath {
// Add a temporary remote
- tmpRemote := strconv.FormatInt(time.Now().UnixNano(), 10)
+ tmpRemote = strconv.FormatInt(time.Now().UnixNano(), 10)
if err = repo.AddRemote(tmpRemote, basePath, true); err != nil {
return nil, fmt.Errorf("AddRemote: %v", err)
}
defer repo.RemoveRemote(tmpRemote)
-
- remoteBranch = "remotes/" + tmpRemote + "/" + baseBranch
- } else {
- remoteBranch = baseBranch
}
- prInfo := new(PullRequestInfo)
- prInfo.MergeBase, err = repo.GetMergeBase(remoteBranch, headBranch)
+ compareInfo := new(CompareInfo)
+ compareInfo.MergeBase, err = repo.GetMergeBase(tmpRemote, baseBranch, headBranch)
if err == nil {
// We have a common base
- logs, err := NewCommand("log", prInfo.MergeBase+"..."+headBranch, prettyLogFormat).RunInDirBytes(repo.Path)
+ logs, err := NewCommand("log", compareInfo.MergeBase+"..."+headBranch, prettyLogFormat).RunInDirBytes(repo.Path)
if err != nil {
return nil, err
}
- prInfo.Commits, err = repo.parsePrettyFormatLogToList(logs)
+ compareInfo.Commits, err = repo.parsePrettyFormatLogToList(logs)
if err != nil {
return nil, fmt.Errorf("parsePrettyFormatLogToList: %v", err)
}
} else {
- prInfo.Commits = list.New()
- prInfo.MergeBase, err = GetFullCommitID(repo.Path, remoteBranch)
+ compareInfo.Commits = list.New()
+ compareInfo.MergeBase, err = GetFullCommitID(repo.Path, remoteBranch)
if err != nil {
- prInfo.MergeBase = remoteBranch
+ compareInfo.MergeBase = remoteBranch
}
}
@@ -71,9 +83,9 @@ func (repo *Repository) GetPullRequestInfo(basePath, baseBranch, headBranch stri
if err != nil {
return nil, err
}
- prInfo.NumFiles = len(strings.Split(stdout, "\n")) - 1
+ compareInfo.NumFiles = len(strings.Split(stdout, "\n")) - 1
- return prInfo, nil
+ return compareInfo, nil
}
// GetPatch generates and returns patch data between given revisions.
diff --git a/modules/git/repo_pull_test.go b/modules/git/repo_compare_test.go
similarity index 100%
rename from modules/git/repo_pull_test.go
rename to modules/git/repo_compare_test.go
diff --git a/public/css/index.css b/public/css/index.css
index 8950cc7038..d192f43d15 100644
--- a/public/css/index.css
+++ b/public/css/index.css
@@ -591,6 +591,7 @@ footer .ui.left,footer .ui.right{line-height:40px}
.repository .milestone.list>.item .content{padding-top:10px}
.repository.new.milestone textarea{height:200px}
.repository.new.milestone #deadline{width:150px}
+.repository.compare.pull .show-form-container{text-align:left}
.repository.compare.pull .choose.branch .octicon{padding-right:10px}
.repository.compare.pull .comment.form .content:after,.repository.compare.pull .comment.form .content:before{right:100%;top:20px;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none}
.repository.compare.pull .comment.form .content:before{border-right-color:#d3d3d4;border-width:9px;margin-top:-9px}
diff --git a/public/js/index.js b/public/js/index.js
index ed3198594a..28023e1061 100644
--- a/public/js/index.js
+++ b/public/js/index.js
@@ -959,8 +959,15 @@ function initRepository() {
});
// Pull request
- if ($('.repository.compare.pull').length > 0) {
+ var $repoComparePull = $('.repository.compare.pull');
+ if ($repoComparePull.length > 0) {
initFilterSearchDropdown('.choose.branch .dropdown');
+ // show pull request form
+ $repoComparePull.find('button.show-form').on('click', function(e) {
+ e.preventDefault();
+ $repoComparePull.find('.pullrequest-form').show();
+ $(this).parent().hide();
+ });
}
// Branches
diff --git a/public/less/_repository.less b/public/less/_repository.less
index 9956bbce74..fcc153e31e 100644
--- a/public/less/_repository.less
+++ b/public/less/_repository.less
@@ -1109,6 +1109,9 @@
}
&.compare.pull {
+ .show-form-container {
+ text-align: left;
+ }
.choose.branch {
.octicon {
padding-right: 10px;
diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go
index f53ab4b8f3..0e1db144b1 100644
--- a/routers/api/v1/repo/pull.go
+++ b/routers/api/v1/repo/pull.go
@@ -188,7 +188,7 @@ func CreatePullRequest(ctx *context.APIContext, form api.CreatePullRequestOption
)
// Get repo/branch information
- headUser, headRepo, headGitRepo, prInfo, baseBranch, headBranch := parseCompareInfo(ctx, form)
+ headUser, headRepo, headGitRepo, compareInfo, baseBranch, headBranch := parseCompareInfo(ctx, form)
if ctx.Written() {
return
}
@@ -240,7 +240,7 @@ func CreatePullRequest(ctx *context.APIContext, form api.CreatePullRequestOption
milestoneID = milestone.ID
}
- patch, err := headGitRepo.GetPatch(prInfo.MergeBase, headBranch)
+ patch, err := headGitRepo.GetPatch(compareInfo.MergeBase, headBranch)
if err != nil {
ctx.Error(500, "GetPatch", err)
return
@@ -277,7 +277,7 @@ func CreatePullRequest(ctx *context.APIContext, form api.CreatePullRequestOption
BaseBranch: baseBranch,
HeadRepo: headRepo,
BaseRepo: repo,
- MergeBase: prInfo.MergeBase,
+ MergeBase: compareInfo.MergeBase,
Type: models.PullRequestGitea,
}
@@ -600,7 +600,7 @@ func MergePullRequest(ctx *context.APIContext, form auth.MergePullRequestForm) {
ctx.Status(200)
}
-func parseCompareInfo(ctx *context.APIContext, form api.CreatePullRequestOption) (*models.User, *models.Repository, *git.Repository, *git.PullRequestInfo, string, string) {
+func parseCompareInfo(ctx *context.APIContext, form api.CreatePullRequestOption) (*models.User, *models.Repository, *git.Repository, *git.CompareInfo, string, string) {
baseRepo := ctx.Repo.Repository
// Get compared branches information
@@ -712,11 +712,11 @@ func parseCompareInfo(ctx *context.APIContext, form api.CreatePullRequestOption)
return nil, nil, nil, nil, "", ""
}
- prInfo, err := headGitRepo.GetPullRequestInfo(models.RepoPath(baseRepo.Owner.Name, baseRepo.Name), baseBranch, headBranch)
+ compareInfo, err := headGitRepo.GetCompareInfo(models.RepoPath(baseRepo.Owner.Name, baseRepo.Name), baseBranch, headBranch)
if err != nil {
- ctx.Error(500, "GetPullRequestInfo", err)
+ ctx.Error(500, "GetCompareInfo", err)
return nil, nil, nil, nil, "", ""
}
- return headUser, headRepo, headGitRepo, prInfo, baseBranch, headBranch
+ return headUser, headRepo, headGitRepo, compareInfo, baseBranch, headBranch
}
diff --git a/routers/repo/commit.go b/routers/repo/commit.go
index 870ff568f3..dde6d8f321 100644
--- a/routers/repo/commit.go
+++ b/routers/repo/commit.go
@@ -19,9 +19,9 @@ import (
)
const (
- tplCommits base.TplName = "repo/commits"
- tplGraph base.TplName = "repo/graph"
- tplDiff base.TplName = "repo/diff/page"
+ tplCommits base.TplName = "repo/commits"
+ tplGraph base.TplName = "repo/graph"
+ tplCommitPage base.TplName = "repo/commit_page"
)
// RefCommits render commits page
@@ -261,7 +261,7 @@ func Diff(ctx *context.Context) {
}
ctx.Data["RawPath"] = setting.AppSubURL + "/" + path.Join(userName, repoName, "raw", "commit", commitID)
ctx.Data["BranchName"], err = commit.GetBranchName()
- ctx.HTML(200, tplDiff)
+ ctx.HTML(200, tplCommitPage)
}
// RawDiff dumps diff results of repository in given commit ID to io.Writer
@@ -276,54 +276,3 @@ func RawDiff(ctx *context.Context) {
return
}
}
-
-// CompareDiff show different from one commit to another commit
-func CompareDiff(ctx *context.Context) {
- ctx.Data["IsRepoToolbarCommits"] = true
- ctx.Data["IsDiffCompare"] = true
- userName := ctx.Repo.Owner.Name
- repoName := ctx.Repo.Repository.Name
- beforeCommitID := ctx.Params(":before")
- afterCommitID := ctx.Params(":after")
-
- commit, err := ctx.Repo.GitRepo.GetCommit(afterCommitID)
- if err != nil {
- ctx.NotFound("GetCommit", err)
- return
- }
-
- diff, err := models.GetDiffRange(models.RepoPath(userName, repoName), beforeCommitID,
- afterCommitID, setting.Git.MaxGitDiffLines,
- setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles)
- if err != nil {
- ctx.NotFound("GetDiffRange", err)
- return
- }
-
- commits, err := commit.CommitsBeforeUntil(beforeCommitID)
- if err != nil {
- ctx.ServerError("CommitsBeforeUntil", err)
- return
- }
- commits = models.ValidateCommitsWithEmails(commits)
- commits = models.ParseCommitsWithSignature(commits)
- commits = models.ParseCommitsWithStatus(commits, ctx.Repo.Repository)
-
- ctx.Data["CommitRepoLink"] = ctx.Repo.RepoLink
- ctx.Data["Commits"] = commits
- ctx.Data["CommitCount"] = commits.Len()
- ctx.Data["BeforeCommitID"] = beforeCommitID
- ctx.Data["AfterCommitID"] = afterCommitID
- ctx.Data["Username"] = userName
- ctx.Data["Reponame"] = repoName
- ctx.Data["IsImageFile"] = commit.IsImageFile
- ctx.Data["Title"] = "Comparing " + base.ShortSha(beforeCommitID) + "..." + base.ShortSha(afterCommitID) + " ยท " + userName + "/" + repoName
- ctx.Data["Commit"] = commit
- ctx.Data["Diff"] = diff
- ctx.Data["DiffNotAvailable"] = diff.NumFiles() == 0
- ctx.Data["SourcePath"] = setting.AppSubURL + "/" + path.Join(userName, repoName, "src", "commit", afterCommitID)
- ctx.Data["BeforeSourcePath"] = setting.AppSubURL + "/" + path.Join(userName, repoName, "src", "commit", beforeCommitID)
- ctx.Data["RawPath"] = setting.AppSubURL + "/" + path.Join(userName, repoName, "raw", "commit", afterCommitID)
- ctx.Data["RequireHighlightJS"] = true
- ctx.HTML(200, tplDiff)
-}
diff --git a/routers/repo/compare.go b/routers/repo/compare.go
new file mode 100644
index 0000000000..a85084791d
--- /dev/null
+++ b/routers/repo/compare.go
@@ -0,0 +1,337 @@
+// Copyright 2019 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package repo
+
+import (
+ "path"
+ "strings"
+
+ "code.gitea.io/gitea/models"
+ "code.gitea.io/gitea/modules/base"
+ "code.gitea.io/gitea/modules/context"
+ "code.gitea.io/gitea/modules/git"
+ "code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/setting"
+)
+
+const (
+ tplCompare base.TplName = "repo/diff/compare"
+)
+
+// ParseCompareInfo parse compare info between two commit for preparing comparing references
+func ParseCompareInfo(ctx *context.Context) (*models.User, *models.Repository, *git.Repository, *git.CompareInfo, string, string) {
+ baseRepo := ctx.Repo.Repository
+
+ // Get compared branches information
+ // format: ...[
:]
+ // base<-head: master...head:feature
+ // same repo: master...feature
+
+ var (
+ headUser *models.User
+ headBranch string
+ isSameRepo bool
+ infoPath string
+ err error
+ )
+ infoPath = ctx.Params("*")
+ infos := strings.Split(infoPath, "...")
+ 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, "", ""
+ }
+
+ baseBranch := infos[0]
+ ctx.Data["BaseBranch"] = baseBranch
+
+ // If there is no head repository, it means compare between same repository.
+ headInfos := strings.Split(infos[1], ":")
+ if len(headInfos) == 1 {
+ isSameRepo = true
+ headUser = ctx.Repo.Owner
+ headBranch = headInfos[0]
+
+ } else if len(headInfos) == 2 {
+ headUser, err = models.GetUserByName(headInfos[0])
+ if err != nil {
+ if models.IsErrUserNotExist(err) {
+ ctx.NotFound("GetUserByName", nil)
+ } else {
+ ctx.ServerError("GetUserByName", err)
+ }
+ return nil, nil, nil, nil, "", ""
+ }
+ headBranch = headInfos[1]
+ isSameRepo = headUser.ID == ctx.Repo.Owner.ID
+ } else {
+ ctx.NotFound("CompareAndPullRequest", nil)
+ return nil, nil, nil, nil, "", ""
+ }
+ ctx.Data["HeadUser"] = headUser
+ ctx.Data["HeadBranch"] = headBranch
+ ctx.Repo.PullRequest.SameRepo = isSameRepo
+
+ // Check if base branch is valid.
+ baseIsCommit := ctx.Repo.GitRepo.IsCommitExist(baseBranch)
+ baseIsBranch := ctx.Repo.GitRepo.IsBranchExist(baseBranch)
+ baseIsTag := ctx.Repo.GitRepo.IsTagExist(baseBranch)
+ if !baseIsCommit && !baseIsBranch && !baseIsTag {
+ // Check if baseBranch is short sha commit hash
+ if baseCommit, _ := ctx.Repo.GitRepo.GetCommit(baseBranch); baseCommit != nil {
+ baseBranch = baseCommit.ID.String()
+ ctx.Data["BaseBranch"] = baseBranch
+ baseIsCommit = true
+ } else {
+ ctx.NotFound("IsRefExist", nil)
+ return nil, nil, nil, nil, "", ""
+ }
+ }
+ ctx.Data["BaseIsCommit"] = baseIsCommit
+ ctx.Data["BaseIsBranch"] = baseIsBranch
+ ctx.Data["BaseIsTag"] = baseIsTag
+
+ // Check if current user has fork of repository or in the same repository.
+ headRepo, has := models.HasForkedRepo(headUser.ID, baseRepo.ID)
+ if !has && !isSameRepo {
+ ctx.Data["PageIsComparePull"] = false
+ }
+
+ var headGitRepo *git.Repository
+ if isSameRepo {
+ headRepo = ctx.Repo.Repository
+ headGitRepo = ctx.Repo.GitRepo
+ ctx.Data["BaseName"] = headUser.Name
+ } else {
+ headGitRepo, err = git.OpenRepository(models.RepoPath(headUser.Name, headRepo.Name))
+ ctx.Data["BaseName"] = baseRepo.OwnerName
+ if err != nil {
+ ctx.ServerError("OpenRepository", err)
+ return nil, nil, nil, nil, "", ""
+ }
+ }
+
+ // user should have permission to read baseRepo's codes and pulls, NOT headRepo's
+ permBase, err := models.GetUserRepoPermission(baseRepo, ctx.User)
+ if err != nil {
+ ctx.ServerError("GetUserRepoPermission", err)
+ return nil, nil, nil, nil, "", ""
+ }
+ if !permBase.CanRead(models.UnitTypeCode) {
+ if log.IsTrace() {
+ log.Trace("Permission Denied: User: %-v cannot read code in Repo: %-v\nUser in baseRepo has Permissions: %-+v",
+ ctx.User,
+ baseRepo,
+ permBase)
+ }
+ ctx.NotFound("ParseCompareInfo", nil)
+ return nil, nil, nil, nil, "", ""
+ }
+
+ // user should have permission to read headrepo's codes
+ permHead, err := models.GetUserRepoPermission(headRepo, ctx.User)
+ if err != nil {
+ ctx.ServerError("GetUserRepoPermission", err)
+ return nil, nil, nil, nil, "", ""
+ }
+ if !permHead.CanRead(models.UnitTypeCode) {
+ if log.IsTrace() {
+ log.Trace("Permission Denied: User: %-v cannot read code in Repo: %-v\nUser in headRepo has Permissions: %-+v",
+ ctx.User,
+ headRepo,
+ permHead)
+ }
+ ctx.NotFound("ParseCompareInfo", nil)
+ return nil, nil, nil, nil, "", ""
+ }
+
+ // Check if head branch is valid.
+ headIsCommit := ctx.Repo.GitRepo.IsCommitExist(headBranch)
+ headIsBranch := headGitRepo.IsBranchExist(headBranch)
+ headIsTag := headGitRepo.IsTagExist(headBranch)
+ if !headIsCommit && !headIsBranch && !headIsTag {
+ // Check if headBranch is short sha commit hash
+ if headCommit, _ := ctx.Repo.GitRepo.GetCommit(headBranch); headCommit != nil {
+ headBranch = headCommit.ID.String()
+ ctx.Data["HeadBranch"] = headBranch
+ headIsCommit = true
+ } else {
+ ctx.NotFound("IsRefExist", nil)
+ return nil, nil, nil, nil, "", ""
+ }
+ }
+ ctx.Data["HeadIsCommit"] = headIsCommit
+ ctx.Data["HeadIsBranch"] = headIsBranch
+ ctx.Data["HeadIsTag"] = headIsTag
+
+ // Treat as pull request if both references are branches
+ 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.User,
+ baseRepo,
+ permBase)
+ }
+ ctx.NotFound("ParseCompareInfo", nil)
+ return nil, nil, nil, nil, "", ""
+ }
+
+ compareInfo, err := headGitRepo.GetCompareInfo(models.RepoPath(baseRepo.Owner.Name, baseRepo.Name), baseBranch, headBranch)
+ if err != nil {
+ ctx.ServerError("GetCompareInfo", err)
+ return nil, nil, nil, nil, "", ""
+ }
+ ctx.Data["BeforeCommitID"] = compareInfo.MergeBase
+
+ return headUser, headRepo, headGitRepo, compareInfo, baseBranch, headBranch
+}
+
+// PrepareCompareDiff renders compare diff page
+func PrepareCompareDiff(
+ ctx *context.Context,
+ headUser *models.User,
+ headRepo *models.Repository,
+ headGitRepo *git.Repository,
+ compareInfo *git.CompareInfo,
+ baseBranch, headBranch string) bool {
+
+ var (
+ repo = ctx.Repo.Repository
+ err error
+ title string
+ )
+
+ // Get diff information.
+ 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.ServerError("GetRefCommitID", err)
+ return false
+ }
+ }
+
+ ctx.Data["AfterCommitID"] = headCommitID
+
+ if headCommitID == compareInfo.MergeBase {
+ ctx.Data["IsNothingToCompare"] = true
+ return true
+ }
+
+ diff, err := models.GetDiffRange(models.RepoPath(headUser.Name, headRepo.Name),
+ compareInfo.MergeBase, headCommitID, setting.Git.MaxGitDiffLines,
+ setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles)
+ if err != nil {
+ ctx.ServerError("GetDiffRange", err)
+ return false
+ }
+ ctx.Data["Diff"] = diff
+ ctx.Data["DiffNotAvailable"] = diff.NumFiles() == 0
+
+ headCommit, err := headGitRepo.GetCommit(headCommitID)
+ if err != nil {
+ ctx.ServerError("GetCommit", err)
+ return false
+ }
+
+ compareInfo.Commits = models.ValidateCommitsWithEmails(compareInfo.Commits)
+ compareInfo.Commits = models.ParseCommitsWithSignature(compareInfo.Commits)
+ compareInfo.Commits = models.ParseCommitsWithStatus(compareInfo.Commits, headRepo)
+ ctx.Data["Commits"] = compareInfo.Commits
+ ctx.Data["CommitCount"] = compareInfo.Commits.Len()
+ if ctx.Data["CommitCount"] == 0 {
+ ctx.Data["PageIsComparePull"] = false
+ }
+
+ if compareInfo.Commits.Len() == 1 {
+ c := compareInfo.Commits.Front().Value.(models.SignCommitWithStatuses)
+ title = strings.TrimSpace(c.UserCommit.Summary())
+
+ body := strings.Split(strings.TrimSpace(c.UserCommit.Message()), "\n")
+ if len(body) > 1 {
+ ctx.Data["content"] = strings.Join(body[1:], "\n")
+ }
+ } else {
+ title = headBranch
+ }
+
+ ctx.Data["title"] = title
+ ctx.Data["Username"] = headUser.Name
+ ctx.Data["Reponame"] = headRepo.Name
+ ctx.Data["IsImageFile"] = headCommit.IsImageFile
+
+ headTarget := path.Join(headUser.Name, repo.Name)
+ ctx.Data["SourcePath"] = setting.AppSubURL + "/" + path.Join(headTarget, "src", "commit", headCommitID)
+ ctx.Data["BeforeSourcePath"] = setting.AppSubURL + "/" + path.Join(headTarget, "src", "commit", compareInfo.MergeBase)
+ ctx.Data["RawPath"] = setting.AppSubURL + "/" + path.Join(headTarget, "raw", "commit", headCommitID)
+ return false
+}
+
+// CompareDiff show different from one commit to another commit
+func CompareDiff(ctx *context.Context) {
+ headUser, headRepo, headGitRepo, compareInfo, baseBranch, headBranch := ParseCompareInfo(ctx)
+ if ctx.Written() {
+ return
+ }
+
+ nothingToCompare := PrepareCompareDiff(ctx, headUser, headRepo, headGitRepo, compareInfo, baseBranch, headBranch)
+ if ctx.Written() {
+ return
+ }
+
+ if ctx.Data["PageIsComparePull"] == true {
+ pr, err := models.GetUnmergedPullRequest(headRepo.ID, ctx.Repo.Repository.ID, headBranch, baseBranch)
+ if err != nil {
+ if !models.IsErrPullRequestNotExist(err) {
+ ctx.ServerError("GetUnmergedPullRequest", err)
+ return
+ }
+ } else {
+ ctx.Data["HasPullRequest"] = true
+ ctx.Data["PullRequest"] = pr
+ ctx.HTML(200, tplCompareDiff)
+ return
+ }
+
+ if !nothingToCompare {
+ // Setup information for new form.
+ RetrieveRepoMetas(ctx, ctx.Repo.Repository)
+ if ctx.Written() {
+ return
+ }
+ }
+
+ headBranches, err := headGitRepo.GetBranches()
+ if err != nil {
+ ctx.ServerError("GetBranches", err)
+ return
+ }
+ ctx.Data["HeadBranches"] = headBranches
+ }
+ beforeCommitID := ctx.Data["BeforeCommitID"].(string)
+ afterCommitID := ctx.Data["AfterCommitID"].(string)
+
+ ctx.Data["Title"] = "Comparing " + base.ShortSha(beforeCommitID) + "..." + base.ShortSha(afterCommitID)
+
+ ctx.Data["IsRepoToolbarCommits"] = true
+ ctx.Data["IsDiffCompare"] = true
+ ctx.Data["RequireHighlightJS"] = true
+ ctx.Data["RequireTribute"] = true
+ ctx.Data["PullRequestWorkInProgressPrefixes"] = setting.Repository.PullRequest.WorkInProgressPrefixes
+ setTemplateIfExists(ctx, pullRequestTemplateKey, pullRequestTemplateCandidates)
+ renderAttachmentSettings(ctx)
+
+ ctx.HTML(200, tplCompare)
+}
diff --git a/routers/repo/pull.go b/routers/repo/pull.go
index 412750dd55..182f715545 100644
--- a/routers/repo/pull.go
+++ b/routers/repo/pull.go
@@ -28,7 +28,7 @@ import (
const (
tplFork base.TplName = "repo/pulls/fork"
- tplComparePull base.TplName = "repo/pulls/compare"
+ tplCompareDiff base.TplName = "repo/diff/compare"
tplPullCommits base.TplName = "repo/pulls/commits"
tplPullFiles base.TplName = "repo/pulls/files"
@@ -280,13 +280,13 @@ func setMergeTarget(ctx *context.Context, pull *models.PullRequest) {
}
// PrepareMergedViewPullInfo show meta information for a merged pull request view page
-func PrepareMergedViewPullInfo(ctx *context.Context, issue *models.Issue) *git.PullRequestInfo {
+func PrepareMergedViewPullInfo(ctx *context.Context, issue *models.Issue) *git.CompareInfo {
pull := issue.PullRequest
setMergeTarget(ctx, pull)
ctx.Data["HasMerged"] = true
- prInfo, err := ctx.Repo.GitRepo.GetPullRequestInfo(ctx.Repo.Repository.RepoPath(),
+ prInfo, err := ctx.Repo.GitRepo.GetCompareInfo(ctx.Repo.Repository.RepoPath(),
pull.MergeBase, pull.GetGitRefName())
if err != nil {
@@ -298,7 +298,7 @@ func PrepareMergedViewPullInfo(ctx *context.Context, issue *models.Issue) *git.P
return nil
}
- ctx.ServerError("GetPullRequestInfo", err)
+ ctx.ServerError("GetCompareInfo", err)
return nil
}
ctx.Data["NumCommits"] = prInfo.Commits.Len()
@@ -307,7 +307,7 @@ func PrepareMergedViewPullInfo(ctx *context.Context, issue *models.Issue) *git.P
}
// PrepareViewPullInfo show meta information for a pull request preview page
-func PrepareViewPullInfo(ctx *context.Context, issue *models.Issue) *git.PullRequestInfo {
+func PrepareViewPullInfo(ctx *context.Context, issue *models.Issue) *git.CompareInfo {
repo := ctx.Repo.Repository
pull := issue.PullRequest
@@ -336,7 +336,7 @@ func PrepareViewPullInfo(ctx *context.Context, issue *models.Issue) *git.PullReq
return nil
}
- prInfo, err := headGitRepo.GetPullRequestInfo(models.RepoPath(repo.Owner.Name, repo.Name),
+ prInfo, err := headGitRepo.GetCompareInfo(models.RepoPath(repo.Owner.Name, repo.Name),
pull.BaseBranch, pull.HeadBranch)
if err != nil {
if strings.Contains(err.Error(), "fatal: Not a valid object name") {
@@ -347,7 +347,7 @@ func PrepareViewPullInfo(ctx *context.Context, issue *models.Issue) *git.PullReq
return nil
}
- ctx.ServerError("GetPullRequestInfo", err)
+ ctx.ServerError("GetCompareInfo", err)
return nil
}
@@ -628,266 +628,6 @@ func stopTimerIfAvailable(user *models.User, issue *models.Issue) error {
return nil
}
-// ParseCompareInfo parse compare info between two commit for preparing pull request
-func ParseCompareInfo(ctx *context.Context) (*models.User, *models.Repository, *git.Repository, *git.PullRequestInfo, string, string) {
- baseRepo := ctx.Repo.Repository
-
- // Get compared branches information
- // format: ...[:]
- // base<-head: master...head:feature
- // same repo: master...feature
-
- var (
- headUser *models.User
- headBranch string
- isSameRepo bool
- infoPath string
- err error
- )
- infoPath = ctx.Params("*")
- infos := strings.Split(infoPath, "...")
- 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, "", ""
- }
-
- baseBranch := infos[0]
- ctx.Data["BaseBranch"] = baseBranch
-
- // If there is no head repository, it means pull request between same repository.
- headInfos := strings.Split(infos[1], ":")
- if len(headInfos) == 1 {
- isSameRepo = true
- headUser = ctx.Repo.Owner
- headBranch = headInfos[0]
-
- } else if len(headInfos) == 2 {
- headUser, err = models.GetUserByName(headInfos[0])
- if err != nil {
- if models.IsErrUserNotExist(err) {
- ctx.NotFound("GetUserByName", nil)
- } else {
- ctx.ServerError("GetUserByName", err)
- }
- return nil, nil, nil, nil, "", ""
- }
- headBranch = headInfos[1]
- isSameRepo = headUser.ID == ctx.Repo.Owner.ID
- } else {
- ctx.NotFound("CompareAndPullRequest", nil)
- return nil, nil, nil, nil, "", ""
- }
- ctx.Data["HeadUser"] = headUser
- ctx.Data["HeadBranch"] = headBranch
- ctx.Repo.PullRequest.SameRepo = isSameRepo
-
- // Check if base branch is valid.
- if !ctx.Repo.GitRepo.IsBranchExist(baseBranch) {
- ctx.NotFound("IsBranchExist", nil)
- return nil, nil, nil, nil, "", ""
- }
-
- // Check if current user has fork of repository or in the same repository.
- headRepo, has := models.HasForkedRepo(headUser.ID, baseRepo.ID)
- if !has && !isSameRepo {
- log.Trace("ParseCompareInfo[%d]: does not have fork or in same repository", baseRepo.ID)
- ctx.NotFound("ParseCompareInfo", nil)
- return nil, nil, nil, nil, "", ""
- }
-
- var headGitRepo *git.Repository
- if isSameRepo {
- headRepo = ctx.Repo.Repository
- headGitRepo = ctx.Repo.GitRepo
- ctx.Data["BaseName"] = headUser.Name
- } else {
- headGitRepo, err = git.OpenRepository(models.RepoPath(headUser.Name, headRepo.Name))
- ctx.Data["BaseName"] = baseRepo.OwnerName
- if err != nil {
- ctx.ServerError("OpenRepository", err)
- return nil, nil, nil, nil, "", ""
- }
- }
-
- // user should have permission to read baseRepo's codes and pulls, NOT headRepo's
- permBase, err := models.GetUserRepoPermission(baseRepo, ctx.User)
- if err != nil {
- ctx.ServerError("GetUserRepoPermission", err)
- return nil, nil, nil, nil, "", ""
- }
- if !permBase.CanReadIssuesOrPulls(true) || !permBase.CanRead(models.UnitTypeCode) {
- if log.IsTrace() {
- 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.User,
- baseRepo,
- permBase)
- }
- ctx.NotFound("ParseCompareInfo", nil)
- return nil, nil, nil, nil, "", ""
- }
-
- // user should have permission to read headrepo's codes
- permHead, err := models.GetUserRepoPermission(headRepo, ctx.User)
- if err != nil {
- ctx.ServerError("GetUserRepoPermission", err)
- return nil, nil, nil, nil, "", ""
- }
- if !permHead.CanRead(models.UnitTypeCode) {
- if log.IsTrace() {
- log.Trace("Permission Denied: User: %-v cannot read code requests in Repo: %-v\nUser in headRepo has Permissions: %-+v",
- ctx.User,
- headRepo,
- permHead)
- }
- ctx.NotFound("ParseCompareInfo", nil)
- return nil, nil, nil, nil, "", ""
- }
-
- // Check if head branch is valid.
- if !headGitRepo.IsBranchExist(headBranch) {
- ctx.NotFound("IsBranchExist", nil)
- return nil, nil, nil, nil, "", ""
- }
-
- headBranches, err := headGitRepo.GetBranches()
- if err != nil {
- ctx.ServerError("GetBranches", err)
- return nil, nil, nil, nil, "", ""
- }
- ctx.Data["HeadBranches"] = headBranches
-
- prInfo, err := headGitRepo.GetPullRequestInfo(models.RepoPath(baseRepo.Owner.Name, baseRepo.Name), baseBranch, headBranch)
- if err != nil {
- ctx.ServerError("GetPullRequestInfo", err)
- return nil, nil, nil, nil, "", ""
- }
- ctx.Data["BeforeCommitID"] = prInfo.MergeBase
-
- return headUser, headRepo, headGitRepo, prInfo, baseBranch, headBranch
-}
-
-// PrepareCompareDiff render pull request preview diff page
-func PrepareCompareDiff(
- ctx *context.Context,
- headUser *models.User,
- headRepo *models.Repository,
- headGitRepo *git.Repository,
- prInfo *git.PullRequestInfo,
- baseBranch, headBranch string) bool {
-
- var (
- repo = ctx.Repo.Repository
- err error
- title string
- )
-
- // Get diff information.
- ctx.Data["CommitRepoLink"] = headRepo.Link()
-
- headCommitID, err := headGitRepo.GetBranchCommitID(headBranch)
- if err != nil {
- ctx.ServerError("GetBranchCommitID", err)
- return false
- }
- ctx.Data["AfterCommitID"] = headCommitID
-
- if headCommitID == prInfo.MergeBase {
- ctx.Data["IsNothingToCompare"] = true
- return true
- }
-
- diff, err := models.GetDiffRange(models.RepoPath(headUser.Name, headRepo.Name),
- prInfo.MergeBase, headCommitID, setting.Git.MaxGitDiffLines,
- setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles)
- if err != nil {
- ctx.ServerError("GetDiffRange", err)
- return false
- }
- ctx.Data["Diff"] = diff
- ctx.Data["DiffNotAvailable"] = diff.NumFiles() == 0
-
- headCommit, err := headGitRepo.GetCommit(headCommitID)
- if err != nil {
- ctx.ServerError("GetCommit", err)
- return false
- }
-
- prInfo.Commits = models.ValidateCommitsWithEmails(prInfo.Commits)
- prInfo.Commits = models.ParseCommitsWithSignature(prInfo.Commits)
- prInfo.Commits = models.ParseCommitsWithStatus(prInfo.Commits, headRepo)
- ctx.Data["Commits"] = prInfo.Commits
- ctx.Data["CommitCount"] = prInfo.Commits.Len()
-
- if prInfo.Commits.Len() == 1 {
- c := prInfo.Commits.Front().Value.(models.SignCommitWithStatuses)
- title = strings.TrimSpace(c.UserCommit.Summary())
-
- body := strings.Split(strings.TrimSpace(c.UserCommit.Message()), "\n")
- if len(body) > 1 {
- ctx.Data["content"] = strings.Join(body[1:], "\n")
- }
- } else {
- title = headBranch
- }
-
- ctx.Data["title"] = title
- ctx.Data["Username"] = headUser.Name
- ctx.Data["Reponame"] = headRepo.Name
- ctx.Data["IsImageFile"] = headCommit.IsImageFile
-
- headTarget := path.Join(headUser.Name, repo.Name)
- ctx.Data["SourcePath"] = setting.AppSubURL + "/" + path.Join(headTarget, "src", "commit", headCommitID)
- ctx.Data["BeforeSourcePath"] = setting.AppSubURL + "/" + path.Join(headTarget, "src", "commit", prInfo.MergeBase)
- ctx.Data["RawPath"] = setting.AppSubURL + "/" + path.Join(headTarget, "raw", "commit", headCommitID)
- return false
-}
-
-// CompareAndPullRequest render pull request preview page
-func CompareAndPullRequest(ctx *context.Context) {
- ctx.Data["Title"] = ctx.Tr("repo.pulls.compare_changes")
- ctx.Data["PageIsComparePull"] = true
- ctx.Data["IsDiffCompare"] = true
- ctx.Data["RequireHighlightJS"] = true
- ctx.Data["RequireTribute"] = true
- ctx.Data["PullRequestWorkInProgressPrefixes"] = setting.Repository.PullRequest.WorkInProgressPrefixes
- setTemplateIfExists(ctx, pullRequestTemplateKey, pullRequestTemplateCandidates)
- renderAttachmentSettings(ctx)
-
- headUser, headRepo, headGitRepo, prInfo, baseBranch, headBranch := ParseCompareInfo(ctx)
- if ctx.Written() {
- return
- }
-
- pr, err := models.GetUnmergedPullRequest(headRepo.ID, ctx.Repo.Repository.ID, headBranch, baseBranch)
- if err != nil {
- if !models.IsErrPullRequestNotExist(err) {
- ctx.ServerError("GetUnmergedPullRequest", err)
- return
- }
- } else {
- ctx.Data["HasPullRequest"] = true
- ctx.Data["PullRequest"] = pr
- ctx.HTML(200, tplComparePull)
- return
- }
-
- nothingToCompare := PrepareCompareDiff(ctx, headUser, headRepo, headGitRepo, prInfo, baseBranch, headBranch)
- if ctx.Written() {
- return
- }
-
- if !nothingToCompare {
- // Setup information for new form.
- RetrieveRepoMetas(ctx, ctx.Repo.Repository)
- if ctx.Written() {
- return
- }
- }
-
- ctx.HTML(200, tplComparePull)
-}
-
// CompareAndPullRequestPost response for creating pull request
func CompareAndPullRequestPost(ctx *context.Context, form auth.CreateIssueForm) {
ctx.Data["Title"] = ctx.Tr("repo.pulls.compare_changes")
@@ -926,7 +666,7 @@ func CompareAndPullRequestPost(ctx *context.Context, form auth.CreateIssueForm)
return
}
- ctx.HTML(200, tplComparePull)
+ ctx.HTML(200, tplCompareDiff)
return
}
@@ -936,7 +676,7 @@ func CompareAndPullRequestPost(ctx *context.Context, form auth.CreateIssueForm)
return
}
- ctx.RenderWithErr(ctx.Tr("repo.issues.new.title_empty"), tplComparePull, form)
+ ctx.RenderWithErr(ctx.Tr("repo.issues.new.title_empty"), tplCompareDiff, form)
return
}
diff --git a/routers/routes/routes.go b/routers/routes/routes.go
index eb5f73768e..4c736f63ed 100644
--- a/routers/routes/routes.go
+++ b/routers/routes/routes.go
@@ -732,9 +732,9 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Group("/milestone", func() {
m.Get("/:id", repo.MilestoneIssuesAndPulls)
}, reqRepoIssuesOrPullsReader, context.RepoRef())
- m.Combo("/compare/*", context.RepoMustNotBeArchived(), reqRepoCodeReader, reqRepoPullsReader, repo.MustAllowPulls, repo.SetEditorconfigIfExists).
- Get(repo.SetDiffViewStyle, repo.CompareAndPullRequest).
- Post(bindIgnErr(auth.CreateIssueForm{}), repo.CompareAndPullRequestPost)
+ m.Combo("/compare/*", repo.MustBeNotEmpty, reqRepoCodeReader, repo.SetEditorconfigIfExists).
+ Get(repo.SetDiffViewStyle, repo.CompareDiff).
+ Post(context.RepoMustNotBeArchived(), reqRepoPullsReader, repo.MustAllowPulls, bindIgnErr(auth.CreateIssueForm{}), repo.CompareAndPullRequestPost)
m.Group("", func() {
m.Group("", func() {
@@ -906,9 +906,6 @@ func RegisterRoutes(m *macaron.Macaron) {
}, context.RepoRef(), reqRepoCodeReader)
m.Get("/commit/:sha([a-f0-9]{7,40})\\.:ext(patch|diff)",
repo.MustBeNotEmpty, reqRepoCodeReader, repo.RawDiff)
-
- m.Get("/compare/:before([a-z0-9]{40})\\.\\.\\.:after([a-z0-9]{40})", repo.SetEditorconfigIfExists,
- repo.SetDiffViewStyle, repo.MustBeNotEmpty, reqRepoCodeReader, repo.CompareDiff)
}, ignSignIn, context.RepoAssignment(), context.UnitTypes())
m.Group("/:username/:reponame", func() {
m.Get("/stars", repo.Stars)
diff --git a/templates/repo/commit_page.tmpl b/templates/repo/commit_page.tmpl
new file mode 100644
index 0000000000..0cfdf5156d
--- /dev/null
+++ b/templates/repo/commit_page.tmpl
@@ -0,0 +1,89 @@
+{{template "base/head" .}}
+
+ {{template "repo/header" .}}
+
+
+
+ {{.i18n.Tr "repo.diff.browse_source"}}
+
+
{{RenderCommitMessage .Commit.Message $.RepoLink $.Repository.ComposeMetas}}{{template "repo/commit_status" .CommitStatus}}
+ {{if IsMultilineCommitMessage .Commit.Message}}
+
{{RenderCommitBody .Commit.Message $.RepoLink $.Repository.ComposeMetas}}
+ {{end}}
+
{{.BranchName}}
+
+
+
+
+ {{if .Author}}
+
+ {{if .Author.FullName}}
+
{{.Author.FullName}} {{if .IsSigned}}<{{.Commit.Author.Email}}>{{end}}
+ {{else}}
+
{{.Commit.Author.Name}} {{if .IsSigned}}<{{.Commit.Author.Email}}>{{end}}
+ {{end}}
+ {{else}}
+
+
{{.Commit.Author.Name}}
+ {{end}}
+
{{TimeSince .Commit.Author.When $.Lang}}
+
+
+
+ {{if .Parents}}
+
+ {{.i18n.Tr "repo.diff.parent"}}
+
+
+ {{end}}
+
+
{{.i18n.Tr "repo.diff.commit"}}
+
{{ShortSha .CommitID}}
+
+
+
+
+ {{if .Commit.Signature}}
+ {{if .Verification.Verified }}
+
+
+
{{.i18n.Tr "repo.commits.signed_by"}}:
+
{{.Commit.Committer.Name}} <{{.Commit.Committer.Email}}>
+
{{.i18n.Tr "repo.commits.gpg_key_id"}}: {{.Verification.SigningKey.KeyID}}
+
+ {{else}}
+
+
+ {{.i18n.Tr .Verification.Reason}}
+
+ {{end}}
+ {{end}}
+ {{if .Note}}
+
+
+
{{RenderNote .Note $.RepoLink $.Repository.ComposeMetas}}
+
+ {{end}}
+ {{template "repo/diff/box" .}}
+
+
+{{template "base/footer" .}}
diff --git a/templates/repo/commits_table.tmpl b/templates/repo/commits_table.tmpl
index 66bfd0d831..10f4b60483 100644
--- a/templates/repo/commits_table.tmpl
+++ b/templates/repo/commits_table.tmpl
@@ -1,13 +1,13 @@