1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* T3Bot. |
4
|
|
|
* |
5
|
|
|
* @author Frank Nägler <[email protected]> |
6
|
|
|
* |
7
|
|
|
* @link http://www.t3bot.de |
8
|
|
|
* @link http://wiki.typo3.org/T3Bot |
9
|
|
|
*/ |
10
|
|
|
namespace T3Bot\Commands; |
11
|
|
|
|
12
|
|
|
use Slack\Payload; |
13
|
|
|
use Slack\RealTimeClient; |
14
|
|
|
use T3Bot\Slack\Message; |
15
|
|
|
|
16
|
|
|
/** |
17
|
|
|
* Class ReviewCommand. |
18
|
|
|
* |
19
|
|
|
* @property string commandName |
20
|
|
|
* @property array helpCommands |
21
|
|
|
*/ |
22
|
|
|
class ReviewCommand extends AbstractCommand |
23
|
|
|
{ |
24
|
|
|
/** |
25
|
|
|
* AbstractCommand constructor. |
26
|
|
|
* |
27
|
|
|
* @param Payload $payload |
28
|
|
|
* @param RealTimeClient $client |
29
|
|
|
* @param array|null $configuration |
30
|
|
|
*/ |
31
|
27 |
|
public function __construct(Payload $payload, RealTimeClient $client, array $configuration = null) |
32
|
|
|
{ |
33
|
27 |
|
$this->commandName = 'review'; |
34
|
27 |
|
$this->helpCommands = [ |
35
|
|
|
'help' => 'shows this help', |
36
|
|
|
'count [PROJECT=Packages/TYPO3.CMS]' => 'shows the number of currently open reviews for [PROJECT]', |
37
|
|
|
'random' => 'shows a random open review', |
38
|
|
|
'show [Ref-ID] [[Ref-ID-2] [[Ref-ID-n]]]' => 'shows the review by given change number(s). Do not use separators other than space.', |
39
|
|
|
'user [username] [PROJECT=Packages/TYPO3.CMS]' => 'shows the open reviews by given username for [PROJECT]', |
40
|
|
|
'query [searchQuery]' => 'shows the results for given [searchQuery], max limit is 50', |
41
|
|
|
'merged [YYYY-MM-DD]' => 'shows a count of merged patches on master since given date', |
42
|
|
|
]; |
43
|
27 |
|
parent::__construct($payload, $client, $configuration); |
44
|
27 |
|
} |
45
|
|
|
|
46
|
|
|
/** |
47
|
|
|
* process count. |
48
|
|
|
* |
49
|
|
|
* @return string |
50
|
|
|
*/ |
51
|
1 |
|
protected function processCount() : string |
52
|
|
|
{ |
53
|
1 |
|
$project = !empty($this->params[1]) ? $this->params[1] : 'Packages/TYPO3.CMS'; |
54
|
1 |
|
$result = $this->queryGerrit("is:open branch:master -message:WIP project:{$project}"); |
55
|
1 |
|
$count = count($result); |
56
|
1 |
|
$result = $this->queryGerrit("label:Code-Review=-1 is:open branch:master -message:WIP project:{$project}"); |
57
|
1 |
|
$countMinus1 = count($result); |
58
|
1 |
|
$result = $this->queryGerrit("label:Code-Review=-2 is:open branch:master -message:WIP project:{$project}"); |
59
|
1 |
|
$countMinus2 = count($result); |
60
|
|
|
|
61
|
1 |
|
$returnString = ''; |
62
|
1 |
|
$returnString .= 'There are currently ' . $this->bold($count) . ' open reviews for project ' |
63
|
1 |
|
. $this->italic($project) . ' and branch master on <https://review.typo3.org/#/q/project:' . $project |
64
|
1 |
|
. '+status:open+branch:master|https://review.typo3.org>' . chr(10); |
65
|
1 |
|
$returnString .= $this->bold($countMinus1) . ' of ' . $this->bold($count) . ' open reviews voted with ' |
66
|
1 |
|
. $this->bold('-1') . ' <https://review.typo3.org/#/q/label:Code-Review%253D-1+is:open+branch:' |
67
|
1 |
|
. 'master+project:' . $project . '|Check now> ' . chr(10); |
68
|
1 |
|
$returnString .= $this->bold($countMinus2) . ' of ' . $this->bold($count) . ' open reviews voted with ' |
69
|
1 |
|
. $this->bold('-2') . ' <https://review.typo3.org/#/q/label:Code-Review%253D-2+is:open+branch:' |
70
|
1 |
|
. 'master+project:' . $project . '|Check now>'; |
71
|
|
|
|
72
|
1 |
|
return $returnString; |
73
|
|
|
} |
74
|
|
|
|
75
|
|
|
/** |
76
|
|
|
* process random. |
77
|
|
|
* |
78
|
|
|
* @return Message |
79
|
|
|
*/ |
80
|
1 |
|
protected function processRandom() : Message |
81
|
|
|
{ |
82
|
|
|
/** @var array $result */ |
83
|
1 |
|
$result = $this->queryGerrit('is:open project:Packages/TYPO3.CMS'); |
84
|
1 |
|
$item = $result[array_rand($result)]; |
85
|
|
|
|
86
|
1 |
|
return $this->buildReviewMessage($item); |
87
|
|
|
} |
88
|
|
|
|
89
|
|
|
/** |
90
|
|
|
* process user. |
91
|
|
|
* |
92
|
|
|
* @return string |
93
|
|
|
*/ |
94
|
3 |
|
protected function processUser() : string |
95
|
|
|
{ |
96
|
3 |
|
$username = $this->params[1] ?? null; |
97
|
3 |
|
$project = $this->params[2] ?? 'Packages/TYPO3.CMS'; |
98
|
3 |
|
if ($username === null) { |
99
|
1 |
|
return 'hey, I need a username!'; |
100
|
|
|
} |
101
|
2 |
|
$results = $this->queryGerrit('is:open owner:"' . $username . '" project:' . $project); |
102
|
2 |
View Code Duplication |
if (!empty($results)) { |
|
|
|
|
103
|
1 |
|
$listOfItems = ['*Here are the results for ' . $username . '*:']; |
104
|
1 |
|
foreach ($results as $item) { |
|
|
|
|
105
|
1 |
|
$listOfItems[] = $this->buildReviewLine($item); |
106
|
|
|
} |
107
|
1 |
|
return implode(chr(10), $listOfItems); |
108
|
|
|
} |
109
|
1 |
|
return $username . ' has no open reviews or username is unknown'; |
110
|
|
|
} |
111
|
|
|
|
112
|
|
|
/** |
113
|
|
|
* process count. |
114
|
|
|
* |
115
|
|
|
* @return string|Message |
116
|
|
|
*/ |
117
|
14 |
|
protected function processShow() |
118
|
|
|
{ |
119
|
14 |
|
$urlPattern = '/http[s]*:\/\/review.typo3.org\/[#\/c]*([\d]*)(?:.*)/i'; |
120
|
14 |
|
$refId = $this->params[1] ?? 0; |
121
|
14 |
|
if (preg_match_all($urlPattern, $refId, $matches)) { |
122
|
4 |
|
$refId = (int) $matches[1][0]; |
123
|
|
|
} else { |
124
|
10 |
|
$refId = (int) $refId; |
125
|
|
|
} |
126
|
14 |
|
if ($refId === 0) { |
127
|
2 |
|
return 'hey, I need at least one change number!'; |
128
|
|
|
} |
129
|
12 |
|
$paramsCount = count($this->params); |
130
|
12 |
|
if ($paramsCount > 2) { |
131
|
1 |
|
$returnMessage = $this->buildReviewLineOutput(); |
132
|
|
|
} else { |
133
|
11 |
|
$returnMessage = $this->buildReviewMessageOutput($refId); |
134
|
|
|
} |
135
|
|
|
|
136
|
12 |
|
return $returnMessage; |
137
|
|
|
} |
138
|
|
|
|
139
|
|
|
/** |
140
|
|
|
* @return string |
141
|
|
|
*/ |
142
|
1 |
|
protected function buildReviewLineOutput() : string |
143
|
|
|
{ |
144
|
1 |
|
$paramsCount = count($this->params); |
145
|
1 |
|
$changeIds = []; |
146
|
1 |
|
for ($i = 1; $i < $paramsCount; ++$i) { |
147
|
1 |
|
$changeIds[] = 'change:' . $this->params[$i]; |
148
|
|
|
} |
149
|
1 |
|
$result = $this->queryGerrit(implode(' OR ', $changeIds)); |
150
|
1 |
|
$listOfItems = []; |
151
|
1 |
|
if (is_array($result)) { |
152
|
1 |
|
foreach ($result as $item) { |
153
|
1 |
|
$listOfItems[] = $this->buildReviewLine($item); |
154
|
|
|
} |
155
|
|
|
} |
156
|
1 |
|
return implode(chr(10), $listOfItems); |
157
|
|
|
} |
158
|
|
|
|
159
|
|
|
/** |
160
|
|
|
* @param int $refId |
161
|
|
|
* |
162
|
|
|
* @return string|Message |
163
|
|
|
*/ |
164
|
11 |
|
protected function buildReviewMessageOutput(int $refId) |
165
|
|
|
{ |
166
|
11 |
|
$result = $this->queryGerrit('change:' . $refId); |
167
|
11 |
|
if (!empty($result)) { |
168
|
10 |
|
foreach ($result as $item) { |
|
|
|
|
169
|
10 |
|
if ($item->_number === $refId) { |
170
|
10 |
|
return $this->buildReviewMessage($item); |
171
|
|
|
} |
172
|
|
|
} |
173
|
|
|
} |
174
|
1 |
|
return "{$refId} not found, sorry!"; |
175
|
|
|
} |
176
|
|
|
|
177
|
|
|
/** |
178
|
|
|
* process query. |
179
|
|
|
* |
180
|
|
|
* @return string |
181
|
|
|
*/ |
182
|
3 |
|
protected function processQuery() : string |
183
|
|
|
{ |
184
|
3 |
|
array_shift($this->params); |
185
|
3 |
|
$query = trim(implode(' ', $this->params)); |
186
|
3 |
|
if ($query === '') { |
187
|
1 |
|
return 'hey, I need a query!'; |
188
|
|
|
} |
189
|
|
|
|
190
|
2 |
|
$results = $this->queryGerrit('limit:50 ' . $query); |
191
|
2 |
View Code Duplication |
if (!empty($results)) { |
|
|
|
|
192
|
1 |
|
$listOfItems = ["*Here are the results for {$query}*:"]; |
193
|
1 |
|
foreach ($results as $item) { |
|
|
|
|
194
|
1 |
|
$listOfItems[] = $this->buildReviewLine($item); |
195
|
|
|
} |
196
|
1 |
|
return implode(chr(10), $listOfItems); |
197
|
|
|
} |
198
|
|
|
|
199
|
1 |
|
return "{$query} not found, sorry!"; |
200
|
|
|
} |
201
|
|
|
|
202
|
|
|
/** |
203
|
|
|
* @return string |
204
|
|
|
*/ |
205
|
3 |
|
protected function processMerged() : string |
206
|
|
|
{ |
207
|
3 |
|
$query = 'project:Packages/TYPO3.CMS status:merged after:###DATE### branch:master'; |
208
|
|
|
|
209
|
3 |
|
$date = !empty($this->params[1]) ? $this->params[1] : ''; |
210
|
3 |
|
if (!$this->isDateFormatCorrect($date)) { |
211
|
2 |
|
return 'hey, I need a date in the format YYYY-MM-DD!'; |
212
|
|
|
} |
213
|
1 |
|
$query = str_replace('###DATE###', $date, $query); |
214
|
1 |
|
$result = $this->queryGerrit($query); |
215
|
|
|
|
216
|
1 |
|
$cnt = count($result); |
217
|
|
|
|
218
|
1 |
|
return 'Good job folks, since ' . $date . ' you merged *' . $cnt . '* patches into master'; |
219
|
|
|
} |
220
|
|
|
|
221
|
|
|
/** |
222
|
|
|
* check format of given date. |
223
|
|
|
* |
224
|
|
|
* @param $date |
225
|
|
|
* |
226
|
|
|
* @return bool |
227
|
|
|
*/ |
228
|
3 |
|
protected function isDateFormatCorrect($date) : bool |
229
|
|
|
{ |
230
|
3 |
|
return preg_match('/[\d]{4}-[\d]{2}-[\d]{2}/', $date) === 1; |
231
|
|
|
} |
232
|
|
|
} |
233
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.