1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-22 05:20:56 +01:00

Make Herald rules more resilient

Summary:
Make Herald conditions and actions more resilient (see discussion in D12896). This protects against invalid rules, which may have been valid in the past but are no longer valid. Specifically:

  - If a rule has an invalid field, the conditions fail and the actions do not execute.
  - The transcript shows that the rule failed because of an invalid field, and points at the issue.
  - If a rule has an invalid action, that action fails but other actions execute.
  - The transcript shows that the action failed.
  - Everything else (particularly, other rules) continues normally in both cases.
  - The edit interface is somewhat working when editing an invalid rule, but it could use some further improvements.

Test Plan:
  # Ran this rule on a differential revision and saw the rule fail in the transcript.
  # Was able to submit a differential without receiving an `ERR-CONDUIT-CORE`.
  # Edited the Herald rule using the UI and was able to save the rule succesfully.
  # Ran this rule on a differential revision and saw one success and one failure in the transcript.
  # Was able to submit a differential without receiving an `ERR-CONDUIT-CORE`.
  # Edited the Herald rule using the UI. Clicking save caused a `HeraldInvalidActionException` to be thrown, but maybe this is okay.

Differential Revision: http://phabricator.local/D41
This commit is contained in:
Joshua Spence 2015-05-25 19:02:49 +10:00
parent 18fe6d58ae
commit f5c9b9c014
5 changed files with 65 additions and 14 deletions

View file

@ -1203,7 +1203,15 @@ abstract class HeraldAdapter {
$rule_global = HeraldRuleTypeConfig::RULE_TYPE_GLOBAL; $rule_global = HeraldRuleTypeConfig::RULE_TYPE_GLOBAL;
$action_type = $action->getAction(); $action_type = $action->getAction();
$action_name = idx($this->getActionNameMap($rule_global), $action_type);
$default = $this->isHeraldCustomKey($action_type)
? pht('(Unknown Custom Action "%s") equals', $action_type)
: pht('(Unknown Action "%s") equals', $action_type);
$action_name = idx(
$this->getActionNameMap($rule_global),
$action_type,
$default);
$target = $this->renderActionTargetAsText($action, $handles); $target = $this->renderActionTargetAsText($action, $handles);
@ -1525,7 +1533,9 @@ abstract class HeraldAdapter {
$supported = $this->getActions($rule_type); $supported = $this->getActions($rule_type);
$supported = array_fuse($supported); $supported = array_fuse($supported);
if (empty($supported[$action])) { if (empty($supported[$action])) {
throw new Exception( return new HeraldApplyTranscript(
$effect,
false,
pht( pht(
'Adapter "%s" does not support action "%s" for rule type "%s".', 'Adapter "%s" does not support action "%s" for rule type "%s".',
get_class($this), get_class($this),
@ -1548,7 +1558,9 @@ abstract class HeraldAdapter {
$result = $this->handleCustomHeraldEffect($effect); $result = $this->handleCustomHeraldEffect($effect);
if (!$result) { if (!$result) {
throw new Exception( return new HeraldApplyTranscript(
$effect,
false,
pht( pht(
'No custom action exists to handle rule action "%s".', 'No custom action exists to handle rule action "%s".',
$action)); $action));

View file

@ -154,7 +154,10 @@ final class HeraldDifferentialDiffAdapter extends HeraldDifferentialAdapter {
pht('Blocked diff.')); pht('Blocked diff.'));
break; break;
default: default:
throw new Exception(pht('No rules to handle action "%s"!', $action)); $result[] = new HeraldApplyTranscript(
$effect,
false,
pht('No rules to handle action "%s"!', $action));
} }
} }

View file

@ -320,7 +320,7 @@ final class HeraldRuleController extends HeraldController {
try { try {
$adapter->willSaveAction($rule, $obj); $adapter->willSaveAction($rule, $obj);
} catch (HeraldInvalidActionException $ex) { } catch (HeraldInvalidActionException $ex) {
$errors[] = $ex; $errors[] = $ex->getMessage();
} }
$actions[] = $obj; $actions[] = $obj;
@ -354,7 +354,6 @@ final class HeraldRuleController extends HeraldController {
if ($rule->getConditions()) { if ($rule->getConditions()) {
$serial_conditions = array(); $serial_conditions = array();
foreach ($rule->getConditions() as $condition) { foreach ($rule->getConditions() as $condition) {
$value = $condition->getValue(); $value = $condition->getValue();
switch ($condition->getFieldName()) { switch ($condition->getFieldName()) {
case HeraldAdapter::FIELD_TASK_PRIORITY: case HeraldAdapter::FIELD_TASK_PRIORITY:
@ -394,10 +393,10 @@ final class HeraldRuleController extends HeraldController {
$serial_actions = array( $serial_actions = array(
array('default', ''), array('default', ''),
); );
if ($rule->getActions()) { if ($rule->getActions()) {
$serial_actions = array(); $serial_actions = array();
foreach ($rule->getActions() as $action) { foreach ($rule->getActions() as $action) {
switch ($action->getAction()) { switch ($action->getAction()) {
case HeraldAdapter::ACTION_FLAG: case HeraldAdapter::ACTION_FLAG:
case HeraldAdapter::ACTION_BLOCK: case HeraldAdapter::ACTION_BLOCK:
@ -438,21 +437,39 @@ final class HeraldRuleController extends HeraldController {
// names of, so that saving a rule without touching anything doesn't change // names of, so that saving a rule without touching anything doesn't change
// it. // it.
foreach ($rule->getConditions() as $condition) { foreach ($rule->getConditions() as $condition) {
if (empty($field_map[$condition->getFieldName()])) { $field_name = $condition->getFieldName();
$field_map[$condition->getFieldName()] = pht('<Unknown Field>');
if (empty($field_map[$field_name])) {
$field_map[$field_name] = pht('<Unknown Field "%s">', $field_name);
} }
} }
$actions = $adapter->getActions($rule->getRuleType()); $actions = $adapter->getActions($rule->getRuleType());
$action_map = array_select_keys($all_actions, $actions); $action_map = array_select_keys($all_actions, $actions);
// Populate any actions which exist in the rule but which we don't know the
// names of, so that saving a rule without touching anything doesn't change
// it.
foreach ($rule->getActions() as $action) {
$action_name = $action->getAction();
if (empty($action_map[$action_name])) {
$action_map[$action_name] = pht('<Unknown Action "%s">', $action_name);
}
}
$config_info = array(); $config_info = array();
$config_info['fields'] = $field_map; $config_info['fields'] = $field_map;
$config_info['conditions'] = $all_conditions; $config_info['conditions'] = $all_conditions;
$config_info['actions'] = $action_map; $config_info['actions'] = $action_map;
foreach ($config_info['fields'] as $field => $name) { foreach ($config_info['fields'] as $field => $name) {
$field_conditions = $adapter->getConditionsForField($field); try {
$field_conditions = $adapter->getConditionsForField($field);
} catch (Exception $ex) {
$field_conditions = array(HeraldAdapter::CONDITION_UNCONDITIONALLY);
}
$config_info['conditionMap'][$field] = $field_conditions; $config_info['conditionMap'][$field] = $field_conditions;
} }
@ -468,9 +485,15 @@ final class HeraldRuleController extends HeraldController {
$config_info['rule_type'] = $rule->getRuleType(); $config_info['rule_type'] = $rule->getRuleType();
foreach ($config_info['actions'] as $action => $name) { foreach ($config_info['actions'] as $action => $name) {
$config_info['targets'][$action] = $adapter->getValueTypeForAction( try {
$action, $action_value = $adapter->getValueTypeForAction(
$rule->getRuleType()); $action,
$rule->getRuleType());
} catch (Exception $ex) {
$action_value = array(HeraldAdapter::VALUE_NONE);
}
$config_info['targets'][$action] = $action_value;
} }
$changeflag_options = $changeflag_options =

View file

@ -380,7 +380,10 @@ final class HeraldTranscriptController extends HeraldController {
$item->setState(PHUIObjectItemView::STATE_FAIL); $item->setState(PHUIObjectItemView::STATE_FAIL);
} }
$rule = idx($action_names, $apply_xscript->getAction(), pht('Unknown')); $rule = idx(
$action_names,
$apply_xscript->getAction(),
pht('Unknown Action "%s"', $apply_xscript->getAction()));
$item->setHeader(pht('%s: %s', $rule, $target)); $item->setHeader(pht('%s: %s', $rule, $target));
$item->addAttribute($apply_xscript->getReason()); $item->addAttribute($apply_xscript->getReason());

View file

@ -272,6 +272,16 @@ final class HeraldEngine {
$result = false; $result = false;
} else { } else {
foreach ($conditions as $condition) { foreach ($conditions as $condition) {
try {
$object->getHeraldField($condition->getFieldName());
} catch (Exception $ex) {
$reason = pht(
'Field "%s" does not exist!',
$condition->getFieldName());
$result = false;
break;
}
$match = $this->doesConditionMatch($rule, $condition, $object); $match = $this->doesConditionMatch($rule, $condition, $object);
if (!$all && $match) { if (!$all && $match) {