Count downloads for tag archives
This commit is contained in:
parent
f8a5d6872c
commit
613e5387c5
22 changed files with 469 additions and 95 deletions
87
models/repo/archive_download_count.go
Normal file
87
models/repo/archive_download_count.go
Normal file
|
@ -0,0 +1,87 @@
|
|||
// Copyright 2024 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package repo
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
)
|
||||
|
||||
// RepoArchiveDownloadCount counts all archive downloads for a tag
|
||||
type RepoArchiveDownloadCount struct { //nolint:revive
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
RepoID int64 `xorm:"index unique(s)"`
|
||||
ReleaseID int64 `xorm:"index unique(s)"`
|
||||
Type git.ArchiveType `xorm:"unique(s)"`
|
||||
Count int64
|
||||
}
|
||||
|
||||
func init() {
|
||||
db.RegisterModel(new(RepoArchiveDownloadCount))
|
||||
}
|
||||
|
||||
// CountArchiveDownload adds one download the the given archive
|
||||
func CountArchiveDownload(ctx context.Context, repoID, releaseID int64, tp git.ArchiveType) error {
|
||||
updateCount, err := db.GetEngine(ctx).Where("repo_id = ?", repoID).And("release_id = ?", releaseID).And("`type` = ?", tp).Incr("count").Update(new(RepoArchiveDownloadCount))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if updateCount != 0 {
|
||||
// The count was updated, so we can exit
|
||||
return nil
|
||||
}
|
||||
|
||||
// The archive does not esxists in the databse, so let's add it
|
||||
newCounter := &RepoArchiveDownloadCount{
|
||||
RepoID: repoID,
|
||||
ReleaseID: releaseID,
|
||||
Type: tp,
|
||||
Count: 1,
|
||||
}
|
||||
|
||||
_, err = db.GetEngine(ctx).Insert(newCounter)
|
||||
return err
|
||||
}
|
||||
|
||||
// GetArchiveDownloadCount returns the download count of a tag
|
||||
func GetArchiveDownloadCount(ctx context.Context, repoID, releaseID int64) (*api.TagArchiveDownloadCount, error) {
|
||||
downloadCountList := make([]RepoArchiveDownloadCount, 0)
|
||||
err := db.GetEngine(ctx).Where("repo_id = ?", repoID).And("release_id = ?", releaseID).Find(&downloadCountList)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tagCounter := new(api.TagArchiveDownloadCount)
|
||||
|
||||
for _, singleCount := range downloadCountList {
|
||||
switch singleCount.Type {
|
||||
case git.ZIP:
|
||||
tagCounter.Zip = singleCount.Count
|
||||
case git.TARGZ:
|
||||
tagCounter.TarGz = singleCount.Count
|
||||
}
|
||||
}
|
||||
|
||||
return tagCounter, nil
|
||||
}
|
||||
|
||||
// GetDownloadCountForTagName returns the download count of a tag with the given name
|
||||
func GetArchiveDownloadCountForTagName(ctx context.Context, repoID int64, tagName string) (*api.TagArchiveDownloadCount, error) {
|
||||
release, err := GetRelease(ctx, repoID, tagName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return GetArchiveDownloadCount(ctx, repoID, release.ID)
|
||||
}
|
||||
|
||||
// DeleteArchiveDownloadCountForRelease deletes the release from the repo_archive_download_count table
|
||||
func DeleteArchiveDownloadCountForRelease(ctx context.Context, releaseID int64) error {
|
||||
_, err := db.GetEngine(ctx).Delete(&RepoArchiveDownloadCount{ReleaseID: releaseID})
|
||||
return err
|
||||
}
|
65
models/repo/archive_download_count_test.go
Normal file
65
models/repo/archive_download_count_test.go
Normal file
|
@ -0,0 +1,65 @@
|
|||
// Copyright 2024 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package repo_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestRepoArchiveDownloadCount(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
release, err := repo_model.GetReleaseByID(db.DefaultContext, 1)
|
||||
require.NoError(t, err)
|
||||
|
||||
// We have no count, so it should return 0
|
||||
downloadCount, err := repo_model.GetArchiveDownloadCount(db.DefaultContext, release.RepoID, release.ID)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, int64(0), downloadCount.Zip)
|
||||
assert.Equal(t, int64(0), downloadCount.TarGz)
|
||||
|
||||
// Set the TarGz counter to 1
|
||||
err = repo_model.CountArchiveDownload(db.DefaultContext, release.RepoID, release.ID, git.TARGZ)
|
||||
require.NoError(t, err)
|
||||
|
||||
downloadCount, err = repo_model.GetArchiveDownloadCountForTagName(db.DefaultContext, release.RepoID, release.TagName)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, int64(0), downloadCount.Zip)
|
||||
assert.Equal(t, int64(1), downloadCount.TarGz)
|
||||
|
||||
// Set the TarGz counter to 2
|
||||
err = repo_model.CountArchiveDownload(db.DefaultContext, release.RepoID, release.ID, git.TARGZ)
|
||||
require.NoError(t, err)
|
||||
|
||||
downloadCount, err = repo_model.GetArchiveDownloadCountForTagName(db.DefaultContext, release.RepoID, release.TagName)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, int64(0), downloadCount.Zip)
|
||||
assert.Equal(t, int64(2), downloadCount.TarGz)
|
||||
|
||||
// Set the Zip counter to 1
|
||||
err = repo_model.CountArchiveDownload(db.DefaultContext, release.RepoID, release.ID, git.ZIP)
|
||||
require.NoError(t, err)
|
||||
|
||||
downloadCount, err = repo_model.GetArchiveDownloadCountForTagName(db.DefaultContext, release.RepoID, release.TagName)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, int64(1), downloadCount.Zip)
|
||||
assert.Equal(t, int64(2), downloadCount.TarGz)
|
||||
|
||||
// Delete the count
|
||||
err = repo_model.DeleteArchiveDownloadCountForRelease(db.DefaultContext, release.ID)
|
||||
require.NoError(t, err)
|
||||
|
||||
downloadCount, err = repo_model.GetArchiveDownloadCountForTagName(db.DefaultContext, release.RepoID, release.TagName)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, int64(0), downloadCount.Zip)
|
||||
assert.Equal(t, int64(0), downloadCount.TarGz)
|
||||
}
|
|
@ -35,6 +35,7 @@ type RepoArchiver struct { //revive:disable-line:exported
|
|||
Status ArchiverStatus
|
||||
CommitID string `xorm:"VARCHAR(64) unique(s)"`
|
||||
CreatedUnix timeutil.TimeStamp `xorm:"INDEX NOT NULL created"`
|
||||
ReleaseID int64 `xorm:"-"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
|
|
@ -65,28 +65,29 @@ func (err ErrReleaseNotExist) Unwrap() error {
|
|||
|
||||
// Release represents a release of repository.
|
||||
type Release struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
RepoID int64 `xorm:"INDEX UNIQUE(n)"`
|
||||
Repo *Repository `xorm:"-"`
|
||||
PublisherID int64 `xorm:"INDEX"`
|
||||
Publisher *user_model.User `xorm:"-"`
|
||||
TagName string `xorm:"INDEX UNIQUE(n)"`
|
||||
OriginalAuthor string
|
||||
OriginalAuthorID int64 `xorm:"index"`
|
||||
LowerTagName string
|
||||
Target string
|
||||
TargetBehind string `xorm:"-"` // to handle non-existing or empty target
|
||||
Title string
|
||||
Sha1 string `xorm:"VARCHAR(64)"`
|
||||
NumCommits int64
|
||||
NumCommitsBehind int64 `xorm:"-"`
|
||||
Note string `xorm:"TEXT"`
|
||||
RenderedNote template.HTML `xorm:"-"`
|
||||
IsDraft bool `xorm:"NOT NULL DEFAULT false"`
|
||||
IsPrerelease bool `xorm:"NOT NULL DEFAULT false"`
|
||||
IsTag bool `xorm:"NOT NULL DEFAULT false"` // will be true only if the record is a tag and has no related releases
|
||||
Attachments []*Attachment `xorm:"-"`
|
||||
CreatedUnix timeutil.TimeStamp `xorm:"INDEX"`
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
RepoID int64 `xorm:"INDEX UNIQUE(n)"`
|
||||
Repo *Repository `xorm:"-"`
|
||||
PublisherID int64 `xorm:"INDEX"`
|
||||
Publisher *user_model.User `xorm:"-"`
|
||||
TagName string `xorm:"INDEX UNIQUE(n)"`
|
||||
OriginalAuthor string
|
||||
OriginalAuthorID int64 `xorm:"index"`
|
||||
LowerTagName string
|
||||
Target string
|
||||
TargetBehind string `xorm:"-"` // to handle non-existing or empty target
|
||||
Title string
|
||||
Sha1 string `xorm:"VARCHAR(64)"`
|
||||
NumCommits int64
|
||||
NumCommitsBehind int64 `xorm:"-"`
|
||||
Note string `xorm:"TEXT"`
|
||||
RenderedNote template.HTML `xorm:"-"`
|
||||
IsDraft bool `xorm:"NOT NULL DEFAULT false"`
|
||||
IsPrerelease bool `xorm:"NOT NULL DEFAULT false"`
|
||||
IsTag bool `xorm:"NOT NULL DEFAULT false"` // will be true only if the record is a tag and has no related releases
|
||||
Attachments []*Attachment `xorm:"-"`
|
||||
CreatedUnix timeutil.TimeStamp `xorm:"INDEX"`
|
||||
ArchiveDownloadCount *structs.TagArchiveDownloadCount `xorm:"-"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
@ -112,9 +113,22 @@ func (r *Release) LoadAttributes(ctx context.Context) error {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
err = r.LoadArchiveDownloadCount(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return GetReleaseAttachments(ctx, r)
|
||||
}
|
||||
|
||||
// LoadArchiveDownloadCount loads the download count for the source archives
|
||||
func (r *Release) LoadArchiveDownloadCount(ctx context.Context) error {
|
||||
var err error
|
||||
r.ArchiveDownloadCount, err = GetArchiveDownloadCount(ctx, r.RepoID, r.ID)
|
||||
return err
|
||||
}
|
||||
|
||||
// APIURL the api url for a release. release must have attributes loaded
|
||||
func (r *Release) APIURL() string {
|
||||
return r.Repo.APIURL() + "/releases/" + strconv.FormatInt(r.ID, 10)
|
||||
|
@ -447,6 +461,18 @@ func PushUpdateDeleteTagsContext(ctx context.Context, repo *Repository, tags []s
|
|||
lowerTags = append(lowerTags, strings.ToLower(tag))
|
||||
}
|
||||
|
||||
for _, tag := range tags {
|
||||
release, err := GetRelease(ctx, repo.ID, tag)
|
||||
if err != nil {
|
||||
return fmt.Errorf("GetRelease: %w", err)
|
||||
}
|
||||
|
||||
err = DeleteArchiveDownloadCountForRelease(ctx, release.ID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("DeleteTagArchiveDownloadCount: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := db.GetEngine(ctx).
|
||||
Where("repo_id = ? AND is_tag = ?", repo.ID, true).
|
||||
In("lower_tag_name", lowerTags).
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue