Skip to content

Commit 7271891

Browse files
committed
Merge master into prod, release: v1.1.29
2 parents 0b5ec35 + f8df132 commit 7271891

File tree

10 files changed

+353
-36
lines changed

10 files changed

+353
-36
lines changed

Godeps/Godeps.json

Lines changed: 6 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,12 @@ If the (commit) message includes `[skip ci]` or `[ci skip]` no build will be tri
3636
* [Assembla](https://assembla.com)
3737
* handled on the path: `/h/assembla/BITRISE-APP-SLUG/BITRISE-APP-API-TOKEN`
3838

39+
Service independent:
40+
41+
* Passthrough - reads the request headers and body and passes it to the triggered build as environment variables.
42+
* handled on the path: `/h/passthrough/BITRISE-APP-SLUG/BITRISE-APP-API-TOKEN`
43+
44+
3945
### GitHub - setup & usage:
4046

4147
All you have to do is register your `bitrise-webhooks` URL for
@@ -206,6 +212,45 @@ You can also send environment variables that will be available in your workflow
206212
An example with all parameters included: `workflow: primary|b: master|tag: v1.0|commit:eee55509f16e7715bdb43308bb55e8736da4e21e|m: start my build!|ENV[DEVICE_NAME]:iPhone 6S|ENV[DEVICE_UDID]:82667b4079914d4aabed9c216620da5dedab630a`
207213

208214

215+
### Passthrough - setup & usage:
216+
217+
Simply register or use the `.../h/passthrough/BITRISE-APP-SLUG/BITRISE-APP-API-TOKEN` url.
218+
**Every** request received on the `passthrough` endpoint will trigger a build, __no filtering is done or supported!__.
219+
220+
_The only limit is that neither the Headers nor the Body can be larger than 10kb._
221+
222+
The headers will be passed to the build in JSON serialized form, as the value of `BITRISE_WEBHOOK_PASSTHROUGH_HEADERS`.
223+
Note: headers are key value maps where the value is an array or strings, not just a single string value!
224+
Example:
225+
226+
```
227+
{
228+
"Content-Type": [
229+
"application/json"
230+
],
231+
"Some-Custom-Header-List": [
232+
"first-value",
233+
"second-value"
234+
]
235+
}
236+
```
237+
238+
The body will be passed to the build as-it-is (in string/text form), as the value of `BITRISE_WEBHOOK_PASSTHROUGH_BODY`.
239+
240+
Demo: run the server locally (e.g. with `bitrise run start`) and call the `.../h/passthrough/...` endpoint with `curl`:
241+
242+
```
243+
curl -X POST --data 'just a text body' -H 'Example-Header: example header value' 'http://localhost:4000/h/passthrough/BITRISE-APP-SLUG/BITRISE-APP-API-TOKEN'
244+
```
245+
246+
by default the server will print what and where it would send (debug mode), so you should see this in the server's log:
247+
248+
```
249+
2017/09/10 16:30:18 ===> Triggering Build: (url:https://www.bitrise.io/app/BITRISE-APP-SLUG/build/start.json)
250+
2017/09/10 16:30:18 ====> JSON body: {"build_params":{"branch":"master","environments":[{"mapped_to":"BITRISE_WEBHOOK_PASSTHROUGH_HEADERS","value":"{\"Accept\":[\"*/*\"],\"Accept-Encoding\":[\"gzip\"],\"Content-Length\":[\"16\"],\"Content-Type\":[\"application/x-www-form-urlencoded\"],\"Example-Header\":[\"example header value\"],\"User-Agent\":[\"curl/7.54.0\"],\"X-Forwarded-For\":[\"::1\"]}","is_expand":false},{"mapped_to":"BITRISE_WEBHOOK_PASSTHROUGH_BODY","value":"just a text body","is_expand":false}]},"triggered_by":"webhook"}
251+
```
252+
253+
209254
## How to compile & run the server
210255

211256
* Install [Go](https://golang.org), and [set up your Workspace](https://golang.org/doc/code.html#Workspaces) and your [$GOPATH](https://golang.org/doc/code.html#GOPATH)

bitriseapi/bitriseapi.go

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,15 @@ import (
1010
"net/http"
1111
"net/url"
1212
"time"
13+
14+
"github.com/bitrise-io/go-utils/colorstring"
1315
)
1416

1517
// EnvironmentItem ...
1618
type EnvironmentItem struct {
17-
Name string `json:"mapped_to,omitempty"`
18-
Value string `json:"value,omitempty"`
19-
IsExpand bool `json:"is_expand,omitempty"`
19+
Name string `json:"mapped_to"`
20+
Value string `json:"value"`
21+
IsExpand bool `json:"is_expand"`
2022
}
2123

2224
// BuildParamsModel ...
@@ -102,8 +104,10 @@ func TriggerBuild(url *url.URL, apiToken string, params TriggerAPIParamsModel, i
102104
return TriggerAPIResponseModel{}, false, fmt.Errorf("TriggerBuild: failed to json marshal: %s", err)
103105
}
104106

105-
log.Printf("===> Triggering Build: (url:%s)", url)
106-
log.Printf("====> JSON body: %s", jsonStr)
107+
if isOnlyLog {
108+
log.Println(colorstring.Yellowf("===> Triggering Build: (url:%s)", url))
109+
log.Println(colorstring.Yellowf("====> JSON body: %s", jsonStr))
110+
}
107111

108112
if isOnlyLog {
109113
return TriggerAPIResponseModel{

service/hook/assembla/assembla_test.go

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import (
44
"net/http"
55
"testing"
66

7-
"github.com/stretchr/testify/require"
87
"github.com/bitrise-io/bitrise-webhooks/bitriseapi"
8+
"github.com/stretchr/testify/require"
99
"io/ioutil"
1010
"strings"
1111
)
@@ -14,7 +14,7 @@ func Test_detectContentType(t *testing.T) {
1414
t.Log("Push event - should handle")
1515
{
1616
header := http.Header{
17-
"Content-Type": {"application/json"},
17+
"Content-Type": {"application/json"},
1818
}
1919
contentType, err := detectContentType(header)
2020
require.NoError(t, err)
@@ -27,20 +27,20 @@ func Test_transformPushEvent(t *testing.T) {
2727
{
2828
pushEvent := PushEventModel{
2929
SpaceEventModel: SpaceEventModel{
30-
Space: "Space name",
30+
Space: "Space name",
3131
Action: "committed",
3232
Object: "Changeset",
3333
},
3434
MessageEventModel: MessageEventModel{
35-
Title: "1 commits [branchname]",
36-
Body: "ErikPoort pushed 1 commits [branchname]\n",
35+
Title: "1 commits [branchname]",
36+
Body: "ErikPoort pushed 1 commits [branchname]\n",
3737
Author: "ErikPoort",
3838
},
3939
GitEventModel: GitEventModel{
4040
RepositorySuffix: "origin",
41-
RepositoryURL: "git@git.assembla.com:username/project.git",
42-
Branch: "branchname",
43-
CommitID: "sha1chars11",
41+
RepositoryURL: "git@git.assembla.com:username/project.git",
42+
Branch: "branchname",
43+
CommitID: "sha1chars11",
4444
},
4545
}
4646

@@ -71,20 +71,20 @@ func Test_incorrectPostOptions(t *testing.T) {
7171
{
7272
pushEvent := PushEventModel{
7373
SpaceEventModel: SpaceEventModel{
74-
Space: "Space name",
74+
Space: "Space name",
7575
Action: "committed",
7676
Object: "Changeset",
7777
},
7878
MessageEventModel: MessageEventModel{
79-
Title: "1 commits [branchname]",
80-
Body: "ErikPoort pushed 1 commits [branchname]\n",
79+
Title: "1 commits [branchname]",
80+
Body: "ErikPoort pushed 1 commits [branchname]\n",
8181
Author: "ErikPoort",
8282
},
8383
GitEventModel: GitEventModel{
8484
RepositorySuffix: "---",
85-
RepositoryURL: "---",
86-
Branch: "---",
87-
CommitID: "---",
85+
RepositoryURL: "---",
86+
Branch: "---",
87+
CommitID: "---",
8888
},
8989
}
9090

@@ -101,20 +101,20 @@ func Test_emptyGitEventOptions(t *testing.T) {
101101
{
102102
pushEvent := PushEventModel{
103103
SpaceEventModel: SpaceEventModel{
104-
Space: "Space name",
104+
Space: "Space name",
105105
Action: "committed",
106106
Object: "Changeset",
107107
},
108108
MessageEventModel: MessageEventModel{
109-
Title: "1 commits [branchname]",
110-
Body: "ErikPoort pushed 1 commits [branchname]\n",
109+
Title: "1 commits [branchname]",
110+
Body: "ErikPoort pushed 1 commits [branchname]\n",
111111
Author: "ErikPoort",
112112
},
113113
GitEventModel: GitEventModel{
114114
RepositorySuffix: "",
115-
RepositoryURL: "",
116-
Branch: "",
117-
CommitID: "",
115+
RepositoryURL: "",
116+
Branch: "",
117+
CommitID: "",
118118
},
119119
}
120120

@@ -172,7 +172,7 @@ func Test_HookProvider_TransformRequest(t *testing.T) {
172172
{
173173
request := http.Request{
174174
Header: http.Header{
175-
"Content-Type": {"not/supported"},
175+
"Content-Type": {"not/supported"},
176176
},
177177
}
178178
hookTransformResult := provider.TransformRequest(&request)
@@ -184,7 +184,7 @@ func Test_HookProvider_TransformRequest(t *testing.T) {
184184
{
185185
request := http.Request{
186186
Header: http.Header{
187-
"Content-Type": {"application/json"},
187+
"Content-Type": {"application/json"},
188188
},
189189
}
190190
hookTransformResult := provider.TransformRequest(&request)
@@ -196,7 +196,7 @@ func Test_HookProvider_TransformRequest(t *testing.T) {
196196
{
197197
request := http.Request{
198198
Header: http.Header{
199-
"Content-Type": {"application/json"},
199+
"Content-Type": {"application/json"},
200200
},
201201
Body: ioutil.NopCloser(strings.NewReader(sampleCodePushData)),
202202
}
@@ -224,11 +224,11 @@ func Test_IncorrectJSONData(t *testing.T) {
224224
{
225225
request := http.Request{
226226
Header: http.Header{
227-
"Content-Type": {"application/json"},
227+
"Content-Type": {"application/json"},
228228
},
229229
Body: ioutil.NopCloser(strings.NewReader(sampleIncorrectJSONData)),
230230
}
231231
hookTransformResult := provider.TransformRequest(&request)
232232
require.Error(t, hookTransformResult.Error)
233233
}
234-
}
234+
}

service/hook/endpoint.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,17 @@ import (
1010
"github.com/bitrise-io/bitrise-webhooks/config"
1111
"github.com/bitrise-io/bitrise-webhooks/metrics"
1212
"github.com/bitrise-io/bitrise-webhooks/service"
13+
"github.com/bitrise-io/bitrise-webhooks/service/hook/assembla"
1314
"github.com/bitrise-io/bitrise-webhooks/service/hook/bitbucketv2"
1415
hookCommon "github.com/bitrise-io/bitrise-webhooks/service/hook/common"
1516
"github.com/bitrise-io/bitrise-webhooks/service/hook/deveo"
1617
"github.com/bitrise-io/bitrise-webhooks/service/hook/github"
1718
"github.com/bitrise-io/bitrise-webhooks/service/hook/gitlab"
1819
"github.com/bitrise-io/bitrise-webhooks/service/hook/gogs"
20+
"github.com/bitrise-io/bitrise-webhooks/service/hook/passthrough"
1921
"github.com/bitrise-io/bitrise-webhooks/service/hook/slack"
2022
"github.com/bitrise-io/bitrise-webhooks/service/hook/visualstudioteamservices"
21-
"github.com/bitrise-io/bitrise-webhooks/service/hook/assembla"
23+
"github.com/bitrise-io/go-utils/colorstring"
2224
"github.com/gorilla/mux"
2325
)
2426

@@ -32,6 +34,7 @@ func supportedProviders() map[string]hookCommon.Provider {
3234
"gogs": gogs.HookProvider{},
3335
"deveo": deveo.HookProvider{},
3436
"assembla": assembla.HookProvider{},
37+
"passthrough": passthrough.HookProvider{},
3538
}
3639
}
3740

@@ -96,7 +99,7 @@ func triggerBuild(triggerURL *url.URL, apiToken string, triggerAPIParams bitrise
9699
log.Printf(" ===> trigger build: %s", triggerURL)
97100
isOnlyLog := !(config.SendRequestToURL != nil || config.GetServerEnvMode() == config.ServerEnvModeProd)
98101
if isOnlyLog {
99-
log.Println(" (debug) isOnlyLog: true")
102+
log.Println(colorstring.Yellow(" (debug) isOnlyLog: true"))
100103
}
101104

102105
responseModel, isSuccess, err := bitriseapi.TriggerBuild(triggerURL, apiToken, triggerAPIParams, isOnlyLog)
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package passthrough
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"io/ioutil"
7+
"net/http"
8+
9+
"github.com/bitrise-io/bitrise-webhooks/bitriseapi"
10+
hookCommon "github.com/bitrise-io/bitrise-webhooks/service/hook/common"
11+
)
12+
13+
const (
14+
envKeyHeaders = `BITRISE_WEBHOOK_PASSTHROUGH_HEADERS`
15+
maxHeaderSizeBytes = 10 * 1024
16+
envKeyBody = `BITRISE_WEBHOOK_PASSTHROUGH_BODY`
17+
maxBodySizeBytes = 10 * 1024
18+
)
19+
20+
// HookProvider ...
21+
type HookProvider struct{}
22+
23+
// TransformRequest ...
24+
func (hp HookProvider) TransformRequest(r *http.Request) hookCommon.TransformResultModel {
25+
headerAsJSON := []byte{}
26+
if r.Header != nil {
27+
b, err := json.Marshal(r.Header)
28+
if err != nil {
29+
return hookCommon.TransformResultModel{Error: fmt.Errorf("Failed to JSON serialize request headers: %s", err)}
30+
}
31+
headerAsJSON = b
32+
}
33+
if len(headerAsJSON) > maxHeaderSizeBytes {
34+
return hookCommon.TransformResultModel{Error: fmt.Errorf("Headers too large, larger than %d bytes", maxHeaderSizeBytes)}
35+
}
36+
37+
bodyBytes := []byte{}
38+
if r.Body != nil {
39+
b, err := ioutil.ReadAll(r.Body)
40+
if err != nil {
41+
return hookCommon.TransformResultModel{Error: fmt.Errorf("Failed to get request body: %s", err)}
42+
}
43+
bodyBytes = b
44+
}
45+
if len(bodyBytes) > maxBodySizeBytes {
46+
return hookCommon.TransformResultModel{Error: fmt.Errorf("Body too large, larger than %d bytes", maxBodySizeBytes)}
47+
}
48+
49+
environments := []bitriseapi.EnvironmentItem{
50+
bitriseapi.EnvironmentItem{Name: envKeyHeaders, Value: string(headerAsJSON), IsExpand: false},
51+
bitriseapi.EnvironmentItem{Name: envKeyBody, Value: string(bodyBytes), IsExpand: false},
52+
}
53+
54+
return hookCommon.TransformResultModel{
55+
TriggerAPIParams: []bitriseapi.TriggerAPIParamsModel{
56+
{
57+
BuildParams: bitriseapi.BuildParamsModel{
58+
Branch: "master",
59+
Environments: environments,
60+
},
61+
},
62+
},
63+
}
64+
}

0 commit comments

Comments
 (0)