feat: update gitea vendor
runner nix smoke / nix label and flake smoke (push) Failing after 1m28s

This commit is contained in:
2026-09-26 21:18:24 +00:00
parent c439c1b948
commit d9b2a4e787
3538 changed files with 116131 additions and 44340 deletions
+168 -221
View File
@@ -15,34 +15,34 @@ import (
"strings"
"unicode"
"code.gitea.io/gitea/models/db"
git_model "code.gitea.io/gitea/models/git"
issues_model "code.gitea.io/gitea/models/issues"
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/base"
"code.gitea.io/gitea/modules/charset"
csv_module "code.gitea.io/gitea/modules/csv"
"code.gitea.io/gitea/modules/fileicon"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/git/gitcmd"
"code.gitea.io/gitea/modules/gitrepo"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/markup"
"code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/templates"
"code.gitea.io/gitea/modules/typesniffer"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/routers/common"
"code.gitea.io/gitea/services/context"
"code.gitea.io/gitea/services/context/upload"
git_service "code.gitea.io/gitea/services/git"
"code.gitea.io/gitea/services/gitdiff"
user_service "code.gitea.io/gitea/services/user"
"gitea.dev/models/db"
git_model "gitea.dev/models/git"
issues_model "gitea.dev/models/issues"
access_model "gitea.dev/models/perm/access"
repo_model "gitea.dev/models/repo"
"gitea.dev/models/unit"
user_model "gitea.dev/models/user"
"gitea.dev/modules/base"
"gitea.dev/modules/charset"
csv_module "gitea.dev/modules/csv"
"gitea.dev/modules/fileicon"
"gitea.dev/modules/git"
"gitea.dev/modules/git/gitcmd"
"gitea.dev/modules/gitrepo"
"gitea.dev/modules/log"
"gitea.dev/modules/markup"
"gitea.dev/modules/optional"
"gitea.dev/modules/setting"
api "gitea.dev/modules/structs"
"gitea.dev/modules/templates"
"gitea.dev/modules/typesniffer"
"gitea.dev/modules/util"
"gitea.dev/routers/common"
"gitea.dev/services/context"
"gitea.dev/services/context/upload"
git_service "gitea.dev/services/git"
"gitea.dev/services/gitdiff"
user_service "gitea.dev/services/user"
)
const (
@@ -190,57 +190,44 @@ func setCsvCompareContext(ctx *context.Context) {
}
}
// ParseCompareInfo parse compare info between two commit for preparing comparing references
func ParseCompareInfo(ctx *context.Context) *git_service.CompareInfo {
type comparePageInfoType struct {
compareInfo *git_service.CompareInfo
nothingToCompare bool
allowCreatePull bool
}
func newComparePageInfo() *comparePageInfoType {
return &comparePageInfoType{}
}
// parseCompareInfo parse compare info between two commit for preparing comparing references
func (cpi *comparePageInfoType) parseCompareInfo(ctx *context.Context, compareParam string) error {
baseRepo := ctx.Repo.Repository
fileOnly := ctx.FormBool("file-only")
// 1 Parse compare router param
compareReq := common.ParseCompareRouterParam(ctx.PathParam("*"))
// remove the check when we support compare with carets
if compareReq.BaseOriRefSuffix != "" {
ctx.HTTPError(http.StatusBadRequest, "Unsupported comparison syntax: ref with suffix")
return nil
}
compareReq := common.ParseCompareRouterParam(compareParam)
// 2 get repository and owner for head
headOwner, headRepo, err := common.GetHeadOwnerAndRepo(ctx, baseRepo, compareReq)
switch {
case errors.Is(err, util.ErrInvalidArgument):
ctx.HTTPError(http.StatusBadRequest, err.Error())
return nil
case errors.Is(err, util.ErrNotExist):
ctx.NotFound(nil)
return nil
case err != nil:
ctx.ServerError("GetHeadOwnerAndRepo", err)
return nil
if err != nil {
return err
}
isSameRepo := baseRepo.ID == headRepo.ID
// 3 permission check
// base repository's code unit read permission check has been done on web.go
permBase := ctx.Repo.Permission
// If we're not merging from the same repo:
isSameRepo := baseRepo.ID == headRepo.ID
if !isSameRepo {
// Assert ctx.Doer has permission to read headRepo's codes
permHead, err := access_model.GetDoerRepoPermission(ctx, headRepo, ctx.Doer)
if err != nil {
ctx.ServerError("GetDoerRepoPermission", err)
return nil
return err
}
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,
headRepo,
permHead)
}
ctx.NotFound(nil)
return nil
return util.NewNotExistErrorf("") // permission: no error message for end users
}
ctx.Data["CanWriteToHeadRepo"] = permHead.CanWrite(unit.TypeCode)
}
@@ -249,26 +236,18 @@ func ParseCompareInfo(ctx *context.Context) *git_service.CompareInfo {
baseRefName := util.IfZero(compareReq.BaseOriRef, baseRepo.GetPullRequestTargetBranch(ctx))
headRefName := util.IfZero(compareReq.HeadOriRef, headRepo.DefaultBranch)
baseRef := ctx.Repo.GitRepo.UnstableGuessRefByShortName(baseRefName)
if baseRef == "" {
ctx.NotFound(nil)
return nil
baseRef, err := common.ResolveRefWithSuffix(ctx.Repo.GitRepo, baseRefName, compareReq.BaseOriRefSuffix)
if err != nil {
return err
}
var headGitRepo *git.Repository
if isSameRepo {
headGitRepo = ctx.Repo.GitRepo
} else {
headGitRepo, err = gitrepo.OpenRepository(ctx, headRepo)
if err != nil {
ctx.ServerError("OpenRepository", err)
return nil
}
defer headGitRepo.Close()
headGitRepo, err := gitrepo.RepositoryFromRequestContextOrOpen(ctx, headRepo)
if err != nil {
return err
}
headRef := headGitRepo.UnstableGuessRefByShortName(headRefName)
if headRef == "" {
ctx.NotFound(nil)
return nil
headRef, err := common.ResolveRefWithSuffix(headGitRepo, headRefName, compareReq.HeadOriRefSuffix)
if err != nil {
return err
}
ctx.Data["BaseName"] = baseRepo.OwnerName
@@ -292,12 +271,9 @@ func ParseCompareInfo(ctx *context.Context) *git_service.CompareInfo {
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 {
if err != nil && !repo_model.IsErrRepoNotExist(err) {
return err
} else if err == nil {
rootRepo = baseRepo.BaseRepo
}
}
@@ -314,42 +290,10 @@ func ParseCompareInfo(ctx *context.Context) *git_service.CompareInfo {
}
}
has := 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 == headOwner.ID {
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 == headOwner.ID {
headRepo = ownForkRepo
has = true
}
// 5. If the headOwner has a fork of the baseRepo - use that
if !has {
headRepo = repo_model.GetForkedRepo(ctx, headOwner.ID, baseRepo.ID)
has = headRepo != nil
}
// 6. If the baseRepo is a fork and the headUser has a fork of that use that
if !has && baseRepo.IsFork {
headRepo = repo_model.GetForkedRepo(ctx, headOwner.ID, baseRepo.ForkID)
has = 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
}
ctx.Data["HeadRepo"] = headRepo
ctx.Data["BaseCompareRepo"] = ctx.Repo.Repository
// If we have a rootRepo and it's different from:
// If we have a rootRepo, and it's different from:
// 1. the computed base
// 2. the computed head
// then get the branches of it
@@ -362,17 +306,15 @@ func ParseCompareInfo(ctx *context.Context) *git_service.CompareInfo {
if !fileOnly {
branches, tags, err := getBranchesAndTagsForRepo(ctx, rootRepo)
if err != nil {
ctx.ServerError("GetBranchesForRepo", err)
return nil
return err
}
ctx.Data["RootRepoBranches"] = branches
ctx.Data["RootRepoTags"] = tags
}
}
}
// If we have a ownForkRepo and it's different from:
// 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)
@@ -387,8 +329,7 @@ func ParseCompareInfo(ctx *context.Context) *git_service.CompareInfo {
if !fileOnly {
branches, tags, err := getBranchesAndTagsForRepo(ctx, ownForkRepo)
if err != nil {
ctx.ServerError("GetBranchesForRepo", err)
return nil
return err
}
ctx.Data["OwnForkRepoBranches"] = branches
ctx.Data["OwnForkRepoTags"] = tags
@@ -396,38 +337,16 @@ func ParseCompareInfo(ctx *context.Context) *git_service.CompareInfo {
}
}
// Treat as pull request if both references are branches
if ctx.Data["PageIsComparePull"] == nil {
ctx.Data["PageIsComparePull"] = baseRef.IsBranch() && headRef.IsBranch() && permBase.CanReadIssuesOrPulls(true)
}
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(nil)
return nil
}
compareInfo, err := git_service.GetCompareInfo(ctx, baseRepo, headRepo, headGitRepo, baseRef, headRef, compareReq.DirectComparison(), fileOnly)
if err != nil {
if errors.Is(err, util.ErrNotExist) {
ctx.Data["IsNoMergeBase"] = true
return compareInfo
}
ctx.ServerError("GetCompareInfo", err)
return nil
}
if compareReq.DirectComparison() {
ctx.Data["BeforeCommitID"] = compareInfo.BaseCommitID
} else {
ctx.Data["BeforeCommitID"] = compareInfo.MergeBase
return err
}
return compareInfo
// Treat as pull request if both references are branches
cpi.allowCreatePull = baseRef.IsBranch() && headRef.IsBranch() && permBase.CanReadIssuesOrPulls(true)
cpi.allowCreatePull = cpi.allowCreatePull && compareInfo.CompareBase != ""
cpi.compareInfo = &compareInfo
return nil
}
// autoTitleFromBranchName humanizes a branch name into a PR title.
@@ -467,16 +386,14 @@ func prepareNewPullRequestTitleContent(ci *git_service.CompareInfo, commits []*g
if useFirstCommitAsTitle {
// the "commits" are from "ShowPrettyFormatLogToList", which is ordered from newest to oldest, here take the oldest one
c := commits[len(commits)-1]
title = strings.TrimSpace(c.UserCommit.Summary())
title = c.UserCommit.GitCommit.MessageTitle()
} else {
title = autoTitleFromBranchName(ci.HeadRef.ShortName())
}
if len(commits) == 1 {
c := commits[0]
_, content, _ = strings.Cut(strings.TrimSpace(c.UserCommit.CommitMessage), "\n")
content = strings.TrimSpace(content)
content = string(charset.ToUTF8([]byte(content), charset.ConvertOpts{}))
content = c.GitCommit.MessageBody()
}
var titleTrailer string
@@ -492,16 +409,18 @@ func prepareNewPullRequestTitleContent(ci *git_service.CompareInfo, commits []*g
return title, content
}
// PrepareCompareDiff renders compare diff page
func PrepareCompareDiff(
ctx *context.Context,
ci *git_service.CompareInfo,
whitespaceBehavior gitcmd.TrustedCmdArgs,
) (nothingToCompare bool) {
// prepareCompareDiff renders compare diff page. TODO: need to refactor it and other "compare diff" related functions together
func (cpi *comparePageInfoType) prepareCompareDiff(ctx *context.Context, whitespaceBehavior gitcmd.TrustedCmdArgs) {
ci := cpi.compareInfo
if ci.CompareBase == "" {
cpi.nothingToCompare = true
return
}
repo := ctx.Repo.Repository
headCommitID := ci.HeadCommitID
ctx.Data["CommitRepoLink"] = ci.HeadRepo.Link()
ctx.Data["BeforeCommitID"] = ci.CompareBase
ctx.Data["AfterCommitID"] = headCommitID
// follow GitHub's behavior: autofill the form and expand
@@ -511,26 +430,18 @@ func PrepareCompareDiff(
ctx.Data["TitleQuery"] = newPrFormTitle
ctx.Data["BodyQuery"] = newPrFormBody
if (headCommitID == ci.MergeBase && !ci.DirectComparison()) ||
headCommitID == ci.BaseCommitID {
ctx.Data["IsNothingToCompare"] = true
if unit, err := repo.GetUnit(ctx, unit.TypePullRequests); err == nil {
config := unit.PullRequestsConfig()
if headCommitID == ci.CompareBase {
config := repo.MustGetUnit(ctx, unit.TypePullRequests).PullRequestsConfig()
// if auto-detect manual merge, an empty PR will be closed immediately because it is already on base branch
supportEmptyPr := !config.AutodetectManualMerge
acrossRepoPr := !ci.IsSameRef()
ctx.Data["AllowEmptyPr"] = supportEmptyPr && acrossRepoPr
if !config.AutodetectManualMerge {
ctx.Data["AllowEmptyPr"] = !ci.IsSameRef()
return ci.IsSameRef()
}
ctx.Data["AllowEmptyPr"] = false
}
return true
cpi.nothingToCompare = true
return
}
beforeCommitID := ci.MergeBase
if ci.DirectComparison() {
beforeCommitID = ci.BaseCommitID
}
beforeCommitID := ci.CompareBase
maxLines, maxFiles := setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffFiles
files := ctx.FormStrings("files")
@@ -553,12 +464,12 @@ func PrepareCompareDiff(
}, ctx.FormStrings("files")...)
if err != nil {
ctx.ServerError("GetDiff", err)
return false
return
}
diffShortStat, err := gitdiff.GetDiffShortStat(ctx, ci.HeadRepo, ci.HeadGitRepo, beforeCommitID, headCommitID)
if err != nil {
ctx.ServerError("GetDiffShortStat", err)
return false
return
}
ctx.Data["DiffShortStat"] = diffShortStat
ctx.Data["Diff"] = diff
@@ -573,7 +484,7 @@ func PrepareCompareDiff(
diffTree, err := gitdiff.GetDiffTree(ctx, ci.HeadGitRepo, false, beforeCommitID, headCommitID)
if err != nil {
ctx.ServerError("GetDiffTree", err)
return false
return
}
renderedIconPool := fileicon.NewRenderedIconPool()
@@ -586,7 +497,7 @@ func PrepareCompareDiff(
headCommit, err := ci.HeadGitRepo.GetCommit(headCommitID)
if err != nil {
ctx.ServerError("GetCommit", err)
return false
return
}
baseGitRepo := ctx.Repo.GitRepo
@@ -594,24 +505,20 @@ func PrepareCompareDiff(
beforeCommit, err := baseGitRepo.GetCommit(beforeCommitID)
if err != nil {
ctx.ServerError("GetCommit", err)
return false
return
}
commits, err := processGitCommits(ctx, ci.Commits)
if err != nil {
ctx.ServerError("processGitCommits", err)
return false
return
}
ctx.Data["Commits"] = commits
ctx.Data["CommitCount"] = len(commits)
ctx.Data["title"], ctx.Data["content"] = prepareNewPullRequestTitleContent(ci, commits, setting.Repository.PullRequest.DefaultTitleSource)
ctx.Data["Username"] = ci.HeadRepo.OwnerName
ctx.Data["Reponame"] = ci.HeadRepo.Name
setCompareContext(ctx, beforeCommit, headCommit, ci.HeadRepo.OwnerName, repo.Name)
return false
}
func getBranchesAndTagsForRepo(ctx gocontext.Context, repo *repo_model.Repository) (branches, tags []string, err error) {
@@ -632,27 +539,24 @@ func getBranchesAndTagsForRepo(ctx gocontext.Context, repo *repo_model.Repositor
// CompareDiff show different from one commit to another commit
func CompareDiff(ctx *context.Context) {
ci := ParseCompareInfo(ctx)
if ctx.Written() {
comparePageInfo := newComparePageInfo()
err := comparePageInfo.parseCompareInfo(ctx, ctx.PathParam("*"))
if errors.Is(err, util.ErrNotExist) || errors.Is(err, util.ErrInvalidArgument) {
ctx.NotFound(nil)
return
} else if err != nil {
ctx.ServerError("ParseCompareInfo", err)
return
}
ci := comparePageInfo.compareInfo
ctx.Data["PageIsViewCode"] = true
ctx.Data["PullRequestWorkInProgressPrefixes"] = setting.Repository.PullRequest.WorkInProgressPrefixes
ctx.Data["CompareInfo"] = ci
var nothingToCompare bool
noMergeBase := ctx.Data["IsNoMergeBase"] == true
if noMergeBase {
ctx.Flash.Error(ctx.Tr("repo.pulls.no_common_history"), true)
ctx.Data["PageIsComparePull"] = false
ctx.Data["CommitCount"] = 0
nothingToCompare = true
} else {
nothingToCompare = PrepareCompareDiff(ctx, ci, gitdiff.GetWhitespaceFlag(ctx.Data["WhitespaceBehavior"].(string)))
if ctx.Written() {
return
}
// TODO: need to refactor "prepare compare" related functions together
comparePageInfo.prepareCompareDiff(ctx, gitdiff.GetWhitespaceFlag(GetWhitespaceBehavior(ctx)))
if ctx.Written() {
return
}
baseTags, err := repo_model.GetTagNamesByRepoID(ctx, ctx.Repo.Repository.ID)
@@ -682,12 +586,62 @@ func CompareDiff(ctx *context.Context) {
return
}
if noMergeBase {
ctx.HTML(http.StatusOK, tplCompare)
if ci.CompareBase != "" {
comparePageInfo.prepareCreatePullRequestPage(ctx)
if ctx.Written() {
return
}
} else {
ctx.Flash.Error(ctx.Tr("repo.pulls.no_common_history"), true)
ctx.Data["CommitCount"] = 0
}
ctx.Data["PageIsComparePull"] = comparePageInfo.allowCreatePull
ctx.Data["IsNothingToCompare"] = comparePageInfo.nothingToCompare
ctx.HTML(http.StatusOK, tplCompare)
}
// DownloadCompareDiff render a comparison's raw unified diff
func DownloadCompareDiff(ctx *context.Context) {
downloadCompareDiffOrPatch(ctx, false)
}
// DownloadComparePatch render a comparison as a git format-patch
func DownloadComparePatch(ctx *context.Context) {
downloadCompareDiffOrPatch(ctx, true)
}
func downloadCompareDiffOrPatch(ctx *context.Context, patch bool) {
// The route captures `basehead` separately so the `.diff`/`.patch` suffix is
// stripped from the catch-all `*` param parseCompareInfo would otherwise read.
cpi := newComparePageInfo()
if err := cpi.parseCompareInfo(ctx, ctx.PathParam("basehead")); err != nil {
if errors.Is(err, util.ErrNotExist) || errors.Is(err, util.ErrInvalidArgument) {
ctx.NotFound(nil)
} else {
ctx.ServerError("ParseCompareInfo", err)
}
return
}
ci := cpi.compareInfo
if ctx.Data["PageIsComparePull"] == true {
ctx.Resp.Header().Set("Content-Type", "text/plain; charset=utf-8")
compareArg := ci.BaseCommitID + ci.CompareSeparator + ci.HeadCommitID
var err error
if patch {
err = ci.HeadGitRepo.GetPatch(compareArg, ctx.Resp)
} else {
err = ci.HeadGitRepo.GetDiff(compareArg, ctx.Resp)
}
if err != nil {
ctx.ServerError("DownloadCompareDiffOrPatch", err)
return
}
}
func (cpi *comparePageInfoType) prepareCreatePullRequestPage(ctx *context.Context) {
ci := cpi.compareInfo
if cpi.allowCreatePull {
pr, err := issues_model.GetUnmergedPullRequest(ctx, ci.HeadRepo.ID, ctx.Repo.Repository.ID, ci.HeadRef.ShortName(), ci.BaseRef.ShortName(), issues_model.PullRequestFlowGithub)
if err != nil {
if !issues_model.IsErrPullRequestNotExist(err) {
@@ -701,11 +655,10 @@ func CompareDiff(ctx *context.Context) {
return
}
ctx.Data["PullRequest"] = pr
ctx.HTML(http.StatusOK, tplCompareDiff)
return
}
if !nothingToCompare {
if !cpi.nothingToCompare {
// Setup information for new form.
pageMetaData := retrieveRepoIssueMetaData(ctx, ctx.Repo.Repository, nil, true)
if ctx.Written() {
@@ -717,8 +670,8 @@ func CompareDiff(ctx *context.Context) {
}
}
}
beforeCommitID := ctx.Data["BeforeCommitID"].(string)
afterCommitID := ctx.Data["AfterCommitID"].(string)
beforeCommitID := cpi.compareInfo.CompareBase
afterCommitID := cpi.compareInfo.HeadCommitID
ctx.Data["Title"] = "Comparing " + base.ShortSha(beforeCommitID) + ci.CompareSeparator + base.ShortSha(afterCommitID)
@@ -727,7 +680,7 @@ func CompareDiff(ctx *context.Context) {
if content, ok := ctx.Data["content"].(string); ok && content != "" {
// If a template content is set, prepend the "content". In this case that's only
// applicable if you have one commit to compare and that commit has a message.
// In that case the commit message will be prepend to the template body.
// In that case the commit message will be prepended to the template body.
if templateContent, ok := ctx.Data[pullRequestTemplateKey].(string); ok && templateContent != "" {
// Re-use the same key as that's prioritized over the "content" key.
// Add two new lines between the content to ensure there's always at least
@@ -749,20 +702,14 @@ func CompareDiff(ctx *context.Context) {
}
}
ctx.Data["IsProjectsEnabled"] = ctx.Repo.CanWrite(unit.TypeProjects)
ctx.Data["IsProjectsEnabled"] = ctx.Repo.Permission.CanWrite(unit.TypeProjects)
ctx.Data["IsAttachmentEnabled"] = setting.Attachment.Enabled
upload.AddUploadContext(ctx, "comment")
ctx.Data["HasIssuesOrPullsWritePermission"] = ctx.Repo.CanWrite(unit.TypePullRequests)
ctx.Data["HasIssuesOrPullsWritePermission"] = ctx.Repo.Permission.CanWrite(unit.TypePullRequests)
if unit, err := ctx.Repo.Repository.GetUnit(ctx, unit.TypePullRequests); err == nil {
config := unit.PullRequestsConfig()
ctx.Data["AllowMaintainerEdit"] = config.DefaultAllowMaintainerEdit
} else {
ctx.Data["AllowMaintainerEdit"] = false
}
ctx.HTML(http.StatusOK, tplCompare)
prConfig := ctx.Repo.Repository.MustGetUnit(ctx, unit.TypePullRequests).PullRequestsConfig()
ctx.Data["AllowMaintainerEdit"] = prConfig.DefaultAllowMaintainerEdit
}
// attachCommentsToLines attaches comments to their corresponding diff lines
@@ -844,7 +791,7 @@ func ExcerptBlob(ctx *context.Context) {
diffBlobExcerptData.PullIssueIndex = ctx.FormInt64("pull_issue_index")
if diffBlobExcerptData.PullIssueIndex > 0 {
if !ctx.Repo.CanRead(unit.TypePullRequests) {
if !ctx.Repo.Permission.CanRead(unit.TypePullRequests) {
ctx.NotFound(nil)
return
}