Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement sync push mirror on commit #19411

Merged
merged 34 commits into from
Jul 8, 2022
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
ac61c17
Update pushmirror model to allow sync-on-push
harryzcy Apr 15, 2022
04d7bd5
Move mirror push functions to a pushmirror service
harryzcy Apr 15, 2022
bd55411
Implement sync-on-push via a mirrorNotifier
harryzcy Apr 15, 2022
8f87595
Fix lint-backend issues
harryzcy Apr 15, 2022
eb25993
Add migration for PushMirror struct
harryzcy Apr 15, 2022
bcabe51
Improve filtering for push mirrors
harryzcy Apr 17, 2022
c6a4f30
Refactor to use modules/mirror
harryzcy Jun 3, 2022
2978942
Update tests after moving code to modules/mirror
harryzcy Jun 3, 2022
6c0e721
Include copyright
harryzcy Jun 3, 2022
0836473
Add 'sync on commit' checkbox in web UI
harryzcy Jun 29, 2022
5a8d2b5
Update checkbox input
harryzcy Jun 29, 2022
88f50e9
Store sync on commit setting
harryzcy Jun 29, 2022
c9d6393
Use more generic name SyncOnCommit
harryzcy Jun 29, 2022
f2de0a0
Trigger mirror on pull requests
harryzcy Jun 30, 2022
4c157e7
Merge remote-tracking branch 'upstream/main' into sync-on-push
harryzcy Jul 4, 2022
0f745bd
Fix table column name
harryzcy Jul 4, 2022
6f66d44
Update sync_on_commit column to false
harryzcy Jul 4, 2022
cb517b2
Make use of mirror queue
harryzcy Jul 4, 2022
3b0bd59
Use boolean keyword FALSE
harryzcy Jul 4, 2022
28925ad
Use False only for postgres
harryzcy Jul 4, 2022
436013e
Remove MergePullRequest event
harryzcy Jul 5, 2022
2bd23e6
Sync with mirror on SyncPushCommits event
harryzcy Jul 5, 2022
9cc7738
Remove unused context
harryzcy Jul 5, 2022
207e0fe
Fill input box with value
harryzcy Jul 5, 2022
08ceff9
Fix a func naming glitch in migration
harryzcy Jul 5, 2022
2cc1297
Apply not null and default to SyncOnCommit
harryzcy Jul 5, 2022
92603fc
Apply suggestions from code review
harryzcy Jul 5, 2022
67fa209
Fix minor errors from code review
harryzcy Jul 5, 2022
740408e
Enable sync on commit by default
harryzcy Jul 6, 2022
2210235
Set SyncOnCommit's default to true in models
harryzcy Jul 6, 2022
bc1afc1
Update comment to match function name
harryzcy Jul 7, 2022
6320a5d
Merge branch 'main' into sync-on-push
zeripath Jul 7, 2022
6aab911
Merge branch 'main' into sync-on-push
lunny Jul 8, 2022
b7331e9
Apply suggestions from code review
harryzcy Jul 8, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions models/migrations/migrations.go
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,8 @@ var migrations = []Migration{
NewMigration("Alter hook_task table TEXT fields to LONGTEXT", alterHookTaskTextFieldsToLongText),
// v218 -> v219
NewMigration("Improve Action table indices v2", improveActionTableIndices),
// v219 -> v220
NewMigration("Add sync_on_commit column to push_mirror table", addSyncOnCommitColForPushMirror),
}

// GetCurrentDBVersion returns the current db version
Expand Down
52 changes: 52 additions & 0 deletions models/migrations/v219.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright 2022 The Gitea 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 migrations

import (
"fmt"
"time"

"code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil"
"xorm.io/xorm"
)

func addSyncOnCommitColForPushMirror(x *xorm.Engine) error {
type PushMirror struct {
ID int64 `xorm:"pk autoincr"`
RepoID int64 `xorm:"INDEX"`
Repo *repo.Repository `xorm:"-"`
RemoteName string

SyncOnCommit bool
harryzcy marked this conversation as resolved.
Show resolved Hide resolved
Interval time.Duration
CreatedUnix timeutil.TimeStamp `xorm:"created"`
LastUpdateUnix timeutil.TimeStamp `xorm:"INDEX last_update"`
LastError string `xorm:"text"`
}

session := x.NewSession()
defer session.Close()
if err := session.Begin(); err != nil {
return err
}

if err := session.Sync2(new(PushMirror)); err != nil {
return fmt.Errorf("sync2: %v", err)
}

if setting.Database.UsePostgreSQL { // PostgreSQL uses Boolean type
if _, err := session.Exec("UPDATE push_mirror SET sync_on_commit = FALSE"); err != nil {
return err
}
} else {
if _, err := session.Exec("UPDATE push_mirror SET sync_on_commit = 0"); err != nil {
return err
}
}

return session.Commit()
}
10 changes: 10 additions & 0 deletions models/repo/pushmirror.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ type PushMirror struct {
Repo *Repository `xorm:"-"`
RemoteName string

SyncOnCommit bool
Interval time.Duration
CreatedUnix timeutil.TimeStamp `xorm:"created"`
LastUpdateUnix timeutil.TimeStamp `xorm:"INDEX last_update"`
Expand Down Expand Up @@ -93,6 +94,15 @@ func GetPushMirrorsByRepoID(repoID int64) ([]*PushMirror, error) {
return mirrors, db.GetEngine(db.DefaultContext).Where("repo_id=?", repoID).Find(&mirrors)
}

// GetPushMirrorsByRepoIDWithSyncOnCommit returns push-mirror information of a repository,
// filtered by sync_on_commit.
harryzcy marked this conversation as resolved.
Show resolved Hide resolved
func GetPushMirrorsByRepoIDWithSyncOnCommit(repoID int64, syncOnCommit bool) ([]*PushMirror, error) {
harryzcy marked this conversation as resolved.
Show resolved Hide resolved
mirrors := make([]*PushMirror, 0, 10)
return mirrors, db.GetEngine(db.DefaultContext).
Where("repo_id=? AND sync_on_commit=?", repoID, syncOnCommit).
harryzcy marked this conversation as resolved.
Show resolved Hide resolved
Find(&mirrors)
}

// PushMirrorsIterate iterates all push-mirror repositories.
func PushMirrorsIterate(limit int, f func(idx int, bean interface{}) error) error {
return db.GetEngine(db.DefaultContext).
Expand Down
75 changes: 75 additions & 0 deletions modules/mirror/mirror.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// Copyright 2022 The Gitea 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 mirror

import (
"code.gitea.io/gitea/modules/graceful"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/queue"
"code.gitea.io/gitea/modules/setting"
)

var mirrorQueue queue.UniqueQueue

// SyncType type of sync request
type SyncType int

const (
// PullMirrorType for pull mirrors
PullMirrorType SyncType = iota
// PushMirrorType for push mirrors
PushMirrorType
)

// SyncRequest for the mirror queue
type SyncRequest struct {
Type SyncType
ReferenceID int64 // RepoID for pull mirror, MirrorID fro push mirror
harryzcy marked this conversation as resolved.
Show resolved Hide resolved
}

// StartSyncMirrors starts a go routine to sync the mirrors
func StartSyncMirrors(queueHandle func(data ...queue.Data) []queue.Data) {
if !setting.Mirror.Enabled {
return
}
mirrorQueue = queue.CreateUniqueQueue("mirror", queueHandle, new(SyncRequest))

go graceful.GetManager().RunWithShutdownFns(mirrorQueue.Run)
}

// AddPullMirrorToQueue adds repoID to mirror queue
func AddPullMirrorToQueue(repoID int64) {
if !setting.Mirror.Enabled {
return
}
go func() {
err := PushToQueue(PullMirrorType, repoID)
if err != nil {
log.Error("Unable to push sync request for to the queue for pull mirror repo[%d]: Error: %v", repoID, err)
return
}
}()
}

// AddPushMirrorToQueue adds the push mirror to the queue
func AddPushMirrorToQueue(mirrorID int64) {
if !setting.Mirror.Enabled {
return
}
go func() {
err := PushToQueue(PushMirrorType, mirrorID)
if err != nil {
log.Error("Unable to push sync request to the queue for pull mirror repo[%d]: Error: %v", mirrorID, err)
}
}()
}

harryzcy marked this conversation as resolved.
Show resolved Hide resolved
// PushToQueue adds the sync request to the queue
func PushToQueue(mirrorType SyncType, referenceID int64) error {
return mirrorQueue.Push(&SyncRequest{
Type: mirrorType,
ReferenceID: referenceID,
})
}
46 changes: 46 additions & 0 deletions modules/notification/mirror/mirror.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright 2022 The Gitea 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 mirror

import (
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
harryzcy marked this conversation as resolved.
Show resolved Hide resolved
"code.gitea.io/gitea/modules/log"
mirror_module "code.gitea.io/gitea/modules/mirror"
"code.gitea.io/gitea/modules/notification/base"
"code.gitea.io/gitea/modules/repository"
)

type mirrorNotifier struct {
base.NullNotifier
}

var _ base.Notifier = &mirrorNotifier{}

// NewNotifier create a new mirrorNotifier notifier
func NewNotifier() base.Notifier {
return &mirrorNotifier{}
}

func (m *mirrorNotifier) NotifyPushCommits(pusher *user_model.User, repo *repo_model.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) {
syncPushMirrorWithSyncOnCommit(repo.ID)
}

func (m *mirrorNotifier) NotifySyncPushCommits(pusher *user_model.User, repo *repo_model.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) {
harryzcy marked this conversation as resolved.
Show resolved Hide resolved
syncPushMirrorWithSyncOnCommit(repo.ID)
}

lunny marked this conversation as resolved.
Show resolved Hide resolved
func syncPushMirrorWithSyncOnCommit(repoID int64) {
syncOnCommit := true
pushMirrors, err := repo_model.GetPushMirrorsByRepoIDWithSyncOnCommit(repoID, syncOnCommit)
harryzcy marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
log.Error("repo_model.GetPushMirrorsByRepoIDWithSyncOnCommit failed: %v", err)
harryzcy marked this conversation as resolved.
Show resolved Hide resolved
return
}

for _, mirror := range pushMirrors {
mirror_module.AddPushMirrorToQueue(mirror.ID)
}
}
2 changes: 2 additions & 0 deletions modules/notification/notification.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"code.gitea.io/gitea/modules/notification/base"
"code.gitea.io/gitea/modules/notification/indexer"
"code.gitea.io/gitea/modules/notification/mail"
"code.gitea.io/gitea/modules/notification/mirror"
"code.gitea.io/gitea/modules/notification/ui"
"code.gitea.io/gitea/modules/notification/webhook"
"code.gitea.io/gitea/modules/repository"
Expand All @@ -37,6 +38,7 @@ func NewContext() {
RegisterNotifier(indexer.NewNotifier())
RegisterNotifier(webhook.NewNotifier())
RegisterNotifier(action.NewNotifier())
RegisterNotifier(mirror.NewNotifier())
}

// NotifyCreateIssueComment notifies issue comment related message to notifiers
Expand Down
3 changes: 2 additions & 1 deletion options/locale/locale_en-US.ini
Original file line number Diff line number Diff line change
Expand Up @@ -861,8 +861,9 @@ default_branch = Default Branch
default_branch_helper = The default branch is the base branch for pull requests and code commits.
mirror_prune = Prune
mirror_prune_desc = Remove obsolete remote-tracking references
mirror_interval = Mirror Interval (valid time units are 'h', 'm', 's'). 0 to disable automatic sync. (Minimum interval: %s)
mirror_interval = Mirror Interval (valid time units are 'h', 'm', 's'). 0 to disable periodic sync. (Minimum interval: %s)
mirror_interval_invalid = The mirror interval is not valid.
mirror_sync_on_commit = Sync when new commit is pushed
harryzcy marked this conversation as resolved.
Show resolved Hide resolved
mirror_address = Clone From URL
mirror_address_desc = Put any required credentials in the Authorization section.
mirror_address_url_invalid = The provided url is invalid. You must escape all components of the url correctly.
Expand Down
4 changes: 2 additions & 2 deletions routers/api/v1/repo/mirror.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import (
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit"
"code.gitea.io/gitea/modules/context"
mirror_module "code.gitea.io/gitea/modules/mirror"
"code.gitea.io/gitea/modules/setting"
mirror_service "code.gitea.io/gitea/services/mirror"
)

// MirrorSync adds a mirrored repository to the sync queue
Expand Down Expand Up @@ -59,7 +59,7 @@ func MirrorSync(ctx *context.APIContext) {
return
}

mirror_service.StartToMirror(repo.ID)
mirror_module.AddPullMirrorToQueue(repo.ID)

ctx.Status(http.StatusOK)
}
14 changes: 8 additions & 6 deletions routers/web/repo/setting.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
"code.gitea.io/gitea/modules/indexer/stats"
"code.gitea.io/gitea/modules/lfs"
"code.gitea.io/gitea/modules/log"
mirror_module "code.gitea.io/gitea/modules/mirror"
"code.gitea.io/gitea/modules/repository"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/structs"
Expand Down Expand Up @@ -272,7 +273,7 @@ func SettingsPost(ctx *context.Context) {
return
}

mirror_service.StartToMirror(repo.ID)
mirror_module.AddPullMirrorToQueue(repo.ID)

ctx.Flash.Info(ctx.Tr("repo.settings.mirror_sync_in_progress"))
ctx.Redirect(repo.Link() + "/settings")
Expand All @@ -289,7 +290,7 @@ func SettingsPost(ctx *context.Context) {
return
}

mirror_service.AddPushMirrorToQueue(m.ID)
mirror_module.AddPushMirrorToQueue(m.ID)

ctx.Flash.Info(ctx.Tr("repo.settings.mirror_sync_in_progress"))
ctx.Redirect(repo.Link() + "/settings")
Expand Down Expand Up @@ -357,10 +358,11 @@ func SettingsPost(ctx *context.Context) {
}

m := &repo_model.PushMirror{
RepoID: repo.ID,
Repo: repo,
RemoteName: fmt.Sprintf("remote_mirror_%s", remoteSuffix),
Interval: interval,
RepoID: repo.ID,
Repo: repo,
RemoteName: fmt.Sprintf("remote_mirror_%s", remoteSuffix),
SyncOnCommit: form.PushMirrorSyncOnCommit,
Interval: interval,
}
if err := repo_model.InsertPushMirror(m); err != nil {
ctx.ServerError("InsertPushMirror", err)
Expand Down
35 changes: 18 additions & 17 deletions services/forms/repo_form.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,23 +115,24 @@ func ParseRemoteAddr(remoteAddr, authUsername, authPassword string) (string, err

// RepoSettingForm form for changing repository settings
type RepoSettingForm struct {
RepoName string `binding:"Required;AlphaDashDot;MaxSize(100)"`
Description string `binding:"MaxSize(255)"`
Website string `binding:"ValidUrl;MaxSize(255)"`
Interval string
MirrorAddress string
MirrorUsername string
MirrorPassword string
LFS bool `form:"mirror_lfs"`
LFSEndpoint string `form:"mirror_lfs_endpoint"`
PushMirrorID string
PushMirrorAddress string
PushMirrorUsername string
PushMirrorPassword string
PushMirrorInterval string
Private bool
Template bool
EnablePrune bool
RepoName string `binding:"Required;AlphaDashDot;MaxSize(100)"`
Description string `binding:"MaxSize(255)"`
Website string `binding:"ValidUrl;MaxSize(255)"`
Interval string
MirrorAddress string
MirrorUsername string
MirrorPassword string
LFS bool `form:"mirror_lfs"`
LFSEndpoint string `form:"mirror_lfs_endpoint"`
PushMirrorID string
PushMirrorAddress string
PushMirrorUsername string
PushMirrorPassword string
PushMirrorSyncOnCommit bool
PushMirrorInterval string
Private bool
Template bool
EnablePrune bool

// Advanced settings
EnableWiki bool
Expand Down
Loading