diff --git a/src/applications/herald/adapter/HeraldAdapter.php b/src/applications/herald/adapter/HeraldAdapter.php index bd6d4953da..e08118a369 100644 --- a/src/applications/herald/adapter/HeraldAdapter.php +++ b/src/applications/herald/adapter/HeraldAdapter.php @@ -14,6 +14,7 @@ abstract class HeraldAdapter extends Phobject { const CONDITION_IS_ME = 'me'; const CONDITION_IS_NOT_ME = '!me'; const CONDITION_REGEXP = 'regexp'; + const CONDITION_NOT_REGEXP = '!regexp'; const CONDITION_RULE = 'conditions'; const CONDITION_NOT_RULE = '!conditions'; const CONDITION_EXISTS = 'exists'; @@ -322,6 +323,7 @@ abstract class HeraldAdapter extends Phobject { self::CONDITION_IS_ME => pht('is myself'), self::CONDITION_IS_NOT_ME => pht('is not myself'), self::CONDITION_REGEXP => pht('matches regexp'), + self::CONDITION_NOT_REGEXP => pht('does not match regexp'), self::CONDITION_RULE => pht('matches:'), self::CONDITION_NOT_RULE => pht('does not match:'), self::CONDITION_EXISTS => pht('exists'), @@ -364,16 +366,18 @@ abstract class HeraldAdapter extends Phobject { switch ($condition_type) { case self::CONDITION_CONTAINS: - // "Contains" can take an array of strings, as in "Any changed - // filename" for diffs. + case self::CONDITION_NOT_CONTAINS: + // "Contains and "does not contain" can take an array of strings, as in + // "Any changed filename" for diffs. + + $result_if_match = ($condition_type == self::CONDITION_CONTAINS); + foreach ((array)$field_value as $value) { if (stripos($value, $condition_value) !== false) { - return true; + return $result_if_match; } } - return false; - case self::CONDITION_NOT_CONTAINS: - return (stripos($field_value, $condition_value) === false); + return !$result_if_match; case self::CONDITION_IS: return ($field_value == $condition_value); case self::CONDITION_IS_NOT: @@ -427,6 +431,9 @@ abstract class HeraldAdapter extends Phobject { case self::CONDITION_NEVER: return false; case self::CONDITION_REGEXP: + case self::CONDITION_NOT_REGEXP: + $result_if_match = ($condition_type == self::CONDITION_REGEXP); + foreach ((array)$field_value as $value) { // We add the 'S' flag because we use the regexp multiple times. // It shouldn't cause any troubles if the flag is already there @@ -437,10 +444,10 @@ abstract class HeraldAdapter extends Phobject { pht('Regular expression is not valid!')); } if ($result) { - return true; + return $result_if_match; } } - return false; + return !$result_if_match; case self::CONDITION_REGEXP_PAIR: // Match a JSON-encoded pair of regular expressions against a // dictionary. The first regexp must match the dictionary key, and the @@ -509,6 +516,7 @@ abstract class HeraldAdapter extends Phobject { switch ($condition_type) { case self::CONDITION_REGEXP: + case self::CONDITION_NOT_REGEXP: $ok = @preg_match($condition_value, ''); if ($ok === false) { throw new HeraldInvalidConditionException( diff --git a/src/applications/herald/field/HeraldField.php b/src/applications/herald/field/HeraldField.php index 2aba443077..98d6d8ffc4 100644 --- a/src/applications/herald/field/HeraldField.php +++ b/src/applications/herald/field/HeraldField.php @@ -47,6 +47,7 @@ abstract class HeraldField extends Phobject { HeraldAdapter::CONDITION_IS, HeraldAdapter::CONDITION_IS_NOT, HeraldAdapter::CONDITION_REGEXP, + HeraldAdapter::CONDITION_NOT_REGEXP, ); case self::STANDARD_PHID: return array( @@ -76,12 +77,16 @@ abstract class HeraldField extends Phobject { case self::STANDARD_TEXT_LIST: return array( HeraldAdapter::CONDITION_CONTAINS, + HeraldAdapter::CONDITION_NOT_CONTAINS, HeraldAdapter::CONDITION_REGEXP, + HeraldAdapter::CONDITION_NOT_REGEXP, ); case self::STANDARD_TEXT_MAP: return array( HeraldAdapter::CONDITION_CONTAINS, + HeraldAdapter::CONDITION_NOT_CONTAINS, HeraldAdapter::CONDITION_REGEXP, + HeraldAdapter::CONDITION_NOT_REGEXP, HeraldAdapter::CONDITION_REGEXP_PAIR, ); } diff --git a/src/infrastructure/customfield/field/PhabricatorCustomField.php b/src/infrastructure/customfield/field/PhabricatorCustomField.php index a89d8005f0..cb561fca58 100644 --- a/src/infrastructure/customfield/field/PhabricatorCustomField.php +++ b/src/infrastructure/customfield/field/PhabricatorCustomField.php @@ -1446,5 +1446,19 @@ abstract class PhabricatorCustomField extends Phobject { return null; } + public function getHeraldFieldStandardType() { + if ($this->proxy) { + return $this->proxy->getHeraldFieldStandardType(); + } + return null; + } + + public function getHeraldDatasource() { + if ($this->proxy) { + return $this->proxy->getHeraldDatasource(); + } + return null; + } + } diff --git a/src/infrastructure/customfield/herald/PhabricatorCustomFieldHeraldField.php b/src/infrastructure/customfield/herald/PhabricatorCustomFieldHeraldField.php index 30e9fc4c12..b9e5724ef6 100644 --- a/src/infrastructure/customfield/herald/PhabricatorCustomFieldHeraldField.php +++ b/src/infrastructure/customfield/herald/PhabricatorCustomFieldHeraldField.php @@ -65,8 +65,20 @@ final class PhabricatorCustomFieldHeraldField extends HeraldField { return $this->getCustomField()->getHeraldFieldConditions(); } + protected function getHeraldFieldStandardType() { + return $this->getCustomField()->getHeraldFieldStandardType(); + } + public function getHeraldFieldValueType($condition) { + if ($this->getHeraldFieldStandardType()) { + return parent::getHeraldFieldValueType($condition); + } + return $this->getCustomField()->getHeraldFieldValueType($condition); } + protected function getDatasource() { + return $this->getCustomField()->getHeraldDatasource(); + } + } diff --git a/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldBool.php b/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldBool.php index b1fc7f7a9b..f1d1371a7d 100644 --- a/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldBool.php +++ b/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldBool.php @@ -129,6 +129,10 @@ final class PhabricatorStandardCustomFieldBool ); } + public function getHeraldFieldStandardType() { + return HeraldField::STANDARD_BOOL; + } + protected function getHTTPParameterType() { return new AphrontBoolHTTPParameterType(); } diff --git a/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldLink.php b/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldLink.php index 904a457616..66f3605b9c 100644 --- a/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldLink.php +++ b/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldLink.php @@ -77,9 +77,14 @@ final class PhabricatorStandardCustomFieldLink HeraldAdapter::CONDITION_IS, HeraldAdapter::CONDITION_IS_NOT, HeraldAdapter::CONDITION_REGEXP, + HeraldAdapter::CONDITION_NOT_REGEXP, ); } + public function getHeraldFieldStandardType() { + return HeraldField::STANDARD_TEXT; + } + protected function getHTTPParameterType() { return new AphrontStringHTTPParameterType(); } diff --git a/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldPHIDs.php b/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldPHIDs.php index b9b1bf6505..78c8caa5a9 100644 --- a/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldPHIDs.php +++ b/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldPHIDs.php @@ -241,6 +241,10 @@ abstract class PhabricatorStandardCustomFieldPHIDs ); } + public function getHeraldFieldStandardType() { + return HeraldField::STANDARD_PHID_NULLABLE; + } + public function getHeraldFieldValue() { // If the field has a `null` value, make sure we hand an `array()` to // Herald. diff --git a/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldRemarkup.php b/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldRemarkup.php index 14e4eede5a..be7db42004 100644 --- a/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldRemarkup.php +++ b/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldRemarkup.php @@ -92,9 +92,14 @@ final class PhabricatorStandardCustomFieldRemarkup HeraldAdapter::CONDITION_IS, HeraldAdapter::CONDITION_IS_NOT, HeraldAdapter::CONDITION_REGEXP, + HeraldAdapter::CONDITION_NOT_REGEXP, ); } + public function getHeraldFieldStandardType() { + return HeraldField::STANDARD_TEXT; + } + protected function getHTTPParameterType() { return new AphrontStringHTTPParameterType(); } diff --git a/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldText.php b/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldText.php index 716e1dfc99..8a4ae97bcf 100644 --- a/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldText.php +++ b/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldText.php @@ -60,9 +60,14 @@ final class PhabricatorStandardCustomFieldText HeraldAdapter::CONDITION_IS, HeraldAdapter::CONDITION_IS_NOT, HeraldAdapter::CONDITION_REGEXP, + HeraldAdapter::CONDITION_NOT_REGEXP, ); } + public function getHeraldFieldStandardType() { + return HeraldField::STANDARD_TEXT; + } + protected function getHTTPParameterType() { return new AphrontStringHTTPParameterType(); } diff --git a/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldTokenizer.php b/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldTokenizer.php index f6a542ec7f..f9a69c2838 100644 --- a/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldTokenizer.php +++ b/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldTokenizer.php @@ -44,4 +44,12 @@ abstract class PhabricatorStandardCustomFieldTokenizer ->setDatasource($this->getDatasource()); } + public function getHeraldFieldStandardType() { + return HeraldField::STANDARD_PHID_LIST; + } + + public function getHeraldDatasource() { + return $this->getDatasource(); + } + }