Move package settings to package instead of being tied to version (#37026)

Unties settings page from package version and adds button to delete the
package version
Settings page now allows for deletion of entire package and it's
versions as opposed to a single version

Adds an API endpoint to delete the entire package with all versions from
registry

fixes: https://github.com/go-gitea/gitea/issues/36904

Co-Authored-By: gemini-3-flash

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Giteabot <teabot@gitea.io>
This commit is contained in:
TheFox0x7
2026-04-05 21:51:51 +02:00
committed by GitHub
parent a8938115d4
commit ca51b4f875
19 changed files with 477 additions and 45 deletions

View File

@@ -9,6 +9,7 @@ import (
"fmt"
"net/url"
"code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/cache"
@@ -53,8 +54,11 @@ func (l PackagePropertyList) GetByName(name string) string {
// PackageDescriptor describes a package
type PackageDescriptor struct {
Package *Package
Owner *user_model.User
// basic package info
Package *Package
Owner *user_model.User
// package version info
Repository *repo_model.Repository
Version *PackageVersion
SemVer *version.Version
@@ -77,6 +81,11 @@ func (pd *PackageDescriptor) PackageWebLink() string {
return fmt.Sprintf("%s/-/packages/%s/%s", pd.Owner.HomeLink(), string(pd.Package.Type), url.PathEscape(pd.Package.LowerName))
}
// PackageSettingsLink returns the relative package settings link
func (pd *PackageDescriptor) PackageSettingsLink() string {
return fmt.Sprintf("%s/-/packages/settings/%s/%s", pd.Owner.HomeLink(), string(pd.Package.Type), url.PathEscape(pd.Package.LowerName))
}
// VersionWebLink returns the relative package version web link
func (pd *PackageDescriptor) VersionWebLink() string {
return fmt.Sprintf("%s/%s", pd.PackageWebLink(), url.PathEscape(pd.Version.LowerVersion))
@@ -267,6 +276,15 @@ func GetPackageDescriptors(ctx context.Context, pvs []*PackageVersion) ([]*Packa
return getPackageDescriptors(ctx, pvs, cache.NewEphemeralCache())
}
// GetAllPackageDescriptors gets all package descriptors for a package
func GetAllPackageDescriptors(ctx context.Context, p *Package) ([]*PackageDescriptor, error) {
pvs := make([]*PackageVersion, 0, 10)
if err := db.GetEngine(ctx).Where("package_id = ?", p.ID).Find(&pvs); err != nil {
return nil, err
}
return getPackageDescriptors(ctx, pvs, cache.NewEphemeralCache())
}
func getPackageDescriptors(ctx context.Context, pvs []*PackageVersion, c *cache.EphemeralCache) ([]*PackageDescriptor, error) {
pds := make([]*PackageDescriptor, 0, len(pvs))
for _, pv := range pvs {

View File

@@ -115,6 +115,20 @@ func DeleteFileByID(ctx context.Context, fileID int64) error {
return err
}
// DeleteFilesByPackageID deletes all files of a specific package
// Versions must not be deleted prior to this call
func DeleteFilesByPackageID(ctx context.Context, packageID int64) error {
deleteStmt := builder.Delete(builder.In("version_id", builder.Select("package_version.id").From("package_version").Where(builder.Eq{"package_id": packageID}))).From("package_file")
_, err := db.GetEngine(ctx).Exec(deleteStmt)
return err
}
// DeleteFilesByVersionID deletes all files of a specific version
func DeleteFilesByVersionID(ctx context.Context, versionID int64) error {
_, err := db.GetEngine(ctx).Where("version_id = ?", versionID).Delete(&PackageFile{})
return err
}
func UpdateFile(ctx context.Context, pf *PackageFile, cols []string) error {
_, err := db.GetEngine(ctx).ID(pf.ID).Cols(cols...).Update(pf)
return err

View File

@@ -5,6 +5,7 @@ package packages
import (
"context"
"errors"
"code.gitea.io/gitea/models/db"
@@ -86,6 +87,46 @@ func DeleteAllProperties(ctx context.Context, refType PropertyType, refID int64)
return err
}
// DeletePropertiesByPackageID deletes properties of a typed linked to the package
// Use to avoid for loops in mass deletion of properties
func DeletePropertiesByPackageID(ctx context.Context, refType PropertyType, packageID int64) error {
var deleteStmt *builder.Builder
switch refType {
case PropertyTypeFile:
deleteStmt = builder.Delete(
// Delete all properties that are attached to a file and are in ids from a subquery
// which returns ids from the package_file table joined on package_version to link it with package id
builder.Eq{"ref_type": PropertyTypeFile}, builder.In("ref_id",
builder.Select("package_file.id").From("package_file").
LeftJoin("package_version", "package_file.version_id = package_version.id").
Where(builder.Eq{"package_version.package_id": packageID}))).From("package_property")
case PropertyTypeVersion:
// Delete all properties that are attached to a version and are in ids from subquery to the package_version filtered by package id
deleteStmt = builder.Delete(
builder.Eq{"ref_type": PropertyTypeVersion}, builder.In("ref_id",
builder.Select("package_version.id").From("package_version").
Where(builder.Eq{"package_version.package_id": packageID}))).From("package_property")
case PropertyTypePackage:
// Delete all properties that are attached to a package and their reference links to the given package ID
deleteStmt = builder.Delete(
builder.Eq{"ref_type": PropertyTypePackage}, builder.Eq{"ref_id": packageID}).
From("package_property")
default:
return errors.New("invalid ref type")
}
_, err := db.GetEngine(ctx).Exec(deleteStmt)
return err
}
// DeleteFilePropertiesByVersionID deletes all file properties linked to specific version
func DeleteFilePropertiesByVersionID(ctx context.Context, versionID int64) error {
deleteStmt := builder.Delete(builder.Eq{"ref_type": PropertyTypeFile}, builder.In("ref_id", builder.Select("id").From("package_file").Where(builder.Eq{"version_id": versionID}))).From("package_property")
_, err := db.GetEngine(ctx).Exec(deleteStmt)
return err
}
// DeletePropertyByID deletes a property
func DeletePropertyByID(ctx context.Context, propertyID int64) error {
_, err := db.GetEngine(ctx).ID(propertyID).Delete(&PackageProperty{})

View File

@@ -157,6 +157,12 @@ func DeleteVersionByID(ctx context.Context, versionID int64) error {
return err
}
// DeleteVersionsByPackageID deletes all versions of a specific package
func DeleteVersionsByPackageID(ctx context.Context, packageID int64) error {
_, err := db.GetEngine(ctx).Where(builder.Eq{"package_id": packageID}).Delete(&PackageVersion{})
return err
}
// HasVersionFileReferences checks if there are associated files
func HasVersionFileReferences(ctx context.Context, versionID int64) (bool, error) {
return db.GetEngine(ctx).Get(&PackageFile{