aboutsummaryrefslogtreecommitdiffstats
path: root/routers/api/v1
diff options
context:
space:
mode:
authorLunny Xiao <xiaolunwen@gmail.com>2024-11-25 11:35:49 -0800
committerGitHub <noreply@github.com>2024-11-25 19:35:49 +0000
commit703be6bf307ed19ce8dc8cd311d24aeb6e5b9861 (patch)
treed688ea0f3db339ab9ca89ef15399419e8c31899a /routers/api/v1
parent44909f6e2c8f94b3153cb5114078e4eebe65a4a8 (diff)
downloadgitea-703be6bf307ed19ce8dc8cd311d24aeb6e5b9861.tar.gz
gitea-703be6bf307ed19ce8dc8cd311d24aeb6e5b9861.zip
Add github compatible tarball download API endpoints (#32572)
Fix #29654 Fix #32481
Diffstat (limited to 'routers/api/v1')
-rw-r--r--routers/api/v1/api.go2
-rw-r--r--routers/api/v1/repo/download.go53
-rw-r--r--routers/api/v1/repo/file.go15
3 files changed, 67 insertions, 3 deletions
diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go
index 23f466873b..0079e8dc87 100644
--- a/routers/api/v1/api.go
+++ b/routers/api/v1/api.go
@@ -1377,6 +1377,8 @@ func Routes() *web.Router {
m.Post("", bind(api.UpdateRepoAvatarOption{}), repo.UpdateAvatar)
m.Delete("", repo.DeleteAvatar)
}, reqAdmin(), reqToken())
+
+ m.Get("/{ball_type:tarball|zipball|bundle}/*", reqRepoReader(unit.TypeCode), repo.DownloadArchive)
}, repoAssignment(), checkTokenPublicOnly())
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryRepository))
diff --git a/routers/api/v1/repo/download.go b/routers/api/v1/repo/download.go
new file mode 100644
index 0000000000..3620c1465f
--- /dev/null
+++ b/routers/api/v1/repo/download.go
@@ -0,0 +1,53 @@
+// Copyright 2024 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package repo
+
+import (
+ "fmt"
+ "net/http"
+
+ "code.gitea.io/gitea/modules/git"
+ "code.gitea.io/gitea/modules/gitrepo"
+ "code.gitea.io/gitea/services/context"
+ archiver_service "code.gitea.io/gitea/services/repository/archiver"
+)
+
+func DownloadArchive(ctx *context.APIContext) {
+ var tp git.ArchiveType
+ switch ballType := ctx.PathParam("ball_type"); ballType {
+ case "tarball":
+ tp = git.TARGZ
+ case "zipball":
+ tp = git.ZIP
+ case "bundle":
+ tp = git.BUNDLE
+ default:
+ ctx.Error(http.StatusBadRequest, "", fmt.Sprintf("Unknown archive type: %s", ballType))
+ return
+ }
+
+ if ctx.Repo.GitRepo == nil {
+ gitRepo, err := gitrepo.OpenRepository(ctx, ctx.Repo.Repository)
+ if err != nil {
+ ctx.Error(http.StatusInternalServerError, "OpenRepository", err)
+ return
+ }
+ ctx.Repo.GitRepo = gitRepo
+ defer gitRepo.Close()
+ }
+
+ r, err := archiver_service.NewRequest(ctx.Repo.Repository.ID, ctx.Repo.GitRepo, ctx.PathParam("*"), tp)
+ if err != nil {
+ ctx.ServerError("NewRequest", err)
+ return
+ }
+
+ archive, err := r.Await(ctx)
+ if err != nil {
+ ctx.ServerError("archive.Await", err)
+ return
+ }
+
+ download(ctx, r.GetArchiveName(), archive)
+}
diff --git a/routers/api/v1/repo/file.go b/routers/api/v1/repo/file.go
index 05650cc9be..959a4b952a 100644
--- a/routers/api/v1/repo/file.go
+++ b/routers/api/v1/repo/file.go
@@ -301,7 +301,13 @@ func GetArchive(ctx *context.APIContext) {
func archiveDownload(ctx *context.APIContext) {
uri := ctx.PathParam("*")
- aReq, err := archiver_service.NewRequest(ctx.Repo.Repository.ID, ctx.Repo.GitRepo, uri)
+ ext, tp, err := archiver_service.ParseFileName(uri)
+ if err != nil {
+ ctx.Error(http.StatusBadRequest, "ParseFileName", err)
+ return
+ }
+
+ aReq, err := archiver_service.NewRequest(ctx.Repo.Repository.ID, ctx.Repo.GitRepo, strings.TrimSuffix(uri, ext), tp)
if err != nil {
if errors.Is(err, archiver_service.ErrUnknownArchiveFormat{}) {
ctx.Error(http.StatusBadRequest, "unknown archive format", err)
@@ -327,9 +333,12 @@ func download(ctx *context.APIContext, archiveName string, archiver *repo_model.
// Add nix format link header so tarballs lock correctly:
// https://github.com/nixos/nix/blob/56763ff918eb308db23080e560ed2ea3e00c80a7/doc/manual/src/protocols/tarball-fetcher.md
- ctx.Resp.Header().Add("Link", fmt.Sprintf(`<%s/archive/%s.tar.gz?rev=%s>; rel="immutable"`,
+ ctx.Resp.Header().Add("Link", fmt.Sprintf(`<%s/archive/%s.%s?rev=%s>; rel="immutable"`,
ctx.Repo.Repository.APIURL(),
- archiver.CommitID, archiver.CommitID))
+ archiver.CommitID,
+ archiver.Type.String(),
+ archiver.CommitID,
+ ))
rPath := archiver.RelativePath()
if setting.RepoArchive.Storage.ServeDirect() {