2011-03-25 05:32:26 +01:00
|
|
|
<?php
|
|
|
|
|
2013-08-15 22:10:45 +02:00
|
|
|
/**
|
|
|
|
* @group herald
|
|
|
|
*/
|
2013-08-02 17:38:17 +02:00
|
|
|
final class HeraldDifferentialRevisionAdapter extends HeraldAdapter {
|
2011-03-25 05:32:26 +01:00
|
|
|
|
|
|
|
protected $revision;
|
2011-04-06 05:49:31 +02:00
|
|
|
protected $diff;
|
2011-03-25 05:32:26 +01:00
|
|
|
|
|
|
|
protected $explicitCCs;
|
|
|
|
protected $explicitReviewers;
|
|
|
|
protected $forbiddenCCs;
|
|
|
|
|
|
|
|
protected $newCCs = array();
|
|
|
|
protected $remCCs = array();
|
2011-05-28 00:52:26 +02:00
|
|
|
protected $emailPHIDs = array();
|
2011-03-25 05:32:26 +01:00
|
|
|
|
2011-04-06 05:49:31 +02:00
|
|
|
protected $repository;
|
|
|
|
protected $affectedPackages;
|
|
|
|
protected $changesets;
|
|
|
|
|
2013-08-02 17:55:13 +02:00
|
|
|
public function isEnabled() {
|
|
|
|
$app = 'PhabricatorApplicationDifferential';
|
|
|
|
return PhabricatorApplication::isClassInstalled($app);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getAdapterContentType() {
|
|
|
|
return 'differential';
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getAdapterContentName() {
|
|
|
|
return pht('Differential Revisions');
|
|
|
|
}
|
|
|
|
|
2013-08-02 19:25:45 +02:00
|
|
|
public function getFields() {
|
|
|
|
return array(
|
|
|
|
self::FIELD_TITLE,
|
|
|
|
self::FIELD_BODY,
|
|
|
|
self::FIELD_AUTHOR,
|
|
|
|
self::FIELD_REVIEWERS,
|
|
|
|
self::FIELD_CC,
|
|
|
|
self::FIELD_REPOSITORY,
|
|
|
|
self::FIELD_DIFF_FILE,
|
|
|
|
self::FIELD_DIFF_CONTENT,
|
|
|
|
self::FIELD_RULE,
|
|
|
|
self::FIELD_AFFECTED_PACKAGE,
|
|
|
|
self::FIELD_AFFECTED_PACKAGE_OWNER,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2013-08-02 21:35:33 +02:00
|
|
|
public function getRepetitionOptions() {
|
|
|
|
return array(
|
|
|
|
HeraldRepetitionPolicyConfig::EVERY,
|
|
|
|
HeraldRepetitionPolicyConfig::FIRST,
|
|
|
|
);
|
|
|
|
}
|
2013-08-02 19:25:45 +02:00
|
|
|
|
2013-08-02 17:55:13 +02:00
|
|
|
public static function newLegacyAdapter(
|
2011-04-06 05:49:31 +02:00
|
|
|
DifferentialRevision $revision,
|
|
|
|
DifferentialDiff $diff) {
|
|
|
|
|
2013-08-02 17:55:13 +02:00
|
|
|
$object = new HeraldDifferentialRevisionAdapter();
|
|
|
|
|
2011-03-25 05:32:26 +01:00
|
|
|
$revision->loadRelationships();
|
2013-08-02 17:55:13 +02:00
|
|
|
$object->revision = $revision;
|
|
|
|
$object->diff = $diff;
|
|
|
|
|
|
|
|
return $object;
|
2011-03-25 05:32:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public function setExplicitCCs($explicit_ccs) {
|
|
|
|
$this->explicitCCs = $explicit_ccs;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function setExplicitReviewers($explicit_reviewers) {
|
|
|
|
$this->explicitReviewers = $explicit_reviewers;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function setForbiddenCCs($forbidden_ccs) {
|
|
|
|
$this->forbiddenCCs = $forbidden_ccs;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getCCsAddedByHerald() {
|
|
|
|
return array_diff_key($this->newCCs, $this->remCCs);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getCCsRemovedByHerald() {
|
|
|
|
return $this->remCCs;
|
|
|
|
}
|
|
|
|
|
2011-05-28 00:52:26 +02:00
|
|
|
public function getEmailPHIDsAddedByHerald() {
|
|
|
|
return $this->emailPHIDs;
|
|
|
|
}
|
|
|
|
|
2011-03-25 05:32:26 +01:00
|
|
|
public function getPHID() {
|
|
|
|
return $this->revision->getPHID();
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getHeraldName() {
|
|
|
|
return $this->revision->getTitle();
|
|
|
|
}
|
|
|
|
|
2011-04-06 05:49:31 +02:00
|
|
|
public function loadRepository() {
|
|
|
|
if ($this->repository === null) {
|
2013-09-27 00:28:42 +02:00
|
|
|
$this->repository = false;
|
2011-04-06 05:49:31 +02:00
|
|
|
|
2013-09-26 01:54:48 +02:00
|
|
|
// TODO: (T603) Implement policy stuff in Herald.
|
2013-09-27 00:28:42 +02:00
|
|
|
$viewer = PhabricatorUser::getOmnipotentUser();
|
|
|
|
|
|
|
|
$revision = $this->revision;
|
|
|
|
if ($revision->getRepositoryPHID()) {
|
|
|
|
$repositories = id(new PhabricatorRepositoryQuery())
|
|
|
|
->setViewer($viewer)
|
|
|
|
->withPHIDs(array($revision->getRepositoryPHID()))
|
|
|
|
->execute();
|
|
|
|
if ($repositories) {
|
|
|
|
$this->repository = head($repositories);
|
|
|
|
return $this->repository;
|
|
|
|
}
|
2011-04-06 05:49:31 +02:00
|
|
|
}
|
|
|
|
|
2013-09-27 00:28:42 +02:00
|
|
|
$repository = id(new DifferentialRepositoryLookup())
|
|
|
|
->setViewer($viewer)
|
|
|
|
->setDiff($this->diff)
|
|
|
|
->lookupRepository();
|
|
|
|
if ($repository) {
|
|
|
|
$this->repository = $repository;
|
|
|
|
return $this->repository;
|
2011-04-06 05:49:31 +02:00
|
|
|
}
|
|
|
|
|
2013-09-27 00:28:42 +02:00
|
|
|
$repository = false;
|
2011-04-06 05:49:31 +02:00
|
|
|
}
|
|
|
|
return $this->repository;
|
|
|
|
}
|
|
|
|
|
2011-03-25 05:32:26 +01:00
|
|
|
protected function loadChangesets() {
|
2011-04-06 05:49:31 +02:00
|
|
|
if ($this->changesets === null) {
|
|
|
|
$this->changesets = $this->diff->loadChangesets();
|
|
|
|
}
|
|
|
|
return $this->changesets;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function loadAffectedPaths() {
|
|
|
|
$changesets = $this->loadChangesets();
|
|
|
|
|
|
|
|
$paths = array();
|
|
|
|
foreach ($changesets as $changeset) {
|
|
|
|
$paths[] = $this->getAbsoluteRepositoryPathForChangeset($changeset);
|
2011-03-25 05:32:26 +01:00
|
|
|
}
|
2011-04-06 05:49:31 +02:00
|
|
|
return $paths;
|
2011-03-25 05:32:26 +01:00
|
|
|
}
|
|
|
|
|
2011-04-06 05:49:31 +02:00
|
|
|
protected function getAbsoluteRepositoryPathForChangeset(
|
|
|
|
DifferentialChangeset $changeset) {
|
|
|
|
|
|
|
|
$repository = $this->loadRepository();
|
|
|
|
if (!$repository) {
|
|
|
|
return '/'.ltrim($changeset->getFilename(), '/');
|
2011-03-25 05:32:26 +01:00
|
|
|
}
|
2011-04-06 05:49:31 +02:00
|
|
|
|
|
|
|
$diff = $this->diff;
|
|
|
|
|
2012-04-10 08:42:12 +02:00
|
|
|
return $changeset->getAbsoluteRepositoryPath($repository, $diff);
|
2011-03-25 05:32:26 +01:00
|
|
|
}
|
|
|
|
|
2011-04-06 05:49:31 +02:00
|
|
|
protected function loadContentDictionary() {
|
|
|
|
$changesets = $this->loadChangesets();
|
2011-03-25 05:32:26 +01:00
|
|
|
|
|
|
|
$hunks = array();
|
2011-04-06 05:49:31 +02:00
|
|
|
if ($changesets) {
|
|
|
|
$hunks = id(new DifferentialHunk())->loadAllWhere(
|
2011-03-25 05:32:26 +01:00
|
|
|
'changesetID in (%Ld)',
|
2011-04-06 05:49:31 +02:00
|
|
|
mpull($changesets, 'getID'));
|
2011-03-25 05:32:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
$dict = array();
|
|
|
|
$hunks = mgroup($hunks, 'getChangesetID');
|
2011-04-06 05:49:31 +02:00
|
|
|
$changesets = mpull($changesets, null, 'getID');
|
|
|
|
foreach ($changesets as $id => $changeset) {
|
|
|
|
$path = $this->getAbsoluteRepositoryPathForChangeset($changeset);
|
2011-03-25 05:32:26 +01:00
|
|
|
$content = array();
|
|
|
|
foreach (idx($hunks, $id, array()) as $hunk) {
|
|
|
|
$content[] = $hunk->makeChanges();
|
|
|
|
}
|
2011-04-06 05:49:31 +02:00
|
|
|
$dict[$path] = implode("\n", $content);
|
2011-03-25 05:32:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return $dict;
|
|
|
|
}
|
|
|
|
|
2011-04-06 05:49:31 +02:00
|
|
|
public function loadAffectedPackages() {
|
|
|
|
if ($this->affectedPackages === null) {
|
|
|
|
$this->affectedPackages = array();
|
|
|
|
|
|
|
|
$repository = $this->loadRepository();
|
|
|
|
if ($repository) {
|
|
|
|
$packages = PhabricatorOwnersPackage::loadAffectedPackages(
|
|
|
|
$repository,
|
|
|
|
$this->loadAffectedPaths());
|
|
|
|
$this->affectedPackages = $packages;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return $this->affectedPackages;
|
|
|
|
}
|
|
|
|
|
2011-03-25 05:32:26 +01:00
|
|
|
public function getHeraldField($field) {
|
|
|
|
switch ($field) {
|
2013-08-02 19:54:19 +02:00
|
|
|
case self::FIELD_TITLE:
|
2011-03-25 05:32:26 +01:00
|
|
|
return $this->revision->getTitle();
|
|
|
|
break;
|
2013-08-02 19:54:19 +02:00
|
|
|
case self::FIELD_BODY:
|
2011-03-25 05:32:26 +01:00
|
|
|
return $this->revision->getSummary()."\n".
|
|
|
|
$this->revision->getTestPlan();
|
|
|
|
break;
|
2013-08-02 19:54:19 +02:00
|
|
|
case self::FIELD_AUTHOR:
|
2011-03-25 05:32:26 +01:00
|
|
|
return $this->revision->getAuthorPHID();
|
|
|
|
break;
|
2013-08-02 19:54:19 +02:00
|
|
|
case self::FIELD_DIFF_FILE:
|
2011-04-06 05:49:31 +02:00
|
|
|
return $this->loadAffectedPaths();
|
2013-08-02 19:54:19 +02:00
|
|
|
case self::FIELD_CC:
|
2011-03-25 05:32:26 +01:00
|
|
|
if (isset($this->explicitCCs)) {
|
|
|
|
return array_keys($this->explicitCCs);
|
|
|
|
} else {
|
|
|
|
return $this->revision->getCCPHIDs();
|
|
|
|
}
|
2013-08-02 19:54:19 +02:00
|
|
|
case self::FIELD_REVIEWERS:
|
2011-03-25 05:32:26 +01:00
|
|
|
if (isset($this->explicitReviewers)) {
|
|
|
|
return array_keys($this->explicitReviewers);
|
|
|
|
} else {
|
|
|
|
return $this->revision->getReviewers();
|
|
|
|
}
|
2013-08-02 19:54:19 +02:00
|
|
|
case self::FIELD_REPOSITORY:
|
2011-04-06 05:49:31 +02:00
|
|
|
$repository = $this->loadRepository();
|
2011-03-25 05:32:26 +01:00
|
|
|
if (!$repository) {
|
|
|
|
return null;
|
|
|
|
}
|
2011-04-06 05:49:31 +02:00
|
|
|
return $repository->getPHID();
|
2013-08-02 19:54:19 +02:00
|
|
|
case self::FIELD_DIFF_CONTENT:
|
2011-04-06 05:49:31 +02:00
|
|
|
return $this->loadContentDictionary();
|
2013-08-02 19:54:19 +02:00
|
|
|
case self::FIELD_AFFECTED_PACKAGE:
|
2011-04-06 05:49:31 +02:00
|
|
|
$packages = $this->loadAffectedPackages();
|
|
|
|
return mpull($packages, 'getPHID');
|
2013-08-02 19:54:19 +02:00
|
|
|
case self::FIELD_AFFECTED_PACKAGE_OWNER:
|
2011-04-06 05:49:31 +02:00
|
|
|
$packages = $this->loadAffectedPackages();
|
2012-03-31 00:46:32 +02:00
|
|
|
return PhabricatorOwnersOwner::loadAffiliatedUserPHIDs(
|
|
|
|
mpull($packages, 'getID'));
|
2011-03-25 05:32:26 +01:00
|
|
|
}
|
2013-08-05 19:02:40 +02:00
|
|
|
|
|
|
|
return parent::getHeraldField($field);
|
2013-08-02 20:32:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public function getActions($rule_type) {
|
|
|
|
switch ($rule_type) {
|
|
|
|
case HeraldRuleTypeConfig::RULE_TYPE_GLOBAL:
|
|
|
|
return array(
|
|
|
|
self::ACTION_ADD_CC,
|
|
|
|
self::ACTION_REMOVE_CC,
|
|
|
|
self::ACTION_EMAIL,
|
|
|
|
self::ACTION_NOTHING,
|
|
|
|
);
|
|
|
|
case HeraldRuleTypeConfig::RULE_TYPE_PERSONAL:
|
|
|
|
return array(
|
|
|
|
self::ACTION_ADD_CC,
|
|
|
|
self::ACTION_REMOVE_CC,
|
|
|
|
self::ACTION_EMAIL,
|
2013-08-06 20:32:13 +02:00
|
|
|
self::ACTION_FLAG,
|
2013-08-02 20:32:50 +02:00
|
|
|
self::ACTION_NOTHING,
|
|
|
|
);
|
|
|
|
}
|
2011-03-25 05:32:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public function applyHeraldEffects(array $effects) {
|
2012-03-30 22:51:54 +02:00
|
|
|
assert_instances_of($effects, 'HeraldEffect');
|
|
|
|
|
2011-03-25 05:32:26 +01:00
|
|
|
$result = array();
|
|
|
|
if ($this->explicitCCs) {
|
|
|
|
$effect = new HeraldEffect();
|
2013-08-06 20:23:01 +02:00
|
|
|
$effect->setAction(self::ACTION_ADD_CC);
|
2011-03-25 05:32:26 +01:00
|
|
|
$effect->setTarget(array_keys($this->explicitCCs));
|
|
|
|
$effect->setReason(
|
2013-05-20 17:24:07 +02:00
|
|
|
pht('CCs provided explicitly by revision author or carried over '.
|
|
|
|
'from a previous version of the revision.'));
|
2011-03-25 05:32:26 +01:00
|
|
|
$result[] = new HeraldApplyTranscript(
|
|
|
|
$effect,
|
|
|
|
true,
|
2013-05-20 17:24:07 +02:00
|
|
|
pht('Added addresses to CC list.'));
|
2011-03-25 05:32:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
$forbidden_ccs = array_fill_keys(
|
|
|
|
nonempty($this->forbiddenCCs, array()),
|
|
|
|
true);
|
|
|
|
|
|
|
|
foreach ($effects as $effect) {
|
|
|
|
$action = $effect->getAction();
|
|
|
|
switch ($action) {
|
2013-08-06 20:23:01 +02:00
|
|
|
case self::ACTION_NOTHING:
|
2011-03-25 05:32:26 +01:00
|
|
|
$result[] = new HeraldApplyTranscript(
|
|
|
|
$effect,
|
|
|
|
true,
|
2013-05-20 17:24:07 +02:00
|
|
|
pht('OK, did nothing.'));
|
2011-03-25 05:32:26 +01:00
|
|
|
break;
|
2013-08-06 20:23:01 +02:00
|
|
|
case self::ACTION_FLAG:
|
2012-03-30 22:51:54 +02:00
|
|
|
$result[] = parent::applyFlagEffect(
|
|
|
|
$effect,
|
|
|
|
$this->revision->getPHID());
|
|
|
|
break;
|
2013-08-06 20:23:01 +02:00
|
|
|
case self::ACTION_EMAIL:
|
|
|
|
case self::ACTION_ADD_CC:
|
|
|
|
$op = ($action == self::ACTION_EMAIL) ? 'email' : 'CC';
|
2011-03-25 05:32:26 +01:00
|
|
|
$base_target = $effect->getTarget();
|
|
|
|
$forbidden = array();
|
|
|
|
foreach ($base_target as $key => $fbid) {
|
|
|
|
if (isset($forbidden_ccs[$fbid])) {
|
|
|
|
$forbidden[] = $fbid;
|
|
|
|
unset($base_target[$key]);
|
|
|
|
} else {
|
2013-08-06 20:23:01 +02:00
|
|
|
if ($action == self::ACTION_EMAIL) {
|
2011-05-28 00:52:26 +02:00
|
|
|
$this->emailPHIDs[$fbid] = true;
|
|
|
|
} else {
|
|
|
|
$this->newCCs[$fbid] = true;
|
|
|
|
}
|
2011-03-25 05:32:26 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($forbidden) {
|
|
|
|
$failed = clone $effect;
|
|
|
|
$failed->setTarget($forbidden);
|
|
|
|
if ($base_target) {
|
|
|
|
$effect->setTarget($base_target);
|
|
|
|
$result[] = new HeraldApplyTranscript(
|
|
|
|
$effect,
|
|
|
|
true,
|
2013-05-20 17:24:07 +02:00
|
|
|
pht('Added these addresses to %s list. '.
|
|
|
|
'Others could not be added.', $op));
|
2011-03-25 05:32:26 +01:00
|
|
|
}
|
|
|
|
$result[] = new HeraldApplyTranscript(
|
|
|
|
$failed,
|
|
|
|
false,
|
2013-05-20 17:24:07 +02:00
|
|
|
pht('%s forbidden, these addresses have unsubscribed.', $op));
|
2011-03-25 05:32:26 +01:00
|
|
|
} else {
|
|
|
|
$result[] = new HeraldApplyTranscript(
|
|
|
|
$effect,
|
|
|
|
true,
|
2013-05-20 17:24:07 +02:00
|
|
|
pht('Added addresses to %s list.', $op));
|
2011-03-25 05:32:26 +01:00
|
|
|
}
|
|
|
|
break;
|
2013-08-06 20:23:01 +02:00
|
|
|
case self::ACTION_REMOVE_CC:
|
2011-03-25 05:32:26 +01:00
|
|
|
foreach ($effect->getTarget() as $fbid) {
|
|
|
|
$this->remCCs[$fbid] = true;
|
|
|
|
}
|
|
|
|
$result[] = new HeraldApplyTranscript(
|
|
|
|
$effect,
|
|
|
|
true,
|
2013-05-20 17:24:07 +02:00
|
|
|
pht('Removed addresses from CC list.'));
|
2011-03-25 05:32:26 +01:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
throw new Exception("No rules to handle action '{$action}'.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return $result;
|
|
|
|
}
|
|
|
|
}
|