1
1
mirror of https://github.com/go-gitea/gitea synced 2025-07-06 02:27:20 +00:00

Add API endpoint to request contents of multiple files simultaniously (#34139)

Adds an API POST endpoint under `/repos/{owner}/{repo}/file-contents`
which receives a list of paths and returns a list of the contents of
these files.

This API endpoint will be helpful for applications like headless CMS
(reference: https://github.com/sveltia/sveltia-cms/issues/198) which
need to retrieve a large number of files by reducing the amount of
needed API calls.

Close #33495

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
Denys Konovalov
2025-04-21 19:20:11 +02:00
committed by GitHub
parent e947f309b1
commit 9a071a596f
24 changed files with 581 additions and 415 deletions

View File

@ -15,6 +15,7 @@ import (
"code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/cache"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/gitrepo"
"code.gitea.io/gitea/modules/httpcache"
"code.gitea.io/gitea/modules/log"
@ -245,7 +246,7 @@ func APIContexter() func(http.Handler) http.Handler {
// String will replace message, errors will be added to a slice
func (ctx *APIContext) APIErrorNotFound(objs ...any) {
message := ctx.Locale.TrString("error.not_found")
var errors []string
var errs []string
for _, obj := range objs {
// Ignore nil
if obj == nil {
@ -253,7 +254,7 @@ func (ctx *APIContext) APIErrorNotFound(objs ...any) {
}
if err, ok := obj.(error); ok {
errors = append(errors, err.Error())
errs = append(errs, err.Error())
} else {
message = obj.(string)
}
@ -262,7 +263,7 @@ func (ctx *APIContext) APIErrorNotFound(objs ...any) {
ctx.JSON(http.StatusNotFound, map[string]any{
"message": message,
"url": setting.API.SwaggerURL,
"errors": errors,
"errors": errs,
})
}
@ -298,39 +299,27 @@ func RepoRefForAPI(next http.Handler) http.Handler {
}
if ctx.Repo.GitRepo == nil {
ctx.APIErrorInternal(errors.New("no open git repo"))
return
panic("no GitRepo, forgot to call the middleware?") // it is a programming error
}
refName, _, _ := getRefNameLegacy(ctx.Base, ctx.Repo, ctx.PathParam("*"), ctx.FormTrim("ref"))
refName, refType, _ := getRefNameLegacy(ctx.Base, ctx.Repo, ctx.PathParam("*"), ctx.FormTrim("ref"))
var err error
if gitrepo.IsBranchExist(ctx, ctx.Repo.Repository, refName) {
switch refType {
case git.RefTypeBranch:
ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetBranchCommit(refName)
if err != nil {
ctx.APIErrorInternal(err)
return
}
ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
} else if gitrepo.IsTagExist(ctx, ctx.Repo.Repository, refName) {
case git.RefTypeTag:
ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetTagCommit(refName)
if err != nil {
ctx.APIErrorInternal(err)
return
}
ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
} else if len(refName) == ctx.Repo.GetObjectFormat().FullLength() {
ctx.Repo.CommitID = refName
case git.RefTypeCommit:
ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetCommit(refName)
if err != nil {
ctx.APIErrorNotFound("GetCommit", err)
return
}
} else {
}
if ctx.Repo.Commit == nil || errors.Is(err, util.ErrNotExist) {
ctx.APIErrorNotFound(fmt.Errorf("not exist: '%s'", ctx.PathParam("*")))
return
} else if err != nil {
ctx.APIErrorInternal(err)
return
}
ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
next.ServeHTTP(w, req)
})
}