2011-03-25 05:32:26 +01:00
|
|
|
<?php
|
|
|
|
|
|
|
|
/*
|
2012-03-14 00:21:04 +01:00
|
|
|
* Copyright 2012 Facebook, Inc.
|
2011-03-25 05:32:26 +01:00
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
2012-03-14 00:21:04 +01:00
|
|
|
final class HeraldDifferentialRevisionAdapter extends HeraldObjectAdapter {
|
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;
|
|
|
|
|
|
|
|
public function __construct(
|
|
|
|
DifferentialRevision $revision,
|
|
|
|
DifferentialDiff $diff) {
|
|
|
|
|
2011-03-25 05:32:26 +01:00
|
|
|
$revision->loadRelationships();
|
|
|
|
$this->revision = $revision;
|
|
|
|
$this->diff = $diff;
|
|
|
|
}
|
|
|
|
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getHeraldTypeName() {
|
|
|
|
return HeraldContentTypeConfig::CONTENT_TYPE_DIFFERENTIAL;
|
|
|
|
}
|
|
|
|
|
2011-04-06 05:49:31 +02:00
|
|
|
public function loadRepository() {
|
|
|
|
if ($this->repository === null) {
|
|
|
|
$diff = $this->diff;
|
|
|
|
|
|
|
|
$repository = false;
|
|
|
|
|
|
|
|
if ($diff->getRepositoryUUID()) {
|
|
|
|
$repository = id(new PhabricatorRepository())->loadOneWhere(
|
|
|
|
'uuid = %s',
|
|
|
|
$diff->getRepositoryUUID());
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!$repository && $diff->getArcanistProjectPHID()) {
|
|
|
|
$project = id(new PhabricatorRepositoryArcanistProject())->loadOneWhere(
|
|
|
|
'phid = %s',
|
|
|
|
$diff->getArcanistProjectPHID());
|
|
|
|
if ($project && $project->getRepositoryID()) {
|
|
|
|
$repository = id(new PhabricatorRepository())->load(
|
|
|
|
$project->getRepositoryID());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->repository = $repository;
|
|
|
|
}
|
|
|
|
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;
|
|
|
|
|
|
|
|
return $changeset->getAbsoluteRepositoryPath($diff, $repository);
|
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) {
|
|
|
|
case HeraldFieldConfig::FIELD_TITLE:
|
|
|
|
return $this->revision->getTitle();
|
|
|
|
break;
|
|
|
|
case HeraldFieldConfig::FIELD_BODY:
|
|
|
|
return $this->revision->getSummary()."\n".
|
|
|
|
$this->revision->getTestPlan();
|
|
|
|
break;
|
|
|
|
case HeraldFieldConfig::FIELD_AUTHOR:
|
|
|
|
return $this->revision->getAuthorPHID();
|
|
|
|
break;
|
|
|
|
case HeraldFieldConfig::FIELD_DIFF_FILE:
|
2011-04-06 05:49:31 +02:00
|
|
|
return $this->loadAffectedPaths();
|
2011-03-25 05:32:26 +01:00
|
|
|
case HeraldFieldConfig::FIELD_CC:
|
|
|
|
if (isset($this->explicitCCs)) {
|
|
|
|
return array_keys($this->explicitCCs);
|
|
|
|
} else {
|
|
|
|
return $this->revision->getCCPHIDs();
|
|
|
|
}
|
|
|
|
case HeraldFieldConfig::FIELD_REVIEWERS:
|
|
|
|
if (isset($this->explicitReviewers)) {
|
|
|
|
return array_keys($this->explicitReviewers);
|
|
|
|
} else {
|
|
|
|
return $this->revision->getReviewers();
|
|
|
|
}
|
|
|
|
case HeraldFieldConfig::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();
|
2011-03-25 05:32:26 +01:00
|
|
|
case HeraldFieldConfig::FIELD_DIFF_CONTENT:
|
2011-04-06 05:49:31 +02:00
|
|
|
return $this->loadContentDictionary();
|
2011-03-25 05:32:26 +01:00
|
|
|
case HeraldFieldConfig::FIELD_AFFECTED_PACKAGE:
|
2011-04-06 05:49:31 +02:00
|
|
|
$packages = $this->loadAffectedPackages();
|
|
|
|
return mpull($packages, 'getPHID');
|
2011-03-25 05:32:26 +01:00
|
|
|
case HeraldFieldConfig::FIELD_AFFECTED_PACKAGE_OWNER:
|
2011-04-06 05:49:31 +02:00
|
|
|
$packages = $this->loadAffectedPackages();
|
|
|
|
$owners = PhabricatorOwnersOwner::loadAllForPackages($packages);
|
|
|
|
return mpull($owners, 'getUserPHID');
|
2011-03-25 05:32:26 +01:00
|
|
|
default:
|
|
|
|
throw new Exception("Invalid field '{$field}'.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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();
|
|
|
|
$effect->setAction(HeraldActionConfig::ACTION_ADD_CC);
|
|
|
|
$effect->setTarget(array_keys($this->explicitCCs));
|
|
|
|
$effect->setReason(
|
|
|
|
'CCs provided explicitly by revision author or carried over from a '.
|
|
|
|
'previous version of the revision.');
|
|
|
|
$result[] = new HeraldApplyTranscript(
|
|
|
|
$effect,
|
|
|
|
true,
|
|
|
|
'Added addresses to CC list.');
|
|
|
|
}
|
|
|
|
|
|
|
|
$forbidden_ccs = array_fill_keys(
|
|
|
|
nonempty($this->forbiddenCCs, array()),
|
|
|
|
true);
|
|
|
|
|
|
|
|
foreach ($effects as $effect) {
|
|
|
|
$action = $effect->getAction();
|
|
|
|
switch ($action) {
|
|
|
|
case HeraldActionConfig::ACTION_NOTHING:
|
|
|
|
$result[] = new HeraldApplyTranscript(
|
|
|
|
$effect,
|
|
|
|
true,
|
|
|
|
'OK, did nothing.');
|
|
|
|
break;
|
2012-03-30 22:51:54 +02:00
|
|
|
case HeraldActionConfig::ACTION_FLAG:
|
|
|
|
$result[] = parent::applyFlagEffect(
|
|
|
|
$effect,
|
|
|
|
$this->revision->getPHID());
|
|
|
|
break;
|
2011-05-28 00:52:26 +02:00
|
|
|
case HeraldActionConfig::ACTION_EMAIL:
|
2011-03-25 05:32:26 +01:00
|
|
|
case HeraldActionConfig::ACTION_ADD_CC:
|
2011-05-28 00:52:26 +02:00
|
|
|
$op = ($action == HeraldActionConfig::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 {
|
2011-05-28 00:52:26 +02:00
|
|
|
if ($action == HeraldActionConfig::ACTION_EMAIL) {
|
|
|
|
$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,
|
2011-05-28 00:52:26 +02:00
|
|
|
'Added these addresses to '.$op.' list. '.
|
|
|
|
'Others could not be added.');
|
2011-03-25 05:32:26 +01:00
|
|
|
}
|
|
|
|
$result[] = new HeraldApplyTranscript(
|
|
|
|
$failed,
|
|
|
|
false,
|
2011-05-28 00:52:26 +02:00
|
|
|
$op.' forbidden, these addresses have unsubscribed.');
|
2011-03-25 05:32:26 +01:00
|
|
|
} else {
|
|
|
|
$result[] = new HeraldApplyTranscript(
|
|
|
|
$effect,
|
|
|
|
true,
|
2011-05-28 00:52:26 +02:00
|
|
|
'Added addresses to '.$op.' list.');
|
2011-03-25 05:32:26 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case HeraldActionConfig::ACTION_REMOVE_CC:
|
|
|
|
foreach ($effect->getTarget() as $fbid) {
|
|
|
|
$this->remCCs[$fbid] = true;
|
|
|
|
}
|
|
|
|
$result[] = new HeraldApplyTranscript(
|
|
|
|
$effect,
|
|
|
|
true,
|
|
|
|
'Removed addresses from CC list.');
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
throw new Exception("No rules to handle action '{$action}'.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return $result;
|
|
|
|
}
|
|
|
|
}
|