diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index ed274197c7bb9..09b473baa71ba 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1205,6 +1205,7 @@ branch = Branch tree = Tree clear_ref = `Clear current reference` filter_branch_and_tag = Filter branch or tag +filter_repo = Search repository find_tag = Find tag branches = Branches tags = Tags @@ -1749,6 +1750,9 @@ issues.reference_link = Reference: %s compare.compare_base = base compare.compare_head = compare +compare.titile = Comparing %s +compare.refs_not_exist = Head or base ref is not exist. +compare.head_info_not_exist = Head user or repository is not exist. pulls.desc = Enable pull requests and code reviews. pulls.new = New Pull Request diff --git a/routers/common/compare.go b/routers/common/compare.go index 4d1cc2f0d8908..2eebf154e8e7b 100644 --- a/routers/common/compare.go +++ b/routers/common/compare.go @@ -18,4 +18,8 @@ type CompareInfo struct { BaseBranch string HeadBranch string DirectComparison bool + RefsNotExist bool + HeadInfoNotExist bool + HeadRef string + BaseRef string } diff --git a/routers/web/repo/compare.go b/routers/web/repo/compare.go index 035a92f22830c..3ae6828a6b32b 100644 --- a/routers/web/repo/compare.go +++ b/routers/web/repo/compare.go @@ -5,7 +5,6 @@ package repo import ( "bufio" - gocontext "context" "encoding/csv" "errors" "fmt" @@ -241,6 +240,9 @@ func ParseCompareInfo(ctx *context.Context) *common.CompareInfo { } } + ci.HeadRef = infos[1] + ci.BaseRef = infos[0] + ctx.Data["BaseName"] = baseRepo.OwnerName ci.BaseBranch = infos[0] ctx.Data["BaseBranch"] = ci.BaseBranch @@ -251,44 +253,56 @@ func ParseCompareInfo(ctx *context.Context) *common.CompareInfo { isSameRepo = true ci.HeadUser = ctx.Repo.Owner ci.HeadBranch = headInfos[0] + ctx.Data["HeadUserName"] = ctx.Repo.Owner.Name } else if len(headInfos) == 2 { headInfosSplit := strings.Split(headInfos[0], "/") if len(headInfosSplit) == 1 { + ctx.Data["HeadUserName"] = headInfos[0] + ctx.Data["HeadRepoName"] = "" + ci.HeadBranch = headInfos[1] + ci.HeadUser, err = user_model.GetUserByName(ctx, headInfos[0]) if err != nil { if user_model.IsErrUserNotExist(err) { - ctx.NotFound("GetUserByName", nil) + ci.HeadInfoNotExist = true + ci.RefsNotExist = true } else { ctx.ServerError("GetUserByName", err) + return nil + } + } else { + ci.HeadBranch = headInfos[1] + isSameRepo = ci.HeadUser.ID == ctx.Repo.Owner.ID + if isSameRepo { + ci.HeadRepo = baseRepo } - return nil - } - ci.HeadBranch = headInfos[1] - isSameRepo = ci.HeadUser.ID == ctx.Repo.Owner.ID - if isSameRepo { - ci.HeadRepo = baseRepo } } else { + ctx.Data["HeadUserName"] = headInfosSplit[0] + ctx.Data["HeadRepoName"] = headInfosSplit[1] + ci.HeadBranch = headInfos[1] + ci.HeadRepo, err = repo_model.GetRepositoryByOwnerAndName(ctx, headInfosSplit[0], headInfosSplit[1]) if err != nil { if repo_model.IsErrRepoNotExist(err) { - ctx.NotFound("GetRepositoryByOwnerAndName", nil) + ci.HeadInfoNotExist = true + ci.RefsNotExist = true } else { ctx.ServerError("GetRepositoryByOwnerAndName", err) + return nil } - return nil - } - if err := ci.HeadRepo.LoadOwner(ctx); err != nil { - if user_model.IsErrUserNotExist(err) { - ctx.NotFound("GetUserByName", nil) - } else { - ctx.ServerError("GetUserByName", err) + } else { + if err := ci.HeadRepo.LoadOwner(ctx); err != nil { + if user_model.IsErrUserNotExist(err) { + ctx.NotFound("GetUserByName", nil) + } else { + ctx.ServerError("GetUserByName", err) + } + return nil } - return nil + ci.HeadUser = ci.HeadRepo.Owner + isSameRepo = ci.HeadRepo.ID == ctx.Repo.Repository.ID } - ci.HeadBranch = headInfos[1] - ci.HeadUser = ci.HeadRepo.Owner - isSameRepo = ci.HeadRepo.ID == ctx.Repo.Repository.ID } } else { ctx.NotFound("CompareAndPullRequest", nil) @@ -317,8 +331,7 @@ func ParseCompareInfo(ctx *context.Context) *common.CompareInfo { } return nil } else { - ctx.NotFound("IsRefExist", nil) - return nil + ci.RefsNotExist = true } } ctx.Data["BaseIsCommit"] = baseIsCommit @@ -363,6 +376,65 @@ func ParseCompareInfo(ctx *context.Context) *common.CompareInfo { } } + loadForkReps := func() *common.CompareInfo { + // list all fork repos + var ( + forks []*repo_model.Repository + err error + ) + + if rootRepo == nil { + forks, err = repo_model.GetForks(ctx, baseRepo, db.ListOptions{ + Page: 0, + PageSize: 20, + }) + } else { + forks, err = repo_model.GetForks(ctx, rootRepo, db.ListOptions{ + Page: 0, + PageSize: 20, + }) + } + + if err != nil { + ctx.ServerError("GetForks", err) + return nil + } + + forkmap := make(map[int64]*repo_model.Repository) + for _, fork := range forks { + forkmap[fork.ID] = fork + } + + if _, ok := forkmap[baseRepo.ID]; !ok { + forkmap[baseRepo.ID] = baseRepo + } + + if rootRepo != nil { + if _, ok := forkmap[rootRepo.ID]; !ok { + forkmap[rootRepo.ID] = rootRepo + } + } + + if ownForkRepo != nil { + if _, ok := forkmap[ownForkRepo.ID]; !ok { + forkmap[ownForkRepo.ID] = ownForkRepo + } + } + + forks = make([]*repo_model.Repository, 0, len(forkmap)) + for _, fork := range forkmap { + forks = append(forks, fork) + } + + ctx.Data["CompareRepos"] = forks + + return ci + } + + if ci.HeadInfoNotExist { + return loadForkReps() + } + 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 @@ -413,6 +485,11 @@ func ParseCompareInfo(ctx *context.Context) *common.CompareInfo { ctx.Data["HeadRepo"] = ci.HeadRepo ctx.Data["BaseCompareRepo"] = ctx.Repo.Repository + ctx.Data["HeadRepoName"] = ci.HeadRepo.Name + + if loadForkReps() == nil { + return nil + } // Now we need to assert that the ctx.Doer has permission to read // the baseRepo's code and pulls @@ -448,57 +525,15 @@ func ParseCompareInfo(ctx *context.Context) *common.CompareInfo { ci.HeadRepo, permHead) } - ctx.NotFound("ParseCompareInfo", nil) - return nil + ci.HeadInfoNotExist = true + ci.RefsNotExist = true + return ci } 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["RootRepoBranches"] = branches - ctx.Data["RootRepoTags"] = tags - } - } - } - - // 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 - } - } + if ci.RefsNotExist { + return ci } // Check if head branch is valid. @@ -512,10 +547,11 @@ func ParseCompareInfo(ctx *context.Context) *common.CompareInfo { ctx.Data["HeadBranch"] = ci.HeadBranch headIsCommit = true } else { - ctx.NotFound("IsRefExist", nil) - return nil + ci.RefsNotExist = true + return ci } } + ctx.Data["HeadIsCommit"] = headIsCommit ctx.Data["HeadIsBranch"] = headIsBranch ctx.Data["HeadIsTag"] = headIsTag @@ -679,26 +715,32 @@ 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{ - RepoID: repo.ID, - ListOptions: db.ListOptionsAll, +func prepareHeadBranchAndTags(ctx *context.Context, headRepoID int64) { + headBranches, err := git_model.FindBranchNames(ctx, git_model.FindBranchOptions{ + RepoID: headRepoID, + ListOptions: db.ListOptions{ + ListAll: true, + }, IsDeletedBranch: optional.Some(false), }) if err != nil { - return nil, nil, err + ctx.ServerError("GetBranches", err) + return + } + ctx.Data["HeadBranches"] = headBranches + + // For compare repo branches + PrepareBranchList(ctx) + if ctx.Written() { + return } - tags, err = gitRepo.GetTags(0, 0) + + headTags, err := repo_model.GetTagNamesByRepoID(ctx, headRepoID) if err != nil { - return nil, nil, err + ctx.ServerError("GetTagNamesByRepoID", err) + return } - return branches, tags, nil + ctx.Data["HeadTags"] = headTags } // CompareDiff show different from one commit to another commit @@ -721,13 +763,19 @@ func CompareDiff(ctx *context.Context) { ctx.Data["CompareSeparator"] = ".." ctx.Data["OtherCompareSeparator"] = "..." } + ctx.Data["CompareRefsNotFound"] = ci.RefsNotExist + ctx.Data["HeadInfoNotExist"] = ci.HeadInfoNotExist - nothingToCompare := PrepareCompareDiff(ctx, ci, - gitdiff.GetWhitespaceFlag(ctx.Data["WhitespaceBehavior"].(string))) - if ctx.Written() { - return + var nothingToCompare bool + if ci.RefsNotExist { + nothingToCompare = true + } else { + nothingToCompare = PrepareCompareDiff(ctx, ci, + gitdiff.GetWhitespaceFlag(ctx.Data["WhitespaceBehavior"].(string))) + if ctx.Written() { + return + } } - baseTags, err := repo_model.GetTagNamesByRepoID(ctx, ctx.Repo.Repository.ID) if err != nil { ctx.ServerError("GetTagNamesByRepoID", err) @@ -741,29 +789,12 @@ func CompareDiff(ctx *context.Context) { 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) - if ctx.Written() { - return - } - - headTags, err := repo_model.GetTagNamesByRepoID(ctx, ci.HeadRepo.ID) - if err != nil { - ctx.ServerError("GetTagNamesByRepoID", err) - return + if !ci.HeadInfoNotExist { + prepareHeadBranchAndTags(ctx, ci.HeadRepo.ID) + if ctx.Written() { + 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) @@ -791,14 +822,12 @@ func CompareDiff(ctx *context.Context) { } } } - beforeCommitID := ctx.Data["BeforeCommitID"].(string) - afterCommitID := ctx.Data["AfterCommitID"].(string) separator := "..." if ci.DirectComparison { separator = ".." } - ctx.Data["Title"] = "Comparing " + base.ShortSha(beforeCommitID) + separator + base.ShortSha(afterCommitID) + ctx.Data["Title"] = ctx.Tr("repo.compare.titile", ci.BaseRef+separator+ci.HeadRef) ctx.Data["IsRepoToolbarCommits"] = true ctx.Data["IsDiffCompare"] = true diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index a0a8e5410cf15..e9c8755ddfccf 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -1248,6 +1248,10 @@ func CompareAndPullRequestPost(ctx *context.Context) { if ctx.Written() { return } + if ci.RefsNotExist { + ctx.NotFound("RefsNotExist", nil) + return + } labelIDs, assigneeIDs, milestoneID, projectID := ValidateRepoMetas(ctx, *form, true) if ctx.Written() { diff --git a/templates/repo/diff/compare.tmpl b/templates/repo/diff/compare.tmpl index f92750119719a..485edee2da392 100644 --- a/templates/repo/diff/compare.tmpl +++ b/templates/repo/diff/compare.tmpl @@ -11,27 +11,30 @@ {{ctx.Locale.Tr "action.compare_commits_general"}} {{end}} - {{$BaseCompareName := $.BaseName -}} - {{- $HeadCompareName := $.HeadRepo.OwnerName -}} - {{- if and (eq $.BaseName $.HeadRepo.OwnerName) (ne $.Repository.Name $.HeadRepo.Name) -}} - {{- $HeadCompareName = printf "%s/%s" $.HeadRepo.OwnerName $.HeadRepo.Name -}} - {{- end -}} - {{- $OwnForkCompareName := "" -}} - {{- if .OwnForkRepo -}} - {{- $OwnForkCompareName = .OwnForkRepo.OwnerName -}} - {{- end -}} - {{- $RootRepoCompareName := "" -}} - {{- if .RootRepo -}} - {{- $RootRepoCompareName = .RootRepo.OwnerName -}} - {{- if eq $.HeadRepo.OwnerName .RootRepo.OwnerName -}} - {{- $HeadCompareName = printf "%s/%s" $.HeadRepo.OwnerName $.HeadRepo.Name -}} - {{- end -}} - {{- end -}}