mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-23 22:10:55 +01:00
Remove DifferentialRevisionEditor
Summary: Ref T2222. This has no callsites and no functionality not present in the TransactionEditor. Test Plan: awwyiss Reviewers: btrahan Reviewed By: btrahan CC: aran Maniphest Tasks: T2222 Differential Revision: https://secure.phabricator.com/D8456
This commit is contained in:
parent
c68703fbcb
commit
1df84168ef
2 changed files with 3 additions and 679 deletions
|
@ -468,7 +468,6 @@ phutil_register_library_map(array(
|
|||
'DifferentialRevisionControlSystem' => 'applications/differential/constants/DifferentialRevisionControlSystem.php',
|
||||
'DifferentialRevisionDetailView' => 'applications/differential/view/DifferentialRevisionDetailView.php',
|
||||
'DifferentialRevisionEditController' => 'applications/differential/controller/DifferentialRevisionEditController.php',
|
||||
'DifferentialRevisionEditor' => 'applications/differential/editor/DifferentialRevisionEditor.php',
|
||||
'DifferentialRevisionIDField' => 'applications/differential/customfield/DifferentialRevisionIDField.php',
|
||||
'DifferentialRevisionIDFieldParserTestCase' => 'applications/differential/field/specification/__tests__/DifferentialRevisionIDFieldParserTestCase.php',
|
||||
'DifferentialRevisionIDFieldSpecification' => 'applications/differential/field/specification/DifferentialRevisionIDFieldSpecification.php',
|
||||
|
@ -2719,7 +2718,7 @@ phutil_register_library_map(array(
|
|||
'ConduitAPI_differential_creatediff_Method' => 'ConduitAPIMethod',
|
||||
'ConduitAPI_differential_createinline_Method' => 'ConduitAPI_differential_Method',
|
||||
'ConduitAPI_differential_createrawdiff_Method' => 'ConduitAPI_differential_Method',
|
||||
'ConduitAPI_differential_createrevision_Method' => 'ConduitAPIMethod',
|
||||
'ConduitAPI_differential_createrevision_Method' => 'ConduitAPI_differential_Method',
|
||||
'ConduitAPI_differential_find_Method' => 'ConduitAPIMethod',
|
||||
'ConduitAPI_differential_finishpostponedlinters_Method' => 'ConduitAPIMethod',
|
||||
'ConduitAPI_differential_getalldiffs_Method' => 'ConduitAPIMethod',
|
||||
|
@ -2733,7 +2732,7 @@ phutil_register_library_map(array(
|
|||
'ConduitAPI_differential_query_Method' => 'ConduitAPIMethod',
|
||||
'ConduitAPI_differential_querydiffs_Method' => 'ConduitAPIMethod',
|
||||
'ConduitAPI_differential_setdiffproperty_Method' => 'ConduitAPIMethod',
|
||||
'ConduitAPI_differential_updaterevision_Method' => 'ConduitAPIMethod',
|
||||
'ConduitAPI_differential_updaterevision_Method' => 'ConduitAPI_differential_Method',
|
||||
'ConduitAPI_differential_updateunitresults_Method' => 'ConduitAPIMethod',
|
||||
'ConduitAPI_diffusion_Method' => 'ConduitAPIMethod',
|
||||
'ConduitAPI_diffusion_abstractquery_Method' => 'ConduitAPI_diffusion_Method',
|
||||
|
@ -3003,7 +3002,7 @@ phutil_register_library_map(array(
|
|||
'DifferentialLintFieldSpecification' => 'DifferentialFieldSpecification',
|
||||
'DifferentialLocalCommitsView' => 'AphrontView',
|
||||
'DifferentialMail' => 'PhabricatorMail',
|
||||
'DifferentialManiphestTasksField' => 'DifferentialCustomField',
|
||||
'DifferentialManiphestTasksField' => 'DifferentialCoreCustomField',
|
||||
'DifferentialManiphestTasksFieldSpecification' => 'DifferentialFieldSpecification',
|
||||
'DifferentialNewDiffMail' => 'DifferentialReviewRequestMail',
|
||||
'DifferentialPHIDTypeDiff' => 'PhabricatorPHIDType',
|
||||
|
@ -3043,7 +3042,6 @@ phutil_register_library_map(array(
|
|||
),
|
||||
'DifferentialRevisionDetailView' => 'AphrontView',
|
||||
'DifferentialRevisionEditController' => 'DifferentialController',
|
||||
'DifferentialRevisionEditor' => 'PhabricatorEditor',
|
||||
'DifferentialRevisionIDField' => 'DifferentialCustomField',
|
||||
'DifferentialRevisionIDFieldParserTestCase' => 'PhabricatorTestCase',
|
||||
'DifferentialRevisionIDFieldSpecification' => 'DifferentialFieldSpecification',
|
||||
|
|
|
@ -1,674 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Handle major edit operations to DifferentialRevision -- adding and removing
|
||||
* reviewers, diffs, and CCs. Unlike simple edits, these changes trigger
|
||||
* complicated email workflows.
|
||||
*/
|
||||
final class DifferentialRevisionEditor extends PhabricatorEditor {
|
||||
|
||||
protected $revision;
|
||||
|
||||
protected $cc = null;
|
||||
protected $reviewers = null;
|
||||
protected $diff;
|
||||
protected $comments;
|
||||
protected $silentUpdate;
|
||||
|
||||
private $auxiliaryFields = array();
|
||||
private $contentSource;
|
||||
private $isCreate;
|
||||
|
||||
public function __construct(DifferentialRevision $revision) {
|
||||
$this->revision = $revision;
|
||||
$this->isCreate = !($revision->getID());
|
||||
}
|
||||
|
||||
public function setAuxiliaryFields(array $auxiliary_fields) {
|
||||
assert_instances_of($auxiliary_fields, 'DifferentialFieldSpecification');
|
||||
$this->auxiliaryFields = $auxiliary_fields;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getRevision() {
|
||||
return $this->revision;
|
||||
}
|
||||
|
||||
public function setReviewers(array $reviewers) {
|
||||
$this->reviewers = $reviewers;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setCCPHIDs(array $cc) {
|
||||
$this->cc = $cc;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setContentSource(PhabricatorContentSource $content_source) {
|
||||
$this->contentSource = $content_source;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function addDiff(DifferentialDiff $diff, $comments) {
|
||||
if ($diff->getRevisionID() &&
|
||||
$diff->getRevisionID() != $this->getRevision()->getID()) {
|
||||
$diff_id = (int)$diff->getID();
|
||||
$targ_id = (int)$this->getRevision()->getID();
|
||||
$real_id = (int)$diff->getRevisionID();
|
||||
throw new Exception(
|
||||
"Can not attach diff #{$diff_id} to Revision D{$targ_id}, it is ".
|
||||
"already attached to D{$real_id}.");
|
||||
}
|
||||
$this->diff = $diff;
|
||||
$this->comments = $comments;
|
||||
|
||||
$repository = id(new DifferentialRepositoryLookup())
|
||||
->setViewer($this->getActor())
|
||||
->setDiff($diff)
|
||||
->lookupRepository();
|
||||
|
||||
if ($repository) {
|
||||
$this->getRevision()->setRepositoryPHID($repository->getPHID());
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function getDiff() {
|
||||
return $this->diff;
|
||||
}
|
||||
|
||||
protected function getComments() {
|
||||
return $this->comments;
|
||||
}
|
||||
|
||||
protected function getActorPHID() {
|
||||
return $this->getActor()->getPHID();
|
||||
}
|
||||
|
||||
public function isNewRevision() {
|
||||
return !$this->getRevision()->getID();
|
||||
}
|
||||
|
||||
|
||||
public function save() {
|
||||
$revision = $this->getRevision();
|
||||
|
||||
$is_new = $this->isNewRevision();
|
||||
|
||||
$revision->loadRelationships();
|
||||
|
||||
if ($this->reviewers === null) {
|
||||
$this->reviewers = $revision->getReviewers();
|
||||
}
|
||||
|
||||
if ($this->cc === null) {
|
||||
$this->cc = $revision->getCCPHIDs();
|
||||
}
|
||||
|
||||
if ($is_new) {
|
||||
$content_blocks = array();
|
||||
foreach ($this->auxiliaryFields as $field) {
|
||||
if ($field->shouldExtractMentions()) {
|
||||
$content_blocks[] = $field->renderValueForCommitMessage(false);
|
||||
}
|
||||
}
|
||||
$phids = PhabricatorMarkupEngine::extractPHIDsFromMentions(
|
||||
$content_blocks);
|
||||
$this->cc = array_unique(array_merge($this->cc, $phids));
|
||||
}
|
||||
|
||||
$diff = $this->getDiff();
|
||||
if ($diff) {
|
||||
$revision->setLineCount($diff->getLineCount());
|
||||
}
|
||||
|
||||
// Save the revision, to generate its ID and PHID if it is new. We need
|
||||
// the ID/PHID in order to record them in Herald transcripts, but don't
|
||||
// want to hold a transaction open while running Herald because it is
|
||||
// potentially somewhat slow. The downside is that we may end up with a
|
||||
// saved revision/diff pair without appropriate CCs. We could be better
|
||||
// about this -- for example:
|
||||
//
|
||||
// - Herald can't affect reviewers, so we could compute them before
|
||||
// opening the transaction and then save them in the transaction.
|
||||
// - Herald doesn't *really* need PHIDs to compute its effects, we could
|
||||
// run it before saving these objects and then hand over the PHIDs later.
|
||||
//
|
||||
// But this should address the problem of orphaned revisions, which is
|
||||
// currently the only problem we experience in practice.
|
||||
|
||||
$revision->openTransaction();
|
||||
|
||||
if ($diff) {
|
||||
$revision->setBranchName($diff->getBranch());
|
||||
$revision->setArcanistProjectPHID($diff->getArcanistProjectPHID());
|
||||
}
|
||||
|
||||
$revision->save();
|
||||
|
||||
if ($diff) {
|
||||
$diff->setRevisionID($revision->getID());
|
||||
$diff->save();
|
||||
}
|
||||
|
||||
$revision->saveTransaction();
|
||||
|
||||
|
||||
// We're going to build up three dictionaries: $add, $rem, and $stable. The
|
||||
// $add dictionary has added reviewers/CCs. The $rem dictionary has
|
||||
// reviewers/CCs who have been removed, and the $stable array is
|
||||
// reviewers/CCs who haven't changed. We're going to send new reviewers/CCs
|
||||
// a different ("welcome") email than we send stable reviewers/CCs.
|
||||
|
||||
$old = array(
|
||||
'rev' => array_fill_keys($revision->getReviewers(), true),
|
||||
'ccs' => array_fill_keys($revision->getCCPHIDs(), true),
|
||||
);
|
||||
|
||||
$xscript_header = null;
|
||||
$xscript_uri = null;
|
||||
|
||||
$new = array(
|
||||
'rev' => array_fill_keys($this->reviewers, true),
|
||||
'ccs' => array_fill_keys($this->cc, true),
|
||||
);
|
||||
|
||||
$rem_ccs = array();
|
||||
$xscript_phid = null;
|
||||
if ($diff) {
|
||||
$unsubscribed_phids = PhabricatorEdgeQuery::loadDestinationPHIDs(
|
||||
$revision->getPHID(),
|
||||
PhabricatorEdgeConfig::TYPE_OBJECT_HAS_UNSUBSCRIBER);
|
||||
|
||||
$adapter = HeraldDifferentialRevisionAdapter::newLegacyAdapter(
|
||||
$revision,
|
||||
$diff);
|
||||
$adapter->setExplicitCCs($new['ccs']);
|
||||
$adapter->setExplicitReviewers($new['rev']);
|
||||
$adapter->setForbiddenCCs($unsubscribed_phids);
|
||||
$adapter->setIsNewObject($is_new);
|
||||
|
||||
$xscript = HeraldEngine::loadAndApplyRules($adapter);
|
||||
$xscript_uri = '/herald/transcript/'.$xscript->getID().'/';
|
||||
$xscript_phid = $xscript->getPHID();
|
||||
$xscript_header = $xscript->getXHeraldRulesHeader();
|
||||
|
||||
$xscript_header = HeraldTranscript::saveXHeraldRulesHeader(
|
||||
$revision->getPHID(),
|
||||
$xscript_header);
|
||||
|
||||
$sub = array(
|
||||
'rev' => $adapter->getReviewersAddedByHerald(),
|
||||
'ccs' => $adapter->getCCsAddedByHerald(),
|
||||
);
|
||||
$rem_ccs = $adapter->getCCsRemovedByHerald();
|
||||
$blocking_reviewers = array_keys(
|
||||
$adapter->getBlockingReviewersAddedByHerald());
|
||||
|
||||
HarbormasterBuildable::applyBuildPlans(
|
||||
$diff->getPHID(),
|
||||
$revision->getPHID(),
|
||||
$adapter->getBuildPlans());
|
||||
} else {
|
||||
$sub = array(
|
||||
'rev' => array(),
|
||||
'ccs' => array(),
|
||||
);
|
||||
$blocking_reviewers = array();
|
||||
}
|
||||
|
||||
// Remove any CCs which are prevented by Herald rules.
|
||||
$sub['ccs'] = array_diff_key($sub['ccs'], $rem_ccs);
|
||||
$new['ccs'] = array_diff_key($new['ccs'], $rem_ccs);
|
||||
|
||||
$add = array();
|
||||
$rem = array();
|
||||
$stable = array();
|
||||
foreach (array('rev', 'ccs') as $key) {
|
||||
$add[$key] = array();
|
||||
if ($new[$key] !== null) {
|
||||
$add[$key] += array_diff_key($new[$key], $old[$key]);
|
||||
}
|
||||
$add[$key] += array_diff_key($sub[$key], $old[$key]);
|
||||
|
||||
$combined = $sub[$key];
|
||||
if ($new[$key] !== null) {
|
||||
$combined += $new[$key];
|
||||
}
|
||||
$rem[$key] = array_diff_key($old[$key], $combined);
|
||||
|
||||
$stable[$key] = array_diff_key($old[$key], $add[$key] + $rem[$key]);
|
||||
}
|
||||
|
||||
// Prevent Herald rules from adding a revision's owner as a reviewer.
|
||||
unset($add['rev'][$revision->getAuthorPHID()]);
|
||||
|
||||
self::updateReviewers(
|
||||
$revision,
|
||||
$this->getActor(),
|
||||
array_keys($add['rev']),
|
||||
array_keys($rem['rev']),
|
||||
$blocking_reviewers);
|
||||
|
||||
// We want to attribute new CCs to a "reasonPHID", representing the reason
|
||||
// they were added. This is either a user (if some user explicitly CCs
|
||||
// them, or uses "Add CCs...") or a Herald transcript PHID, indicating that
|
||||
// they were added by a Herald rule.
|
||||
|
||||
if ($add['ccs'] || $rem['ccs']) {
|
||||
$reasons = array();
|
||||
foreach ($add['ccs'] as $phid => $ignored) {
|
||||
if (empty($new['ccs'][$phid])) {
|
||||
$reasons[$phid] = $xscript_phid;
|
||||
} else {
|
||||
$reasons[$phid] = $this->getActorPHID();
|
||||
}
|
||||
}
|
||||
foreach ($rem['ccs'] as $phid => $ignored) {
|
||||
if (empty($new['ccs'][$phid])) {
|
||||
$reasons[$phid] = $this->getActorPHID();
|
||||
} else {
|
||||
$reasons[$phid] = $xscript_phid;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$reasons = $this->getActorPHID();
|
||||
}
|
||||
|
||||
self::alterCCs(
|
||||
$revision,
|
||||
$this->cc,
|
||||
array_keys($rem['ccs']),
|
||||
array_keys($add['ccs']),
|
||||
$reasons);
|
||||
|
||||
$this->updateAuxiliaryFields();
|
||||
|
||||
// Add the author and users included from Herald rules to the relevant set
|
||||
// of users so they get a copy of the email.
|
||||
if (!$this->silentUpdate) {
|
||||
if ($is_new) {
|
||||
$add['rev'][$this->getActorPHID()] = true;
|
||||
if ($diff) {
|
||||
$add['rev'] += $adapter->getEmailPHIDsAddedByHerald();
|
||||
}
|
||||
} else {
|
||||
$stable['rev'][$this->getActorPHID()] = true;
|
||||
if ($diff) {
|
||||
$stable['rev'] += $adapter->getEmailPHIDsAddedByHerald();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$mail = array();
|
||||
|
||||
$phids = array($this->getActorPHID());
|
||||
|
||||
$handles = id(new PhabricatorHandleQuery())
|
||||
->setViewer($this->getActor())
|
||||
->withPHIDs($phids)
|
||||
->execute();
|
||||
$actor_handle = $handles[$this->getActorPHID()];
|
||||
|
||||
$changesets = null;
|
||||
$old_status = $revision->getStatus();
|
||||
|
||||
if ($diff) {
|
||||
$changesets = $diff->loadChangesets();
|
||||
// TODO: This should probably be in DifferentialFeedbackEditor?
|
||||
if (!$is_new) {
|
||||
$this->createComment();
|
||||
$mail[] = id(new DifferentialNewDiffMail(
|
||||
$revision,
|
||||
$actor_handle,
|
||||
$changesets))
|
||||
->setActor($this->getActor())
|
||||
->setIsFirstMailAboutRevision(false)
|
||||
->setIsFirstMailToRecipients(false)
|
||||
->setCommentText($this->getComments())
|
||||
->setToPHIDs(array_keys($stable['rev']))
|
||||
->setCCPHIDs(array_keys($stable['ccs']));
|
||||
}
|
||||
|
||||
// Save the changes we made above.
|
||||
|
||||
$diff->setDescription(preg_replace('/\n.*/s', '', $this->getComments()));
|
||||
$diff->save();
|
||||
|
||||
// An updated diff should require review, as long as it's not closed
|
||||
// or accepted. The "accepted" status is "sticky" to encourage courtesy
|
||||
// re-diffs after someone accepts with minor changes/suggestions.
|
||||
|
||||
$status = $revision->getStatus();
|
||||
if ($status != ArcanistDifferentialRevisionStatus::CLOSED &&
|
||||
$status != ArcanistDifferentialRevisionStatus::ACCEPTED) {
|
||||
$revision->setStatus(ArcanistDifferentialRevisionStatus::NEEDS_REVIEW);
|
||||
}
|
||||
|
||||
} else {
|
||||
$diff = $revision->loadActiveDiff();
|
||||
if ($diff) {
|
||||
$changesets = $diff->loadChangesets();
|
||||
} else {
|
||||
$changesets = array();
|
||||
}
|
||||
}
|
||||
|
||||
$revision->save();
|
||||
|
||||
// If the actor just deleted all the blocking/rejected reviewers, we may
|
||||
// be able to put the revision into "accepted".
|
||||
switch ($revision->getStatus()) {
|
||||
case ArcanistDifferentialRevisionStatus::NEEDS_REVISION:
|
||||
case ArcanistDifferentialRevisionStatus::CHANGES_PLANNED:
|
||||
case ArcanistDifferentialRevisionStatus::NEEDS_REVIEW:
|
||||
$revision = self::updateAcceptedStatus(
|
||||
$this->getActor(),
|
||||
$revision);
|
||||
break;
|
||||
}
|
||||
|
||||
$event_data = array(
|
||||
'revision_id' => $revision->getID(),
|
||||
'revision_phid' => $revision->getPHID(),
|
||||
'revision_name' => $revision->getTitle(),
|
||||
'revision_author_phid' => $revision->getAuthorPHID(),
|
||||
'action' => $is_new
|
||||
? DifferentialAction::ACTION_CREATE
|
||||
: DifferentialAction::ACTION_UPDATE,
|
||||
'feedback_content' => $is_new
|
||||
? phutil_utf8_shorten($revision->getSummary(), 140)
|
||||
: $this->getComments(),
|
||||
'actor_phid' => $revision->getAuthorPHID(),
|
||||
);
|
||||
|
||||
$mailed_phids = array();
|
||||
if (!$this->silentUpdate) {
|
||||
$revision->loadRelationships();
|
||||
|
||||
if ($add['rev']) {
|
||||
$message = id(new DifferentialNewDiffMail(
|
||||
$revision,
|
||||
$actor_handle,
|
||||
$changesets))
|
||||
->setActor($this->getActor())
|
||||
->setIsFirstMailAboutRevision($is_new)
|
||||
->setIsFirstMailToRecipients(true)
|
||||
->setToPHIDs(array_keys($add['rev']));
|
||||
|
||||
if ($is_new) {
|
||||
// The first time we send an email about a revision, put the CCs in
|
||||
// the "CC:" field of the same "Review Requested" email that reviewers
|
||||
// get, so you don't get two initial emails if you're on a list that
|
||||
// is CC'd.
|
||||
$message->setCCPHIDs(array_keys($add['ccs']));
|
||||
}
|
||||
|
||||
$mail[] = $message;
|
||||
}
|
||||
|
||||
// If we added CCs, we want to send them an email, but only if they were
|
||||
// not already a reviewer and were not added as one (in these cases, they
|
||||
// got a "NewDiff" mail, either in the past or just a moment ago). You can
|
||||
// still get two emails, but only if a revision is updated and you are
|
||||
// added as a reviewer at the same time a list you are on is added as a
|
||||
// CC, which is rare and reasonable.
|
||||
|
||||
$implied_ccs = self::getImpliedCCs($revision);
|
||||
$implied_ccs = array_fill_keys($implied_ccs, true);
|
||||
$add['ccs'] = array_diff_key($add['ccs'], $implied_ccs);
|
||||
|
||||
if (!$is_new && $add['ccs']) {
|
||||
$mail[] = id(new DifferentialCCWelcomeMail(
|
||||
$revision,
|
||||
$actor_handle,
|
||||
$changesets))
|
||||
->setActor($this->getActor())
|
||||
->setIsFirstMailToRecipients(true)
|
||||
->setToPHIDs(array_keys($add['ccs']));
|
||||
}
|
||||
|
||||
foreach ($mail as $message) {
|
||||
$message->setHeraldTranscriptURI($xscript_uri);
|
||||
$message->setXHeraldRulesHeader($xscript_header);
|
||||
$message->send();
|
||||
|
||||
$mailed_phids[] = $message->getRawMail()->buildRecipientList();
|
||||
}
|
||||
$mailed_phids = array_mergev($mailed_phids);
|
||||
}
|
||||
|
||||
id(new PhabricatorFeedStoryPublisher())
|
||||
->setStoryType('PhabricatorFeedStoryDifferential')
|
||||
->setStoryData($event_data)
|
||||
->setStoryTime(time())
|
||||
->setStoryAuthorPHID($revision->getAuthorPHID())
|
||||
->setRelatedPHIDs(
|
||||
array(
|
||||
$revision->getPHID(),
|
||||
$revision->getAuthorPHID(),
|
||||
))
|
||||
->setPrimaryObjectPHID($revision->getPHID())
|
||||
->setSubscribedPHIDs(
|
||||
array_merge(
|
||||
array($revision->getAuthorPHID()),
|
||||
$revision->getReviewers(),
|
||||
$revision->getCCPHIDs()))
|
||||
->setMailRecipientPHIDs($mailed_phids)
|
||||
->publish();
|
||||
|
||||
id(new PhabricatorSearchIndexer())
|
||||
->queueDocumentForIndexing($revision->getPHID());
|
||||
}
|
||||
|
||||
protected static function alterCCs(
|
||||
DifferentialRevision $revision,
|
||||
array $stable_phids,
|
||||
array $rem_phids,
|
||||
array $add_phids,
|
||||
$reason_phid) {
|
||||
|
||||
$dont_add = self::getImpliedCCs($revision);
|
||||
$add_phids = array_diff($add_phids, $dont_add);
|
||||
|
||||
id(new PhabricatorSubscriptionsEditor())
|
||||
->setActor(PhabricatorUser::getOmnipotentUser())
|
||||
->setObject($revision)
|
||||
->subscribeExplicit($add_phids)
|
||||
->unsubscribe($rem_phids)
|
||||
->save();
|
||||
}
|
||||
|
||||
private static function getImpliedCCs(DifferentialRevision $revision) {
|
||||
return array_merge(
|
||||
$revision->getReviewers(),
|
||||
array($revision->getAuthorPHID()));
|
||||
}
|
||||
|
||||
public static function updateReviewers(
|
||||
DifferentialRevision $revision,
|
||||
PhabricatorUser $actor,
|
||||
array $add_phids,
|
||||
array $remove_phids,
|
||||
array $blocking_phids = array()) {
|
||||
|
||||
$reviewers = $revision->getReviewers();
|
||||
|
||||
$editor = id(new PhabricatorEdgeEditor())
|
||||
->setActor($actor);
|
||||
|
||||
$reviewer_phids_map = array_fill_keys($reviewers, true);
|
||||
|
||||
$blocking_phids = array_fuse($blocking_phids);
|
||||
foreach ($add_phids as $phid) {
|
||||
|
||||
// Adding an already existing edge again would have cause memory loss
|
||||
// That is, the previous state for that reviewer would be lost
|
||||
if (isset($reviewer_phids_map[$phid])) {
|
||||
// TODO: If we're writing a blocking edge, we should overwrite an
|
||||
// existing weaker edge (like "added" or "commented"), just not a
|
||||
// stronger existing edge.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isset($blocking_phids[$phid])) {
|
||||
$status = DifferentialReviewerStatus::STATUS_BLOCKING;
|
||||
} else {
|
||||
$status = DifferentialReviewerStatus::STATUS_ADDED;
|
||||
}
|
||||
|
||||
$options = array(
|
||||
'data' => array(
|
||||
'status' => $status,
|
||||
)
|
||||
);
|
||||
|
||||
$editor->addEdge(
|
||||
$revision->getPHID(),
|
||||
PhabricatorEdgeConfig::TYPE_DREV_HAS_REVIEWER,
|
||||
$phid,
|
||||
$options);
|
||||
}
|
||||
|
||||
foreach ($remove_phids as $phid) {
|
||||
$editor->removeEdge(
|
||||
$revision->getPHID(),
|
||||
PhabricatorEdgeConfig::TYPE_DREV_HAS_REVIEWER,
|
||||
$phid);
|
||||
}
|
||||
|
||||
$editor->save();
|
||||
}
|
||||
|
||||
private function createComment() {
|
||||
$template = id(new DifferentialComment())
|
||||
->setAuthorPHID($this->getActorPHID())
|
||||
->setRevision($this->revision);
|
||||
|
||||
if ($this->contentSource) {
|
||||
$content_source = $this->contentSource;
|
||||
} else {
|
||||
$content_source = PhabricatorContentSource::newForSource(
|
||||
PhabricatorContentSource::SOURCE_LEGACY,
|
||||
array());
|
||||
}
|
||||
|
||||
$template->setContentSource($content_source);
|
||||
|
||||
|
||||
// Write the "update active diff" transaction.
|
||||
id(clone $template)
|
||||
->setAction(DifferentialAction::ACTION_UPDATE)
|
||||
->setMetadata(
|
||||
array(
|
||||
DifferentialComment::METADATA_DIFF_ID => $this->getDiff()->getID(),
|
||||
))
|
||||
->save();
|
||||
|
||||
// If we have a comment, write the "add a comment" transaction.
|
||||
if (strlen($this->getComments())) {
|
||||
id(clone $template)
|
||||
->setAction(DifferentialAction::ACTION_COMMENT)
|
||||
->setContent($this->getComments())
|
||||
->save();
|
||||
}
|
||||
}
|
||||
|
||||
private function updateAuxiliaryFields() {
|
||||
$aux_map = array();
|
||||
foreach ($this->auxiliaryFields as $aux_field) {
|
||||
$key = $aux_field->getStorageKey();
|
||||
if ($key !== null) {
|
||||
$val = $aux_field->getValueForStorage();
|
||||
$aux_map[$key] = $val;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$aux_map) {
|
||||
return;
|
||||
}
|
||||
|
||||
$revision = $this->revision;
|
||||
|
||||
$fields = id(new DifferentialCustomFieldStorage())->loadAllWhere(
|
||||
'objectPHID = %s',
|
||||
$revision->getPHID());
|
||||
$fields = mpull($fields, null, 'getFieldIndex');
|
||||
|
||||
foreach ($aux_map as $key => $val) {
|
||||
$index = PhabricatorHash::digestForIndex($key);
|
||||
$obj = idx($fields, $index);
|
||||
if (!strlen($val)) {
|
||||
// If the new value is empty, just delete the old row if one exists and
|
||||
// don't add a new row if it doesn't.
|
||||
if ($obj) {
|
||||
$obj->delete();
|
||||
}
|
||||
} else {
|
||||
if (!$obj) {
|
||||
$obj = new DifferentialCustomFieldStorage();
|
||||
$obj->setObjectPHID($revision->getPHID());
|
||||
$obj->setFieldIndex($index);
|
||||
}
|
||||
|
||||
if ($obj->getFieldValue() !== $val) {
|
||||
$obj->setFieldValue($val);
|
||||
$obj->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Try to move a revision to "accepted". We look for:
|
||||
*
|
||||
* - at least one accepting reviewer who is a user; and
|
||||
* - no rejects; and
|
||||
* - no blocking reviewers.
|
||||
*/
|
||||
public static function updateAcceptedStatus(
|
||||
PhabricatorUser $viewer,
|
||||
DifferentialRevision $revision) {
|
||||
|
||||
$revision = id(new DifferentialRevisionQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($revision->getID()))
|
||||
->needRelationships(true)
|
||||
->needReviewerStatus(true)
|
||||
->needReviewerAuthority(true)
|
||||
->executeOne();
|
||||
|
||||
$has_user_accept = false;
|
||||
foreach ($revision->getReviewerStatus() as $reviewer) {
|
||||
$status = $reviewer->getStatus();
|
||||
if ($status == DifferentialReviewerStatus::STATUS_BLOCKING) {
|
||||
// We have a blocking reviewer, so just leave the revision in its
|
||||
// existing state.
|
||||
return $revision;
|
||||
}
|
||||
|
||||
if ($status == DifferentialReviewerStatus::STATUS_REJECTED) {
|
||||
// We have a rejecting reviewer, so leave the revisoin as is.
|
||||
return $revision;
|
||||
}
|
||||
|
||||
if ($reviewer->isUser()) {
|
||||
if ($status == DifferentialReviewerStatus::STATUS_ACCEPTED) {
|
||||
$has_user_accept = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($has_user_accept) {
|
||||
$revision
|
||||
->setStatus(ArcanistDifferentialRevisionStatus::ACCEPTED)
|
||||
->save();
|
||||
}
|
||||
|
||||
return $revision;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue