To register the RPM registry add the url to the list of known apt sources:
```shell
-dnf config-manager --add-repo https://gitea.example.com/api/packages/{owner}/rpm.repo
+dnf config-manager --add-repo https://gitea.example.com/api/packages/{owner}/rpm/{group}.repo
```
-| Placeholder | Description |
-| ----------- | ----------- |
-| `owner` | The owner of the package. |
+| Placeholder | Description |
+| ----------- |----------------------------------------------------|
+| `owner` | The owner of the package. |
+| `group` | Everything, e.g. `el7`, `rocky/el9` , `test/fc38`.|
If the registry is private, provide credentials in the url. You can use a password or a [personal access token](development/api-usage.md#authentication):
```shell
-dnf config-manager --add-repo https://{username}:{your_password_or_token}@gitea.example.com/api/packages/{owner}/rpm.repo
+dnf config-manager --add-repo https://{username}:{your_password_or_token}@gitea.example.com/api/packages/{owner}/rpm/{group}.repo
```
You have to add the credentials to the urls in the `rpm.repo` file in `/etc/yum.repos.d` too.
To publish a RPM package (`*.rpm`), perform a HTTP PUT operation with the package content in the request body.
```
-PUT https://gitea.example.com/api/packages/{owner}/rpm/upload
+PUT https://gitea.example.com/api/packages/{owner}/rpm/{group}/upload
```
| Parameter | Description |
| --------- | ----------- |
| `owner` | The owner of the package. |
+| `group` | Everything, e.g. `el7`, `rocky/el9` , `test/fc38`.|
Example request using HTTP Basic authentication:
```shell
curl --user your_username:your_password_or_token \
--upload-file path/to/file.rpm \
- https://gitea.example.com/api/packages/testuser/rpm/upload
+ https://gitea.example.com/api/packages/testuser/rpm/centos/el7/upload
```
If you are using 2FA or OAuth use a [personal access token](development/api-usage.md#authentication) instead of the password.
To delete an RPM package perform a HTTP DELETE operation. This will delete the package version too if there is no file left.
```
-DELETE https://gitea.example.com/api/packages/{owner}/rpm/{package_name}/{package_version}/{architecture}
+DELETE https://gitea.example.com/api/packages/{owner}/rpm/{group}/package/{package_name}/{package_version}/{architecture}
```
-| Parameter | Description |
-| ----------------- | ----------- |
-| `owner` | The owner of the package. |
-| `package_name` | The package name. |
-| `package_version` | The package version. |
-| `architecture` | The package architecture. |
+| Parameter | Description |
+|-------------------|----------------------------|
+| `owner` | The owner of the package. |
+| `group` | The package group . |
+| `package_name` | The package name. |
+| `package_version` | The package version. |
+| `architecture` | The package architecture. |
Example request using HTTP Basic authentication:
```shell
curl --user your_username:your_token_or_password -X DELETE \
- https://gitea.example.com/api/packages/testuser/rpm/test-package/1.0.0/x86_64
+ https://gitea.example.com/api/packages/testuser/rpm/centos/el7/package/test-package/1.0.0/x86_64
```
The server responds with the following HTTP Status codes.
要注册RPM注册表,请将 URL 添加到已知 `apt` 源列表中:
```shell
-dnf config-manager --add-repo https://gitea.example.com/api/packages/{owner}/rpm.repo
+dnf config-manager --add-repo https://gitea.example.com/api/packages/{owner}/rpm/{group}.repo
```
-| 占位符 | 描述 |
-| ------- | -------------- |
-| `owner` | 软件包的所有者 |
+| 占位符 | 描述 |
+| ------- |--------------------------------------|
+| `owner` | 软件包的所有者 |
+| `group` | 任何名称,例如 `centos/7`、`el-7`、`fc38` |
如果注册表是私有的,请在URL中提供凭据。您可以使用密码或[个人访问令牌](development/api-usage.md#通过-api-认证):
```shell
-dnf config-manager --add-repo https://{username}:{your_password_or_token}@gitea.example.com/api/packages/{owner}/rpm.repo
+dnf config-manager --add-repo https://{username}:{your_password_or_token}@gitea.example.com/api/packages/{owner}/rpm/{group}.repo
```
您还必须将凭据添加到 `/etc/yum.repos.d` 中的 `rpm.repo` 文件中的URL中。
要发布RPM软件包(`*.rpm`),请执行带有软件包内容的 HTTP `PUT` 操作。
```
-PUT https://gitea.example.com/api/packages/{owner}/rpm/upload
+PUT https://gitea.example.com/api/packages/{owner}/rpm/{group}/upload
```
| 参数 | 描述 |
-| ------- | -------------- |
-| `owner` | 软件包的所有者 |
+| ------- |--------------|
+| `owner` | 软件包的所有者 |
+| `group` | 软件包自定义分组名称 |
使用HTTP基本身份验证的示例请求:
```shell
curl --user your_username:your_password_or_token \
--upload-file path/to/file.rpm \
- https://gitea.example.com/api/packages/testuser/rpm/upload
+ https://gitea.example.com/api/packages/testuser/rpm/centos/el7/version/upload
```
如果您使用 2FA 或 OAuth,请使用[个人访问令牌](development/api-usage.md#通过-api-认证)替代密码。您无法将具有相同名称的文件两次发布到软件包中。您必须先删除现有的软件包版本。
要删除 RPM 软件包,请执行 HTTP `DELETE` 操作。如果没有文件剩余,这也将删除软件包版本。
```
-DELETE https://gitea.example.com/api/packages/{owner}/rpm/{package_name}/{package_version}/{architecture}
+DELETE https://gitea.example.com/api/packages/{owner}/rpm/{group}/package/{package_name}/{package_version}/{architecture}
```
| 参数 | 描述 |
| ----------------- | -------------- |
| `owner` | 软件包的所有者 |
+| `group` | 软件包自定义分组 |
| `package_name` | 软件包名称 |
| `package_version` | 软件包版本 |
| `architecture` | 软件包架构 |
```shell
curl --user your_username:your_token_or_password -X DELETE \
- https://gitea.example.com/api/packages/testuser/rpm/test-package/1.0.0/x86_64
+ https://gitea.example.com/api/packages/testuser/rpm/centos/el7/package/test-package/1.0.0/x86_64
```
服务器将以以下HTTP状态码响应:
)
const (
- PropertyMetadata = "rpm.metadata"
-
+ PropertyMetadata = "rpm.metadata"
SettingKeyPrivate = "rpm.key.private"
SettingKeyPublic = "rpm.key.public"
package templates
import (
+ "regexp"
"strings"
"code.gitea.io/gitea/modules/base"
return strings.Contains(s, substr)
}
+func (su *StringUtils) ReplaceAllStringRegex(s, regex, new string) string {
+ return regexp.MustCompile(regex).ReplaceAllString(s, new)
+}
+
func (su *StringUtils) Split(s, sep string) []string {
return strings.Split(s, sep)
}
r.Get("/files/{id}/{version}/{filename}", pypi.DownloadPackageFile)
r.Get("/simple/{id}", pypi.PackageMetadata)
}, reqPackageAccess(perm.AccessModeRead))
- r.Group("/rpm", func() {
- r.Get(".repo", rpm.GetRepositoryConfig)
- r.Get("/repository.key", rpm.GetRepositoryKey)
- r.Put("/upload", reqPackageAccess(perm.AccessModeWrite), rpm.UploadPackageFile)
- r.Group("/package/{name}/{version}/{architecture}", func() {
- r.Get("", rpm.DownloadPackageFile)
- r.Delete("", reqPackageAccess(perm.AccessModeWrite), rpm.DeletePackageFile)
- })
- r.Group("/repodata/{filename}", func() {
- r.Head("", rpm.CheckRepositoryFileExistence)
- r.Get("", rpm.GetRepositoryFile)
- })
- }, reqPackageAccess(perm.AccessModeRead))
+ r.Group("/rpm", RpmRoutes(r), reqPackageAccess(perm.AccessModeRead))
r.Group("/rubygems", func() {
r.Get("/specs.4.8.gz", rubygems.EnumeratePackages)
r.Get("/latest_specs.4.8.gz", rubygems.EnumeratePackagesLatest)
return r
}
+// Support for uploading rpm packages with arbitrary depth paths
+func RpmRoutes(r *web.Route) func() {
+ var (
+ groupRepoInfo = regexp.MustCompile(`\A((?:/(?:[^/]+))*|)\.repo\z`)
+ groupUpload = regexp.MustCompile(`\A((?:/(?:[^/]+))*|)/upload\z`)
+ groupRpm = regexp.MustCompile(`\A((?:/(?:[^/]+))*|)/package/([^/]+)/([^/]+)/([^/]+)(?:/([^/]+\.rpm)|)\z`)
+ groupMetadata = regexp.MustCompile(`\A((?:/(?:[^/]+))*|)/repodata/([^/]+)\z`)
+ )
+
+ return func() {
+ r.Methods("HEAD,GET,POST,PUT,PATCH,DELETE", "*", func(ctx *context.Context) {
+ path := ctx.Params("*")
+ isHead := ctx.Req.Method == "HEAD"
+ isGetHead := ctx.Req.Method == "HEAD" || ctx.Req.Method == "GET"
+ isPut := ctx.Req.Method == "PUT"
+ isDelete := ctx.Req.Method == "DELETE"
+
+ if path == "/repository.key" && isGetHead {
+ rpm.GetRepositoryKey(ctx)
+ return
+ }
+
+ // get repo
+ m := groupRepoInfo.FindStringSubmatch(path)
+ if len(m) == 2 && isGetHead {
+ ctx.SetParams("group", strings.Trim(m[1], "/"))
+ rpm.GetRepositoryConfig(ctx)
+ return
+ }
+ // get meta
+ m = groupMetadata.FindStringSubmatch(path)
+ if len(m) == 3 && isGetHead {
+ ctx.SetParams("group", strings.Trim(m[1], "/"))
+ ctx.SetParams("filename", m[2])
+ if isHead {
+ rpm.CheckRepositoryFileExistence(ctx)
+ } else {
+ rpm.GetRepositoryFile(ctx)
+ }
+ return
+ }
+ // upload
+ m = groupUpload.FindStringSubmatch(path)
+ if len(m) == 2 && isPut {
+ reqPackageAccess(perm.AccessModeWrite)(ctx)
+ if ctx.Written() {
+ return
+ }
+ ctx.SetParams("group", strings.Trim(m[1], "/"))
+ rpm.UploadPackageFile(ctx)
+ return
+ }
+ // rpm down/delete
+ m = groupRpm.FindStringSubmatch(path)
+ if len(m) == 6 {
+ ctx.SetParams("group", strings.Trim(m[1], "/"))
+ ctx.SetParams("name", m[2])
+ ctx.SetParams("version", m[3])
+ ctx.SetParams("architecture", m[4])
+ if isGetHead {
+ rpm.DownloadPackageFile(ctx)
+ return
+ } else if isDelete {
+ reqPackageAccess(perm.AccessModeWrite)(ctx)
+ if ctx.Written() {
+ return
+ }
+ rpm.DeletePackageFile(ctx)
+ }
+ }
+ // default
+ ctx.Status(http.StatusNotFound)
+ })
+ }
+}
+
// ContainerRoutes provides endpoints that implement the OCI API to serve containers
// These have to be mounted on `/v2/...` to comply with the OCI spec:
// https://github.com/opencontainers/distribution-spec/blob/main/spec.md
// https://dnf.readthedocs.io/en/latest/conf_ref.html
func GetRepositoryConfig(ctx *context.Context) {
+ group := ctx.Params("group")
+ if group != "" {
+ group = fmt.Sprintf("/%s", group)
+ }
url := fmt.Sprintf("%sapi/packages/%s/rpm", setting.AppURL, ctx.Package.Owner.Name)
-
- ctx.PlainText(http.StatusOK, `[gitea-`+ctx.Package.Owner.LowerName+`]
-name=`+ctx.Package.Owner.Name+` - `+setting.AppName+`
-baseurl=`+url+`
+ ctx.PlainText(http.StatusOK, `[gitea-`+ctx.Package.Owner.LowerName+strings.ReplaceAll(group, "/", "-")+`]
+name=`+ctx.Package.Owner.Name+` - `+setting.AppName+strings.ReplaceAll(group, "/", " - ")+`
+baseurl=`+url+group+`/
enabled=1
gpgcheck=1
gpgkey=`+url+`/repository.key`)
return
}
- pf, err := packages_model.GetFileForVersionByName(ctx, pv.ID, ctx.Params("filename"), packages_model.EmptyFileKey)
+ pf, err := packages_model.GetFileForVersionByName(ctx, pv.ID, ctx.Params("filename"), ctx.Params("group"))
if err != nil {
if errors.Is(err, util.ErrNotExist) {
ctx.Status(http.StatusNotFound)
ctx,
pv,
&packages_service.PackageFileInfo{
- Filename: ctx.Params("filename"),
+ Filename: ctx.Params("filename"),
+ CompositeKey: ctx.Params("group"),
},
)
if err != nil {
apiError(ctx, http.StatusInternalServerError, err)
return
}
-
+ group := ctx.Params("group")
_, _, err = packages_service.CreatePackageOrAddFileToExisting(
ctx,
&packages_service.PackageCreationInfo{
Owner: ctx.Package.Owner,
PackageType: packages_model.TypeRpm,
Name: pck.Name,
- Version: pck.Version,
+ Version: strings.Trim(fmt.Sprintf("%s/%s", group, pck.Version), "/"),
},
Creator: ctx.Doer,
Metadata: pck.VersionMetadata,
},
&packages_service.PackageFileCreationInfo{
PackageFileInfo: packages_service.PackageFileInfo{
- Filename: fmt.Sprintf("%s-%s.%s.rpm", pck.Name, pck.Version, pck.FileMetadata.Architecture),
+ Filename: fmt.Sprintf("%s-%s.%s.rpm", pck.Name, pck.Version, pck.FileMetadata.Architecture),
+ CompositeKey: group,
},
Creator: ctx.Doer,
Data: buf,
return
}
- if err := rpm_service.BuildRepositoryFiles(ctx, ctx.Package.Owner.ID); err != nil {
+ if err := rpm_service.BuildRepositoryFiles(ctx, ctx.Package.Owner.ID, group); err != nil {
apiError(ctx, http.StatusInternalServerError, err)
return
}
}
func DownloadPackageFile(ctx *context.Context) {
+ group := ctx.Params("group")
name := ctx.Params("name")
version := ctx.Params("version")
-
s, u, pf, err := packages_service.GetFileStreamByPackageNameAndVersion(
ctx,
&packages_service.PackageInfo{
Owner: ctx.Package.Owner,
PackageType: packages_model.TypeRpm,
Name: name,
- Version: version,
+ Version: strings.Trim(fmt.Sprintf("%s/%s", group, version), "/"),
},
&packages_service.PackageFileInfo{
- Filename: fmt.Sprintf("%s-%s.%s.rpm", name, version, ctx.Params("architecture")),
+ Filename: fmt.Sprintf("%s-%s.%s.rpm", name, version, ctx.Params("architecture")),
+ CompositeKey: group,
},
)
if err != nil {
}
func DeletePackageFile(webctx *context.Context) {
+ group := webctx.Params("group")
name := webctx.Params("name")
version := webctx.Params("version")
architecture := webctx.Params("architecture")
-
var pd *packages_model.PackageDescriptor
err := db.WithTx(webctx, func(ctx stdctx.Context) error {
- pv, err := packages_model.GetVersionByNameAndVersion(ctx, webctx.Package.Owner.ID, packages_model.TypeRpm, name, version)
+ pv, err := packages_model.GetVersionByNameAndVersion(ctx,
+ webctx.Package.Owner.ID,
+ packages_model.TypeRpm,
+ name,
+ strings.Trim(fmt.Sprintf("%s/%s", group, version), "/"),
+ )
if err != nil {
return err
}
ctx,
pv.ID,
fmt.Sprintf("%s-%s.%s.rpm", name, version, architecture),
- packages_model.EmptyFileKey,
+ group,
)
if err != nil {
return err
notify_service.PackageDelete(webctx, webctx.Doer, pd)
}
- if err := rpm_service.BuildRepositoryFiles(webctx, webctx.Package.Owner.ID); err != nil {
+ if err := rpm_service.BuildRepositoryFiles(webctx, webctx.Package.Owner.ID, group); err != nil {
apiError(webctx, http.StatusInternalServerError, err)
return
}
type packageCache = map[*packages_model.PackageFile]*packageData
-// BuildRepositoryFiles builds metadata files for the repository
-func BuildRepositoryFiles(ctx context.Context, ownerID int64) error {
+// BuildSpecificRepositoryFiles builds metadata files for the repository
+func BuildRepositoryFiles(ctx context.Context, ownerID int64, compositeKey string) error {
pv, err := GetOrCreateRepositoryVersion(ctx, ownerID)
if err != nil {
return err
}
pfs, _, err := packages_model.SearchFiles(ctx, &packages_model.PackageFileSearchOptions{
- OwnerID: ownerID,
- PackageType: packages_model.TypeRpm,
- Query: "%.rpm",
+ OwnerID: ownerID,
+ PackageType: packages_model.TypeRpm,
+ Query: "%.rpm",
+ CompositeKey: compositeKey,
})
if err != nil {
return err
cache[pf] = pd
}
- primary, err := buildPrimary(ctx, pv, pfs, cache)
+ primary, err := buildPrimary(ctx, pv, pfs, cache, compositeKey)
if err != nil {
return err
}
- filelists, err := buildFilelists(ctx, pv, pfs, cache)
+ filelists, err := buildFilelists(ctx, pv, pfs, cache, compositeKey)
if err != nil {
return err
}
- other, err := buildOther(ctx, pv, pfs, cache)
+ other, err := buildOther(ctx, pv, pfs, cache, compositeKey)
if err != nil {
return err
}
filelists,
other,
},
+ compositeKey,
)
}
// https://docs.pulpproject.org/en/2.19/plugins/pulp_rpm/tech-reference/rpm.html#repomd-xml
-func buildRepomd(ctx context.Context, pv *packages_model.PackageVersion, ownerID int64, data []*repoData) error {
+func buildRepomd(ctx context.Context, pv *packages_model.PackageVersion, ownerID int64, data []*repoData, compositeKey string) error {
type Repomd struct {
XMLName xml.Name `xml:"repomd"`
Xmlns string `xml:"xmlns,attr"`
pv,
&packages_service.PackageFileCreationInfo{
PackageFileInfo: packages_service.PackageFileInfo{
- Filename: file.Name,
+ Filename: file.Name,
+ CompositeKey: compositeKey,
},
Creator: user_model.NewGhostUser(),
Data: file.Data,
}
// https://docs.pulpproject.org/en/2.19/plugins/pulp_rpm/tech-reference/rpm.html#primary-xml
-func buildPrimary(ctx context.Context, pv *packages_model.PackageVersion, pfs []*packages_model.PackageFile, c packageCache) (*repoData, error) {
+func buildPrimary(ctx context.Context, pv *packages_model.PackageVersion, pfs []*packages_model.PackageFile, c packageCache, compositeKey string) (*repoData, error) {
type Version struct {
Epoch string `xml:"epoch,attr"`
Version string `xml:"ver,attr"`
files = append(files, f)
}
}
-
+ packageVersion := fmt.Sprintf("%s-%s", pd.FileMetadata.Version, pd.FileMetadata.Release)
packages = append(packages, &Package{
Type: "rpm",
Name: pd.Package.Name,
Archive: pd.FileMetadata.ArchiveSize,
},
Location: Location{
- Href: fmt.Sprintf("package/%s/%s/%s", url.PathEscape(pd.Package.Name), url.PathEscape(pd.Version.Version), url.PathEscape(pd.FileMetadata.Architecture)),
+ Href: fmt.Sprintf("package/%s/%s/%s/%s", url.PathEscape(pd.Package.Name), url.PathEscape(packageVersion), url.PathEscape(pd.FileMetadata.Architecture), url.PathEscape(fmt.Sprintf("%s-%s.%s.rpm", pd.Package.Name, packageVersion, pd.FileMetadata.Architecture))),
},
Format: Format{
License: pd.VersionMetadata.License,
XmlnsRpm: "http://linux.duke.edu/metadata/rpm",
PackageCount: len(pfs),
Packages: packages,
- })
+ }, compositeKey)
}
// https://docs.pulpproject.org/en/2.19/plugins/pulp_rpm/tech-reference/rpm.html#filelists-xml
-func buildFilelists(ctx context.Context, pv *packages_model.PackageVersion, pfs []*packages_model.PackageFile, c packageCache) (*repoData, error) { //nolint:dupl
+func buildFilelists(ctx context.Context, pv *packages_model.PackageVersion, pfs []*packages_model.PackageFile, c packageCache, compositeKey string) (*repoData, error) { //nolint:dupl
type Version struct {
Epoch string `xml:"epoch,attr"`
Version string `xml:"ver,attr"`
Xmlns: "http://linux.duke.edu/metadata/other",
PackageCount: len(pfs),
Packages: packages,
- })
+ },
+ compositeKey)
}
// https://docs.pulpproject.org/en/2.19/plugins/pulp_rpm/tech-reference/rpm.html#other-xml
-func buildOther(ctx context.Context, pv *packages_model.PackageVersion, pfs []*packages_model.PackageFile, c packageCache) (*repoData, error) { //nolint:dupl
+func buildOther(ctx context.Context, pv *packages_model.PackageVersion, pfs []*packages_model.PackageFile, c packageCache, compositeKey string) (*repoData, error) { //nolint:dupl
type Version struct {
Epoch string `xml:"epoch,attr"`
Version string `xml:"ver,attr"`
Xmlns: "http://linux.duke.edu/metadata/other",
PackageCount: len(pfs),
Packages: packages,
- })
+ }, compositeKey)
}
// writtenCounter counts all written bytes
return wc.written
}
-func addDataAsFileToRepo(ctx context.Context, pv *packages_model.PackageVersion, filetype string, obj any) (*repoData, error) {
+func addDataAsFileToRepo(ctx context.Context, pv *packages_model.PackageVersion, filetype string, obj any, compositeKey string) (*repoData, error) {
content, _ := packages_module.NewHashedBuffer()
- defer content.Close()
-
gzw := gzip.NewWriter(content)
wc := &writtenCounter{}
h := sha256.New()
pv,
&packages_service.PackageFileCreationInfo{
PackageFileInfo: packages_service.PackageFileInfo{
- Filename: filename,
+ Filename: filename,
+ CompositeKey: compositeKey,
},
Creator: user_model.NewGhostUser(),
Data: content,
<div class="ui form">
<div class="field">
<label>{{svg "octicon-terminal"}} {{ctx.Locale.Tr "packages.rpm.registry"}}</label>
- <div class="markup"><pre class="code-block"><code># {{ctx.Locale.Tr "packages.rpm.distro.redhat"}}
-dnf config-manager --add-repo <gitea-origin-url data-url="{{AppSubUrl}}/api/packages/{{$.PackageDescriptor.Owner.Name}}/rpm.repo"></gitea-origin-url>
+ <div class="markup"><pre class="code-block"><code># {{ctx.Locale.Tr "packages.rpm.distros.redhat"}}
+{{$group_name:= StringUtils.ReplaceAllStringRegex .PackageDescriptor.Version.Version "(/[^/]+|[^/]*)\\z" "" -}}
+{{- if $group_name -}}
+{{- $group_name = (print "/" $group_name) -}}
+{{- end -}}
+dnf config-manager --add-repo <gitea-origin-url data-url="{{AppSubUrl}}/api/packages/{{$.PackageDescriptor.Owner.Name}}/rpm{{$group_name}}.repo"></gitea-origin-url>
-# {{ctx.Locale.Tr "packages.rpm.distro.suse"}}
-zypper addrepo <gitea-origin-url data-url="{{AppSubUrl}}/api/packages/{{$.PackageDescriptor.Owner.Name}}/rpm.repo"></gitea-origin-url></code></pre></div>
+# {{ctx.Locale.Tr "packages.rpm.distros.suse"}}
+zypper addrepo <gitea-origin-url data-url="{{AppSubUrl}}/api/packages/{{$.PackageDescriptor.Owner.Name}}/rpm{{$group_name}}.repo"></gitea-origin-url></code></pre></div>
</div>
<div class="field">
<label>{{svg "octicon-terminal"}} {{ctx.Locale.Tr "packages.rpm.install"}}</label>
<div class="markup">
- <pre class="code-block"><code># {{ctx.Locale.Tr "packages.rpm.distro.redhat"}}
+ <pre class="code-block"><code># {{ctx.Locale.Tr "packages.rpm.distros.redhat"}}
dnf install {{$.PackageDescriptor.Package.Name}}
-# {{ctx.Locale.Tr "packages.rpm.distro.suse"}}
+# {{ctx.Locale.Tr "packages.rpm.distros.suse"}}
zypper install {{$.PackageDescriptor.Package.Name}}</code></pre>
</div>
</div>
t.Run("RepositoryConfig", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
- req := NewRequest(t, "GET", rootURL+".repo")
+ req := NewRequest(t, "GET", rootURL+"/el9/stable.repo")
resp := MakeRequest(t, req, http.StatusOK)
- expected := fmt.Sprintf(`[gitea-%s]
-name=%s - %s
-baseurl=%sapi/packages/%s/rpm
+ expected := fmt.Sprintf(`[gitea-%s-el9-stable]
+name=%s - %s - el9 - stable
+baseurl=%sapi/packages/%s/rpm/el9/stable/
enabled=1
gpgcheck=1
gpgkey=%sapi/packages/%s/rpm/repository.key`, user.Name, user.Name, setting.AppName, setting.AppURL, user.Name, setting.AppURL, user.Name)
})
t.Run("Upload", func(t *testing.T) {
- url := rootURL + "/upload"
+ url := rootURL + "/el9/stable/upload"
req := NewRequestWithBody(t, "PUT", url, bytes.NewReader(content))
MakeRequest(t, req, http.StatusUnauthorized)
assert.Nil(t, pd.SemVer)
assert.IsType(t, &rpm_module.VersionMetadata{}, pd.Metadata)
assert.Equal(t, packageName, pd.Package.Name)
- assert.Equal(t, packageVersion, pd.Version.Version)
+ assert.Equal(t, fmt.Sprintf("el9/stable/%s", packageVersion), pd.Version.Version)
pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID)
assert.NoError(t, err)
t.Run("Download", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
- req := NewRequest(t, "GET", fmt.Sprintf("%s/package/%s/%s/%s", rootURL, packageName, packageVersion, packageArchitecture))
+ req := NewRequest(t, "GET", fmt.Sprintf("%s/el9/stable/package/%s/%s/%s", rootURL, packageName, packageVersion, packageArchitecture))
resp := MakeRequest(t, req, http.StatusOK)
assert.Equal(t, content, resp.Body.Bytes())
t.Run("Repository", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
- url := rootURL + "/repodata"
+ url := rootURL + "/el9/stable/repodata"
req := NewRequest(t, "HEAD", url+"/dummy.xml")
MakeRequest(t, req, http.StatusNotFound)
switch d.Type {
case "primary":
- assert.EqualValues(t, 718, d.Size)
- assert.EqualValues(t, 1729, d.OpenSize)
+ assert.EqualValues(t, 722, d.Size)
+ assert.EqualValues(t, 1759, d.OpenSize)
assert.Equal(t, "repodata/primary.xml.gz", d.Location.Href)
case "filelists":
assert.EqualValues(t, 257, d.Size)
assert.EqualValues(t, len(content), p.Size.Package)
assert.EqualValues(t, 13, p.Size.Installed)
assert.EqualValues(t, 272, p.Size.Archive)
- assert.Equal(t, fmt.Sprintf("package/%s/%s/%s", packageName, packageVersion, packageArchitecture), p.Location.Href)
+ assert.Equal(t, fmt.Sprintf("package/%s/%s/%s/%s", packageName, packageVersion, packageArchitecture, fmt.Sprintf("%s-%s.%s.rpm", packageName, packageVersion, packageArchitecture)), p.Location.Href)
f := p.Format
assert.Equal(t, "MIT", f.License)
assert.Len(t, f.Provides.Entries, 2)
t.Run("Delete", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
- req := NewRequest(t, "DELETE", fmt.Sprintf("%s/package/%s/%s/%s", rootURL, packageName, packageVersion, packageArchitecture))
+ req := NewRequest(t, "DELETE", fmt.Sprintf("%s/el9/stable/package/%s/%s/%s", rootURL, packageName, packageVersion, packageArchitecture))
MakeRequest(t, req, http.StatusUnauthorized)
- req = NewRequest(t, "DELETE", fmt.Sprintf("%s/package/%s/%s/%s", rootURL, packageName, packageVersion, packageArchitecture)).
+ req = NewRequest(t, "DELETE", fmt.Sprintf("%s/el9/stable/package/%s/%s/%s", rootURL, packageName, packageVersion, packageArchitecture)).
AddBasicAuth(user.Name)
MakeRequest(t, req, http.StatusNoContent)
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeRpm)
assert.NoError(t, err)
assert.Empty(t, pvs)
-
- req = NewRequest(t, "DELETE", fmt.Sprintf("%s/package/%s/%s/%s", rootURL, packageName, packageVersion, packageArchitecture)).
+ req = NewRequest(t, "DELETE", fmt.Sprintf("%s/el9/stable/package/%s/%s/%s", rootURL, packageName, packageVersion, packageArchitecture)).
AddBasicAuth(user.Name)
MakeRequest(t, req, http.StatusNotFound)
})