Phabricator:调整 Herald 规则以根据项目成员资格修改任务策略
Phabricator: Adjust Herald rules to modify task policies based on project membership
我尝试调整 Phabricator 的先驱规则,因此查看和编辑策略是根据项目成员设置的。目前无法自动调整基于项目的任务的查看和编辑策略。
我通过 Haskell 项目找到了 this modification,但这似乎不再有效。
谁能告诉我如何解决它们?
<?php
/**
* Extends Herald with a custom 'Set "Visible To" policy' action for Maniphest
* tasks.
*/
final class SetTaskViewPolicyHeraldAction extends HeraldAction {
public function appliesToAdapter(HeraldAdapter $adapter) {
return $adapter instanceof HeraldManiphestTaskAdapter;
}
public function appliesToRuleType($type) {
return $type == HeraldRuleTypeConfig::RULE_TYPE_GLOBAL;
}
public function getActionKey() {
return 'custom:view-policy';
}
public function getActionName() {
return 'Set view policy to project';
}
public function getActionType() {
return HeraldAdapter::VALUE_PROJECT;
}
public function applyEffect(
HeraldAdapter $adapter,
$object,
HeraldEffect $effect) {
// First off, ensure there's only one set project
if (count($effect->getTarget()) != 1) {
throw new HeraldInvalidConditionException(
'Expected only one project to be set for visibility policy');
}
$project = $effect->getTarget();
$project_phid = $project[0];
// Set new value by queueing a transaction, and returning the transcript.
$adapter->queueTransaction(
id(new ManiphestTransaction())
->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY)
->setNewValue($project_phid));
return new HeraldApplyTranscript(
$effect,
true,
pht('Set view policy of task'));
}
}
我只添加了旧版本SetTaskViewPolicyHeraldAction.php
的源代码,在this link还有文件SetTaskEditPolicyHeraldAction.php
,这也与我的问题有关。
终于找到了解决方案,或者更准确地说是写了一个扩展。
<?php
final class HeraldManiphestMoveSpaceAction extends HeraldAction {
// ACTIONCONST: internal ID, unique (assumably for mapping objects)
const ACTIONCONST = 'space.move';
// supposably key for mapping history entries
const DO_MOVE_SPACE = 'do.move.space';
// entry in Herald action selection drop down menu when configuring a rule
public function getHeraldActionName() {
return pht('Move to space');
}
// section in Herald action selection drop down menu
public function getActionGroupKey() {
return HeraldSupportActionGroup::ACTIONGROUPKEY;
}
// source for input field
protected function getDatasource() {
return new PhabricatorSpacesNamespaceDatasource();
}
// which UI element to show when configuring the action
public function getHeraldActionStandardType() {
return self::STANDARD_PHID_LIST;
}
// allowed applicable objects
public function supportsObject($object) {
return ($object instanceof PhabricatorProjectInterface);
}
// permitted user roles (globally or locally)
public function supportsRuleType($rule_type) {
return ($rule_type == HeraldRuleTypeConfig::RULE_TYPE_GLOBAL);
}
// appearance in transcript
protected function getActionEffectMap() {
return array(
self::DO_MOVE_SPACE => array(
'icon' => 'fa-diamond',
'color' => 'green',
'name' => pht('Moved to space'),
),
);
}
// description of action that will be taken (present tense)
public function renderActionDescription($value) {
return pht('Move to space: %s.', $this->renderHandleList($value));
}
// description of action that has been taken (past tense, for history view etc.)
protected function renderActionEffectDescription($type, $data) {
switch ($type) {
case self::DO_MOVE_SPACE:
return pht(
'Moved to %s space: %s.',
phutil_count($data),
$this->renderHandleList($data));
}
}
// executed by Herald rules on objects that match condition (calls function applySpace)
public function applyEffect($object, HeraldEffect $effect) {
$current_space = array($object->getSpacePHID());
// allowed objects for transaction
$allowed_types = array(
PhabricatorSpacesNamespacePHIDType::TYPECONST,
);
// loadStandardTargets() figures out the to-set spaces from the Phabricator IDs ($phids)
// and excludes $current_space from this list, potentially resulting in an empty list (NULL).
// Misconfigured Herald action may result in an empty $phids.
$new_phids = $effect->getTarget();
$new_spaces = $this->loadStandardTargets($new_phids, $allowed_types, $current_space);
// if no spaces need to be set (either because of bad rule (see above comment), or space already manually set), avoid doing work
if(!$new_spaces) {
return;
} else {
// One object can only be at one space at a time. This silently fixes if one misconfigured Herald rule tries to move one object into different spaces.
$phid = head_key($new_spaces);
$adapter = $this->getAdapter();
$xaction = $adapter->newTransaction()
->setTransactionType(PhabricatorTransactions::TYPE_SPACE)
->setNewValue($phid);
$adapter->queueTransaction($xaction);
$this->logEffect(self::DO_MOVE_SPACE, array($phid));
}
}
}
这里应该注意一些事情(也记录在这个扩展的 Github repo 中)。我使用这个扩展主要是为了在相应的 space 中自动转移任务(基于项目管理),但它应该也适用于其他对象(所有可以有 space 的对象)——但我没有测试过它。
一个问题是,Herald(还)不明白对象只能有一个 space - 如果多个 Herald 规则适用,它们将全部执行,最后创建的那个将决定对象的space。作为解决方法,Github 存储库中还有一个补丁,它创建了一个先驱规则 "is exactly"。
diff --git a/src/applications/herald/adapter/HeraldAdapter.php b/src/applications/herald/adapter/HeraldAdapter.php
index 78ce86294..600033247 100644
--- a/src/applications/herald/adapter/HeraldAdapter.php
+++ b/src/applications/herald/adapter/HeraldAdapter.php
@@ -10,6 +10,7 @@ abstract class HeraldAdapter extends Phobject {
const CONDITION_IS_NOT_ANY = '!isany';
const CONDITION_INCLUDE_ALL = 'all';
const CONDITION_INCLUDE_ANY = 'any';
+ const CONDITION_INCLUDE_EXACTLY = 'exactly';
const CONDITION_INCLUDE_NONE = 'none';
const CONDITION_IS_ME = 'me';
const CONDITION_IS_NOT_ME = '!me';
@@ -335,6 +336,7 @@ abstract class HeraldAdapter extends Phobject {
self::CONDITION_IS_NOT_ANY => pht('is not any of'),
self::CONDITION_INCLUDE_ALL => pht('include all of'),
self::CONDITION_INCLUDE_ANY => pht('include any of'),
+ self::CONDITION_INCLUDE_EXACTLY => pht('is exactly'), // custom adaptation for projects
self::CONDITION_INCLUDE_NONE => pht('do not include'),
self::CONDITION_IS_ME => pht('is myself'),
self::CONDITION_IS_NOT_ME => pht('is not myself'),
@@ -432,6 +434,19 @@ abstract class HeraldAdapter extends Phobject {
return (bool)array_select_keys(
array_fuse($field_value),
$condition_value);
+ case self::CONDITION_INCLUDE_EXACTLY:
+ if (!is_array($field_value)) {
+ throw new HeraldInvalidConditionException(
+ pht('Object produced non-array value!'));
+ }
+ if (!is_array($condition_value)) {
+ throw new HeraldInvalidConditionException(
+ pht('Expected condition value to be an array.'));
+ }
+
+ $have = array_select_keys(array_fuse($field_value), $condition_value);
+ return (count($have) == count($condition_value) &&
+ count($have) == count(array_fuse($field_value)));
case self::CONDITION_INCLUDE_NONE:
return !array_select_keys(
array_fuse($field_value),
@@ -592,6 +607,7 @@ abstract class HeraldAdapter extends Phobject {
case self::CONDITION_IS_NOT_ANY:
case self::CONDITION_INCLUDE_ALL:
case self::CONDITION_INCLUDE_ANY:
+ case self::CONDITION_INCLUDE_EXACTLY:
case self::CONDITION_INCLUDE_NONE:
case self::CONDITION_IS_ME:
case self::CONDITION_IS_NOT_ME:
diff --git a/src/applications/herald/field/HeraldField.php b/src/applications/herald/field/HeraldField.php
index 2abed0ff1..8bbcfa3dd 100644
--- a/src/applications/herald/field/HeraldField.php
+++ b/src/applications/herald/field/HeraldField.php
@@ -58,6 +58,7 @@ abstract class HeraldField extends Phobject {
return array(
HeraldAdapter::CONDITION_INCLUDE_ALL,
HeraldAdapter::CONDITION_INCLUDE_ANY,
+ HeraldAdapter::CONDITION_INCLUDE_EXACTLY,
HeraldAdapter::CONDITION_INCLUDE_NONE,
HeraldAdapter::CONDITION_EXISTS,
HeraldAdapter::CONDITION_NOT_EXISTS,
diff --git a/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldPHIDs.php b/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldPHIDs.php
index 78c8caa5a..be267d2e4 100644
--- a/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldPHIDs.php
+++ b/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldPHIDs.php
@@ -235,6 +235,7 @@ abstract class PhabricatorStandardCustomFieldPHIDs
return array(
HeraldAdapter::CONDITION_INCLUDE_ALL,
HeraldAdapter::CONDITION_INCLUDE_ANY,
+ HeraldAdapter::CONDITION_INCLUDE_EXACTLY,
HeraldAdapter::CONDITION_INCLUDE_NONE,
HeraldAdapter::CONDITION_EXISTS,
HeraldAdapter::CONDITION_NOT_EXISTS,
查看 Github repo 中的 README.md 了解更多详情。
我尝试调整 Phabricator 的先驱规则,因此查看和编辑策略是根据项目成员设置的。目前无法自动调整基于项目的任务的查看和编辑策略。
我通过 Haskell 项目找到了 this modification,但这似乎不再有效。
谁能告诉我如何解决它们?
<?php
/**
* Extends Herald with a custom 'Set "Visible To" policy' action for Maniphest
* tasks.
*/
final class SetTaskViewPolicyHeraldAction extends HeraldAction {
public function appliesToAdapter(HeraldAdapter $adapter) {
return $adapter instanceof HeraldManiphestTaskAdapter;
}
public function appliesToRuleType($type) {
return $type == HeraldRuleTypeConfig::RULE_TYPE_GLOBAL;
}
public function getActionKey() {
return 'custom:view-policy';
}
public function getActionName() {
return 'Set view policy to project';
}
public function getActionType() {
return HeraldAdapter::VALUE_PROJECT;
}
public function applyEffect(
HeraldAdapter $adapter,
$object,
HeraldEffect $effect) {
// First off, ensure there's only one set project
if (count($effect->getTarget()) != 1) {
throw new HeraldInvalidConditionException(
'Expected only one project to be set for visibility policy');
}
$project = $effect->getTarget();
$project_phid = $project[0];
// Set new value by queueing a transaction, and returning the transcript.
$adapter->queueTransaction(
id(new ManiphestTransaction())
->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY)
->setNewValue($project_phid));
return new HeraldApplyTranscript(
$effect,
true,
pht('Set view policy of task'));
}
}
我只添加了旧版本SetTaskViewPolicyHeraldAction.php
的源代码,在this link还有文件SetTaskEditPolicyHeraldAction.php
,这也与我的问题有关。
终于找到了解决方案,或者更准确地说是写了一个扩展。
<?php
final class HeraldManiphestMoveSpaceAction extends HeraldAction {
// ACTIONCONST: internal ID, unique (assumably for mapping objects)
const ACTIONCONST = 'space.move';
// supposably key for mapping history entries
const DO_MOVE_SPACE = 'do.move.space';
// entry in Herald action selection drop down menu when configuring a rule
public function getHeraldActionName() {
return pht('Move to space');
}
// section in Herald action selection drop down menu
public function getActionGroupKey() {
return HeraldSupportActionGroup::ACTIONGROUPKEY;
}
// source for input field
protected function getDatasource() {
return new PhabricatorSpacesNamespaceDatasource();
}
// which UI element to show when configuring the action
public function getHeraldActionStandardType() {
return self::STANDARD_PHID_LIST;
}
// allowed applicable objects
public function supportsObject($object) {
return ($object instanceof PhabricatorProjectInterface);
}
// permitted user roles (globally or locally)
public function supportsRuleType($rule_type) {
return ($rule_type == HeraldRuleTypeConfig::RULE_TYPE_GLOBAL);
}
// appearance in transcript
protected function getActionEffectMap() {
return array(
self::DO_MOVE_SPACE => array(
'icon' => 'fa-diamond',
'color' => 'green',
'name' => pht('Moved to space'),
),
);
}
// description of action that will be taken (present tense)
public function renderActionDescription($value) {
return pht('Move to space: %s.', $this->renderHandleList($value));
}
// description of action that has been taken (past tense, for history view etc.)
protected function renderActionEffectDescription($type, $data) {
switch ($type) {
case self::DO_MOVE_SPACE:
return pht(
'Moved to %s space: %s.',
phutil_count($data),
$this->renderHandleList($data));
}
}
// executed by Herald rules on objects that match condition (calls function applySpace)
public function applyEffect($object, HeraldEffect $effect) {
$current_space = array($object->getSpacePHID());
// allowed objects for transaction
$allowed_types = array(
PhabricatorSpacesNamespacePHIDType::TYPECONST,
);
// loadStandardTargets() figures out the to-set spaces from the Phabricator IDs ($phids)
// and excludes $current_space from this list, potentially resulting in an empty list (NULL).
// Misconfigured Herald action may result in an empty $phids.
$new_phids = $effect->getTarget();
$new_spaces = $this->loadStandardTargets($new_phids, $allowed_types, $current_space);
// if no spaces need to be set (either because of bad rule (see above comment), or space already manually set), avoid doing work
if(!$new_spaces) {
return;
} else {
// One object can only be at one space at a time. This silently fixes if one misconfigured Herald rule tries to move one object into different spaces.
$phid = head_key($new_spaces);
$adapter = $this->getAdapter();
$xaction = $adapter->newTransaction()
->setTransactionType(PhabricatorTransactions::TYPE_SPACE)
->setNewValue($phid);
$adapter->queueTransaction($xaction);
$this->logEffect(self::DO_MOVE_SPACE, array($phid));
}
}
}
这里应该注意一些事情(也记录在这个扩展的 Github repo 中)。我使用这个扩展主要是为了在相应的 space 中自动转移任务(基于项目管理),但它应该也适用于其他对象(所有可以有 space 的对象)——但我没有测试过它。
一个问题是,Herald(还)不明白对象只能有一个 space - 如果多个 Herald 规则适用,它们将全部执行,最后创建的那个将决定对象的space。作为解决方法,Github 存储库中还有一个补丁,它创建了一个先驱规则 "is exactly"。
diff --git a/src/applications/herald/adapter/HeraldAdapter.php b/src/applications/herald/adapter/HeraldAdapter.php
index 78ce86294..600033247 100644
--- a/src/applications/herald/adapter/HeraldAdapter.php
+++ b/src/applications/herald/adapter/HeraldAdapter.php
@@ -10,6 +10,7 @@ abstract class HeraldAdapter extends Phobject {
const CONDITION_IS_NOT_ANY = '!isany';
const CONDITION_INCLUDE_ALL = 'all';
const CONDITION_INCLUDE_ANY = 'any';
+ const CONDITION_INCLUDE_EXACTLY = 'exactly';
const CONDITION_INCLUDE_NONE = 'none';
const CONDITION_IS_ME = 'me';
const CONDITION_IS_NOT_ME = '!me';
@@ -335,6 +336,7 @@ abstract class HeraldAdapter extends Phobject {
self::CONDITION_IS_NOT_ANY => pht('is not any of'),
self::CONDITION_INCLUDE_ALL => pht('include all of'),
self::CONDITION_INCLUDE_ANY => pht('include any of'),
+ self::CONDITION_INCLUDE_EXACTLY => pht('is exactly'), // custom adaptation for projects
self::CONDITION_INCLUDE_NONE => pht('do not include'),
self::CONDITION_IS_ME => pht('is myself'),
self::CONDITION_IS_NOT_ME => pht('is not myself'),
@@ -432,6 +434,19 @@ abstract class HeraldAdapter extends Phobject {
return (bool)array_select_keys(
array_fuse($field_value),
$condition_value);
+ case self::CONDITION_INCLUDE_EXACTLY:
+ if (!is_array($field_value)) {
+ throw new HeraldInvalidConditionException(
+ pht('Object produced non-array value!'));
+ }
+ if (!is_array($condition_value)) {
+ throw new HeraldInvalidConditionException(
+ pht('Expected condition value to be an array.'));
+ }
+
+ $have = array_select_keys(array_fuse($field_value), $condition_value);
+ return (count($have) == count($condition_value) &&
+ count($have) == count(array_fuse($field_value)));
case self::CONDITION_INCLUDE_NONE:
return !array_select_keys(
array_fuse($field_value),
@@ -592,6 +607,7 @@ abstract class HeraldAdapter extends Phobject {
case self::CONDITION_IS_NOT_ANY:
case self::CONDITION_INCLUDE_ALL:
case self::CONDITION_INCLUDE_ANY:
+ case self::CONDITION_INCLUDE_EXACTLY:
case self::CONDITION_INCLUDE_NONE:
case self::CONDITION_IS_ME:
case self::CONDITION_IS_NOT_ME:
diff --git a/src/applications/herald/field/HeraldField.php b/src/applications/herald/field/HeraldField.php
index 2abed0ff1..8bbcfa3dd 100644
--- a/src/applications/herald/field/HeraldField.php
+++ b/src/applications/herald/field/HeraldField.php
@@ -58,6 +58,7 @@ abstract class HeraldField extends Phobject {
return array(
HeraldAdapter::CONDITION_INCLUDE_ALL,
HeraldAdapter::CONDITION_INCLUDE_ANY,
+ HeraldAdapter::CONDITION_INCLUDE_EXACTLY,
HeraldAdapter::CONDITION_INCLUDE_NONE,
HeraldAdapter::CONDITION_EXISTS,
HeraldAdapter::CONDITION_NOT_EXISTS,
diff --git a/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldPHIDs.php b/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldPHIDs.php
index 78c8caa5a..be267d2e4 100644
--- a/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldPHIDs.php
+++ b/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldPHIDs.php
@@ -235,6 +235,7 @@ abstract class PhabricatorStandardCustomFieldPHIDs
return array(
HeraldAdapter::CONDITION_INCLUDE_ALL,
HeraldAdapter::CONDITION_INCLUDE_ANY,
+ HeraldAdapter::CONDITION_INCLUDE_EXACTLY,
HeraldAdapter::CONDITION_INCLUDE_NONE,
HeraldAdapter::CONDITION_EXISTS,
HeraldAdapter::CONDITION_NOT_EXISTS,
查看 Github repo 中的 README.md 了解更多详情。