Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add uploading packages through the Web UI #26960

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
Open
15 changes: 15 additions & 0 deletions models/packages/package.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,21 @@ func (pt Type) SVGName() string {
panic(fmt.Sprintf("unknown package type: %s", string(pt)))
}

// String converts the package type to a string
func (pt Type) String() string {
return string(pt)
}

// GetPackageTypeByString returns the type for the given string
func GetPackageTypeByString(typeName string) *Type {
for _, currentType := range TypeList {
if currentType.String() == typeName {
return &currentType
}
}
return nil
}

// Package represents a package
type Package struct {
ID int64 `xorm:"pk autoincr"`
Expand Down
18 changes: 18 additions & 0 deletions options/locale/locale_en-US.ini
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@ confirm_delete_selected = Confirm to delete all selected items?
name = Name
value = Value

upload = Upload

[aria]
navbar = Navigation Bar
footer = Footer
Expand Down Expand Up @@ -3445,6 +3447,22 @@ owner.settings.cleanuprules.success.delete = Cleanup rule has been deleted.
owner.settings.chef.title = Chef Registry
owner.settings.chef.keypair = Generate key pair
owner.settings.chef.keypair.description = A key pair is necessary to authenticate to the Chef registry. If you have generated a key pair before, generating a new key pair will discard the old key pair.
upload.title = Upload %s Package
upload.branch.label = Branch:
upload.branch.placeholder = The branch to use
upload.repo.label = Repository:
upload.repo.placeholder = The repository to use
upload.file.label = File:
upload.distribution.label = Distribution:
upload.distribution.placeholder = The distribution may match the release name of the OS
upload.component.label = Component:
upload.component.placeholder = The component can be used to group packages or just main or similar
upload.name.label = Name:
upload.name.placeholder = Package name
upload.version.label = Version:
upload.version.placeholder = Package version
upload.filename.label = Filename:
upload.filename.placeholder = Filename (leave empty to use name from uploaded file)

[secrets]
secrets = Secrets
Expand Down
77 changes: 7 additions & 70 deletions routers/api/packages/alpine/alpine.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,11 @@ import (
"encoding/pem"
"errors"
"fmt"
"io"
"net/http"
"strings"

packages_model "code.gitea.io/gitea/models/packages"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/json"
packages_module "code.gitea.io/gitea/modules/packages"
alpine_module "code.gitea.io/gitea/modules/packages/alpine"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/routers/api/packages/helper"
packages_service "code.gitea.io/gitea/services/packages"
Expand Down Expand Up @@ -105,79 +101,20 @@ func UploadPackageFile(ctx *context.Context) {
defer upload.Close()
}

buf, err := packages_module.CreateHashedBufferFromReader(upload)
userError, _, err := alpine_service.UploadAlpinePackage(ctx, upload, branch, repository)
if err != nil {
apiError(ctx, http.StatusInternalServerError, err)
return
}
defer buf.Close()

pck, err := alpine_module.ParsePackage(buf)
if err != nil {
if errors.Is(err, util.ErrInvalidArgument) || err == io.EOF {
apiError(ctx, http.StatusBadRequest, err)
if userError {
if err == packages_service.ErrQuotaTotalCount || err == packages_service.ErrQuotaTypeSize || err == packages_service.ErrQuotaTotalSize {
apiError(ctx, http.StatusForbidden, err)
} else {
apiError(ctx, http.StatusBadRequest, err)
}
} else {
apiError(ctx, http.StatusInternalServerError, err)
}
return
}

if _, err := buf.Seek(0, io.SeekStart); err != nil {
apiError(ctx, http.StatusInternalServerError, err)
return
}

fileMetadataRaw, err := json.Marshal(pck.FileMetadata)
if err != nil {
apiError(ctx, http.StatusInternalServerError, err)
return
}

_, _, err = packages_service.CreatePackageOrAddFileToExisting(
ctx,
&packages_service.PackageCreationInfo{
PackageInfo: packages_service.PackageInfo{
Owner: ctx.Package.Owner,
PackageType: packages_model.TypeAlpine,
Name: pck.Name,
Version: pck.Version,
},
Creator: ctx.Doer,
Metadata: pck.VersionMetadata,
},
&packages_service.PackageFileCreationInfo{
PackageFileInfo: packages_service.PackageFileInfo{
Filename: fmt.Sprintf("%s-%s.apk", pck.Name, pck.Version),
CompositeKey: fmt.Sprintf("%s|%s|%s", branch, repository, pck.FileMetadata.Architecture),
},
Creator: ctx.Doer,
Data: buf,
IsLead: true,
Properties: map[string]string{
alpine_module.PropertyBranch: branch,
alpine_module.PropertyRepository: repository,
alpine_module.PropertyArchitecture: pck.FileMetadata.Architecture,
alpine_module.PropertyMetadata: string(fileMetadataRaw),
},
},
)
if err != nil {
switch err {
case packages_model.ErrDuplicatePackageVersion, packages_model.ErrDuplicatePackageFile:
apiError(ctx, http.StatusBadRequest, err)
case packages_service.ErrQuotaTotalCount, packages_service.ErrQuotaTypeSize, packages_service.ErrQuotaTotalSize:
apiError(ctx, http.StatusForbidden, err)
default:
apiError(ctx, http.StatusInternalServerError, err)
}
return
}

if err := alpine_service.BuildSpecificRepositoryFiles(ctx, ctx.Package.Owner.ID, branch, repository, pck.FileMetadata.Architecture); err != nil {
apiError(ctx, http.StatusInternalServerError, err)
return
}

ctx.Status(http.StatusCreated)
}

Expand Down
70 changes: 7 additions & 63 deletions routers/api/packages/debian/debian.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,12 @@ import (
stdctx "context"
"errors"
"fmt"
"io"
"net/http"
"strings"

"code.gitea.io/gitea/models/db"
packages_model "code.gitea.io/gitea/models/packages"
"code.gitea.io/gitea/modules/context"
packages_module "code.gitea.io/gitea/modules/packages"
debian_module "code.gitea.io/gitea/modules/packages/debian"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/routers/api/packages/helper"
notify_service "code.gitea.io/gitea/services/notify"
Expand Down Expand Up @@ -136,73 +133,20 @@ func UploadPackageFile(ctx *context.Context) {
defer upload.Close()
}

buf, err := packages_module.CreateHashedBufferFromReader(upload)
userError, _, err := debian_service.UploadDebianPackage(ctx, upload, distribution, component)
if err != nil {
apiError(ctx, http.StatusInternalServerError, err)
return
}
defer buf.Close()

pck, err := debian_module.ParsePackage(buf)
if err != nil {
if errors.Is(err, util.ErrInvalidArgument) {
apiError(ctx, http.StatusBadRequest, err)
if userError {
if err == packages_service.ErrQuotaTotalCount || err == packages_service.ErrQuotaTypeSize || err == packages_service.ErrQuotaTotalSize {
apiError(ctx, http.StatusForbidden, err)
} else {
apiError(ctx, http.StatusBadRequest, err)
}
} else {
apiError(ctx, http.StatusInternalServerError, err)
}
return
}

if _, err := buf.Seek(0, io.SeekStart); err != nil {
apiError(ctx, http.StatusInternalServerError, err)
return
}

_, _, err = packages_service.CreatePackageOrAddFileToExisting(
ctx,
&packages_service.PackageCreationInfo{
PackageInfo: packages_service.PackageInfo{
Owner: ctx.Package.Owner,
PackageType: packages_model.TypeDebian,
Name: pck.Name,
Version: pck.Version,
},
Creator: ctx.Doer,
Metadata: pck.Metadata,
},
&packages_service.PackageFileCreationInfo{
PackageFileInfo: packages_service.PackageFileInfo{
Filename: fmt.Sprintf("%s_%s_%s.deb", pck.Name, pck.Version, pck.Architecture),
CompositeKey: fmt.Sprintf("%s|%s", distribution, component),
},
Creator: ctx.Doer,
Data: buf,
IsLead: true,
Properties: map[string]string{
debian_module.PropertyDistribution: distribution,
debian_module.PropertyComponent: component,
debian_module.PropertyArchitecture: pck.Architecture,
debian_module.PropertyControl: pck.Control,
},
},
)
if err != nil {
switch err {
case packages_model.ErrDuplicatePackageVersion, packages_model.ErrDuplicatePackageFile:
apiError(ctx, http.StatusBadRequest, err)
case packages_service.ErrQuotaTotalCount, packages_service.ErrQuotaTypeSize, packages_service.ErrQuotaTotalSize:
apiError(ctx, http.StatusForbidden, err)
default:
apiError(ctx, http.StatusInternalServerError, err)
}
return
}

if err := debian_service.BuildSpecificRepositoryFiles(ctx, ctx.Package.Owner.ID, distribution, component, pck.Architecture); err != nil {
apiError(ctx, http.StatusInternalServerError, err)
return
}

ctx.Status(http.StatusCreated)
}

Expand Down
45 changes: 9 additions & 36 deletions routers/api/packages/generic/generic.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,9 @@ import (

packages_model "code.gitea.io/gitea/models/packages"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log"
packages_module "code.gitea.io/gitea/modules/packages"
"code.gitea.io/gitea/routers/api/packages/helper"
packages_service "code.gitea.io/gitea/services/packages"
generic_service "code.gitea.io/gitea/services/packages/generic"
)

var (
Expand Down Expand Up @@ -80,41 +79,15 @@ func UploadPackage(ctx *context.Context) {
defer upload.Close()
}

buf, err := packages_module.CreateHashedBufferFromReader(upload)
userError, _, err := generic_service.UploadGenericPackage(ctx, upload, packageName, packageVersion, filename)
if err != nil {
log.Error("Error creating hashed buffer: %v", err)
apiError(ctx, http.StatusInternalServerError, err)
return
}
defer buf.Close()

_, _, err = packages_service.CreatePackageOrAddFileToExisting(
ctx,
&packages_service.PackageCreationInfo{
PackageInfo: packages_service.PackageInfo{
Owner: ctx.Package.Owner,
PackageType: packages_model.TypeGeneric,
Name: packageName,
Version: packageVersion,
},
Creator: ctx.Doer,
},
&packages_service.PackageFileCreationInfo{
PackageFileInfo: packages_service.PackageFileInfo{
Filename: filename,
},
Creator: ctx.Doer,
Data: buf,
IsLead: true,
},
)
if err != nil {
switch err {
case packages_model.ErrDuplicatePackageFile:
apiError(ctx, http.StatusConflict, err)
case packages_service.ErrQuotaTotalCount, packages_service.ErrQuotaTypeSize, packages_service.ErrQuotaTotalSize:
apiError(ctx, http.StatusForbidden, err)
default:
if userError {
if err == packages_service.ErrQuotaTotalCount || err == packages_service.ErrQuotaTypeSize || err == packages_service.ErrQuotaTotalSize {
apiError(ctx, http.StatusForbidden, err)
} else {
apiError(ctx, http.StatusBadRequest, err)
}
} else {
apiError(ctx, http.StatusInternalServerError, err)
}
return
Expand Down
Loading
Loading