Skip to content

Commit 524bfc4

Browse files
mohsekzeripath
authored and
Sysoev, Vladimir
committed
Add new API endpoints for push mirrors management (go-gitea#19841)
- Add a new push mirror to specific repository - Sync now ( send all the changes to the configured push mirrors ) - Get list of all push mirrors of a repository - Get a push mirror by ID - Delete push mirror by ID Signed-off-by: Mohamed Sekour <[email protected]> Signed-off-by: Andrew Thornton <[email protected]> Co-authored-by: zeripath <[email protected]>
1 parent d6f15bf commit 524bfc4

File tree

14 files changed

+787
-44
lines changed

14 files changed

+787
-44
lines changed

integrations/mirror_push_test.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"testing"
1414

1515
"code.gitea.io/gitea/models"
16+
"code.gitea.io/gitea/models/db"
1617
repo_model "code.gitea.io/gitea/models/repo"
1718
"code.gitea.io/gitea/models/unittest"
1819
user_model "code.gitea.io/gitea/models/user"
@@ -47,7 +48,7 @@ func testMirrorPush(t *testing.T, u *url.URL) {
4748

4849
doCreatePushMirror(ctx, fmt.Sprintf("%s%s/%s", u.String(), url.PathEscape(ctx.Username), url.PathEscape(mirrorRepo.Name)), user.LowerName, userPassword)(t)
4950

50-
mirrors, err := repo_model.GetPushMirrorsByRepoID(srcRepo.ID)
51+
mirrors, _, err := repo_model.GetPushMirrorsByRepoID(db.DefaultContext, srcRepo.ID, db.ListOptions{})
5152
assert.NoError(t, err)
5253
assert.Len(t, mirrors, 1)
5354

@@ -72,7 +73,7 @@ func testMirrorPush(t *testing.T, u *url.URL) {
7273

7374
// Cleanup
7475
doRemovePushMirror(ctx, fmt.Sprintf("%s%s/%s", u.String(), url.PathEscape(ctx.Username), url.PathEscape(mirrorRepo.Name)), user.LowerName, userPassword, int(mirrors[0].ID))(t)
75-
mirrors, err = repo_model.GetPushMirrorsByRepoID(srcRepo.ID)
76+
mirrors, _, err = repo_model.GetPushMirrorsByRepoID(db.DefaultContext, srcRepo.ID, db.ListOptions{})
7677
assert.NoError(t, err)
7778
assert.Len(t, mirrors, 0)
7879
}

models/repo/pushmirror.go

+49-24
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,15 @@
55
package repo
66

77
import (
8+
"context"
89
"errors"
910
"time"
1011

1112
"code.gitea.io/gitea/models/db"
1213
"code.gitea.io/gitea/modules/log"
1314
"code.gitea.io/gitea/modules/timeutil"
15+
16+
"xorm.io/builder"
1417
)
1518

1619
// ErrPushMirrorNotExist mirror does not exist error
@@ -29,6 +32,25 @@ type PushMirror struct {
2932
LastUpdateUnix timeutil.TimeStamp `xorm:"INDEX last_update"`
3033
LastError string `xorm:"text"`
3134
}
35+
type PushMirrorOptions struct {
36+
ID int64
37+
RepoID int64
38+
RemoteName string
39+
}
40+
41+
func (opts *PushMirrorOptions) toConds() builder.Cond {
42+
cond := builder.NewCond()
43+
if opts.RepoID > 0 {
44+
cond = cond.And(builder.Eq{"repo_id": opts.RepoID})
45+
}
46+
if opts.RemoteName != "" {
47+
cond = cond.And(builder.Eq{"remote_name": opts.RemoteName})
48+
}
49+
if opts.ID > 0 {
50+
cond = cond.And(builder.Eq{"id": opts.ID})
51+
}
52+
return cond
53+
}
3254

3355
func init() {
3456
db.RegisterModel(new(PushMirror))
@@ -53,45 +75,48 @@ func (m *PushMirror) GetRemoteName() string {
5375
}
5476

5577
// InsertPushMirror inserts a push-mirror to database
56-
func InsertPushMirror(m *PushMirror) error {
57-
_, err := db.GetEngine(db.DefaultContext).Insert(m)
78+
func InsertPushMirror(ctx context.Context, m *PushMirror) error {
79+
_, err := db.GetEngine(ctx).Insert(m)
5880
return err
5981
}
6082

6183
// UpdatePushMirror updates the push-mirror
62-
func UpdatePushMirror(m *PushMirror) error {
63-
_, err := db.GetEngine(db.DefaultContext).ID(m.ID).AllCols().Update(m)
64-
return err
65-
}
66-
67-
// DeletePushMirrorByID deletes a push-mirrors by ID
68-
func DeletePushMirrorByID(ID int64) error {
69-
_, err := db.GetEngine(db.DefaultContext).ID(ID).Delete(&PushMirror{})
84+
func UpdatePushMirror(ctx context.Context, m *PushMirror) error {
85+
_, err := db.GetEngine(ctx).ID(m.ID).AllCols().Update(m)
7086
return err
7187
}
7288

73-
// DeletePushMirrorsByRepoID deletes all push-mirrors by repoID
74-
func DeletePushMirrorsByRepoID(repoID int64) error {
75-
_, err := db.GetEngine(db.DefaultContext).Delete(&PushMirror{RepoID: repoID})
76-
return err
89+
func DeletePushMirrors(ctx context.Context, opts PushMirrorOptions) error {
90+
if opts.RepoID > 0 {
91+
_, err := db.GetEngine(ctx).Where(opts.toConds()).Delete(&PushMirror{})
92+
return err
93+
}
94+
return errors.New("repoID required and must be set")
7795
}
7896

79-
// GetPushMirrorByID returns push-mirror information.
80-
func GetPushMirrorByID(ID int64) (*PushMirror, error) {
81-
m := &PushMirror{}
82-
has, err := db.GetEngine(db.DefaultContext).ID(ID).Get(m)
97+
func GetPushMirror(ctx context.Context, opts PushMirrorOptions) (*PushMirror, error) {
98+
mirror := &PushMirror{}
99+
exist, err := db.GetEngine(ctx).Where(opts.toConds()).Get(mirror)
83100
if err != nil {
84101
return nil, err
85-
} else if !has {
102+
} else if !exist {
86103
return nil, ErrPushMirrorNotExist
87104
}
88-
return m, nil
105+
return mirror, nil
89106
}
90107

91108
// GetPushMirrorsByRepoID returns push-mirror information of a repository.
92-
func GetPushMirrorsByRepoID(repoID int64) ([]*PushMirror, error) {
109+
func GetPushMirrorsByRepoID(ctx context.Context, repoID int64, listOptions db.ListOptions) ([]*PushMirror, int64, error) {
110+
sess := db.GetEngine(ctx).Where("repo_id = ?", repoID)
111+
if listOptions.Page != 0 {
112+
sess = db.SetSessionPagination(sess, &listOptions)
113+
mirrors := make([]*PushMirror, 0, listOptions.PageSize)
114+
count, err := sess.FindAndCount(&mirrors)
115+
return mirrors, count, err
116+
}
93117
mirrors := make([]*PushMirror, 0, 10)
94-
return mirrors, db.GetEngine(db.DefaultContext).Where("repo_id=?", repoID).Find(&mirrors)
118+
count, err := sess.FindAndCount(&mirrors)
119+
return mirrors, count, err
95120
}
96121

97122
// GetPushMirrorsSyncedOnCommit returns push-mirrors for this repo that should be updated by new commits
@@ -103,8 +128,8 @@ func GetPushMirrorsSyncedOnCommit(repoID int64) ([]*PushMirror, error) {
103128
}
104129

105130
// PushMirrorsIterate iterates all push-mirror repositories.
106-
func PushMirrorsIterate(limit int, f func(idx int, bean interface{}) error) error {
107-
return db.GetEngine(db.DefaultContext).
131+
func PushMirrorsIterate(ctx context.Context, limit int, f func(idx int, bean interface{}) error) error {
132+
return db.GetEngine(ctx).
108133
Where("last_update + (`interval` / ?) <= ?", time.Second, time.Now().Unix()).
109134
And("`interval` != 0").
110135
OrderBy("last_update ASC").

models/repo/pushmirror_test.go

+5-4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"testing"
99
"time"
1010

11+
"code.gitea.io/gitea/models/db"
1112
repo_model "code.gitea.io/gitea/models/repo"
1213
"code.gitea.io/gitea/models/unittest"
1314
"code.gitea.io/gitea/modules/timeutil"
@@ -20,28 +21,28 @@ func TestPushMirrorsIterate(t *testing.T) {
2021

2122
now := timeutil.TimeStampNow()
2223

23-
repo_model.InsertPushMirror(&repo_model.PushMirror{
24+
repo_model.InsertPushMirror(db.DefaultContext, &repo_model.PushMirror{
2425
RemoteName: "test-1",
2526
LastUpdateUnix: now,
2627
Interval: 1,
2728
})
2829

2930
long, _ := time.ParseDuration("24h")
30-
repo_model.InsertPushMirror(&repo_model.PushMirror{
31+
repo_model.InsertPushMirror(db.DefaultContext, &repo_model.PushMirror{
3132
RemoteName: "test-2",
3233
LastUpdateUnix: now,
3334
Interval: long,
3435
})
3536

36-
repo_model.InsertPushMirror(&repo_model.PushMirror{
37+
repo_model.InsertPushMirror(db.DefaultContext, &repo_model.PushMirror{
3738
RemoteName: "test-3",
3839
LastUpdateUnix: now,
3940
Interval: 0,
4041
})
4142

4243
time.Sleep(1 * time.Millisecond)
4344

44-
repo_model.PushMirrorsIterate(1, func(idx int, bean interface{}) error {
45+
repo_model.PushMirrorsIterate(db.DefaultContext, 1, func(idx int, bean interface{}) error {
4546
m, ok := bean.(*repo_model.PushMirror)
4647
assert.True(t, ok)
4748
assert.Equal(t, "test-1", m.RemoteName)

modules/context/repo.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,7 @@ func repoAssignment(ctx *Context, repo *repo_model.Repository) {
393393
}
394394
}
395395

396-
pushMirrors, err := repo_model.GetPushMirrorsByRepoID(repo.ID)
396+
pushMirrors, _, err := repo_model.GetPushMirrorsByRepoID(ctx, repo.ID, db.ListOptions{})
397397
if err != nil {
398398
ctx.ServerError("GetPushMirrorsByRepoID", err)
399399
return

modules/convert/mirror.go

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Copyright 2022 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 convert
6+
7+
import (
8+
repo_model "code.gitea.io/gitea/models/repo"
9+
"code.gitea.io/gitea/modules/git"
10+
api "code.gitea.io/gitea/modules/structs"
11+
)
12+
13+
// ToPushMirror convert from repo_model.PushMirror and remoteAddress to api.TopicResponse
14+
func ToPushMirror(pm *repo_model.PushMirror) (*api.PushMirror, error) {
15+
repo := pm.GetRepository()
16+
remoteAddress, err := getRemoteAddress(repo, pm.RemoteName)
17+
if err != nil {
18+
return nil, err
19+
}
20+
return &api.PushMirror{
21+
RepoName: repo.Name,
22+
RemoteName: pm.RemoteName,
23+
RemoteAddress: remoteAddress,
24+
CreatedUnix: pm.CreatedUnix.FormatLong(),
25+
LastUpdateUnix: pm.LastUpdateUnix.FormatLong(),
26+
LastError: pm.LastError,
27+
Interval: pm.Interval.String(),
28+
}, nil
29+
}
30+
31+
func getRemoteAddress(repo *repo_model.Repository, remoteName string) (string, error) {
32+
url, err := git.GetRemoteURL(git.DefaultContext, repo.RepoPath(), remoteName)
33+
if err != nil {
34+
return "", err
35+
}
36+
// remove confidential information
37+
url.User = nil
38+
return url.String(), nil
39+
}

modules/structs/mirror.go

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright 2021 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 structs
6+
7+
// CreatePushMirrorOption represents need information to create a push mirror of a repository.
8+
type CreatePushMirrorOption struct {
9+
RemoteAddress string `json:"remote_address"`
10+
RemoteUsername string `json:"remote_username"`
11+
RemotePassword string `json:"remote_password"`
12+
Interval string `json:"interval"`
13+
}
14+
15+
// PushMirror represents information of a push mirror
16+
// swagger:model
17+
type PushMirror struct {
18+
RepoName string `json:"repo_name"`
19+
RemoteName string `json:"remote_name"`
20+
RemoteAddress string `json:"remote_address"`
21+
CreatedUnix string `json:"created"`
22+
LastUpdateUnix string `json:"last_update"`
23+
LastError string `json:"last_error"`
24+
Interval string `json:"interval"`
25+
}

routers/api/v1/api.go

+9
Original file line numberDiff line numberDiff line change
@@ -982,6 +982,15 @@ func Routes() *web.Route {
982982
})
983983
}, reqRepoReader(unit.TypeReleases))
984984
m.Post("/mirror-sync", reqToken(), reqRepoWriter(unit.TypeCode), repo.MirrorSync)
985+
m.Post("/push_mirrors-sync", reqAdmin(), repo.PushMirrorSync)
986+
m.Group("/push_mirrors", func() {
987+
m.Combo("").Get(repo.ListPushMirrors).
988+
Post(bind(api.CreatePushMirrorOption{}), repo.AddPushMirror)
989+
m.Combo("/{name}").
990+
Delete(repo.DeletePushMirrorByRemoteName).
991+
Get(repo.GetPushMirrorByName)
992+
}, reqAdmin())
993+
985994
m.Get("/editorconfig/{filename}", context.ReferencesGitRepo(), context.RepoRefForAPI, reqRepoReader(unit.TypeCode), repo.GetEditorconfig)
986995
m.Group("/pulls", func() {
987996
m.Combo("").Get(repo.ListPullRequests).

0 commit comments

Comments
 (0)