mirror of
https://github.com/go-gitea/gitea.git
synced 2026-09-23 23:54:50 +02:00
Merge branch 'main' into kerwin612-add-file-tree-to-file-view-page
This commit is contained in:
@@ -3,27 +3,7 @@
|
||||
|
||||
package context
|
||||
|
||||
import (
|
||||
"code.gitea.io/gitea/models/unit"
|
||||
)
|
||||
|
||||
// IsUserSiteAdmin returns true if current user is a site admin
|
||||
func (ctx *Context) IsUserSiteAdmin() bool {
|
||||
return ctx.IsSigned && ctx.Doer.IsAdmin
|
||||
}
|
||||
|
||||
// IsUserRepoAdmin returns true if current user is admin in current repo
|
||||
func (ctx *Context) IsUserRepoAdmin() bool {
|
||||
return ctx.Repo.IsAdmin()
|
||||
}
|
||||
|
||||
// IsUserRepoWriter returns true if current user has write privilege in current repo
|
||||
func (ctx *Context) IsUserRepoWriter(unitTypes []unit.Type) bool {
|
||||
for _, unitType := range unitTypes {
|
||||
if ctx.Repo.CanWrite(unitType) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
+94
-121
@@ -21,7 +21,6 @@ import (
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
unit_model "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/cache"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/gitrepo"
|
||||
@@ -47,22 +46,27 @@ type PullRequest struct {
|
||||
// Repository contains information to operate a repository
|
||||
type Repository struct {
|
||||
access_model.Permission
|
||||
IsWatching bool
|
||||
|
||||
Repository *repo_model.Repository
|
||||
Owner *user_model.User
|
||||
|
||||
RepoLink string
|
||||
GitRepo *git.Repository
|
||||
|
||||
// these fields indicate the current ref type, for example: ".../src/branch/master" means IsViewBranch=true
|
||||
IsViewBranch bool
|
||||
IsViewTag bool
|
||||
IsViewCommit bool
|
||||
Repository *repo_model.Repository
|
||||
Owner *user_model.User
|
||||
Commit *git.Commit
|
||||
Tag *git.Tag
|
||||
GitRepo *git.Repository
|
||||
RefName string
|
||||
BranchName string
|
||||
TagName string
|
||||
TreePath string
|
||||
CommitID string
|
||||
RepoLink string
|
||||
CloneLink repo_model.CloneLink
|
||||
|
||||
RefFullName git.RefName
|
||||
BranchName string
|
||||
TagName string
|
||||
TreePath string
|
||||
|
||||
// Commit it is always set to the commit for the branch or tag
|
||||
Commit *git.Commit
|
||||
CommitID string
|
||||
|
||||
CommitsCount int64
|
||||
|
||||
PullRequest *PullRequest
|
||||
@@ -150,7 +154,7 @@ func (r *Repository) CanCommitToBranch(ctx context.Context, doer *user_model.Use
|
||||
}, err
|
||||
}
|
||||
|
||||
// CanUseTimetracker returns whether or not a user can use the timetracker.
|
||||
// CanUseTimetracker returns whether a user can use the timetracker.
|
||||
func (r *Repository) CanUseTimetracker(ctx context.Context, issue *issues_model.Issue, user *user_model.User) bool {
|
||||
// Checking for following:
|
||||
// 1. Is timetracker enabled
|
||||
@@ -200,8 +204,12 @@ func (r *Repository) GetCommitGraphsCount(ctx context.Context, hidePRRefs bool,
|
||||
})
|
||||
}
|
||||
|
||||
// BranchNameSubURL sub-URL for the BranchName field
|
||||
func (r *Repository) BranchNameSubURL() string {
|
||||
// RefTypeNameSubURL makes a sub-url for the current ref (branch/tag/commit) field, for example:
|
||||
// * "branch/master"
|
||||
// * "tag/v1.0.0"
|
||||
// * "commit/123456"
|
||||
// It is usually used to construct a link like ".../src/{{RefTypeNameSubURL}}/{{PathEscapeSegments TreePath}}"
|
||||
func (r *Repository) RefTypeNameSubURL() string {
|
||||
switch {
|
||||
case r.IsViewBranch:
|
||||
return "branch/" + util.PathEscapeSegments(r.BranchName)
|
||||
@@ -214,21 +222,6 @@ func (r *Repository) BranchNameSubURL() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// FileExists returns true if a file exists in the given repo branch
|
||||
func (r *Repository) FileExists(path, branch string) (bool, error) {
|
||||
if branch == "" {
|
||||
branch = r.Repository.DefaultBranch
|
||||
}
|
||||
commit, err := r.GitRepo.GetBranchCommit(branch)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if _, err := commit.GetTreeEntryByPath(path); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// GetEditorconfig returns the .editorconfig definition if found in the
|
||||
// HEAD of the default repo branch.
|
||||
func (r *Repository) GetEditorconfig(optCommit ...*git.Commit) (cfg *editorconfig.Editorconfig, warning, err error) {
|
||||
@@ -399,33 +392,25 @@ func repoAssignment(ctx *Context, repo *repo_model.Repository) {
|
||||
|
||||
// RepoAssignment returns a middleware to handle repository assignment
|
||||
func RepoAssignment(ctx *Context) {
|
||||
if _, repoAssignmentOnce := ctx.Data["repoAssignmentExecuted"]; repoAssignmentOnce {
|
||||
// FIXME: it should panic in dev/test modes to have a clear behavior
|
||||
if !setting.IsProd || setting.IsInTesting {
|
||||
panic("RepoAssignment should not be executed twice")
|
||||
}
|
||||
return
|
||||
if ctx.Data["Repository"] != nil {
|
||||
setting.PanicInDevOrTesting("RepoAssignment should not be executed twice")
|
||||
}
|
||||
ctx.Data["repoAssignmentExecuted"] = true
|
||||
|
||||
var (
|
||||
owner *user_model.User
|
||||
err error
|
||||
)
|
||||
|
||||
var err error
|
||||
userName := ctx.PathParam("username")
|
||||
repoName := ctx.PathParam("reponame")
|
||||
repoName = strings.TrimSuffix(repoName, ".git")
|
||||
if setting.Other.EnableFeed {
|
||||
ctx.Data["EnableFeed"] = true
|
||||
repoName = strings.TrimSuffix(repoName, ".rss")
|
||||
repoName = strings.TrimSuffix(repoName, ".atom")
|
||||
}
|
||||
|
||||
// Check if the user is the same as the repository owner
|
||||
if ctx.IsSigned && ctx.Doer.LowerName == strings.ToLower(userName) {
|
||||
owner = ctx.Doer
|
||||
ctx.Repo.Owner = ctx.Doer
|
||||
} else {
|
||||
owner, err = user_model.GetUserByName(ctx, userName)
|
||||
ctx.Repo.Owner, err = user_model.GetUserByName(ctx, userName)
|
||||
if err != nil {
|
||||
if user_model.IsErrUserNotExist(err) {
|
||||
// go-get does not support redirects
|
||||
@@ -448,10 +433,8 @@ func RepoAssignment(ctx *Context) {
|
||||
return
|
||||
}
|
||||
}
|
||||
ctx.Repo.Owner = owner
|
||||
ctx.ContextUser = owner
|
||||
ctx.ContextUser = ctx.Repo.Owner
|
||||
ctx.Data["ContextUser"] = ctx.ContextUser
|
||||
ctx.Data["Username"] = ctx.Repo.Owner.Name
|
||||
|
||||
// redirect link to wiki
|
||||
if strings.HasSuffix(repoName, ".wiki") {
|
||||
@@ -474,10 +457,10 @@ func RepoAssignment(ctx *Context) {
|
||||
}
|
||||
|
||||
// Get repository.
|
||||
repo, err := repo_model.GetRepositoryByName(ctx, owner.ID, repoName)
|
||||
repo, err := repo_model.GetRepositoryByName(ctx, ctx.Repo.Owner.ID, repoName)
|
||||
if err != nil {
|
||||
if repo_model.IsErrRepoNotExist(err) {
|
||||
redirectRepoID, err := repo_model.LookupRedirect(ctx, owner.ID, repoName)
|
||||
redirectRepoID, err := repo_model.LookupRedirect(ctx, ctx.Repo.Owner.ID, repoName)
|
||||
if err == nil {
|
||||
RedirectToRepo(ctx.Base, redirectRepoID)
|
||||
} else if repo_model.IsErrRedirectNotExist(err) {
|
||||
@@ -494,7 +477,7 @@ func RepoAssignment(ctx *Context) {
|
||||
}
|
||||
return
|
||||
}
|
||||
repo.Owner = owner
|
||||
repo.Owner = ctx.Repo.Owner
|
||||
|
||||
repoAssignment(ctx, repo)
|
||||
if ctx.Written() {
|
||||
@@ -503,12 +486,7 @@ func RepoAssignment(ctx *Context) {
|
||||
|
||||
ctx.Repo.RepoLink = repo.Link()
|
||||
ctx.Data["RepoLink"] = ctx.Repo.RepoLink
|
||||
ctx.Data["RepoRelPath"] = ctx.Repo.Owner.Name + "/" + ctx.Repo.Repository.Name
|
||||
|
||||
if setting.Other.EnableFeed {
|
||||
ctx.Data["EnableFeed"] = true
|
||||
ctx.Data["FeedURL"] = ctx.Repo.RepoLink
|
||||
}
|
||||
ctx.Data["FeedURL"] = ctx.Repo.RepoLink
|
||||
|
||||
unit, err := ctx.Repo.Repository.GetUnit(ctx, unit_model.TypeExternalTracker)
|
||||
if err == nil {
|
||||
@@ -535,12 +513,9 @@ func RepoAssignment(ctx *Context) {
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Data["Title"] = owner.Name + "/" + repo.Name
|
||||
ctx.Data["Title"] = repo.Owner.Name + "/" + repo.Name
|
||||
ctx.Data["Repository"] = repo
|
||||
ctx.Data["Owner"] = ctx.Repo.Repository.Owner
|
||||
ctx.Data["IsRepositoryOwner"] = ctx.Repo.IsOwner()
|
||||
ctx.Data["IsRepositoryAdmin"] = ctx.Repo.IsAdmin()
|
||||
ctx.Data["RepoOwnerIsOrganization"] = repo.Owner.IsOrganization()
|
||||
ctx.Data["CanWriteCode"] = ctx.Repo.CanWrite(unit_model.TypeCode)
|
||||
ctx.Data["CanWriteIssues"] = ctx.Repo.CanWrite(unit_model.TypeIssues)
|
||||
ctx.Data["CanWritePulls"] = ctx.Repo.CanWrite(unit_model.TypePullRequests)
|
||||
@@ -608,7 +583,6 @@ func RepoAssignment(ctx *Context) {
|
||||
|
||||
// Disable everything when the repo is being created
|
||||
if ctx.Repo.Repository.IsBeingCreated() || ctx.Repo.Repository.IsBroken() {
|
||||
ctx.Data["BranchName"] = ctx.Repo.Repository.DefaultBranch
|
||||
if !isHomeOrSettings {
|
||||
ctx.Redirect(ctx.Repo.RepoLink)
|
||||
}
|
||||
@@ -616,9 +590,7 @@ func RepoAssignment(ctx *Context) {
|
||||
}
|
||||
|
||||
if ctx.Repo.GitRepo != nil {
|
||||
if !setting.IsProd || setting.IsInTesting {
|
||||
panic("RepoAssignment: GitRepo should be nil")
|
||||
}
|
||||
setting.PanicInDevOrTesting("RepoAssignment: GitRepo should be nil")
|
||||
_ = ctx.Repo.GitRepo.Close()
|
||||
ctx.Repo.GitRepo = nil
|
||||
}
|
||||
@@ -628,7 +600,6 @@ func RepoAssignment(ctx *Context) {
|
||||
if strings.Contains(err.Error(), "repository does not exist") || strings.Contains(err.Error(), "no such file or directory") {
|
||||
log.Error("Repository %-v has a broken repository on the file system: %s Error: %v", ctx.Repo.Repository, ctx.Repo.Repository.RepoPath(), err)
|
||||
ctx.Repo.Repository.MarkAsBrokenEmpty()
|
||||
ctx.Data["BranchName"] = ctx.Repo.Repository.DefaultBranch
|
||||
// Only allow access to base of repo or settings
|
||||
if !isHomeOrSettings {
|
||||
ctx.Redirect(ctx.Repo.RepoLink)
|
||||
@@ -641,7 +612,6 @@ func RepoAssignment(ctx *Context) {
|
||||
|
||||
// Stop at this point when the repo is empty.
|
||||
if ctx.Repo.Repository.IsEmpty {
|
||||
ctx.Data["BranchName"] = ctx.Repo.Repository.DefaultBranch
|
||||
return
|
||||
}
|
||||
|
||||
@@ -667,22 +637,6 @@ func RepoAssignment(ctx *Context) {
|
||||
|
||||
ctx.Data["BranchesCount"] = branchesTotal
|
||||
|
||||
// If no branch is set in the request URL, try to guess a default one.
|
||||
if len(ctx.Repo.BranchName) == 0 {
|
||||
if len(ctx.Repo.Repository.DefaultBranch) > 0 && ctx.Repo.GitRepo.IsBranchExist(ctx.Repo.Repository.DefaultBranch) {
|
||||
ctx.Repo.BranchName = ctx.Repo.Repository.DefaultBranch
|
||||
} else {
|
||||
ctx.Repo.BranchName, _ = gitrepo.GetDefaultBranch(ctx, ctx.Repo.Repository)
|
||||
if ctx.Repo.BranchName == "" {
|
||||
// If it still can't get a default branch, fall back to default branch from setting.
|
||||
// Something might be wrong. Either site admin should fix the repo sync or Gitea should fix a potential bug.
|
||||
ctx.Repo.BranchName = setting.Repository.DefaultBranch
|
||||
}
|
||||
}
|
||||
ctx.Repo.RefName = ctx.Repo.BranchName
|
||||
}
|
||||
ctx.Data["BranchName"] = ctx.Repo.BranchName
|
||||
|
||||
// People who have push access or have forked repository can propose a new pull request.
|
||||
canPush := ctx.Repo.CanWrite(unit_model.TypeCode) ||
|
||||
(ctx.IsSigned && repo_model.HasForkedRepo(ctx, ctx.Doer.ID, ctx.Repo.Repository.ID))
|
||||
@@ -725,7 +679,7 @@ func RepoAssignment(ctx *Context) {
|
||||
}
|
||||
|
||||
if ctx.FormString("go-get") == "1" {
|
||||
ctx.Data["GoGetImport"] = ComposeGoGetImport(ctx, owner.Name, repo.Name)
|
||||
ctx.Data["GoGetImport"] = ComposeGoGetImport(ctx, repo.Owner.Name, repo.Name)
|
||||
fullURLPrefix := repo.HTMLURL() + "/src/branch/" + util.PathEscapeSegments(ctx.Repo.BranchName)
|
||||
ctx.Data["GoDocDirectory"] = fullURLPrefix + "{/dir}"
|
||||
ctx.Data["GoDocFile"] = fullURLPrefix + "{/dir}/{file}#L{line}"
|
||||
@@ -871,26 +825,39 @@ type RepoRefByTypeOptions struct {
|
||||
IgnoreNotExistErr bool
|
||||
}
|
||||
|
||||
func repoRefFullName(shortName string, typ RepoRefType) git.RefName {
|
||||
switch typ {
|
||||
case RepoRefBranch:
|
||||
return git.RefNameFromBranch(shortName)
|
||||
case RepoRefTag:
|
||||
return git.RefNameFromTag(shortName)
|
||||
case RepoRefCommit:
|
||||
return git.RefNameFromCommit(shortName)
|
||||
default:
|
||||
setting.PanicInDevOrTesting("Unknown RepoRefType: %v", typ)
|
||||
return git.RefNameFromBranch("main") // just a dummy result, it shouldn't happen
|
||||
}
|
||||
}
|
||||
|
||||
// RepoRefByType handles repository reference name for a specific type
|
||||
// of repository reference
|
||||
func RepoRefByType(detectRefType RepoRefType, opts ...RepoRefByTypeOptions) func(*Context) {
|
||||
opt := util.OptionalArg(opts)
|
||||
return func(ctx *Context) {
|
||||
var err error
|
||||
refType := detectRefType
|
||||
// Empty repository does not have reference information.
|
||||
if ctx.Repo.Repository.IsEmpty {
|
||||
// assume the user is viewing the (non-existent) default branch
|
||||
ctx.Repo.IsViewBranch = true
|
||||
ctx.Repo.BranchName = ctx.Repo.Repository.DefaultBranch
|
||||
ctx.Repo.RefFullName = git.RefNameFromBranch(ctx.Repo.BranchName)
|
||||
// these variables are used by the template to "add/upload" new files
|
||||
ctx.Data["BranchName"] = ctx.Repo.BranchName
|
||||
ctx.Data["TreePath"] = ""
|
||||
return
|
||||
}
|
||||
|
||||
var (
|
||||
refName string
|
||||
err error
|
||||
)
|
||||
|
||||
if ctx.Repo.GitRepo == nil {
|
||||
ctx.Repo.GitRepo, err = gitrepo.RepositoryFromRequestContextOrOpen(ctx, ctx.Repo.Repository)
|
||||
if err != nil {
|
||||
@@ -900,22 +867,23 @@ func RepoRefByType(detectRefType RepoRefType, opts ...RepoRefByTypeOptions) func
|
||||
}
|
||||
|
||||
// Get default branch.
|
||||
var refShortName string
|
||||
reqPath := ctx.PathParam("*")
|
||||
if reqPath == "" {
|
||||
refName = ctx.Repo.Repository.DefaultBranch
|
||||
if !ctx.Repo.GitRepo.IsBranchExist(refName) {
|
||||
refShortName = ctx.Repo.Repository.DefaultBranch
|
||||
if !ctx.Repo.GitRepo.IsBranchExist(refShortName) {
|
||||
brs, _, err := ctx.Repo.GitRepo.GetBranches(0, 1)
|
||||
if err == nil && len(brs) != 0 {
|
||||
refName = brs[0].Name
|
||||
refShortName = brs[0].Name
|
||||
} else if len(brs) == 0 {
|
||||
log.Error("No branches in non-empty repository %s", ctx.Repo.GitRepo.Path)
|
||||
} else {
|
||||
log.Error("GetBranches error: %v", err)
|
||||
}
|
||||
}
|
||||
ctx.Repo.RefName = refName
|
||||
ctx.Repo.BranchName = refName
|
||||
ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetBranchCommit(refName)
|
||||
ctx.Repo.RefFullName = git.RefNameFromBranch(refShortName)
|
||||
ctx.Repo.BranchName = refShortName
|
||||
ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetBranchCommit(refShortName)
|
||||
if err == nil {
|
||||
ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
|
||||
} else if strings.Contains(err.Error(), "fatal: not a git repository") || strings.Contains(err.Error(), "object does not exist") {
|
||||
@@ -929,35 +897,37 @@ func RepoRefByType(detectRefType RepoRefType, opts ...RepoRefByTypeOptions) func
|
||||
} else { // there is a path in request
|
||||
guessLegacyPath := refType == RepoRefUnknown
|
||||
if guessLegacyPath {
|
||||
refName, refType = getRefNameLegacy(ctx.Base, ctx.Repo, reqPath, "")
|
||||
refShortName, refType = getRefNameLegacy(ctx.Base, ctx.Repo, reqPath, "")
|
||||
} else {
|
||||
refName = getRefName(ctx.Base, ctx.Repo, reqPath, refType)
|
||||
refShortName = getRefName(ctx.Base, ctx.Repo, reqPath, refType)
|
||||
}
|
||||
ctx.Repo.RefName = refName
|
||||
ctx.Repo.RefFullName = repoRefFullName(refShortName, refType)
|
||||
isRenamedBranch, has := ctx.Data["IsRenamedBranch"].(bool)
|
||||
if isRenamedBranch && has {
|
||||
renamedBranchName := ctx.Data["RenamedBranchName"].(string)
|
||||
ctx.Flash.Info(ctx.Tr("repo.branch.renamed", refName, renamedBranchName))
|
||||
link := setting.AppSubURL + strings.Replace(ctx.Req.URL.EscapedPath(), util.PathEscapeSegments(refName), util.PathEscapeSegments(renamedBranchName), 1)
|
||||
ctx.Flash.Info(ctx.Tr("repo.branch.renamed", refShortName, renamedBranchName))
|
||||
link := setting.AppSubURL + strings.Replace(ctx.Req.URL.EscapedPath(), util.PathEscapeSegments(refShortName), util.PathEscapeSegments(renamedBranchName), 1)
|
||||
ctx.Redirect(link)
|
||||
return
|
||||
}
|
||||
|
||||
if refType == RepoRefBranch && ctx.Repo.GitRepo.IsBranchExist(refName) {
|
||||
if refType == RepoRefBranch && ctx.Repo.GitRepo.IsBranchExist(refShortName) {
|
||||
ctx.Repo.IsViewBranch = true
|
||||
ctx.Repo.BranchName = refName
|
||||
ctx.Repo.BranchName = refShortName
|
||||
ctx.Repo.RefFullName = git.RefNameFromBranch(refShortName)
|
||||
|
||||
ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetBranchCommit(refName)
|
||||
ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetBranchCommit(refShortName)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetBranchCommit", err)
|
||||
return
|
||||
}
|
||||
ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
|
||||
} else if refType == RepoRefTag && ctx.Repo.GitRepo.IsTagExist(refName) {
|
||||
} else if refType == RepoRefTag && ctx.Repo.GitRepo.IsTagExist(refShortName) {
|
||||
ctx.Repo.IsViewTag = true
|
||||
ctx.Repo.TagName = refName
|
||||
ctx.Repo.RefFullName = git.RefNameFromTag(refShortName)
|
||||
ctx.Repo.TagName = refShortName
|
||||
|
||||
ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetTagCommit(refName)
|
||||
ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetTagCommit(refShortName)
|
||||
if err != nil {
|
||||
if git.IsErrNotExist(err) {
|
||||
ctx.NotFound("GetTagCommit", err)
|
||||
@@ -967,25 +937,26 @@ func RepoRefByType(detectRefType RepoRefType, opts ...RepoRefByTypeOptions) func
|
||||
return
|
||||
}
|
||||
ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
|
||||
} else if git.IsStringLikelyCommitID(ctx.Repo.GetObjectFormat(), refName, 7) {
|
||||
} else if git.IsStringLikelyCommitID(ctx.Repo.GetObjectFormat(), refShortName, 7) {
|
||||
ctx.Repo.IsViewCommit = true
|
||||
ctx.Repo.CommitID = refName
|
||||
ctx.Repo.RefFullName = git.RefNameFromCommit(refShortName)
|
||||
ctx.Repo.CommitID = refShortName
|
||||
|
||||
ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetCommit(refName)
|
||||
ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetCommit(refShortName)
|
||||
if err != nil {
|
||||
ctx.NotFound("GetCommit", err)
|
||||
return
|
||||
}
|
||||
// If short commit ID add canonical link header
|
||||
if len(refName) < ctx.Repo.GetObjectFormat().FullLength() {
|
||||
canonicalURL := util.URLJoin(httplib.GuessCurrentAppURL(ctx), strings.Replace(ctx.Req.URL.RequestURI(), util.PathEscapeSegments(refName), url.PathEscape(ctx.Repo.Commit.ID.String()), 1))
|
||||
if len(refShortName) < ctx.Repo.GetObjectFormat().FullLength() {
|
||||
canonicalURL := util.URLJoin(httplib.GuessCurrentAppURL(ctx), strings.Replace(ctx.Req.URL.RequestURI(), util.PathEscapeSegments(refShortName), url.PathEscape(ctx.Repo.Commit.ID.String()), 1))
|
||||
ctx.RespHeader().Set("Link", fmt.Sprintf(`<%s>; rel="canonical"`, canonicalURL))
|
||||
}
|
||||
} else {
|
||||
if opt.IgnoreNotExistErr {
|
||||
return
|
||||
}
|
||||
ctx.NotFound("RepoRef invalid repo", fmt.Errorf("branch or tag not exist: %s", refName))
|
||||
ctx.NotFound("RepoRef invalid repo", fmt.Errorf("branch or tag not exist: %s", refShortName))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -995,24 +966,26 @@ func RepoRefByType(detectRefType RepoRefType, opts ...RepoRefByTypeOptions) func
|
||||
redirect := path.Join(
|
||||
ctx.Repo.RepoLink,
|
||||
util.PathEscapeSegments(prefix),
|
||||
ctx.Repo.BranchNameSubURL(),
|
||||
ctx.Repo.RefTypeNameSubURL(),
|
||||
util.PathEscapeSegments(ctx.Repo.TreePath))
|
||||
ctx.Redirect(redirect)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
ctx.Data["BranchName"] = ctx.Repo.BranchName
|
||||
ctx.Data["RefName"] = ctx.Repo.RefName
|
||||
ctx.Data["RefShortName"] = util.Iif(refType == RepoRefCommit, base.ShortSha(ctx.Repo.RefName), ctx.Repo.RefName)
|
||||
ctx.Data["RefType"] = RefTypeName(refType)
|
||||
ctx.Data["BranchNameSubURL"] = ctx.Repo.BranchNameSubURL()
|
||||
ctx.Data["TagName"] = ctx.Repo.TagName
|
||||
ctx.Data["CommitID"] = ctx.Repo.CommitID
|
||||
ctx.Data["RefFullName"] = ctx.Repo.RefFullName
|
||||
ctx.Data["RefTypeNameSubURL"] = ctx.Repo.RefTypeNameSubURL()
|
||||
ctx.Data["TreePath"] = ctx.Repo.TreePath
|
||||
|
||||
ctx.Data["IsViewBranch"] = ctx.Repo.IsViewBranch
|
||||
ctx.Data["BranchName"] = ctx.Repo.BranchName
|
||||
|
||||
ctx.Data["IsViewTag"] = ctx.Repo.IsViewTag
|
||||
ctx.Data["TagName"] = ctx.Repo.TagName
|
||||
|
||||
ctx.Data["IsViewCommit"] = ctx.Repo.IsViewCommit
|
||||
ctx.Data["CommitID"] = ctx.Repo.CommitID
|
||||
|
||||
ctx.Data["CanCreateBranch"] = ctx.Repo.CanCreateBranch() // only used by the branch selector dropdown: AllowCreateNewRef
|
||||
|
||||
ctx.Repo.CommitsCount, err = ctx.Repo.GetCommitsCount()
|
||||
|
||||
@@ -87,6 +87,7 @@ type mirrorSyncResult struct {
|
||||
/*
|
||||
// * [new tag] v0.1.8 -> v0.1.8
|
||||
// * [new branch] master -> origin/master
|
||||
// * [new ref] refs/pull/2/head -> refs/pull/2/head"
|
||||
// - [deleted] (none) -> origin/test // delete a branch
|
||||
// - [deleted] (none) -> 1 // delete a tag
|
||||
// 957a993..a87ba5f test -> origin/test
|
||||
@@ -117,6 +118,11 @@ func parseRemoteUpdateOutput(output, remoteName string) []*mirrorSyncResult {
|
||||
refName: git.RefNameFromBranch(refName),
|
||||
oldCommitID: gitShortEmptySha,
|
||||
})
|
||||
case strings.HasPrefix(lines[i], " * [new ref]"): // new reference
|
||||
results = append(results, &mirrorSyncResult{
|
||||
refName: git.RefName(refName),
|
||||
oldCommitID: gitShortEmptySha,
|
||||
})
|
||||
case strings.HasPrefix(lines[i], " - "): // Delete reference
|
||||
isTag := !strings.HasPrefix(refName, remoteName+"/")
|
||||
var refFullName git.RefName
|
||||
@@ -159,8 +165,15 @@ func parseRemoteUpdateOutput(output, remoteName string) []*mirrorSyncResult {
|
||||
log.Error("Expect two SHAs but not what found: %q", lines[i])
|
||||
continue
|
||||
}
|
||||
var refFullName git.RefName
|
||||
if strings.HasPrefix(refName, "refs/") {
|
||||
refFullName = git.RefName(refName)
|
||||
} else {
|
||||
refFullName = git.RefNameFromBranch(strings.TrimPrefix(refName, remoteName+"/"))
|
||||
}
|
||||
|
||||
results = append(results, &mirrorSyncResult{
|
||||
refName: git.RefNameFromBranch(strings.TrimPrefix(refName, remoteName+"/")),
|
||||
refName: refFullName,
|
||||
oldCommitID: shas[0],
|
||||
newCommitID: shas[1],
|
||||
})
|
||||
|
||||
@@ -31,19 +31,20 @@ import (
|
||||
// handle elsewhere.
|
||||
type ArchiveRequest struct {
|
||||
RepoID int64
|
||||
refName string
|
||||
Type git.ArchiveType
|
||||
CommitID string
|
||||
|
||||
archiveRefShortName string // the ref short name to download the archive, for example: "master", "v1.0.0", "commit id"
|
||||
}
|
||||
|
||||
// ErrUnknownArchiveFormat request archive format is not supported
|
||||
type ErrUnknownArchiveFormat struct {
|
||||
RequestFormat string
|
||||
RequestNameType string
|
||||
}
|
||||
|
||||
// Error implements error
|
||||
func (err ErrUnknownArchiveFormat) Error() string {
|
||||
return fmt.Sprintf("unknown format: %s", err.RequestFormat)
|
||||
return fmt.Sprintf("unknown format: %s", err.RequestNameType)
|
||||
}
|
||||
|
||||
// Is implements error
|
||||
@@ -54,12 +55,12 @@ func (ErrUnknownArchiveFormat) Is(err error) bool {
|
||||
|
||||
// RepoRefNotFoundError is returned when a requested reference (commit, tag) was not found.
|
||||
type RepoRefNotFoundError struct {
|
||||
RefName string
|
||||
RefShortName string
|
||||
}
|
||||
|
||||
// Error implements error.
|
||||
func (e RepoRefNotFoundError) Error() string {
|
||||
return fmt.Sprintf("unrecognized repository reference: %s", e.RefName)
|
||||
return fmt.Sprintf("unrecognized repository reference: %s", e.RefShortName)
|
||||
}
|
||||
|
||||
func (e RepoRefNotFoundError) Is(err error) bool {
|
||||
@@ -67,43 +68,23 @@ func (e RepoRefNotFoundError) Is(err error) bool {
|
||||
return ok
|
||||
}
|
||||
|
||||
func ParseFileName(uri string) (ext string, tp git.ArchiveType, err error) {
|
||||
switch {
|
||||
case strings.HasSuffix(uri, ".zip"):
|
||||
ext = ".zip"
|
||||
tp = git.ZIP
|
||||
case strings.HasSuffix(uri, ".tar.gz"):
|
||||
ext = ".tar.gz"
|
||||
tp = git.TARGZ
|
||||
case strings.HasSuffix(uri, ".bundle"):
|
||||
ext = ".bundle"
|
||||
tp = git.BUNDLE
|
||||
default:
|
||||
return "", 0, ErrUnknownArchiveFormat{RequestFormat: uri}
|
||||
}
|
||||
return ext, tp, nil
|
||||
}
|
||||
|
||||
// NewRequest creates an archival request, based on the URI. The
|
||||
// resulting ArchiveRequest is suitable for being passed to Await()
|
||||
// if it's determined that the request still needs to be satisfied.
|
||||
func NewRequest(repoID int64, repo *git.Repository, refName string, fileType git.ArchiveType) (*ArchiveRequest, error) {
|
||||
if fileType < git.ZIP || fileType > git.BUNDLE {
|
||||
return nil, ErrUnknownArchiveFormat{RequestFormat: fileType.String()}
|
||||
}
|
||||
|
||||
r := &ArchiveRequest{
|
||||
RepoID: repoID,
|
||||
refName: refName,
|
||||
Type: fileType,
|
||||
func NewRequest(repoID int64, repo *git.Repository, archiveRefExt string) (*ArchiveRequest, error) {
|
||||
// here the archiveRefShortName is not a clear ref, it could be a tag, branch or commit id
|
||||
archiveRefShortName, archiveType := git.SplitArchiveNameType(archiveRefExt)
|
||||
if archiveType == git.ArchiveUnknown {
|
||||
return nil, ErrUnknownArchiveFormat{archiveRefExt}
|
||||
}
|
||||
|
||||
// Get corresponding commit.
|
||||
commitID, err := repo.ConvertToGitID(r.refName)
|
||||
commitID, err := repo.ConvertToGitID(archiveRefShortName)
|
||||
if err != nil {
|
||||
return nil, RepoRefNotFoundError{RefName: r.refName}
|
||||
return nil, RepoRefNotFoundError{RefShortName: archiveRefShortName}
|
||||
}
|
||||
|
||||
r := &ArchiveRequest{RepoID: repoID, archiveRefShortName: archiveRefShortName, Type: archiveType}
|
||||
r.CommitID = commitID.String()
|
||||
return r, nil
|
||||
}
|
||||
@@ -111,11 +92,11 @@ func NewRequest(repoID int64, repo *git.Repository, refName string, fileType git
|
||||
// GetArchiveName returns the name of the caller, based on the ref used by the
|
||||
// caller to create this request.
|
||||
func (aReq *ArchiveRequest) GetArchiveName() string {
|
||||
return strings.ReplaceAll(aReq.refName, "/", "-") + "." + aReq.Type.String()
|
||||
return strings.ReplaceAll(aReq.archiveRefShortName, "/", "-") + "." + aReq.Type.String()
|
||||
}
|
||||
|
||||
// Await awaits the completion of an ArchiveRequest. If the archive has
|
||||
// already been prepared the method returns immediately. Otherwise an archiver
|
||||
// already been prepared the method returns immediately. Otherwise, an archiver
|
||||
// process will be started and its completion awaited. On success the returned
|
||||
// RepoArchiver may be used to download the archive. Note that even if the
|
||||
// context is cancelled/times out a started archiver will still continue to run
|
||||
@@ -208,8 +189,8 @@ func doArchive(ctx context.Context, r *ArchiveRequest) (*repo_model.RepoArchiver
|
||||
|
||||
rd, w := io.Pipe()
|
||||
defer func() {
|
||||
w.Close()
|
||||
rd.Close()
|
||||
_ = w.Close()
|
||||
_ = rd.Close()
|
||||
}()
|
||||
done := make(chan error, 1) // Ensure that there is some capacity which will ensure that the goroutine below can always finish
|
||||
repo, err := repo_model.GetRepositoryByID(ctx, archiver.RepoID)
|
||||
@@ -230,7 +211,7 @@ func doArchive(ctx context.Context, r *ArchiveRequest) (*repo_model.RepoArchiver
|
||||
}
|
||||
}()
|
||||
|
||||
if archiver.Type == git.BUNDLE {
|
||||
if archiver.Type == git.ArchiveBundle {
|
||||
err = gitRepo.CreateBundle(
|
||||
ctx,
|
||||
archiver.CommitID,
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/services/contexttest"
|
||||
|
||||
_ "code.gitea.io/gitea/models/actions"
|
||||
@@ -31,47 +30,47 @@ func TestArchive_Basic(t *testing.T) {
|
||||
contexttest.LoadGitRepo(t, ctx)
|
||||
defer ctx.Repo.GitRepo.Close()
|
||||
|
||||
bogusReq, err := NewRequest(ctx.Repo.Repository.ID, ctx.Repo.GitRepo, firstCommit, git.ZIP)
|
||||
bogusReq, err := NewRequest(ctx.Repo.Repository.ID, ctx.Repo.GitRepo, firstCommit+".zip")
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, bogusReq)
|
||||
assert.EqualValues(t, firstCommit+".zip", bogusReq.GetArchiveName())
|
||||
|
||||
// Check a series of bogus requests.
|
||||
// Step 1, valid commit with a bad extension.
|
||||
bogusReq, err = NewRequest(ctx.Repo.Repository.ID, ctx.Repo.GitRepo, firstCommit, 100)
|
||||
bogusReq, err = NewRequest(ctx.Repo.Repository.ID, ctx.Repo.GitRepo, firstCommit+".unknown")
|
||||
assert.Error(t, err)
|
||||
assert.Nil(t, bogusReq)
|
||||
|
||||
// Step 2, missing commit.
|
||||
bogusReq, err = NewRequest(ctx.Repo.Repository.ID, ctx.Repo.GitRepo, "dbffff", git.ZIP)
|
||||
bogusReq, err = NewRequest(ctx.Repo.Repository.ID, ctx.Repo.GitRepo, "dbffff.zip")
|
||||
assert.Error(t, err)
|
||||
assert.Nil(t, bogusReq)
|
||||
|
||||
// Step 3, doesn't look like branch/tag/commit.
|
||||
bogusReq, err = NewRequest(ctx.Repo.Repository.ID, ctx.Repo.GitRepo, "db", git.ZIP)
|
||||
bogusReq, err = NewRequest(ctx.Repo.Repository.ID, ctx.Repo.GitRepo, "db.zip")
|
||||
assert.Error(t, err)
|
||||
assert.Nil(t, bogusReq)
|
||||
|
||||
bogusReq, err = NewRequest(ctx.Repo.Repository.ID, ctx.Repo.GitRepo, "master", git.ZIP)
|
||||
bogusReq, err = NewRequest(ctx.Repo.Repository.ID, ctx.Repo.GitRepo, "master.zip")
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, bogusReq)
|
||||
assert.EqualValues(t, "master.zip", bogusReq.GetArchiveName())
|
||||
|
||||
bogusReq, err = NewRequest(ctx.Repo.Repository.ID, ctx.Repo.GitRepo, "test/archive", git.ZIP)
|
||||
bogusReq, err = NewRequest(ctx.Repo.Repository.ID, ctx.Repo.GitRepo, "test/archive.zip")
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, bogusReq)
|
||||
assert.EqualValues(t, "test-archive.zip", bogusReq.GetArchiveName())
|
||||
|
||||
// Now two valid requests, firstCommit with valid extensions.
|
||||
zipReq, err := NewRequest(ctx.Repo.Repository.ID, ctx.Repo.GitRepo, firstCommit, git.ZIP)
|
||||
zipReq, err := NewRequest(ctx.Repo.Repository.ID, ctx.Repo.GitRepo, firstCommit+".zip")
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, zipReq)
|
||||
|
||||
tgzReq, err := NewRequest(ctx.Repo.Repository.ID, ctx.Repo.GitRepo, firstCommit, git.TARGZ)
|
||||
tgzReq, err := NewRequest(ctx.Repo.Repository.ID, ctx.Repo.GitRepo, firstCommit+".tar.gz")
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, tgzReq)
|
||||
|
||||
secondReq, err := NewRequest(ctx.Repo.Repository.ID, ctx.Repo.GitRepo, secondCommit, git.ZIP)
|
||||
secondReq, err := NewRequest(ctx.Repo.Repository.ID, ctx.Repo.GitRepo, secondCommit+".bundle")
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, secondReq)
|
||||
|
||||
@@ -91,7 +90,7 @@ func TestArchive_Basic(t *testing.T) {
|
||||
// Sleep two seconds to make sure the queue doesn't change.
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
zipReq2, err := NewRequest(ctx.Repo.Repository.ID, ctx.Repo.GitRepo, firstCommit, git.ZIP)
|
||||
zipReq2, err := NewRequest(ctx.Repo.Repository.ID, ctx.Repo.GitRepo, firstCommit+".zip")
|
||||
assert.NoError(t, err)
|
||||
// This zipReq should match what's sitting in the queue, as we haven't
|
||||
// let it release yet. From the consumer's point of view, this looks like
|
||||
@@ -106,12 +105,12 @@ func TestArchive_Basic(t *testing.T) {
|
||||
// Now we'll submit a request and TimedWaitForCompletion twice, before and
|
||||
// after we release it. We should trigger both the timeout and non-timeout
|
||||
// cases.
|
||||
timedReq, err := NewRequest(ctx.Repo.Repository.ID, ctx.Repo.GitRepo, secondCommit, git.TARGZ)
|
||||
timedReq, err := NewRequest(ctx.Repo.Repository.ID, ctx.Repo.GitRepo, secondCommit+".tar.gz")
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, timedReq)
|
||||
doArchive(db.DefaultContext, timedReq)
|
||||
|
||||
zipReq2, err = NewRequest(ctx.Repo.Repository.ID, ctx.Repo.GitRepo, firstCommit, git.ZIP)
|
||||
zipReq2, err = NewRequest(ctx.Repo.Repository.ID, ctx.Repo.GitRepo, firstCommit+".zip")
|
||||
assert.NoError(t, err)
|
||||
// Now, we're guaranteed to have released the original zipReq from the queue.
|
||||
// Ensure that we don't get handed back the released entry somehow, but they
|
||||
@@ -129,6 +128,6 @@ func TestArchive_Basic(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestErrUnknownArchiveFormat(t *testing.T) {
|
||||
err := ErrUnknownArchiveFormat{RequestFormat: "master"}
|
||||
err := ErrUnknownArchiveFormat{RequestNameType: "xxx"}
|
||||
assert.ErrorIs(t, err, ErrUnknownArchiveFormat{})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user