1
|
|
|
<?php declare(strict_types = 1); |
2
|
|
|
/** |
3
|
|
|
* Created by Vitaly Iegorov <[email protected]>. |
4
|
|
|
* on 22.09.16 at 09:26 |
5
|
|
|
*/ |
6
|
|
|
namespace samsonframework\bitbucket; |
7
|
|
|
|
8
|
|
|
use Bitbucket\API\Authentication\AuthenticationInterface; |
9
|
|
|
use Bitbucket\API\Repositories\Changesets; |
10
|
|
|
use Bitbucket\API\Repositories\PullRequests; |
11
|
|
|
use Buzz\Message\MessageInterface; |
12
|
|
|
use Psr\Log\LoggerAwareInterface; |
13
|
|
|
use Symfony\Component\Console\Logger\ConsoleLogger; |
14
|
|
|
|
15
|
|
|
/** |
16
|
|
|
* Class BitBucketCloudReporter. |
17
|
|
|
* |
18
|
|
|
* @author Vitaly Egorov <[email protected]> |
19
|
|
|
*/ |
20
|
|
|
class CloudReporter |
21
|
|
|
{ |
22
|
|
|
/** @var PullRequests */ |
23
|
|
|
protected $pullRequests; |
24
|
|
|
|
25
|
|
|
/** @var Changesets */ |
26
|
|
|
protected $changeSets; |
27
|
|
|
|
28
|
|
|
/** @var string BitBucket account name */ |
29
|
|
|
protected $accountName; |
30
|
|
|
|
31
|
|
|
/** @var string BitBucket repository name */ |
32
|
|
|
protected $repoName; |
33
|
|
|
|
34
|
|
|
/** @var int BitBucket pull request id */ |
35
|
|
|
protected $pullRequestId; |
36
|
|
|
|
37
|
|
|
/** @var ConsoleLogger */ |
38
|
|
|
protected $logger; |
39
|
|
|
|
40
|
|
|
/** @var string Pull request author */ |
41
|
|
|
protected $author; |
42
|
|
|
|
43
|
|
|
/** @var ReporterInterface[] */ |
44
|
|
|
protected $reporters = []; |
45
|
|
|
|
46
|
|
|
public function __construct( |
47
|
|
|
AuthenticationInterface $credentials, |
48
|
|
|
ConsoleLogger $logger, |
49
|
|
|
string $accountName, |
50
|
|
|
string $repoName, |
51
|
|
|
int $pullRequestId |
52
|
|
|
) { |
53
|
|
|
$this->accountName = trim($accountName); |
54
|
|
|
$this->repoName = trim($repoName); |
55
|
|
|
$this->pullRequestId = $pullRequestId; |
56
|
|
|
$this->logger = $logger; |
57
|
|
|
|
58
|
|
|
$this->pullRequests = new PullRequests(); |
59
|
|
|
$this->pullRequests->setCredentials($credentials); |
60
|
|
|
|
61
|
|
|
$this->changesets = new Changesets(); |
|
|
|
|
62
|
|
|
$this->changesets->setCredentials(clone $credentials); |
|
|
|
|
63
|
|
|
|
64
|
|
|
$this->author = $this->getPullRequestAuthor(); |
65
|
|
|
} |
66
|
|
|
|
67
|
|
|
/** |
68
|
|
|
* Add reporter. |
69
|
|
|
* |
70
|
|
|
* @param ReporterInterface $reporter Reporter instance |
71
|
|
|
*/ |
72
|
|
|
public function addReporter(ReporterInterface $reporter) |
73
|
|
|
{ |
74
|
|
|
$this->reporters[] = $reporter; |
75
|
|
|
} |
76
|
|
|
|
77
|
|
|
/** |
78
|
|
|
* Report violations to BitBucket pull request. |
79
|
|
|
*/ |
80
|
|
|
public function report() |
81
|
|
|
{ |
82
|
|
|
// Gather all violations |
83
|
|
|
$violations = []; |
84
|
|
|
foreach ($this->reporters as $reporter) { |
85
|
|
|
if ($reporter instanceof ViolationReporterInterface) { |
86
|
|
|
/** @var ViolationReporterInterface $reporter */ |
87
|
|
|
$violations = array_merge($violations, $reporter->parseViolations()); |
88
|
|
|
} |
89
|
|
|
} |
90
|
|
|
|
91
|
|
|
$this->logger->log(ConsoleLogger::INFO, 'Found '.count($violations).' files with violations'); |
92
|
|
|
|
93
|
|
|
// Iterate only files changed by pull request |
94
|
|
|
foreach ($this->getChangedFiles() as $file) { |
95
|
|
|
// Check if we have PMD violations in that files |
96
|
|
|
if (array_key_exists($file, $violations)) { |
97
|
|
|
// Iterate file violations |
98
|
|
|
// TODO: Check lines if they are within this changeset |
99
|
|
|
foreach ($violations[$file] as $line => $violations) { |
100
|
|
|
// Iterate file line violations |
101
|
|
|
foreach ($violations as $violation) { |
102
|
|
|
// Send comment to BitBucket pull request |
103
|
|
|
$this->createFileComment($violation, $file, $line); |
104
|
|
|
} |
105
|
|
|
} |
106
|
|
|
} |
107
|
|
|
} |
108
|
|
|
|
109
|
|
|
if (array_key_exists(ScreenshotReporter::MARKER, $violations)) { |
110
|
|
|
foreach ($violations[ScreenshotReporter::MARKER][0] as $screenshot) { |
111
|
|
|
$this->createGeneralComment(''); |
112
|
|
|
} |
113
|
|
|
} |
114
|
|
|
} |
115
|
|
|
|
116
|
|
|
/** |
117
|
|
|
* Get pull request author username. |
118
|
|
|
* |
119
|
|
|
* @return string Pull request author username |
120
|
|
|
*/ |
121
|
|
|
public function getPullRequestAuthor() |
122
|
|
|
{ |
123
|
|
|
$responseString = $this->pullRequests->get($this->accountName, $this->repoName, $this->pullRequestId); |
124
|
|
|
try { |
125
|
|
|
$responseObject = json_decode($responseString->getContent()); |
126
|
|
|
|
127
|
|
|
if (isset($responseObject->error)) { |
128
|
|
|
$this->logger->critical($responseObject->error->message); |
129
|
|
|
} elseif (isset($responseObject->author)) { |
130
|
|
|
return $responseObject->author->username; |
131
|
|
|
} else { |
132
|
|
|
$this->logger->log(ConsoleLogger::INFO, 'BitBucket response has no values'); |
133
|
|
|
} |
134
|
|
|
} catch (\InvalidArgumentException $exception) { |
135
|
|
|
$this->logger->critical('Cannot json_decode BitBucket response'); |
136
|
|
|
} |
137
|
|
|
} |
138
|
|
|
|
139
|
|
|
/** |
140
|
|
|
* Collection of changed files in pull request. |
141
|
|
|
* |
142
|
|
|
* @return string[] Collection of changed files |
143
|
|
|
*/ |
144
|
|
|
public function getChangedFiles() |
145
|
|
|
{ |
146
|
|
|
$files = []; |
147
|
|
|
$responseString = $this->pullRequests->commits($this->accountName, $this->repoName, $this->pullRequestId); |
148
|
|
|
|
149
|
|
|
try { |
150
|
|
|
$responseObject = json_decode($responseString->getContent()); |
151
|
|
|
|
152
|
|
|
if (isset($responseObject->error)) { |
153
|
|
|
$this->logger->critical($responseObject->error->message); |
154
|
|
|
} elseif (isset($responseObject->values) && is_array($responseObject->values)) { |
155
|
|
|
foreach ($responseObject->values as $commit) { |
156
|
|
|
$changeSet = $this->changesets->diffstat($this->accountName, $this->repoName, $commit->hash); |
|
|
|
|
157
|
|
|
$files[] = json_decode($changeSet->getContent())[0]->file; |
158
|
|
|
} |
159
|
|
|
} else { |
160
|
|
|
$this->logger->log(ConsoleLogger::INFO, 'BitBucket response has no values'); |
161
|
|
|
} |
162
|
|
|
} catch (\InvalidArgumentException $exception) { |
163
|
|
|
$this->logger->critical('Cannot json_decode BitBucket response'); |
164
|
|
|
} |
165
|
|
|
|
166
|
|
|
return $files; |
167
|
|
|
} |
168
|
|
|
|
169
|
|
|
/** |
170
|
|
|
* Create general pull request comment. |
171
|
|
|
* |
172
|
|
|
* @param string $content The comment content |
173
|
|
|
* |
174
|
|
|
* @return MessageInterface |
175
|
|
|
*/ |
176
|
|
|
public function createGeneralComment(string $content) |
177
|
|
|
{ |
178
|
|
|
return $this->postComment(['content' => $content]); |
179
|
|
|
} |
180
|
|
|
|
181
|
|
|
/** |
182
|
|
|
* Add a new comment to pull request. |
183
|
|
|
* |
184
|
|
|
* @param string $content The comment content |
185
|
|
|
* @param null|string $filename File name |
186
|
|
|
* @param int|null $lineFrom Source code line number |
187
|
|
|
* |
188
|
|
|
* @return MessageInterface |
189
|
|
|
*/ |
190
|
|
|
public function createFileComment(string $content, string $filename = null, int $lineFrom = null) : MessageInterface |
191
|
|
|
{ |
192
|
|
|
$this->logger->log(ConsoleLogger::INFO, 'Creating comment in: '.$filename.'#'.$lineFrom.' - '.$content); |
193
|
|
|
|
194
|
|
|
return $this->postComment([ |
195
|
|
|
'content' => $content, |
196
|
|
|
'filename' => $filename, |
197
|
|
|
'line_from' => $lineFrom |
198
|
|
|
]); |
199
|
|
|
} |
200
|
|
|
|
201
|
|
|
/** |
202
|
|
|
* Low level post request for creating pull request comment. |
203
|
|
|
* |
204
|
|
|
* @param array $commentData Comment data |
205
|
|
|
* |
206
|
|
|
* @return MessageInterface |
207
|
|
|
*/ |
208
|
|
|
protected function postComment(array $commentData) |
209
|
|
|
{ |
210
|
|
|
// Add pull request author |
211
|
|
|
$commentData['content'] = '@'.$this->author.' '.$commentData['content']; |
212
|
|
|
|
213
|
|
|
// Switch to old API version |
214
|
|
|
$this->pullRequests->getClient()->setApiVersion('1.0'); |
215
|
|
|
|
216
|
|
|
return $this->pullRequests->comments()->requestPost( |
217
|
|
|
sprintf('repositories/%s/%s/pullrequests/%d/comments', $this->accountName, $this->repoName, $this->pullRequestId), |
218
|
|
|
$commentData |
219
|
|
|
); |
220
|
|
|
} |
221
|
|
|
} |
222
|
|
|
|
An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.
If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.