mirror of
https://github.com/go-gitea/gitea.git
synced 2025-01-02 01:17:43 +03:00
Compare commits
27 Commits
7b63ffb7ce
...
96576a97f8
Author | SHA1 | Date | |
---|---|---|---|
|
96576a97f8 | ||
|
232867cff6 | ||
|
cd1b5488a3 | ||
|
1dbf0d7f08 | ||
|
d08942e300 | ||
|
4579e49532 | ||
|
2461ad00ff | ||
|
831fb56414 | ||
|
6b3bc6eb8d | ||
|
b7f2be5c4d | ||
|
92e68ae407 | ||
|
27b67534e3 | ||
|
91147db3bb | ||
|
95bccdbc3b | ||
|
050fad97d6 | ||
|
743cebe66f | ||
|
a2804a5efc | ||
|
a3eb356f7a | ||
|
52639ffaa9 | ||
|
72f6e28f7f | ||
|
743fa68010 | ||
|
07abd8d1a9 | ||
|
4ee5334c10 | ||
|
f19b4b7967 | ||
|
283c030497 | ||
|
48b5bab880 | ||
|
8eb19a5ae1 |
10
Makefile
10
Makefile
@ -806,22 +806,22 @@ $(DIST_DIRS):
|
||||
|
||||
.PHONY: release-windows
|
||||
release-windows: | $(DIST_DIRS)
|
||||
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION) .
|
||||
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'osusergo $(TAGS)' -ldflags '-s -w -linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION) .
|
||||
ifeq (,$(findstring gogit,$(TAGS)))
|
||||
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'osusergo gogit $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION)-gogit .
|
||||
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'osusergo gogit $(TAGS)' -ldflags '-s -w -linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION)-gogit .
|
||||
endif
|
||||
|
||||
.PHONY: release-linux
|
||||
release-linux: | $(DIST_DIRS)
|
||||
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets '$(LINUX_ARCHS)' -out gitea-$(VERSION) .
|
||||
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-s -w -linkmode external -extldflags "-static" $(LDFLAGS)' -targets '$(LINUX_ARCHS)' -out gitea-$(VERSION) .
|
||||
|
||||
.PHONY: release-darwin
|
||||
release-darwin: | $(DIST_DIRS)
|
||||
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '$(LDFLAGS)' -targets 'darwin-10.12/amd64,darwin-10.12/arm64' -out gitea-$(VERSION) .
|
||||
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-s -w $(LDFLAGS)' -targets 'darwin-10.12/amd64,darwin-10.12/arm64' -out gitea-$(VERSION) .
|
||||
|
||||
.PHONY: release-freebsd
|
||||
release-freebsd: | $(DIST_DIRS)
|
||||
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '$(LDFLAGS)' -targets 'freebsd/amd64' -out gitea-$(VERSION) .
|
||||
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-s -w $(LDFLAGS)' -targets 'freebsd/amd64' -out gitea-$(VERSION) .
|
||||
|
||||
.PHONY: release-copy
|
||||
release-copy: | $(DIST_DIRS)
|
||||
|
@ -39,8 +39,6 @@ type SearchUserOptions struct {
|
||||
IsTwoFactorEnabled optional.Option[bool]
|
||||
IsProhibitLogin optional.Option[bool]
|
||||
IncludeReserved bool
|
||||
|
||||
ExtraParamStrings map[string]string
|
||||
}
|
||||
|
||||
func (opts *SearchUserOptions) toSearchQueryBase(ctx context.Context) *xorm.Session {
|
||||
|
@ -4,12 +4,18 @@
|
||||
package repo
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
access_model "code.gitea.io/gitea/models/perm/access"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unit"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/gitrepo"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/routers/common"
|
||||
"code.gitea.io/gitea/services/context"
|
||||
"code.gitea.io/gitea/services/convert"
|
||||
)
|
||||
@ -52,30 +58,65 @@ func CompareDiff(ctx *context.APIContext) {
|
||||
}
|
||||
}
|
||||
|
||||
infoPath := ctx.PathParam("*")
|
||||
infos := []string{ctx.Repo.Repository.DefaultBranch, ctx.Repo.Repository.DefaultBranch}
|
||||
if infoPath != "" {
|
||||
infos = strings.SplitN(infoPath, "...", 2)
|
||||
if len(infos) != 2 {
|
||||
if infos = strings.SplitN(infoPath, "..", 2); len(infos) != 2 {
|
||||
infos = []string{ctx.Repo.Repository.DefaultBranch, infoPath}
|
||||
pathParam := ctx.PathParam("*")
|
||||
baseRepo := ctx.Repo.Repository
|
||||
ci, err := common.ParseComparePathParams(ctx, pathParam, baseRepo, ctx.Repo.GitRepo)
|
||||
if err != nil {
|
||||
switch {
|
||||
case user_model.IsErrUserNotExist(err):
|
||||
ctx.NotFound("GetUserByName")
|
||||
case repo_model.IsErrRepoNotExist(err):
|
||||
ctx.NotFound("GetRepositoryByOwnerAndName")
|
||||
case errors.Is(err, util.ErrInvalidArgument):
|
||||
ctx.NotFound("ParseComparePathParams")
|
||||
default:
|
||||
ctx.ServerError("GetRepositoryByOwnerAndName", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
defer ci.Close()
|
||||
|
||||
// remove the check when we support compare with carets
|
||||
if ci.CaretTimes > 0 {
|
||||
ctx.NotFound("Unsupported compare")
|
||||
return
|
||||
}
|
||||
|
||||
if !ci.IsSameRepo() {
|
||||
// user should have permission to read headrepo's codes
|
||||
permHead, err := access_model.GetUserRepoPermission(ctx, ci.HeadRepo, ctx.Doer)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "GetUserRepoPermission", err)
|
||||
return
|
||||
}
|
||||
if !permHead.CanRead(unit.TypeCode) {
|
||||
if log.IsTrace() {
|
||||
log.Trace("Permission Denied: User: %-v cannot read code in Repo: %-v\nUser in headRepo has Permissions: %-+v",
|
||||
ctx.Doer,
|
||||
ci.HeadRepo,
|
||||
permHead)
|
||||
}
|
||||
ctx.NotFound("Can't read headRepo UnitTypeCode")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
compareResult, closer := parseCompareInfo(ctx, api.CreatePullRequestOption{Base: infos[0], Head: infos[1]})
|
||||
if ctx.Written() {
|
||||
ctx.Repo.PullRequest.SameRepo = ci.IsSameRepo()
|
||||
log.Trace("Repo path: %q, base branch: %q, head branch: %q", ctx.Repo.GitRepo.Path, ci.BaseOriRef, ci.HeadOriRef)
|
||||
|
||||
ci.CompareInfo, err = ci.HeadGitRepo.GetCompareInfo(repo_model.RepoPath(baseRepo.Owner.Name, baseRepo.Name), ci.BaseOriRef, ci.HeadOriRef, false, false)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "GetCompareInfo", err)
|
||||
return
|
||||
}
|
||||
defer closer()
|
||||
|
||||
verification := ctx.FormString("verification") == "" || ctx.FormBool("verification")
|
||||
files := ctx.FormString("files") == "" || ctx.FormBool("files")
|
||||
|
||||
apiCommits := make([]*api.Commit, 0, len(compareResult.compareInfo.Commits))
|
||||
apiCommits := make([]*api.Commit, 0, len(ci.CompareInfo.Commits))
|
||||
userCache := make(map[string]*user_model.User)
|
||||
for i := 0; i < len(compareResult.compareInfo.Commits); i++ {
|
||||
apiCommit, err := convert.ToCommit(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, compareResult.compareInfo.Commits[i], userCache,
|
||||
for i := 0; i < len(ci.CompareInfo.Commits); i++ {
|
||||
apiCommit, err := convert.ToCommit(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, ci.CompareInfo.Commits[i], userCache,
|
||||
convert.ToCommitOptions{
|
||||
Stat: true,
|
||||
Verification: verification,
|
||||
@ -89,7 +130,7 @@ func CompareDiff(ctx *context.APIContext) {
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusOK, &api.Compare{
|
||||
TotalCommits: len(compareResult.compareInfo.Commits),
|
||||
TotalCommits: len(ci.CompareInfo.Commits),
|
||||
Commits: apiCommits,
|
||||
})
|
||||
}
|
||||
|
@ -27,8 +27,10 @@ import (
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/modules/web"
|
||||
"code.gitea.io/gitea/routers/api/v1/utils"
|
||||
"code.gitea.io/gitea/routers/common"
|
||||
asymkey_service "code.gitea.io/gitea/services/asymkey"
|
||||
"code.gitea.io/gitea/services/automerge"
|
||||
"code.gitea.io/gitea/services/context"
|
||||
@ -393,28 +395,70 @@ func CreatePullRequest(ctx *context.APIContext) {
|
||||
}
|
||||
|
||||
var (
|
||||
repo = ctx.Repo.Repository
|
||||
baseRepo = ctx.Repo.Repository
|
||||
labelIDs []int64
|
||||
milestoneID int64
|
||||
)
|
||||
|
||||
// Get repo/branch information
|
||||
compareResult, closer := parseCompareInfo(ctx, form)
|
||||
if ctx.Written() {
|
||||
baseGitRepo, closer, err := gitrepo.RepositoryFromContextOrOpen(ctx, baseRepo)
|
||||
if err != nil {
|
||||
ctx.ServerError("OpenRepository", err)
|
||||
return
|
||||
}
|
||||
defer closer()
|
||||
defer closer.Close()
|
||||
|
||||
if !compareResult.baseRef.IsBranch() || !compareResult.headRef.IsBranch() {
|
||||
ctx.Error(http.StatusUnprocessableEntity, "BaseHeadInvalidRefType", "Invalid PullRequest: base and head must be branches")
|
||||
// Get repo/branch information
|
||||
ci, err := common.ParseComparePathParams(ctx, form.Base+"..."+form.Head, baseRepo, baseGitRepo)
|
||||
if err != nil {
|
||||
switch {
|
||||
case user_model.IsErrUserNotExist(err):
|
||||
ctx.NotFound("GetUserByName")
|
||||
case repo_model.IsErrRepoNotExist(err):
|
||||
ctx.NotFound("GetRepositoryByOwnerAndName")
|
||||
case errors.Is(err, util.ErrInvalidArgument):
|
||||
ctx.NotFound("ParseComparePathParams")
|
||||
default:
|
||||
ctx.ServerError("GetRepositoryByOwnerAndName", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
defer ci.Close()
|
||||
|
||||
if !ci.IsPull() {
|
||||
ctx.Error(http.StatusUnprocessableEntity, "Bad base or head refs", "Only support branch to branch comparison")
|
||||
return
|
||||
}
|
||||
|
||||
// we just need to check the head repository's permission here because the base
|
||||
// repository's permission is already checked in api.go with
|
||||
// mustAllowPulls, reqRepoReader(unit.TypeCode)
|
||||
if !ci.IsSameRepo() {
|
||||
// user should have permission to read headrepo's codes
|
||||
permHead, err := access_model.GetUserRepoPermission(ctx, ci.HeadRepo, ctx.Doer)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "GetUserRepoPermission", err)
|
||||
return
|
||||
}
|
||||
if !permHead.CanRead(unit.TypeCode) {
|
||||
if log.IsTrace() {
|
||||
log.Trace("Permission Denied: User: %-v cannot read code in Repo: %-v\nUser in headRepo has Permissions: %-+v",
|
||||
ctx.Doer,
|
||||
ci.HeadRepo,
|
||||
permHead)
|
||||
}
|
||||
ctx.NotFound("Can't read headRepo UnitTypeCode")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
ci.CompareInfo, err = ci.HeadGitRepo.GetCompareInfo(repo_model.RepoPath(baseRepo.Owner.Name, baseRepo.Name), ci.BaseOriRef, ci.HeadOriRef, false, false)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "GetCompareInfo", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Check if another PR exists with the same targets
|
||||
existingPr, err := issues_model.GetUnmergedPullRequest(ctx, compareResult.headRepo.ID, ctx.Repo.Repository.ID,
|
||||
compareResult.headRef.ShortName(), compareResult.baseRef.ShortName(),
|
||||
issues_model.PullRequestFlowGithub,
|
||||
)
|
||||
existingPr, err := issues_model.GetUnmergedPullRequest(ctx, ci.HeadRepo.ID, baseRepo.ID, ci.HeadOriRef, ci.BaseOriRef, issues_model.PullRequestFlowGithub)
|
||||
if err != nil {
|
||||
if !issues_model.IsErrPullRequestNotExist(err) {
|
||||
ctx.Error(http.StatusInternalServerError, "GetUnmergedPullRequest", err)
|
||||
@ -434,7 +478,7 @@ func CreatePullRequest(ctx *context.APIContext) {
|
||||
}
|
||||
|
||||
if len(form.Labels) > 0 {
|
||||
labels, err := issues_model.GetLabelsInRepoByIDs(ctx, ctx.Repo.Repository.ID, form.Labels)
|
||||
labels, err := issues_model.GetLabelsInRepoByIDs(ctx, baseRepo.ID, form.Labels)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "GetLabelsInRepoByIDs", err)
|
||||
return
|
||||
@ -461,7 +505,7 @@ func CreatePullRequest(ctx *context.APIContext) {
|
||||
}
|
||||
|
||||
if form.Milestone > 0 {
|
||||
milestone, err := issues_model.GetMilestoneByRepoID(ctx, ctx.Repo.Repository.ID, form.Milestone)
|
||||
milestone, err := issues_model.GetMilestoneByRepoID(ctx, baseRepo.ID, form.Milestone)
|
||||
if err != nil {
|
||||
if issues_model.IsErrMilestoneNotExist(err) {
|
||||
ctx.NotFound()
|
||||
@ -480,7 +524,7 @@ func CreatePullRequest(ctx *context.APIContext) {
|
||||
}
|
||||
|
||||
prIssue := &issues_model.Issue{
|
||||
RepoID: repo.ID,
|
||||
RepoID: baseRepo.ID,
|
||||
Title: form.Title,
|
||||
PosterID: ctx.Doer.ID,
|
||||
Poster: ctx.Doer,
|
||||
@ -490,13 +534,13 @@ func CreatePullRequest(ctx *context.APIContext) {
|
||||
DeadlineUnix: deadlineUnix,
|
||||
}
|
||||
pr := &issues_model.PullRequest{
|
||||
HeadRepoID: compareResult.headRepo.ID,
|
||||
BaseRepoID: repo.ID,
|
||||
HeadBranch: compareResult.headRef.ShortName(),
|
||||
BaseBranch: compareResult.baseRef.ShortName(),
|
||||
HeadRepo: compareResult.headRepo,
|
||||
BaseRepo: repo,
|
||||
MergeBase: compareResult.compareInfo.MergeBase,
|
||||
HeadRepoID: ci.HeadRepo.ID,
|
||||
BaseRepoID: baseRepo.ID,
|
||||
HeadBranch: ci.HeadOriRef,
|
||||
BaseBranch: ci.BaseOriRef,
|
||||
HeadRepo: ci.HeadRepo,
|
||||
BaseRepo: baseRepo,
|
||||
MergeBase: ci.CompareInfo.MergeBase,
|
||||
Type: issues_model.PullRequestGitea,
|
||||
}
|
||||
|
||||
@ -518,19 +562,19 @@ func CreatePullRequest(ctx *context.APIContext) {
|
||||
return
|
||||
}
|
||||
|
||||
valid, err := access_model.CanBeAssigned(ctx, assignee, repo, true)
|
||||
valid, err := access_model.CanBeAssigned(ctx, assignee, baseRepo, true)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "canBeAssigned", err)
|
||||
return
|
||||
}
|
||||
if !valid {
|
||||
ctx.Error(http.StatusUnprocessableEntity, "canBeAssigned", repo_model.ErrUserDoesNotHaveAccessToRepo{UserID: aID, RepoName: repo.Name})
|
||||
ctx.Error(http.StatusUnprocessableEntity, "canBeAssigned", repo_model.ErrUserDoesNotHaveAccessToRepo{UserID: aID, RepoName: baseRepo.Name})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
prOpts := &pull_service.NewPullRequestOptions{
|
||||
Repo: repo,
|
||||
Repo: baseRepo,
|
||||
Issue: prIssue,
|
||||
LabelIDs: labelIDs,
|
||||
PullRequest: pr,
|
||||
@ -554,7 +598,7 @@ func CreatePullRequest(ctx *context.APIContext) {
|
||||
return
|
||||
}
|
||||
|
||||
log.Trace("Pull request created: %d/%d", repo.ID, prIssue.ID)
|
||||
log.Trace("Pull request created: %d/%d", baseRepo.ID, prIssue.ID)
|
||||
ctx.JSON(http.StatusCreated, convert.ToAPIPullRequest(ctx, pr, ctx.Doer))
|
||||
}
|
||||
|
||||
@ -1070,135 +1114,6 @@ func MergePullRequest(ctx *context.APIContext) {
|
||||
ctx.Status(http.StatusOK)
|
||||
}
|
||||
|
||||
type parseCompareInfoResult struct {
|
||||
headRepo *repo_model.Repository
|
||||
headGitRepo *git.Repository
|
||||
compareInfo *git.CompareInfo
|
||||
baseRef git.RefName
|
||||
headRef git.RefName
|
||||
}
|
||||
|
||||
// parseCompareInfo returns non-nil if it succeeds, it always writes to the context and returns nil if it fails
|
||||
func parseCompareInfo(ctx *context.APIContext, form api.CreatePullRequestOption) (result *parseCompareInfoResult, closer func()) {
|
||||
var err error
|
||||
// Get compared branches information
|
||||
// format: <base branch>...[<head repo>:]<head branch>
|
||||
// base<-head: master...head:feature
|
||||
// same repo: master...feature
|
||||
baseRepo := ctx.Repo.Repository
|
||||
baseRefToGuess := form.Base
|
||||
|
||||
headUser := ctx.Repo.Owner
|
||||
headRefToGuess := form.Head
|
||||
if headInfos := strings.Split(form.Head, ":"); len(headInfos) == 1 {
|
||||
// If there is no head repository, it means pull request between same repository.
|
||||
// Do nothing here because the head variables have been assigned above.
|
||||
} else if len(headInfos) == 2 {
|
||||
// There is a head repository (the head repository could also be the same base repo)
|
||||
headRefToGuess = headInfos[1]
|
||||
headUser, err = user_model.GetUserByName(ctx, headInfos[0])
|
||||
if err != nil {
|
||||
if user_model.IsErrUserNotExist(err) {
|
||||
ctx.NotFound("GetUserByName")
|
||||
} else {
|
||||
ctx.Error(http.StatusInternalServerError, "GetUserByName", err)
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
} else {
|
||||
ctx.NotFound()
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
isSameRepo := ctx.Repo.Owner.ID == headUser.ID
|
||||
|
||||
// Check if current user has fork of repository or in the same repository.
|
||||
headRepo := repo_model.GetForkedRepo(ctx, headUser.ID, baseRepo.ID)
|
||||
if headRepo == nil && !isSameRepo {
|
||||
err = baseRepo.GetBaseRepo(ctx)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "GetBaseRepo", err)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Check if baseRepo's base repository is the same as headUser's repository.
|
||||
if baseRepo.BaseRepo == nil || baseRepo.BaseRepo.OwnerID != headUser.ID {
|
||||
log.Trace("parseCompareInfo[%d]: does not have fork or in same repository", baseRepo.ID)
|
||||
ctx.NotFound("GetBaseRepo")
|
||||
return nil, nil
|
||||
}
|
||||
// Assign headRepo so it can be used below.
|
||||
headRepo = baseRepo.BaseRepo
|
||||
}
|
||||
|
||||
var headGitRepo *git.Repository
|
||||
if isSameRepo {
|
||||
headRepo = ctx.Repo.Repository
|
||||
headGitRepo = ctx.Repo.GitRepo
|
||||
closer = func() {} // no need to close the head repo because it shares the base repo
|
||||
} else {
|
||||
headGitRepo, err = gitrepo.OpenRepository(ctx, headRepo)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "OpenRepository", err)
|
||||
return nil, nil
|
||||
}
|
||||
closer = func() { _ = headGitRepo.Close() }
|
||||
}
|
||||
defer func() {
|
||||
if result == nil && !isSameRepo {
|
||||
_ = headGitRepo.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
// user should have permission to read baseRepo's codes and pulls, NOT headRepo's
|
||||
permBase, err := access_model.GetUserRepoPermission(ctx, baseRepo, ctx.Doer)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "GetUserRepoPermission", err)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if !permBase.CanReadIssuesOrPulls(true) || !permBase.CanRead(unit.TypeCode) {
|
||||
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.Doer, baseRepo, permBase)
|
||||
ctx.NotFound("Can't read pulls or can't read UnitTypeCode")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// user should have permission to read headRepo's codes
|
||||
// TODO: could the logic be simplified if the headRepo is the same as the baseRepo? Need to think more about it.
|
||||
permHead, err := access_model.GetUserRepoPermission(ctx, headRepo, ctx.Doer)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "GetUserRepoPermission", err)
|
||||
return nil, nil
|
||||
}
|
||||
if !permHead.CanRead(unit.TypeCode) {
|
||||
log.Trace("Permission Denied: User: %-v cannot read code in Repo: %-v\nUser in headRepo has Permissions: %-+v", ctx.Doer, headRepo, permHead)
|
||||
ctx.NotFound("Can't read headRepo UnitTypeCode")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
baseRef := ctx.Repo.GitRepo.UnstableGuessRefByShortName(baseRefToGuess)
|
||||
headRef := headGitRepo.UnstableGuessRefByShortName(headRefToGuess)
|
||||
|
||||
log.Trace("Repo path: %q, base ref: %q->%q, head ref: %q->%q", ctx.Repo.GitRepo.Path, baseRefToGuess, baseRef, headRefToGuess, headRef)
|
||||
|
||||
baseRefValid := baseRef.IsBranch() || baseRef.IsTag() || git.IsStringLikelyCommitID(git.ObjectFormatFromName(ctx.Repo.Repository.ObjectFormatName), baseRef.ShortName())
|
||||
headRefValid := headRef.IsBranch() || headRef.IsTag() || git.IsStringLikelyCommitID(git.ObjectFormatFromName(headRepo.ObjectFormatName), headRef.ShortName())
|
||||
// Check if base&head ref are valid.
|
||||
if !baseRefValid || !headRefValid {
|
||||
ctx.NotFound()
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
compareInfo, err := headGitRepo.GetCompareInfo(repo_model.RepoPath(baseRepo.Owner.Name, baseRepo.Name), baseRef.ShortName(), headRef.ShortName(), false, false)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "GetCompareInfo", err)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
result = &parseCompareInfoResult{headRepo: headRepo, headGitRepo: headGitRepo, compareInfo: compareInfo, baseRef: baseRef, headRef: headRef}
|
||||
return result, closer
|
||||
}
|
||||
|
||||
// UpdatePullRequest merge PR's baseBranch into headBranch
|
||||
func UpdatePullRequest(ctx *context.APIContext) {
|
||||
// swagger:operation POST /repos/{owner}/{repo}/pulls/{index}/update repository repoUpdatePullRequest
|
||||
|
@ -4,18 +4,336 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
git_model "code.gitea.io/gitea/models/git"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/gitrepo"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
)
|
||||
|
||||
type CompareRouter struct {
|
||||
BaseOriRef string
|
||||
BaseFullRef git.RefName
|
||||
HeadOwnerName string
|
||||
HeadRepoName string
|
||||
HeadOriRef string
|
||||
HeadFullRef git.RefName
|
||||
CaretTimes int // ^ times after base ref
|
||||
DotTimes int // 2(..) or 3(...)
|
||||
}
|
||||
|
||||
func (cr *CompareRouter) DirectComparison() bool {
|
||||
return cr.DotTimes == 2
|
||||
}
|
||||
|
||||
func parseBase(base string) (string, int) {
|
||||
parts := strings.SplitN(base, "^", 2)
|
||||
if len(parts) == 1 {
|
||||
return base, 0
|
||||
}
|
||||
return parts[0], len(parts[1]) + 1
|
||||
}
|
||||
|
||||
func parseHead(head string) (string, string, string) {
|
||||
paths := strings.SplitN(head, ":", 2)
|
||||
if len(paths) == 1 {
|
||||
return "", "", paths[0]
|
||||
}
|
||||
ownerRepo := strings.SplitN(paths[0], "/", 2)
|
||||
if len(ownerRepo) == 1 {
|
||||
return paths[0], "", paths[1]
|
||||
}
|
||||
return ownerRepo[0], ownerRepo[1], paths[1]
|
||||
}
|
||||
|
||||
func parseCompareRouter(router string) (*CompareRouter, error) {
|
||||
var basePart, headPart string
|
||||
dotTimes := 3
|
||||
parts := strings.Split(router, "...")
|
||||
if len(parts) > 2 {
|
||||
return nil, util.NewSilentWrapErrorf(util.ErrInvalidArgument, "invalid compare router: %s", router)
|
||||
}
|
||||
if len(parts) != 2 {
|
||||
parts = strings.Split(router, "..")
|
||||
if len(parts) == 1 {
|
||||
headOwnerName, headRepoName, headRef := parseHead(router)
|
||||
return &CompareRouter{
|
||||
HeadOriRef: headRef,
|
||||
HeadOwnerName: headOwnerName,
|
||||
HeadRepoName: headRepoName,
|
||||
DotTimes: dotTimes,
|
||||
}, nil
|
||||
} else if len(parts) > 2 {
|
||||
return nil, util.NewSilentWrapErrorf(util.ErrInvalidArgument, "invalid compare router: %s", router)
|
||||
}
|
||||
dotTimes = 2
|
||||
}
|
||||
basePart, headPart = parts[0], parts[1]
|
||||
|
||||
baseRef, caretTimes := parseBase(basePart)
|
||||
headOwnerName, headRepoName, headRef := parseHead(headPart)
|
||||
|
||||
return &CompareRouter{
|
||||
BaseOriRef: baseRef,
|
||||
HeadOriRef: headRef,
|
||||
HeadOwnerName: headOwnerName,
|
||||
HeadRepoName: headRepoName,
|
||||
CaretTimes: caretTimes,
|
||||
DotTimes: dotTimes,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CompareInfo represents the collected results from ParseCompareInfo
|
||||
type CompareInfo struct {
|
||||
HeadUser *user_model.User
|
||||
HeadRepo *repo_model.Repository
|
||||
HeadGitRepo *git.Repository
|
||||
CompareInfo *git.CompareInfo
|
||||
BaseBranch string
|
||||
HeadBranch string
|
||||
DirectComparison bool
|
||||
*CompareRouter
|
||||
BaseRepo *repo_model.Repository
|
||||
HeadUser *user_model.User
|
||||
HeadRepo *repo_model.Repository
|
||||
HeadGitRepo *git.Repository
|
||||
CompareInfo *git.CompareInfo
|
||||
close func()
|
||||
IsBaseCommit bool
|
||||
IsHeadCommit bool
|
||||
}
|
||||
|
||||
func (cr *CompareInfo) IsSameRepo() bool {
|
||||
return cr.HeadRepo.ID == cr.BaseRepo.ID
|
||||
}
|
||||
|
||||
func (cr *CompareInfo) IsSameRef() bool {
|
||||
return cr.IsSameRepo() && cr.BaseOriRef == cr.HeadOriRef
|
||||
}
|
||||
|
||||
// display pull related information or not
|
||||
func (cr *CompareInfo) IsPull() bool {
|
||||
return cr.CaretTimes == 0 && !cr.DirectComparison() &&
|
||||
cr.BaseFullRef.IsBranch() && (cr.HeadRepo == nil || cr.HeadFullRef.IsBranch())
|
||||
}
|
||||
|
||||
func (cr *CompareInfo) Close() {
|
||||
if cr.close != nil {
|
||||
cr.close()
|
||||
}
|
||||
}
|
||||
|
||||
// detectFullRef detects a short name as a branch, tag or commit's full ref name and type.
|
||||
// It's the same job as git.UnstableGuessRefByShortName but with a database read instead of git read.
|
||||
func detectFullRef(ctx context.Context, repoID int64, gitRepo *git.Repository, oriRef string) (git.RefName, bool, error) {
|
||||
b, err := git_model.GetBranch(ctx, repoID, oriRef)
|
||||
if err != nil && !git_model.IsErrBranchNotExist(err) {
|
||||
return "", false, err
|
||||
}
|
||||
if b != nil && !b.IsDeleted {
|
||||
return git.RefNameFromBranch(oriRef), false, nil
|
||||
}
|
||||
|
||||
rel, err := repo_model.GetRelease(ctx, repoID, oriRef)
|
||||
if err != nil && !repo_model.IsErrReleaseNotExist(err) {
|
||||
return "", false, err
|
||||
}
|
||||
if rel != nil && rel.Sha1 != "" {
|
||||
return git.RefNameFromTag(oriRef), false, nil
|
||||
}
|
||||
|
||||
commitObjectID, err := gitRepo.ConvertToGitID(oriRef)
|
||||
if err != nil {
|
||||
return "", false, err
|
||||
}
|
||||
return git.RefName(commitObjectID.String()), true, nil
|
||||
}
|
||||
|
||||
func findHeadRepo(ctx context.Context, baseRepo *repo_model.Repository, headUserID int64) (*repo_model.Repository, error) {
|
||||
if baseRepo.IsFork {
|
||||
curRepo := baseRepo
|
||||
for curRepo.OwnerID != headUserID { // We assume the fork deepth is not too deep.
|
||||
if err := curRepo.GetBaseRepo(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if curRepo.BaseRepo == nil {
|
||||
return findHeadRepoFromRootBase(ctx, curRepo, headUserID, 3)
|
||||
}
|
||||
curRepo = curRepo.BaseRepo
|
||||
}
|
||||
return curRepo, nil
|
||||
}
|
||||
|
||||
return findHeadRepoFromRootBase(ctx, baseRepo, headUserID, 3)
|
||||
}
|
||||
|
||||
func findHeadRepoFromRootBase(ctx context.Context, baseRepo *repo_model.Repository, headUserID int64, traverseLevel int) (*repo_model.Repository, error) {
|
||||
if traverseLevel == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
// test if we are lucky
|
||||
repo, err := repo_model.GetUserFork(ctx, headUserID, baseRepo.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if repo != nil {
|
||||
return repo, nil
|
||||
}
|
||||
|
||||
firstLevelForkedRepo, err := repo_model.GetRepositoriesByForkID(ctx, baseRepo.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, repo := range firstLevelForkedRepo {
|
||||
forked, err := findHeadRepoFromRootBase(ctx, repo, headUserID, traverseLevel-1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if forked != nil {
|
||||
return forked, nil
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func getRootRepo(ctx context.Context, repo *repo_model.Repository) (*repo_model.Repository, error) {
|
||||
curRepo := repo
|
||||
for curRepo.IsFork {
|
||||
if err := curRepo.GetBaseRepo(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if curRepo.BaseRepo == nil {
|
||||
break
|
||||
}
|
||||
curRepo = curRepo.BaseRepo
|
||||
}
|
||||
return curRepo, nil
|
||||
}
|
||||
|
||||
// ParseComparePathParams Get compare information
|
||||
// A full compare url is of the form:
|
||||
//
|
||||
// 1. /{:baseOwner}/{:baseRepoName}/compare/{:baseBranch}...{:headBranch}
|
||||
// 2. /{:baseOwner}/{:baseRepoName}/compare/{:baseBranch}...{:headOwner}:{:headBranch}
|
||||
// 3. /{:baseOwner}/{:baseRepoName}/compare/{:baseBranch}...{:headOwner}/{:headRepoName}:{:headBranch}
|
||||
// 4. /{:baseOwner}/{:baseRepoName}/compare/{:headBranch}
|
||||
// 5. /{:baseOwner}/{:baseRepoName}/compare/{:headOwner}:{:headBranch}
|
||||
// 6. /{:baseOwner}/{:baseRepoName}/compare/{:headOwner}/{:headRepoName}:{:headBranch}
|
||||
//
|
||||
// Here we obtain the infoPath "{:baseBranch}...[{:headOwner}/{:headRepoName}:]{:headBranch}" as ctx.PathParam("*")
|
||||
// with the :baseRepo in ctx.Repo.
|
||||
//
|
||||
// Note: Generally :headRepoName is not provided here - we are only passed :headOwner.
|
||||
//
|
||||
// How do we determine the :headRepo?
|
||||
//
|
||||
// 1. If :headOwner is not set then the :headRepo = :baseRepo
|
||||
// 2. If :headOwner is set - then look for the fork of :baseRepo owned by :headOwner
|
||||
// 3. But... :baseRepo could be a fork of :headOwner's repo - so check that
|
||||
// 4. Now, :baseRepo and :headRepos could be forks of the same repo - so check that
|
||||
//
|
||||
// format: <base branch>...[<head repo>:]<head branch>
|
||||
// base<-head: master...head:feature
|
||||
// same repo: master...feature
|
||||
func ParseComparePathParams(ctx context.Context, pathParam string, baseRepo *repo_model.Repository, baseGitRepo *git.Repository) (*CompareInfo, error) {
|
||||
ci := &CompareInfo{BaseRepo: baseRepo}
|
||||
var err error
|
||||
|
||||
if pathParam == "" {
|
||||
ci.HeadOriRef = baseRepo.DefaultBranch
|
||||
} else {
|
||||
ci.CompareRouter, err = parseCompareRouter(pathParam)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if ci.BaseOriRef == "" {
|
||||
ci.BaseOriRef = baseRepo.DefaultBranch
|
||||
}
|
||||
|
||||
if (ci.HeadOwnerName == "" && ci.HeadRepoName == "") ||
|
||||
(ci.HeadOwnerName == baseRepo.Owner.Name && ci.HeadRepoName == baseRepo.Name) {
|
||||
ci.HeadOwnerName = baseRepo.Owner.Name
|
||||
ci.HeadRepoName = baseRepo.Name
|
||||
ci.HeadUser = baseRepo.Owner
|
||||
ci.HeadRepo = baseRepo
|
||||
ci.HeadGitRepo = baseGitRepo
|
||||
} else {
|
||||
if ci.HeadOwnerName == baseRepo.Owner.Name {
|
||||
ci.HeadUser = baseRepo.Owner
|
||||
if ci.HeadRepoName == "" {
|
||||
ci.HeadRepoName = baseRepo.Name
|
||||
ci.HeadRepo = baseRepo
|
||||
}
|
||||
} else {
|
||||
ci.HeadUser, err = user_model.GetUserByName(ctx, ci.HeadOwnerName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if ci.HeadRepo == nil {
|
||||
if ci.HeadRepoName != "" {
|
||||
ci.HeadRepo, err = repo_model.GetRepositoryByOwnerAndName(ctx, ci.HeadOwnerName, ci.HeadRepoName)
|
||||
} else {
|
||||
ci.HeadRepo, err = findHeadRepo(ctx, baseRepo, ci.HeadUser.ID)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if ci.HeadRepo != nil {
|
||||
ci.HeadRepo.Owner = ci.HeadUser
|
||||
ci.HeadGitRepo, err = gitrepo.OpenRepository(ctx, ci.HeadRepo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ci.close = func() {
|
||||
if ci.HeadGitRepo != nil {
|
||||
ci.HeadGitRepo.Close()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ci.BaseFullRef, ci.IsBaseCommit, err = detectFullRef(ctx, baseRepo.ID, baseGitRepo, ci.BaseOriRef)
|
||||
if err != nil {
|
||||
ci.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if ci.HeadRepo != nil {
|
||||
ci.HeadFullRef, ci.IsHeadCommit, err = detectFullRef(ctx, ci.HeadRepo.ID, ci.HeadGitRepo, ci.HeadOriRef)
|
||||
if err != nil {
|
||||
ci.Close()
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return ci, nil
|
||||
}
|
||||
|
||||
func (cr *CompareInfo) LoadRootRepoAndOwnForkRepo(ctx context.Context, baseRepo *repo_model.Repository, doer *user_model.User) (*repo_model.Repository, *repo_model.Repository, error) {
|
||||
// find root repo
|
||||
var rootRepo *repo_model.Repository
|
||||
var err error
|
||||
if !baseRepo.IsFork {
|
||||
rootRepo = baseRepo
|
||||
} else {
|
||||
if !cr.HeadRepo.IsFork {
|
||||
rootRepo = cr.HeadRepo
|
||||
} else {
|
||||
rootRepo, err = getRootRepo(ctx, baseRepo)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// find ownfork repo
|
||||
var ownForkRepo *repo_model.Repository
|
||||
if doer != nil && cr.HeadRepo.OwnerID != doer.ID && baseRepo.OwnerID != doer.ID {
|
||||
ownForkRepo, err = findHeadRepo(ctx, baseRepo, doer.ID)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return rootRepo, ownForkRepo, nil
|
||||
}
|
||||
|
329
routers/common/compare_test.go
Normal file
329
routers/common/compare_test.go
Normal file
@ -0,0 +1,329 @@
|
||||
// Copyright 2024 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package common
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
"code.gitea.io/gitea/modules/gitrepo"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCompareRouters(t *testing.T) {
|
||||
kases := []struct {
|
||||
router string
|
||||
compareRouter *CompareRouter
|
||||
}{
|
||||
{
|
||||
router: "main...develop",
|
||||
compareRouter: &CompareRouter{
|
||||
BaseOriRef: "main",
|
||||
HeadOriRef: "develop",
|
||||
DotTimes: 3,
|
||||
},
|
||||
},
|
||||
{
|
||||
router: "main..develop",
|
||||
compareRouter: &CompareRouter{
|
||||
BaseOriRef: "main",
|
||||
HeadOriRef: "develop",
|
||||
DotTimes: 2,
|
||||
},
|
||||
},
|
||||
{
|
||||
router: "main^...develop",
|
||||
compareRouter: &CompareRouter{
|
||||
BaseOriRef: "main",
|
||||
HeadOriRef: "develop",
|
||||
CaretTimes: 1,
|
||||
DotTimes: 3,
|
||||
},
|
||||
},
|
||||
{
|
||||
router: "main^^^^^...develop",
|
||||
compareRouter: &CompareRouter{
|
||||
BaseOriRef: "main",
|
||||
HeadOriRef: "develop",
|
||||
CaretTimes: 5,
|
||||
DotTimes: 3,
|
||||
},
|
||||
},
|
||||
{
|
||||
router: "develop",
|
||||
compareRouter: &CompareRouter{
|
||||
HeadOriRef: "develop",
|
||||
DotTimes: 3,
|
||||
},
|
||||
},
|
||||
{
|
||||
router: "lunny/forked_repo:develop",
|
||||
compareRouter: &CompareRouter{
|
||||
HeadOwnerName: "lunny",
|
||||
HeadRepoName: "forked_repo",
|
||||
HeadOriRef: "develop",
|
||||
DotTimes: 3,
|
||||
},
|
||||
},
|
||||
{
|
||||
router: "main...lunny/forked_repo:develop",
|
||||
compareRouter: &CompareRouter{
|
||||
BaseOriRef: "main",
|
||||
HeadOwnerName: "lunny",
|
||||
HeadRepoName: "forked_repo",
|
||||
HeadOriRef: "develop",
|
||||
DotTimes: 3,
|
||||
},
|
||||
},
|
||||
{
|
||||
router: "main...lunny/forked_repo:develop",
|
||||
compareRouter: &CompareRouter{
|
||||
BaseOriRef: "main",
|
||||
HeadOwnerName: "lunny",
|
||||
HeadRepoName: "forked_repo",
|
||||
HeadOriRef: "develop",
|
||||
DotTimes: 3,
|
||||
},
|
||||
},
|
||||
{
|
||||
router: "main^...lunny/forked_repo:develop",
|
||||
compareRouter: &CompareRouter{
|
||||
BaseOriRef: "main",
|
||||
HeadOwnerName: "lunny",
|
||||
HeadRepoName: "forked_repo",
|
||||
HeadOriRef: "develop",
|
||||
DotTimes: 3,
|
||||
CaretTimes: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
router: "v1.0...v1.1",
|
||||
compareRouter: &CompareRouter{
|
||||
BaseOriRef: "v1.0",
|
||||
HeadOriRef: "v1.1",
|
||||
DotTimes: 3,
|
||||
},
|
||||
},
|
||||
{
|
||||
router: "teabot-patch-1...v0.0.1",
|
||||
compareRouter: &CompareRouter{
|
||||
BaseOriRef: "teabot-patch-1",
|
||||
HeadOriRef: "v0.0.1",
|
||||
DotTimes: 3,
|
||||
},
|
||||
},
|
||||
{
|
||||
router: "teabot:feature1",
|
||||
compareRouter: &CompareRouter{
|
||||
HeadOwnerName: "teabot",
|
||||
HeadOriRef: "feature1",
|
||||
DotTimes: 3,
|
||||
},
|
||||
},
|
||||
{
|
||||
router: "8eb19a5ae19abae15c0666d4ab98906139a7f439...283c030497b455ecfa759d4649f9f8b45158742e",
|
||||
compareRouter: &CompareRouter{
|
||||
BaseOriRef: "8eb19a5ae19abae15c0666d4ab98906139a7f439",
|
||||
HeadOriRef: "283c030497b455ecfa759d4649f9f8b45158742e",
|
||||
DotTimes: 3,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, kase := range kases {
|
||||
t.Run(kase.router, func(t *testing.T) {
|
||||
r, err := parseCompareRouter(kase.router)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, kase.compareRouter, r)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_ParseComparePathParams(t *testing.T) {
|
||||
baseRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
assert.NotNil(t, baseRepo)
|
||||
assert.NoError(t, baseRepo.LoadOwner(db.DefaultContext))
|
||||
baseGitRepo, err := gitrepo.OpenRepository(context.Background(), baseRepo)
|
||||
assert.NoError(t, err)
|
||||
defer baseGitRepo.Close()
|
||||
|
||||
kases := []struct {
|
||||
router string
|
||||
compareInfo *CompareInfo
|
||||
}{
|
||||
{
|
||||
router: "main...develop",
|
||||
compareInfo: &CompareInfo{
|
||||
CompareRouter: &CompareRouter{
|
||||
BaseOriRef: "main",
|
||||
HeadOriRef: "develop",
|
||||
DotTimes: 3,
|
||||
},
|
||||
BaseRepo: baseRepo,
|
||||
HeadUser: baseRepo.Owner,
|
||||
HeadRepo: baseRepo,
|
||||
HeadGitRepo: baseGitRepo,
|
||||
},
|
||||
},
|
||||
{
|
||||
router: "main..develop",
|
||||
compareInfo: &CompareInfo{
|
||||
CompareRouter: &CompareRouter{
|
||||
BaseOriRef: "main",
|
||||
HeadOriRef: "develop",
|
||||
DotTimes: 2,
|
||||
},
|
||||
BaseRepo: baseRepo,
|
||||
HeadUser: baseRepo.Owner,
|
||||
HeadRepo: baseRepo,
|
||||
HeadGitRepo: baseGitRepo,
|
||||
},
|
||||
},
|
||||
{
|
||||
router: "main^...develop",
|
||||
compareInfo: &CompareInfo{
|
||||
CompareRouter: &CompareRouter{
|
||||
BaseOriRef: "main",
|
||||
HeadOriRef: "develop",
|
||||
CaretTimes: 1,
|
||||
DotTimes: 3,
|
||||
},
|
||||
BaseRepo: baseRepo,
|
||||
HeadUser: baseRepo.Owner,
|
||||
HeadRepo: baseRepo,
|
||||
HeadGitRepo: baseGitRepo,
|
||||
},
|
||||
},
|
||||
{
|
||||
router: "main^^^^^...develop",
|
||||
compareInfo: &CompareInfo{
|
||||
CompareRouter: &CompareRouter{
|
||||
BaseOriRef: "main",
|
||||
HeadOriRef: "develop",
|
||||
CaretTimes: 5,
|
||||
DotTimes: 3,
|
||||
},
|
||||
BaseRepo: baseRepo,
|
||||
HeadUser: baseRepo.Owner,
|
||||
HeadRepo: baseRepo,
|
||||
HeadGitRepo: baseGitRepo,
|
||||
},
|
||||
},
|
||||
{
|
||||
router: "develop",
|
||||
compareInfo: &CompareInfo{
|
||||
CompareRouter: &CompareRouter{
|
||||
BaseOriRef: baseRepo.DefaultBranch,
|
||||
HeadOriRef: "develop",
|
||||
DotTimes: 3,
|
||||
},
|
||||
BaseRepo: baseRepo,
|
||||
HeadUser: baseRepo.Owner,
|
||||
HeadRepo: baseRepo,
|
||||
HeadGitRepo: baseGitRepo,
|
||||
},
|
||||
},
|
||||
{
|
||||
router: "lunny/forked_repo:develop",
|
||||
compareInfo: &CompareInfo{
|
||||
CompareRouter: &CompareRouter{
|
||||
BaseOriRef: baseRepo.DefaultBranch,
|
||||
HeadOwnerName: "lunny",
|
||||
HeadRepoName: "forked_repo",
|
||||
HeadOriRef: "develop",
|
||||
DotTimes: 3,
|
||||
},
|
||||
BaseRepo: baseRepo,
|
||||
},
|
||||
},
|
||||
{
|
||||
router: "main...lunny/forked_repo:develop",
|
||||
compareInfo: &CompareInfo{
|
||||
CompareRouter: &CompareRouter{
|
||||
BaseOriRef: "main",
|
||||
HeadOwnerName: "lunny",
|
||||
HeadRepoName: "forked_repo",
|
||||
HeadOriRef: "develop",
|
||||
DotTimes: 3,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
router: "main...lunny/forked_repo:develop",
|
||||
compareInfo: &CompareInfo{
|
||||
CompareRouter: &CompareRouter{
|
||||
BaseOriRef: "main",
|
||||
HeadOwnerName: "lunny",
|
||||
HeadRepoName: "forked_repo",
|
||||
HeadOriRef: "develop",
|
||||
DotTimes: 3,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
router: "main^...lunny/forked_repo:develop",
|
||||
compareInfo: &CompareInfo{
|
||||
CompareRouter: &CompareRouter{
|
||||
BaseOriRef: "main",
|
||||
HeadOwnerName: "lunny",
|
||||
HeadRepoName: "forked_repo",
|
||||
HeadOriRef: "develop",
|
||||
DotTimes: 3,
|
||||
CaretTimes: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
router: "v1.0...v1.1",
|
||||
compareInfo: &CompareInfo{
|
||||
CompareRouter: &CompareRouter{
|
||||
BaseOriRef: "v1.0",
|
||||
HeadOriRef: "v1.1",
|
||||
DotTimes: 3,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
router: "teabot-patch-1...v0.0.1",
|
||||
compareInfo: &CompareInfo{
|
||||
CompareRouter: &CompareRouter{
|
||||
BaseOriRef: "teabot-patch-1",
|
||||
HeadOriRef: "v0.0.1",
|
||||
DotTimes: 3,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
router: "teabot:feature1",
|
||||
compareInfo: &CompareInfo{
|
||||
CompareRouter: &CompareRouter{
|
||||
HeadOwnerName: "teabot",
|
||||
HeadOriRef: "feature1",
|
||||
DotTimes: 3,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
router: "8eb19a5ae19abae15c0666d4ab98906139a7f439...283c030497b455ecfa759d4649f9f8b45158742e",
|
||||
compareInfo: &CompareInfo{
|
||||
CompareRouter: &CompareRouter{
|
||||
BaseOriRef: "8eb19a5ae19abae15c0666d4ab98906139a7f439",
|
||||
HeadOriRef: "283c030497b455ecfa759d4649f9f8b45158742e",
|
||||
DotTimes: 3,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, kase := range kases {
|
||||
t.Run(kase.router, func(t *testing.T) {
|
||||
r, err := ParseComparePathParams(context.Background(), kase.router, baseRepo, baseGitRepo)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, kase.compareInfo, r)
|
||||
})
|
||||
}
|
||||
}
|
@ -94,7 +94,7 @@ func Emails(ctx *context.Context) {
|
||||
ctx.Data["Emails"] = emails
|
||||
|
||||
pager := context.NewPagination(int(count), opts.PageSize, opts.Page, 5)
|
||||
pager.SetDefaultParams(ctx)
|
||||
pager.AddParamFromRequest(ctx.Req)
|
||||
ctx.Data["Page"] = pager
|
||||
|
||||
ctx.HTML(http.StatusOK, tplEmails)
|
||||
|
@ -77,9 +77,7 @@ func Packages(ctx *context.Context) {
|
||||
ctx.Data["TotalUnreferencedBlobSize"] = totalUnreferencedBlobSize
|
||||
|
||||
pager := context.NewPagination(int(total), setting.UI.PackagesPagingNum, page, 5)
|
||||
pager.AddParamString("q", query)
|
||||
pager.AddParamString("type", packageType)
|
||||
pager.AddParamString("sort", sort)
|
||||
pager.AddParamFromRequest(ctx.Req)
|
||||
ctx.Data["Page"] = pager
|
||||
|
||||
ctx.HTML(http.StatusOK, tplPackagesList)
|
||||
|
@ -4,7 +4,6 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
@ -84,8 +83,7 @@ func UnadoptedRepos(ctx *context.Context) {
|
||||
|
||||
if !doSearch {
|
||||
pager := context.NewPagination(0, opts.PageSize, opts.Page, 5)
|
||||
pager.SetDefaultParams(ctx)
|
||||
pager.AddParamString("search", fmt.Sprint(doSearch))
|
||||
pager.AddParamFromRequest(ctx.Req)
|
||||
ctx.Data["Page"] = pager
|
||||
ctx.HTML(http.StatusOK, tplUnadoptedRepos)
|
||||
return
|
||||
@ -99,8 +97,7 @@ func UnadoptedRepos(ctx *context.Context) {
|
||||
}
|
||||
ctx.Data["Dirs"] = repoNames
|
||||
pager := context.NewPagination(count, opts.PageSize, opts.Page, 5)
|
||||
pager.SetDefaultParams(ctx)
|
||||
pager.AddParamString("search", fmt.Sprint(doSearch))
|
||||
pager.AddParamFromRequest(ctx.Req)
|
||||
ctx.Data["Page"] = pager
|
||||
ctx.HTML(http.StatusOK, tplUnadoptedRepos)
|
||||
}
|
||||
|
@ -47,16 +47,12 @@ func Users(ctx *context.Context) {
|
||||
ctx.Data["Title"] = ctx.Tr("admin.users")
|
||||
ctx.Data["PageIsAdminUsers"] = true
|
||||
|
||||
extraParamStrings := map[string]string{}
|
||||
statusFilterKeys := []string{"is_active", "is_admin", "is_restricted", "is_2fa_enabled", "is_prohibit_login"}
|
||||
statusFilterMap := map[string]string{}
|
||||
for _, filterKey := range statusFilterKeys {
|
||||
paramKey := "status_filter[" + filterKey + "]"
|
||||
paramVal := ctx.FormString(paramKey)
|
||||
statusFilterMap[filterKey] = paramVal
|
||||
if paramVal != "" {
|
||||
extraParamStrings[paramKey] = paramVal
|
||||
}
|
||||
}
|
||||
|
||||
sortType := ctx.FormString("sort")
|
||||
@ -82,7 +78,6 @@ func Users(ctx *context.Context) {
|
||||
IsTwoFactorEnabled: util.OptionalBoolParse(statusFilterMap["is_2fa_enabled"]),
|
||||
IsProhibitLogin: util.OptionalBoolParse(statusFilterMap["is_prohibit_login"]),
|
||||
IncludeReserved: true, // administrator needs to list all accounts include reserved, bot, remote ones
|
||||
ExtraParamStrings: extraParamStrings,
|
||||
}, tplUsers)
|
||||
}
|
||||
|
||||
|
@ -137,8 +137,7 @@ func Code(ctx *context.Context) {
|
||||
ctx.Data["SearchResultLanguages"] = searchResultLanguages
|
||||
|
||||
pager := context.NewPagination(total, setting.UI.RepoSearchPagingNum, page, 5)
|
||||
pager.SetDefaultParams(ctx)
|
||||
pager.AddParamString("l", language)
|
||||
pager.AddParamFromRequest(ctx.Req)
|
||||
ctx.Data["Page"] = pager
|
||||
|
||||
ctx.HTML(http.StatusOK, tplExploreCode)
|
||||
|
@ -4,7 +4,6 @@
|
||||
package explore
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
@ -139,25 +138,7 @@ func RenderRepoSearch(ctx *context.Context, opts *RepoSearchOptions) {
|
||||
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
|
||||
|
||||
pager := context.NewPagination(int(count), opts.PageSize, page, 5)
|
||||
pager.SetDefaultParams(ctx)
|
||||
pager.AddParamString("topic", fmt.Sprint(topicOnly))
|
||||
pager.AddParamString("language", language)
|
||||
pager.AddParamString(relevantReposOnlyParam, fmt.Sprint(opts.OnlyShowRelevant))
|
||||
if archived.Has() {
|
||||
pager.AddParamString("archived", fmt.Sprint(archived.Value()))
|
||||
}
|
||||
if fork.Has() {
|
||||
pager.AddParamString("fork", fmt.Sprint(fork.Value()))
|
||||
}
|
||||
if mirror.Has() {
|
||||
pager.AddParamString("mirror", fmt.Sprint(mirror.Value()))
|
||||
}
|
||||
if template.Has() {
|
||||
pager.AddParamString("template", fmt.Sprint(template.Value()))
|
||||
}
|
||||
if private.Has() {
|
||||
pager.AddParamString("private", fmt.Sprint(private.Value()))
|
||||
}
|
||||
pager.AddParamFromRequest(ctx.Req)
|
||||
ctx.Data["Page"] = pager
|
||||
|
||||
ctx.HTML(http.StatusOK, opts.TplName)
|
||||
|
@ -120,10 +120,7 @@ func RenderUserSearch(ctx *context.Context, opts *user_model.SearchUserOptions,
|
||||
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
|
||||
|
||||
pager := context.NewPagination(int(count), opts.PageSize, opts.Page, 5)
|
||||
pager.SetDefaultParams(ctx)
|
||||
for paramKey, paramVal := range opts.ExtraParamStrings {
|
||||
pager.AddParamString(paramKey, paramVal)
|
||||
}
|
||||
pager.AddParamFromRequest(ctx.Req)
|
||||
ctx.Data["Page"] = pager
|
||||
|
||||
ctx.HTML(http.StatusOK, tplName)
|
||||
|
@ -4,7 +4,6 @@
|
||||
package org
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"path"
|
||||
"strings"
|
||||
@ -146,23 +145,7 @@ func home(ctx *context.Context, viewRepositories bool) {
|
||||
ctx.Data["Total"] = count
|
||||
|
||||
pager := context.NewPagination(int(count), setting.UI.User.RepoPagingNum, page, 5)
|
||||
pager.SetDefaultParams(ctx)
|
||||
pager.AddParamString("language", language)
|
||||
if archived.Has() {
|
||||
pager.AddParamString("archived", fmt.Sprint(archived.Value()))
|
||||
}
|
||||
if fork.Has() {
|
||||
pager.AddParamString("fork", fmt.Sprint(fork.Value()))
|
||||
}
|
||||
if mirror.Has() {
|
||||
pager.AddParamString("mirror", fmt.Sprint(mirror.Value()))
|
||||
}
|
||||
if template.Has() {
|
||||
pager.AddParamString("template", fmt.Sprint(template.Value()))
|
||||
}
|
||||
if private.Has() {
|
||||
pager.AddParamString("private", fmt.Sprint(private.Value()))
|
||||
}
|
||||
pager.AddParamFromRequest(ctx.Req)
|
||||
ctx.Data["Page"] = pager
|
||||
|
||||
ctx.HTML(http.StatusOK, tplOrgHome)
|
||||
|
@ -120,7 +120,7 @@ func Projects(ctx *context.Context) {
|
||||
}
|
||||
|
||||
pager := context.NewPagination(int(total), setting.UI.IssuePagingNum, page, numPages)
|
||||
pager.AddParamString("state", fmt.Sprint(ctx.Data["State"]))
|
||||
pager.AddParamFromRequest(ctx.Req)
|
||||
ctx.Data["Page"] = pager
|
||||
|
||||
ctx.Data["CanWriteProjects"] = canWriteProjects(ctx)
|
||||
|
@ -6,7 +6,6 @@ package actions
|
||||
import (
|
||||
"bytes"
|
||||
stdCtx "context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"slices"
|
||||
"strings"
|
||||
@ -262,10 +261,7 @@ func List(ctx *context.Context) {
|
||||
ctx.Data["StatusInfoList"] = actions_model.GetStatusInfoList(ctx)
|
||||
|
||||
pager := context.NewPagination(int(total), opts.PageSize, opts.Page, 5)
|
||||
pager.SetDefaultParams(ctx)
|
||||
pager.AddParamString("workflow", workflowID)
|
||||
pager.AddParamString("actor", fmt.Sprint(actorID))
|
||||
pager.AddParamString("status", fmt.Sprint(status))
|
||||
pager.AddParamFromRequest(ctx.Req)
|
||||
ctx.Data["Page"] = pager
|
||||
ctx.Data["HasWorkflowsOrRuns"] = len(workflows) > 0 || len(runs) > 0
|
||||
|
||||
|
@ -87,7 +87,7 @@ func Branches(ctx *context.Context) {
|
||||
ctx.Data["CommitStatuses"] = commitStatuses
|
||||
ctx.Data["DefaultBranchBranch"] = defaultBranch
|
||||
pager := context.NewPagination(int(branchesCount), pageSize, page, 5)
|
||||
pager.SetDefaultParams(ctx)
|
||||
pager.AddParamFromRequest(ctx.Req)
|
||||
ctx.Data["Page"] = pager
|
||||
ctx.HTML(http.StatusOK, tplBranch)
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ func Commits(ctx *context.Context) {
|
||||
ctx.Data["CommitCount"] = commitsCount
|
||||
|
||||
pager := context.NewPagination(int(commitsCount), pageSize, page, 5)
|
||||
pager.SetDefaultParams(ctx)
|
||||
pager.AddParamFromRequest(ctx.Req)
|
||||
ctx.Data["Page"] = pager
|
||||
ctx.HTML(http.StatusOK, tplCommits)
|
||||
}
|
||||
@ -139,7 +139,6 @@ func Graph(ctx *context.Context) {
|
||||
if err != nil {
|
||||
log.Warn("GetCommitGraphsCount error for generate graph exclude prs: %t branches: %s in %-v, Will Ignore branches and try again. Underlying Error: %v", hidePRRefs, branches, ctx.Repo.Repository, err)
|
||||
realBranches = []string{}
|
||||
branches = []string{}
|
||||
graphCommitsCount, err = ctx.Repo.GetCommitGraphsCount(ctx, hidePRRefs, realBranches, files)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetCommitGraphsCount", err)
|
||||
@ -175,14 +174,7 @@ func Graph(ctx *context.Context) {
|
||||
ctx.Data["CommitCount"] = commitsCount
|
||||
|
||||
paginator := context.NewPagination(int(graphCommitsCount), setting.UI.GraphMaxCommitNum, page, 5)
|
||||
paginator.AddParamString("mode", mode)
|
||||
paginator.AddParamString("hide-pr-refs", fmt.Sprint(hidePRRefs))
|
||||
for _, branch := range branches {
|
||||
paginator.AddParamString("branch", branch)
|
||||
}
|
||||
for _, file := range files {
|
||||
paginator.AddParamString("file", file)
|
||||
}
|
||||
paginator.AddParamFromRequest(ctx.Req)
|
||||
ctx.Data["Page"] = paginator
|
||||
if ctx.FormBool("div-only") {
|
||||
ctx.HTML(http.StatusOK, tplGraphDiv)
|
||||
@ -262,7 +254,7 @@ func FileHistory(ctx *context.Context) {
|
||||
ctx.Data["CommitCount"] = commitsCount
|
||||
|
||||
pager := context.NewPagination(int(commitsCount), setting.Git.CommitsRangeSize, page, 5)
|
||||
pager.SetDefaultParams(ctx)
|
||||
pager.AddParamFromRequest(ctx.Req)
|
||||
ctx.Data["Page"] = pager
|
||||
ctx.HTML(http.StatusOK, tplCommits)
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
@ -188,254 +189,44 @@ func setCsvCompareContext(ctx *context.Context) {
|
||||
}
|
||||
|
||||
// ParseCompareInfo parse compare info between two commit for preparing comparing references
|
||||
// Permission check for base repository's code read should be checked before invoking this function
|
||||
func ParseCompareInfo(ctx *context.Context) *common.CompareInfo {
|
||||
baseRepo := ctx.Repo.Repository
|
||||
ci := &common.CompareInfo{}
|
||||
|
||||
fileOnly := ctx.FormBool("file-only")
|
||||
pathParam := ctx.PathParam("*")
|
||||
baseRepo := ctx.Repo.Repository
|
||||
|
||||
// Get compared branches information
|
||||
// A full compare url is of the form:
|
||||
//
|
||||
// 1. /{:baseOwner}/{:baseRepoName}/compare/{:baseBranch}...{:headBranch}
|
||||
// 2. /{:baseOwner}/{:baseRepoName}/compare/{:baseBranch}...{:headOwner}:{:headBranch}
|
||||
// 3. /{:baseOwner}/{:baseRepoName}/compare/{:baseBranch}...{:headOwner}/{:headRepoName}:{:headBranch}
|
||||
// 4. /{:baseOwner}/{:baseRepoName}/compare/{:headBranch}
|
||||
// 5. /{:baseOwner}/{:baseRepoName}/compare/{:headOwner}:{:headBranch}
|
||||
// 6. /{:baseOwner}/{:baseRepoName}/compare/{:headOwner}/{:headRepoName}:{:headBranch}
|
||||
//
|
||||
// Here we obtain the infoPath "{:baseBranch}...[{:headOwner}/{:headRepoName}:]{:headBranch}" as ctx.PathParam("*")
|
||||
// with the :baseRepo in ctx.Repo.
|
||||
//
|
||||
// Note: Generally :headRepoName is not provided here - we are only passed :headOwner.
|
||||
//
|
||||
// How do we determine the :headRepo?
|
||||
//
|
||||
// 1. If :headOwner is not set then the :headRepo = :baseRepo
|
||||
// 2. If :headOwner is set - then look for the fork of :baseRepo owned by :headOwner
|
||||
// 3. But... :baseRepo could be a fork of :headOwner's repo - so check that
|
||||
// 4. Now, :baseRepo and :headRepos could be forks of the same repo - so check that
|
||||
//
|
||||
// format: <base branch>...[<head repo>:]<head branch>
|
||||
// base<-head: master...head:feature
|
||||
// same repo: master...feature
|
||||
|
||||
var (
|
||||
isSameRepo bool
|
||||
infoPath string
|
||||
err error
|
||||
)
|
||||
|
||||
infoPath = ctx.PathParam("*")
|
||||
var infos []string
|
||||
if infoPath == "" {
|
||||
infos = []string{baseRepo.DefaultBranch, baseRepo.DefaultBranch}
|
||||
} else {
|
||||
infos = strings.SplitN(infoPath, "...", 2)
|
||||
if len(infos) != 2 {
|
||||
if infos = strings.SplitN(infoPath, "..", 2); len(infos) == 2 {
|
||||
ci.DirectComparison = true
|
||||
ctx.Data["PageIsComparePull"] = false
|
||||
} else {
|
||||
infos = []string{baseRepo.DefaultBranch, infoPath}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ctx.Data["BaseName"] = baseRepo.OwnerName
|
||||
ci.BaseBranch = infos[0]
|
||||
ctx.Data["BaseBranch"] = ci.BaseBranch
|
||||
|
||||
// If there is no head repository, it means compare between same repository.
|
||||
headInfos := strings.Split(infos[1], ":")
|
||||
if len(headInfos) == 1 {
|
||||
isSameRepo = true
|
||||
ci.HeadUser = ctx.Repo.Owner
|
||||
ci.HeadBranch = headInfos[0]
|
||||
} else if len(headInfos) == 2 {
|
||||
headInfosSplit := strings.Split(headInfos[0], "/")
|
||||
if len(headInfosSplit) == 1 {
|
||||
ci.HeadUser, err = user_model.GetUserByName(ctx, headInfos[0])
|
||||
if err != nil {
|
||||
if user_model.IsErrUserNotExist(err) {
|
||||
ctx.NotFound("GetUserByName", nil)
|
||||
} else {
|
||||
ctx.ServerError("GetUserByName", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
ci.HeadBranch = headInfos[1]
|
||||
isSameRepo = ci.HeadUser.ID == ctx.Repo.Owner.ID
|
||||
if isSameRepo {
|
||||
ci.HeadRepo = baseRepo
|
||||
}
|
||||
} else {
|
||||
ci.HeadRepo, err = repo_model.GetRepositoryByOwnerAndName(ctx, headInfosSplit[0], headInfosSplit[1])
|
||||
if err != nil {
|
||||
if repo_model.IsErrRepoNotExist(err) {
|
||||
ctx.NotFound("GetRepositoryByOwnerAndName", nil)
|
||||
} else {
|
||||
ctx.ServerError("GetRepositoryByOwnerAndName", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if err := ci.HeadRepo.LoadOwner(ctx); err != nil {
|
||||
if user_model.IsErrUserNotExist(err) {
|
||||
ctx.NotFound("GetUserByName", nil)
|
||||
} else {
|
||||
ctx.ServerError("GetUserByName", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
ci.HeadBranch = headInfos[1]
|
||||
ci.HeadUser = ci.HeadRepo.Owner
|
||||
isSameRepo = ci.HeadRepo.ID == ctx.Repo.Repository.ID
|
||||
}
|
||||
} else {
|
||||
ctx.NotFound("CompareAndPullRequest", nil)
|
||||
return nil
|
||||
}
|
||||
ctx.Data["HeadUser"] = ci.HeadUser
|
||||
ctx.Data["HeadBranch"] = ci.HeadBranch
|
||||
ctx.Repo.PullRequest.SameRepo = isSameRepo
|
||||
|
||||
// Check if base branch is valid.
|
||||
baseIsCommit := ctx.Repo.GitRepo.IsCommitExist(ci.BaseBranch)
|
||||
baseIsBranch := ctx.Repo.GitRepo.IsBranchExist(ci.BaseBranch)
|
||||
baseIsTag := ctx.Repo.GitRepo.IsTagExist(ci.BaseBranch)
|
||||
|
||||
if !baseIsCommit && !baseIsBranch && !baseIsTag {
|
||||
// Check if baseBranch is short sha commit hash
|
||||
if baseCommit, _ := ctx.Repo.GitRepo.GetCommit(ci.BaseBranch); baseCommit != nil {
|
||||
ci.BaseBranch = baseCommit.ID.String()
|
||||
ctx.Data["BaseBranch"] = ci.BaseBranch
|
||||
baseIsCommit = true
|
||||
} else if ci.BaseBranch == ctx.Repo.GetObjectFormat().EmptyObjectID().String() {
|
||||
if isSameRepo {
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + util.PathEscapeSegments(ci.HeadBranch))
|
||||
} else {
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + util.PathEscapeSegments(ci.HeadRepo.FullName()) + ":" + util.PathEscapeSegments(ci.HeadBranch))
|
||||
}
|
||||
return nil
|
||||
} else {
|
||||
ctx.NotFound("IsRefExist", nil)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
ctx.Data["BaseIsCommit"] = baseIsCommit
|
||||
ctx.Data["BaseIsBranch"] = baseIsBranch
|
||||
ctx.Data["BaseIsTag"] = baseIsTag
|
||||
ctx.Data["IsPull"] = true
|
||||
|
||||
// Now we have the repository that represents the base
|
||||
|
||||
// The current base and head repositories and branches may not
|
||||
// actually be the intended branches that the user wants to
|
||||
// create a pull-request from - but also determining the head
|
||||
// repo is difficult.
|
||||
|
||||
// We will want therefore to offer a few repositories to set as
|
||||
// our base and head
|
||||
|
||||
// 1. First if the baseRepo is a fork get the "RootRepo" it was
|
||||
// forked from
|
||||
var rootRepo *repo_model.Repository
|
||||
if baseRepo.IsFork {
|
||||
err = baseRepo.GetBaseRepo(ctx)
|
||||
if err != nil {
|
||||
if !repo_model.IsErrRepoNotExist(err) {
|
||||
ctx.ServerError("Unable to find root repo", err)
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
rootRepo = baseRepo.BaseRepo
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Now if the current user is not the owner of the baseRepo,
|
||||
// check if they have a fork of the base repo and offer that as
|
||||
// "OwnForkRepo"
|
||||
var ownForkRepo *repo_model.Repository
|
||||
if ctx.Doer != nil && baseRepo.OwnerID != ctx.Doer.ID {
|
||||
repo := repo_model.GetForkedRepo(ctx, ctx.Doer.ID, baseRepo.ID)
|
||||
if repo != nil {
|
||||
ownForkRepo = repo
|
||||
ctx.Data["OwnForkRepo"] = ownForkRepo
|
||||
}
|
||||
}
|
||||
|
||||
has := ci.HeadRepo != nil
|
||||
// 3. If the base is a forked from "RootRepo" and the owner of
|
||||
// the "RootRepo" is the :headUser - set headRepo to that
|
||||
if !has && rootRepo != nil && rootRepo.OwnerID == ci.HeadUser.ID {
|
||||
ci.HeadRepo = rootRepo
|
||||
has = true
|
||||
}
|
||||
|
||||
// 4. If the ctx.Doer has their own fork of the baseRepo and the headUser is the ctx.Doer
|
||||
// set the headRepo to the ownFork
|
||||
if !has && ownForkRepo != nil && ownForkRepo.OwnerID == ci.HeadUser.ID {
|
||||
ci.HeadRepo = ownForkRepo
|
||||
has = true
|
||||
}
|
||||
|
||||
// 5. If the headOwner has a fork of the baseRepo - use that
|
||||
if !has {
|
||||
ci.HeadRepo = repo_model.GetForkedRepo(ctx, ci.HeadUser.ID, baseRepo.ID)
|
||||
has = ci.HeadRepo != nil
|
||||
}
|
||||
|
||||
// 6. If the baseRepo is a fork and the headUser has a fork of that use that
|
||||
if !has && baseRepo.IsFork {
|
||||
ci.HeadRepo = repo_model.GetForkedRepo(ctx, ci.HeadUser.ID, baseRepo.ForkID)
|
||||
has = ci.HeadRepo != nil
|
||||
}
|
||||
|
||||
// 7. Otherwise if we're not the same repo and haven't found a repo give up
|
||||
if !isSameRepo && !has {
|
||||
ctx.Data["PageIsComparePull"] = false
|
||||
}
|
||||
|
||||
// 8. Finally open the git repo
|
||||
if isSameRepo {
|
||||
ci.HeadRepo = ctx.Repo.Repository
|
||||
ci.HeadGitRepo = ctx.Repo.GitRepo
|
||||
} else if has {
|
||||
ci.HeadGitRepo, err = gitrepo.OpenRepository(ctx, ci.HeadRepo)
|
||||
if err != nil {
|
||||
ctx.ServerError("OpenRepository", err)
|
||||
return nil
|
||||
}
|
||||
defer ci.HeadGitRepo.Close()
|
||||
} else {
|
||||
ctx.NotFound("ParseCompareInfo", nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
ctx.Data["HeadRepo"] = ci.HeadRepo
|
||||
ctx.Data["BaseCompareRepo"] = ctx.Repo.Repository
|
||||
|
||||
// Now we need to assert that the ctx.Doer has permission to read
|
||||
// the baseRepo's code and pulls
|
||||
// (NOT headRepo's)
|
||||
permBase, err := access_model.GetUserRepoPermission(ctx, baseRepo, ctx.Doer)
|
||||
ci, err := common.ParseComparePathParams(ctx, pathParam, baseRepo, ctx.Repo.GitRepo)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetUserRepoPermission", err)
|
||||
switch {
|
||||
case user_model.IsErrUserNotExist(err):
|
||||
ctx.NotFound("GetUserByName", nil)
|
||||
case repo_model.IsErrRepoNotExist(err):
|
||||
ctx.NotFound("GetRepositoryByOwnerAndName", nil)
|
||||
case errors.Is(err, util.ErrInvalidArgument):
|
||||
ctx.NotFound("ParseComparePathParams", nil)
|
||||
default:
|
||||
ctx.ServerError("GetRepositoryByOwnerAndName", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if !permBase.CanRead(unit.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)
|
||||
|
||||
// remove the check when we support compare with carets
|
||||
if ci.CaretTimes > 0 {
|
||||
ctx.NotFound("Unsupported compare", nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
if ci.BaseOriRef == ctx.Repo.GetObjectFormat().EmptyObjectID().String() {
|
||||
if ci.IsSameRepo() {
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + util.PathEscapeSegments(ci.HeadOriRef))
|
||||
} else {
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + util.PathEscapeSegments(ci.HeadRepo.FullName()) + ":" + util.PathEscapeSegments(ci.HeadOriRef))
|
||||
}
|
||||
ctx.NotFound("ParseCompareInfo", nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
// If we're not merging from the same repo:
|
||||
if !isSameRepo {
|
||||
if !ci.IsSameRepo() {
|
||||
// Assert ctx.Doer has permission to read headRepo's codes
|
||||
permHead, err := access_model.GetUserRepoPermission(ctx, ci.HeadRepo, ctx.Doer)
|
||||
if err != nil {
|
||||
@ -455,107 +246,30 @@ func ParseCompareInfo(ctx *context.Context) *common.CompareInfo {
|
||||
ctx.Data["CanWriteToHeadRepo"] = permHead.CanWrite(unit.TypeCode)
|
||||
}
|
||||
|
||||
// If we have a rootRepo and it's different from:
|
||||
// 1. the computed base
|
||||
// 2. the computed head
|
||||
// then get the branches of it
|
||||
if rootRepo != nil &&
|
||||
rootRepo.ID != ci.HeadRepo.ID &&
|
||||
rootRepo.ID != baseRepo.ID {
|
||||
canRead := access_model.CheckRepoUnitUser(ctx, rootRepo, ctx.Doer, unit.TypeCode)
|
||||
if canRead {
|
||||
ctx.Data["RootRepo"] = rootRepo
|
||||
if !fileOnly {
|
||||
branches, tags, err := getBranchesAndTagsForRepo(ctx, rootRepo)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetBranchesForRepo", err)
|
||||
return nil
|
||||
}
|
||||
ctx.Data["PageIsComparePull"] = ci.IsPull() && ctx.Repo.CanReadIssuesOrPulls(true)
|
||||
ctx.Data["BaseName"] = baseRepo.OwnerName
|
||||
ctx.Data["BaseBranch"] = ci.BaseOriRef
|
||||
ctx.Data["HeadUser"] = ci.HeadUser
|
||||
ctx.Data["HeadBranch"] = ci.HeadOriRef
|
||||
ctx.Repo.PullRequest.SameRepo = ci.IsSameRepo()
|
||||
|
||||
ctx.Data["RootRepoBranches"] = branches
|
||||
ctx.Data["RootRepoTags"] = tags
|
||||
}
|
||||
}
|
||||
}
|
||||
ctx.Data["BaseIsCommit"] = ci.IsBaseCommit
|
||||
ctx.Data["BaseIsBranch"] = ci.BaseFullRef.IsBranch()
|
||||
ctx.Data["BaseIsTag"] = ci.BaseFullRef.IsTag()
|
||||
ctx.Data["IsPull"] = true
|
||||
|
||||
// If we have a ownForkRepo and it's different from:
|
||||
// 1. The computed base
|
||||
// 2. The computed head
|
||||
// 3. The rootRepo (if we have one)
|
||||
// then get the branches from it.
|
||||
if ownForkRepo != nil &&
|
||||
ownForkRepo.ID != ci.HeadRepo.ID &&
|
||||
ownForkRepo.ID != baseRepo.ID &&
|
||||
(rootRepo == nil || ownForkRepo.ID != rootRepo.ID) {
|
||||
canRead := access_model.CheckRepoUnitUser(ctx, ownForkRepo, ctx.Doer, unit.TypeCode)
|
||||
if canRead {
|
||||
ctx.Data["OwnForkRepo"] = ownForkRepo
|
||||
if !fileOnly {
|
||||
branches, tags, err := getBranchesAndTagsForRepo(ctx, ownForkRepo)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetBranchesForRepo", err)
|
||||
return nil
|
||||
}
|
||||
ctx.Data["OwnForkRepoBranches"] = branches
|
||||
ctx.Data["OwnForkRepoTags"] = tags
|
||||
}
|
||||
}
|
||||
}
|
||||
ctx.Data["HeadRepo"] = ci.HeadRepo
|
||||
ctx.Data["BaseCompareRepo"] = ctx.Repo.Repository
|
||||
ctx.Data["HeadIsCommit"] = ci.IsHeadCommit
|
||||
ctx.Data["HeadIsBranch"] = ci.HeadFullRef.IsBranch()
|
||||
ctx.Data["HeadIsTag"] = ci.HeadFullRef.IsTag()
|
||||
|
||||
// Check if head branch is valid.
|
||||
headIsCommit := ci.HeadGitRepo.IsCommitExist(ci.HeadBranch)
|
||||
headIsBranch := ci.HeadGitRepo.IsBranchExist(ci.HeadBranch)
|
||||
headIsTag := ci.HeadGitRepo.IsTagExist(ci.HeadBranch)
|
||||
if !headIsCommit && !headIsBranch && !headIsTag {
|
||||
// Check if headBranch is short sha commit hash
|
||||
if headCommit, _ := ci.HeadGitRepo.GetCommit(ci.HeadBranch); headCommit != nil {
|
||||
ci.HeadBranch = headCommit.ID.String()
|
||||
ctx.Data["HeadBranch"] = ci.HeadBranch
|
||||
headIsCommit = true
|
||||
} else {
|
||||
ctx.NotFound("IsRefExist", nil)
|
||||
return 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.Doer,
|
||||
baseRepo,
|
||||
permBase)
|
||||
}
|
||||
ctx.NotFound("ParseCompareInfo", nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
baseBranchRef := ci.BaseBranch
|
||||
if baseIsBranch {
|
||||
baseBranchRef = git.BranchPrefix + ci.BaseBranch
|
||||
} else if baseIsTag {
|
||||
baseBranchRef = git.TagPrefix + ci.BaseBranch
|
||||
}
|
||||
headBranchRef := ci.HeadBranch
|
||||
if headIsBranch {
|
||||
headBranchRef = git.BranchPrefix + ci.HeadBranch
|
||||
} else if headIsTag {
|
||||
headBranchRef = git.TagPrefix + ci.HeadBranch
|
||||
}
|
||||
|
||||
ci.CompareInfo, err = ci.HeadGitRepo.GetCompareInfo(baseRepo.RepoPath(), baseBranchRef, headBranchRef, ci.DirectComparison, fileOnly)
|
||||
ci.CompareInfo, err = ci.HeadGitRepo.GetCompareInfo(baseRepo.RepoPath(), ci.BaseFullRef.String(), ci.HeadFullRef.String(), ci.DirectComparison(), fileOnly)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetCompareInfo", err)
|
||||
return nil
|
||||
}
|
||||
if ci.DirectComparison {
|
||||
if ci.DirectComparison() {
|
||||
ctx.Data["BeforeCommitID"] = ci.CompareInfo.BaseCommitID
|
||||
} else {
|
||||
ctx.Data["BeforeCommitID"] = ci.CompareInfo.MergeBase
|
||||
@ -583,14 +297,14 @@ func PrepareCompareDiff(
|
||||
|
||||
ctx.Data["AfterCommitID"] = headCommitID
|
||||
|
||||
if (headCommitID == ci.CompareInfo.MergeBase && !ci.DirectComparison) ||
|
||||
if (headCommitID == ci.CompareInfo.MergeBase && !ci.DirectComparison()) ||
|
||||
headCommitID == ci.CompareInfo.BaseCommitID {
|
||||
ctx.Data["IsNothingToCompare"] = true
|
||||
if unit, err := repo.GetUnit(ctx, unit.TypePullRequests); err == nil {
|
||||
config := unit.PullRequestsConfig()
|
||||
|
||||
if !config.AutodetectManualMerge {
|
||||
allowEmptyPr := !(ci.BaseBranch == ci.HeadBranch && ctx.Repo.Repository.Name == ci.HeadRepo.Name)
|
||||
allowEmptyPr := !(ci.BaseOriRef == ci.HeadOriRef && ctx.Repo.Repository.Name == ci.HeadRepo.Name)
|
||||
ctx.Data["AllowEmptyPr"] = allowEmptyPr
|
||||
|
||||
return !allowEmptyPr
|
||||
@ -602,7 +316,7 @@ func PrepareCompareDiff(
|
||||
}
|
||||
|
||||
beforeCommitID := ci.CompareInfo.MergeBase
|
||||
if ci.DirectComparison {
|
||||
if ci.DirectComparison() {
|
||||
beforeCommitID = ci.CompareInfo.BaseCommitID
|
||||
}
|
||||
|
||||
@ -623,7 +337,7 @@ func PrepareCompareDiff(
|
||||
MaxLineCharacters: setting.Git.MaxGitDiffLineCharacters,
|
||||
MaxFiles: maxFiles,
|
||||
WhitespaceBehavior: whitespaceBehavior,
|
||||
DirectComparison: ci.DirectComparison,
|
||||
DirectComparison: ci.DirectComparison(),
|
||||
FileOnly: fileOnly,
|
||||
}, ctx.FormStrings("files")...)
|
||||
if err != nil {
|
||||
@ -660,7 +374,7 @@ func PrepareCompareDiff(
|
||||
ctx.Data["content"] = strings.Join(body[1:], "\n")
|
||||
}
|
||||
} else {
|
||||
title = ci.HeadBranch
|
||||
title = ci.HeadOriRef
|
||||
}
|
||||
if len(title) > 255 {
|
||||
var trailer string
|
||||
@ -683,14 +397,8 @@ func PrepareCompareDiff(
|
||||
return false
|
||||
}
|
||||
|
||||
func getBranchesAndTagsForRepo(ctx gocontext.Context, repo *repo_model.Repository) (branches, tags []string, err error) {
|
||||
gitRepo, err := gitrepo.OpenRepository(ctx, repo)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer gitRepo.Close()
|
||||
|
||||
branches, err = git_model.FindBranchNames(ctx, git_model.FindBranchOptions{
|
||||
func getBranchesAndTagsForRepo(ctx gocontext.Context, repo *repo_model.Repository) ([]string, []string, error) {
|
||||
branches, err := git_model.FindBranchNames(ctx, git_model.FindBranchOptions{
|
||||
RepoID: repo.ID,
|
||||
ListOptions: db.ListOptionsAll,
|
||||
IsDeletedBranch: optional.Some(false),
|
||||
@ -698,19 +406,88 @@ func getBranchesAndTagsForRepo(ctx gocontext.Context, repo *repo_model.Repositor
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
tags, err = gitRepo.GetTags(0, 0)
|
||||
// always put default branch on the top if it exists
|
||||
if slices.Contains(branches, repo.DefaultBranch) {
|
||||
branches = util.SliceRemoveAll(branches, repo.DefaultBranch)
|
||||
branches = append([]string{repo.DefaultBranch}, branches...)
|
||||
}
|
||||
|
||||
tags, err := repo_model.GetTagNamesByRepoID(ctx, repo.ID)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return branches, tags, nil
|
||||
}
|
||||
|
||||
func prepareCompareRepoBranchesTagsDropdowns(ctx *context.Context, ci *common.CompareInfo) {
|
||||
baseRepo := ctx.Repo.Repository
|
||||
// For compare repo branches
|
||||
baseBranches, baseTags, err := getBranchesAndTagsForRepo(ctx, baseRepo)
|
||||
if err != nil {
|
||||
ctx.ServerError("getBranchesAndTagsForRepo", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Data["Branches"] = baseBranches
|
||||
ctx.Data["Tags"] = baseTags
|
||||
|
||||
if ci.IsSameRepo() {
|
||||
ctx.Data["HeadBranches"] = baseBranches
|
||||
ctx.Data["HeadTags"] = baseTags
|
||||
} else {
|
||||
headBranches, headTags, err := getBranchesAndTagsForRepo(ctx, ci.HeadRepo)
|
||||
if err != nil {
|
||||
ctx.ServerError("getBranchesAndTagsForRepo", err)
|
||||
return
|
||||
}
|
||||
ctx.Data["HeadBranches"] = headBranches
|
||||
ctx.Data["HeadTags"] = headTags
|
||||
}
|
||||
|
||||
rootRepo, ownForkRepo, err := ci.LoadRootRepoAndOwnForkRepo(ctx, baseRepo, ctx.Doer)
|
||||
if err != nil {
|
||||
ctx.ServerError("LoadRootRepoAndOwnForkRepo", err)
|
||||
return
|
||||
}
|
||||
|
||||
if rootRepo != nil &&
|
||||
rootRepo.ID != ci.HeadRepo.ID &&
|
||||
rootRepo.ID != baseRepo.ID {
|
||||
canRead := access_model.CheckRepoUnitUser(ctx, rootRepo, ctx.Doer, unit.TypeCode)
|
||||
if canRead {
|
||||
ctx.Data["RootRepo"] = rootRepo
|
||||
branches, tags, err := getBranchesAndTagsForRepo(ctx, rootRepo)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetBranchesForRepo", err)
|
||||
return
|
||||
}
|
||||
ctx.Data["RootRepoBranches"] = branches
|
||||
ctx.Data["RootRepoTags"] = tags
|
||||
}
|
||||
}
|
||||
|
||||
if ownForkRepo != nil &&
|
||||
ownForkRepo.ID != ci.HeadRepo.ID &&
|
||||
ownForkRepo.ID != baseRepo.ID &&
|
||||
(rootRepo == nil || ownForkRepo.ID != rootRepo.ID) {
|
||||
ctx.Data["OwnForkRepo"] = ownForkRepo
|
||||
branches, tags, err := getBranchesAndTagsForRepo(ctx, ownForkRepo)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetBranchesForRepo", err)
|
||||
return
|
||||
}
|
||||
ctx.Data["OwnForkRepoBranches"] = branches
|
||||
ctx.Data["OwnForkRepoTags"] = tags
|
||||
}
|
||||
}
|
||||
|
||||
// CompareDiff show different from one commit to another commit
|
||||
func CompareDiff(ctx *context.Context) {
|
||||
ci := ParseCompareInfo(ctx)
|
||||
defer func() {
|
||||
if ci != nil && ci.HeadGitRepo != nil {
|
||||
ci.HeadGitRepo.Close()
|
||||
if ci != nil {
|
||||
ci.Close()
|
||||
}
|
||||
}()
|
||||
if ctx.Written() {
|
||||
@ -721,7 +498,7 @@ func CompareDiff(ctx *context.Context) {
|
||||
ctx.Data["DirectComparison"] = ci.DirectComparison
|
||||
ctx.Data["OtherCompareSeparator"] = ".."
|
||||
ctx.Data["CompareSeparator"] = "..."
|
||||
if ci.DirectComparison {
|
||||
if ci.DirectComparison() {
|
||||
ctx.Data["CompareSeparator"] = ".."
|
||||
ctx.Data["OtherCompareSeparator"] = "..."
|
||||
}
|
||||
@ -732,45 +509,19 @@ func CompareDiff(ctx *context.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
baseTags, err := repo_model.GetTagNamesByRepoID(ctx, ctx.Repo.Repository.ID)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetTagNamesByRepoID", err)
|
||||
return
|
||||
}
|
||||
ctx.Data["Tags"] = baseTags
|
||||
|
||||
fileOnly := ctx.FormBool("file-only")
|
||||
if fileOnly {
|
||||
ctx.HTML(http.StatusOK, tplDiffBox)
|
||||
return
|
||||
}
|
||||
|
||||
headBranches, err := git_model.FindBranchNames(ctx, git_model.FindBranchOptions{
|
||||
RepoID: ci.HeadRepo.ID,
|
||||
ListOptions: db.ListOptionsAll,
|
||||
IsDeletedBranch: optional.Some(false),
|
||||
})
|
||||
if err != nil {
|
||||
ctx.ServerError("GetBranches", err)
|
||||
return
|
||||
}
|
||||
ctx.Data["HeadBranches"] = headBranches
|
||||
|
||||
// For compare repo branches
|
||||
PrepareBranchList(ctx)
|
||||
prepareCompareRepoBranchesTagsDropdowns(ctx, ci)
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
|
||||
headTags, err := repo_model.GetTagNamesByRepoID(ctx, ci.HeadRepo.ID)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetTagNamesByRepoID", err)
|
||||
return
|
||||
}
|
||||
ctx.Data["HeadTags"] = headTags
|
||||
|
||||
if ctx.Data["PageIsComparePull"] == true {
|
||||
pr, err := issues_model.GetUnmergedPullRequest(ctx, ci.HeadRepo.ID, ctx.Repo.Repository.ID, ci.HeadBranch, ci.BaseBranch, issues_model.PullRequestFlowGithub)
|
||||
pr, err := issues_model.GetUnmergedPullRequest(ctx, ci.HeadRepo.ID, ctx.Repo.Repository.ID, ci.HeadOriRef, ci.BaseOriRef, issues_model.PullRequestFlowGithub)
|
||||
if err != nil {
|
||||
if !issues_model.IsErrPullRequestNotExist(err) {
|
||||
ctx.ServerError("GetUnmergedPullRequest", err)
|
||||
@ -803,7 +554,7 @@ func CompareDiff(ctx *context.Context) {
|
||||
afterCommitID := ctx.Data["AfterCommitID"].(string)
|
||||
|
||||
separator := "..."
|
||||
if ci.DirectComparison {
|
||||
if ci.DirectComparison() {
|
||||
separator = ".."
|
||||
}
|
||||
ctx.Data["Title"] = "Comparing " + base.ShortSha(beforeCommitID) + separator + base.ShortSha(afterCommitID)
|
||||
|
@ -4,7 +4,6 @@
|
||||
package repo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
@ -93,8 +92,7 @@ func Milestones(ctx *context.Context) {
|
||||
ctx.Data["IsShowClosed"] = isShowClosed
|
||||
|
||||
pager := context.NewPagination(int(total), setting.UI.IssuePagingNum, page, 5)
|
||||
pager.AddParamString("state", fmt.Sprint(ctx.Data["State"]))
|
||||
pager.AddParamString("q", keyword)
|
||||
pager.AddParamFromRequest(ctx.Req)
|
||||
ctx.Data["Page"] = pager
|
||||
|
||||
ctx.HTML(http.StatusOK, tplMilestone)
|
||||
|
@ -70,8 +70,7 @@ func Packages(ctx *context.Context) {
|
||||
ctx.Data["RepositoryAccessMap"] = map[int64]bool{ctx.Repo.Repository.ID: true} // There is only the current repository
|
||||
|
||||
pager := context.NewPagination(int(total), setting.UI.PackagesPagingNum, page, 5)
|
||||
pager.AddParamString("q", query)
|
||||
pager.AddParamString("type", packageType)
|
||||
pager.AddParamFromRequest(ctx.Req)
|
||||
ctx.Data["Page"] = pager
|
||||
|
||||
ctx.HTML(http.StatusOK, tplPackagesList)
|
||||
|
@ -115,7 +115,7 @@ func Projects(ctx *context.Context) {
|
||||
}
|
||||
|
||||
pager := context.NewPagination(total, setting.UI.IssuePagingNum, page, numPages)
|
||||
pager.AddParamString("state", fmt.Sprint(ctx.Data["State"]))
|
||||
pager.AddParamFromRequest(ctx.Req)
|
||||
ctx.Data["Page"] = pager
|
||||
|
||||
ctx.Data["CanWriteProjects"] = ctx.Repo.Permission.CanWrite(unit.TypeProjects)
|
||||
|
@ -1262,8 +1262,8 @@ func CompareAndPullRequestPost(ctx *context.Context) {
|
||||
|
||||
ci := ParseCompareInfo(ctx)
|
||||
defer func() {
|
||||
if ci != nil && ci.HeadGitRepo != nil {
|
||||
ci.HeadGitRepo.Close()
|
||||
if ci != nil {
|
||||
ci.Close()
|
||||
}
|
||||
}()
|
||||
if ctx.Written() {
|
||||
@ -1311,8 +1311,8 @@ func CompareAndPullRequestPost(ctx *context.Context) {
|
||||
pullRequest := &issues_model.PullRequest{
|
||||
HeadRepoID: ci.HeadRepo.ID,
|
||||
BaseRepoID: repo.ID,
|
||||
HeadBranch: ci.HeadBranch,
|
||||
BaseBranch: ci.BaseBranch,
|
||||
HeadBranch: ci.HeadOriRef,
|
||||
BaseBranch: ci.BaseOriRef,
|
||||
HeadRepo: ci.HeadRepo,
|
||||
BaseRepo: repo,
|
||||
MergeBase: ci.CompareInfo.MergeBase,
|
||||
|
@ -186,7 +186,7 @@ func Releases(ctx *context.Context) {
|
||||
|
||||
numReleases := ctx.Data["NumReleases"].(int64)
|
||||
pager := context.NewPagination(int(numReleases), listOptions.PageSize, listOptions.Page, 5)
|
||||
pager.SetDefaultParams(ctx)
|
||||
pager.AddParamFromRequest(ctx.Req)
|
||||
ctx.Data["Page"] = pager
|
||||
ctx.HTML(http.StatusOK, tplReleasesList)
|
||||
}
|
||||
@ -240,7 +240,7 @@ func TagsList(ctx *context.Context) {
|
||||
ctx.Data["TagCount"] = count
|
||||
|
||||
pager := context.NewPagination(int(count), opts.PageSize, opts.Page, 5)
|
||||
pager.SetDefaultParams(ctx)
|
||||
pager.AddParamFromRequest(ctx.Req)
|
||||
ctx.Data["Page"] = pager
|
||||
ctx.Data["PageIsViewCode"] = !ctx.Repo.Repository.UnitEnabled(ctx, unit.TypeReleases)
|
||||
ctx.HTML(http.StatusOK, tplTagsList)
|
||||
|
@ -108,8 +108,7 @@ func Search(ctx *context.Context) {
|
||||
ctx.Data["SearchResultLanguages"] = searchResultLanguages
|
||||
|
||||
pager := context.NewPagination(total, setting.UI.RepoSearchPagingNum, page, 5)
|
||||
pager.SetDefaultParams(ctx)
|
||||
pager.AddParamString("l", language)
|
||||
pager.AddParamFromRequest(ctx.Req)
|
||||
ctx.Data["Page"] = pager
|
||||
|
||||
ctx.HTML(http.StatusOK, tplSearch)
|
||||
|
@ -440,8 +440,7 @@ func renderRevisionPage(ctx *context.Context) (*git.Repository, *git.TreeEntry)
|
||||
ctx.Data["Commits"] = git_model.ConvertFromGitCommit(ctx, commitsHistory, ctx.Repo.Repository)
|
||||
|
||||
pager := context.NewPagination(int(commitsCount), setting.Git.CommitsRangeSize, page, 5)
|
||||
pager.SetDefaultParams(ctx)
|
||||
pager.AddParamString("action", "_revision")
|
||||
pager.AddParamFromRequest(ctx.Req)
|
||||
ctx.Data["Page"] = pager
|
||||
|
||||
return wikiRepo, entry
|
||||
|
@ -121,8 +121,7 @@ func CodeSearch(ctx *context.Context) {
|
||||
ctx.Data["SearchResultLanguages"] = searchResultLanguages
|
||||
|
||||
pager := context.NewPagination(total, setting.UI.RepoSearchPagingNum, page, 5)
|
||||
pager.SetDefaultParams(ctx)
|
||||
pager.AddParamString("l", language)
|
||||
pager.AddParamFromRequest(ctx.Req)
|
||||
ctx.Data["Page"] = pager
|
||||
|
||||
ctx.HTML(http.StatusOK, tplUserCode)
|
||||
|
@ -139,7 +139,7 @@ func Dashboard(ctx *context.Context) {
|
||||
ctx.Data["Feeds"] = feeds
|
||||
|
||||
pager := context.NewPagination(int(count), setting.UI.FeedPagingNum, page, 5)
|
||||
pager.AddParamString("date", date)
|
||||
pager.AddParamFromRequest(ctx.Req)
|
||||
ctx.Data["Page"] = pager
|
||||
|
||||
ctx.HTML(http.StatusOK, tplDashboard)
|
||||
@ -330,10 +330,7 @@ func Milestones(ctx *context.Context) {
|
||||
ctx.Data["IsShowClosed"] = isShowClosed
|
||||
|
||||
pager := context.NewPagination(pagerCount, setting.UI.IssuePagingNum, page, 5)
|
||||
pager.AddParamString("q", keyword)
|
||||
pager.AddParamString("repos", reposQuery)
|
||||
pager.AddParamString("sort", sortType)
|
||||
pager.AddParamString("state", fmt.Sprint(ctx.Data["State"]))
|
||||
pager.AddParamFromRequest(ctx.Req)
|
||||
ctx.Data["Page"] = pager
|
||||
|
||||
ctx.HTML(http.StatusOK, tplMilestones)
|
||||
|
@ -173,7 +173,7 @@ func getNotifications(ctx *context.Context) {
|
||||
ctx.Data["Status"] = status
|
||||
ctx.Data["Notifications"] = notifications
|
||||
|
||||
pager.SetDefaultParams(ctx)
|
||||
pager.AddParamFromRequest(ctx.Req)
|
||||
ctx.Data["Page"] = pager
|
||||
}
|
||||
|
||||
@ -357,8 +357,7 @@ func NotificationSubscriptions(ctx *context.Context) {
|
||||
ctx.Redirect(fmt.Sprintf("/notifications/subscriptions?page=%d", pager.Paginater.Current()))
|
||||
return
|
||||
}
|
||||
pager.AddParamString("sort", sortType)
|
||||
pager.AddParamString("state", state)
|
||||
pager.AddParamFromRequest(ctx.Req)
|
||||
ctx.Data["Page"] = pager
|
||||
|
||||
ctx.HTML(http.StatusOK, tplNotificationSubscriptions)
|
||||
@ -446,22 +445,7 @@ func NotificationWatching(ctx *context.Context) {
|
||||
|
||||
// redirect to last page if request page is more than total pages
|
||||
pager := context.NewPagination(total, setting.UI.User.RepoPagingNum, page, 5)
|
||||
pager.SetDefaultParams(ctx)
|
||||
if archived.Has() {
|
||||
pager.AddParamString("archived", fmt.Sprint(archived.Value()))
|
||||
}
|
||||
if fork.Has() {
|
||||
pager.AddParamString("fork", fmt.Sprint(fork.Value()))
|
||||
}
|
||||
if mirror.Has() {
|
||||
pager.AddParamString("mirror", fmt.Sprint(mirror.Value()))
|
||||
}
|
||||
if template.Has() {
|
||||
pager.AddParamString("template", fmt.Sprint(template.Value()))
|
||||
}
|
||||
if private.Has() {
|
||||
pager.AddParamString("private", fmt.Sprint(private.Value()))
|
||||
}
|
||||
pager.AddParamFromRequest(ctx.Req)
|
||||
ctx.Data["Page"] = pager
|
||||
|
||||
ctx.Data["Status"] = 2
|
||||
|
@ -128,8 +128,7 @@ func ListPackages(ctx *context.Context) {
|
||||
}
|
||||
|
||||
pager := context.NewPagination(int(total), setting.UI.PackagesPagingNum, page, 5)
|
||||
pager.AddParamString("q", query)
|
||||
pager.AddParamString("type", packageType)
|
||||
pager.AddParamFromRequest(ctx.Req)
|
||||
ctx.Data["Page"] = pager
|
||||
|
||||
ctx.HTML(http.StatusOK, tplPackagesList)
|
||||
@ -348,11 +347,6 @@ func ListPackageVersions(ctx *context.Context) {
|
||||
ctx.Data["Query"] = query
|
||||
ctx.Data["Sort"] = sort
|
||||
|
||||
pagerParams := map[string]string{
|
||||
"q": query,
|
||||
"sort": sort,
|
||||
}
|
||||
|
||||
var (
|
||||
total int64
|
||||
pvs []*packages_model.PackageVersion
|
||||
@ -361,7 +355,6 @@ func ListPackageVersions(ctx *context.Context) {
|
||||
case packages_model.TypeContainer:
|
||||
tagged := ctx.FormTrim("tagged")
|
||||
|
||||
pagerParams["tagged"] = tagged
|
||||
ctx.Data["Tagged"] = tagged
|
||||
|
||||
pvs, total, err = container_model.SearchImageTags(ctx, &container_model.ImageTagsSearchOptions{
|
||||
@ -407,9 +400,7 @@ func ListPackageVersions(ctx *context.Context) {
|
||||
}
|
||||
|
||||
pager := context.NewPagination(int(total), setting.UI.PackagesPagingNum, page, 5)
|
||||
for k, v := range pagerParams {
|
||||
pager.AddParamString(k, v)
|
||||
}
|
||||
pager.AddParamFromRequest(ctx.Req)
|
||||
ctx.Data["Page"] = pager
|
||||
|
||||
ctx.HTML(http.StatusOK, tplPackageVersionList)
|
||||
|
@ -222,7 +222,7 @@ func Organization(ctx *context.Context) {
|
||||
|
||||
ctx.Data["Orgs"] = orgs
|
||||
pager := context.NewPagination(int(total), opts.PageSize, opts.Page, 5)
|
||||
pager.SetDefaultParams(ctx)
|
||||
pager.AddParamFromRequest(ctx.Req)
|
||||
ctx.Data["Page"] = pager
|
||||
ctx.HTML(http.StatusOK, tplSettingsOrganization)
|
||||
}
|
||||
@ -329,7 +329,7 @@ func Repos(ctx *context.Context) {
|
||||
}
|
||||
ctx.Data["ContextUser"] = ctxUser
|
||||
pager := context.NewPagination(count, opts.PageSize, opts.Page, 5)
|
||||
pager.SetDefaultParams(ctx)
|
||||
pager.AddParamFromRequest(ctx.Req)
|
||||
ctx.Data["Page"] = pager
|
||||
ctx.HTML(http.StatusOK, tplSettingsRepositories)
|
||||
}
|
||||
|
@ -27,19 +27,13 @@ func NewPagination(total, pagingNum, current, numPages int) *Pagination {
|
||||
return p
|
||||
}
|
||||
|
||||
// AddParamString adds a string parameter directly
|
||||
func (p *Pagination) AddParamString(key, value string) {
|
||||
urlParam := fmt.Sprintf("%s=%v", url.QueryEscape(key), url.QueryEscape(value))
|
||||
p.urlParams = append(p.urlParams, urlParam)
|
||||
}
|
||||
|
||||
func (p *Pagination) AddParamFromRequest(req *http.Request) {
|
||||
for key, values := range req.URL.Query() {
|
||||
if key == "page" || len(values) == 0 {
|
||||
if key == "page" || len(values) == 0 || (len(values) == 1 && values[0] == "") {
|
||||
continue
|
||||
}
|
||||
for _, value := range values {
|
||||
urlParam := fmt.Sprintf("%s=%v", key, url.QueryEscape(value))
|
||||
urlParam := fmt.Sprintf("%s=%v", url.QueryEscape(key), url.QueryEscape(value))
|
||||
p.urlParams = append(p.urlParams, urlParam)
|
||||
}
|
||||
}
|
||||
@ -49,17 +43,3 @@ func (p *Pagination) AddParamFromRequest(req *http.Request) {
|
||||
func (p *Pagination) GetParams() template.URL {
|
||||
return template.URL(strings.Join(p.urlParams, "&"))
|
||||
}
|
||||
|
||||
// SetDefaultParams sets common pagination params that are often used
|
||||
func (p *Pagination) SetDefaultParams(ctx *Context) {
|
||||
if v, ok := ctx.Data["SortType"].(string); ok {
|
||||
p.AddParamString("sort", v)
|
||||
}
|
||||
if v, ok := ctx.Data["Keyword"].(string); ok {
|
||||
p.AddParamString("q", v)
|
||||
}
|
||||
if v, ok := ctx.Data["IsFuzzy"].(bool); ok {
|
||||
p.AddParamString("fuzzy", fmt.Sprint(v))
|
||||
}
|
||||
// do not add any more uncommon params here!
|
||||
}
|
||||
|
@ -9,11 +9,15 @@ import (
|
||||
"code.gitea.io/gitea/models/db"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
webhook_model "code.gitea.io/gitea/models/webhook"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
webhook_module "code.gitea.io/gitea/modules/webhook"
|
||||
"code.gitea.io/gitea/services/convert"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestWebhook_GetSlackHook(t *testing.T) {
|
||||
@ -77,3 +81,11 @@ func TestPrepareWebhooksBranchFilterNoMatch(t *testing.T) {
|
||||
unittest.AssertNotExistsBean(t, hookTask)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWebhookUserMail(t *testing.T) {
|
||||
require.NoError(t, unittest.PrepareTestDatabase())
|
||||
setting.Service.NoReplyAddress = "no-reply.com"
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
|
||||
assert.Equal(t, user.GetPlaceholderEmail(), convert.ToUser(db.DefaultContext, user, nil).Email)
|
||||
assert.Equal(t, user.Email, convert.ToUser(db.DefaultContext, user, user).Email)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user