Skip to content

Commit

Permalink
feat: adding support for multiple events in GitLab webhook (#696)
Browse files Browse the repository at this point in the history
* feat: adding support for multiple events in GitLab webhook

* chore: fixing build error

* chore: fixing test error

* chore: reverting back to travis until we fix circle ci memory issue

* chore: remove defunct dockerfile

* fix: gitlab event source events

* fix: rename project id
  • Loading branch information
VaibhavPage authored Jun 14, 2020
1 parent df314d3 commit 82cb830
Show file tree
Hide file tree
Showing 10 changed files with 128 additions and 183 deletions.
17 changes: 0 additions & 17 deletions Dockerfile

This file was deleted.

34 changes: 5 additions & 29 deletions api/event-source.html
Original file line number Diff line number Diff line change
Expand Up @@ -1114,24 +1114,24 @@ <h3 id="argoproj.io/v1alpha1.GitlabEventSource">GitlabEventSource
</tr>
<tr>
<td>
<code>projectId</code></br>
<code>projectID</code></br>
<em>
string
</em>
</td>
<td>
<p>ProjectId is the id of project for which integration needs to setup</p>
<p>ProjectID is the id of project for which integration needs to setup</p>
</td>
</tr>
<tr>
<td>
<code>event</code></br>
<code>events</code></br>
<em>
string
[]string
</em>
</td>
<td>
<p>Event is a gitlab event to listen to.
<p>Events are gitlab event to listen to.
Refer <a href="https://github.com/xanzy/go-gitlab/blob/bf34eca5d13a9f4c3f501d8a97b8ac226d55e4d9/projects.go#L794">https://github.com/xanzy/go-gitlab/blob/bf34eca5d13a9f4c3f501d8a97b8ac226d55e4d9/projects.go#L794</a>.</p>
</td>
</tr>
Expand Down Expand Up @@ -1173,18 +1173,6 @@ <h3 id="argoproj.io/v1alpha1.GitlabEventSource">GitlabEventSource
</tr>
<tr>
<td>
<code>namespace</code></br>
<em>
string
</em>
</td>
<td>
<em>(Optional)</em>
<p>Namespace refers to Kubernetes namespace which is used to retrieve access token from.</p>
</td>
</tr>
<tr>
<td>
<code>deleteHookOnFinish</code></br>
<em>
bool
Expand All @@ -1195,18 +1183,6 @@ <h3 id="argoproj.io/v1alpha1.GitlabEventSource">GitlabEventSource
<p>DeleteHookOnFinish determines whether to delete the GitLab hook for the project once the event source is stopped.</p>
</td>
</tr>
<tr>
<td>
<code>allowDuplicate</code></br>
<em>
bool
</em>
</td>
<td>
<p>AllowDuplicate allows the gateway to register the same webhook integrations for multiple event source configurations.
Defaults to false.</p>
</td>
</tr>
</tbody>
</table>
<h3 id="argoproj.io/v1alpha1.HDFSEventSource">HDFSEventSource
Expand Down
53 changes: 4 additions & 49 deletions api/event-source.md
Original file line number Diff line number Diff line change
Expand Up @@ -2193,15 +2193,15 @@ Webhook holds configuration to run a http server

<td>

<code>projectId</code></br> <em> string </em>
<code>projectID</code></br> <em> string </em>

</td>

<td>

<p>

ProjectId is the id of project for which integration needs to setup
ProjectID is the id of project for which integration needs to setup

</p>

Expand All @@ -2213,15 +2213,15 @@ ProjectId is the id of project for which integration needs to setup

<td>

<code>event</code></br> <em> string </em>
<code>events</code></br> <em> \[\]string </em>

</td>

<td>

<p>

Event is a gitlab event to listen to. Refer
Events are gitlab event to listen to. Refer
<a href="https://github.com/xanzy/go-gitlab/blob/bf34eca5d13a9f4c3f501d8a97b8ac226d55e4d9/projects.go#L794">https://github.com/xanzy/go-gitlab/blob/bf34eca5d13a9f4c3f501d8a97b8ac226d55e4d9/projects.go\#L794</a>.

</p>
Expand Down Expand Up @@ -2299,29 +2299,6 @@ GitlabBaseURL is the base URL for API requests to a custom endpoint

<td>

<code>namespace</code></br> <em> string </em>

</td>

<td>

<em>(Optional)</em>

<p>

Namespace refers to Kubernetes namespace which is used to retrieve
access token from.

</p>

</td>

</tr>

<tr>

<td>

<code>deleteHookOnFinish</code></br> <em> bool </em>

</td>
Expand All @@ -2341,28 +2318,6 @@ project once the event source is stopped.

</tr>

<tr>

<td>

<code>allowDuplicate</code></br> <em> bool </em>

</td>

<td>

<p>

AllowDuplicate allows the gateway to register the same webhook
integrations for multiple event source configurations. Defaults to
false.

</p>

</td>

</tr>

</tbody>

</table>
Expand Down
16 changes: 7 additions & 9 deletions examples/event-sources/gitlab.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ spec:
gitlab:
example:
# id of the project
projectId: "1"
projectID: "1"
# Github will send events to following port and endpoint
webhook:
# endpoint to listen to events on
Expand All @@ -21,14 +21,11 @@ spec:
# This url must be reachable from outside the cluster.
# The gateway pod is backed by the service defined in the gateway spec. So get the URL for that service Github can reach to.
url: http://url-that-is-reachable-from-GitLab
# event to listen to
# events to listen to
# Visit https://docs.gitlab.com/ee/user/project/integrations/webhooks.html#events
event: PushEvents

# # Namespace where the api token secret live.
# # +Optional. Default to gateway's namespace.
# namespace: "argo-events"

events:
- PushEvents
- TagPushEvents
# accessToken refers to K8s secret that stores the gitlab api token
accessToken:
# Key within the K8s secret whose corresponding value (must be base64 encoded) is access token
Expand All @@ -52,7 +49,8 @@ spec:
# serverCertPath: "some path in pod"
# # path to file that is mounted in gateway pod which contains private key
# serverKeyPath: "some path in pod"
# event: "PushEvents"
# events:
# - PushEvents
# accessToken:
# key: accesskey
# name: gitlab-access
Expand Down
127 changes: 84 additions & 43 deletions gateways/server/gitlab/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,12 +125,11 @@ func (router *Router) PostActivate() error {

logger := route.Logger.WithFields(map[string]interface{}{
common.LabelEventSource: route.EventSource.Name,
"event-type": gitlabEventSource.Event,
"project-id": gitlabEventSource.ProjectId,
"project-id": gitlabEventSource.ProjectID,
})

logger.Infoln("retrieving the access token credentials...")
c, err := router.getCredentials(gitlabEventSource.AccessToken, gitlabEventSource.Namespace)
c, err := router.getCredentials(gitlabEventSource.AccessToken, router.namespace)
if err != nil {
return errors.Errorf("failed to get gitlab credentials. err: %+v", err)
}
Expand All @@ -143,51 +142,96 @@ func (router *Router) PostActivate() error {

formattedUrl := common.FormattedURL(gitlabEventSource.Webhook.URL, gitlabEventSource.Webhook.Endpoint)

// Get existing webhooks and check if the integration for same url and event type is already available
if !gitlabEventSource.AllowDuplicate {
hooks, _, err := router.gitlabClient.Projects.ListProjectHooks(router.gitlabEventSource.ProjectId, &gitlab.ListProjectHooksOptions{})
if err != nil {
return errors.Wrapf(err, "failed to list existing hooks to check for duplicates for project id %s", router.gitlabEventSource.ProjectId)
}
hooks, _, err := router.gitlabClient.Projects.ListProjectHooks(gitlabEventSource.ProjectID, &gitlab.ListProjectHooksOptions{})
if err != nil {
return errors.Wrapf(err, "failed to list existing hooks to check for duplicates for project id %s", router.gitlabEventSource.ProjectID)
}

var existingHook *gitlab.ProjectHook
isAlreadyExists := false

for _, hook := range hooks {
elem := reflect.ValueOf(hook).Elem().FieldByName(router.gitlabEventSource.Event)
if ok := elem.IsValid(); !ok {
return errors.Errorf("unknown event %s", router.gitlabEventSource.Event)
}
value := elem.Bool()

if value && hook.URL == formattedUrl {
logger.Infoln("webhook already exists, won't register it...")
return nil
}
for _, hook := range hooks {
if hook.URL == formattedUrl {
existingHook = hook
isAlreadyExists = true
}
}

opt := &gitlab.AddProjectHookOptions{
URL: &formattedUrl,
Token: &c.token,
EnableSSLVerification: &router.gitlabEventSource.EnableSSLVerification,
defaultEventValue := false

editOpt := &gitlab.EditProjectHookOptions{
URL: &formattedUrl,
ConfidentialNoteEvents: &defaultEventValue,
PushEvents: &defaultEventValue,
IssuesEvents: &defaultEventValue,
ConfidentialIssuesEvents: &defaultEventValue,
MergeRequestsEvents: &defaultEventValue,
TagPushEvents: &defaultEventValue,
NoteEvents: &defaultEventValue,
JobEvents: &defaultEventValue,
PipelineEvents: &defaultEventValue,
WikiPageEvents: &defaultEventValue,
EnableSSLVerification: &router.gitlabEventSource.EnableSSLVerification,
Token: &c.token,
}

logger.Infoln("configuring the type of the GitLab event the hook must register against...")
elem := reflect.ValueOf(opt).Elem().FieldByName(router.gitlabEventSource.Event)
if ok := elem.IsValid(); !ok {
return errors.Errorf("unknown event %s", router.gitlabEventSource.Event)
addOpt := &gitlab.AddProjectHookOptions{
URL: &formattedUrl,
Token: &c.token,
EnableSSLVerification: &router.gitlabEventSource.EnableSSLVerification,
ConfidentialNoteEvents: &defaultEventValue,
PushEvents: &defaultEventValue,
IssuesEvents: &defaultEventValue,
ConfidentialIssuesEvents: &defaultEventValue,
MergeRequestsEvents: &defaultEventValue,
TagPushEvents: &defaultEventValue,
NoteEvents: &defaultEventValue,
JobEvents: &defaultEventValue,
PipelineEvents: &defaultEventValue,
WikiPageEvents: &defaultEventValue,
}

iev := reflect.New(elem.Type().Elem())
reflect.Indirect(iev).SetBool(true)
elem.Set(iev)
var opt interface{}

logger.Infoln("creating project hook...")
hook, _, err := router.gitlabClient.Projects.AddProjectHook(router.gitlabEventSource.ProjectId, opt)
if err != nil {
return errors.Errorf("failed to add project hook. err: %+v", err)
opt = addOpt
if isAlreadyExists {
opt = editOpt
}

logger.Infoln("configuring the GitLab events for the hook...")

for _, event := range gitlabEventSource.Events {
elem := reflect.ValueOf(opt).Elem().FieldByName(event)
if ok := elem.IsValid(); !ok {
return errors.Errorf("unknown event %s", event)
}

iev := reflect.New(elem.Type().Elem())
reflect.Indirect(iev).SetBool(true)
elem.Set(iev)
}

router.hook = hook
logger.WithField("hook-id", hook.ID).Info("hook created for the project")
var newHook *gitlab.ProjectHook

if !isAlreadyExists {
logger.Infoln("creating project hook...")
newHook, _, err = router.gitlabClient.Projects.AddProjectHook(router.gitlabEventSource.ProjectID, opt.(*gitlab.AddProjectHookOptions))
if err != nil {
return errors.Errorf("failed to add project hook. err: %+v", err)
}
} else {
logger.Infoln("project hook already exists, updating it...")
if existingHook == nil {
return errors.Errorf("existing hook contents are empty, unable to edit existing webhook")
}
newHook, _, err = router.gitlabClient.Projects.EditProjectHook(router.gitlabEventSource.ProjectID, existingHook.ID, opt.(*gitlab.EditProjectHookOptions))
if err != nil {
return errors.Errorf("failed to add project hook. err: %+v", err)
}
}

router.hook = newHook
logger.WithField("hook-id", newHook.ID).Info("hook registered for the project")
return nil
}

Expand All @@ -199,12 +243,12 @@ func (router *Router) PostInactivate() error {
if gitlabEventSource.DeleteHookOnFinish {
logger := route.Logger.WithFields(map[string]interface{}{
common.LabelEventSource: route.EventSource.Name,
"project-id": gitlabEventSource.ProjectId,
"project-id": gitlabEventSource.ProjectID,
"hook-id": router.hook.ID,
})

logger.Infoln("deleting project hook...")
if _, err := router.gitlabClient.Projects.DeleteProjectHook(router.gitlabEventSource.ProjectId, router.hook.ID); err != nil {
if _, err := router.gitlabClient.Projects.DeleteProjectHook(router.gitlabEventSource.ProjectID, router.hook.ID); err != nil {
return errors.Errorf("failed to delete hook. err: %+v", err)
}

Expand All @@ -227,15 +271,12 @@ func (listener *EventListener) StartEventSource(eventSource *gateways.EventSourc
return err
}

if gitlabEventSource.Namespace == "" {
gitlabEventSource.Namespace = listener.Namespace
}

route := webhook.NewRoute(gitlabEventSource.Webhook, listener.Logger, eventSource)

return webhook.ManageRoute(&Router{
route: route,
k8sClient: listener.K8sClient,
gitlabEventSource: gitlabEventSource,
namespace: listener.Namespace,
}, controller, eventStream)
}
Loading

0 comments on commit 82cb830

Please sign in to comment.