1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-09-20 01:08:50 +02:00

Modularize "add projects" and "remove projects" Herald actions

Summary: Ref T8726. Convert these to be modular.

Test Plan:
  - Created rules using these actions.
  - Upgraded them.
  - Verified they still work.

{F659266}

Reviewers: btrahan

Reviewed By: btrahan

Subscribers: joshuaspence, epriestley

Maniphest Tasks: T8726

Differential Revision: https://secure.phabricator.com/D13705
This commit is contained in:
epriestley 2015-07-24 10:56:52 -07:00
parent 51fead17cf
commit 3782992670
7 changed files with 273 additions and 58 deletions

View file

@ -0,0 +1,11 @@
UPDATE {$NAMESPACE}_herald.herald_actionrecord a
JOIN {$NAMESPACE}_herald.herald_rule r
ON a.ruleID = r.id
SET a.action = 'projects.add'
WHERE a.action = 'addprojects';
UPDATE {$NAMESPACE}_herald.herald_actionrecord a
JOIN {$NAMESPACE}_herald.herald_rule r
ON a.ruleID = r.id
SET a.action = 'projects.remove'
WHERE a.action = 'removeprojects';

View file

@ -2540,6 +2540,7 @@ phutil_register_library_map(array(
'PhabricatorPolicyType' => 'applications/policy/constants/PhabricatorPolicyType.php', 'PhabricatorPolicyType' => 'applications/policy/constants/PhabricatorPolicyType.php',
'PhabricatorPonderApplication' => 'applications/ponder/application/PhabricatorPonderApplication.php', 'PhabricatorPonderApplication' => 'applications/ponder/application/PhabricatorPonderApplication.php',
'PhabricatorProject' => 'applications/project/storage/PhabricatorProject.php', 'PhabricatorProject' => 'applications/project/storage/PhabricatorProject.php',
'PhabricatorProjectAddHeraldAction' => 'applications/project/herald/PhabricatorProjectAddHeraldAction.php',
'PhabricatorProjectApplication' => 'applications/project/application/PhabricatorProjectApplication.php', 'PhabricatorProjectApplication' => 'applications/project/application/PhabricatorProjectApplication.php',
'PhabricatorProjectArchiveController' => 'applications/project/controller/PhabricatorProjectArchiveController.php', 'PhabricatorProjectArchiveController' => 'applications/project/controller/PhabricatorProjectArchiveController.php',
'PhabricatorProjectBoardController' => 'applications/project/controller/PhabricatorProjectBoardController.php', 'PhabricatorProjectBoardController' => 'applications/project/controller/PhabricatorProjectBoardController.php',
@ -2572,6 +2573,7 @@ phutil_register_library_map(array(
'PhabricatorProjectEditPictureController' => 'applications/project/controller/PhabricatorProjectEditPictureController.php', 'PhabricatorProjectEditPictureController' => 'applications/project/controller/PhabricatorProjectEditPictureController.php',
'PhabricatorProjectEditorTestCase' => 'applications/project/editor/__tests__/PhabricatorProjectEditorTestCase.php', 'PhabricatorProjectEditorTestCase' => 'applications/project/editor/__tests__/PhabricatorProjectEditorTestCase.php',
'PhabricatorProjectFeedController' => 'applications/project/controller/PhabricatorProjectFeedController.php', 'PhabricatorProjectFeedController' => 'applications/project/controller/PhabricatorProjectFeedController.php',
'PhabricatorProjectHeraldAction' => 'applications/project/herald/PhabricatorProjectHeraldAction.php',
'PhabricatorProjectIcon' => 'applications/project/icon/PhabricatorProjectIcon.php', 'PhabricatorProjectIcon' => 'applications/project/icon/PhabricatorProjectIcon.php',
'PhabricatorProjectInterface' => 'applications/project/interface/PhabricatorProjectInterface.php', 'PhabricatorProjectInterface' => 'applications/project/interface/PhabricatorProjectInterface.php',
'PhabricatorProjectListController' => 'applications/project/controller/PhabricatorProjectListController.php', 'PhabricatorProjectListController' => 'applications/project/controller/PhabricatorProjectListController.php',
@ -2593,6 +2595,7 @@ phutil_register_library_map(array(
'PhabricatorProjectProjectHasObjectEdgeType' => 'applications/project/edge/PhabricatorProjectProjectHasObjectEdgeType.php', 'PhabricatorProjectProjectHasObjectEdgeType' => 'applications/project/edge/PhabricatorProjectProjectHasObjectEdgeType.php',
'PhabricatorProjectProjectPHIDType' => 'applications/project/phid/PhabricatorProjectProjectPHIDType.php', 'PhabricatorProjectProjectPHIDType' => 'applications/project/phid/PhabricatorProjectProjectPHIDType.php',
'PhabricatorProjectQuery' => 'applications/project/query/PhabricatorProjectQuery.php', 'PhabricatorProjectQuery' => 'applications/project/query/PhabricatorProjectQuery.php',
'PhabricatorProjectRemoveHeraldAction' => 'applications/project/herald/PhabricatorProjectRemoveHeraldAction.php',
'PhabricatorProjectSchemaSpec' => 'applications/project/storage/PhabricatorProjectSchemaSpec.php', 'PhabricatorProjectSchemaSpec' => 'applications/project/storage/PhabricatorProjectSchemaSpec.php',
'PhabricatorProjectSearchEngine' => 'applications/project/query/PhabricatorProjectSearchEngine.php', 'PhabricatorProjectSearchEngine' => 'applications/project/query/PhabricatorProjectSearchEngine.php',
'PhabricatorProjectSearchField' => 'applications/project/searchfield/PhabricatorProjectSearchField.php', 'PhabricatorProjectSearchField' => 'applications/project/searchfield/PhabricatorProjectSearchField.php',
@ -6496,6 +6499,7 @@ phutil_register_library_map(array(
'PhabricatorCustomFieldInterface', 'PhabricatorCustomFieldInterface',
'PhabricatorDestructibleInterface', 'PhabricatorDestructibleInterface',
), ),
'PhabricatorProjectAddHeraldAction' => 'PhabricatorProjectHeraldAction',
'PhabricatorProjectApplication' => 'PhabricatorApplication', 'PhabricatorProjectApplication' => 'PhabricatorApplication',
'PhabricatorProjectArchiveController' => 'PhabricatorProjectController', 'PhabricatorProjectArchiveController' => 'PhabricatorProjectController',
'PhabricatorProjectBoardController' => 'PhabricatorProjectController', 'PhabricatorProjectBoardController' => 'PhabricatorProjectController',
@ -6539,6 +6543,7 @@ phutil_register_library_map(array(
'PhabricatorProjectEditPictureController' => 'PhabricatorProjectController', 'PhabricatorProjectEditPictureController' => 'PhabricatorProjectController',
'PhabricatorProjectEditorTestCase' => 'PhabricatorTestCase', 'PhabricatorProjectEditorTestCase' => 'PhabricatorTestCase',
'PhabricatorProjectFeedController' => 'PhabricatorProjectController', 'PhabricatorProjectFeedController' => 'PhabricatorProjectController',
'PhabricatorProjectHeraldAction' => 'HeraldAction',
'PhabricatorProjectIcon' => 'Phobject', 'PhabricatorProjectIcon' => 'Phobject',
'PhabricatorProjectListController' => 'PhabricatorProjectController', 'PhabricatorProjectListController' => 'PhabricatorProjectController',
'PhabricatorProjectLogicalAndDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 'PhabricatorProjectLogicalAndDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
@ -6559,6 +6564,7 @@ phutil_register_library_map(array(
'PhabricatorProjectProjectHasObjectEdgeType' => 'PhabricatorEdgeType', 'PhabricatorProjectProjectHasObjectEdgeType' => 'PhabricatorEdgeType',
'PhabricatorProjectProjectPHIDType' => 'PhabricatorPHIDType', 'PhabricatorProjectProjectPHIDType' => 'PhabricatorPHIDType',
'PhabricatorProjectQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorProjectQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorProjectRemoveHeraldAction' => 'PhabricatorProjectHeraldAction',
'PhabricatorProjectSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'PhabricatorProjectSchemaSpec' => 'PhabricatorConfigSchemaSpec',
'PhabricatorProjectSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorProjectSearchEngine' => 'PhabricatorApplicationSearchEngine',
'PhabricatorProjectSearchField' => 'PhabricatorSearchTokenizerField', 'PhabricatorProjectSearchField' => 'PhabricatorSearchTokenizerField',

View file

@ -28,8 +28,6 @@ abstract class HeraldAdapter extends Phobject {
const ACTION_AUDIT = 'audit'; const ACTION_AUDIT = 'audit';
const ACTION_ASSIGN_TASK = 'assigntask'; const ACTION_ASSIGN_TASK = 'assigntask';
const ACTION_ADD_PROJECTS = 'addprojects';
const ACTION_REMOVE_PROJECTS = 'removeprojects';
const ACTION_ADD_REVIEWERS = 'addreviewers'; const ACTION_ADD_REVIEWERS = 'addreviewers';
const ACTION_ADD_BLOCKING_REVIEWERS = 'addblockingreviewers'; const ACTION_ADD_BLOCKING_REVIEWERS = 'addblockingreviewers';
const ACTION_APPLY_BUILD_PLANS = 'applybuildplans'; const ACTION_APPLY_BUILD_PLANS = 'applybuildplans';
@ -707,15 +705,6 @@ abstract class HeraldAdapter extends Phobject {
$actions = $custom_actions; $actions = $custom_actions;
$object = $this->newObject();
if (($object instanceof PhabricatorProjectInterface)) {
if ($rule_type == HeraldRuleTypeConfig::RULE_TYPE_GLOBAL) {
$actions[] = self::ACTION_ADD_PROJECTS;
$actions[] = self::ACTION_REMOVE_PROJECTS;
}
}
foreach ($this->getActionsForRuleType($rule_type) as $key => $action) { foreach ($this->getActionsForRuleType($rule_type) as $key => $action) {
$actions[] = $key; $actions[] = $key;
} }
@ -730,8 +719,6 @@ abstract class HeraldAdapter extends Phobject {
$standard = array( $standard = array(
self::ACTION_AUDIT => pht('Trigger an Audit by'), self::ACTION_AUDIT => pht('Trigger an Audit by'),
self::ACTION_ASSIGN_TASK => pht('Assign task to'), self::ACTION_ASSIGN_TASK => pht('Assign task to'),
self::ACTION_ADD_PROJECTS => pht('Add projects'),
self::ACTION_REMOVE_PROJECTS => pht('Remove projects'),
self::ACTION_ADD_REVIEWERS => pht('Add reviewers'), self::ACTION_ADD_REVIEWERS => pht('Add reviewers'),
self::ACTION_ADD_BLOCKING_REVIEWERS => pht('Add blocking reviewers'), self::ACTION_ADD_BLOCKING_REVIEWERS => pht('Add blocking reviewers'),
self::ACTION_APPLY_BUILD_PLANS => pht('Run build plans'), self::ACTION_APPLY_BUILD_PLANS => pht('Run build plans'),
@ -829,17 +816,9 @@ abstract class HeraldAdapter extends Phobject {
case self::ACTION_ADD_REVIEWERS: case self::ACTION_ADD_REVIEWERS:
case self::ACTION_ADD_BLOCKING_REVIEWERS: case self::ACTION_ADD_BLOCKING_REVIEWERS:
return new HeraldEmptyFieldValue(); return new HeraldEmptyFieldValue();
case self::ACTION_ADD_PROJECTS:
case self::ACTION_REMOVE_PROJECTS:
return $this->buildTokenizerFieldValue(
new PhabricatorProjectDatasource());
} }
} else { } else {
switch ($action) { switch ($action) {
case self::ACTION_ADD_PROJECTS:
case self::ACTION_REMOVE_PROJECTS:
return $this->buildTokenizerFieldValue(
new PhabricatorProjectDatasource());
case self::ACTION_ASSIGN_TASK: case self::ACTION_ASSIGN_TASK:
return $this->buildTokenizerFieldValue( return $this->buildTokenizerFieldValue(
new PhabricatorPeopleDatasource()); new PhabricatorPeopleDatasource());
@ -1200,14 +1179,6 @@ abstract class HeraldAdapter extends Phobject {
$rule_type)); $rule_type));
} }
switch ($action) {
case self::ACTION_ADD_PROJECTS:
case self::ACTION_REMOVE_PROJECTS:
return $this->applyProjectsEffect($effect);
default:
break;
}
$result = $this->handleCustomHeraldEffect($effect); $result = $this->handleCustomHeraldEffect($effect);
if (!$result) { if (!$result) {
@ -1222,35 +1193,6 @@ abstract class HeraldAdapter extends Phobject {
return $result; return $result;
} }
/**
* @task apply
*/
private function applyProjectsEffect(HeraldEffect $effect) {
if ($effect->getAction() == self::ACTION_ADD_PROJECTS) {
$kind = '+';
} else {
$kind = '-';
}
$project_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST;
$project_phids = $effect->getTarget();
$xaction = $this->newTransaction()
->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
->setMetadataValue('edge:type', $project_type)
->setNewValue(
array(
$kind => array_fuse($project_phids),
));
$this->queueTransaction($xaction);
return new HeraldApplyTranscript(
$effect,
true,
pht('Added projects.'));
}
public function loadEdgePHIDs($type) { public function loadEdgePHIDs($type) {
if (!isset($this->edgeCache[$type])) { if (!isset($this->edgeCache[$type])) {
$phids = PhabricatorEdgeQuery::loadDestinationPHIDs( $phids = PhabricatorEdgeQuery::loadDestinationPHIDs(

View file

@ -0,0 +1,28 @@
<?php
final class PhabricatorProjectAddHeraldAction
extends PhabricatorProjectHeraldAction {
const ACTIONCONST = 'projects.add';
public function getHeraldActionName() {
return pht('Add projects');
}
public function applyEffect($object, HeraldEffect $effect) {
return $this->applyProjects($effect->getTarget(), $is_add = true);
}
public function getHeraldActionStandardType() {
return self::STANDARD_PHID_LIST;
}
protected function getDatasource() {
return new PhabricatorProjectDatasource();
}
public function renderActionDescription($value) {
return pht('Add projects: %s.', $this->renderHandleList($value));
}
}

View file

@ -0,0 +1,180 @@
<?php
abstract class PhabricatorProjectHeraldAction
extends HeraldAction {
const DO_NO_TARGETS = 'do.no-targets';
const DO_INVALID = 'do.invalid';
const DO_ALREADY_ASSOCIATED = 'do.already-associated';
const DO_ALREADY_UNASSOCIATED = 'do.already-unassociated';
const DO_ADD_PROJECTS = 'do.add-projects';
const DO_REMOVE_PROJECTS = 'do.remove-projects';
public function getActionGroupKey() {
return HeraldSupportActionGroup::ACTIONGROUPKEY;
}
public function supportsObject($object) {
return ($object instanceof PhabricatorProjectInterface);
}
public function supportsRuleType($rule_type) {
return ($rule_type == HeraldRuleTypeConfig::RULE_TYPE_GLOBAL);
}
protected function applyProjects(array $phids, $is_add) {
$phids = array_fuse($phids);
$adapter = $this->getAdapter();
if (!$phids) {
$this->logEffect(self::DO_NO_TARGETS);
return;
}
$projects = id(new PhabricatorProjectQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withPHIDs($phids)
->execute();
$projects = mpull($projects, null, 'getPHID');
$invalid = array();
foreach ($phids as $phid) {
if (empty($projects[$phid])) {
$invalid[] = $phid;
unset($phids[$phid]);
}
}
if ($invalid) {
$this->logEffect(self::DO_INVALID, $invalid);
}
if (!$phids) {
return;
}
$project_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST;
$current = $adapter->loadEdgePHIDs($project_type);
if ($is_add) {
$already = array();
foreach ($phids as $phid) {
if (isset($current[$phid])) {
$already[$phid] = $phid;
unset($phids[$phid]);
}
}
if ($already) {
$this->logEffect(self::DO_ALREADY_ASSOCIATED, $already);
}
} else {
$already = array();
foreach ($phids as $phid) {
if (empty($current[$phid])) {
$already[$phid] = $phid;
unset($phids[$phid]);
}
}
if ($already) {
$this->logEffect(self::DO_ALREADY_UNASSOCIATED, $already);
}
}
if (!$phids) {
return;
}
if ($is_add) {
$kind = '+';
} else {
$kind = '-';
}
$xaction = $adapter->newTransaction()
->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
->setMetadataValue('edge:type', $project_type)
->setNewValue(
array(
$kind => $phids,
));
$adapter->queueTransaction($xaction);
if ($is_add) {
$this->logEffect(self::DO_ADD_PROJECTS, $phids);
} else {
$this->logEffect(self::DO_REMOVE_PROJECTS, $phids);
}
}
protected function getActionEffectMap() {
return array(
self::DO_NO_TARGETS => array(
'icon' => 'fa-ban',
'color' => 'grey',
'name' => pht('No Targets'),
),
self::DO_INVALID => array(
'icon' => 'fa-ban',
'color' => 'red',
'name' => pht('Invalid Targets'),
),
self::DO_ALREADY_ASSOCIATED => array(
'icon' => 'fa-chevron-right',
'color' => 'grey',
'name' => pht('Already Associated'),
),
self::DO_ALREADY_UNASSOCIATED => array(
'icon' => 'fa-chevron-right',
'color' => 'grey',
'name' => pht('Already Unassociated'),
),
self::DO_ADD_PROJECTS => array(
'icon' => 'fa-briefcase',
'color' => 'green',
'name' => pht('Added Projects'),
),
self::DO_REMOVE_PROJECTS => array(
'icon' => 'fa-minus-circle',
'color' => 'green',
'name' => pht('Removed Projects'),
),
);
}
public function renderActionEffectDescription($type, $data) {
switch ($type) {
case self::DO_NO_TARGETS:
return pht('Rule lists no projects.');
case self::DO_INVALID:
return pht(
'Declined to act on %s invalid project(s): %s.',
new PhutilNumber(count($data)),
$this->renderHandleList($data));
case self::DO_ALREADY_ASSOCIATED:
return pht(
'%s project(s) are already associated: %s.',
new PhutilNumber(count($data)),
$this->renderHandleList($data));
case self::DO_ALREADY_UNASSOCIATED:
return pht(
'%s project(s) are not associated: %s.',
new PhutilNumber(count($data)),
$this->renderHandleList($data));
case self::DO_ADD_PROJECTS:
return pht(
'Added %s project(s): %s.',
new PhutilNumber(count($data)),
$this->renderHandleList($data));
case self::DO_REMOVE_PROJECTS:
return pht(
'Removed %s project(s): %s.',
new PhutilNumber(count($data)),
$this->renderHandleList($data));
}
}
}

View file

@ -0,0 +1,28 @@
<?php
final class PhabricatorProjectRemoveHeraldAction
extends PhabricatorProjectHeraldAction {
const ACTIONCONST = 'projects.remove';
public function getHeraldActionName() {
return pht('Remove projects');
}
public function applyEffect($object, HeraldEffect $effect) {
return $this->applyProjects($effect->getTarget(), $is_add = false);
}
public function getHeraldActionStandardType() {
return self::STANDARD_PHID_LIST;
}
protected function getDatasource() {
return new PhabricatorProjectDatasource();
}
public function renderActionDescription($value) {
return pht('Remove projects: %s.', $this->renderHandleList($value));
}
}

View file

@ -1303,6 +1303,26 @@ final class PhabricatorUSEnglishTranslation
'preferences: %2$s.', 'preferences: %2$s.',
), ),
'%s project(s) are not associated: %s.' => array(
'A project is not associated: %2$s.',
'Projects are not associated: %2$s.',
),
'%s project(s) are already associated: %s.' => array(
'A project is already associated: %2$s.',
'Projects are already associated: %2$s.',
),
'Added %s project(s): %s.' => array(
'Added a project: %2$s.',
'Added projects: %2$s.',
),
'Removed %s project(s): %s.' => array(
'Removed a project: %2$s.',
'Removed projects: %2$s.',
),
); );
} }