Skip to content

Commit 1924c25

Browse files
committed
Sync releases table with tags on push and for mirrors
1 parent b0f7457 commit 1924c25

File tree

10 files changed

+327
-84
lines changed

10 files changed

+327
-84
lines changed

models/migrations/migrations.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,8 @@ var migrations = []Migration{
132132
NewMigration("migrate protected branch struct", migrateProtectedBranchStruct),
133133
// v41 -> v42
134134
NewMigration("add default value to user prohibit_login", addDefaultValueToUserProhibitLogin),
135+
// v42 -> v43
136+
NewMigration("add tags to releases and sync existing repositories", releaseAddColumnIsTagAndSyncTags),
135137
}
136138

137139
// Migrate database to current version

models/migrations/v42.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Copyright 2017 The Gitea Authors. All rights reserved.
2+
// Use of this source code is governed by a MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
package migrations
6+
7+
import (
8+
"fmt"
9+
10+
"code.gitea.io/git"
11+
"code.gitea.io/gitea/models"
12+
"code.gitea.io/gitea/modules/log"
13+
14+
"github.com/go-xorm/xorm"
15+
)
16+
17+
// ReleaseV39 describes the added field for Release
18+
type ReleaseV39 struct {
19+
IsTag bool `xorm:"NOT NULL DEFAULT false"`
20+
}
21+
22+
// TableName will be invoked by XORM to customrize the table name
23+
func (*ReleaseV39) TableName() string {
24+
return "release"
25+
}
26+
27+
func releaseAddColumnIsTagAndSyncTags(x *xorm.Engine) error {
28+
if err := x.Sync2(new(ReleaseV39)); err != nil {
29+
return fmt.Errorf("Sync2: %v", err)
30+
}
31+
32+
// For the sake of SQLite3, we can't use x.Iterate here.
33+
offset := 0
34+
pageSize := 20
35+
for {
36+
repos := make([]*models.Repository, 0, pageSize)
37+
if err := x.Table("repository").Asc("id").Limit(pageSize, offset).Find(&repos); err != nil {
38+
return fmt.Errorf("select repos [offset: %d]: %v", offset, err)
39+
}
40+
for _, repo := range repos {
41+
gitRepo, err := git.OpenRepository(repo.RepoPath())
42+
if err != nil {
43+
log.Warn("OpenRepository: %v", err)
44+
continue
45+
}
46+
47+
if err = models.SyncReleasesWithTags(repo, gitRepo); err != nil {
48+
log.Warn("SyncReleasesWithTags: %v", err)
49+
}
50+
}
51+
if len(repos) < pageSize {
52+
break
53+
}
54+
offset += pageSize
55+
}
56+
return nil
57+
}

models/release.go

Lines changed: 67 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ type Release struct {
3434
NumCommitsBehind int64 `xorm:"-"`
3535
Note string `xorm:"TEXT"`
3636
IsDraft bool `xorm:"NOT NULL DEFAULT false"`
37-
IsPrerelease bool
37+
IsPrerelease bool `xorm:"NOT NULL DEFAULT false"`
38+
IsTag bool `xorm:"NOT NULL DEFAULT false"`
3839

3940
Attachments []*Attachment `xorm:"-"`
4041

@@ -236,6 +237,7 @@ func GetReleaseByID(id int64) (*Release, error) {
236237
// FindReleasesOptions describes the conditions to Find releases
237238
type FindReleasesOptions struct {
238239
IncludeDrafts bool
240+
IncludeTags bool
239241
TagNames []string
240242
}
241243

@@ -246,6 +248,9 @@ func (opts *FindReleasesOptions) toConds(repoID int64) builder.Cond {
246248
if !opts.IncludeDrafts {
247249
cond = cond.And(builder.Eq{"is_draft": false})
248250
}
251+
if !opts.IncludeTags {
252+
cond = cond.And(builder.Eq{"is_release": false})
253+
}
249254
if len(opts.TagNames) > 0 {
250255
cond = cond.And(builder.In("tag_name", opts.TagNames))
251256
}
@@ -361,6 +366,8 @@ func UpdateRelease(gitRepo *git.Repository, rel *Release, attachmentUUIDs []stri
361366
if err = createTag(gitRepo, rel); err != nil {
362367
return err
363368
}
369+
rel.LowerTagName = strings.ToLower(rel.TagName)
370+
364371
_, err = x.Id(rel.ID).AllCols().Update(rel)
365372
if err != nil {
366373
return err
@@ -397,11 +404,67 @@ func DeleteReleaseByID(id int64, u *User, delTag bool) error {
397404
if err != nil && !strings.Contains(stderr, "not found") {
398405
return fmt.Errorf("git tag -d: %v - %s", err, stderr)
399406
}
400-
}
401407

402-
if _, err = x.Id(rel.ID).Delete(new(Release)); err != nil {
403-
return fmt.Errorf("Delete: %v", err)
408+
if _, err = x.Id(rel.ID).Delete(new(Release)); err != nil {
409+
return fmt.Errorf("Delete: %v", err)
410+
}
411+
} else {
412+
rel.IsTag = true
413+
rel.IsDraft = false
414+
rel.IsPrerelease = false
415+
rel.Title = ""
416+
rel.Note = ""
417+
418+
if _, err = x.Id(rel.ID).AllCols().Update(rel); err != nil {
419+
return fmt.Errorf("Update: %v", err)
420+
}
404421
}
405422

406423
return nil
407424
}
425+
426+
// SyncReleasesWithTags synchronizes release table with repository tags
427+
func SyncReleasesWithTags(repo *Repository, gitRepo *git.Repository) error {
428+
checked := make([]string, 100)
429+
opts := FindReleasesOptions{IncludeDrafts: true, IncludeTags: true}
430+
page := 0
431+
for {
432+
page++
433+
rels, err := GetReleasesByRepoID(repo.ID, opts, page, 100)
434+
if err != nil {
435+
return fmt.Errorf("GetReleasesByRepoID: %v", err)
436+
}
437+
if len(rels) == 0 {
438+
break
439+
}
440+
for _, rel := range rels {
441+
if rel.IsDraft {
442+
continue
443+
}
444+
if !gitRepo.IsTagExist(rel.TagName) {
445+
if err := pushUpdateDeleteTag(repo, gitRepo, rel.TagName); err != nil {
446+
return fmt.Errorf("pushUpdateDeleteTag: %v", err)
447+
}
448+
} else {
449+
checked = append(checked, rel.TagName)
450+
}
451+
}
452+
}
453+
tags, err := gitRepo.GetTags()
454+
if err != nil {
455+
return fmt.Errorf("GetTags: %v", err)
456+
}
457+
for _, tagName := range tags {
458+
exists := false
459+
for _, relTagName := range checked {
460+
if tagName == relTagName {
461+
exists = true
462+
break
463+
}
464+
}
465+
if !exists {
466+
pushUpdateAddTag(repo, gitRepo, tagName)
467+
}
468+
}
469+
return nil
470+
}

models/repo.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -940,6 +940,10 @@ func MigrateRepository(doer, u *User, opts MigrateRepoOptions) (*Repository, err
940940
if headBranch != nil {
941941
repo.DefaultBranch = headBranch.Name
942942
}
943+
944+
if err = SyncReleasesWithTags(repo, gitRepo); err != nil {
945+
log.Error(4, "Failed to synchronize tags to releases for repository: %v", err)
946+
}
943947
}
944948

945949
if err = repo.UpdateSize(); err != nil {

models/repo_mirror.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"github.com/go-xorm/xorm"
1414
"gopkg.in/ini.v1"
1515

16+
"code.gitea.io/git"
1617
"code.gitea.io/gitea/modules/log"
1718
"code.gitea.io/gitea/modules/process"
1819
"code.gitea.io/gitea/modules/setting"
@@ -156,6 +157,15 @@ func (m *Mirror) runSync() bool {
156157
return false
157158
}
158159

160+
gitRepo, err := git.OpenRepository(repoPath)
161+
if err != nil {
162+
log.Error(4, "OpenRepository: %v", err)
163+
return false
164+
}
165+
if err = SyncReleasesWithTags(m.Repo, gitRepo); err != nil {
166+
log.Error(4, "Failed to synchronize tags to releases for repository: %v", err)
167+
}
168+
159169
if err := m.Repo.UpdateSize(); err != nil {
160170
log.Error(4, "Failed to update size for mirror repository: %v", err)
161171
}

models/update.go

Lines changed: 98 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,91 @@ func PushUpdate(branch string, opt PushUpdateOptions) error {
8181
return nil
8282
}
8383

84+
func pushUpdateDeleteTag(repo *Repository, gitRepo *git.Repository, tagName string) error {
85+
rel, err := GetRelease(repo.ID, tagName)
86+
if err != nil {
87+
if IsErrReleaseNotExist(err) {
88+
return nil
89+
}
90+
return fmt.Errorf("GetRelease: %v", err)
91+
}
92+
if rel.IsTag {
93+
if _, err = x.Id(rel.ID).Delete(new(Release)); err != nil {
94+
return fmt.Errorf("Delete: %v", err)
95+
}
96+
} else {
97+
rel.IsDraft = true
98+
rel.NumCommits = 0
99+
rel.Sha1 = ""
100+
if _, err = x.Id(rel.ID).AllCols().Update(rel); err != nil {
101+
return fmt.Errorf("Update: %v", err)
102+
}
103+
}
104+
105+
return nil
106+
}
107+
108+
func pushUpdateAddTag(repo *Repository, gitRepo *git.Repository, tagName string) error {
109+
rel, err := GetRelease(repo.ID, tagName)
110+
if err != nil && !IsErrReleaseNotExist(err) {
111+
return fmt.Errorf("GetRelease: %v", err)
112+
}
113+
114+
tag, err := gitRepo.GetTag(tagName)
115+
if err != nil {
116+
return fmt.Errorf("GetTag: %v", err)
117+
}
118+
commit, err := tag.Commit()
119+
if err != nil {
120+
return fmt.Errorf("Commit: %v", err)
121+
}
122+
tagCreatedUnix := commit.Author.When.Unix()
123+
124+
author, err := GetUserByEmail(commit.Author.Email)
125+
if err != nil && !IsErrUserNotExist(err) {
126+
return fmt.Errorf("GetUserByEmail: %v", err)
127+
}
128+
129+
commitsCount, err := commit.CommitsCount()
130+
if err != nil {
131+
return fmt.Errorf("CommitsCount: %v", err)
132+
}
133+
134+
if rel == nil {
135+
rel = &Release{
136+
RepoID: repo.ID,
137+
Title: "",
138+
TagName: tagName,
139+
Target: "",
140+
Sha1: commit.ID.String(),
141+
NumCommits: commitsCount,
142+
Note: "",
143+
IsDraft: false,
144+
IsPrerelease: false,
145+
IsTag: true,
146+
CreatedUnix: tagCreatedUnix,
147+
}
148+
if author != nil {
149+
rel.PublisherID = author.ID
150+
}
151+
152+
if _, err = x.InsertOne(rel); err != nil {
153+
return fmt.Errorf("InsertOne: %v", err)
154+
}
155+
} else {
156+
rel.Sha1 = commit.ID.String()
157+
rel.CreatedUnix = tagCreatedUnix
158+
rel.NumCommits = commitsCount
159+
if rel.IsTag && author != nil {
160+
rel.PublisherID = author.ID
161+
}
162+
if _, err = x.Id(rel.ID).AllCols().Update(rel); err != nil {
163+
return fmt.Errorf("Update: %v", err)
164+
}
165+
}
166+
return nil
167+
}
168+
84169
func pushUpdate(opts PushUpdateOptions) (repo *Repository, err error) {
85170
isNewRef := opts.OldCommitID == git.EmptySHA
86171
isDelRef := opts.NewCommitID == git.EmptySHA
@@ -106,23 +191,31 @@ func pushUpdate(opts PushUpdateOptions) (repo *Repository, err error) {
106191
return nil, fmt.Errorf("GetRepositoryByName: %v", err)
107192
}
108193

194+
gitRepo, err := git.OpenRepository(repoPath)
195+
if err != nil {
196+
return nil, fmt.Errorf("OpenRepository: %v", err)
197+
}
198+
109199
if isDelRef {
200+
// Tag has been deleted
201+
if strings.HasPrefix(opts.RefFullName, git.TagPrefix) {
202+
err = pushUpdateDeleteTag(repo, gitRepo, opts.RefFullName[len(git.TagPrefix):])
203+
if err != nil {
204+
return nil, fmt.Errorf("pushUpdateDeleteTag: %v", err)
205+
}
206+
}
110207
log.GitLogger.Info("Reference '%s' has been deleted from '%s/%s' by %s",
111208
opts.RefFullName, opts.RepoUserName, opts.RepoName, opts.PusherName)
112209
return repo, nil
113210
}
114211

115-
gitRepo, err := git.OpenRepository(repoPath)
116-
if err != nil {
117-
return nil, fmt.Errorf("OpenRepository: %v", err)
118-
}
119-
120212
if err = repo.UpdateSize(); err != nil {
121213
log.Error(4, "Failed to update size for repository: %v", err)
122214
}
123215

124216
// Push tags.
125217
if strings.HasPrefix(opts.RefFullName, git.TagPrefix) {
218+
pushUpdateAddTag(repo, gitRepo, opts.RefFullName[len(git.TagPrefix):])
126219
if err := CommitRepoAction(CommitRepoActionOptions{
127220
PusherName: opts.PusherName,
128221
RepoOwnerID: owner.ID,

modules/context/repo.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,7 @@ func RepoAssignment() macaron.Handler {
288288

289289
count, err := models.GetReleaseCountByRepoID(ctx.Repo.Repository.ID, models.FindReleasesOptions{
290290
IncludeDrafts: false,
291+
IncludeTags: true,
291292
})
292293
if err != nil {
293294
ctx.Handle(500, "GetReleaseCountByRepoID", err)

0 commit comments

Comments
 (0)