diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -778,6 +778,7 @@ 'HeraldCondition' => 'applications/herald/storage/HeraldCondition.php', 'HeraldConditionTranscript' => 'applications/herald/storage/transcript/HeraldConditionTranscript.php', 'HeraldController' => 'applications/herald/controller/HeraldController.php', + 'HeraldCustomAction' => 'applications/herald/extension/HeraldCustomAction.php', 'HeraldDAO' => 'applications/herald/storage/HeraldDAO.php', 'HeraldDifferentialRevisionAdapter' => 'applications/herald/adapter/HeraldDifferentialRevisionAdapter.php', 'HeraldDisableController' => 'applications/herald/controller/HeraldDisableController.php', diff --git a/src/applications/herald/adapter/HeraldAdapter.php b/src/applications/herald/adapter/HeraldAdapter.php --- a/src/applications/herald/adapter/HeraldAdapter.php +++ b/src/applications/herald/adapter/HeraldAdapter.php @@ -100,6 +100,22 @@ private $isNewObject; private $customFields = false; + private static $customActions = null; + + public function __construct() { + if (self::$customActions === null) { + $symbols = id(new PhutilSymbolLoader()) + ->setAncestorClass('HeraldCustomAction') + ->selectAndLoadSymbols(); + + self::$customActions = array(); + foreach ($symbols as $symbol) { + $name = $symbol['name']; + self::$customActions[] = new $name(); + } + } + } + public function setContentSource(PhabricatorContentSource $content_source) { $this->contentSource = $content_source; return $this; @@ -143,7 +159,21 @@ } } - abstract public function applyHeraldEffects(array $effects); + public abstract function applyHeraldEffects(array $effects); + + protected function handleCustomHeraldEffect(HeraldEffect $effect) { + foreach (self::$customActions as $customAction) { + $result = $customAction->applyEffect( + $this->getObjectForCustomActions(), + $effect); + + if ($result !== null) { + return $result; + } + } + + return null; + } public function isAvailableToUser(PhabricatorUser $viewer) { $applications = id(new PhabricatorApplicationQuery()) @@ -196,6 +226,10 @@ return 1000; } + protected function getObjectForCustomActions() { + return null; + } + /* -( Fields )------------------------------------------------------------- */ @@ -643,13 +677,23 @@ /* -( Actions )------------------------------------------------------------ */ - abstract public function getActions($rule_type); + public function getActions($rule_type) { + $arrays = array(); + foreach (self::$customActions as $customAction) { + $result = array(); + foreach ($customAction->getActions($this, $rule_type) as $key => $action) { + $result[] = 'custom:'.$key; + } + $arrays = array_merge($arrays, $result); + } + return $arrays; + } public function getActionNameMap($rule_type) { switch ($rule_type) { case HeraldRuleTypeConfig::RULE_TYPE_GLOBAL: case HeraldRuleTypeConfig::RULE_TYPE_OBJECT: - return array( + $standard = array( self::ACTION_NOTHING => pht('Do nothing'), self::ACTION_ADD_CC => pht('Add emails to CC'), self::ACTION_REMOVE_CC => pht('Remove emails from CC'), @@ -663,8 +707,9 @@ self::ACTION_APPLY_BUILD_PLANS => pht('Run build plans'), self::ACTION_BLOCK => pht('Block change with message'), ); + break; case HeraldRuleTypeConfig::RULE_TYPE_PERSONAL: - return array( + $standard = array( self::ACTION_NOTHING => pht('Do nothing'), self::ACTION_ADD_CC => pht('Add me to CC'), self::ACTION_REMOVE_CC => pht('Remove me from CC'), @@ -677,9 +722,20 @@ self::ACTION_ADD_BLOCKING_REVIEWERS => pht('Add me as a blocking reviewer'), ); + break; default: throw new Exception("Unknown rule type '{$rule_type}'!"); } + + foreach (self::$customActions as $customAction) { + $result = array(); + foreach ($customAction->getActions($this, $rule_type) as $key => $action) { + $result['custom:'.$key] = $action['name']; + } + $standard = array_merge($standard, $result); + } + + return $standard; } public function willSaveAction( @@ -811,7 +867,7 @@ } } - public static function getValueTypeForAction($action, $rule_type) { + public function getValueTypeForAction($action, $rule_type) { $is_personal = ($rule_type == HeraldRuleTypeConfig::RULE_TYPE_PERSONAL); if ($is_personal) { @@ -829,8 +885,6 @@ return self::VALUE_FLAG_COLOR; case self::ACTION_ADD_PROJECTS: return self::VALUE_PROJECT; - default: - throw new Exception("Unknown or invalid action '{$action}'."); } } else { switch ($action) { @@ -854,10 +908,18 @@ return self::VALUE_BUILD_PLAN; case self::ACTION_BLOCK: return self::VALUE_TEXT; - default: - throw new Exception("Unknown or invalid action '{$action}'."); } } + + foreach (self::$customActions as $customAction) { + foreach ($customAction->getActions($this, $rule_type) as $key => $act) { + if ('custom:'.$key === $action) { + return $act['type']; + } + } + } + + throw new Exception("Unknown or invalid action '".$action."'."); } diff --git a/src/applications/herald/adapter/HeraldDifferentialRevisionAdapter.php b/src/applications/herald/adapter/HeraldDifferentialRevisionAdapter.php --- a/src/applications/herald/adapter/HeraldDifferentialRevisionAdapter.php +++ b/src/applications/herald/adapter/HeraldDifferentialRevisionAdapter.php @@ -47,6 +47,10 @@ "and run build plans."); } + protected function getObjectForCustomActions() { + return $this->revision; + } + public function supportsRuleType($rule_type) { switch ($rule_type) { case HeraldRuleTypeConfig::RULE_TYPE_GLOBAL: @@ -366,25 +370,29 @@ 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_ADD_REVIEWERS, - self::ACTION_ADD_BLOCKING_REVIEWERS, - self::ACTION_APPLY_BUILD_PLANS, - self::ACTION_NOTHING, - ); + return array_merge( + array( + self::ACTION_ADD_CC, + self::ACTION_REMOVE_CC, + self::ACTION_EMAIL, + self::ACTION_ADD_REVIEWERS, + self::ACTION_ADD_BLOCKING_REVIEWERS, + self::ACTION_APPLY_BUILD_PLANS, + self::ACTION_NOTHING, + ), + parent::getActions($rule_type)); case HeraldRuleTypeConfig::RULE_TYPE_PERSONAL: - return array( - self::ACTION_ADD_CC, - self::ACTION_REMOVE_CC, - self::ACTION_EMAIL, - self::ACTION_FLAG, - self::ACTION_ADD_REVIEWERS, - self::ACTION_ADD_BLOCKING_REVIEWERS, - self::ACTION_NOTHING, - ); + return array_merge( + array( + self::ACTION_ADD_CC, + self::ACTION_REMOVE_CC, + self::ACTION_EMAIL, + self::ACTION_FLAG, + self::ACTION_ADD_REVIEWERS, + self::ACTION_ADD_BLOCKING_REVIEWERS, + self::ACTION_NOTHING, + ), + parent::getActions($rule_type)); } } @@ -502,7 +510,13 @@ pht('Applied build plans.')); break; default: - throw new Exception("No rules to handle action '{$action}'."); + $custom_result = parent::handleCustomHeraldEffect($effect); + if ($custom_result === null) { + throw new Exception("No rules to handle action '{$action}'."); + } + + $result[] = $custom_result; + break; } } return $result; diff --git a/src/applications/herald/controller/HeraldTranscriptController.php b/src/applications/herald/controller/HeraldTranscriptController.php --- a/src/applications/herald/controller/HeraldTranscriptController.php +++ b/src/applications/herald/controller/HeraldTranscriptController.php @@ -310,13 +310,15 @@ $target = $target; break; default: - if ($target) { + if (is_array($target) && $target) { foreach ($target as $k => $phid) { if (isset($handles[$phid])) { $target[$k] = $handles[$phid]->getName(); } } $target = implode("\n", $target); + } elseif (is_string($target)) { + $target = $target; } else { $target = ''; } diff --git a/src/applications/herald/extension/HeraldCustomAction.php b/src/applications/herald/extension/HeraldCustomAction.php new file mode 100644 --- /dev/null +++ b/src/applications/herald/extension/HeraldCustomAction.php @@ -0,0 +1,11 @@ +