Skip to content

Commit

Permalink
feat(eventsource): Gitlab eventsource - support groups (#2386) (#2474)
Browse files Browse the repository at this point in the history
Signed-off-by: neo502721 <zgmhdu@163.com>
  • Loading branch information
neo502721 committed Feb 23, 2023
1 parent a576601 commit 0564890
Show file tree
Hide file tree
Showing 15 changed files with 671 additions and 442 deletions.
16 changes: 15 additions & 1 deletion api/event-source.html

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

16 changes: 15 additions & 1 deletion api/event-source.md

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

9 changes: 8 additions & 1 deletion api/jsonschema/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -1775,6 +1775,13 @@
"description": "GitlabBaseURL is the base URL for API requests to a custom endpoint",
"type": "string"
},
"groups": {
"description": "List of group IDs or group name like \"test\". Group level hook available in Premium and Ultimate Gitlab.",
"items": {
"type": "string"
},
"type": "array"
},
"metadata": {
"additionalProperties": {
"type": "string"
Expand All @@ -1787,7 +1794,7 @@
"type": "string"
},
"projects": {
"description": "List of project IDs or project namespace paths like \"whynowy/test\"",
"description": "List of project IDs or project namespace paths like \"whynowy/test\". Projects and groups cannot be empty at the same time.",
"items": {
"type": "string"
},
Expand Down
9 changes: 8 additions & 1 deletion api/openapi-spec/swagger.json

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

25 changes: 25 additions & 0 deletions eventsources/sources/gitlab/hook_util.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package gitlab

import (
"github.com/xanzy/go-gitlab"
)

func getProjectHook(hooks []*gitlab.ProjectHook, url string) *gitlab.ProjectHook {
for _, h := range hooks {
if h.URL != url {
continue
}
return h
}
return nil
}

func getGroupHook(hooks []*gitlab.GroupHook, url string) *gitlab.GroupHook {
for _, h := range hooks {
if h.URL != url {
continue
}
return h
}
return nil
}
36 changes: 36 additions & 0 deletions eventsources/sources/gitlab/hook_util_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package gitlab

import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/xanzy/go-gitlab"
)

func TestGetGroupHook(t *testing.T) {
hooks := []*gitlab.GroupHook{
{
URL: "https://example0.com/",
},
{
URL: "https://example1.com/",
},
}

assert.Equal(t, hooks[1], getGroupHook(hooks, "https://example1.com/"))
assert.Nil(t, getGroupHook(hooks, "https://example.com/"))
}

func TestGetProjectHook(t *testing.T) {
hooks := []*gitlab.ProjectHook{
{
URL: "https://example0.com/",
},
{
URL: "https://example1.com/",
},
}

assert.Equal(t, hooks[1], getProjectHook(hooks, "https://example1.com/"))
assert.Nil(t, getProjectHook(hooks, "https://example.com/"))
}
62 changes: 49 additions & 13 deletions eventsources/sources/gitlab/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,19 @@ func (router *Router) PostInactivate() error {
logger := router.route.Logger
logger.Info("deleting Gitlab hooks...")

for _, g := range gitlabEventSource.GetGroups() {
id, ok := router.groupHookIDs[g]
if !ok {
return fmt.Errorf("can not find hook ID for group %s", g)
}
if _, err := router.gitlabClient.Groups.DeleteGroupHook(g, id); err != nil {
return fmt.Errorf("failed to delete hook for group %s. err: %w", g, err)
}
logger.Infof("Gitlab hook deleted for group %s", g)
}

for _, p := range gitlabEventSource.GetProjects() {
id, ok := router.hookIDs[p]
id, ok := router.projectHookIDs[p]
if !ok {
return fmt.Errorf("can not find hook ID for project %s", p)
}
Expand All @@ -158,6 +169,8 @@ func (el *EventListener) StartListening(ctx context.Context, dispatch func([]byt
router := &Router{
route: route,
gitlabEventSource: gitlabEventSource,
projectHookIDs: make(map[string]int),
groupHookIDs: make(map[string]int),
}

if gitlabEventSource.NeedToCreateHooks() {
Expand Down Expand Up @@ -195,6 +208,20 @@ func (el *EventListener) StartListening(ctx context.Context, dispatch func([]byt
reflect.Indirect(iev).SetBool(true)
elem.Set(iev)
}
groupHookOpt := &gitlab.AddGroupHookOptions{
URL: opt.URL,
EnableSSLVerification: opt.EnableSSLVerification,
ConfidentialNoteEvents: opt.ConfidentialNoteEvents,
PushEvents: opt.PushEvents,
IssuesEvents: opt.IssuesEvents,
ConfidentialIssuesEvents: opt.ConfidentialIssuesEvents,
MergeRequestsEvents: opt.MergeRequestsEvents,
TagPushEvents: opt.TagPushEvents,
NoteEvents: opt.NoteEvents,
JobEvents: opt.JobEvents,
PipelineEvents: opt.PipelineEvents,
WikiPageEvents: opt.WikiPageEvents,
}

if gitlabEventSource.SecretToken != nil {
token, err := common.GetSecretFromVolume(gitlabEventSource.SecretToken)
Expand All @@ -216,28 +243,37 @@ func (el *EventListener) StartListening(ctx context.Context, dispatch func([]byt
return fmt.Errorf("failed to initialize client, %w", err)
}

getHook := func(hooks []*gitlab.ProjectHook, url string) *gitlab.ProjectHook {
for _, h := range hooks {
if h.URL != url {
f := func() {
for _, g := range gitlabEventSource.GetGroups() {
hooks, _, err := router.gitlabClient.Groups.ListGroupHooks(g, &gitlab.ListGroupHooksOptions{})
if err != nil {
logger.Errorf("failed to list existing webhooks of group %s. err: %+v", g, err)
continue
}
hook := getGroupHook(hooks, formattedURL)
if hook != nil {
router.groupHookIDs[g] = hook.ID
continue
}
logger.Infof("hook not found for group %s, creating ...", g)
hook, _, err = router.gitlabClient.Groups.AddGroupHook(g, groupHookOpt)
if err != nil {
logger.Errorf("failed to create gitlab webhook for group %s. err: %+v", g, err)
continue
}
return h
router.groupHookIDs[g] = hook.ID
time.Sleep(500 * time.Millisecond)
}
return nil
}

router.hookIDs = make(map[string]int)

f := func() {
for _, p := range gitlabEventSource.GetProjects() {
hooks, _, err := router.gitlabClient.Projects.ListProjectHooks(p, &gitlab.ListProjectHooksOptions{})
if err != nil {
logger.Errorf("failed to list existing webhooks of project %s. err: %+v", p, err)
continue
}
hook := getHook(hooks, formattedURL)
hook := getProjectHook(hooks, formattedURL)
if hook != nil {
router.hookIDs[p] = hook.ID
router.projectHookIDs[p] = hook.ID
continue
}
logger.Infof("hook not found for project %s, creating ...", p)
Expand All @@ -246,7 +282,7 @@ func (el *EventListener) StartListening(ctx context.Context, dispatch func([]byt
logger.Errorf("failed to create gitlab webhook for project %s. err: %+v", p, err)
continue
}
router.hookIDs[p] = hook.ID
router.projectHookIDs[p] = hook.ID
time.Sleep(500 * time.Millisecond)
}
}
Expand Down
4 changes: 3 additions & 1 deletion eventsources/sources/gitlab/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@ type Router struct {
// gitlabClient is the client to connect to GitLab
gitlabClient *gitlab.Client
// projectID -> hook ID
hookIDs map[string]int
projectHookIDs map[string]int
// groupID -> hook ID
groupHookIDs map[string]int
// gitlabEventSource is the event source that contains configuration necessary to consume events from GitLab
gitlabEventSource *v1alpha1.GitlabEventSource
// gitlab webhook secret token
Expand Down
4 changes: 2 additions & 2 deletions eventsources/sources/gitlab/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ func validate(eventSource *v1alpha1.GitlabEventSource) error {
if eventSource == nil {
return common.ErrNilEventSource
}
if len(eventSource.GetProjects()) == 0 {
return fmt.Errorf("projects can't be empty")
if len(eventSource.GetProjects()) == 0 && len(eventSource.GetGroups()) == 0 {
return fmt.Errorf("projects and groups cannot be empty at the same time")
}
if eventSource.Events == nil {
return fmt.Errorf("events can't be empty")
Expand Down
2 changes: 1 addition & 1 deletion eventsources/sources/gitlab/validate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func TestValidateEventSource(t *testing.T) {

err := listener.ValidateEventSource(context.Background())
assert.Error(t, err)
assert.Equal(t, "projects can't be empty", err.Error())
assert.Equal(t, "projects and groups cannot be empty at the same time", err.Error())

content, err := os.ReadFile(fmt.Sprintf("%s/%s", sources.EventSourceDir, "gitlab.yaml"))
assert.Nil(t, err)
Expand Down

0 comments on commit 0564890

Please sign in to comment.