Skip to content

Commit dc906bd

Browse files
committed
Git payload handling extracted & service support extended
1 parent 91579b1 commit dc906bd

File tree

5 files changed

+309
-36
lines changed

5 files changed

+309
-36
lines changed

src/GitHook/GitHook.php

+8-35
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
use Monolog\Logger;
1717
use Monolog\Handler\StreamHandler;
18+
use Webklex\GitHook\Payload\Payload;
1819

1920
class GitHook {
2021

@@ -95,44 +96,16 @@ public function getLogger(){
9596
public function parseRequest($rawRequest){
9697
$this->aRequest = collect(json_decode($rawRequest, true));
9798

98-
/* Check if the Request comes from bitbucket
99-
* An example payload can be found here: https://confluence.atlassian.com/bitbucket/event-payloads-740262817.html#EventPayloads-Push
100-
* */
101-
if($this->aRequest->has('push')){
102-
$aPush = $this->aRequest->get('push');
103-
$aRepository = $this->aRequest->get('repository');
104-
$aCommit = [];
105-
106-
foreach($aPush['changes'] as $aChange){
107-
foreach($aChange['commits'] as $commit){
108-
109-
$this->aRequest->put('user_name', $commit['author']['user']['display_name']);
110-
$this->aRequest->put('before', $aChange['new']['target']['parents'][0]['hash']);
111-
$this->aRequest->put('after', $aChange['new']['target']['hash']);
112-
113-
$commit['id'] = $commit['hash'];
114-
$commit['timestamp'] = $commit['date'];
115-
$commit['url'] = $commit['links']['html']['href'];
116-
$commit['author'] = [
117-
'name' => $commit['author']['user']['display_name'],
118-
'email' => '',
119-
];
120-
121-
$aCommit[] = $commit;
122-
}
123-
$this->aRequest->put('ref', 'ref/branch/'.$aChange['new']['name']);
124-
}
99+
$service = 'Webklex\GitHook\Payload\Services\\'.ucfirst($this->config['service']).'Service';
125100

126-
$aRepository['description'] = '';
127-
$aRepository['url'] = $aRepository['links']['html']['href'];
128-
$aRepository['homepage'] = $aRepository['website'];
101+
/***
102+
* @var Payload $oPayload
103+
*/
104+
$oPayload = with(new $service())->parsePayload($rawRequest);
129105

130-
$this->aRequest->put('commits', $aCommit);
131-
$this->aRequest->put('repository', $aRepository);
132-
}
106+
$this->aRequest = $oPayload->getPayload();
133107

134-
if($this->aRequest->has('commits'))
135-
$this->aRequest->put('commits', collect($this->aRequest->get('commits')));
108+
$this->aRequest->put('commits', collect($this->aRequest->get('commits')));
136109

137110
return $this->aRequest->count() > 0;
138111
}

src/GitHook/Payload/Payload.php

+189
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
<?php
2+
/*
3+
* File: Payload.php
4+
* Category: -
5+
* Author: MSG
6+
* Created: 05.03.17 05:41
7+
* Updated: -
8+
*
9+
* Description:
10+
* -
11+
*/
12+
13+
namespace Webklex\GitHook\Payload;
14+
15+
class Payload {
16+
17+
/**
18+
* Payload holder
19+
* @var array $aPayload
20+
*/
21+
protected $aPayload = [];
22+
23+
/**
24+
* Map all required attributes
25+
* @var array $map
26+
*/
27+
protected $map = [
28+
'commits' => [[
29+
'id' => null,
30+
'timestamp' => null,
31+
'message' => null,
32+
'url' => null,
33+
'author' => [
34+
'name' => null,
35+
'email' => null,
36+
],
37+
]],
38+
'repository' => [
39+
'name' => null,
40+
'description' => null,
41+
'url' => null,
42+
'homepage' => null,
43+
],
44+
'ref' => null,
45+
'user_name' => null,
46+
'before' => null,
47+
'after' => null,
48+
];
49+
50+
/**
51+
* Cast any mapped value to a given schema
52+
* @var array $casts
53+
*/
54+
protected $casts = [];
55+
56+
/**
57+
* Payload constructor.
58+
*/
59+
public function __construct() {}
60+
61+
/**
62+
* Parse a payload string into the service
63+
* @param $payload
64+
*
65+
* @return $this
66+
*/
67+
public function parsePayload($payload){
68+
if($this->isJson($payload)){
69+
$this->aPayload = $this->validate(json_decode($payload, true), $this->map);
70+
$this->castPayload();
71+
}
72+
73+
return $this;
74+
}
75+
76+
/**
77+
* Check if a given string is valid JSON
78+
* @param $string string
79+
* @return bool
80+
*/
81+
public function isJson($string) {
82+
json_decode($string);
83+
return (json_last_error() == JSON_ERROR_NONE);
84+
}
85+
86+
/**
87+
* Validate and map a given payload recursive
88+
* @param array $aPayload
89+
* @param array $aMap
90+
*
91+
* @return array
92+
*/
93+
public function validate(array $aPayload, array $aMap){
94+
$payload = [];
95+
foreach($aMap as $key => $map){
96+
if($map === ''){
97+
$payload[$key] = '';
98+
}elseif(isset($aPayload[$key])){
99+
if(is_array($aPayload[$key])){
100+
$payload[$key] = $this->validate($aPayload[$key], $map);
101+
}elseif($map != null){
102+
$payload[$key] = $this->getPayloadValue($map, $aPayload);
103+
}else{
104+
$payload[$key] = $aPayload[$key];
105+
}
106+
}elseif(is_array($map)){
107+
$payload[$key] = [];
108+
109+
foreach($map as $k => $m){
110+
if(is_array($m)){
111+
$payload[$key][$k] = $this->validate($aPayload, $m);
112+
}elseif($m != null){
113+
$payload[$key][$k] = $this->getPayloadValue($m, $aPayload);
114+
}elseif($m === ''){
115+
$payload[$key][$k] = '';
116+
}else{
117+
$payload[$key][$k] = $aPayload[$key][$k];
118+
}
119+
}
120+
}elseif($map != null){
121+
$payload[$key] = $this->getPayloadValue($map, $aPayload);
122+
}
123+
}
124+
return $payload;
125+
}
126+
127+
/**
128+
* Get a payload value from a given compact string index
129+
* @param $key
130+
* @param array $payload
131+
*
132+
* @return array|mixed
133+
*/
134+
protected function getPayloadValue($key, array $payload){
135+
$keys = explode('.', $key);
136+
foreach($keys as $i => $key){
137+
unset($keys[$i]);
138+
if(isset($payload[$key])){
139+
$payload = $payload[$key];
140+
}
141+
}
142+
143+
return $payload;
144+
}
145+
146+
/**
147+
* Cast available casts on the current payload
148+
*/
149+
protected function castPayload(){
150+
foreach($this->casts as $string => $cast){
151+
$keys = explode('.', $string);
152+
153+
$key = $keys[0];
154+
unset($keys[0]);
155+
sort($keys);
156+
157+
$this->aPayload = $this->replace($this->aPayload, $key, $keys, $cast);
158+
}
159+
}
160+
161+
/**
162+
* Cast a specific value within the payload
163+
* @param $arr array
164+
* @param $key string
165+
* @param $keys array
166+
* @param $cast string
167+
*
168+
* @return mixed
169+
*/
170+
protected function replace($arr, $key, $keys, $cast){
171+
if(!empty($keys)){
172+
$kkey = $keys[0];
173+
unset($keys[0]);
174+
sort($keys);
175+
$arr[$key] = $this->replace($arr[$key], $kkey, $keys, $cast);
176+
}else{
177+
$arr[$key] = str_replace('{$1}', $arr[$key], $cast);
178+
}
179+
return $arr;
180+
}
181+
182+
/**
183+
* Get the current payload
184+
* @return \Illuminate\Support\Collection
185+
*/
186+
public function getPayload(){
187+
return collect($this->aPayload);
188+
}
189+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?php
2+
3+
/*
4+
* File: BitbucketService.php
5+
* Category: -
6+
* Author: MSG
7+
* Created: 05.03.17 06:08
8+
* Updated: -
9+
*
10+
* Description:
11+
* An example payload can be found here:
12+
* https://confluence.atlassian.com/bitbucket/event-payloads-740262817.html#EventPayloads-Push
13+
*/
14+
15+
namespace Webklex\GitHook\Payload\Services;
16+
17+
use Webklex\GitHook\Payload\Payload;
18+
19+
class BitbucketService extends Payload {
20+
21+
protected $map = [
22+
'commits' => [[
23+
'id' => 'push.changes.0.commits.0.hash',
24+
'timestamp' => 'push.changes.0.commits.0.date',
25+
'message' => 'push.changes.0.commits.0.hash',
26+
'url' => 'push.changes.0.commits.0.links.html.href',
27+
'author' => [
28+
'name' => 'push.changes.0.commits.0.author.user.display_name',
29+
'email' => '',
30+
]
31+
]],
32+
'repository' => [
33+
'name' => 'repository.name',
34+
'description' => '',
35+
'url' => 'repository.links.html.href',
36+
'homepage' => 'repository.website',
37+
],
38+
'ref' => 'push.changes.0.new.name',
39+
'user_name' => 'push.changes.0.commits.0.author.user.display_name',
40+
'before' => 'push.changes.0.new.target.parents.0.hash',
41+
'after' => 'push.changes.0.new.target.hash',
42+
];
43+
44+
protected $casts = [
45+
'ref' => 'ref/branch/{$1}'
46+
];
47+
48+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
3+
/*
4+
* File: GithubService.php
5+
* Category: -
6+
* Author: MSG
7+
* Created: 05.03.17 18:31
8+
* Updated: -
9+
*
10+
* Description:
11+
* An example payload can be found here:
12+
* https://developer.github.com/v3/activity/events/types/#pushevent
13+
*/
14+
15+
16+
namespace Webklex\GitHook\Payload\Services;
17+
18+
use Webklex\GitHook\Payload\Payload;
19+
20+
class GithubService extends Payload {
21+
22+
protected $map = [
23+
'commits' => [[
24+
'id' => null,
25+
'timestamp' => null,
26+
'message' => null,
27+
'url' => null,
28+
'author' => [
29+
'name' => null,
30+
'email' => null,
31+
],
32+
]],
33+
'repository' => [
34+
'name' => null,
35+
'description' => null,
36+
'url' => null,
37+
'homepage' => null,
38+
],
39+
'ref' => null,
40+
'user_name' => null,
41+
'before' => null,
42+
'after' => null,
43+
];
44+
45+
protected $casts = [];
46+
47+
}

src/config/git-hook.php

+17-1
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@
9898

9999
/*
100100
|--------------------------------------------------------------------------
101-
| Logger file name
101+
| Logfile name
102102
|--------------------------------------------------------------------------
103103
|
104104
| The filename of the logfile which will be used to store deployment
@@ -112,6 +112,22 @@
112112
'logfile' => 'git-hook',
113113

114114

115+
/*
116+
|--------------------------------------------------------------------------
117+
| Remote git service
118+
|--------------------------------------------------------------------------
119+
|
120+
| Please select a service. This is required in order to parse the delivered
121+
| payload.
122+
|
123+
| Available services:
124+
| github [default]
125+
| bitbucket
126+
|
127+
*/
128+
'service' => 'github',
129+
130+
115131
/*
116132
|--------------------------------------------------------------------------
117133
| Url parameter

0 commit comments

Comments
 (0)