diff --git a/src/applications/releeph/conduit/ConduitAPI_releeph_queryrequests_Method.php b/src/applications/releeph/conduit/ConduitAPI_releeph_queryrequests_Method.php index 9683215576..44767e6b6b 100644 --- a/src/applications/releeph/conduit/ConduitAPI_releeph_queryrequests_Method.php +++ b/src/applications/releeph/conduit/ConduitAPI_releeph_queryrequests_Method.php @@ -1,71 +1,77 @@ 'optional list', 'requestedCommitPHIDs' => 'optional list' ); } public function defineReturnType() { return 'dict'; } public function defineErrorTypes() { return array(); } protected function execute(ConduitAPIRequest $conduit_request) { $revision_phids = $conduit_request->getValue('revisionPHIDs'); $requested_commit_phids = $conduit_request->getValue('requestedCommitPHIDs'); $result = array(); if (!$revision_phids && !$requested_commit_phids) { return $result; } $query = new ReleephRequestQuery(); $query->setViewer($conduit_request->getUser()); if ($revision_phids) { - $query->withRevisionPHIDs($revision_phids); + $query->withRequestedObjectPHIDs($revision_phids); } else if ($requested_commit_phids) { $query->withRequestedCommitPHIDs($requested_commit_phids); } $releephRequests = $query->execute(); foreach ($releephRequests as $releephRequest) { $branch = $releephRequest->getBranch(); $request_commit_phid = $releephRequest->getRequestCommitPHID(); - $revisionPHID = - $query->getRevisionPHID($request_commit_phid); + + $object = $releephRequest->getRequestedObject(); + if ($object instanceof DifferentialRevision) { + $object_phid = $object->getPHID(); + } else { + $object_phid = null; + } + $status = $releephRequest->getStatus(); $statusName = ReleephRequestStatus::getStatusDescriptionFor($status); $url = PhabricatorEnv::getProductionURI('/RQ'.$releephRequest->getID()); $result[] = array( 'branchBasename' => $branch->getBasename(), 'branchSymbolic' => $branch->getSymbolicName(), 'requestID' => $releephRequest->getID(), - 'revisionPHID' => $revisionPHID, + 'revisionPHID' => $object_phid, 'status' => $status, 'statusName' => $statusName, 'url' => $url, ); } return $result; } } diff --git a/src/applications/releeph/conduit/work/ConduitAPI_releephwork_nextrequest_Method.php b/src/applications/releeph/conduit/work/ConduitAPI_releephwork_nextrequest_Method.php index 329b3f0451..f39a02568d 100644 --- a/src/applications/releeph/conduit/work/ConduitAPI_releephwork_nextrequest_Method.php +++ b/src/applications/releeph/conduit/work/ConduitAPI_releephwork_nextrequest_Method.php @@ -1,216 +1,223 @@ 'required phid', 'seen' => 'required map', ); } public function defineReturnType() { return ''; } public function defineErrorTypes() { return array( 'ERR-NOT-PUSHER' => 'You are not listed as a pusher for thie Releeph project!', ); } protected function execute(ConduitAPIRequest $request) { $viewer = $request->getUser(); $seen = $request->getValue('seen'); $branch = id(new ReleephBranchQuery()) ->setViewer($viewer) ->withPHIDs(array($request->getValue('branchPHID'))) ->executeOne(); $project = $branch->getProduct(); $needs_pick = array(); $needs_revert = array(); // Load every request ever made for this branch...?!!! $releeph_requests = id(new ReleephRequestQuery()) ->setViewer($viewer) ->withBranchIDs(array($branch->getID())) ->execute(); foreach ($releeph_requests as $candidate) { $phid = $candidate->getPHID(); if (idx($seen, $phid)) { continue; } $should = $candidate->shouldBeInBranch(); $in = $candidate->getInBranch(); if ($should && !$in) { $needs_pick[] = $candidate; } if (!$should && $in) { $needs_revert[] = $candidate; } } /** * Sort both needs_pick and needs_revert in ascending commit order, as * discovered by Phabricator (using the `id` column to perform that * ordering). * * This is easy for $needs_pick as the ordinal is stored. It is hard for * reverts, as we have to look that information up. */ $needs_pick = $this->sortPicks($needs_pick); $needs_revert = $this->sortReverts($needs_revert); /** * Do reverts first in reverse order, then the picks in original-commit * order. * * This seems like the correct thing to do, but there may be a better * algorithm for the releephwork.nextrequest Conduit call that orders * things better. * * We could also button-mash our way through everything that failed (at the * end of the run) to try failed things again. */ $releeph_request = null; $action = null; if ($needs_revert) { $releeph_request = last($needs_revert); $action = 'revert'; $commit_id = $releeph_request->getCommitIdentifier(); $commit_phid = $releeph_request->getCommitPHID(); } elseif ($needs_pick) { $releeph_request = head($needs_pick); $action = 'pick'; $commit = $releeph_request->loadPhabricatorRepositoryCommit(); $commit_id = $commit->getCommitIdentifier(); $commit_phid = $commit->getPHID(); } else { // Return early if there's nothing to do! return array(); } // Build the response $phids = array(); $phids[] = $commit_phid; $diff_phid = null; $diff_rev_id = null; - $diff_rev = $releeph_request->loadDifferentialRevision(); + + $requested_object = $releeph_request->getRequestedObject(); + if ($requested_object instanceof DifferentialRevision) { + $diff_rev = $requested_object; + } else { + $diff_rev = null; + } + if ($diff_rev) { $diff_phid = $diff_rev->getPHID(); $phids[] = $diff_phid; $diff_rev_id = $diff_rev->getID(); } $phids[] = $releeph_request->getPHID(); $handles = id(new PhabricatorHandleQuery()) ->setViewer($request->getUser()) ->withPHIDs($phids) ->execute(); $diff_name = null; if ($diff_rev) { $diff_name = $handles[$diff_phid]->getName(); } $new_author_phid = null; if ($diff_rev) { $new_author_phid = $diff_rev->getAuthorPHID(); } else { $pr_commit = $releeph_request->loadPhabricatorRepositoryCommit(); if ($pr_commit) { $new_author_phid = $pr_commit->getAuthorPHID(); } } return array( 'requestID' => $releeph_request->getID(), 'requestPHID' => $releeph_request->getPHID(), 'requestName' => $handles[$releeph_request->getPHID()]->getName(), 'requestorPHID' => $releeph_request->getRequestUserPHID(), 'action' => $action, 'diffRevID' => $diff_rev_id, 'diffName' => $diff_name, 'commitIdentifier' => $commit_id, 'commitPHID' => $commit_phid, 'commitName' => $handles[$commit_phid]->getName(), 'needsRevert' => mpull($needs_revert, 'getID'), 'needsPick' => mpull($needs_pick, 'getID'), 'newAuthorPHID' => $new_author_phid, ); } private function sortPicks(array $releeph_requests) { $surrogate = array(); foreach ($releeph_requests as $rq) { // TODO: it's likely that relying on the `id` column to provide // trunk-commit-order is thoroughly broken. $ordinal = (int) $rq->loadPhabricatorRepositoryCommit()->getID(); $surrogate[$ordinal] = $rq; } ksort($surrogate); return $surrogate; } /** * Sort an array of ReleephRequests, that have been picked into a branch, in * the order in which they were picked to the branch. */ private function sortReverts(array $releeph_requests) { if (!$releeph_requests) { return array(); } // ReleephRequests, keyed by $releeph_requests = mpull($releeph_requests, null, 'getCommitIdentifier'); $commits = id(new PhabricatorRepositoryCommit()) ->loadAllWhere( 'commitIdentifier IN (%Ls)', mpull($releeph_requests, 'getCommitIdentifier')); // A map of => $surrogate = mpull($commits, 'getID', 'getCommitIdentifier'); $unparsed = array(); $result = array(); foreach ($releeph_requests as $commit_id => $releeph_request) { $ordinal = idx($surrogate, $commit_id); if ($ordinal) { $result[$ordinal] = $releeph_request; } else { $unparsed[] = $releeph_request; } } // Sort $result in ascending order ksort($result); // Unparsed commits we'll just have to guess, based on time $unparsed = msort($unparsed, 'getDateModified'); return array_merge($result, $unparsed); } } diff --git a/src/applications/releeph/field/specification/ReleephDependsOnFieldSpecification.php b/src/applications/releeph/field/specification/ReleephDependsOnFieldSpecification.php index e951b4bf11..7048b5d3e7 100644 --- a/src/applications/releeph/field/specification/ReleephDependsOnFieldSpecification.php +++ b/src/applications/releeph/field/specification/ReleephDependsOnFieldSpecification.php @@ -1,33 +1,33 @@ getDependentRevisionPHIDs(); } public function renderPropertyViewValue(array $handles) { return $this->renderHandleList($handles); } private function getDependentRevisionPHIDs() { - $revision = $this - ->getReleephRequest() - ->loadDifferentialRevision(); - if (!$revision) { + $requested_object = $this->getObject()->getRequestedObjectPHID(); + if (!($requested_object instanceof DifferentialRevision)) { return array(); } + $revision = $requested_object; + return PhabricatorEdgeQuery::loadDestinationPHIDs( $revision->getPHID(), PhabricatorEdgeConfig::TYPE_DREV_DEPENDS_ON_DREV); } } diff --git a/src/applications/releeph/field/specification/ReleephDiffChurnFieldSpecification.php b/src/applications/releeph/field/specification/ReleephDiffChurnFieldSpecification.php index 43d1b024c4..026392a1bc 100644 --- a/src/applications/releeph/field/specification/ReleephDiffChurnFieldSpecification.php +++ b/src/applications/releeph/field/specification/ReleephDiffChurnFieldSpecification.php @@ -1,90 +1,89 @@ getReleephRequest()->loadDifferentialRevision(); - if (!$diff_rev) { + $requested_object = $this->getObject()->getRequestedObject(); + if (!($requested_object instanceof DifferentialRevision)) { return null; } - - $diff_rev = $this->getReleephRequest()->loadDifferentialRevision(); + $diff_rev = $requested_object; $xactions = id(new DifferentialTransactionQuery()) - ->setViewer(PhabricatorUser::getOmnipotentUser()) + ->setViewer($this->getViewer()) ->withObjectPHIDs(array($diff_rev->getPHID())) ->execute(); $rejections = 0; $comments = 0; $updates = 0; foreach ($xactions as $xaction) { switch ($xaction->getTransactionType()) { case PhabricatorTransactions::TYPE_COMMENT: $comments++; break; case DifferentialTransaction::TYPE_UPDATE: $updates++; break; case DifferentialTransaction::TYPE_ACTION: switch ($xaction->getNewValue()) { case DifferentialAction::ACTION_REJECT: $rejections++; break; } break; } } $points = self::REJECTIONS_WEIGHT * $rejections + self::COMMENTS_WEIGHT * $comments + self::UPDATES_WEIGHT * $updates; if ($points === 0) { $points = 0.15 * self::MAX_POINTS; $blurb = 'Silent diff'; } else { $parts = array(); if ($rejections) { $parts[] = pht('%d rejection(s)', $rejections); } if ($comments) { $parts[] = pht('%d comment(s)', $comments); } if ($updates) { $parts[] = pht('%d update(s)', $updates); } if (count($parts) === 0) { $blurb = ''; } else if (count($parts) === 1) { $blurb = head($parts); } else { $last = array_pop($parts); $blurb = implode(', ', $parts).' and '.$last; } } return id(new AphrontProgressBarView()) ->setValue($points) ->setMax(self::MAX_POINTS) ->setCaption($blurb) ->render(); } } diff --git a/src/applications/releeph/field/specification/ReleephDiffSizeFieldSpecification.php b/src/applications/releeph/field/specification/ReleephDiffSizeFieldSpecification.php index 9c269d3c81..b0e1e44bf9 100644 --- a/src/applications/releeph/field/specification/ReleephDiffSizeFieldSpecification.php +++ b/src/applications/releeph/field/specification/ReleephDiffSizeFieldSpecification.php @@ -1,112 +1,113 @@ getReleephRequest()->loadDifferentialRevision(); - if (!$diff_rev) { + $requested_object = $this->getObject()->getRequestedObject(); + if (!($requested_object instanceof DifferentialRevision)) { return null; } + $diff_rev = $requested_object; $diffs = $diff_rev->loadRelatives( new DifferentialDiff(), 'revisionID', 'getID', 'creationMethod <> "commit"'); $all_changesets = array(); $most_recent_changesets = null; foreach ($diffs as $diff) { $changesets = $diff->loadRelatives(new DifferentialChangeset(), 'diffID'); $all_changesets += $changesets; $most_recent_changesets = $changesets; } // The score is based on all changesets for all versions of this diff $all_changes = $this->countLinesAndPaths($all_changesets); $points = self::LINES_WEIGHT * $all_changes['code']['lines'] + self::PATHS_WEIGHT * count($all_changes['code']['paths']); // The blurb is just based on the most recent version of the diff $mr_changes = $this->countLinesAndPaths($most_recent_changesets); $test_tag = ''; if ($mr_changes['tests']['paths']) { Javelin::initBehavior('phabricator-tooltips'); require_celerity_resource('aphront-tooltip-css'); $test_blurb = pht('%d line(s)', $mr_changes['tests']['lines']).' and '. pht('%d path(s)', count($mr_changes['tests']['paths'])). " contain changes to test code:\n"; foreach ($mr_changes['tests']['paths'] as $mr_test_path) { $test_blurb .= pht("%s\n", $mr_test_path); } $test_tag = javelin_tag( 'span', array( 'sigil' => 'has-tooltip', 'meta' => array( 'tip' => $test_blurb, 'align' => 'E', 'size' => 'auto'), 'style' => ''), ' + tests'); } $blurb = hsprintf("%s%s.", pht('%d line(s)', $mr_changes['code']['lines']).' and '. pht('%d path(s)', count($mr_changes['code']['paths'])).' over '. pht('%d diff(s)', count($diffs)), $test_tag); return id(new AphrontProgressBarView()) ->setValue($points) ->setMax(self::MAX_POINTS) ->setCaption($blurb) ->render(); } private function countLinesAndPaths(array $changesets) { assert_instances_of($changesets, 'DifferentialChangeset'); $lines = 0; $paths_touched = array(); $test_lines = 0; $test_paths_touched = array(); foreach ($changesets as $ch) { if ($this->getReleephProject()->isTestFile($ch->getFilename())) { $test_lines += $ch->getAddLines() + $ch->getDelLines(); $test_paths_touched[] = $ch->getFilename(); } else { $lines += $ch->getAddLines() + $ch->getDelLines(); $paths_touched[] = $ch->getFilename(); } } return array( 'code' => array( 'lines' => $lines, 'paths' => array_unique($paths_touched), ), 'tests' => array( 'lines' => $test_lines, 'paths' => array_unique($test_paths_touched), ) ); } } diff --git a/src/applications/releeph/field/specification/ReleephRevisionFieldSpecification.php b/src/applications/releeph/field/specification/ReleephRevisionFieldSpecification.php index a070ddd8a8..f9aa6fd2a1 100644 --- a/src/applications/releeph/field/specification/ReleephRevisionFieldSpecification.php +++ b/src/applications/releeph/field/specification/ReleephRevisionFieldSpecification.php @@ -1,29 +1,29 @@ getReleephRequest()->loadRequestCommitDiffPHID(); - if ($phid) { - $phids[] = $phid; + $requested_object = $this->getObject()->getRequestedObjectPHID(); + if (!($requested_object instanceof DifferentialRevision)) { + return array(); } - return $phids; + return array( + $requested_object->getPHID(), + ); } public function renderPropertyViewValue(array $handles) { return $this->renderHandleList($handles); } } diff --git a/src/applications/releeph/query/ReleephRequestQuery.php b/src/applications/releeph/query/ReleephRequestQuery.php index 5108e6361d..5a0a0056d2 100644 --- a/src/applications/releeph/query/ReleephRequestQuery.php +++ b/src/applications/releeph/query/ReleephRequestQuery.php @@ -1,257 +1,249 @@ ids = $ids; return $this; } public function withPHIDs(array $phids) { $this->phids = $phids; return $this; } public function withBranchIDs(array $branch_ids) { $this->branchIDs = $branch_ids; return $this; } - public function getRevisionPHID($commit_phid) { - if ($this->commitToRevMap) { - return idx($this->commitToRevMap, $commit_phid, null); - } - - return null; - } - public function withStatus($status) { $this->status = $status; return $this; } public function withRequestedCommitPHIDs(array $requested_commit_phids) { $this->requestedCommitPHIDs = $requested_commit_phids; return $this; } public function withRequestorPHIDs(array $phids) { $this->requestorPHIDs = $phids; return $this; } public function withSeverities(array $severities) { $this->severities = $severities; return $this; } - public function withRevisionPHIDs(array $revision_phids) { - $this->revisionPHIDs = $revision_phids; + public function withRequestedObjectPHIDs(array $phids) { + $this->requestedObjectPHIDs = $phids; return $this; } public function loadPage() { $table = new ReleephRequest(); $conn_r = $table->establishConnection('r'); $data = queryfx_all( $conn_r, 'SELECT * FROM %T %Q %Q %Q', $table->getTableName(), $this->buildWhereClause($conn_r), $this->buildOrderClause($conn_r), $this->buildLimitClause($conn_r)); return $table->loadAllFromArray($data); } public function willFilterPage(array $requests) { + // Load requested objects: you must be able to see an object to see + // requests for it. + $object_phids = mpull($requests, 'getRequestedObjectPHID'); + $objects = id(new PhabricatorObjectQuery()) + ->setViewer($this->getViewer()) + ->setParentQuery($this) + ->withPHIDs($object_phids) + ->execute(); + + foreach ($requests as $key => $request) { + $object_phid = $request->getRequestedObjectPHID(); + $object = idx($objects, $object_phid); + if (!$object) { + unset($requests[$key]); + continue; + } + $request->attachRequestedObject($object); + } + if ($this->severities) { $severities = array_fuse($this->severities); foreach ($requests as $key => $request) { // NOTE: Facebook uses a custom field here. if (ReleephDefaultFieldSelector::isFacebook()) { $severity = $request->getDetail('severity'); } else { $severity = $request->getDetail('releeph:severity'); } if (empty($severities[$severity])) { unset($requests[$key]); } } } $branch_ids = array_unique(mpull($requests, 'getBranchID')); $branches = id(new ReleephBranchQuery()) ->withIDs($branch_ids) ->setViewer($this->getViewer()) ->execute(); $branches = mpull($branches, null, 'getID'); foreach ($requests as $key => $request) { $branch = idx($branches, $request->getBranchID()); if (!$branch) { unset($requests[$key]); continue; } $request->attachBranch($branch); } // TODO: These should be serviced by the query, but are not currently // denormalized anywhere. For now, filter them here instead. Note that // we must perform this filtering *after* querying and attaching branches, // because request status depends on the product. $keep_status = array_fuse($this->getKeepStatusConstants()); if ($keep_status) { foreach ($requests as $key => $request) { if (empty($keep_status[$request->getStatus()])) { unset($requests[$key]); } } } return $requests; } private function buildWhereClause(AphrontDatabaseConnection $conn_r) { $where = array(); - if ($this->ids) { + if ($this->ids !== null) { $where[] = qsprintf( $conn_r, 'id IN (%Ld)', $this->ids); } - if ($this->phids) { + if ($this->phids !== null) { $where[] = qsprintf( $conn_r, 'phid IN (%Ls)', $this->phids); } - if ($this->branchIDs) { + if ($this->branchIDs !== null) { $where[] = qsprintf( $conn_r, 'branchID IN (%Ld)', $this->branchIDs); } - if ($this->requestedCommitPHIDs) { + if ($this->requestedCommitPHIDs !== null) { $where[] = qsprintf( $conn_r, 'requestCommitPHID IN (%Ls)', $this->requestedCommitPHIDs); } - if ($this->requestorPHIDs) { + if ($this->requestorPHIDs !== null) { $where[] = qsprintf( $conn_r, 'requestUserPHID IN (%Ls)', $this->requestorPHIDs); } - if ($this->revisionPHIDs) { - $type = PhabricatorEdgeConfig::TYPE_DREV_HAS_COMMIT; - - $edges = id(new PhabricatorEdgeQuery()) - ->withSourcePHIDs($this->revisionPHIDs) - ->withEdgeTypes(array($type)) - ->execute(); - - $this->commitToRevMap = array(); - foreach ($edges as $revision_phid => $edge) { - foreach ($edge[$type] as $commitPHID => $item) { - $this->commitToRevMap[$commitPHID] = $revision_phid; - } - } - - if (!$this->commitToRevMap) { - throw new PhabricatorEmptyQueryException("Malformed Revision Phids"); - } - + if ($this->requestedObjectPHIDs !== null) { $where[] = qsprintf( $conn_r, - 'requestCommitPHID IN (%Ls)', - array_keys($this->commitToRevMap)); + 'requestedObjectPHID IN (%Ls)', + $this->requestedObjectPHIDs); } $where[] = $this->buildPagingClause($conn_r); return $this->formatWhereClause($where); } private function getKeepStatusConstants() { switch ($this->status) { case self::STATUS_ALL: return array(); case self::STATUS_OPEN: return array( ReleephRequestStatus::STATUS_REQUESTED, ReleephRequestStatus::STATUS_NEEDS_PICK, ReleephRequestStatus::STATUS_NEEDS_REVERT, ); case self::STATUS_REQUESTED: return array( ReleephRequestStatus::STATUS_REQUESTED, ); case self::STATUS_NEEDS_PULL: return array( ReleephRequestStatus::STATUS_NEEDS_PICK, ); case self::STATUS_REJECTED: return array( ReleephRequestStatus::STATUS_REJECTED, ); case self::STATUS_ABANDONED: return array( ReleephRequestStatus::STATUS_ABANDONED, ); case self::STATUS_PULLED: return array( ReleephRequestStatus::STATUS_PICKED, ); case self::STATUS_NEEDS_REVERT: return array( ReleephRequestStatus::NEEDS_REVERT, ); case self::STATUS_REVERTED: return array( ReleephRequestStatus::REVERTED, ); default: throw new Exception("Unknown status '{$this->status}'!"); } } public function getQueryApplicationClass() { return 'PhabricatorApplicationReleeph'; } } diff --git a/src/applications/releeph/storage/ReleephRequest.php b/src/applications/releeph/storage/ReleephRequest.php index 4ff2af1ae7..487f1de7cb 100644 --- a/src/applications/releeph/storage/ReleephRequest.php +++ b/src/applications/releeph/storage/ReleephRequest.php @@ -1,335 +1,320 @@ getPusherIntent() == self::INTENT_WANT && /** * We use "!= pass" instead of "== want" in case the requestor intent is * not present. In other words, only revert if the requestor explicitly * passed. */ $this->getRequestorIntent() != self::INTENT_PASS; } /** * Will return INTENT_WANT if any pusher wants this request, and no pusher * passes on this request. */ public function getPusherIntent() { $product = $this->getBranch()->getProduct(); if (!$product->getPushers()) { return self::INTENT_WANT; } $found_pusher_want = false; foreach ($this->userIntents as $phid => $intent) { if ($product->isAuthoritativePHID($phid)) { if ($intent == self::INTENT_PASS) { return self::INTENT_PASS; } $found_pusher_want = true; } } if ($found_pusher_want) { return self::INTENT_WANT; } else { return null; } } public function getRequestorIntent() { return idx($this->userIntents, $this->requestUserPHID); } public function getStatus() { return $this->calculateStatus(); } public function getMonogram() { return 'Y'.$this->getID(); } public function getBranch() { return $this->assertAttached($this->branch); } public function attachBranch(ReleephBranch $branch) { $this->branch = $branch; return $this; } + public function getRequestedObject() { + return $this->assertAttached($this->requestedObject); + } + + public function attachRequestedObject($object) { + $this->requestedObject = $object; + return $this; + } + private function calculateStatus() { if ($this->shouldBeInBranch()) { if ($this->getInBranch()) { return ReleephRequestStatus::STATUS_PICKED; } else { return ReleephRequestStatus::STATUS_NEEDS_PICK; } } else { if ($this->getInBranch()) { return ReleephRequestStatus::STATUS_NEEDS_REVERT; } else { $has_been_in_branch = $this->getCommitIdentifier(); // Regardless of why we reverted something, always say reverted if it // was once in the branch. if ($has_been_in_branch) { return ReleephRequestStatus::STATUS_REVERTED; } elseif ($this->getPusherIntent() === ReleephRequest::INTENT_PASS) { // Otherwise, if it has never been in the branch, explicitly say why: return ReleephRequestStatus::STATUS_REJECTED; } elseif ($this->getRequestorIntent() === ReleephRequest::INTENT_WANT) { return ReleephRequestStatus::STATUS_REQUESTED; } else { return ReleephRequestStatus::STATUS_ABANDONED; } } } } /* -( Lisk mechanics )----------------------------------------------------- */ public function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, self::CONFIG_SERIALIZATION => array( 'details' => self::SERIALIZATION_JSON, 'userIntents' => self::SERIALIZATION_JSON, ), ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( ReleephPHIDTypeRequest::TYPECONST); } public function save() { if (!$this->getMailKey()) { $this->setMailKey(Filesystem::readRandomCharacters(20)); } return parent::save(); } /* -( Helpful accessors )--------------------------------------------------- */ public function getDetail($key, $default = null) { return idx($this->getDetails(), $key, $default); } public function setDetail($key, $value) { $this->details[$key] = $value; return $this; } /** * Get the commit PHIDs this request is requesting. * * NOTE: For now, this always returns one PHID. * * @return list Commit PHIDs requested by this request. */ public function getCommitPHIDs() { return array( $this->requestCommitPHID, ); } public function getReason() { // Backward compatibility: reason used to be called comments $reason = $this->getDetail('reason'); if (!$reason) { return $this->getDetail('comments'); } return $reason; } /** * Allow a null summary, and fall back to the title of the commit. */ public function getSummaryForDisplay() { $summary = $this->getDetail('summary'); if (!strlen($summary)) { $commit = $this->loadPhabricatorRepositoryCommit(); if ($commit) { $summary = $commit->getSummary(); } } if (!strlen($summary)) { $summary = pht('None'); } return $summary; } - public function loadRequestCommitDiffPHID() { - $phids = array(); - $commit = $this->loadPhabricatorRepositoryCommit(); - if ($commit) { - $phids = PhabricatorEdgeQuery::loadDestinationPHIDs( - $commit->getPHID(), - PhabricatorEdgeConfig::TYPE_COMMIT_HAS_DREV); - } - - return head($phids); - } - - /* -( Loading external objects )------------------------------------------- */ public function loadPhabricatorRepositoryCommit() { return $this->loadOneRelative( new PhabricatorRepositoryCommit(), 'phid', 'getRequestCommitPHID'); } public function loadPhabricatorRepositoryCommitData() { $commit = $this->loadPhabricatorRepositoryCommit(); if ($commit) { return $commit->loadOneRelative( new PhabricatorRepositoryCommitData(), 'commitID'); } } - // TODO: (T603) Get rid of all this one-off ad-hoc loading. - public function loadDifferentialRevision() { - $diff_phid = $this->loadRequestCommitDiffPHID(); - if (!$diff_phid) { - return null; - } - return $this->loadOneRelative( - new DifferentialRevision(), - 'phid', - 'loadRequestCommitDiffPHID'); - } - /* -( State change helpers )----------------------------------------------- */ public function setUserIntent(PhabricatorUser $user, $intent) { $this->userIntents[$user->getPHID()] = $intent; return $this; } /* -( Migrating to status-less ReleephRequests )--------------------------- */ protected function didReadData() { if ($this->userIntents === null) { $this->userIntents = array(); } } public function setStatus($value) { throw new Exception('`status` is now deprecated!'); } /* -( Make magic Lisk methods private )------------------------------------ */ private function setUserIntents(array $ar) { return parent::setUserIntents($ar); } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, ); } public function getPolicy($capability) { return $this->getBranch()->getPolicy($capability); } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { return $this->getBranch()->hasAutomaticCapability($capability, $viewer); } public function describeAutomaticCapability($capability) { return pht( 'Pull requests have the same policies as the branches they are '. 'requested against.'); } /* -( PhabricatorCustomFieldInterface )------------------------------------ */ public function getCustomFieldSpecificationForRole($role) { return PhabricatorEnv::getEnvConfig('releeph.fields'); } public function getCustomFieldBaseClass() { return 'ReleephFieldSpecification'; } public function getCustomFields() { return $this->assertAttached($this->customFields); } public function attachCustomFields(PhabricatorCustomFieldAttachment $fields) { $this->customFields = $fields; return $this; } }