Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/phabricator
Path: blob/master/src/applications/diffusion/view/DiffusionCommitGraphView.php
12242 views
1
<?php
2
3
final class DiffusionCommitGraphView
4
extends DiffusionView {
5
6
private $history;
7
private $commits;
8
private $isHead;
9
private $isTail;
10
private $parents;
11
private $filterParents;
12
13
private $commitMap;
14
private $buildableMap;
15
private $revisionMap;
16
17
private $showAuditors;
18
19
public function setHistory(array $history) {
20
assert_instances_of($history, 'DiffusionPathChange');
21
$this->history = $history;
22
return $this;
23
}
24
25
public function getHistory() {
26
return $this->history;
27
}
28
29
public function setCommits(array $commits) {
30
assert_instances_of($commits, 'PhabricatorRepositoryCommit');
31
$this->commits = $commits;
32
return $this;
33
}
34
35
public function getCommits() {
36
return $this->commits;
37
}
38
39
public function setShowAuditors($show_auditors) {
40
$this->showAuditors = $show_auditors;
41
return $this;
42
}
43
44
public function getShowAuditors() {
45
return $this->showAuditors;
46
}
47
48
public function setParents(array $parents) {
49
$this->parents = $parents;
50
return $this;
51
}
52
53
public function getParents() {
54
return $this->parents;
55
}
56
57
public function setIsHead($is_head) {
58
$this->isHead = $is_head;
59
return $this;
60
}
61
62
public function getIsHead() {
63
return $this->isHead;
64
}
65
66
public function setIsTail($is_tail) {
67
$this->isTail = $is_tail;
68
return $this;
69
}
70
71
public function getIsTail() {
72
return $this->isTail;
73
}
74
75
public function setFilterParents($filter_parents) {
76
$this->filterParents = $filter_parents;
77
return $this;
78
}
79
80
public function getFilterParents() {
81
return $this->filterParents;
82
}
83
84
private function getRepository() {
85
$drequest = $this->getDiffusionRequest();
86
87
if (!$drequest) {
88
return null;
89
}
90
91
return $drequest->getRepository();
92
}
93
94
public function newObjectItemListView() {
95
$list_view = id(new PHUIObjectItemListView());
96
97
$item_views = $this->newObjectItemViews();
98
foreach ($item_views as $item_view) {
99
$list_view->addItem($item_view);
100
}
101
102
return $list_view;
103
}
104
105
private function newObjectItemViews() {
106
$viewer = $this->getViewer();
107
108
require_celerity_resource('diffusion-css');
109
110
$show_builds = $this->shouldShowBuilds();
111
$show_revisions = $this->shouldShowRevisions();
112
$show_auditors = $this->shouldShowAuditors();
113
114
$phids = array();
115
116
if ($show_revisions) {
117
$revision_map = $this->getRevisionMap();
118
foreach ($revision_map as $revisions) {
119
foreach ($revisions as $revision) {
120
$phids[] = $revision->getPHID();
121
}
122
}
123
}
124
125
$commits = $this->getCommitMap();
126
127
foreach ($commits as $commit) {
128
$author_phid = $commit->getAuthorDisplayPHID();
129
if ($author_phid !== null) {
130
$phids[] = $author_phid;
131
}
132
}
133
134
if ($show_auditors) {
135
foreach ($commits as $commit) {
136
$audits = $commit->getAudits();
137
foreach ($audits as $auditor) {
138
$phids[] = $auditor->getAuditorPHID();
139
}
140
}
141
}
142
143
$handles = $viewer->loadHandles($phids);
144
145
$views = array();
146
147
$items = $this->newHistoryItems();
148
foreach ($items as $hash => $item) {
149
$content = array();
150
151
$commit = $item['commit'];
152
153
$commit_description = $this->getCommitDescription($commit);
154
$commit_link = $this->getCommitURI($hash);
155
156
$short_hash = $this->getCommitObjectName($hash);
157
$is_disabled = $this->getCommitIsDisabled($commit);
158
159
$item_view = id(new PHUIObjectItemView())
160
->setViewer($viewer)
161
->setHeader($commit_description)
162
->setObjectName($short_hash)
163
->setHref($commit_link)
164
->setDisabled($is_disabled);
165
166
$this->addBrowseAction($item_view, $hash);
167
168
if ($show_builds) {
169
$this->addBuildAction($item_view, $hash);
170
}
171
172
$this->addAuditAction($item_view, $hash);
173
174
if ($show_auditors) {
175
$auditor_list = $item_view->newMapView();
176
if ($commit) {
177
$auditors = $this->newAuditorList($commit, $handles);
178
$auditor_list->newItem()
179
->setName(pht('Auditors'))
180
->setValue($auditors);
181
}
182
}
183
184
$property_list = $item_view->newMapView();
185
186
if ($commit) {
187
$author_view = $this->getCommitAuthorView($commit);
188
if ($author_view) {
189
$property_list->newItem()
190
->setName(pht('Author'))
191
->setValue($author_view);
192
}
193
}
194
195
if ($show_revisions) {
196
if ($commit) {
197
$revisions = $this->getRevisions($commit);
198
if ($revisions) {
199
$list_view = $handles->newSublist(mpull($revisions, 'getPHID'))
200
->newListView();
201
202
$property_list->newItem()
203
->setName(pht('Revisions'))
204
->setValue($list_view);
205
}
206
}
207
}
208
209
$views[$hash] = $item_view;
210
}
211
212
return $views;
213
}
214
215
private function newObjectItemRows() {
216
$viewer = $this->getViewer();
217
218
$items = $this->newHistoryItems();
219
$views = $this->newObjectItemViews();
220
221
$last_date = null;
222
$rows = array();
223
foreach ($items as $hash => $item) {
224
$item_epoch = $item['epoch'];
225
$item_date = phabricator_date($item_epoch, $viewer);
226
if ($item_date !== $last_date) {
227
$last_date = $item_date;
228
$header = $item_date;
229
} else {
230
$header = null;
231
}
232
233
$item_view = $views[$hash];
234
235
$list_view = id(new PHUIObjectItemListView())
236
->setViewer($viewer)
237
->setFlush(true)
238
->addItem($item_view);
239
240
if ($header !== null) {
241
$list_view->setHeader($header);
242
}
243
244
$rows[] = $list_view;
245
}
246
247
return $rows;
248
}
249
250
public function render() {
251
$rows = $this->newObjectItemRows();
252
253
$graph = $this->newGraphView();
254
foreach ($rows as $idx => $row) {
255
$cells = array();
256
257
if ($graph) {
258
$cells[] = phutil_tag(
259
'td',
260
array(
261
'class' => 'diffusion-commit-graph-path-cell',
262
),
263
$graph[$idx]);
264
}
265
266
$cells[] = phutil_tag(
267
'td',
268
array(
269
'class' => 'diffusion-commit-graph-content-cell',
270
),
271
$row);
272
273
$rows[$idx] = phutil_tag('tr', array(), $cells);
274
}
275
276
$table = phutil_tag(
277
'table',
278
array(
279
'class' => 'diffusion-commit-graph-table',
280
),
281
$rows);
282
283
return $table;
284
}
285
286
private function newGraphView() {
287
if (!$this->getParents()) {
288
return null;
289
}
290
291
$parents = $this->getParents();
292
293
// If we're filtering parents, remove relationships which point to
294
// commits that are not part of the visible graph. Otherwise, we get
295
// a big tree of nonsense when viewing release branches like "stable"
296
// versus "master".
297
if ($this->getFilterParents()) {
298
foreach ($parents as $key => $nodes) {
299
foreach ($nodes as $nkey => $node) {
300
if (empty($parents[$node])) {
301
unset($parents[$key][$nkey]);
302
}
303
}
304
}
305
}
306
307
return id(new PHUIDiffGraphView())
308
->setIsHead($this->getIsHead())
309
->setIsTail($this->getIsTail())
310
->renderGraph($parents);
311
}
312
313
private function shouldShowBuilds() {
314
$viewer = $this->getViewer();
315
316
$show_builds = PhabricatorApplication::isClassInstalledForViewer(
317
'PhabricatorHarbormasterApplication',
318
$this->getUser());
319
320
return $show_builds;
321
}
322
323
private function shouldShowRevisions() {
324
$viewer = $this->getViewer();
325
326
$show_revisions = PhabricatorApplication::isClassInstalledForViewer(
327
'PhabricatorDifferentialApplication',
328
$viewer);
329
330
return $show_revisions;
331
}
332
333
private function shouldShowAuditors() {
334
return $this->getShowAuditors();
335
}
336
337
private function newHistoryItems() {
338
$items = array();
339
340
$history = $this->getHistory();
341
if ($history !== null) {
342
foreach ($history as $history_item) {
343
$commit_hash = $history_item->getCommitIdentifier();
344
345
$items[$commit_hash] = array(
346
'epoch' => $history_item->getEpoch(),
347
'hash' => $commit_hash,
348
'commit' => $this->getCommit($commit_hash),
349
);
350
}
351
} else {
352
$commits = $this->getCommitMap();
353
foreach ($commits as $commit) {
354
$commit_hash = $commit->getCommitIdentifier();
355
356
$items[$commit_hash] = array(
357
'epoch' => $commit->getEpoch(),
358
'hash' => $commit_hash,
359
'commit' => $commit,
360
);
361
}
362
}
363
364
return $items;
365
}
366
367
private function getCommitDescription($commit) {
368
if (!$commit) {
369
return phutil_tag('em', array(), pht("Discovering\xE2\x80\xA6"));
370
}
371
372
// We can show details once the message and change have been imported.
373
$partial_import = PhabricatorRepositoryCommit::IMPORTED_MESSAGE |
374
PhabricatorRepositoryCommit::IMPORTED_CHANGE;
375
if (!$commit->isPartiallyImported($partial_import)) {
376
return phutil_tag('em', array(), pht("Importing\xE2\x80\xA6"));
377
}
378
379
return $commit->getCommitData()->getSummary();
380
}
381
382
private function getCommitURI($hash) {
383
$repository = $this->getRepository();
384
385
if ($repository) {
386
return $repository->getCommitURI($hash);
387
}
388
389
$commit = $this->getCommit($hash);
390
if ($commit) {
391
return $commit->getURI();
392
}
393
394
return null;
395
}
396
397
private function getCommitObjectName($hash) {
398
$repository = $this->getRepository();
399
400
if ($repository) {
401
return $repository->formatCommitName(
402
$hash,
403
$is_local = true);
404
}
405
406
$commit = $this->getCommit($hash);
407
if ($commit) {
408
return $commit->getDisplayName();
409
}
410
411
return null;
412
}
413
414
private function getCommitIsDisabled($commit) {
415
if (!$commit) {
416
return true;
417
}
418
419
if ($commit->isUnreachable()) {
420
return true;
421
}
422
423
return false;
424
}
425
426
private function getCommitAuthorView($commit) {
427
if (!$commit) {
428
return null;
429
}
430
431
$viewer = $this->getViewer();
432
433
$author_phid = $commit->getAuthorDisplayPHID();
434
if ($author_phid) {
435
return $viewer->loadHandles(array($author_phid))
436
->newListView();
437
}
438
439
return $commit->newCommitAuthorView($viewer);
440
}
441
442
private function getCommit($hash) {
443
$commit_map = $this->getCommitMap();
444
return idx($commit_map, $hash);
445
}
446
447
private function getCommitMap() {
448
if ($this->commitMap === null) {
449
$commit_list = $this->newCommitList();
450
$this->commitMap = mpull($commit_list, null, 'getCommitIdentifier');
451
}
452
453
return $this->commitMap;
454
}
455
456
private function addBrowseAction(PHUIObjectItemView $item, $hash) {
457
$repository = $this->getRepository();
458
459
if (!$repository) {
460
return;
461
}
462
463
$drequest = $this->getDiffusionRequest();
464
$path = $drequest->getPath();
465
466
$uri = $drequest->generateURI(
467
array(
468
'action' => 'browse',
469
'path' => $path,
470
'commit' => $hash,
471
));
472
473
$menu_item = $item->newMenuItem()
474
->setName(pht('Browse Repository'))
475
->setURI($uri);
476
477
$menu_item->newIcon()
478
->setIcon('fa-folder-open-o')
479
->setColor('bluegrey');
480
}
481
482
private function addBuildAction(PHUIObjectItemView $item, $hash) {
483
$is_disabled = true;
484
485
$buildable = null;
486
487
$commit = $this->getCommit($hash);
488
if ($commit) {
489
$buildable = $this->getBuildable($commit);
490
}
491
492
if ($buildable) {
493
$icon = $buildable->getStatusIcon();
494
$color = $buildable->getStatusColor();
495
$name = $buildable->getStatusDisplayName();
496
$uri = $buildable->getURI();
497
} else {
498
$icon = 'fa-times';
499
$color = 'grey';
500
$name = pht('No Builds');
501
$uri = null;
502
}
503
504
$menu_item = $item->newMenuItem()
505
->setName($name)
506
->setURI($uri)
507
->setDisabled(($uri === null));
508
509
$menu_item->newIcon()
510
->setIcon($icon)
511
->setColor($color);
512
}
513
514
private function addAuditAction(PHUIObjectItemView $item_view, $hash) {
515
$commit = $this->getCommit($hash);
516
517
if ($commit) {
518
$status = $commit->getAuditStatusObject();
519
520
$text = $status->getName();
521
$icon = $status->getIcon();
522
523
$is_disabled = $status->isNoAudit();
524
if ($is_disabled) {
525
$uri = null;
526
$color = 'grey';
527
} else {
528
$color = $status->getColor();
529
$uri = $commit->getURI();
530
}
531
} else {
532
$text = pht('No Audit');
533
$color = 'grey';
534
$icon = 'fa-times';
535
$uri = null;
536
537
$is_disabled = true;
538
}
539
540
$menu_item = $item_view->newMenuItem()
541
->setName($text)
542
->setURI($uri)
543
->setBackgroundColor($color)
544
->setDisabled($is_disabled);
545
546
$menu_item->newIcon()
547
->setIcon($icon)
548
->setColor($color);
549
}
550
551
private function getBuildable(PhabricatorRepositoryCommit $commit) {
552
$buildable_map = $this->getBuildableMap();
553
return idx($buildable_map, $commit->getPHID());
554
}
555
556
private function getBuildableMap() {
557
if ($this->buildableMap === null) {
558
$commits = $this->getCommitMap();
559
$buildables = $this->loadBuildables($commits);
560
$this->buildableMap = $buildables;
561
}
562
563
return $this->buildableMap;
564
}
565
566
private function getRevisions(PhabricatorRepositoryCommit $commit) {
567
$revision_map = $this->getRevisionMap();
568
return idx($revision_map, $commit->getPHID(), array());
569
}
570
571
private function getRevisionMap() {
572
if ($this->revisionMap === null) {
573
$this->revisionMap = $this->newRevisionMap();
574
}
575
576
return $this->revisionMap;
577
}
578
579
private function newRevisionMap() {
580
$viewer = $this->getViewer();
581
$commits = $this->getCommitMap();
582
583
return DiffusionCommitRevisionQuery::loadRevisionMapForCommits(
584
$viewer,
585
$commits);
586
}
587
588
private function newCommitList() {
589
$commits = $this->getCommits();
590
if ($commits !== null) {
591
return $commits;
592
}
593
594
$repository = $this->getRepository();
595
if (!$repository) {
596
return array();
597
}
598
599
$history = $this->getHistory();
600
if ($history === null) {
601
return array();
602
}
603
604
$identifiers = array();
605
foreach ($history as $item) {
606
$identifiers[] = $item->getCommitIdentifier();
607
}
608
609
if (!$identifiers) {
610
return array();
611
}
612
613
$viewer = $this->getViewer();
614
615
$commits = id(new DiffusionCommitQuery())
616
->setViewer($viewer)
617
->withRepository($repository)
618
->withIdentifiers($identifiers)
619
->needCommitData(true)
620
->needIdentities(true)
621
->execute();
622
623
return $commits;
624
}
625
626
private function newAuditorList(
627
PhabricatorRepositoryCommit $commit,
628
$handles) {
629
630
$auditors = $commit->getAudits();
631
if (!$auditors) {
632
return phutil_tag('em', array(), pht('None'));
633
}
634
635
$auditor_phids = mpull($auditors, 'getAuditorPHID');
636
$auditor_list = $handles->newSublist($auditor_phids)
637
->newListView();
638
639
return $auditor_list;
640
}
641
642
}
643
644