Page MenuHomestyx hydra

No OneTemporary

diff --git a/src/applications/releeph/conduit/ConduitAPI_releeph_queryrequests_Method.php b/src/applications/releeph/conduit/ConduitAPI_releeph_queryrequests_Method.php
index 7180166efb..9683215576 100644
--- a/src/applications/releeph/conduit/ConduitAPI_releeph_queryrequests_Method.php
+++ b/src/applications/releeph/conduit/ConduitAPI_releeph_queryrequests_Method.php
@@ -1,73 +1,71 @@
<?php
final class ConduitAPI_releeph_queryrequests_Method
extends ConduitAPI_releeph_Method {
public function getMethodDescription() {
return
"Return information about all Releeph requests linked to the given ids.";
}
public function defineParamTypes() {
return array(
'revisionPHIDs' => 'optional list<phid>',
'requestedCommitPHIDs' => 'optional list<phid>'
);
}
public function defineReturnType() {
return 'dict<string, wild>';
}
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);
} else if ($requested_commit_phids) {
$query->withRequestedCommitPHIDs($requested_commit_phids);
}
$releephRequests = $query->execute();
foreach ($releephRequests as $releephRequest) {
- $branch = $releephRequest->loadReleephBranch();
- if (!$branch) {
- continue;
- }
+ $branch = $releephRequest->getBranch();
+
$request_commit_phid = $releephRequest->getRequestCommitPHID();
$revisionPHID =
$query->getRevisionPHID($request_commit_phid);
$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,
'status' => $status,
'statusName' => $statusName,
'url' => $url,
);
}
return $result;
}
}
diff --git a/src/applications/releeph/conduit/ConduitAPI_releeph_request_Method.php b/src/applications/releeph/conduit/ConduitAPI_releeph_request_Method.php
index bd9d0be36f..762b4a4c9f 100644
--- a/src/applications/releeph/conduit/ConduitAPI_releeph_request_Method.php
+++ b/src/applications/releeph/conduit/ConduitAPI_releeph_request_Method.php
@@ -1,157 +1,159 @@
<?php
final class ConduitAPI_releeph_request_Method
extends ConduitAPI_releeph_Method {
public function getMethodDescription() {
return "Request a commit or diff to be picked to a branch.";
}
public function defineParamTypes() {
return array(
'branchPHID' => 'required string',
- 'things' => 'required string',
+ 'things' => 'required list<string>',
'fields' => 'dict<string, string>',
);
}
public function defineReturnType() {
return 'dict<string, wild>';
}
public function defineErrorTypes() {
return array(
"ERR_BRANCH" => 'Unknown Releeph branch.',
"ERR_FIELD_PARSE" => 'Unable to parse a Releeph field.',
);
}
protected function execute(ConduitAPIRequest $request) {
$user = $request->getUser();
$viewer_handle = id(new PhabricatorHandleQuery())
->setViewer($user)
->withPHIDs(array($user->getPHID()))
->executeOne();
$branch_phid = $request->getValue('branchPHID');
- $releeph_branch = id(new ReleephBranch())
- ->loadOneWhere('phid = %s', $branch_phid);
+ $releeph_branch = id(new ReleephBranchQuery())
+ ->setViewer($user)
+ ->withPHIDs(array($branch_phid))
+ ->executeOne();
if (!$releeph_branch) {
throw id(new ConduitException("ERR_BRANCH"))->setErrorDescription(
"No ReleephBranch found with PHID {$branch_phid}!");
}
- $releeph_project = $releeph_branch->loadReleephProject();
+ $releeph_project = $releeph_branch->getProduct();
// Find the requested commit identifiers
$requested_commits = array();
$things = $request->getValue('things');
$finder = id(new ReleephCommitFinder())
->setUser($user)
->setReleephProject($releeph_project);
foreach ($things as $thing) {
try {
$requested_commits[$thing] = $finder->fromPartial($thing);
} catch (ReleephCommitFinderException $ex) {
throw id(new ConduitException('ERR_NO_MATCHES'))
->setErrorDescription($ex->getMessage());
}
}
$requested_commit_phids = mpull($requested_commits, 'getPHID');
// Find any existing requests that clash on the commit id, for this branch
$existing_releeph_requests = id(new ReleephRequest())->loadAllWhere(
'requestCommitPHID IN (%Ls) AND branchID = %d',
$requested_commit_phids,
$releeph_branch->getID());
$existing_releeph_requests = mpull(
$existing_releeph_requests,
null,
'getRequestCommitPHID');
$selector = $releeph_project->getReleephFieldSelector();
$fields = $selector->getFieldSpecifications();
foreach ($fields as $field) {
$field
->setReleephProject($releeph_project)
->setReleephBranch($releeph_branch);
}
$results = array();
$handles = id(new PhabricatorHandleQuery())
->setViewer($user)
->withPHIDs($requested_commit_phids)
->execute();
foreach ($requested_commits as $thing => $commit) {
$phid = $commit->getPHID();
$name = id($handles[$phid])->getName();
$releeph_request = null;
$existing_releeph_request = idx($existing_releeph_requests, $phid);
if ($existing_releeph_request) {
$releeph_request = $existing_releeph_request;
} else {
$releeph_request = id(new ReleephRequest())
->setRequestUserPHID($user->getPHID())
->setBranchID($releeph_branch->getID())
->setInBranch(0);
$xactions = array();
$xactions[] = id(new ReleephRequestTransaction())
->setTransactionType(ReleephRequestTransaction::TYPE_REQUEST)
->setNewValue($commit->getPHID());
$xactions[] = id(new ReleephRequestTransaction())
->setTransactionType(ReleephRequestTransaction::TYPE_USER_INTENT)
->setMetadataValue('userPHID', $user->getPHID())
->setMetadataValue(
'isAuthoritative',
$releeph_project->isAuthoritative($user))
->setNewValue(ReleephRequest::INTENT_WANT);
foreach ($fields as $field) {
if (!$field->isEditable()) {
continue;
}
$field->setReleephRequest($releeph_request);
try {
$field->setValueFromConduitAPIRequest($request);
} catch (ReleephFieldParseException $ex) {
throw id(new ConduitException('ERR_FIELD_PARSE'))
->setErrorDescription($ex->getMessage());
}
}
$editor = id(new ReleephRequestTransactionalEditor())
->setActor($user)
->setContinueOnNoEffect(true)
->setContentSource(
PhabricatorContentSource::newForSource(
PhabricatorContentSource::SOURCE_CONDUIT,
array()));
$editor->applyTransactions($releeph_request, $xactions);
}
$url = PhabricatorEnv::getProductionURI('/Y'.$releeph_request->getID());
$results[$thing] = array(
'thing' => $thing,
'branch' => $releeph_branch->getDisplayNameWithDetail(),
'commitName' => $name,
'commitID' => $commit->getCommitIdentifier(),
'url' => $url,
'requestID' => $releeph_request->getID(),
'requestor' => $viewer_handle->getName(),
'requestTime' => $releeph_request->getDateCreated(),
'existing' => $existing_releeph_request !== null,
);
}
return $results;
}
}
diff --git a/src/applications/releeph/conduit/work/ConduitAPI_releephwork_getbranchcommitmessage_Method.php b/src/applications/releeph/conduit/work/ConduitAPI_releephwork_getbranchcommitmessage_Method.php
index 9095205466..9f5c6932c8 100644
--- a/src/applications/releeph/conduit/work/ConduitAPI_releephwork_getbranchcommitmessage_Method.php
+++ b/src/applications/releeph/conduit/work/ConduitAPI_releephwork_getbranchcommitmessage_Method.php
@@ -1,95 +1,99 @@
<?php
final class ConduitAPI_releephwork_getbranchcommitmessage_Method
extends ConduitAPI_releeph_Method {
public function getMethodStatus() {
return self::METHOD_STATUS_UNSTABLE;
}
public function getMethodDescription() {
return "Get a commit message for committing a Releeph branch.";
}
public function defineParamTypes() {
return array(
'branchPHID' => 'required string',
);
}
public function defineReturnType() {
return 'nonempty string';
}
public function defineErrorTypes() {
return array();
}
protected function execute(ConduitAPIRequest $request) {
- $branch = id(new ReleephBranch())
- ->loadOneWhere('phid = %s', $request->getValue('branchPHID'));
+ $viewer = $request->getUser();
- $project = $branch->loadReleephProject();
+ $branch = id(new ReleephBranchQuery())
+ ->setViewer($viewer)
+ ->withPHIDs(array($request->getValue('branchPHID')))
+ ->executeOne();
+
+ $project = $branch->getProduct();
$creator_phid = $branch->getCreatedByUserPHID();
$cut_phid = $branch->getCutPointCommitPHID();
$phids = array(
$branch->getPHID(),
$project->getPHID(),
$creator_phid,
$cut_phid,
);
$handles = id(new PhabricatorHandleQuery())
->setViewer($request->getUser())
->withPHIDs($phids)
->execute();
$h_branch = $handles[$branch->getPHID()];
$h_project = $handles[$project->getPHID()];
// Not as customizable as a ReleephRequest's commit message. It doesn't
// really need to be.
$commit_message = array();
$commit_message[] = $h_branch->getFullName();
$commit_message[] = $h_branch->getURI();
$commit_message[] = "Cut Point: ".$handles[$cut_phid]->getName();
$cut_point_pr_commit = id(new PhabricatorRepositoryCommit())
->loadOneWhere('phid = %s', $cut_phid);
$cut_point_commit_date = strftime(
'%Y-%m-%d %H:%M:%S%z',
$cut_point_pr_commit->getEpoch());
$commit_message[] = "Cut Point Date: {$cut_point_commit_date}";
$commit_message[] = "Created By: ".$handles[$creator_phid]->getName();
$project_uri = $project->getURI();
$commit_message[] = "Project: ".$h_project->getName()." ".$project_uri;
/**
* Required for 090-limit_new_branch_creations.sh in
* admin/scripts/git/hosting/hooks/update.d (in the E repo):
*
* http://fburl.com/2372545
*
* The commit message must have a line saying:
*
* @new-branch: <branch-name>
*
*/
$repo = $project->loadPhabricatorRepository();
switch ($repo->getVersionControlSystem()) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
$commit_message[] = sprintf(
'@new-branch: %s',
$branch->getName());
break;
}
return implode("\n\n", $commit_message);
}
}
diff --git a/src/applications/releeph/conduit/work/ConduitAPI_releephwork_getcommitmessage_Method.php b/src/applications/releeph/conduit/work/ConduitAPI_releephwork_getcommitmessage_Method.php
index 3241369579..3bdf941c8d 100644
--- a/src/applications/releeph/conduit/work/ConduitAPI_releephwork_getcommitmessage_Method.php
+++ b/src/applications/releeph/conduit/work/ConduitAPI_releephwork_getcommitmessage_Method.php
@@ -1,90 +1,94 @@
<?php
final class ConduitAPI_releephwork_getcommitmessage_Method
extends ConduitAPI_releeph_Method {
public function getMethodStatus() {
return self::METHOD_STATUS_UNSTABLE;
}
public function getMethodDescription() {
return
"Get commit message components for building ".
"a ReleephRequest commit message.";
}
public function defineParamTypes() {
return array(
'requestPHID' => 'required string',
'action' => 'required enum<"pick", "revert">',
);
}
public function defineReturnType() {
return 'dict<string, string>';
}
public function defineErrorTypes() {
return array();
}
protected function execute(ConduitAPIRequest $request) {
- $releeph_request = id(new ReleephRequest())
- ->loadOneWhere('phid = %s', $request->getValue('requestPHID'));
+ $viewer = $request->getUser();
+
+ $releeph_request = id(new ReleephRequestQuery())
+ ->setViewer($viewer)
+ ->withPHIDs(array($request->getValue('requestPHID')))
+ ->executeOne();
$action = $request->getValue('action');
$title = $releeph_request->getSummaryForDisplay();
$commit_message = array();
- $project = $releeph_request->loadReleephProject();
- $branch = $releeph_request->loadReleephBranch();
+ $branch = $releeph_request->getBranch();
+ $project = $branch->getProduct();
$selector = $project->getReleephFieldSelector();
$fields = $selector->getFieldSpecifications();
$fields = $selector->sortFieldsForCommitMessage($fields);
foreach ($fields as $field) {
$field
->setUser($request->getUser())
->setReleephProject($project)
->setReleephBranch($branch)
->setReleephRequest($releeph_request);
$label = null;
$value = null;
switch ($action) {
case 'pick':
if ($field->shouldAppearOnCommitMessage()) {
$label = $field->renderLabelForCommitMessage();
$value = $field->renderValueForCommitMessage();
}
break;
case 'revert':
if ($field->shouldAppearOnRevertMessage()) {
$label = $field->renderLabelForRevertMessage();
$value = $field->renderValueForRevertMessage();
}
break;
}
if ($label && $value) {
if (strpos($value, "\n") !== false ||
substr($value, 0, 2) === ' ') {
$commit_message[] = "{$label}:\n{$value}";
} else {
$commit_message[] = "{$label}: {$value}";
}
}
}
return array(
'title' => $title,
'body' => implode("\n\n", $commit_message),
);
}
}
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 125d9f10da..329b3f0451 100644
--- a/src/applications/releeph/conduit/work/ConduitAPI_releephwork_nextrequest_Method.php
+++ b/src/applications/releeph/conduit/work/ConduitAPI_releephwork_nextrequest_Method.php
@@ -1,214 +1,216 @@
<?php
final class ConduitAPI_releephwork_nextrequest_Method
extends ConduitAPI_releeph_Method {
private $project;
private $branch;
public function getMethodStatus() {
return self::METHOD_STATUS_UNSTABLE;
}
public function getMethodDescription() {
return
"Return info required to cut a branch, ".
"and pick and revert ReleephRequests";
}
public function defineParamTypes() {
return array(
'branchPHID' => 'required phid',
'seen' => 'required map<string, bool>',
);
}
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 ReleephBranch())
- ->loadOneWhere('phid = %s', $request->getValue('branchPHID'));
+ $branch = id(new ReleephBranchQuery())
+ ->setViewer($viewer)
+ ->withPHIDs(array($request->getValue('branchPHID')))
+ ->executeOne();
- $project = $branch->loadReleephProject();
+ $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();
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 <branch-commit-id>
$releeph_requests = mpull($releeph_requests, null, 'getCommitIdentifier');
$commits = id(new PhabricatorRepositoryCommit())
->loadAllWhere(
'commitIdentifier IN (%Ls)',
mpull($releeph_requests, 'getCommitIdentifier'));
// A map of <branch-commit-id> => <branch-commit-ordinal>
$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/differential/DifferentialReleephRequestFieldSpecification.php b/src/applications/releeph/differential/DifferentialReleephRequestFieldSpecification.php
index 6c94f7cd17..5ae00fb4e6 100644
--- a/src/applications/releeph/differential/DifferentialReleephRequestFieldSpecification.php
+++ b/src/applications/releeph/differential/DifferentialReleephRequestFieldSpecification.php
@@ -1,369 +1,371 @@
<?php
/**
* This DifferentialFieldSpecification exists for two reason:
*
* 1: To parse "Releeph: picks RQ<nn>" headers in commits created by
* arc-releeph so that RQs committed by arc-releeph have real
* PhabricatorRepositoryCommits associated with them (instaed of just the SHA
* of the commit, as seen by the pusher).
*
* 2: If requestors want to commit directly to their release branch, they can
* use this header to (i) indicate on a differential revision that this
* differential revision is for the release branch, and (ii) when they land
* their diff on to the release branch manually, the ReleephRequest is
* automatically updated (instead of having to use the "Mark Manually Picked"
* button.)
*
*/
final class DifferentialReleephRequestFieldSpecification {
// TODO: This class is essentially dead right now, see T2222.
const ACTION_PICKS = 'picks';
const ACTION_REVERTS = 'reverts';
private $releephAction;
private $releephPHIDs = array();
public function getStorageKey() {
return 'releeph:actions';
}
public function getValueForStorage() {
return json_encode(array(
'releephAction' => $this->releephAction,
'releephPHIDs' => $this->releephPHIDs,
));
}
public function setValueFromStorage($json) {
if ($json) {
$dict = json_decode($json, true);
$this->releephAction = idx($dict, 'releephAction');
$this->releephPHIDs = idx($dict, 'releephPHIDs');
}
return $this;
}
public function shouldAppearOnRevisionView() {
return true;
}
public function renderLabelForRevisionView() {
return 'Releeph';
}
public function getRequiredHandlePHIDs() {
return mpull($this->loadReleephRequests(), 'getPHID');
}
public function renderValueForRevisionView() {
static $tense = array(
self::ACTION_PICKS => array(
'future' => 'Will pick',
'past' => 'Picked',
),
self::ACTION_REVERTS => array(
'future' => 'Will revert',
'past' => 'Reverted',
),
);
$releeph_requests = $this->loadReleephRequests();
if (!$releeph_requests) {
return null;
}
$status = $this->getRevision()->getStatus();
if ($status == ArcanistDifferentialRevisionStatus::CLOSED) {
$verb = $tense[$this->releephAction]['past'];
} else {
$verb = $tense[$this->releephAction]['future'];
}
$parts = hsprintf('%s...', $verb);
foreach ($releeph_requests as $releeph_request) {
$parts->appendHTML(phutil_tag('br'));
$parts->appendHTML(
$this->getHandle($releeph_request->getPHID())->renderLink());
}
return $parts;
}
public function shouldAppearOnCommitMessage() {
return true;
}
public function getCommitMessageKey() {
return 'releephActions';
}
public function setValueFromParsedCommitMessage($dict) {
$this->releephAction = $dict['releephAction'];
$this->releephPHIDs = $dict['releephPHIDs'];
return $this;
}
public function renderValueForCommitMessage($is_edit) {
$releeph_requests = $this->loadReleephRequests();
if (!$releeph_requests) {
return null;
}
$parts = array($this->releephAction);
foreach ($releeph_requests as $releeph_request) {
$parts[] = 'RQ'.$releeph_request->getID();
}
return implode(' ', $parts);
}
/**
* Releeph fields should look like:
*
* Releeph: picks RQ1 RQ2, RQ3
* Releeph: reverts RQ1
*/
public function parseValueFromCommitMessage($value) {
/**
* Releeph commit messages look like this (but with more blank lines,
* omitted here):
*
* Make CaptainHaddock more reasonable
* Releeph: picks RQ1
* Requested By: edward
* Approved By: edward (requestor)
* Request Reason: x
* Summary: Make the Haddock implementation more reasonable.
* Test Plan: none
* Reviewers: user1
*
* Some of these fields are recognized by Differential (e.g. "Requested
* By"). They are folded up into the "Releeph" field, parsed by this
* class. As such $value includes more than just the first-line:
*
* "picks RQ1\n\nRequested By: edward\n\nApproved By: edward (requestor)"
*
* To hack around this, just consider the first line of $value when
* determining what Releeph actions the parsed commit is performing.
*/
$first_line = head(array_filter(explode("\n", $value)));
$tokens = preg_split('/\s*,?\s+/', $first_line);
$raw_action = array_shift($tokens);
$action = strtolower($raw_action);
if (!$action) {
return null;
}
switch ($action) {
case self::ACTION_REVERTS:
case self::ACTION_PICKS:
break;
default:
throw new DifferentialFieldParseException(
"Commit message contains unknown Releeph action '{$raw_action}'!");
break;
}
$releeph_requests = array();
foreach ($tokens as $token) {
$match = array();
if (!preg_match('/^(?:RQ)?(\d+)$/i', $token, $match)) {
$label = $this->renderLabelForCommitMessage();
throw new DifferentialFieldParseException(
"Commit message contains unparseable ".
"Releeph request token '{$token}'!");
}
$id = (int) $match[1];
$releeph_request = id(new ReleephRequest())->load($id);
if (!$releeph_request) {
throw new DifferentialFieldParseException(
"Commit message references non existent releeph request: {$value}!");
}
$releeph_requests[] = $releeph_request;
}
if (count($releeph_requests) > 1) {
$rqs_seen = array();
$groups = array();
foreach ($releeph_requests as $releeph_request) {
- $releeph_branch = $releeph_request->loadReleephBranch();
+ $releeph_branch = $releeph_request->getBranch();
$branch_name = $releeph_branch->getName();
$rq_id = 'RQ'.$releeph_request->getID();
if (idx($rqs_seen, $rq_id)) {
throw new DifferentialFieldParseException(
"Commit message refers to {$rq_id} multiple times!");
}
$rqs_seen[$rq_id] = true;
if (!isset($groups[$branch_name])) {
$groups[$branch_name] = array();
}
$groups[$branch_name][] = $rq_id;
}
if (count($groups) > 1) {
$lists = array();
foreach ($groups as $branch_name => $rq_ids) {
$lists[] = implode(', ', $rq_ids).' in '.$branch_name;
}
throw new DifferentialFieldParseException(
"Commit message references multiple Releeph requests, ".
"but the requests are in different branches: ".
implode('; ', $lists));
}
}
$phids = mpull($releeph_requests, 'getPHID');
$data = array(
'releephAction' => $action,
'releephPHIDs' => $phids,
);
return $data;
}
public function renderLabelForCommitMessage() {
return 'Releeph';
}
public function shouldAppearOnCommitMessageTemplate() {
return false;
}
public function didParseCommit(PhabricatorRepository $repo,
PhabricatorRepositoryCommit $commit,
PhabricatorRepositoryCommitData $data) {
// NOTE: This is currently dead code. See T2222.
$releeph_requests = $this->loadReleephRequests();
if (!$releeph_requests) {
return;
}
- $releeph_branch = head($releeph_requests)->loadReleephBranch();
+ $releeph_branch = head($releeph_requests)->getBranch();
if (!$this->isCommitOnBranch($repo, $commit, $releeph_branch)) {
return;
}
foreach ($releeph_requests as $releeph_request) {
if ($this->releephAction === self::ACTION_PICKS) {
$action = 'pick';
} else {
$action = 'revert';
}
$actor_phid = coalesce(
$data->getCommitDetail('committerPHID'),
$data->getCommitDetail('authorPHID'));
$actor = id(new PhabricatorUser())
->loadOneWhere('phid = %s', $actor_phid);
$xactions = array();
$xactions[] = id(new ReleephRequestTransaction())
->setTransactionType(ReleephRequestTransaction::TYPE_DISCOVERY)
->setMetadataValue('action', $action)
->setMetadataValue('authorPHID',
$data->getCommitDetail('authorPHID'))
->setMetadataValue('committerPHID',
$data->getCommitDetail('committerPHID'))
->setNewValue($commit->getPHID());
$editor = id(new ReleephRequestTransactionalEditor())
->setActor($actor)
->setContinueOnNoEffect(true)
->setContentSource(
PhabricatorContentSource::newForSource(
PhabricatorContentSource::SOURCE_UNKNOWN,
array()));
$editor->applyTransactions($releeph_request, $xactions);
}
}
private function loadReleephRequests() {
if (!$this->releephPHIDs) {
return array();
- } else {
- return id(new ReleephRequest())
- ->loadAllWhere('phid IN (%Ls)', $this->releephPHIDs);
}
+
+ return id(new ReleephRequestQuery())
+ ->setViewer($this->getViewer())
+ ->withPHIDs($this->releephPHIDs)
+ ->execute();
}
private function isCommitOnBranch(PhabricatorRepository $repo,
PhabricatorRepositoryCommit $commit,
ReleephBranch $releeph_branch) {
switch ($repo->getVersionControlSystem()) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
list($output) = $repo->execxLocalCommand(
'branch --all --no-color --contains %s',
$commit->getCommitIdentifier());
$remote_prefix = 'remotes/origin/';
$branches = array();
foreach (array_filter(explode("\n", $output)) as $line) {
$tokens = explode(' ', $line);
$ref = last($tokens);
if (strncmp($ref, $remote_prefix, strlen($remote_prefix)) === 0) {
$branch = substr($ref, strlen($remote_prefix));
$branches[$branch] = $branch;
}
}
return idx($branches, $releeph_branch->getName());
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
$change_query = DiffusionPathChangeQuery::newFromDiffusionRequest(
DiffusionRequest::newFromDictionary(array(
'user' => $this->getUser(),
'repository' => $repo,
'commit' => $commit->getCommitIdentifier(),
)));
$path_changes = $change_query->loadChanges();
$commit_paths = mpull($path_changes, 'getPath');
$branch_path = $releeph_branch->getName();
$in_branch = array();
$ex_branch = array();
foreach ($commit_paths as $path) {
if (strncmp($path, $branch_path, strlen($branch_path)) === 0) {
$in_branch[] = $path;
} else {
$ex_branch[] = $path;
}
}
if ($in_branch && $ex_branch) {
$error = sprintf(
"CONFUSION: commit %s in %s contains %d path change(s) that were ".
"part of a Releeph branch, but also has %d path change(s) not ".
"part of a Releeph branch!",
$commit->getCommitIdentifier(),
$repo->getCallsign(),
count($in_branch),
count($ex_branch));
phlog($error);
}
return !empty($in_branch);
break;
}
}
}
diff --git a/src/applications/releeph/editor/ReleephRequestTransactionalEditor.php b/src/applications/releeph/editor/ReleephRequestTransactionalEditor.php
index 56fd690846..775766cc96 100644
--- a/src/applications/releeph/editor/ReleephRequestTransactionalEditor.php
+++ b/src/applications/releeph/editor/ReleephRequestTransactionalEditor.php
@@ -1,302 +1,302 @@
<?php
final class ReleephRequestTransactionalEditor
extends PhabricatorApplicationTransactionEditor {
public function getTransactionTypes() {
$types = parent::getTransactionTypes();
$types[] = PhabricatorTransactions::TYPE_COMMENT;
$types[] = ReleephRequestTransaction::TYPE_COMMIT;
$types[] = ReleephRequestTransaction::TYPE_DISCOVERY;
$types[] = ReleephRequestTransaction::TYPE_EDIT_FIELD;
$types[] = ReleephRequestTransaction::TYPE_MANUAL_IN_BRANCH;
$types[] = ReleephRequestTransaction::TYPE_PICK_STATUS;
$types[] = ReleephRequestTransaction::TYPE_REQUEST;
$types[] = ReleephRequestTransaction::TYPE_USER_INTENT;
return $types;
}
public function getCustomTransactionOldValue(
PhabricatorLiskDAO $object,
PhabricatorApplicationTransaction $xaction) {
switch ($xaction->getTransactionType()) {
case ReleephRequestTransaction::TYPE_REQUEST:
return $object->getRequestCommitPHID();
case ReleephRequestTransaction::TYPE_EDIT_FIELD:
$field = newv($xaction->getMetadataValue('fieldClass'), array());
$value = $field->setReleephRequest($object)->getValue();
return $value;
case ReleephRequestTransaction::TYPE_USER_INTENT:
$user_phid = $xaction->getAuthorPHID();
return idx($object->getUserIntents(), $user_phid);
case ReleephRequestTransaction::TYPE_PICK_STATUS:
return (int)$object->getPickStatus();
break;
case ReleephRequestTransaction::TYPE_COMMIT:
return $object->getCommitIdentifier();
case ReleephRequestTransaction::TYPE_DISCOVERY:
return $object->getCommitPHID();
case ReleephRequestTransaction::TYPE_MANUAL_IN_BRANCH:
return $object->getInBranch();
}
}
public function getCustomTransactionNewValue(
PhabricatorLiskDAO $object,
PhabricatorApplicationTransaction $xaction) {
switch ($xaction->getTransactionType()) {
case ReleephRequestTransaction::TYPE_REQUEST:
case ReleephRequestTransaction::TYPE_USER_INTENT:
case ReleephRequestTransaction::TYPE_EDIT_FIELD:
case ReleephRequestTransaction::TYPE_PICK_STATUS:
case ReleephRequestTransaction::TYPE_COMMIT:
case ReleephRequestTransaction::TYPE_DISCOVERY:
case ReleephRequestTransaction::TYPE_MANUAL_IN_BRANCH:
return $xaction->getNewValue();
}
}
public function applyCustomInternalTransaction(
PhabricatorLiskDAO $object,
PhabricatorApplicationTransaction $xaction) {
$new = $xaction->getNewValue();
switch ($xaction->getTransactionType()) {
case ReleephRequestTransaction::TYPE_REQUEST:
$object->setRequestCommitPHID($new);
break;
case ReleephRequestTransaction::TYPE_USER_INTENT:
$user_phid = $xaction->getAuthorPHID();
$intents = $object->getUserIntents();
$intents[$user_phid] = $new;
$object->setUserIntents($intents);
break;
case ReleephRequestTransaction::TYPE_EDIT_FIELD:
$field = newv($xaction->getMetadataValue('fieldClass'), array());
$field
->setReleephRequest($object)
->setValue($new);
break;
case ReleephRequestTransaction::TYPE_PICK_STATUS:
$object->setPickStatus($new);
break;
case ReleephRequestTransaction::TYPE_COMMIT:
$this->setInBranchFromAction($object, $xaction);
$object->setCommitIdentifier($new);
break;
case ReleephRequestTransaction::TYPE_DISCOVERY:
$this->setInBranchFromAction($object, $xaction);
$object->setCommitPHID($new);
break;
case ReleephRequestTransaction::TYPE_MANUAL_IN_BRANCH:
$object->setInBranch((int) $new);
break;
}
}
protected function applyCustomExternalTransaction(
PhabricatorLiskDAO $object,
PhabricatorApplicationTransaction $xaction) {
return;
}
protected function filterTransactions(
PhabricatorLiskDAO $object,
array $xactions) {
// Remove TYPE_DISCOVERY xactions that are the result of a reparse.
$previously_discovered_commits = array();
$discovery_xactions = idx(
mgroup($xactions, 'getTransactionType'),
ReleephRequestTransaction::TYPE_DISCOVERY);
if ($discovery_xactions) {
$previous_xactions = id(new ReleephRequestTransactionQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withObjectPHIDs(array($object->getPHID()))
->execute();
foreach ($previous_xactions as $xaction) {
if ($xaction->getTransactionType() ===
ReleephRequestTransaction::TYPE_DISCOVERY) {
$commit_phid = $xaction->getNewValue();
$previously_discovered_commits[$commit_phid] = true;
}
}
}
foreach ($xactions as $key => $xaction) {
if ($xaction->getTransactionType() ===
ReleephRequestTransaction::TYPE_DISCOVERY &&
idx($previously_discovered_commits, $xaction->getNewValue())) {
unset($xactions[$key]);
}
}
return parent::filterTransactions($object, $xactions);
}
protected function shouldSendMail(
PhabricatorLiskDAO $object,
array $xactions) {
return true;
}
protected function sendMail(
PhabricatorLiskDAO $object,
array $xactions) {
// Avoid sending emails that only talk about commit discovery.
$types = array_unique(mpull($xactions, 'getTransactionType'));
if ($types === array(ReleephRequestTransaction::TYPE_DISCOVERY)) {
return null;
}
// Don't email people when we discover that something picks or reverts OK.
if ($types === array(ReleephRequestTransaction::TYPE_PICK_STATUS)) {
if (!mfilter($xactions, 'isBoringPickStatus', true /* negate */)) {
// If we effectively call "isInterestingPickStatus" and get nothing...
return null;
}
}
return parent::sendMail($object, $xactions);
}
protected function buildReplyHandler(PhabricatorLiskDAO $object) {
return id(new ReleephRequestReplyHandler())
->setActor($this->getActor())
->setMailReceiver($object);
}
protected function getMailSubjectPrefix() {
return '[Releeph]';
}
protected function buildMailTemplate(PhabricatorLiskDAO $object) {
$id = $object->getID();
$phid = $object->getPHID();
$title = $object->getSummaryForDisplay();
return id(new PhabricatorMetaMTAMail())
->setSubject("RQ{$id}: {$title}")
->addHeader('Thread-Topic', "RQ{$id}: {$phid}");
}
protected function getMailTo(PhabricatorLiskDAO $object) {
$to_phids = array();
- $releeph_project = $object->loadReleephProject();
- foreach ($releeph_project->getPushers() as $phid) {
+ $product = $object->getBranch()->getProduct();
+ foreach ($product->getPushers() as $phid) {
$to_phids[] = $phid;
}
foreach ($object->getUserIntents() as $phid => $intent) {
$to_phids[] = $phid;
}
return $to_phids;
}
protected function getMailCC(PhabricatorLiskDAO $object) {
return array();
}
protected function buildMailBody(
PhabricatorLiskDAO $object,
array $xactions) {
$body = parent::buildMailBody($object, $xactions);
$rq = $object;
- $releeph_branch = $rq->loadReleephBranch();
- $releeph_project = $releeph_branch->loadReleephProject();
+ $releeph_branch = $rq->getBranch();
+ $releeph_project = $releeph_branch->getProduct();
/**
* If any of the events we are emailing about were about a pick failure
* (and/or a revert failure?), include pick failure instructions.
*/
$has_pick_failure = false;
foreach ($xactions as $xaction) {
if ($xaction->getTransactionType() ===
ReleephRequestTransaction::TYPE_PICK_STATUS &&
$xaction->getNewValue() === ReleephRequest::PICK_FAILED) {
$has_pick_failure = true;
break;
}
}
if ($has_pick_failure) {
$instructions = $releeph_project->getDetail('pick_failure_instructions');
if ($instructions) {
$body->addTextSection(
pht('PICK FAILURE INSTRUCTIONS'),
$instructions);
}
}
$name = sprintf("RQ%s: %s", $rq->getID(), $rq->getSummaryForDisplay());
$body->addTextSection(
pht('RELEEPH REQUEST'),
$name."\n".
PhabricatorEnv::getProductionURI('/RQ'.$rq->getID()));
$project_and_branch = sprintf(
'%s - %s',
$releeph_project->getName(),
$releeph_branch->getDisplayNameWithDetail());
$body->addTextSection(
pht('RELEEPH BRANCH'),
$project_and_branch."\n".
PhabricatorEnv::getProductionURI($releeph_branch->getURI()));
return $body;
}
private function setInBranchFromAction(
ReleephRequest $rq,
ReleephRequestTransaction $xaction) {
$action = $xaction->getMetadataValue('action');
switch ($action) {
case 'pick':
$rq->setInBranch(1);
break;
case 'revert':
$rq->setInBranch(0);
break;
default:
$id = $rq->getID();
$type = $xaction->getTransactionType();
$new = $xaction->getNewValue();
phlog(
"Unknown discovery action '{$action}' ".
"for xaction of type {$type} ".
"with new value {$new} ".
"mentioning RQ{$id}!");
break;
}
}
}
diff --git a/src/applications/releeph/query/ReleephRequestQuery.php b/src/applications/releeph/query/ReleephRequestQuery.php
index 23725de1ec..5108e6361d 100644
--- a/src/applications/releeph/query/ReleephRequestQuery.php
+++ b/src/applications/releeph/query/ReleephRequestQuery.php
@@ -1,255 +1,257 @@
<?php
final class ReleephRequestQuery
extends PhabricatorCursorPagedPolicyAwareQuery {
private $requestedCommitPHIDs;
private $commitToRevMap;
private $ids;
private $phids;
private $severities;
private $requestorPHIDs;
private $branchIDs;
private $revisionPHIDs;
const STATUS_ALL = 'status-all';
const STATUS_OPEN = 'status-open';
const STATUS_REQUESTED = 'status-requested';
const STATUS_NEEDS_PULL = 'status-needs-pull';
const STATUS_REJECTED = 'status-rejected';
const STATUS_ABANDONED = 'status-abandoned';
const STATUS_PULLED = 'status-pulled';
const STATUS_NEEDS_REVERT = 'status-needs-revert';
const STATUS_REVERTED = 'status-reverted';
private $status = self::STATUS_ALL;
public function withIDs(array $ids) {
$this->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;
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) {
- // TODO: These should be serviced by the query, but are not currently
- // denormalized anywhere. For now, filter them here instead.
-
- $keep_status = array_fuse($this->getKeepStatusConstants());
- if ($keep_status) {
- foreach ($requests as $key => $request) {
- if (empty($keep_status[$request->getStatus()])) {
- unset($requests[$key]);
- }
- }
- }
-
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) {
$where[] = qsprintf(
$conn_r,
'id IN (%Ld)',
$this->ids);
}
if ($this->phids) {
$where[] = qsprintf(
$conn_r,
'phid IN (%Ls)',
$this->phids);
}
if ($this->branchIDs) {
$where[] = qsprintf(
$conn_r,
'branchID IN (%Ld)',
$this->branchIDs);
}
if ($this->requestedCommitPHIDs) {
$where[] = qsprintf(
$conn_r,
'requestCommitPHID IN (%Ls)',
$this->requestedCommitPHIDs);
}
if ($this->requestorPHIDs) {
$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");
}
$where[] = qsprintf(
$conn_r,
'requestCommitPHID IN (%Ls)',
array_keys($this->commitToRevMap));
}
$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/ReleephBranch.php b/src/applications/releeph/storage/ReleephBranch.php
index be6fc11428..d779af56a8 100644
--- a/src/applications/releeph/storage/ReleephBranch.php
+++ b/src/applications/releeph/storage/ReleephBranch.php
@@ -1,162 +1,154 @@
<?php
final class ReleephBranch extends ReleephDAO
implements PhabricatorPolicyInterface {
protected $releephProjectID;
protected $isActive;
protected $createdByUserPHID;
// The immutable name of this branch ('releases/foo-2013.01.24')
protected $name;
protected $basename;
// The symbolic name of this branch (LATEST, PRODUCTION, RC, ...)
// See SYMBOLIC_NAME_NOTE below
protected $symbolicName;
// Where to cut the branch
protected $cutPointCommitPHID;
protected $details = array();
private $project = self::ATTACHABLE;
private $cutPointCommit = self::ATTACHABLE;
public function getConfiguration() {
return array(
self::CONFIG_AUX_PHID => true,
self::CONFIG_SERIALIZATION => array(
'details' => self::SERIALIZATION_JSON,
),
) + parent::getConfiguration();
}
public function generatePHID() {
return PhabricatorPHID::generateNewPHID(ReleephPHIDTypeBranch::TYPECONST);
}
public function getDetail($key, $default = null) {
return idx($this->getDetails(), $key, $default);
}
public function setDetail($key, $value) {
$this->details[$key] = $value;
return $this;
}
public function willWriteData(array &$data) {
// If symbolicName is omitted, set it to the basename.
//
// This means that we can enforce symbolicName as a UNIQUE column in the
// DB. We'll interpret symbolicName === basename as meaning "no symbolic
// name".
//
// SYMBOLIC_NAME_NOTE
if (!$data['symbolicName']) {
$data['symbolicName'] = $data['basename'];
}
parent::willWriteData($data);
}
public function getSymbolicName() {
// See SYMBOLIC_NAME_NOTE above for why this is needed
if ($this->symbolicName == $this->getBasename()) {
return '';
}
return $this->symbolicName;
}
public function setSymbolicName($name) {
if ($name) {
parent::setSymbolicName($name);
} else {
parent::setSymbolicName($this->getBasename());
}
return $this;
}
public function getDisplayName() {
if ($sn = $this->getSymbolicName()) {
return $sn;
}
return $this->getBasename();
}
public function getDisplayNameWithDetail() {
$n = $this->getBasename();
if ($sn = $this->getSymbolicName()) {
return "{$sn} ({$n})";
} else {
return $n;
}
}
public function getURI($path = null) {
$components = array(
- '/releeph',
- rawurlencode($this->loadReleephProject()->getName()),
- rawurlencode($this->getBasename()),
- $path
+ '/releeph/branch',
+ $this->getID(),
+ $path,
);
return implode('/', $components);
}
- public function loadReleephProject() {
- return $this->loadOneRelative(
- new ReleephProject(),
- 'id',
- 'getReleephProjectID');
- }
-
public function isActive() {
return $this->getIsActive();
}
public function attachProject(ReleephProject $project) {
$this->project = $project;
return $this;
}
public function getProject() {
return $this->assertAttached($this->project);
}
public function getProduct() {
return $this->getProject();
}
public function attachCutPointCommit(
PhabricatorRepositoryCommit $commit = null) {
$this->cutPointCommit = $commit;
return $this;
}
public function getCutPointCommit() {
return $this->assertAttached($this->cutPointCommit);
}
/* -( PhabricatorPolicyInterface )----------------------------------------- */
public function getCapabilities() {
return $this->getProduct()->getCapabilities();
}
public function getPolicy($capability) {
return $this->getProduct()->getPolicy($capability);
}
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
return $this->getProduct()->hasAutomaticCapability($capability, $viewer);
}
public function describeAutomaticCapability($capability) {
return pht(
'Release branches have the same policies as the product they are a '.
'part of.');
}
}
diff --git a/src/applications/releeph/storage/ReleephProject.php b/src/applications/releeph/storage/ReleephProject.php
index b05dd3f50b..d6b520ac89 100644
--- a/src/applications/releeph/storage/ReleephProject.php
+++ b/src/applications/releeph/storage/ReleephProject.php
@@ -1,143 +1,143 @@
<?php
final class ReleephProject extends ReleephDAO
implements PhabricatorPolicyInterface {
const DEFAULT_BRANCH_NAMESPACE = 'releeph-releases';
const SYSTEM_AGENT_USERNAME_PREFIX = 'releeph-agent-';
protected $name;
// Specifying the place to pick from is a requirement for svn, though not
// for git. It's always useful though for reasoning about what revs have
// been picked and which haven't.
protected $trunkBranch;
protected $repositoryPHID;
protected $isActive;
protected $createdByUserPHID;
protected $arcanistProjectID;
protected $details = array();
private $repository = self::ATTACHABLE;
private $arcanistProject = self::ATTACHABLE;
public function getConfiguration() {
return array(
self::CONFIG_AUX_PHID => true,
self::CONFIG_SERIALIZATION => array(
'details' => self::SERIALIZATION_JSON,
),
) + parent::getConfiguration();
}
public function generatePHID() {
return PhabricatorPHID::generateNewPHID(ReleephPHIDTypeProduct::TYPECONST);
}
public function getDetail($key, $default = null) {
return idx($this->details, $key, $default);
}
public function getURI($path = null) {
$components = array(
- '/releeph/project',
+ '/releeph/product',
$this->getID(),
$path
);
return implode('/', $components);
}
public function setDetail($key, $value) {
$this->details[$key] = $value;
return $this;
}
public function getArcanistProject() {
return $this->assertAttached($this->arcanistProject);
}
public function attachArcanistProject(
PhabricatorRepositoryArcanistProject $arcanist_project = null) {
$this->arcanistProject = $arcanist_project;
return $this;
}
public function getPushers() {
return $this->getDetail('pushers', array());
}
public function isPusher(PhabricatorUser $user) {
// TODO Deprecate this once `isPusher` is out of the Facebook codebase.
return $this->isAuthoritative($user);
}
public function isAuthoritative(PhabricatorUser $user) {
return $this->isAuthoritativePHID($user->getPHID());
}
public function isAuthoritativePHID($phid) {
$pushers = $this->getPushers();
if (!$pushers) {
return true;
} else {
return in_array($phid, $pushers);
}
}
public function attachRepository(PhabricatorRepository $repository) {
$this->repository = $repository;
return $this;
}
public function getRepository() {
return $this->assertAttached($this->repository);
}
// TODO: Remove once everything uses ProjectQuery. Also, T603.
public function loadPhabricatorRepository() {
return $this->loadOneRelative(
new PhabricatorRepository(),
'phid',
'getRepositoryPHID');
}
public function getReleephFieldSelector() {
return new ReleephDefaultFieldSelector();
}
public function isTestFile($filename) {
$test_paths = $this->getDetail('testPaths', array());
foreach ($test_paths as $test_path) {
if (preg_match($test_path, $filename)) {
return true;
}
}
return false;
}
/* -( PhabricatorPolicyInterface )----------------------------------------- */
public function getCapabilities() {
return array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
);
}
public function getPolicy($capability) {
return PhabricatorPolicies::POLICY_USER;
}
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
return false;
}
public function describeAutomaticCapability($capability) {
return null;
}
}
diff --git a/src/applications/releeph/storage/ReleephRequest.php b/src/applications/releeph/storage/ReleephRequest.php
index 92f7de87a5..3c5af69850 100644
--- a/src/applications/releeph/storage/ReleephRequest.php
+++ b/src/applications/releeph/storage/ReleephRequest.php
@@ -1,330 +1,313 @@
<?php
final class ReleephRequest extends ReleephDAO
implements
PhabricatorPolicyInterface,
PhabricatorCustomFieldInterface {
protected $branchID;
protected $requestUserPHID;
protected $details = array();
protected $userIntents = array();
protected $inBranch;
protected $pickStatus;
protected $mailKey;
// Information about the thing being requested
protected $requestCommitPHID;
// Information about the last commit to the releeph branch
protected $commitIdentifier;
protected $commitPHID;
private $customFields = self::ATTACHABLE;
private $branch = self::ATTACHABLE;
/* -( Constants and helper methods )--------------------------------------- */
const INTENT_WANT = 'want';
const INTENT_PASS = 'pass';
const PICK_PENDING = 1; // old
const PICK_FAILED = 2;
const PICK_OK = 3;
const PICK_MANUAL = 4; // old
const REVERT_OK = 5;
const REVERT_FAILED = 6;
public function shouldBeInBranch() {
return
$this->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() {
- $project = $this->loadReleephProject();
- if (!$project) {
- return null;
- }
+ $product = $this->getBranch()->getProduct();
- if (!$project->getPushers()) {
+ if (!$product->getPushers()) {
return self::INTENT_WANT;
}
$found_pusher_want = false;
foreach ($this->userIntents as $phid => $intent) {
- if ($project->isAuthoritativePHID($phid)) {
+ 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;
}
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;
}
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 loadReleephBranch() {
- return $this->loadOneRelative(
- new ReleephBranch(),
- 'id',
- 'getBranchID');
- }
-
- public function loadReleephProject() {
- $branch = $this->loadReleephBranch();
- if ($branch) {
- return $branch->loadReleephProject();
- }
- }
-
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;
}
}

File Metadata

Mime Type
text/x-diff
Expires
Tue, Jul 29, 7:44 AM (2 w, 6 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
188298
Default Alt Text
(68 KB)

Event Timeline