@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 PhabricatorRepositoryCommit
4 extends PhabricatorRepositoryDAO
5 implements
6 PhabricatorPolicyInterface,
7 PhabricatorFlaggableInterface,
8 PhabricatorProjectInterface,
9 PhabricatorTokenReceiverInterface,
10 PhabricatorSubscribableInterface,
11 PhabricatorMentionableInterface,
12 HarbormasterBuildableInterface,
13 HarbormasterCircleCIBuildableInterface,
14 HarbormasterBuildkiteBuildableInterface,
15 PhabricatorCustomFieldInterface,
16 PhabricatorApplicationTransactionInterface,
17 PhabricatorTimelineInterface,
18 PhabricatorFulltextInterface,
19 PhabricatorFerretInterface,
20 PhabricatorConduitResultInterface,
21 PhabricatorDraftInterface {
22
23 protected $repositoryID;
24 protected $phid;
25 protected $authorIdentityPHID;
26 protected $committerIdentityPHID;
27 protected $commitIdentifier;
28 protected $epoch;
29 protected $authorPHID;
30 protected $auditStatus = DiffusionCommitAuditStatus::NONE;
31 protected $summary = '';
32 protected $importStatus = 0;
33
34 const IMPORTED_MESSAGE = 1;
35 const IMPORTED_CHANGE = 2;
36 const IMPORTED_PUBLISH = 8;
37 const IMPORTED_ALL = 11;
38
39 const IMPORTED_PERMANENT = 1024;
40 const IMPORTED_UNREACHABLE = 2048;
41
42 private $commitData = self::ATTACHABLE;
43 private $audits = self::ATTACHABLE;
44 private $repository = self::ATTACHABLE;
45 private $customFields = self::ATTACHABLE;
46 private $authorIdentity = self::ATTACHABLE;
47 private $committerIdentity = self::ATTACHABLE;
48
49 private $drafts = array();
50 private $auditAuthorityPHIDs = array();
51
52 public function attachRepository(PhabricatorRepository $repository) {
53 $this->repository = $repository;
54 return $this;
55 }
56
57 public function getRepository($assert_attached = true) {
58 if ($assert_attached) {
59 return $this->assertAttached($this->repository);
60 }
61 return $this->repository;
62 }
63
64 public function isPartiallyImported($mask) {
65 return (($mask & $this->getImportStatus()) == $mask);
66 }
67
68 public function isImported() {
69 return $this->isPartiallyImported(self::IMPORTED_ALL);
70 }
71
72 public function isUnreachable() {
73 return $this->isPartiallyImported(self::IMPORTED_UNREACHABLE);
74 }
75
76 public function writeImportStatusFlag($flag) {
77 return $this->adjustImportStatusFlag($flag, true);
78 }
79
80 public function clearImportStatusFlag($flag) {
81 return $this->adjustImportStatusFlag($flag, false);
82 }
83
84 private function adjustImportStatusFlag(int $flag, $set) {
85 $conn_w = $this->establishConnection('w');
86 $table_name = $this->getTableName();
87 $id = $this->getID();
88
89 if ($set) {
90 queryfx(
91 $conn_w,
92 'UPDATE %T SET importStatus = (importStatus | %d) WHERE id = %d',
93 $table_name,
94 $flag,
95 $id);
96
97 $this->setImportStatus($this->getImportStatus() | $flag);
98 } else {
99 queryfx(
100 $conn_w,
101 'UPDATE %T SET importStatus = (importStatus & ~%d) WHERE id = %d',
102 $table_name,
103 $flag,
104 $id);
105
106 $this->setImportStatus($this->getImportStatus() & ~$flag);
107 }
108
109 return $this;
110 }
111
112 protected function getConfiguration() {
113 return array(
114 self::CONFIG_AUX_PHID => true,
115 self::CONFIG_TIMESTAMPS => false,
116 self::CONFIG_COLUMN_SCHEMA => array(
117 'commitIdentifier' => 'text40',
118 'authorPHID' => 'phid?',
119 'authorIdentityPHID' => 'phid?',
120 'committerIdentityPHID' => 'phid?',
121 'auditStatus' => 'text32',
122 'summary' => 'text255',
123 'importStatus' => 'uint32',
124 ),
125 self::CONFIG_KEY_SCHEMA => array(
126 'key_phid' => null,
127 'phid' => array(
128 'columns' => array('phid'),
129 'unique' => true,
130 ),
131 'repositoryID' => array(
132 'columns' => array('repositoryID', 'importStatus'),
133 ),
134 'authorPHID' => array(
135 'columns' => array('authorPHID', 'auditStatus', 'epoch'),
136 ),
137 'repositoryID_2' => array(
138 'columns' => array('repositoryID', 'epoch'),
139 ),
140 'key_commit_identity' => array(
141 'columns' => array('commitIdentifier', 'repositoryID'),
142 'unique' => true,
143 ),
144 'key_epoch' => array(
145 'columns' => array('epoch'),
146 ),
147 'key_author' => array(
148 'columns' => array('authorPHID', 'epoch'),
149 ),
150 ),
151 self::CONFIG_NO_MUTATE => array(
152 'importStatus',
153 ),
154 ) + parent::getConfiguration();
155 }
156
157 public function generatePHID() {
158 return PhabricatorPHID::generateNewPHID(
159 PhabricatorRepositoryCommitPHIDType::TYPECONST);
160 }
161
162 public function loadCommitData() {
163 if (!$this->getID()) {
164 return null;
165 }
166 return id(new PhabricatorRepositoryCommitData())->loadOneWhere(
167 'commitID = %d',
168 $this->getID());
169 }
170
171 public function attachCommitData(
172 ?PhabricatorRepositoryCommitData $data = null) {
173 $this->commitData = $data;
174 return $this;
175 }
176
177 public function hasCommitData() {
178 return ($this->commitData !== self::ATTACHABLE) &&
179 ($this->commitData !== null);
180 }
181
182 public function getCommitData() {
183 return $this->assertAttached($this->commitData);
184 }
185
186 /**
187 * @param array<PhabricatorRepositoryAuditRequest> $audits
188 */
189 public function attachAudits(array $audits) {
190 assert_instances_of($audits, PhabricatorRepositoryAuditRequest::class);
191 $this->audits = $audits;
192 return $this;
193 }
194
195 public function getAudits() {
196 return $this->assertAttached($this->audits);
197 }
198
199 public function hasAttachedAudits() {
200 return ($this->audits !== self::ATTACHABLE);
201 }
202
203 public function attachIdentities(
204 ?PhabricatorRepositoryIdentity $author = null,
205 ?PhabricatorRepositoryIdentity $committer = null) {
206
207 $this->authorIdentity = $author;
208 $this->committerIdentity = $committer;
209
210 return $this;
211 }
212
213 public function getAuthorIdentity() {
214 return $this->assertAttached($this->authorIdentity);
215 }
216
217 public function getCommitterIdentity() {
218 return $this->assertAttached($this->committerIdentity);
219 }
220
221 public function attachAuditAuthority(
222 PhabricatorUser $user,
223 array $authority) {
224
225 $user_phid = $user->getPHID();
226 if (!$user->getPHID()) {
227 throw new Exception(
228 pht('You can not attach audit authority for a user with no PHID.'));
229 }
230
231 $this->auditAuthorityPHIDs[$user_phid] = $authority;
232
233 return $this;
234 }
235
236 public function hasAuditAuthority(
237 PhabricatorUser $user,
238 PhabricatorRepositoryAuditRequest $audit) {
239
240 $user_phid = $user->getPHID();
241 if (!$user_phid) {
242 return false;
243 }
244
245 $map = $this->assertAttachedKey($this->auditAuthorityPHIDs, $user_phid);
246
247 return isset($map[$audit->getAuditorPHID()]);
248 }
249
250 public function writeOwnersEdges(array $package_phids) {
251 $src_phid = $this->getPHID();
252 $edge_type = DiffusionCommitHasPackageEdgeType::EDGECONST;
253
254 $editor = new PhabricatorEdgeEditor();
255
256 $dst_phids = PhabricatorEdgeQuery::loadDestinationPHIDs(
257 $src_phid,
258 $edge_type);
259
260 foreach ($dst_phids as $dst_phid) {
261 $editor->removeEdge($src_phid, $edge_type, $dst_phid);
262 }
263
264 foreach ($package_phids as $package_phid) {
265 $editor->addEdge($src_phid, $edge_type, $package_phid);
266 }
267
268 $editor->save();
269
270 return $this;
271 }
272
273 public function getAuditorPHIDsForEdit() {
274 $audits = $this->getAudits();
275 return mpull($audits, 'getAuditorPHID');
276 }
277
278 public function delete() {
279 $data = $this->loadCommitData();
280 $audits = id(new PhabricatorRepositoryAuditRequest())
281 ->loadAllWhere('commitPHID = %s', $this->getPHID());
282 $this->openTransaction();
283
284 if ($data) {
285 $data->delete();
286 }
287 foreach ($audits as $audit) {
288 $audit->delete();
289 }
290 $result = parent::delete();
291
292 $this->saveTransaction();
293 return $result;
294 }
295
296 public function getDateCreated() {
297 // This is primarily to make analysis of commits with the Fact engine work.
298 return $this->getEpoch();
299 }
300
301 public function getURI() {
302 return '/'.$this->getMonogram();
303 }
304
305 /**
306 * Synchronize a commit's overall audit status with the individual audit
307 * triggers.
308 *
309 * @param array<PhabricatorRepositoryAuditRequest> $requests
310 */
311 public function updateAuditStatus(array $requests) {
312 assert_instances_of($requests, PhabricatorRepositoryAuditRequest::class);
313
314 $any_concern = false;
315 $any_accept = false;
316 $any_need = false;
317
318 foreach ($requests as $request) {
319 switch ($request->getAuditStatus()) {
320 case PhabricatorAuditRequestStatus::AUDIT_REQUIRED:
321 case PhabricatorAuditRequestStatus::AUDIT_REQUESTED:
322 $any_need = true;
323 break;
324 case PhabricatorAuditRequestStatus::ACCEPTED:
325 $any_accept = true;
326 break;
327 case PhabricatorAuditRequestStatus::CONCERNED:
328 $any_concern = true;
329 break;
330 }
331 }
332
333 if ($any_concern) {
334 if ($this->isAuditStatusNeedsVerification()) {
335 // If the change is in "Needs Verification", we keep it there as
336 // long as any auditors still have concerns.
337 $status = DiffusionCommitAuditStatus::NEEDS_VERIFICATION;
338 } else {
339 $status = DiffusionCommitAuditStatus::CONCERN_RAISED;
340 }
341 } else if ($any_accept) {
342 if ($any_need) {
343 $status = DiffusionCommitAuditStatus::PARTIALLY_AUDITED;
344 } else {
345 $status = DiffusionCommitAuditStatus::AUDITED;
346 }
347 } else if ($any_need) {
348 $status = DiffusionCommitAuditStatus::NEEDS_AUDIT;
349 } else {
350 $status = DiffusionCommitAuditStatus::NONE;
351 }
352
353 return $this->setAuditStatus($status);
354 }
355
356 public function getMonogram() {
357 $repository = $this->getRepository();
358 $callsign = $repository->getCallsign();
359 $identifier = $this->getCommitIdentifier();
360 if ($callsign !== null) {
361 return "r{$callsign}{$identifier}";
362 } else {
363 $id = $repository->getID();
364 return "R{$id}:{$identifier}";
365 }
366 }
367
368 public function getDisplayName() {
369 $repository = $this->getRepository();
370 $identifier = $this->getCommitIdentifier();
371 return $repository->formatCommitName($identifier);
372 }
373
374 /**
375 * Return a local display name for use in the context of the containing
376 * repository.
377 *
378 * In Git and Mercurial, this returns only a short hash, like "abcdef012345".
379 * See @{method:getDisplayName} for a short name that always includes
380 * repository context.
381 *
382 * @return string Short human-readable name for use inside a repository.
383 */
384 public function getLocalName() {
385 $repository = $this->getRepository();
386 $identifier = $this->getCommitIdentifier();
387 return $repository->formatCommitName($identifier, $local = true);
388 }
389
390 public function loadIdentities(PhabricatorUser $viewer) {
391 if ($this->authorIdentity !== self::ATTACHABLE) {
392 return $this;
393 }
394
395 $commit = id(new DiffusionCommitQuery())
396 ->setViewer($viewer)
397 ->withIDs(array($this->getID()))
398 ->needIdentities(true)
399 ->executeOne();
400
401 $author_identity = $commit->getAuthorIdentity();
402 $committer_identity = $commit->getCommitterIdentity();
403
404 return $this->attachIdentities($author_identity, $committer_identity);
405 }
406
407 public function hasCommitterIdentity() {
408 return ($this->getCommitterIdentity() !== null);
409 }
410
411 public function hasAuthorIdentity() {
412 return ($this->getAuthorIdentity() !== null);
413 }
414
415 public function getCommitterDisplayPHID() {
416 if ($this->hasCommitterIdentity()) {
417 return $this->getCommitterIdentity()->getIdentityDisplayPHID();
418 }
419
420 $data = $this->getCommitData();
421 return $data->getCommitDetail('committerPHID');
422 }
423
424 public function getAuthorDisplayPHID() {
425 if ($this->hasAuthorIdentity()) {
426 return $this->getAuthorIdentity()->getIdentityDisplayPHID();
427 }
428
429 $data = $this->getCommitData();
430 return $data->getCommitDetail('authorPHID');
431 }
432
433 public function getEffectiveAuthorPHID() {
434 if ($this->hasAuthorIdentity()) {
435 $identity = $this->getAuthorIdentity();
436 if ($identity->hasEffectiveUser()) {
437 return $identity->getCurrentEffectiveUserPHID();
438 }
439 }
440
441 $data = $this->getCommitData();
442 return $data->getCommitDetail('authorPHID');
443 }
444
445 public function getAuditStatusObject() {
446 $status = $this->getAuditStatus();
447 return DiffusionCommitAuditStatus::newForStatus($status);
448 }
449
450 public function isAuditStatusNoAudit() {
451 return $this->getAuditStatusObject()->isNoAudit();
452 }
453
454 public function isAuditStatusNeedsAudit() {
455 return $this->getAuditStatusObject()->isNeedsAudit();
456 }
457
458 public function isAuditStatusConcernRaised() {
459 return $this->getAuditStatusObject()->isConcernRaised();
460 }
461
462 public function isAuditStatusNeedsVerification() {
463 return $this->getAuditStatusObject()->isNeedsVerification();
464 }
465
466 public function isAuditStatusPartiallyAudited() {
467 return $this->getAuditStatusObject()->isPartiallyAudited();
468 }
469
470 public function isAuditStatusAudited() {
471 return $this->getAuditStatusObject()->isAudited();
472 }
473
474 public function isPermanentCommit() {
475 return (bool)$this->isPartiallyImported(self::IMPORTED_PERMANENT);
476 }
477
478 public function newCommitAuthorView(PhabricatorUser $viewer) {
479 $author_phid = $this->getAuthorDisplayPHID();
480 if ($author_phid) {
481 $handles = $viewer->loadHandles(array($author_phid));
482 return $handles[$author_phid]->renderLink();
483 }
484
485 $author = $this->getRawAuthorStringForDisplay();
486 if (phutil_nonempty_string($author)) {
487 return DiffusionView::renderName($author);
488 }
489
490 return null;
491 }
492
493 public function newCommitCommitterView(PhabricatorUser $viewer) {
494 $committer_phid = $this->getCommitterDisplayPHID();
495 if ($committer_phid) {
496 $handles = $viewer->loadHandles(array($committer_phid));
497 return $handles[$committer_phid]->renderLink();
498 }
499
500 $committer = $this->getRawCommitterStringForDisplay();
501 if (phutil_nonempty_string($committer)) {
502 return DiffusionView::renderName($committer);
503 }
504
505 return null;
506 }
507
508 public function isAuthorSameAsCommitter() {
509 $author_phid = $this->getAuthorDisplayPHID();
510 $committer_phid = $this->getCommitterDisplayPHID();
511
512 if ($author_phid && $committer_phid) {
513 return ($author_phid === $committer_phid);
514 }
515
516 if ($author_phid || $committer_phid) {
517 return false;
518 }
519
520 $author = $this->getRawAuthorStringForDisplay();
521 $committer = $this->getRawCommitterStringForDisplay();
522
523 return ($author === $committer);
524 }
525
526 private function getRawAuthorStringForDisplay() {
527 $data = $this->getCommitData();
528 return $data->getAuthorString();
529 }
530
531 private function getRawCommitterStringForDisplay() {
532 $data = $this->getCommitData();
533 return $data->getCommitterString();
534 }
535
536 public function getCommitMessageForDisplay() {
537 $data = $this->getCommitData();
538 $message = $data->getCommitMessage();
539 return $message;
540 }
541
542 public function newCommitRef(PhabricatorUser $viewer) {
543 $repository = $this->getRepository();
544
545 $future = $repository->newConduitFuture(
546 $viewer,
547 'internal.commit.search',
548 array(
549 'constraints' => array(
550 'repositoryPHIDs' => array($repository->getPHID()),
551 'phids' => array($this->getPHID()),
552 ),
553 ));
554 $result = $future->resolve();
555
556 $commit_display = $this->getMonogram();
557
558 if (empty($result['data'])) {
559 throw new Exception(
560 pht(
561 'Unable to retrieve details for commit "%s"!',
562 $commit_display));
563 }
564
565 if (count($result['data']) !== 1) {
566 throw new Exception(
567 pht(
568 'Got too many results (%s) for commit "%s", expected %s.',
569 phutil_count($result['data']),
570 $commit_display,
571 1));
572 }
573
574 $record = head($result['data']);
575 $ref_record = idxv($record, array('fields', 'ref'));
576
577 if (!$ref_record) {
578 throw new Exception(
579 pht(
580 'Unable to retrieve CommitRef record for commit "%s".',
581 $commit_display));
582 }
583
584 return DiffusionCommitRef::newFromDictionary($ref_record);
585 }
586
587/* -( PhabricatorPolicyInterface )----------------------------------------- */
588
589 public function getCapabilities() {
590 return array(
591 PhabricatorPolicyCapability::CAN_VIEW,
592 PhabricatorPolicyCapability::CAN_EDIT,
593 );
594 }
595
596 public function getPolicy($capability) {
597 switch ($capability) {
598 case PhabricatorPolicyCapability::CAN_VIEW:
599 return $this->getRepository()->getPolicy($capability);
600 case PhabricatorPolicyCapability::CAN_EDIT:
601 return PhabricatorPolicies::POLICY_USER;
602 }
603 }
604
605 public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
606 return $this->getRepository()->hasAutomaticCapability($capability, $viewer);
607 }
608
609 public function describeAutomaticCapability($capability) {
610 return pht(
611 'Commits inherit the policies of the repository they belong to.');
612 }
613
614
615/* -( PhabricatorTokenReceiverInterface )---------------------------------- */
616
617 public function getUsersToNotifyOfTokenGiven() {
618 return array(
619 $this->getAuthorPHID(),
620 );
621 }
622
623/* -( Stuff for serialization )---------------------------------------------- */
624
625 /**
626 * NOTE: this is not a complete serialization; only the 'protected' fields are
627 * involved. This is due to ease of (ab)using the Lisk abstraction to get this
628 * done, as well as complexity of the other fields.
629 */
630 public function toDictionary() {
631 return array(
632 'repositoryID' => $this->getRepositoryID(),
633 'phid' => $this->getPHID(),
634 'commitIdentifier' => $this->getCommitIdentifier(),
635 'epoch' => $this->getEpoch(),
636 'authorPHID' => $this->getAuthorPHID(),
637 'auditStatus' => $this->getAuditStatus(),
638 'summary' => $this->getSummary(),
639 'importStatus' => $this->getImportStatus(),
640 );
641 }
642
643 public static function newFromDictionary(array $dict) {
644 return id(new PhabricatorRepositoryCommit())
645 ->loadFromArray($dict);
646 }
647
648
649/* -( HarbormasterBuildableInterface )------------------------------------- */
650
651
652 public function getHarbormasterBuildableDisplayPHID() {
653 return $this->getHarbormasterBuildablePHID();
654 }
655
656 public function getHarbormasterBuildablePHID() {
657 return $this->getPHID();
658 }
659
660 public function getHarbormasterContainerPHID() {
661 return $this->getRepository()->getPHID();
662 }
663
664 public function getBuildVariables() {
665 $results = array();
666
667 $results['buildable.commit'] = $this->getCommitIdentifier();
668 $repo = $this->getRepository();
669
670 $results['repository.callsign'] = $repo->getCallsign();
671 $results['repository.phid'] = $repo->getPHID();
672 $results['repository.vcs'] = $repo->getVersionControlSystem();
673 $results['repository.uri'] = $repo->getPublicCloneURI();
674
675 return $results;
676 }
677
678 public function getAvailableBuildVariables() {
679 return array(
680 'buildable.commit' => pht('The commit identifier, if applicable.'),
681 'repository.callsign' =>
682 pht('The callsign of the repository.'),
683 'repository.phid' =>
684 pht('The PHID of the repository.'),
685 'repository.vcs' =>
686 pht('The version control system, either "svn", "hg" or "git".'),
687 'repository.uri' =>
688 pht('The URI to clone or checkout the repository from.'),
689 );
690 }
691
692 public function newBuildableEngine() {
693 return new DiffusionBuildableEngine();
694 }
695
696
697/* -( HarbormasterCircleCIBuildableInterface )----------------------------- */
698
699
700 public function getCircleCIGitHubRepositoryURI() {
701 $repository = $this->getRepository();
702
703 $commit_phid = $this->getPHID();
704 $repository_phid = $repository->getPHID();
705
706 if ($repository->isHosted()) {
707 throw new Exception(
708 pht(
709 'This commit ("%s") is associated with a hosted repository '.
710 '("%s"). Repositories must be imported from GitHub to be built '.
711 'with CircleCI.',
712 $commit_phid,
713 $repository_phid));
714 }
715
716 $remote_uri = $repository->getRemoteURI();
717 $path = HarbormasterCircleCIBuildStepImplementation::getGitHubPath(
718 $remote_uri);
719 if (!$path) {
720 throw new Exception(
721 pht(
722 'This commit ("%s") is associated with a repository ("%s") which '.
723 'has a remote URI ("%s") that does not appear to be hosted on '.
724 'GitHub. Repositories must be hosted on GitHub to be built with '.
725 'CircleCI.',
726 $commit_phid,
727 $repository_phid,
728 $remote_uri));
729 }
730
731 return $remote_uri;
732 }
733
734 public function getCircleCIBuildIdentifierType() {
735 return 'revision';
736 }
737
738 public function getCircleCIBuildIdentifier() {
739 return $this->getCommitIdentifier();
740 }
741
742
743/* -( HarbormasterBuildkiteBuildableInterface )---------------------------- */
744
745
746 public function getBuildkiteBranch() {
747 $viewer = PhabricatorUser::getOmnipotentUser();
748 $repository = $this->getRepository();
749
750 $branches = DiffusionQuery::callConduitWithDiffusionRequest(
751 $viewer,
752 DiffusionRequest::newFromDictionary(
753 array(
754 'repository' => $repository,
755 'user' => $viewer,
756 )),
757 'diffusion.branchquery',
758 array(
759 'contains' => $this->getCommitIdentifier(),
760 'repository' => $repository->getPHID(),
761 ));
762
763 if (!$branches) {
764 throw new Exception(
765 pht(
766 'Commit "%s" is not an ancestor of any branch head, so it can not '.
767 'be built with Buildkite.',
768 $this->getCommitIdentifier()));
769 }
770
771 $branch = head($branches);
772
773 return 'refs/heads/'.$branch['shortName'];
774 }
775
776 public function getBuildkiteCommit() {
777 return $this->getCommitIdentifier();
778 }
779
780
781/* -( PhabricatorCustomFieldInterface )------------------------------------ */
782
783
784 public function getCustomFieldSpecificationForRole($role) {
785 return PhabricatorEnv::getEnvConfig('diffusion.fields');
786 }
787
788 public function getCustomFieldBaseClass() {
789 return 'PhabricatorCommitCustomField';
790 }
791
792 public function getCustomFields() {
793 return $this->assertAttached($this->customFields);
794 }
795
796 public function attachCustomFields(PhabricatorCustomFieldAttachment $fields) {
797 $this->customFields = $fields;
798 return $this;
799 }
800
801
802/* -( PhabricatorSubscribableInterface )----------------------------------- */
803
804
805 public function isAutomaticallySubscribed($phid) {
806
807 // TODO: This should also list auditors, but handling that is a bit messy
808 // right now because we are not guaranteed to have the data. (It should not
809 // include resigned auditors.)
810
811 return ($phid == $this->getAuthorPHID());
812 }
813
814
815/* -( PhabricatorApplicationTransactionInterface )------------------------- */
816
817
818 public function getApplicationTransactionEditor() {
819 return new PhabricatorAuditEditor();
820 }
821
822 public function getApplicationTransactionTemplate() {
823 return new PhabricatorAuditTransaction();
824 }
825
826/* -( PhabricatorFulltextInterface )--------------------------------------- */
827
828
829 public function newFulltextEngine() {
830 return new DiffusionCommitFulltextEngine();
831 }
832
833
834/* -( PhabricatorFerretInterface )----------------------------------------- */
835
836
837 public function newFerretEngine() {
838 return new DiffusionCommitFerretEngine();
839 }
840
841
842/* -( PhabricatorConduitResultInterface )---------------------------------- */
843
844 public function getFieldSpecificationsForConduit() {
845 return array(
846 id(new PhabricatorConduitSearchFieldSpecification())
847 ->setKey('identifier')
848 ->setType('string')
849 ->setDescription(pht('The commit identifier.')),
850 id(new PhabricatorConduitSearchFieldSpecification())
851 ->setKey('repositoryPHID')
852 ->setType('phid')
853 ->setDescription(pht('The repository this commit belongs to.')),
854 id(new PhabricatorConduitSearchFieldSpecification())
855 ->setKey('author')
856 ->setType('map<string, wild>')
857 ->setDescription(pht('Information about the commit author.')),
858 id(new PhabricatorConduitSearchFieldSpecification())
859 ->setKey('committer')
860 ->setType('map<string, wild>')
861 ->setDescription(pht('Information about the committer.')),
862 id(new PhabricatorConduitSearchFieldSpecification())
863 ->setKey('isImported')
864 ->setType('bool')
865 ->setDescription(pht('True if the commit is fully imported.')),
866 id(new PhabricatorConduitSearchFieldSpecification())
867 ->setKey('isUnreachable')
868 ->setType('bool')
869 ->setDescription(
870 pht(
871 'True if the commit is not the ancestor of any tag, branch, or '.
872 'ref.')),
873 id(new PhabricatorConduitSearchFieldSpecification())
874 ->setKey('auditStatus')
875 ->setType('map<string, wild>')
876 ->setDescription(pht('Information about the current audit status.')),
877 id(new PhabricatorConduitSearchFieldSpecification())
878 ->setKey('message')
879 ->setType('string')
880 ->setDescription(pht('The commit message.')),
881 );
882 }
883
884 public function getFieldValuesForConduit() {
885 $data = $this->getCommitData();
886
887 $author_identity = $this->getAuthorIdentity();
888 if ($author_identity) {
889 $author_name = $author_identity->getIdentityDisplayName();
890 $author_email = $author_identity->getIdentityEmailAddress();
891 $author_raw = $author_identity->getIdentityName();
892 $author_identity_phid = $author_identity->getPHID();
893 $author_user_phid = $author_identity->getCurrentEffectiveUserPHID();
894 } else {
895 $author_name = null;
896 $author_email = null;
897 $author_raw = null;
898 $author_identity_phid = null;
899 $author_user_phid = null;
900 }
901
902 $committer_identity = $this->getCommitterIdentity();
903 if ($committer_identity) {
904 $committer_name = $committer_identity->getIdentityDisplayName();
905 $committer_email = $committer_identity->getIdentityEmailAddress();
906 $committer_raw = $committer_identity->getIdentityName();
907 $committer_identity_phid = $committer_identity->getPHID();
908 $committer_user_phid = $committer_identity->getCurrentEffectiveUserPHID();
909 } else {
910 $committer_name = null;
911 $committer_email = null;
912 $committer_raw = null;
913 $committer_identity_phid = null;
914 $committer_user_phid = null;
915 }
916
917 $author_epoch = $data->getAuthorEpoch();
918
919 $audit_status = $this->getAuditStatusObject();
920
921 return array(
922 'identifier' => $this->getCommitIdentifier(),
923 'repositoryPHID' => $this->getRepository()->getPHID(),
924 'author' => array(
925 'name' => $author_name,
926 'email' => $author_email,
927 'raw' => $author_raw,
928 'epoch' => $author_epoch,
929 'identityPHID' => $author_identity_phid,
930 'userPHID' => $author_user_phid,
931 ),
932 'committer' => array(
933 'name' => $committer_name,
934 'email' => $committer_email,
935 'raw' => $committer_raw,
936 'epoch' => (int)$this->getEpoch(),
937 'identityPHID' => $committer_identity_phid,
938 'userPHID' => $committer_user_phid,
939 ),
940 'isUnreachable' => (bool)$this->isUnreachable(),
941 'isImported' => (bool)$this->isImported(),
942 'auditStatus' => array(
943 'value' => $audit_status->getKey(),
944 'name' => $audit_status->getName(),
945 'closed' => (bool)$audit_status->getIsClosed(),
946 'color.ansi' => $audit_status->getAnsiColor(),
947 ),
948 'message' => $data->getCommitMessage(),
949 );
950 }
951
952 public function getConduitSearchAttachments() {
953 return array(
954 id(new DiffusionAuditorsSearchEngineAttachment())
955 ->setAttachmentKey('auditors'),
956 );
957 }
958
959
960/* -( PhabricatorDraftInterface )------------------------------------------ */
961
962 public function newDraftEngine() {
963 return new DiffusionCommitDraftEngine();
964 }
965
966 public function getHasDraft(PhabricatorUser $viewer) {
967 return $this->assertAttachedKey($this->drafts, $viewer->getCacheFragment());
968 }
969
970 public function attachHasDraft(PhabricatorUser $viewer, $has_draft) {
971 $this->drafts[$viewer->getCacheFragment()] = $has_draft;
972 return $this;
973 }
974
975
976/* -( PhabricatorTimelineInterface )--------------------------------------- */
977
978
979 public function newTimelineEngine() {
980 return new DiffusionCommitTimelineEngine();
981 }
982
983}