mirror of
https://github.com/gogs/gogs.git
synced 2025-05-25 17:00:55 +00:00
Move 'Commits' and 'Releases' tabs down to body. This patch also reduces page load time for pages that do not need to use commits count anywhere. Get commits count can hurt performance badly for huge repositories that has tens of thousands commits like Linux Kernel.
766 lines
20 KiB
Go
766 lines
20 KiB
Go
// Copyright 2014 The Gogs 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 (
|
|
"container/list"
|
|
"path"
|
|
"strings"
|
|
|
|
"github.com/Unknwon/com"
|
|
log "gopkg.in/clog.v1"
|
|
|
|
"github.com/gogits/git-module"
|
|
|
|
"github.com/gogits/gogs/models"
|
|
"github.com/gogits/gogs/modules/base"
|
|
"github.com/gogits/gogs/modules/context"
|
|
"github.com/gogits/gogs/modules/form"
|
|
"github.com/gogits/gogs/modules/setting"
|
|
)
|
|
|
|
const (
|
|
FORK base.TplName = "repo/pulls/fork"
|
|
COMPARE_PULL base.TplName = "repo/pulls/compare"
|
|
PULL_COMMITS base.TplName = "repo/pulls/commits"
|
|
PULL_FILES base.TplName = "repo/pulls/files"
|
|
|
|
PULL_REQUEST_TEMPLATE_KEY = "PullRequestTemplate"
|
|
)
|
|
|
|
var (
|
|
PullRequestTemplateCandidates = []string{
|
|
"PULL_REQUEST.md",
|
|
".gogs/PULL_REQUEST.md",
|
|
".github/PULL_REQUEST.md",
|
|
}
|
|
)
|
|
|
|
func parseBaseRepository(ctx *context.Context) *models.Repository {
|
|
baseRepo, err := models.GetRepositoryByID(ctx.ParamsInt64(":repoid"))
|
|
if err != nil {
|
|
ctx.NotFoundOrServerError("GetRepositoryByID", models.IsErrRepoNotExist, err)
|
|
return nil
|
|
}
|
|
|
|
if !baseRepo.CanBeForked() || !baseRepo.HasAccess(ctx.User.ID) {
|
|
ctx.NotFound()
|
|
return nil
|
|
}
|
|
|
|
ctx.Data["repo_name"] = baseRepo.Name
|
|
ctx.Data["description"] = baseRepo.Description
|
|
ctx.Data["IsPrivate"] = baseRepo.IsPrivate
|
|
|
|
if err = baseRepo.GetOwner(); err != nil {
|
|
ctx.Handle(500, "GetOwner", err)
|
|
return nil
|
|
}
|
|
ctx.Data["ForkFrom"] = baseRepo.Owner.Name + "/" + baseRepo.Name
|
|
|
|
if err := ctx.User.GetOrganizations(true); err != nil {
|
|
ctx.Handle(500, "GetOrganizations", err)
|
|
return nil
|
|
}
|
|
ctx.Data["Orgs"] = ctx.User.Orgs
|
|
|
|
return baseRepo
|
|
}
|
|
|
|
func Fork(ctx *context.Context) {
|
|
ctx.Data["Title"] = ctx.Tr("new_fork")
|
|
|
|
parseBaseRepository(ctx)
|
|
if ctx.Written() {
|
|
return
|
|
}
|
|
|
|
ctx.Data["ContextUser"] = ctx.User
|
|
ctx.HTML(200, FORK)
|
|
}
|
|
|
|
func ForkPost(ctx *context.Context, f form.CreateRepo) {
|
|
ctx.Data["Title"] = ctx.Tr("new_fork")
|
|
|
|
baseRepo := parseBaseRepository(ctx)
|
|
if ctx.Written() {
|
|
return
|
|
}
|
|
|
|
ctxUser := checkContextUser(ctx, f.UserID)
|
|
if ctx.Written() {
|
|
return
|
|
}
|
|
ctx.Data["ContextUser"] = ctxUser
|
|
|
|
if ctx.HasError() {
|
|
ctx.HTML(200, FORK)
|
|
return
|
|
}
|
|
|
|
repo, has := models.HasForkedRepo(ctxUser.ID, baseRepo.ID)
|
|
if has {
|
|
ctx.Redirect(repo.Link())
|
|
return
|
|
}
|
|
|
|
// Check ownership of organization.
|
|
if ctxUser.IsOrganization() && !ctxUser.IsOwnedBy(ctx.User.ID) {
|
|
ctx.Error(403)
|
|
return
|
|
}
|
|
|
|
// Cannot fork to same owner
|
|
if ctxUser.ID == baseRepo.OwnerID {
|
|
ctx.RenderWithErr(ctx.Tr("repo.settings.cannot_fork_to_same_owner"), FORK, &f)
|
|
return
|
|
}
|
|
|
|
repo, err := models.ForkRepository(ctx.User, ctxUser, baseRepo, f.RepoName, f.Description)
|
|
if err != nil {
|
|
ctx.Data["Err_RepoName"] = true
|
|
switch {
|
|
case models.IsErrRepoAlreadyExist(err):
|
|
ctx.RenderWithErr(ctx.Tr("repo.settings.new_owner_has_same_repo"), FORK, &f)
|
|
case models.IsErrNameReserved(err):
|
|
ctx.RenderWithErr(ctx.Tr("repo.form.name_reserved", err.(models.ErrNameReserved).Name), FORK, &f)
|
|
case models.IsErrNamePatternNotAllowed(err):
|
|
ctx.RenderWithErr(ctx.Tr("repo.form.name_pattern_not_allowed", err.(models.ErrNamePatternNotAllowed).Pattern), FORK, &f)
|
|
default:
|
|
ctx.Handle(500, "ForkPost", err)
|
|
}
|
|
return
|
|
}
|
|
|
|
log.Trace("Repository forked from '%s' -> '%s'", baseRepo.FullName(), repo.FullName())
|
|
ctx.Redirect(repo.Link())
|
|
}
|
|
|
|
func checkPullInfo(ctx *context.Context) *models.Issue {
|
|
issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
|
|
if err != nil {
|
|
if models.IsErrIssueNotExist(err) {
|
|
ctx.Handle(404, "GetIssueByIndex", err)
|
|
} else {
|
|
ctx.Handle(500, "GetIssueByIndex", err)
|
|
}
|
|
return nil
|
|
}
|
|
ctx.Data["Title"] = issue.Title
|
|
ctx.Data["Issue"] = issue
|
|
|
|
if !issue.IsPull {
|
|
ctx.Handle(404, "ViewPullCommits", nil)
|
|
return nil
|
|
}
|
|
|
|
if ctx.IsSigned {
|
|
// Update issue-user.
|
|
if err = issue.ReadBy(ctx.User.ID); err != nil {
|
|
ctx.Handle(500, "ReadBy", err)
|
|
return nil
|
|
}
|
|
}
|
|
|
|
return issue
|
|
}
|
|
|
|
func PrepareMergedViewPullInfo(ctx *context.Context, issue *models.Issue) {
|
|
pull := issue.PullRequest
|
|
ctx.Data["HasMerged"] = true
|
|
ctx.Data["HeadTarget"] = issue.PullRequest.HeadUserName + "/" + pull.HeadBranch
|
|
ctx.Data["BaseTarget"] = ctx.Repo.Owner.Name + "/" + pull.BaseBranch
|
|
|
|
var err error
|
|
ctx.Data["NumCommits"], err = ctx.Repo.GitRepo.CommitsCountBetween(pull.MergeBase, pull.MergedCommitID)
|
|
if err != nil {
|
|
ctx.Handle(500, "Repo.GitRepo.CommitsCountBetween", err)
|
|
return
|
|
}
|
|
ctx.Data["NumFiles"], err = ctx.Repo.GitRepo.FilesCountBetween(pull.MergeBase, pull.MergedCommitID)
|
|
if err != nil {
|
|
ctx.Handle(500, "Repo.GitRepo.FilesCountBetween", err)
|
|
return
|
|
}
|
|
}
|
|
|
|
func PrepareViewPullInfo(ctx *context.Context, issue *models.Issue) *git.PullRequestInfo {
|
|
repo := ctx.Repo.Repository
|
|
pull := issue.PullRequest
|
|
|
|
ctx.Data["HeadTarget"] = pull.HeadUserName + "/" + pull.HeadBranch
|
|
ctx.Data["BaseTarget"] = ctx.Repo.Owner.Name + "/" + pull.BaseBranch
|
|
|
|
var (
|
|
headGitRepo *git.Repository
|
|
err error
|
|
)
|
|
|
|
if pull.HeadRepo != nil {
|
|
headGitRepo, err = git.OpenRepository(pull.HeadRepo.RepoPath())
|
|
if err != nil {
|
|
ctx.Handle(500, "OpenRepository", err)
|
|
return nil
|
|
}
|
|
}
|
|
|
|
if pull.HeadRepo == nil || !headGitRepo.IsBranchExist(pull.HeadBranch) {
|
|
ctx.Data["IsPullReuqestBroken"] = true
|
|
ctx.Data["HeadTarget"] = "deleted"
|
|
ctx.Data["NumCommits"] = 0
|
|
ctx.Data["NumFiles"] = 0
|
|
return nil
|
|
}
|
|
|
|
prInfo, err := headGitRepo.GetPullRequestInfo(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") {
|
|
ctx.Data["IsPullReuqestBroken"] = true
|
|
ctx.Data["BaseTarget"] = "deleted"
|
|
ctx.Data["NumCommits"] = 0
|
|
ctx.Data["NumFiles"] = 0
|
|
return nil
|
|
}
|
|
|
|
ctx.Handle(500, "GetPullRequestInfo", err)
|
|
return nil
|
|
}
|
|
ctx.Data["NumCommits"] = prInfo.Commits.Len()
|
|
ctx.Data["NumFiles"] = prInfo.NumFiles
|
|
return prInfo
|
|
}
|
|
|
|
func ViewPullCommits(ctx *context.Context) {
|
|
ctx.Data["PageIsPullList"] = true
|
|
ctx.Data["PageIsPullCommits"] = true
|
|
|
|
issue := checkPullInfo(ctx)
|
|
if ctx.Written() {
|
|
return
|
|
}
|
|
pull := issue.PullRequest
|
|
ctx.Data["Username"] = pull.HeadUserName
|
|
ctx.Data["Reponame"] = pull.HeadRepo.Name
|
|
|
|
var commits *list.List
|
|
if pull.HasMerged {
|
|
PrepareMergedViewPullInfo(ctx, issue)
|
|
if ctx.Written() {
|
|
return
|
|
}
|
|
startCommit, err := ctx.Repo.GitRepo.GetCommit(pull.MergeBase)
|
|
if err != nil {
|
|
ctx.Handle(500, "Repo.GitRepo.GetCommit", err)
|
|
return
|
|
}
|
|
endCommit, err := ctx.Repo.GitRepo.GetCommit(pull.MergedCommitID)
|
|
if err != nil {
|
|
ctx.Handle(500, "Repo.GitRepo.GetCommit", err)
|
|
return
|
|
}
|
|
commits, err = ctx.Repo.GitRepo.CommitsBetween(endCommit, startCommit)
|
|
if err != nil {
|
|
ctx.Handle(500, "Repo.GitRepo.CommitsBetween", err)
|
|
return
|
|
}
|
|
|
|
} else {
|
|
prInfo := PrepareViewPullInfo(ctx, issue)
|
|
if ctx.Written() {
|
|
return
|
|
} else if prInfo == nil {
|
|
ctx.Handle(404, "ViewPullCommits", nil)
|
|
return
|
|
}
|
|
commits = prInfo.Commits
|
|
}
|
|
|
|
commits = models.ValidateCommitsWithEmails(commits)
|
|
ctx.Data["Commits"] = commits
|
|
ctx.Data["CommitsCount"] = commits.Len()
|
|
|
|
ctx.HTML(200, PULL_COMMITS)
|
|
}
|
|
|
|
func ViewPullFiles(ctx *context.Context) {
|
|
ctx.Data["PageIsPullList"] = true
|
|
ctx.Data["PageIsPullFiles"] = true
|
|
|
|
issue := checkPullInfo(ctx)
|
|
if ctx.Written() {
|
|
return
|
|
}
|
|
pull := issue.PullRequest
|
|
|
|
var (
|
|
diffRepoPath string
|
|
startCommitID string
|
|
endCommitID string
|
|
gitRepo *git.Repository
|
|
)
|
|
|
|
if pull.HasMerged {
|
|
PrepareMergedViewPullInfo(ctx, issue)
|
|
if ctx.Written() {
|
|
return
|
|
}
|
|
|
|
diffRepoPath = ctx.Repo.GitRepo.Path
|
|
startCommitID = pull.MergeBase
|
|
endCommitID = pull.MergedCommitID
|
|
gitRepo = ctx.Repo.GitRepo
|
|
} else {
|
|
prInfo := PrepareViewPullInfo(ctx, issue)
|
|
if ctx.Written() {
|
|
return
|
|
} else if prInfo == nil {
|
|
ctx.Handle(404, "ViewPullFiles", nil)
|
|
return
|
|
}
|
|
|
|
headRepoPath := models.RepoPath(pull.HeadUserName, pull.HeadRepo.Name)
|
|
|
|
headGitRepo, err := git.OpenRepository(headRepoPath)
|
|
if err != nil {
|
|
ctx.Handle(500, "OpenRepository", err)
|
|
return
|
|
}
|
|
|
|
headCommitID, err := headGitRepo.GetBranchCommitID(pull.HeadBranch)
|
|
if err != nil {
|
|
ctx.Handle(500, "GetBranchCommitID", err)
|
|
return
|
|
}
|
|
|
|
diffRepoPath = headRepoPath
|
|
startCommitID = prInfo.MergeBase
|
|
endCommitID = headCommitID
|
|
gitRepo = headGitRepo
|
|
}
|
|
|
|
diff, err := models.GetDiffRange(diffRepoPath,
|
|
startCommitID, endCommitID, setting.Git.MaxGitDiffLines,
|
|
setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles)
|
|
if err != nil {
|
|
ctx.Handle(500, "GetDiffRange", err)
|
|
return
|
|
}
|
|
ctx.Data["Diff"] = diff
|
|
ctx.Data["DiffNotAvailable"] = diff.NumFiles() == 0
|
|
|
|
commit, err := gitRepo.GetCommit(endCommitID)
|
|
if err != nil {
|
|
ctx.Handle(500, "GetCommit", err)
|
|
return
|
|
}
|
|
|
|
setEditorconfigIfExists(ctx)
|
|
if ctx.Written() {
|
|
return
|
|
}
|
|
|
|
headTarget := path.Join(pull.HeadUserName, pull.HeadRepo.Name)
|
|
ctx.Data["IsSplitStyle"] = ctx.Query("style") == "split"
|
|
ctx.Data["Username"] = pull.HeadUserName
|
|
ctx.Data["Reponame"] = pull.HeadRepo.Name
|
|
ctx.Data["IsImageFile"] = commit.IsImageFile
|
|
ctx.Data["SourcePath"] = setting.AppSubUrl + "/" + path.Join(headTarget, "src", endCommitID)
|
|
ctx.Data["BeforeSourcePath"] = setting.AppSubUrl + "/" + path.Join(headTarget, "src", startCommitID)
|
|
ctx.Data["RawPath"] = setting.AppSubUrl + "/" + path.Join(headTarget, "raw", endCommitID)
|
|
ctx.Data["RequireHighlightJS"] = true
|
|
|
|
ctx.HTML(200, PULL_FILES)
|
|
}
|
|
|
|
func MergePullRequest(ctx *context.Context) {
|
|
issue := checkPullInfo(ctx)
|
|
if ctx.Written() {
|
|
return
|
|
}
|
|
if issue.IsClosed {
|
|
ctx.Handle(404, "MergePullRequest", nil)
|
|
return
|
|
}
|
|
|
|
pr, err := models.GetPullRequestByIssueID(issue.ID)
|
|
if err != nil {
|
|
if models.IsErrPullRequestNotExist(err) {
|
|
ctx.Handle(404, "GetPullRequestByIssueID", nil)
|
|
} else {
|
|
ctx.Handle(500, "GetPullRequestByIssueID", err)
|
|
}
|
|
return
|
|
}
|
|
|
|
if !pr.CanAutoMerge() || pr.HasMerged {
|
|
ctx.Handle(404, "MergePullRequest", nil)
|
|
return
|
|
}
|
|
|
|
pr.Issue = issue
|
|
pr.Issue.Repo = ctx.Repo.Repository
|
|
if err = pr.Merge(ctx.User, ctx.Repo.GitRepo); err != nil {
|
|
ctx.Handle(500, "Merge", err)
|
|
return
|
|
}
|
|
|
|
log.Trace("Pull request merged: %d", pr.ID)
|
|
ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + com.ToStr(pr.Index))
|
|
}
|
|
|
|
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 branch>...[<head repo>:]<head branch>
|
|
// base<-head: master...head:feature
|
|
// same repo: master...feature
|
|
infos := strings.Split(ctx.Params("*"), "...")
|
|
if len(infos) != 2 {
|
|
log.Trace("ParseCompareInfo[%d]: not enough compared branches information %s", baseRepo.ID, infos)
|
|
ctx.Handle(404, "CompareAndPullRequest", nil)
|
|
return nil, nil, nil, nil, "", ""
|
|
}
|
|
|
|
baseBranch := infos[0]
|
|
ctx.Data["BaseBranch"] = baseBranch
|
|
|
|
var (
|
|
headUser *models.User
|
|
headBranch string
|
|
isSameRepo bool
|
|
err error
|
|
)
|
|
|
|
// 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.Handle(404, "GetUserByName", nil)
|
|
} else {
|
|
ctx.Handle(500, "GetUserByName", err)
|
|
}
|
|
return nil, nil, nil, nil, "", ""
|
|
}
|
|
headBranch = headInfos[1]
|
|
isSameRepo = headUser.ID == baseRepo.OwnerID
|
|
|
|
} else {
|
|
ctx.Handle(404, "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.Handle(404, "IsBranchExist", nil)
|
|
return nil, nil, nil, nil, "", ""
|
|
}
|
|
|
|
var (
|
|
headRepo *models.Repository
|
|
headGitRepo *git.Repository
|
|
)
|
|
|
|
// In case user included redundant head user name for comparison in same repository,
|
|
// no need to check the fork relation.
|
|
if !isSameRepo {
|
|
var has bool
|
|
headRepo, has = models.HasForkedRepo(headUser.ID, baseRepo.ID)
|
|
if !has {
|
|
log.Trace("ParseCompareInfo[%d]: does not have fork or in same repository", baseRepo.ID)
|
|
ctx.Handle(404, "ParseCompareInfo", nil)
|
|
return nil, nil, nil, nil, "", ""
|
|
}
|
|
|
|
headGitRepo, err = git.OpenRepository(models.RepoPath(headUser.Name, headRepo.Name))
|
|
if err != nil {
|
|
ctx.Handle(500, "OpenRepository", err)
|
|
return nil, nil, nil, nil, "", ""
|
|
}
|
|
} else {
|
|
headRepo = ctx.Repo.Repository
|
|
headGitRepo = ctx.Repo.GitRepo
|
|
}
|
|
|
|
if !ctx.User.IsWriterOfRepo(headRepo) && !ctx.User.IsAdmin {
|
|
log.Trace("ParseCompareInfo[%d]: does not have write access or site admin", baseRepo.ID)
|
|
ctx.Handle(404, "ParseCompareInfo", nil)
|
|
return nil, nil, nil, nil, "", ""
|
|
}
|
|
|
|
// Check if head branch is valid.
|
|
if !headGitRepo.IsBranchExist(headBranch) {
|
|
ctx.Handle(404, "IsBranchExist", nil)
|
|
return nil, nil, nil, nil, "", ""
|
|
}
|
|
|
|
headBranches, err := headGitRepo.GetBranches()
|
|
if err != nil {
|
|
ctx.Handle(500, "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.Handle(500, "GetPullRequestInfo", err)
|
|
return nil, nil, nil, nil, "", ""
|
|
}
|
|
ctx.Data["BeforeCommitID"] = prInfo.MergeBase
|
|
|
|
return headUser, headRepo, headGitRepo, prInfo, baseBranch, headBranch
|
|
}
|
|
|
|
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
|
|
)
|
|
|
|
// Get diff information.
|
|
ctx.Data["CommitRepoLink"] = headRepo.Link()
|
|
|
|
headCommitID, err := headGitRepo.GetBranchCommitID(headBranch)
|
|
if err != nil {
|
|
ctx.Handle(500, "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.Handle(500, "GetDiffRange", err)
|
|
return false
|
|
}
|
|
ctx.Data["Diff"] = diff
|
|
ctx.Data["DiffNotAvailable"] = diff.NumFiles() == 0
|
|
|
|
headCommit, err := headGitRepo.GetCommit(headCommitID)
|
|
if err != nil {
|
|
ctx.Handle(500, "GetCommit", err)
|
|
return false
|
|
}
|
|
|
|
prInfo.Commits = models.ValidateCommitsWithEmails(prInfo.Commits)
|
|
ctx.Data["Commits"] = prInfo.Commits
|
|
ctx.Data["CommitCount"] = prInfo.Commits.Len()
|
|
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", headCommitID)
|
|
ctx.Data["BeforeSourcePath"] = setting.AppSubUrl + "/" + path.Join(headTarget, "src", prInfo.MergeBase)
|
|
ctx.Data["RawPath"] = setting.AppSubUrl + "/" + path.Join(headTarget, "raw", headCommitID)
|
|
return false
|
|
}
|
|
|
|
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
|
|
setTemplateIfExists(ctx, PULL_REQUEST_TEMPLATE_KEY, 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.Handle(500, "GetUnmergedPullRequest", err)
|
|
return
|
|
}
|
|
} else {
|
|
ctx.Data["HasPullRequest"] = true
|
|
ctx.Data["PullRequest"] = pr
|
|
ctx.HTML(200, COMPARE_PULL)
|
|
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
|
|
}
|
|
}
|
|
|
|
setEditorconfigIfExists(ctx)
|
|
if ctx.Written() {
|
|
return
|
|
}
|
|
|
|
ctx.Data["IsSplitStyle"] = ctx.Query("style") == "split"
|
|
ctx.HTML(200, COMPARE_PULL)
|
|
}
|
|
|
|
func CompareAndPullRequestPost(ctx *context.Context, f form.CreateIssue) {
|
|
ctx.Data["Title"] = ctx.Tr("repo.pulls.compare_changes")
|
|
ctx.Data["PageIsComparePull"] = true
|
|
ctx.Data["IsDiffCompare"] = true
|
|
ctx.Data["RequireHighlightJS"] = true
|
|
renderAttachmentSettings(ctx)
|
|
|
|
var (
|
|
repo = ctx.Repo.Repository
|
|
attachments []string
|
|
)
|
|
|
|
headUser, headRepo, headGitRepo, prInfo, baseBranch, headBranch := ParseCompareInfo(ctx)
|
|
if ctx.Written() {
|
|
return
|
|
}
|
|
|
|
labelIDs, milestoneID, assigneeID := ValidateRepoMetas(ctx, f)
|
|
if ctx.Written() {
|
|
return
|
|
}
|
|
|
|
if setting.AttachmentEnabled {
|
|
attachments = f.Files
|
|
}
|
|
|
|
if ctx.HasError() {
|
|
form.Assign(f, ctx.Data)
|
|
|
|
// This stage is already stop creating new pull request, so it does not matter if it has
|
|
// something to compare or not.
|
|
PrepareCompareDiff(ctx, headUser, headRepo, headGitRepo, prInfo, baseBranch, headBranch)
|
|
if ctx.Written() {
|
|
return
|
|
}
|
|
|
|
ctx.HTML(200, COMPARE_PULL)
|
|
return
|
|
}
|
|
|
|
patch, err := headGitRepo.GetPatch(prInfo.MergeBase, headBranch)
|
|
if err != nil {
|
|
ctx.Handle(500, "GetPatch", err)
|
|
return
|
|
}
|
|
|
|
pullIssue := &models.Issue{
|
|
RepoID: repo.ID,
|
|
Index: repo.NextIssueIndex(),
|
|
Title: f.Title,
|
|
PosterID: ctx.User.ID,
|
|
Poster: ctx.User,
|
|
MilestoneID: milestoneID,
|
|
AssigneeID: assigneeID,
|
|
IsPull: true,
|
|
Content: f.Content,
|
|
}
|
|
pullRequest := &models.PullRequest{
|
|
HeadRepoID: headRepo.ID,
|
|
BaseRepoID: repo.ID,
|
|
HeadUserName: headUser.Name,
|
|
HeadBranch: headBranch,
|
|
BaseBranch: baseBranch,
|
|
HeadRepo: headRepo,
|
|
BaseRepo: repo,
|
|
MergeBase: prInfo.MergeBase,
|
|
Type: models.PULL_REQUEST_GOGS,
|
|
}
|
|
// FIXME: check error in the case two people send pull request at almost same time, give nice error prompt
|
|
// instead of 500.
|
|
if err := models.NewPullRequest(repo, pullIssue, labelIDs, attachments, pullRequest, patch); err != nil {
|
|
ctx.Handle(500, "NewPullRequest", err)
|
|
return
|
|
} else if err := pullRequest.PushToBaseRepo(); err != nil {
|
|
ctx.Handle(500, "PushToBaseRepo", err)
|
|
return
|
|
}
|
|
|
|
log.Trace("Pull request created: %d/%d", repo.ID, pullIssue.ID)
|
|
ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + com.ToStr(pullIssue.Index))
|
|
}
|
|
|
|
func parseOwnerAndRepo(ctx *context.Context) (*models.User, *models.Repository) {
|
|
owner, err := models.GetUserByName(ctx.Params(":username"))
|
|
if err != nil {
|
|
ctx.NotFoundOrServerError("GetUserByName", models.IsErrUserNotExist, err)
|
|
return nil, nil
|
|
}
|
|
|
|
repo, err := models.GetRepositoryByName(owner.ID, ctx.Params(":reponame"))
|
|
if err != nil {
|
|
ctx.NotFoundOrServerError("GetRepositoryByName", models.IsErrRepoNotExist, err)
|
|
return nil, nil
|
|
}
|
|
|
|
return owner, repo
|
|
}
|
|
|
|
func TriggerTask(ctx *context.Context) {
|
|
pusherID := ctx.QueryInt64("pusher")
|
|
branch := ctx.Query("branch")
|
|
secret := ctx.Query("secret")
|
|
if len(branch) == 0 || len(secret) == 0 || pusherID <= 0 {
|
|
ctx.Error(404)
|
|
log.Trace("TriggerTask: branch or secret is empty, or pusher ID is not valid")
|
|
return
|
|
}
|
|
owner, repo := parseOwnerAndRepo(ctx)
|
|
if ctx.Written() {
|
|
return
|
|
}
|
|
if secret != base.EncodeMD5(owner.Salt) {
|
|
ctx.Error(404)
|
|
log.Trace("TriggerTask [%s/%s]: invalid secret", owner.Name, repo.Name)
|
|
return
|
|
}
|
|
|
|
pusher, err := models.GetUserByID(pusherID)
|
|
if err != nil {
|
|
if models.IsErrUserNotExist(err) {
|
|
ctx.Error(404)
|
|
} else {
|
|
ctx.Handle(500, "GetUserByID", err)
|
|
}
|
|
return
|
|
}
|
|
|
|
log.Trace("TriggerTask '%s/%s' by '%s'", repo.Name, branch, pusher.Name)
|
|
|
|
go models.HookQueue.Add(repo.ID)
|
|
go models.AddTestPullRequestTask(pusher, repo.ID, branch, true)
|
|
ctx.Status(202)
|
|
}
|