@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
fork

Configure Feed

Select the types of activity you want to include in your feed.

at recaptime-dev/main 983 lines 28 kB view raw
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}