Skip to content

Commit 5191b82

Browse files
committed
add bitbucket webhook
1 parent 8ad6b8f commit 5191b82

File tree

5 files changed

+249
-4
lines changed

5 files changed

+249
-4
lines changed

README.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<p align="center">
66
<a href="https://godoc.org/github.com/clivern/rabbit"><img src="https://godoc.org/github.com/clivern/rabbit?status.svg"></a>
77
<a href="https://travis-ci.org/Clivern/Rabbit"><img src="https://travis-ci.org/Clivern/Rabbit.svg?branch=master"></a>
8-
<a href="https://github.com/Clivern/Rabbit/releases"><img src="https://img.shields.io/badge/Version-0.0.2-red.svg"></a>
8+
<a href="https://github.com/Clivern/Rabbit/releases"><img src="https://img.shields.io/badge/Version-0.1.0-red.svg"></a>
99
<a href="https://goreportcard.com/report/github.com/Clivern/Rabbit"><img src="https://goreportcard.com/badge/github.com/Clivern/Rabbit"></a>
1010
<a href="https://github.com/Clivern/Rabbit/blob/master/LICENSE"><img src="https://img.shields.io/badge/LICENSE-MIT-orange.svg"></a>
1111
</p>
@@ -105,10 +105,22 @@ database:
105105
integrations:
106106
# Github Configs
107107
github:
108+
# Webhook URI (Full URL will be app.domain + webhook_uri)
109+
webhook_uri: /webhook/github
108110
# Webhook Secret (From Repo settings page > Webhooks)
109111
webhook_secret: Pz2ufk7r5BTjnkOo
110112
# whether to use ssh or https to clone
111113
clone_with: https
114+
# Bitbucket Configs
115+
bitbucket:
116+
# Webhook URI (Full URL will be app.domain + webhook_uri)
117+
webhook_uri: /webhook/bitbucket
118+
# whether to use ssh or https to clone
119+
clone_with: ssh
120+
# HTTPS URL format, Full name will be something like Clivern/Rabbit
121+
https_format: https://bitbucket.org/{$full_name}.git
122+
# SSH URL format, Full name will be something like Clivern/Rabbit
123+
ssh_format: [email protected]:{$full_name}.git
112124
```
113125
114126
And then run the application.

config.dist.yml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,19 @@ database:
6666
integrations:
6767
# Github Configs
6868
github:
69+
# Webhook URI (Full URL will be app.domain + webhook_uri)
70+
webhook_uri: /webhook/github
6971
# Webhook Secret (From Repo settings page > Webhooks)
7072
webhook_secret: Pz2ufk7r5BTjnkOo
7173
# whether to use ssh or https to clone
72-
clone_with: https
74+
clone_with: https
75+
# Bitbucket Configs
76+
bitbucket:
77+
# Webhook URI (Full URL will be app.domain + webhook_uri)
78+
webhook_uri: /webhook/bitbucket
79+
# whether to use ssh or https to clone
80+
clone_with: ssh
81+
# HTTPS URL format, Full name will be something like Clivern/Rabbit
82+
https_format: https://bitbucket.org/{$full_name}.git
83+
# SSH URL format, Full name will be something like Clivern/Rabbit
84+
ssh_format: [email protected]:{$full_name}.git

deployments/docker-compose/configs/config.docker.yml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,19 @@ database:
6666
integrations:
6767
# Github Configs
6868
github:
69+
# Webhook URI (Full URL will be app.domain + webhook_uri)
70+
webhook_uri: /webhook/github
6971
# Webhook Secret (From Repo settings page > Webhooks)
7072
webhook_secret: Pz2ufk7r5BTjnkOo
7173
# whether to use ssh or https to clone
72-
clone_with: https
74+
clone_with: https
75+
# Bitbucket Configs
76+
bitbucket:
77+
# Webhook URI (Full URL will be app.domain + webhook_uri)
78+
webhook_uri: /webhook/bitbucket
79+
# whether to use ssh or https to clone
80+
clone_with: ssh
81+
# HTTPS URL format, Full name will be something like Clivern/Rabbit
82+
https_format: https://bitbucket.org/{$full_name}.git
83+
# SSH URL format, Full name will be something like Clivern/Rabbit
84+
ssh_format: [email protected]:{$full_name}.git
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
// Copyright 2019 Clivern. All rights reserved.
2+
// Use of this source code is governed by the MIT
3+
// license that can be found in the LICENSE file.
4+
5+
package controller
6+
7+
import (
8+
"fmt"
9+
"github.com/clivern/hippo"
10+
"github.com/clivern/rabbit/internal/app/model"
11+
"github.com/clivern/rabbit/pkg"
12+
"github.com/gin-gonic/gin"
13+
"github.com/spf13/viper"
14+
"go.uber.org/zap"
15+
"net/http"
16+
"strings"
17+
)
18+
19+
// BitbucketListener controller
20+
func BitbucketListener(c *gin.Context, messages chan<- string) {
21+
22+
rawBody, _ := c.GetRawData()
23+
body := string(rawBody)
24+
25+
logger, _ := hippo.NewLogger(
26+
viper.GetString("log.level"),
27+
viper.GetString("log.format"),
28+
[]string{viper.GetString("log.output")},
29+
)
30+
31+
defer logger.Sync()
32+
33+
pushEvent := pkg.PushEvent{}
34+
ok, err := pushEvent.LoadFromJSON(rawBody)
35+
36+
if err != nil {
37+
logger.Info(fmt.Sprintf(
38+
`Invalid event received %s`,
39+
body,
40+
), zap.String("CorrelationID", c.Request.Header.Get("X-Correlation-ID")))
41+
42+
c.JSON(http.StatusForbidden, gin.H{
43+
"status": "Oops!",
44+
})
45+
return
46+
}
47+
48+
if ok {
49+
50+
// Push event received
51+
if len(pushEvent.Push.Changes) > 0 && pushEvent.Push.Changes[0].Created && pushEvent.Push.Changes[0].New.Type == "tag" {
52+
href := strings.ReplaceAll(
53+
viper.GetString("integrations.bitbucket.https_format"),
54+
"{$full_name}",
55+
pushEvent.Repository.FullName,
56+
)
57+
58+
if viper.GetString("integrations.bitbucket.clone_with") == "ssh" {
59+
href = strings.ReplaceAll(
60+
viper.GetString("integrations.bitbucket.ssh_format"),
61+
"{$full_name}",
62+
pushEvent.Repository.FullName,
63+
)
64+
}
65+
66+
releaseRequest := model.ReleaseRequest{
67+
Name: pushEvent.Repository.Name,
68+
URL: href,
69+
Version: pushEvent.Push.Changes[0].New.Name,
70+
}
71+
72+
validate := pkg.Validator{}
73+
74+
if validate.IsEmpty(releaseRequest.Name) {
75+
c.JSON(http.StatusBadRequest, gin.H{
76+
"status": "error",
77+
"error": "Repository name is required",
78+
})
79+
return
80+
}
81+
82+
if validate.IsEmpty(releaseRequest.URL) {
83+
c.JSON(http.StatusBadRequest, gin.H{
84+
"status": "error",
85+
"error": "Repository url is required",
86+
})
87+
return
88+
}
89+
90+
if validate.IsEmpty(releaseRequest.Version) {
91+
c.JSON(http.StatusBadRequest, gin.H{
92+
"status": "error",
93+
"error": "Repository version is required",
94+
})
95+
return
96+
}
97+
98+
requestBody, err := releaseRequest.ConvertToJSON()
99+
100+
if err != nil {
101+
logger.Error(fmt.Sprintf(
102+
`Error while converting request body to json %s`,
103+
err.Error(),
104+
), zap.String("CorrelationID", c.Request.Header.Get("X-Correlation-ID")))
105+
106+
c.JSON(http.StatusBadRequest, gin.H{
107+
"status": "error",
108+
"error": "Invalid request",
109+
})
110+
return
111+
}
112+
113+
if viper.GetString("broker.driver") == "redis" {
114+
driver := hippo.NewRedisDriver(
115+
viper.GetString("redis.addr"),
116+
viper.GetString("redis.password"),
117+
viper.GetInt("redis.db"),
118+
)
119+
120+
// connect to redis server
121+
ok, err = driver.Connect()
122+
123+
if err != nil {
124+
logger.Error(fmt.Sprintf(
125+
`Unable to connect to redis server %s`,
126+
err.Error(),
127+
), zap.String("CorrelationID", c.Request.Header.Get("X-Correlation-ID")))
128+
129+
c.JSON(http.StatusServiceUnavailable, gin.H{
130+
"status": "error",
131+
"error": "Internal server error",
132+
})
133+
return
134+
}
135+
136+
if !ok {
137+
logger.Error(
138+
`Unable to connect to redis server`,
139+
zap.String("CorrelationID", c.Request.Header.Get("X-Correlation-ID")),
140+
)
141+
142+
c.JSON(http.StatusServiceUnavailable, gin.H{
143+
"status": "error",
144+
"error": "Internal server error",
145+
})
146+
return
147+
}
148+
149+
// ping check
150+
ok, err = driver.Ping()
151+
152+
if err != nil {
153+
logger.Error(fmt.Sprintf(
154+
`Unable to ping redis server %s`,
155+
err.Error(),
156+
), zap.String("CorrelationID", c.Request.Header.Get("X-Correlation-ID")))
157+
158+
c.JSON(http.StatusServiceUnavailable, gin.H{
159+
"status": "error",
160+
"error": "Internal server error",
161+
})
162+
return
163+
}
164+
165+
if !ok {
166+
logger.Error(
167+
`Unable to ping redis server`,
168+
zap.String("CorrelationID", c.Request.Header.Get("X-Correlation-ID")),
169+
)
170+
171+
c.JSON(http.StatusServiceUnavailable, gin.H{
172+
"status": "error",
173+
"error": "Internal server error",
174+
})
175+
return
176+
}
177+
178+
logger.Info(fmt.Sprintf(
179+
`Send request [%s] to workers`,
180+
requestBody,
181+
), zap.String("CorrelationID", c.Request.Header.Get("X-Correlation-ID")))
182+
183+
driver.Publish(
184+
viper.GetString("broker.redis.channel"),
185+
requestBody,
186+
)
187+
} else {
188+
logger.Info(fmt.Sprintf(
189+
`Send request [%s] to workers`,
190+
requestBody,
191+
), zap.String("CorrelationID", c.Request.Header.Get("X-Correlation-ID")))
192+
193+
messages <- requestBody
194+
}
195+
}
196+
197+
c.JSON(http.StatusOK, gin.H{
198+
"status": "Nice!",
199+
})
200+
} else {
201+
c.JSON(http.StatusForbidden, gin.H{
202+
"status": "Oops!",
203+
})
204+
}
205+
}

rabbit.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,11 +122,15 @@ func main() {
122122
r.POST("/api/project", func(c *gin.Context) {
123123
controller.CreateProject(c, messages)
124124
})
125+
125126
r.GET("/api/project/:id", controller.GetProjectByID)
126127
r.GET("/api/project", controller.GetProjects)
127-
r.POST("/webhook/github", func(c *gin.Context) {
128+
r.POST(strings.TrimSuffix(viper.GetString("integrations.github.webhook_uri"), "/"), func(c *gin.Context) {
128129
controller.GithubListener(c, messages)
129130
})
131+
r.POST(strings.TrimSuffix(viper.GetString("integrations.bitbucket.webhook_uri"), "/"), func(c *gin.Context) {
132+
controller.BitbucketListener(c, messages)
133+
})
130134

131135
for i := 0; i < viper.GetInt("broker.native.workers"); i++ {
132136
go controller.Worker(i+1, messages)

0 commit comments

Comments
 (0)