@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.)
hq.recaptime.dev/wiki/Phorge
phorge
phabricator
1<?php
2
3final class NuanceGitHubRawEvent extends Phobject {
4
5 private $raw;
6 private $type;
7
8 const TYPE_ISSUE = 'issue';
9 const TYPE_REPOSITORY = 'repository';
10
11 public static function newEvent($type, array $raw) {
12 $event = new self();
13 $event->type = $type;
14 $event->raw = $raw;
15 return $event;
16 }
17
18 public function getRepositoryFullName() {
19 return $this->getRepositoryFullRawName();
20 }
21
22 public function isIssueEvent() {
23 if ($this->isPullRequestEvent()) {
24 return false;
25 }
26
27 if ($this->type == self::TYPE_ISSUE) {
28 return true;
29 }
30
31 switch ($this->getIssueRawKind()) {
32 case 'IssuesEvent':
33 return true;
34 case 'IssueCommentEvent':
35 if (!$this->getRawPullRequestData()) {
36 return true;
37 }
38 break;
39 }
40
41 return false;
42 }
43
44 public function isPullRequestEvent() {
45 if ($this->type == self::TYPE_ISSUE) {
46 // TODO: This is wrong, some of these are pull events.
47 return false;
48 }
49
50 $raw = $this->raw;
51
52 switch ($this->getIssueRawKind()) {
53 case 'PullRequestEvent':
54 return true;
55 case 'IssueCommentEvent':
56 if ($this->getRawPullRequestData()) {
57 return true;
58 }
59 break;
60 }
61
62 return false;
63 }
64
65 public function getIssueNumber() {
66 if (!$this->isIssueEvent()) {
67 return null;
68 }
69
70 return $this->getRawIssueNumber();
71 }
72
73 public function getPullRequestNumber() {
74 if (!$this->isPullRequestEvent()) {
75 return null;
76 }
77
78 return $this->getRawIssueNumber();
79 }
80
81
82 public function getID() {
83 $raw = $this->raw;
84
85 $id = idx($raw, 'id');
86 if ($id) {
87 return (int)$id;
88 }
89
90 return null;
91 }
92
93 public function getComment() {
94 if (!$this->isIssueEvent() && !$this->isPullRequestEvent()) {
95 return null;
96 }
97
98 $raw = $this->raw;
99
100 return idxv($raw, array('payload', 'comment', 'body'));
101 }
102
103 public function getURI() {
104 $raw = $this->raw;
105
106 if ($this->isIssueEvent() || $this->isPullRequestEvent()) {
107 if ($this->type == self::TYPE_ISSUE) {
108 $uri = idxv($raw, array('issue', 'html_url'));
109 $uri = $uri.'#event-'.$this->getID();
110 } else {
111 // The format of pull request events varies so we need to fish around
112 // a bit to find the correct URI.
113 $uri = idxv($raw, array('payload', 'pull_request', 'html_url'));
114 $need_anchor = true;
115
116 // For comments, we get a different anchor to link to the comment. In
117 // this case, the URI comes with an anchor already.
118 if (!$uri) {
119 $uri = idxv($raw, array('payload', 'comment', 'html_url'));
120 $need_anchor = false;
121 }
122
123 if (!$uri) {
124 $uri = idxv($raw, array('payload', 'issue', 'html_url'));
125 $need_anchor = true;
126 }
127
128 if ($need_anchor) {
129 $uri = $uri.'#event-'.$this->getID();
130 }
131 }
132 } else {
133 switch ($this->getIssueRawKind()) {
134 case 'CreateEvent':
135 $ref = idxv($raw, array('payload', 'ref'));
136
137 $repo = $this->getRepositoryFullRawName();
138 return "https://github.com/{$repo}/commits/{$ref}";
139 case 'PushEvent':
140 // These don't really have a URI since there may be multiple commits
141 // involved and GitHub doesn't bundle the push as an object on its
142 // own. Just try to find the URI for the log. The API also does
143 // not return any HTML URI for these events.
144
145 $head = idxv($raw, array('payload', 'head'));
146 if ($head === null) {
147 return null;
148 }
149
150 $repo = $this->getRepositoryFullRawName();
151 return "https://github.com/{$repo}/commits/{$head}";
152 case 'WatchEvent':
153 // These have no reasonable URI.
154 return null;
155 default:
156 return null;
157 }
158 }
159
160 return $uri;
161 }
162
163 private function getRepositoryFullRawName() {
164 $raw = $this->raw;
165
166 $full = idxv($raw, array('repo', 'name'));
167 if (phutil_nonempty_string($full)) {
168 return $full;
169 }
170
171 // For issue events, the repository is not identified explicitly in the
172 // response body. Parse it out of the URI.
173
174 $matches = null;
175 $ok = preg_match(
176 '(/repos/((?:[^/]+)/(?:[^/]+))/issues/events/)',
177 idx($raw, 'url'),
178 $matches);
179
180 if ($ok) {
181 return $matches[1];
182 }
183
184 return null;
185 }
186
187 private function getIssueRawKind() {
188 $raw = $this->raw;
189 return idxv($raw, array('type'));
190 }
191
192 private function getRawIssueNumber() {
193 $raw = $this->raw;
194
195 if ($this->type == self::TYPE_ISSUE) {
196 return idxv($raw, array('issue', 'number'));
197 }
198
199 if ($this->type == self::TYPE_REPOSITORY) {
200 $issue_number = idxv($raw, array('payload', 'issue', 'number'));
201 if ($issue_number) {
202 return $issue_number;
203 }
204
205 $pull_number = idxv($raw, array('payload', 'number'));
206 if ($pull_number) {
207 return $pull_number;
208 }
209 }
210
211 return null;
212 }
213
214 private function getRawPullRequestData() {
215 $raw = $this->raw;
216 return idxv($raw, array('payload', 'issue', 'pull_request'));
217 }
218
219 public function getEventFullTitle() {
220 switch ($this->type) {
221 case self::TYPE_ISSUE:
222 $title = $this->getRawIssueEventTitle();
223 break;
224 case self::TYPE_REPOSITORY:
225 $title = $this->getRawRepositoryEventTitle();
226 break;
227 default:
228 $title = pht('Unknown Event Type ("%s")', $this->type);
229 break;
230 }
231
232 return pht(
233 'GitHub %s %s (%s)',
234 $this->getRepositoryFullRawName(),
235 $this->getTargetObjectName(),
236 $title);
237 }
238
239 public function getActorGitHubUserID() {
240 $raw = $this->raw;
241 return (int)idxv($raw, array('actor', 'id'));
242 }
243
244 private function getTargetObjectName() {
245 if ($this->isPullRequestEvent()) {
246 $number = $this->getRawIssueNumber();
247 return pht('Pull Request #%d', $number);
248 } else if ($this->isIssueEvent()) {
249 $number = $this->getRawIssueNumber();
250 return pht('Issue #%d', $number);
251 } else if ($this->type == self::TYPE_REPOSITORY) {
252 $raw = $this->raw;
253
254
255 $type = idx($raw, 'type');
256 switch ($type) {
257 case 'CreateEvent':
258 $ref = idxv($raw, array('payload', 'ref'));
259 $ref_type = idxv($raw, array('payload', 'ref_type'));
260
261 switch ($ref_type) {
262 case 'branch':
263 return pht('Branch %s', $ref);
264 case 'tag':
265 return pht('Tag %s', $ref);
266 default:
267 return pht('Ref %s', $ref);
268 }
269 case 'PushEvent':
270 $ref = idxv($raw, array('payload', 'ref'));
271 if (preg_match('(^refs/heads/)', $ref)) {
272 return pht('Branch %s', substr($ref, strlen('refs/heads/')));
273 } else {
274 return pht('Ref %s', $ref);
275 }
276 case 'WatchEvent':
277 $actor = idxv($raw, array('actor', 'login'));
278 return pht('User %s', $actor);
279 }
280
281 return pht('Unknown Object');
282 } else {
283 return pht('Unknown Object');
284 }
285 }
286
287 private function getRawIssueEventTitle() {
288 $raw = $this->raw;
289
290 $action = idxv($raw, array('event'));
291 switch ($action) {
292 case 'assigned':
293 $assignee = idxv($raw, array('assignee', 'login'));
294 $title = pht('Assigned: %s', $assignee);
295 break;
296 case 'closed':
297 $title = pht('Closed');
298 break;
299 case 'demilestoned':
300 $milestone = idxv($raw, array('milestone', 'title'));
301 $title = pht('Removed Milestone: %s', $milestone);
302 break;
303 case 'labeled':
304 $label = idxv($raw, array('label', 'name'));
305 $title = pht('Added Label: %s', $label);
306 break;
307 case 'locked':
308 $title = pht('Locked');
309 break;
310 case 'milestoned':
311 $milestone = idxv($raw, array('milestone', 'title'));
312 $title = pht('Added Milestone: %s', $milestone);
313 break;
314 case 'renamed':
315 $title = pht('Renamed');
316 break;
317 case 'reopened':
318 $title = pht('Reopened');
319 break;
320 case 'unassigned':
321 $assignee = idxv($raw, array('assignee', 'login'));
322 $title = pht('Unassigned: %s', $assignee);
323 break;
324 case 'unlabeled':
325 $label = idxv($raw, array('label', 'name'));
326 $title = pht('Removed Label: %s', $label);
327 break;
328 case 'unlocked':
329 $title = pht('Unlocked');
330 break;
331 default:
332 $title = pht('"%s"', $action);
333 break;
334 }
335
336
337 return $title;
338 }
339
340 private function getRawRepositoryEventTitle() {
341 $raw = $this->raw;
342
343 $type = idx($raw, 'type');
344 switch ($type) {
345 case 'CreateEvent':
346 return pht('Created');
347 case 'PushEvent':
348 $head = idxv($raw, array('payload', 'head'));
349 $head = substr($head, 0, 12);
350 return pht('Pushed: %s', $head);
351 case 'IssuesEvent':
352 $action = idxv($raw, array('payload', 'action'));
353 switch ($action) {
354 case 'closed':
355 return pht('Closed');
356 case 'opened':
357 return pht('Created');
358 case 'reopened':
359 return pht('Reopened');
360 default:
361 return pht('"%s"', $action);
362 }
363 case 'IssueCommentEvent':
364 $action = idxv($raw, array('payload', 'action'));
365 switch ($action) {
366 case 'created':
367 return pht('Comment');
368 default:
369 return pht('"%s"', $action);
370 }
371 case 'PullRequestEvent':
372 $action = idxv($raw, array('payload', 'action'));
373 switch ($action) {
374 case 'opened':
375 return pht('Created');
376 default:
377 return pht('"%s"', $action);
378 }
379 case 'WatchEvent':
380 return pht('Watched');
381 }
382
383 return pht('"%s"', $type);
384 }
385
386}