Skip to content
This repository was archived by the owner on May 30, 2024. It is now read-only.

feat: filter organizations when Gitploy sync #56

Merged
merged 4 commits into from
Aug 24, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 2 additions & 1 deletion cmd/server/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ type (
ServerProxyProto string `default:"https" split_words:"true"`
ServerProxyPort string `default:"8081" split_words:"true"`

AdminUsers []string `split_words:"true"`
OrganizationEntries []string `split_words:"true"`
AdminUsers []string `split_words:"true"`

License string `split_words:"true"`
}
Expand Down
1 change: 1 addition & 0 deletions cmd/server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ func NewInteractor(c *Config) server.Interactor {
&interactor.InteractorConfig{
ServerHost: c.ServerHost,
ServerProto: c.ServerProto,
OrgEntries: c.OrganizationEntries,
AdminUsers: c.AdminUsers,
LicenseKey: c.License,
Store: newStore(c),
Expand Down
7 changes: 7 additions & 0 deletions docs/references/GITPLOY_ORGANIZATION_ENTRIES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# GITPLOY_ORGANIZATION_ENTRIES

Optional comma-separated list of accounts, used to limit which organization(or owner) are syncronized between your source control management system and Gitploy. *Note that this variable must be set before your first login. If you don't set this environment it synchronize with all repositories the user owns.

```
GITPLOY_ORGANIZATION_ENTRIES=gitploy-io,octocat,facebook
```
1 change: 1 addition & 0 deletions docs/references/index.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Reference

* [GITPLOY_SERVER_HOST](./GITPLOY_SERVER_HOST.md)
* [GITPLOY_ORGANIZATION_ENTRIES](./GITPLOY_ORGANIZATION_ENTRIES.md)
* [GITPLOY_LICENSE](./GITPLOY_LICENSE.md)
3 changes: 3 additions & 0 deletions internal/interactor/interactor.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ type (
ServerHost string
ServerProto string

orgEntries []string
// Admin Users
admins []string

Expand All @@ -31,6 +32,7 @@ type (
ServerHost string
ServerProto string

OrgEntries []string
AdminUsers []string

LicenseKey string
Expand All @@ -44,6 +46,7 @@ func NewInteractor(c *InteractorConfig) *Interactor {
i := &Interactor{
ServerHost: c.ServerHost,
ServerProto: c.ServerProto,
orgEntries: c.OrgEntries,
admins: c.AdminUsers,
licenseKey: c.LicenseKey,
Store: c.Store,
Expand Down
14 changes: 14 additions & 0 deletions internal/interactor/sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,20 @@ import (
"github.com/hanjunlee/gitploy/vo"
)

func (i *Interactor) IsEntryOrg(ctx context.Context, namespace string) bool {
if i.orgEntries == nil {
return true
}

for _, r := range i.orgEntries {
if namespace == r {
return true
}
}

return false
}

func (i *Interactor) SyncRemoteRepo(ctx context.Context, u *ent.User, re *vo.RemoteRepo) error {
var (
r *ent.Repo
Expand Down
3 changes: 3 additions & 0 deletions internal/server/api/v1/sync/interface.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//go:generate mockgen -source ./interface.go -destination ./mock/interactor.go -package mock

package sync

import (
Expand All @@ -11,6 +13,7 @@ import (
type (
Interactor interface {
ListRemoteRepos(ctx context.Context, u *ent.User) ([]*vo.RemoteRepo, error)
IsEntryOrg(ctx context.Context, namespace string) bool
SyncRemoteRepo(ctx context.Context, u *ent.User, re *vo.RemoteRepo) error
DeletePermsOfUserLessThanUpdatedAt(ctx context.Context, u *ent.User, t time.Time) (int, error)
}
Expand Down
96 changes: 96 additions & 0 deletions internal/server/api/v1/sync/mock/interactor.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 9 additions & 1 deletion internal/server/api/v1/sync/syncher.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,20 @@ func (s *Syncher) Sync(c *gin.Context) {
}

syncTime := time.Now()
syncCnt := 0
for _, re := range remotes {
// Skip un-selected repositories.
if !s.i.IsEntryOrg(ctx, re.Namespace) {
continue
}

if err := s.i.SyncRemoteRepo(ctx, u, re); err != nil {
s.log.Error("It has failed to sync with the remote repository.", zap.Error(err), zap.String("repo_id", re.ID))
continue
}
syncCnt = syncCnt + 1
}
s.log.Debug(fmt.Sprintf("Schronize with %d repositories.", len(remotes)), zap.String("user_id", u.ID))
s.log.Debug(fmt.Sprintf("Processed to schronize with %d repositories.", syncCnt), zap.String("user_id", u.ID))

// Delete staled perms.
var cnt int
Expand Down
82 changes: 82 additions & 0 deletions internal/server/api/v1/sync/syncher_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package sync

import (
"context"
"net/http"
"net/http/httptest"
"testing"

"github.com/gin-gonic/gin"
"github.com/golang/mock/gomock"
"github.com/hanjunlee/gitploy/ent"
"github.com/hanjunlee/gitploy/internal/server/api/v1/sync/mock"
"github.com/hanjunlee/gitploy/internal/server/global"
"github.com/hanjunlee/gitploy/vo"
)

func TestSyncher_Sync(t *testing.T) {
ctx := gomock.Any()

t.Run("Synchronize with remote repositories", func(t *testing.T) {
ctrl := gomock.NewController(t)
m := mock.NewMockInteractor(ctrl)

t.Log("List remote repositories")
m.
EXPECT().
ListRemoteRepos(ctx, gomock.AssignableToTypeOf(&ent.User{})).
Return([]*vo.RemoteRepo{
{
ID: "1",
Namespace: "octocat",
Name: "HelloWorld",
},
{
ID: "1",
Namespace: "cat",
Name: "GoodBye",
},
}, nil)

t.Log("Only octocat is trusted namespace.")
m.
EXPECT().
IsEntryOrg(ctx, gomock.Any()).
DoAndReturn(func(ctx context.Context, namespace string) bool {
return namespace == "octocat"
}).
AnyTimes()

t.Log("Sync with HelloWorld only.")
m.
EXPECT().
SyncRemoteRepo(ctx, gomock.Any(), gomock.Eq(&vo.RemoteRepo{
ID: "1",
Namespace: "octocat",
Name: "HelloWorld",
})).
Return(nil)

t.Log("Delete staled perms.")
m.
EXPECT().
DeletePermsOfUserLessThanUpdatedAt(ctx, gomock.Any(), gomock.Any()).
Return(0, nil)

gin.SetMode(gin.ReleaseMode)
router := gin.New()

s := NewSyncher(m)
router.POST("/sync", func(c *gin.Context) {
c.Set(global.KeyUser, &ent.User{})
}, s.Sync)

req, _ := http.NewRequest("POST", "/sync", nil)
w := httptest.NewRecorder()

router.ServeHTTP(w, req)
if w.Code != http.StatusOK {
t.Fatalf("Sync = %v, wanted %v", w.Code, http.StatusOK)
}
})
}