2014-04-14 09:57:25 +04:00
// Copyright 2014 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package models
import (
2015-11-20 10:38:41 +03:00
"fmt"
2014-06-13 01:47:23 +04:00
"sort"
2014-04-14 09:57:25 +04:00
"strings"
2019-03-27 12:33:00 +03:00
"code.gitea.io/gitea/modules/git"
2018-05-16 17:01:55 +03:00
"code.gitea.io/gitea/modules/log"
2016-11-10 19:24:48 +03:00
"code.gitea.io/gitea/modules/process"
2016-12-31 19:51:22 +03:00
"code.gitea.io/gitea/modules/setting"
2019-05-11 13:21:34 +03:00
api "code.gitea.io/gitea/modules/structs"
2017-12-11 07:37:04 +03:00
"code.gitea.io/gitea/modules/util"
2019-03-27 12:33:00 +03:00
2019-06-23 18:22:43 +03:00
"xorm.io/builder"
2014-04-14 09:57:25 +04:00
)
// Release represents a release of repository.
type Release struct {
2017-01-06 04:51:15 +03:00
ID int64 ` xorm:"pk autoincr" `
2017-01-06 18:14:33 +03:00
RepoID int64 ` xorm:"INDEX UNIQUE(n)" `
2016-12-31 19:51:22 +03:00
Repo * Repository ` xorm:"-" `
2017-01-06 18:14:33 +03:00
PublisherID int64 ` xorm:"INDEX" `
Publisher * User ` xorm:"-" `
TagName string ` xorm:"INDEX UNIQUE(n)" `
2014-04-14 09:57:25 +04:00
LowerTagName string
2014-06-12 17:10:39 +04:00
Target string
2014-06-13 01:47:23 +04:00
Title string
2014-06-12 17:10:39 +04:00
Sha1 string ` xorm:"VARCHAR(40)" `
2015-12-10 04:46:05 +03:00
NumCommits int64
2017-12-11 07:37:04 +03:00
NumCommitsBehind int64 ` xorm:"-" `
Note string ` xorm:"TEXT" `
IsDraft bool ` xorm:"NOT NULL DEFAULT false" `
IsPrerelease bool ` xorm:"NOT NULL DEFAULT false" `
IsTag bool ` xorm:"NOT NULL DEFAULT false" `
Attachments [ ] * Attachment ` xorm:"-" `
2018-02-21 04:38:03 +03:00
CreatedUnix util . TimeStamp ` xorm:"INDEX" `
2015-08-24 16:01:23 +03:00
}
2016-12-31 19:51:22 +03:00
func ( r * Release ) loadAttributes ( e Engine ) error {
var err error
if r . Repo == nil {
r . Repo , err = GetRepositoryByID ( r . RepoID )
if err != nil {
return err
}
}
if r . Publisher == nil {
2019-06-12 22:41:28 +03:00
r . Publisher , err = getUserByID ( e , r . PublisherID )
2016-12-31 19:51:22 +03:00
if err != nil {
return err
}
}
2019-06-12 22:41:28 +03:00
return getReleaseAttachments ( e , r )
2016-12-31 19:51:22 +03:00
}
2017-03-15 03:52:01 +03:00
// LoadAttributes load repo and publisher attributes for a release
2016-12-31 19:51:22 +03:00
func ( r * Release ) LoadAttributes ( ) error {
return r . loadAttributes ( x )
}
// APIURL the api url for a release. release must have attributes loaded
func ( r * Release ) APIURL ( ) string {
return fmt . Sprintf ( "%sapi/v1/%s/releases/%d" ,
setting . AppURL , r . Repo . FullName ( ) , r . ID )
}
// ZipURL the zip url for a release. release must have attributes loaded
func ( r * Release ) ZipURL ( ) string {
return fmt . Sprintf ( "%s/archive/%s.zip" , r . Repo . HTMLURL ( ) , r . TagName )
}
// TarURL the tar.gz url for a release. release must have attributes loaded
func ( r * Release ) TarURL ( ) string {
return fmt . Sprintf ( "%s/archive/%s.tar.gz" , r . Repo . HTMLURL ( ) , r . TagName )
}
// APIFormat convert a Release to api.Release
func ( r * Release ) APIFormat ( ) * api . Release {
2018-03-06 04:22:16 +03:00
assets := make ( [ ] * api . Attachment , 0 )
for _ , att := range r . Attachments {
assets = append ( assets , att . APIFormat ( ) )
}
2016-12-31 19:51:22 +03:00
return & api . Release {
ID : r . ID ,
TagName : r . TagName ,
Target : r . Target ,
2018-08-26 18:24:33 +03:00
Title : r . Title ,
2016-12-31 19:51:22 +03:00
Note : r . Note ,
URL : r . APIURL ( ) ,
TarURL : r . TarURL ( ) ,
ZipURL : r . ZipURL ( ) ,
IsDraft : r . IsDraft ,
IsPrerelease : r . IsPrerelease ,
2017-12-11 07:37:04 +03:00
CreatedAt : r . CreatedUnix . AsTime ( ) ,
PublishedAt : r . CreatedUnix . AsTime ( ) ,
2016-12-31 19:51:22 +03:00
Publisher : r . Publisher . APIFormat ( ) ,
2018-03-06 04:22:16 +03:00
Attachments : assets ,
2016-12-31 19:51:22 +03:00
}
}
2014-04-14 09:57:25 +04:00
// IsReleaseExist returns true if release with given tag name already exists.
2015-11-16 07:52:46 +03:00
func IsReleaseExist ( repoID int64 , tagName string ) ( bool , error ) {
2014-04-14 09:57:25 +04:00
if len ( tagName ) == 0 {
return false , nil
}
2015-11-16 07:52:46 +03:00
return x . Get ( & Release { RepoID : repoID , LowerTagName : strings . ToLower ( tagName ) } )
2014-04-14 09:57:25 +04:00
}
2014-06-13 01:47:23 +04:00
func createTag ( gitRepo * git . Repository , rel * Release ) error {
// Only actual create when publish.
if ! rel . IsDraft {
if ! gitRepo . IsTagExist ( rel . TagName ) {
2018-10-15 06:52:52 +03:00
commit , err := gitRepo . GetCommit ( rel . Target )
2014-06-13 01:47:23 +04:00
if err != nil {
2018-10-15 06:52:52 +03:00
return fmt . Errorf ( "GetCommit: %v" , err )
2014-06-13 01:47:23 +04:00
}
2016-07-23 10:59:19 +03:00
// Trim '--' prefix to prevent command line argument vulnerability.
2016-05-06 22:40:41 +03:00
rel . TagName = strings . TrimPrefix ( rel . TagName , "--" )
2015-11-04 06:49:06 +03:00
if err = gitRepo . CreateTag ( rel . TagName , commit . ID . String ( ) ) ; err != nil {
2016-07-23 10:59:19 +03:00
if strings . Contains ( err . Error ( ) , "is not a valid tag name" ) {
return ErrInvalidTagName { rel . TagName }
}
2014-06-13 01:47:23 +04:00
return err
}
2017-09-20 08:26:49 +03:00
rel . LowerTagName = strings . ToLower ( rel . TagName )
}
commit , err := gitRepo . GetTagCommit ( rel . TagName )
if err != nil {
return fmt . Errorf ( "GetTagCommit: %v" , err )
}
2014-06-13 01:47:23 +04:00
2017-09-20 08:26:49 +03:00
rel . Sha1 = commit . ID . String ( )
2017-12-11 07:37:04 +03:00
rel . CreatedUnix = util . TimeStamp ( commit . Author . When . Unix ( ) )
2017-09-20 08:26:49 +03:00
rel . NumCommits , err = commit . CommitsCount ( )
if err != nil {
return fmt . Errorf ( "CommitsCount: %v" , err )
2014-06-13 01:47:23 +04:00
}
2018-02-21 04:38:03 +03:00
} else {
rel . CreatedUnix = util . TimeStampNow ( )
2014-06-13 01:47:23 +04:00
}
return nil
}
2017-01-15 17:57:00 +03:00
func addReleaseAttachments ( releaseID int64 , attachmentUUIDs [ ] string ) ( err error ) {
// Check attachments
2017-01-17 08:58:58 +03:00
var attachments = make ( [ ] * Attachment , 0 )
2017-01-15 17:57:00 +03:00
for _ , uuid := range attachmentUUIDs {
attach , err := getAttachmentByUUID ( x , uuid )
if err != nil {
if IsErrAttachmentNotExist ( err ) {
continue
}
return fmt . Errorf ( "getAttachmentByUUID [%s]: %v" , uuid , err )
}
attachments = append ( attachments , attach )
}
for i := range attachments {
attachments [ i ] . ReleaseID = releaseID
// No assign value could be 0, so ignore AllCols().
2017-10-05 07:43:04 +03:00
if _ , err = x . ID ( attachments [ i ] . ID ) . Update ( attachments [ i ] ) ; err != nil {
2017-01-15 17:57:00 +03:00
return fmt . Errorf ( "update attachment [%d]: %v" , attachments [ i ] . ID , err )
}
}
return
}
2014-04-14 09:57:25 +04:00
// CreateRelease creates a new release of repository.
2017-01-15 17:57:00 +03:00
func CreateRelease ( gitRepo * git . Repository , rel * Release , attachmentUUIDs [ ] string ) error {
2015-11-16 07:52:46 +03:00
isExist , err := IsReleaseExist ( rel . RepoID , rel . TagName )
2014-04-14 09:57:25 +04:00
if err != nil {
return err
} else if isExist {
2015-11-16 07:52:46 +03:00
return ErrReleaseAlreadyExist { rel . TagName }
2014-04-14 09:57:25 +04:00
}
2014-06-13 01:47:23 +04:00
if err = createTag ( gitRepo , rel ) ; err != nil {
return err
}
rel . LowerTagName = strings . ToLower ( rel . TagName )
2017-01-15 17:57:00 +03:00
2014-06-21 08:51:41 +04:00
_ , err = x . InsertOne ( rel )
2017-01-15 17:57:00 +03:00
if err != nil {
return err
}
err = addReleaseAttachments ( rel . ID , attachmentUUIDs )
2018-05-16 17:01:55 +03:00
if err != nil {
return err
}
2017-01-15 17:57:00 +03:00
2018-05-16 17:01:55 +03:00
if ! rel . IsDraft {
if err := rel . LoadAttributes ( ) ; err != nil {
2019-04-02 10:48:31 +03:00
log . Error ( "LoadAttributes: %v" , err )
2018-05-16 17:01:55 +03:00
} else {
2018-11-28 14:26:14 +03:00
mode , _ := AccessLevel ( rel . Publisher , rel . Repo )
2018-05-16 17:01:55 +03:00
if err := PrepareWebhooks ( rel . Repo , HookEventRelease , & api . ReleasePayload {
Action : api . HookReleasePublished ,
Release : rel . APIFormat ( ) ,
Repository : rel . Repo . APIFormat ( mode ) ,
Sender : rel . Publisher . APIFormat ( ) ,
} ) ; err != nil {
2019-04-02 10:48:31 +03:00
log . Error ( "PrepareWebhooks: %v" , err )
2018-05-21 05:28:29 +03:00
} else {
go HookQueue . Add ( rel . Repo . ID )
2018-05-16 17:01:55 +03:00
}
}
}
return nil
2014-06-13 01:47:23 +04:00
}
2014-06-12 17:10:39 +04:00
2014-06-13 01:47:23 +04:00
// GetRelease returns release by given ID.
2015-11-16 07:52:46 +03:00
func GetRelease ( repoID int64 , tagName string ) ( * Release , error ) {
isExist , err := IsReleaseExist ( repoID , tagName )
2014-06-13 01:47:23 +04:00
if err != nil {
return nil , err
} else if ! isExist {
2015-11-20 10:38:41 +03:00
return nil , ErrReleaseNotExist { 0 , tagName }
2014-06-13 01:47:23 +04:00
}
2014-04-14 09:57:25 +04:00
2015-11-16 07:52:46 +03:00
rel := & Release { RepoID : repoID , LowerTagName : strings . ToLower ( tagName ) }
2014-06-21 08:51:41 +04:00
_ , err = x . Get ( rel )
2014-06-13 01:47:23 +04:00
return rel , err
}
2015-11-20 10:38:41 +03:00
// GetReleaseByID returns release with given ID.
func GetReleaseByID ( id int64 ) ( * Release , error ) {
rel := new ( Release )
2016-11-10 18:16:32 +03:00
has , err := x .
2017-10-05 07:43:04 +03:00
ID ( id ) .
2016-11-10 18:16:32 +03:00
Get ( rel )
2015-11-20 10:38:41 +03:00
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 {
IncludeDrafts bool
2017-09-20 08:26:49 +03:00
IncludeTags bool
2017-06-29 18:11:38 +03:00
TagNames [ ] string
2014-06-13 01:47:23 +04:00
}
2017-06-29 18:11:38 +03:00
func ( opts * FindReleasesOptions ) toConds ( repoID int64 ) builder . Cond {
2017-06-28 17:47:00 +03:00
var cond = builder . NewCond ( )
cond = cond . And ( builder . Eq { "repo_id" : repoID } )
2017-06-29 18:11:38 +03:00
if ! opts . IncludeDrafts {
cond = cond . And ( builder . Eq { "is_draft" : false } )
2017-06-28 17:47:00 +03: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 ) )
}
return cond
2017-06-28 17:47:00 +03:00
}
2017-06-29 18:11:38 +03:00
// GetReleasesByRepoID returns a list of releases of repository.
func GetReleasesByRepoID ( repoID int64 , opts FindReleasesOptions , page , pageSize int ) ( rels [ ] * Release , err error ) {
if page <= 0 {
page = 1
}
2017-01-06 04:51:15 +03:00
err = x .
2017-06-29 18:11:38 +03:00
Desc ( "created_unix" , "id" ) .
Limit ( pageSize , ( page - 1 ) * pageSize ) .
Where ( opts . toConds ( repoID ) ) .
Find ( & rels )
2017-01-06 04:51:15 +03:00
return rels , err
}
2019-01-07 01:37:30 +03:00
// GetReleasesByRepoIDAndNames returns a list of releases of repository according repoID and tagNames.
func GetReleasesByRepoIDAndNames ( repoID int64 , tagNames [ ] string ) ( rels [ ] * Release , err error ) {
err = x .
Desc ( "created_unix" ) .
In ( "tag_name" , tagNames ) .
Find ( & rels , Release { RepoID : repoID } )
return rels , err
}
2017-06-29 18:11:38 +03:00
// GetReleaseCountByRepoID returns the count of releases of repository
func GetReleaseCountByRepoID ( repoID int64 , opts FindReleasesOptions ) ( int64 , error ) {
return x . Where ( opts . toConds ( repoID ) ) . Count ( & Release { } )
}
2017-01-15 17:57:00 +03:00
type releaseMetaSearch struct {
2017-01-17 08:58:58 +03:00
ID [ ] int64
Rel [ ] * Release
2017-01-15 17:57:00 +03:00
}
2017-01-17 08:58:58 +03:00
2017-01-15 17:57:00 +03:00
func ( s releaseMetaSearch ) Len ( ) int {
return len ( s . ID )
}
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 ]
}
func ( s releaseMetaSearch ) Less ( i , j int ) bool {
return s . ID [ i ] < s . ID [ j ]
}
// GetReleaseAttachments retrieves the attachments for releases
2017-01-17 08:58:58 +03:00
func GetReleaseAttachments ( rels ... * Release ) ( err error ) {
2019-06-12 22:41:28 +03:00
return getReleaseAttachments ( x , rels ... )
}
func getReleaseAttachments ( e Engine , rels ... * Release ) ( err error ) {
2017-01-15 17:57:00 +03:00
if len ( rels ) == 0 {
return
}
2017-01-17 08:58:58 +03:00
// To keep this efficient as possible sort all releases by id,
2017-01-15 17:57:00 +03:00
// select attachments by release id,
// then merge join them
// Sort
var sortedRels = releaseMetaSearch { ID : make ( [ ] int64 , len ( rels ) ) , Rel : make ( [ ] * Release , len ( rels ) ) }
2017-01-17 08:58:58 +03:00
var attachments [ ] * Attachment
2017-01-15 17:57:00 +03:00
for index , element := range rels {
element . Attachments = [ ] * Attachment { }
sortedRels . ID [ index ] = element . ID
sortedRels . Rel [ index ] = element
}
sort . Sort ( sortedRels )
// Select attachments
2019-06-12 22:41:28 +03:00
err = e .
2017-01-15 17:57:00 +03:00
Asc ( "release_id" ) .
In ( "release_id" , sortedRels . ID ) .
Find ( & attachments , Attachment { } )
if err != nil {
return err
}
// merge join
var currentIndex = 0
for _ , attachment := range attachments {
for sortedRels . ID [ currentIndex ] < attachment . ReleaseID {
currentIndex ++
}
sortedRels . Rel [ currentIndex ] . Attachments = append ( sortedRels . Rel [ currentIndex ] . Attachments , attachment )
}
return
}
2016-11-25 11:11:12 +03:00
type releaseSorter struct {
2014-06-13 01:47:23 +04:00
rels [ ] * Release
}
2016-11-25 11:11:12 +03:00
func ( rs * releaseSorter ) Len ( ) int {
2014-06-13 01:47:23 +04:00
return len ( rs . rels )
}
2016-11-25 11:11:12 +03:00
func ( rs * releaseSorter ) Less ( i , j int ) bool {
2014-06-13 01:47:23 +04:00
diffNum := rs . rels [ i ] . NumCommits - rs . rels [ j ] . NumCommits
if diffNum != 0 {
return diffNum > 0
2014-04-14 09:57:25 +04:00
}
2017-12-11 07:37:04 +03:00
return rs . rels [ i ] . CreatedUnix > rs . rels [ j ] . CreatedUnix
2014-06-13 01:47:23 +04:00
}
2014-04-14 09:57:25 +04:00
2016-11-25 11:11:12 +03:00
func ( rs * releaseSorter ) Swap ( i , j int ) {
2014-06-13 01: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 11:11:12 +03:00
sorter := & releaseSorter { rels : rels }
2014-06-13 01:47:23 +04:00
sort . Sort ( sorter )
}
// UpdateRelease updates information of a release.
2018-05-21 05:28:29 +03:00
func UpdateRelease ( doer * User , gitRepo * git . Repository , rel * Release , attachmentUUIDs [ ] string ) ( err error ) {
2014-06-13 01:47:23 +04:00
if err = createTag ( gitRepo , rel ) ; err != nil {
return err
}
2017-09-20 08:26:49 +03:00
rel . LowerTagName = strings . ToLower ( rel . TagName )
2017-10-05 07:43:04 +03:00
_ , err = x . ID ( rel . ID ) . AllCols ( ) . Update ( rel )
2017-01-15 17:57:00 +03:00
if err != nil {
return err
}
2018-05-21 05:28:29 +03:00
err = rel . loadAttributes ( x )
if err != nil {
return err
}
2017-01-15 17:57:00 +03:00
err = addReleaseAttachments ( rel . ID , attachmentUUIDs )
2018-11-28 14:26:14 +03:00
mode , _ := AccessLevel ( doer , rel . Repo )
2018-05-21 05:28:29 +03:00
if err1 := PrepareWebhooks ( rel . Repo , HookEventRelease , & api . ReleasePayload {
Action : api . HookReleaseUpdated ,
Release : rel . APIFormat ( ) ,
Repository : rel . Repo . APIFormat ( mode ) ,
Sender : rel . Publisher . APIFormat ( ) ,
} ) ; err1 != nil {
2019-04-02 10:48:31 +03:00
log . Error ( "PrepareWebhooks: %v" , err )
2018-05-21 05:28:29 +03:00
} else {
go HookQueue . Add ( rel . Repo . ID )
}
2014-04-14 09:57:25 +04:00
return err
}
2015-11-20 10:38:41 +03:00
// DeleteReleaseByID deletes a release and corresponding Git tag by given ID.
2016-12-31 14:51:12 +03:00
func DeleteReleaseByID ( id int64 , u * User , delTag bool ) error {
2015-11-20 10:38:41 +03:00
rel , err := GetReleaseByID ( id )
if err != nil {
return fmt . Errorf ( "GetReleaseByID: %v" , err )
}
repo , err := GetRepositoryByID ( rel . RepoID )
if err != nil {
return fmt . Errorf ( "GetRepositoryByID: %v" , err )
}
2016-12-31 14:51:12 +03:00
if delTag {
2017-01-17 08:58:58 +03:00
_ , stderr , err := process . GetManager ( ) . ExecDir ( - 1 , repo . RepoPath ( ) ,
2016-12-31 14:51:12 +03:00
fmt . Sprintf ( "DeleteReleaseByID (git tag -d): %d" , rel . ID ) ,
2019-06-26 21:15:26 +03:00
git . GitExecutable , "tag" , "-d" , rel . TagName )
2016-12-31 14:51:12 +03:00
if err != nil && ! strings . Contains ( stderr , "not found" ) {
return fmt . Errorf ( "git tag -d: %v - %s" , err , stderr )
}
2015-11-20 10:38:41 +03:00
2017-10-05 07:43:04 +03:00
if _ , err = x . ID ( rel . ID ) . Delete ( new ( Release ) ) ; err != nil {
2017-09-20 08:26:49 +03:00
return fmt . Errorf ( "Delete: %v" , err )
}
} else {
rel . IsTag = true
rel . IsDraft = false
rel . IsPrerelease = false
rel . Title = ""
rel . Note = ""
2017-10-05 07:43:04 +03:00
if _ , err = x . ID ( rel . ID ) . AllCols ( ) . Update ( rel ) ; err != nil {
2017-09-20 08:26:49 +03:00
return fmt . Errorf ( "Update: %v" , err )
}
2015-11-20 10:38:41 +03:00
}
2018-06-12 19:44:17 +03:00
rel . Repo = repo
if err = rel . LoadAttributes ( ) ; err != nil {
return fmt . Errorf ( "LoadAttributes: %v" , err )
}
2018-11-28 14:26:14 +03:00
mode , _ := AccessLevel ( u , rel . Repo )
2018-05-21 05:28:29 +03:00
if err := PrepareWebhooks ( rel . Repo , HookEventRelease , & api . ReleasePayload {
Action : api . HookReleaseDeleted ,
Release : rel . APIFormat ( ) ,
Repository : rel . Repo . APIFormat ( mode ) ,
Sender : rel . Publisher . APIFormat ( ) ,
} ) ; err != nil {
2019-04-02 10:48:31 +03:00
log . Error ( "PrepareWebhooks: %v" , err )
2018-05-21 05:28:29 +03:00
} else {
go HookQueue . Add ( rel . Repo . ID )
}
2015-11-20 10:38:41 +03:00
return nil
}
2017-09-20 08:26:49 +03:00
// SyncReleasesWithTags synchronizes release table with repository tags
func SyncReleasesWithTags ( repo * Repository , gitRepo * git . Repository ) error {
existingRelTags := make ( map [ string ] struct { } )
opts := FindReleasesOptions { IncludeDrafts : true , IncludeTags : true }
for page := 1 ; ; page ++ {
rels , err := GetReleasesByRepoID ( repo . ID , opts , page , 100 )
if err != nil {
return fmt . Errorf ( "GetReleasesByRepoID: %v" , err )
}
if len ( rels ) == 0 {
break
}
for _ , rel := range rels {
if rel . IsDraft {
continue
}
commitID , err := gitRepo . GetTagCommitID ( rel . TagName )
2019-01-01 02:00:54 +03:00
if err != nil && ! git . IsErrNotExist ( err ) {
2017-09-20 08:26:49 +03:00
return fmt . Errorf ( "GetTagCommitID: %v" , err )
}
2019-01-01 02:00:54 +03:00
if git . IsErrNotExist ( err ) || commitID != rel . Sha1 {
2019-06-12 22:41:28 +03:00
if err := pushUpdateDeleteTag ( repo , rel . TagName ) ; err != nil {
2017-09-20 08:26:49 +03:00
return fmt . Errorf ( "pushUpdateDeleteTag: %v" , err )
}
} else {
existingRelTags [ strings . ToLower ( rel . TagName ) ] = struct { } { }
}
}
}
tags , err := gitRepo . GetTags ( )
if err != nil {
return fmt . Errorf ( "GetTags: %v" , err )
}
for _ , tagName := range tags {
if _ , ok := existingRelTags [ strings . ToLower ( tagName ) ] ; ! ok {
if err := pushUpdateAddTag ( repo , gitRepo , tagName ) ; err != nil {
return fmt . Errorf ( "pushUpdateAddTag: %v" , err )
}
}
}
return nil
}