2014-04-14 01:57:25 -04:00
// Copyright 2014 The Gogs Authors. All rights reserved.
2019-09-22 10:05:48 +01:00
// Copyright 2019 The Gitea Authors. All rights reserved.
2022-11-27 13:20:29 -05:00
// SPDX-License-Identifier: MIT
2014-04-14 01:57:25 -04:00
2022-08-25 10:31:57 +08:00
package repo
2014-04-14 01:57:25 -04:00
import (
2021-09-23 16:45:36 +01:00
"context"
2015-11-20 02:38:41 -05:00
"fmt"
2024-03-01 15:11:51 +08:00
"html/template"
2023-04-12 11:05:23 +02:00
"net/url"
2014-06-12 17:47:23 -04:00
"sort"
2021-11-16 18:18:25 +00:00
"strconv"
2014-04-14 01:57:25 -04:00
"strings"
2021-09-19 19:49:59 +08:00
"code.gitea.io/gitea/models/db"
2021-11-24 17:49:20 +08:00
user_model "code.gitea.io/gitea/models/user"
2023-07-27 17:24:22 +08:00
"code.gitea.io/gitea/modules/container"
2024-02-28 06:39:12 +01:00
"code.gitea.io/gitea/modules/optional"
2019-10-14 14:10:42 +08:00
"code.gitea.io/gitea/modules/structs"
2019-08-15 22:46:21 +08:00
"code.gitea.io/gitea/modules/timeutil"
2021-06-17 10:58:10 +02:00
"code.gitea.io/gitea/modules/util"
2019-03-27 17:33:00 +08:00
2019-06-23 23:22:43 +08:00
"xorm.io/builder"
2014-04-14 01:57:25 -04:00
)
2022-08-25 10:31:57 +08:00
// ErrReleaseAlreadyExist represents a "ReleaseAlreadyExist" kind of error.
type ErrReleaseAlreadyExist struct {
TagName string
}
// IsErrReleaseAlreadyExist checks if an error is a ErrReleaseAlreadyExist.
func IsErrReleaseAlreadyExist ( err error ) bool {
_ , ok := err . ( ErrReleaseAlreadyExist )
return ok
}
func ( err ErrReleaseAlreadyExist ) Error ( ) string {
return fmt . Sprintf ( "release tag already exist [tag_name: %s]" , err . TagName )
}
2022-10-18 06:50:37 +01:00
func ( err ErrReleaseAlreadyExist ) Unwrap ( ) error {
return util . ErrAlreadyExist
}
2022-08-25 10:31:57 +08:00
// ErrReleaseNotExist represents a "ReleaseNotExist" kind of error.
type ErrReleaseNotExist struct {
ID int64
TagName string
}
// IsErrReleaseNotExist checks if an error is a ErrReleaseNotExist.
func IsErrReleaseNotExist ( err error ) bool {
_ , ok := err . ( ErrReleaseNotExist )
return ok
}
func ( err ErrReleaseNotExist ) Error ( ) string {
return fmt . Sprintf ( "release tag does not exist [id: %d, tag_name: %s]" , err . ID , err . TagName )
}
2022-10-18 06:50:37 +01:00
func ( err ErrReleaseNotExist ) Unwrap ( ) error {
return util . ErrNotExist
}
2014-04-14 01:57:25 -04:00
// Release represents a release of repository.
type Release struct {
2022-08-25 10:31:57 +08:00
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)" `
2019-10-05 19:09:27 +08:00
OriginalAuthor string
OriginalAuthorID int64 ` xorm:"index" `
2014-04-14 01:57:25 -04:00
LowerTagName string
2014-06-12 09:10:39 -04:00
Target string
2023-05-10 05:43:55 +02:00
TargetBehind string ` xorm:"-" ` // to handle non-existing or empty target
2014-06-12 17:47:23 -04:00
Title string
2024-01-19 16:05:02 +00:00
Sha1 string ` xorm:"VARCHAR(64)" `
2015-12-09 20:46:05 -05:00
NumCommits int64
2022-08-25 10:31:57 +08:00
NumCommitsBehind int64 ` xorm:"-" `
Note string ` xorm:"TEXT" `
2024-03-01 15:11:51 +08:00
RenderedNote template . HTML ` xorm:"-" `
2022-08-25 10:31:57 +08:00
IsDraft bool ` xorm:"NOT NULL DEFAULT false" `
IsPrerelease bool ` xorm:"NOT NULL DEFAULT false" `
2023-04-04 05:08:29 +08:00
IsTag bool ` xorm:"NOT NULL DEFAULT false" ` // will be true only if the record is a tag and has no related releases
2022-08-25 10:31:57 +08:00
Attachments [ ] * Attachment ` xorm:"-" `
CreatedUnix timeutil . TimeStamp ` xorm:"INDEX" `
2015-08-24 21:01:23 +08:00
}
2021-09-19 19:49:59 +08:00
func init ( ) {
db . RegisterModel ( new ( Release ) )
}
2022-11-19 09:12:33 +01:00
// LoadAttributes load repo and publisher attributes for a release
func ( r * Release ) LoadAttributes ( ctx context . Context ) error {
2016-12-31 11:51:22 -05:00
var err error
if r . Repo == nil {
2022-12-03 10:48:26 +08:00
r . Repo , err = GetRepositoryByID ( ctx , r . RepoID )
2016-12-31 11:51:22 -05:00
if err != nil {
return err
}
}
if r . Publisher == nil {
2022-12-03 10:48:26 +08:00
r . Publisher , err = user_model . GetUserByID ( ctx , r . PublisherID )
2016-12-31 11:51:22 -05:00
if err != nil {
2021-11-24 17:49:20 +08:00
if user_model . IsErrUserNotExist ( err ) {
r . Publisher = user_model . NewGhostUser ( )
2020-11-03 07:10:22 +08:00
} else {
return err
}
2016-12-31 11:51:22 -05:00
}
}
2022-05-20 22:08:52 +08:00
return GetReleaseAttachments ( ctx , r )
2016-12-31 11:51:22 -05:00
}
// APIURL the api url for a release. release must have attributes loaded
func ( r * Release ) APIURL ( ) string {
2021-11-16 18:18:25 +00:00
return r . Repo . APIURL ( ) + "/releases/" + strconv . FormatInt ( r . ID , 10 )
2016-12-31 11:51:22 -05:00
}
// ZipURL the zip url for a release. release must have attributes loaded
func ( r * Release ) ZipURL ( ) string {
2021-11-16 18:18:25 +00:00
return r . Repo . HTMLURL ( ) + "/archive/" + util . PathEscapeSegments ( r . TagName ) + ".zip"
2016-12-31 11:51:22 -05:00
}
// TarURL the tar.gz url for a release. release must have attributes loaded
func ( r * Release ) TarURL ( ) string {
2021-11-16 18:18:25 +00:00
return r . Repo . HTMLURL ( ) + "/archive/" + util . PathEscapeSegments ( r . TagName ) + ".tar.gz"
2016-12-31 11:51:22 -05:00
}
2020-04-18 09:47:15 -05:00
// HTMLURL the url for a release on the web UI. release must have attributes loaded
func ( r * Release ) HTMLURL ( ) string {
2021-11-16 18:18:25 +00:00
return r . Repo . HTMLURL ( ) + "/releases/tag/" + util . PathEscapeSegments ( r . TagName )
2020-04-18 09:47:15 -05:00
}
2023-08-24 12:36:10 +02:00
// APIUploadURL the api url to upload assets to a release. release must have attributes loaded
func ( r * Release ) APIUploadURL ( ) string {
return r . APIURL ( ) + "/assets"
}
2023-02-07 02:09:18 +08:00
// Link the relative url for a release on the web UI. release must have attributes loaded
func ( r * Release ) Link ( ) string {
return r . Repo . Link ( ) + "/releases/tag/" + util . PathEscapeSegments ( r . TagName )
}
2014-04-14 01:57:25 -04:00
// IsReleaseExist returns true if release with given tag name already exists.
2022-06-03 14:13:58 +08:00
func IsReleaseExist ( ctx context . Context , repoID int64 , tagName string ) ( bool , error ) {
2014-04-14 01:57:25 -04:00
if len ( tagName ) == 0 {
return false , nil
}
2022-06-03 14:13:58 +08:00
return db . GetEngine ( ctx ) . Exist ( & Release { RepoID : repoID , LowerTagName : strings . ToLower ( tagName ) } )
2020-02-03 16:47:04 +08:00
}
2019-09-15 23:28:25 +08:00
// UpdateRelease updates all columns of a release
2021-09-23 16:45:36 +01:00
func UpdateRelease ( ctx context . Context , rel * Release ) error {
_ , err := db . GetEngine ( ctx ) . ID ( rel . ID ) . AllCols ( ) . Update ( rel )
2019-09-15 23:28:25 +08:00
return err
2014-06-12 17:47:23 -04:00
}
2019-09-15 23:28:25 +08:00
// AddReleaseAttachments adds a release attachments
2021-09-23 16:45:36 +01:00
func AddReleaseAttachments ( ctx context . Context , releaseID int64 , attachmentUUIDs [ ] string ) ( err error ) {
2017-01-15 14:57:00 +00:00
// Check attachments
2022-08-25 10:31:57 +08:00
attachments , err := GetAttachmentsByUUIDs ( ctx , attachmentUUIDs )
2019-12-11 01:01:52 +01:00
if err != nil {
2022-10-24 21:29:17 +02:00
return fmt . Errorf ( "GetAttachmentsByUUIDs [uuids: %v]: %w" , attachmentUUIDs , err )
2017-01-15 14:57:00 +00:00
}
for i := range attachments {
2021-03-23 00:09:51 +08:00
if attachments [ i ] . ReleaseID != 0 {
2022-12-31 12:49:37 +01:00
return util . NewPermissionDeniedErrorf ( "release permission denied" )
2021-03-23 00:09:51 +08:00
}
2017-01-15 14:57:00 +00:00
attachments [ i ] . ReleaseID = releaseID
// No assign value could be 0, so ignore AllCols().
2021-09-23 16:45:36 +01:00
if _ , err = db . GetEngine ( ctx ) . ID ( attachments [ i ] . ID ) . Update ( attachments [ i ] ) ; err != nil {
2022-10-24 21:29:17 +02:00
return fmt . Errorf ( "update attachment [%d]: %w" , attachments [ i ] . ID , err )
2017-01-15 14:57:00 +00:00
}
}
2022-06-20 12:02:49 +02:00
return err
2017-01-15 14:57:00 +00:00
}
2014-06-12 17:47:23 -04:00
// GetRelease returns release by given ID.
2023-09-25 15:17:37 +02:00
func GetRelease ( ctx context . Context , repoID int64 , tagName string ) ( * Release , error ) {
2022-06-03 14:13:58 +08:00
rel := & Release { RepoID : repoID , LowerTagName : strings . ToLower ( tagName ) }
2023-09-25 15:17:37 +02:00
has , err := db . GetEngine ( ctx ) . Get ( rel )
2014-06-12 17:47:23 -04:00
if err != nil {
return nil , err
2022-06-03 14:13:58 +08:00
} else if ! has {
2015-11-20 02:38:41 -05:00
return nil , ErrReleaseNotExist { 0 , tagName }
2014-06-12 17:47:23 -04:00
}
2022-06-03 14:13:58 +08:00
return rel , nil
2014-06-12 17:47:23 -04:00
}
2015-11-20 02:38:41 -05:00
// GetReleaseByID returns release with given ID.
2022-06-03 14:13:58 +08:00
func GetReleaseByID ( ctx context . Context , id int64 ) ( * Release , error ) {
2015-11-20 02:38:41 -05:00
rel := new ( Release )
2022-06-03 14:13:58 +08:00
has , err := db . GetEngine ( ctx ) .
2017-10-04 21:43:04 -07:00
ID ( id ) .
2016-11-10 16:16:32 +01:00
Get ( rel )
2015-11-20 02:38:41 -05:00
if err != nil {
return nil , err
} else if ! has {
return nil , ErrReleaseNotExist { id , "" }
}
return rel , nil
}
2023-11-26 01:21:21 +08:00
// GetReleaseForRepoByID returns release with given ID.
func GetReleaseForRepoByID ( ctx context . Context , repoID , id int64 ) ( * Release , error ) {
rel := new ( Release )
has , err := db . GetEngine ( ctx ) .
Where ( "id=? AND repo_id=?" , id , repoID ) .
Get ( rel )
if err != nil {
return nil , err
} else if ! has {
return nil , ErrReleaseNotExist { id , "" }
}
return rel , nil
}
2017-06-29 18:11:38 +03:00
// FindReleasesOptions describes the conditions to Find releases
type FindReleasesOptions struct {
2021-09-24 19:32:56 +08:00
db . ListOptions
2024-01-15 10:19:25 +08:00
RepoID int64
2017-06-29 18:11:38 +03:00
IncludeDrafts bool
2017-09-20 08:26:49 +03:00
IncludeTags bool
2024-02-28 06:39:12 +01:00
IsPreRelease optional . Option [ bool ]
IsDraft optional . Option [ bool ]
2017-06-29 18:11:38 +03:00
TagNames [ ] string
2024-02-28 06:39:12 +01:00
HasSha1 optional . Option [ bool ] // useful to find draft releases which are created with existing tags
2014-06-12 17:47:23 -04:00
}
2024-01-15 10:19:25 +08:00
func ( opts FindReleasesOptions ) ToConds ( ) builder . Cond {
var cond builder . Cond = builder . Eq { "repo_id" : opts . RepoID }
2017-06-28 16:47:00 +02:00
2017-06-29 18:11:38 +03:00
if ! opts . IncludeDrafts {
cond = cond . And ( builder . Eq { "is_draft" : false } )
2017-06-28 16:47:00 +02:00
}
2017-09-20 08:26:49 +03:00
if ! opts . IncludeTags {
cond = cond . And ( builder . Eq { "is_tag" : false } )
}
2017-06-29 18:11:38 +03:00
if len ( opts . TagNames ) > 0 {
cond = cond . And ( builder . In ( "tag_name" , opts . TagNames ) )
}
2024-02-28 06:39:12 +01:00
if opts . IsPreRelease . Has ( ) {
cond = cond . And ( builder . Eq { "is_prerelease" : opts . IsPreRelease . Value ( ) } )
2021-06-17 10:58:10 +02:00
}
2024-02-28 06:39:12 +01:00
if opts . IsDraft . Has ( ) {
cond = cond . And ( builder . Eq { "is_draft" : opts . IsDraft . Value ( ) } )
2021-06-17 10:58:10 +02:00
}
2024-02-28 06:39:12 +01:00
if opts . HasSha1 . Has ( ) {
if opts . HasSha1 . Value ( ) {
2022-10-03 20:05:53 +08:00
cond = cond . And ( builder . Neq { "sha1" : "" } )
} else {
cond = cond . And ( builder . Eq { "sha1" : "" } )
}
}
2017-06-29 18:11:38 +03:00
return cond
2017-06-28 16:47:00 +02:00
}
2024-01-15 10:19:25 +08:00
func ( opts FindReleasesOptions ) ToOrders ( ) string {
return "created_unix DESC, id DESC"
2017-01-06 09:51:15 +08:00
}
2023-03-17 01:01:10 +08:00
// GetTagNamesByRepoID returns a list of release tag names of repository.
func GetTagNamesByRepoID ( ctx context . Context , repoID int64 ) ( [ ] string , error ) {
listOptions := db . ListOptions {
ListAll : true ,
}
opts := FindReleasesOptions {
ListOptions : listOptions ,
IncludeDrafts : true ,
IncludeTags : true ,
2024-02-28 06:39:12 +01:00
HasSha1 : optional . Some ( true ) ,
2024-01-15 10:19:25 +08:00
RepoID : repoID ,
2023-03-17 01:01:10 +08:00
}
tags := make ( [ ] string , 0 )
sess := db . GetEngine ( ctx ) .
Table ( "release" ) .
Desc ( "created_unix" , "id" ) .
2024-01-15 10:19:25 +08:00
Where ( opts . ToConds ( ) ) .
2023-03-17 01:01:10 +08:00
Cols ( "tag_name" )
return tags , sess . Find ( & tags )
}
2020-04-18 09:47:15 -05:00
// GetLatestReleaseByRepoID returns the latest release for a repository
2023-09-25 15:17:37 +02:00
func GetLatestReleaseByRepoID ( ctx context . Context , repoID int64 ) ( * Release , error ) {
2020-04-18 09:47:15 -05:00
cond := builder . NewCond ( ) .
And ( builder . Eq { "repo_id" : repoID } ) .
And ( builder . Eq { "is_draft" : false } ) .
And ( builder . Eq { "is_prerelease" : false } ) .
And ( builder . Eq { "is_tag" : false } )
rel := new ( Release )
2023-09-25 15:17:37 +02:00
has , err := db . GetEngine ( ctx ) .
2020-04-18 09:47:15 -05:00
Desc ( "created_unix" , "id" ) .
Where ( cond ) .
Get ( rel )
if err != nil {
return nil , err
} else if ! has {
return nil , ErrReleaseNotExist { 0 , "latest" }
}
return rel , nil
}
2017-01-15 14:57:00 +00:00
type releaseMetaSearch struct {
2017-01-17 06:58:58 +01:00
ID [ ] int64
Rel [ ] * Release
2017-01-15 14:57:00 +00:00
}
2017-01-17 06:58:58 +01:00
2017-01-15 14:57:00 +00:00
func ( s releaseMetaSearch ) Len ( ) int {
return len ( s . ID )
}
2021-03-15 02:52:12 +08:00
2017-01-15 14:57:00 +00:00
func ( s releaseMetaSearch ) Swap ( i , j int ) {
s . ID [ i ] , s . ID [ j ] = s . ID [ j ] , s . ID [ i ]
s . Rel [ i ] , s . Rel [ j ] = s . Rel [ j ] , s . Rel [ i ]
}
2021-03-15 02:52:12 +08:00
2017-01-15 14:57:00 +00:00
func ( s releaseMetaSearch ) Less ( i , j int ) bool {
return s . ID [ i ] < s . ID [ j ]
}
2023-07-27 17:24:22 +08:00
func hasDuplicateName ( attaches [ ] * Attachment ) bool {
attachSet := container . Set [ string ] { }
for _ , attachment := range attaches {
if attachSet . Contains ( attachment . Name ) {
return true
}
attachSet . Add ( attachment . Name )
}
return false
}
2017-01-15 14:57:00 +00:00
// GetReleaseAttachments retrieves the attachments for releases
2022-05-20 22:08:52 +08:00
func GetReleaseAttachments ( ctx context . Context , rels ... * Release ) ( err error ) {
2017-01-15 14:57:00 +00:00
if len ( rels ) == 0 {
2023-07-04 17:52:33 +02:00
return nil
2017-01-15 14:57:00 +00:00
}
2017-01-17 06:58:58 +01:00
// To keep this efficient as possible sort all releases by id,
2017-01-15 14:57:00 +00:00
// select attachments by release id,
// then merge join them
// Sort
2021-03-15 02:52:12 +08:00
sortedRels := releaseMetaSearch { ID : make ( [ ] int64 , len ( rels ) ) , Rel : make ( [ ] * Release , len ( rels ) ) }
2022-08-25 10:31:57 +08:00
var attachments [ ] * Attachment
2017-01-15 14:57:00 +00:00
for index , element := range rels {
2022-08-25 10:31:57 +08:00
element . Attachments = [ ] * Attachment { }
2017-01-15 14:57:00 +00:00
sortedRels . ID [ index ] = element . ID
sortedRels . Rel [ index ] = element
}
sort . Sort ( sortedRels )
// Select attachments
2022-05-20 22:08:52 +08:00
err = db . GetEngine ( ctx ) .
2021-03-17 09:25:49 +00:00
Asc ( "release_id" , "name" ) .
2017-01-15 14:57:00 +00:00
In ( "release_id" , sortedRels . ID ) .
2023-07-27 17:24:22 +08:00
Find ( & attachments )
2017-01-15 14:57:00 +00:00
if err != nil {
return err
}
// merge join
2021-03-15 02:52:12 +08:00
currentIndex := 0
2017-01-15 14:57:00 +00:00
for _ , attachment := range attachments {
for sortedRels . ID [ currentIndex ] < attachment . ReleaseID {
currentIndex ++
}
sortedRels . Rel [ currentIndex ] . Attachments = append ( sortedRels . Rel [ currentIndex ] . Attachments , attachment )
}
2023-04-12 11:05:23 +02:00
// Makes URL's predictable
for _ , release := range rels {
// If we have no Repo, we don't need to execute this loop
if release . Repo == nil {
continue
}
// If the names unique, use the URL with the Name instead of the UUID
2023-07-27 17:24:22 +08:00
if ! hasDuplicateName ( release . Attachments ) {
2023-04-12 11:05:23 +02:00
for _ , attachment := range release . Attachments {
attachment . CustomDownloadURL = release . Repo . HTMLURL ( ) + "/releases/download/" + url . PathEscape ( release . TagName ) + "/" + url . PathEscape ( attachment . Name )
}
}
}
2022-06-20 12:02:49 +02:00
return err
2017-01-15 14:57:00 +00:00
}
2016-11-25 09:11:12 +01:00
type releaseSorter struct {
2014-06-12 17:47:23 -04:00
rels [ ] * Release
}
2016-11-25 09:11:12 +01:00
func ( rs * releaseSorter ) Len ( ) int {
2014-06-12 17:47:23 -04:00
return len ( rs . rels )
}
2016-11-25 09:11:12 +01:00
func ( rs * releaseSorter ) Less ( i , j int ) bool {
2014-06-12 17:47:23 -04:00
diffNum := rs . rels [ i ] . NumCommits - rs . rels [ j ] . NumCommits
if diffNum != 0 {
return diffNum > 0
2014-04-14 01:57:25 -04:00
}
2017-12-11 12:37:04 +08:00
return rs . rels [ i ] . CreatedUnix > rs . rels [ j ] . CreatedUnix
2014-06-12 17:47:23 -04:00
}
2014-04-14 01:57:25 -04:00
2016-11-25 09:11:12 +01:00
func ( rs * releaseSorter ) Swap ( i , j int ) {
2014-06-12 17:47:23 -04:00
rs . rels [ i ] , rs . rels [ j ] = rs . rels [ j ] , rs . rels [ i ]
}
// SortReleases sorts releases by number of commits and created time.
func SortReleases ( rels [ ] * Release ) {
2016-11-25 09:11:12 +01:00
sorter := & releaseSorter { rels : rels }
2014-06-12 17:47:23 -04:00
sort . Sort ( sorter )
}
2019-10-14 14:10:42 +08:00
// UpdateReleasesMigrationsByType updates all migrated repositories' releases from gitServiceType to replace originalAuthorID to posterID
2023-09-25 15:17:37 +02:00
func UpdateReleasesMigrationsByType ( ctx context . Context , gitServiceType structs . GitServiceType , originalAuthorID string , posterID int64 ) error {
_ , err := db . GetEngine ( ctx ) . Table ( "release" ) .
2019-10-14 14:10:42 +08:00
Where ( "repo_id IN (SELECT id FROM repository WHERE original_service_type = ?)" , gitServiceType ) .
And ( "original_author_id = ?" , originalAuthorID ) .
2023-07-04 20:36:08 +02:00
Update ( map [ string ] any {
2019-10-14 14:10:42 +08:00
"publisher_id" : posterID ,
"original_author" : "" ,
"original_author_id" : 0 ,
} )
return err
}
2021-12-12 23:48:20 +08:00
// PushUpdateDeleteTagsContext updates a number of delete tags with context
2022-08-25 10:31:57 +08:00
func PushUpdateDeleteTagsContext ( ctx context . Context , repo * Repository , tags [ ] string ) error {
2021-12-12 23:48:20 +08:00
if len ( tags ) == 0 {
return nil
}
lowerTags := make ( [ ] string , 0 , len ( tags ) )
for _ , tag := range tags {
lowerTags = append ( lowerTags , strings . ToLower ( tag ) )
}
2022-05-20 22:08:52 +08:00
if _ , err := db . GetEngine ( ctx ) .
2021-12-12 23:48:20 +08:00
Where ( "repo_id = ? AND is_tag = ?" , repo . ID , true ) .
In ( "lower_tag_name" , lowerTags ) .
Delete ( new ( Release ) ) ; err != nil {
2022-10-24 21:29:17 +02:00
return fmt . Errorf ( "Delete: %w" , err )
2021-12-12 23:48:20 +08:00
}
2022-05-20 22:08:52 +08:00
if _ , err := db . GetEngine ( ctx ) .
2021-12-12 23:48:20 +08:00
Where ( "repo_id = ? AND is_tag = ?" , repo . ID , false ) .
In ( "lower_tag_name" , lowerTags ) .
Cols ( "is_draft" , "num_commits" , "sha1" ) .
Update ( & Release {
IsDraft : true ,
} ) ; err != nil {
2022-10-24 21:29:17 +02:00
return fmt . Errorf ( "Update: %w" , err )
2021-12-12 23:48:20 +08:00
}
return nil
}
// PushUpdateDeleteTag must be called for any push actions to delete tag
2023-09-25 15:17:37 +02:00
func PushUpdateDeleteTag ( ctx context . Context , repo * Repository , tagName string ) error {
rel , err := GetRelease ( ctx , repo . ID , tagName )
2021-12-12 23:48:20 +08:00
if err != nil {
if IsErrReleaseNotExist ( err ) {
return nil
}
2022-10-24 21:29:17 +02:00
return fmt . Errorf ( "GetRelease: %w" , err )
2021-12-12 23:48:20 +08:00
}
if rel . IsTag {
2023-12-25 21:25:29 +01:00
if _ , err = db . DeleteByID [ Release ] ( ctx , rel . ID ) ; err != nil {
2022-10-24 21:29:17 +02:00
return fmt . Errorf ( "Delete: %w" , err )
2021-12-12 23:48:20 +08:00
}
} else {
rel . IsDraft = true
rel . NumCommits = 0
rel . Sha1 = ""
2023-09-25 15:17:37 +02:00
if _ , err = db . GetEngine ( ctx ) . ID ( rel . ID ) . AllCols ( ) . Update ( rel ) ; err != nil {
2022-10-24 21:29:17 +02:00
return fmt . Errorf ( "Update: %w" , err )
2021-12-12 23:48:20 +08:00
}
}
return nil
}
// SaveOrUpdateTag must be called for any push actions to add tag
2023-09-25 15:17:37 +02:00
func SaveOrUpdateTag ( ctx context . Context , repo * Repository , newRel * Release ) error {
rel , err := GetRelease ( ctx , repo . ID , newRel . TagName )
2021-12-12 23:48:20 +08:00
if err != nil && ! IsErrReleaseNotExist ( err ) {
2022-10-24 21:29:17 +02:00
return fmt . Errorf ( "GetRelease: %w" , err )
2021-12-12 23:48:20 +08:00
}
if rel == nil {
rel = newRel
2023-09-25 15:17:37 +02:00
if _ , err = db . GetEngine ( ctx ) . Insert ( rel ) ; err != nil {
2022-10-24 21:29:17 +02:00
return fmt . Errorf ( "InsertOne: %w" , err )
2021-12-12 23:48:20 +08:00
}
} else {
rel . Sha1 = newRel . Sha1
rel . CreatedUnix = newRel . CreatedUnix
rel . NumCommits = newRel . NumCommits
rel . IsDraft = false
if rel . IsTag && newRel . PublisherID > 0 {
rel . PublisherID = newRel . PublisherID
}
2023-09-25 15:17:37 +02:00
if _ , err = db . GetEngine ( ctx ) . ID ( rel . ID ) . AllCols ( ) . Update ( rel ) ; err != nil {
2022-10-24 21:29:17 +02:00
return fmt . Errorf ( "Update: %w" , err )
2021-12-12 23:48:20 +08:00
}
}
return nil
}
2022-02-01 19:20:28 +01:00
// RemapExternalUser ExternalUserRemappable interface
func ( r * Release ) RemapExternalUser ( externalName string , externalID , userID int64 ) error {
r . OriginalAuthor = externalName
r . OriginalAuthorID = externalID
r . PublisherID = userID
return nil
}
// UserID ExternalUserRemappable interface
func ( r * Release ) GetUserID ( ) int64 { return r . PublisherID }
// ExternalName ExternalUserRemappable interface
func ( r * Release ) GetExternalName ( ) string { return r . OriginalAuthor }
// ExternalID ExternalUserRemappable interface
func ( r * Release ) GetExternalID ( ) int64 { return r . OriginalAuthorID }
2023-09-09 05:09:23 +08:00
// InsertReleases migrates release
2023-09-25 15:17:37 +02:00
func InsertReleases ( ctx context . Context , rels ... * Release ) error {
ctx , committer , err := db . TxContext ( ctx )
2023-09-09 05:09:23 +08:00
if err != nil {
return err
}
defer committer . Close ( )
sess := db . GetEngine ( ctx )
for _ , rel := range rels {
if _ , err := sess . NoAutoTime ( ) . Insert ( rel ) ; err != nil {
return err
}
if len ( rel . Attachments ) > 0 {
for i := range rel . Attachments {
rel . Attachments [ i ] . ReleaseID = rel . ID
}
if _ , err := sess . NoAutoTime ( ) . Insert ( rel . Attachments ) ; err != nil {
return err
}
}
}
return committer . Commit ( )
}