Page MenuHomestyx hydra

No OneTemporary

diff --git a/resources/sql/patches/20131227.heraldobject.sql b/resources/sql/patches/20131227.heraldobject.sql
new file mode 100644
index 0000000000..b53d95ab86
--- /dev/null
+++ b/resources/sql/patches/20131227.heraldobject.sql
@@ -0,0 +1,6 @@
+ALTER TABLE {$NAMESPACE}_herald.herald_rule
+ ADD triggerObjectPHID VARCHAR(64) COLLATE utf8_bin;
+
+ALTER TABLE {$NAMESPACE}_herald.herald_rule
+ ADD KEY `key_trigger` (triggerObjectPHID);
+
diff --git a/src/applications/herald/config/HeraldRuleTypeConfig.php b/src/applications/herald/config/HeraldRuleTypeConfig.php
index 6d9712134a..d55c435f46 100644
--- a/src/applications/herald/config/HeraldRuleTypeConfig.php
+++ b/src/applications/herald/config/HeraldRuleTypeConfig.php
@@ -1,15 +1,17 @@
<?php
final class HeraldRuleTypeConfig {
const RULE_TYPE_GLOBAL = 'global';
+ const RULE_TYPE_OBJECT = 'object';
const RULE_TYPE_PERSONAL = 'personal';
public static function getRuleTypeMap() {
$map = array(
- self::RULE_TYPE_GLOBAL => pht('Global'),
- self::RULE_TYPE_PERSONAL => pht('Personal'),
+ self::RULE_TYPE_PERSONAL => pht('Personal'),
+ self::RULE_TYPE_OBJECT => pht('Object'),
+ self::RULE_TYPE_GLOBAL => pht('Global'),
);
return $map;
}
}
diff --git a/src/applications/herald/controller/HeraldDisableController.php b/src/applications/herald/controller/HeraldDisableController.php
index 13c8ad0807..1ded3d615a 100644
--- a/src/applications/herald/controller/HeraldDisableController.php
+++ b/src/applications/herald/controller/HeraldDisableController.php
@@ -1,74 +1,74 @@
<?php
final class HeraldDisableController extends HeraldController {
private $id;
private $action;
public function willProcessRequest(array $data) {
$this->id = $data['id'];
$this->action = $data['action'];
}
public function processRequest() {
$request = $this->getRequest();
$viewer = $request->getUser();
$id = $this->id;
$rule = id(new HeraldRuleQuery())
->setViewer($viewer)
->withIDs(array($id))
->requireCapabilities(
array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
))
->executeOne();
if (!$rule) {
return new Aphront404Response();
}
- if ($rule->getRuleType() == HeraldRuleTypeConfig::RULE_TYPE_GLOBAL) {
+ if ($rule->isGlobalRule()) {
$this->requireApplicationCapability(
HeraldCapabilityManageGlobalRules::CAPABILITY);
}
$view_uri = $this->getApplicationURI("rule/{$id}/");
$is_disable = ($this->action === 'disable');
if ($request->isFormPost()) {
$xaction = id(new HeraldRuleTransaction())
->setTransactionType(HeraldRuleTransaction::TYPE_DISABLE)
->setNewValue($is_disable);
id(new HeraldRuleEditor())
->setActor($viewer)
->setContinueOnNoEffect(true)
->setContentSourceFromRequest($request)
->applyTransactions($rule, array($xaction));
return id(new AphrontRedirectResponse())->setURI($view_uri);
}
if ($is_disable) {
$title = pht('Really disable this rule?');
$body = pht('This rule will no longer activate.');
$button = pht('Disable Rule');
} else {
$title = pht('Really enable this rule?');
$body = pht('This rule will become active again.');
$button = pht('Enable Rule');
}
$dialog = id(new AphrontDialogView())
->setUser($viewer)
->setTitle($title)
->appendChild($body)
->addSubmitButton($button)
->addCancelButton($view_uri);
return id(new AphrontDialogResponse())->setDialog($dialog);
}
}
diff --git a/src/applications/herald/controller/HeraldNewController.php b/src/applications/herald/controller/HeraldNewController.php
index e65c322f71..41ed03cf4b 100644
--- a/src/applications/herald/controller/HeraldNewController.php
+++ b/src/applications/herald/controller/HeraldNewController.php
@@ -1,197 +1,202 @@
<?php
final class HeraldNewController extends HeraldController {
public function processRequest() {
$request = $this->getRequest();
$user = $request->getUser();
$content_type_map = HeraldAdapter::getEnabledAdapterMap($user);
$rule_type_map = HeraldRuleTypeConfig::getRuleTypeMap();
$errors = array();
$e_type = null;
$e_rule = null;
$step = 0;
if ($request->isFormPost()) {
$step = $request->getInt('step');
$content_type = $request->getStr('content_type');
if (empty($content_type_map[$content_type])) {
$errors[] = pht('You must choose a content type for this rule.');
$e_type = pht('Required');
$step = 0;
}
if (!$errors && $step > 1) {
$rule_type = $request->getStr('rule_type');
if (empty($rule_type_map[$rule_type])) {
$errors[] = pht('You must choose a rule type for this rule.');
$e_rule = pht('Required');
$step = 1;
}
}
if (!$errors && $step == 2) {
$uri = id(new PhutilURI('edit/'))
->setQueryParams(
array(
'content_type' => $content_type,
'rule_type' => $rule_type,
));
$uri = $this->getApplicationURI($uri);
return id(new AphrontRedirectResponse())->setURI($uri);
}
}
if ($errors) {
$errors = id(new AphrontErrorView())->setErrors($errors);
}
$form = id(new AphrontFormView())
->setUser($user)
->setAction($this->getApplicationURI('new/'));
$content_types = $this->renderContentTypeControl(
$content_type_map,
$e_type);
$rule_types = $this->renderRuleTypeControl(
$rule_type_map,
$e_rule);
switch ($step) {
case 0:
default:
$form
->addHiddenInput('step', 1)
->appendChild($content_types);
$cancel_text = null;
$cancel_uri = $this->getApplicationURI();
break;
case 1:
$form
->addHiddenInput('content_type', $request->getStr('content_type'))
->addHiddenInput('step', 2)
->appendChild(
id(new AphrontFormStaticControl())
->setLabel(pht('Rule for'))
->setValue(
phutil_tag(
'strong',
array(),
idx($content_type_map, $content_type))))
->appendChild($rule_types);
$cancel_text = pht('Back');
$cancel_uri = id(new PhutilURI('new/'))
->setQueryParams(
array(
'content_type' => $request->getStr('content_type'),
'step' => 1,
));
$cancel_uri = $this->getApplicationURI($cancel_uri);
break;
}
$form
->appendChild(
id(new AphrontFormSubmitControl())
->setValue(pht('Continue'))
->addCancelButton($cancel_uri, $cancel_text));
$form_box = id(new PHUIObjectBoxView())
->setFormError($errors)
->setHeaderText(pht('Create Herald Rule'))
->setForm($form);
$crumbs = $this
->buildApplicationCrumbs()
->addTextCrumb(pht('Create Rule'));
return $this->buildApplicationPage(
array(
$crumbs,
$form_box,
),
array(
'title' => pht('Create Herald Rule'),
'device' => true,
));
}
private function renderContentTypeControl(array $content_type_map, $e_type) {
$request = $this->getRequest();
$radio = id(new AphrontFormRadioButtonControl())
->setLabel(pht('New Rule for'))
->setName('content_type')
->setValue($request->getStr('content_type'))
->setError($e_type);
foreach ($content_type_map as $value => $name) {
$adapter = HeraldAdapter::getAdapterForContentType($value);
$radio->addButton(
$value,
$name,
phutil_escape_html_newlines($adapter->getAdapterContentDescription()));
}
return $radio;
}
private function renderRuleTypeControl(array $rule_type_map, $e_rule) {
$request = $this->getRequest();
- // Reorder array to put "personal" first.
+ // Reorder array to put less powerful rules first.
$rule_type_map = array_select_keys(
$rule_type_map,
array(
HeraldRuleTypeConfig::RULE_TYPE_PERSONAL,
+ HeraldRuleTypeConfig::RULE_TYPE_OBJECT,
+ HeraldRuleTypeConfig::RULE_TYPE_GLOBAL,
)) + $rule_type_map;
+ // TODO: Enable this.
+ unset($rule_type_map[HeraldRuleTypeConfig::RULE_TYPE_OBJECT]);
+
list($can_global, $global_link) = $this->explainApplicationCapability(
HeraldCapabilityManageGlobalRules::CAPABILITY,
pht('You have permission to create and manage global rules.'),
pht('You do not have permission to create or manage global rules.'));
$captions = array(
HeraldRuleTypeConfig::RULE_TYPE_PERSONAL =>
pht(
'Personal rules notify you about events. You own them, but they can '.
'only affect you. Personal rules only trigger for objects you have '.
'permission to see.'),
HeraldRuleTypeConfig::RULE_TYPE_GLOBAL =>
array(
pht(
'Global rules notify anyone about events. Global rules can '.
'bypass access control policies and act on any object.'),
$global_link,
),
);
$radio = id(new AphrontFormRadioButtonControl())
->setLabel(pht('Type'))
->setName('rule_type')
->setValue($request->getStr('rule_type'))
->setError($e_rule);
foreach ($rule_type_map as $value => $name) {
$disabled = ($value == HeraldRuleTypeConfig::RULE_TYPE_GLOBAL) &&
(!$can_global);
$radio->addButton(
$value,
$name,
idx($captions, $value),
$disabled ? 'disabled' : null,
$disabled);
}
return $radio;
}
}
diff --git a/src/applications/herald/controller/HeraldRuleController.php b/src/applications/herald/controller/HeraldRuleController.php
index 85b8a61640..d4e48c95aa 100644
--- a/src/applications/herald/controller/HeraldRuleController.php
+++ b/src/applications/herald/controller/HeraldRuleController.php
@@ -1,581 +1,591 @@
<?php
final class HeraldRuleController extends HeraldController {
private $id;
private $filter;
public function willProcessRequest(array $data) {
$this->id = (int)idx($data, 'id');
}
public function processRequest() {
$request = $this->getRequest();
$user = $request->getUser();
$content_type_map = HeraldAdapter::getEnabledAdapterMap($user);
$rule_type_map = HeraldRuleTypeConfig::getRuleTypeMap();
if ($this->id) {
$id = $this->id;
$rule = id(new HeraldRuleQuery())
->setViewer($user)
->withIDs(array($id))
->requireCapabilities(
array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
))
->executeOne();
if (!$rule) {
return new Aphront404Response();
}
$cancel_uri = $this->getApplicationURI("rule/{$id}/");
} else {
$rule = new HeraldRule();
$rule->setAuthorPHID($user->getPHID());
$rule->setMustMatchAll(1);
$content_type = $request->getStr('content_type');
$rule->setContentType($content_type);
$rule_type = $request->getStr('rule_type');
if (!isset($rule_type_map[$rule_type])) {
$rule_type = HeraldRuleTypeConfig::RULE_TYPE_PERSONAL;
}
$rule->setRuleType($rule_type);
$cancel_uri = $this->getApplicationURI();
}
- if ($rule->getRuleType() == HeraldRuleTypeConfig::RULE_TYPE_GLOBAL) {
+ if ($rule->isGlobalRule()) {
$this->requireApplicationCapability(
HeraldCapabilityManageGlobalRules::CAPABILITY);
}
$adapter = HeraldAdapter::getAdapterForContentType($rule->getContentType());
$local_version = id(new HeraldRule())->getConfigVersion();
if ($rule->getConfigVersion() > $local_version) {
throw new Exception(
"This rule was created with a newer version of Herald. You can not ".
"view or edit it in this older version. Upgrade your Phabricator ".
"deployment.");
}
// Upgrade rule version to our version, since we might add newly-defined
// conditions, etc.
$rule->setConfigVersion($local_version);
$rule_conditions = $rule->loadConditions();
$rule_actions = $rule->loadActions();
$rule->attachConditions($rule_conditions);
$rule->attachActions($rule_actions);
$e_name = true;
$errors = array();
if ($request->isFormPost() && $request->getStr('save')) {
list($e_name, $errors) = $this->saveRule($adapter, $rule, $request);
if (!$errors) {
$id = $rule->getID();
$uri = $this->getApplicationURI("rule/{$id}/");
return id(new AphrontRedirectResponse())->setURI($uri);
}
}
if ($errors) {
$error_view = new AphrontErrorView();
$error_view->setTitle(pht('Form Errors'));
$error_view->setErrors($errors);
} else {
$error_view = null;
}
$must_match_selector = $this->renderMustMatchSelector($rule);
$repetition_selector = $this->renderRepetitionSelector($rule, $adapter);
$handles = $this->loadHandlesForRule($rule);
require_celerity_resource('herald-css');
$content_type_name = $content_type_map[$rule->getContentType()];
$rule_type_name = $rule_type_map[$rule->getRuleType()];
$form = id(new AphrontFormView())
->setUser($user)
->setID('herald-rule-edit-form')
->addHiddenInput('content_type', $rule->getContentType())
->addHiddenInput('rule_type', $rule->getRuleType())
->addHiddenInput('save', 1)
->appendChild(
// Build this explicitly (instead of using addHiddenInput())
// so we can add a sigil to it.
javelin_tag(
'input',
array(
'type' => 'hidden',
'name' => 'rule',
'sigil' => 'rule',
)))
->appendChild(
id(new AphrontFormTextControl())
->setLabel(pht('Rule Name'))
->setName('name')
->setError($e_name)
->setValue($rule->getName()));
$form
->appendChild(
id(new AphrontFormMarkupControl())
->setValue(pht(
"This %s rule triggers for %s.",
phutil_tag('strong', array(), $rule_type_name),
phutil_tag('strong', array(), $content_type_name))))
->appendChild(
id(new AphrontFormInsetView())
->setTitle(pht('Conditions'))
->setRightButton(javelin_tag(
'a',
array(
'href' => '#',
'class' => 'button green',
'sigil' => 'create-condition',
'mustcapture' => true
),
pht('New Condition')))
->setDescription(
pht('When %s these conditions are met:', $must_match_selector))
->setContent(javelin_tag(
'table',
array(
'sigil' => 'rule-conditions',
'class' => 'herald-condition-table'
),
'')))
->appendChild(
id(new AphrontFormInsetView())
->setTitle(pht('Action'))
->setRightButton(javelin_tag(
'a',
array(
'href' => '#',
'class' => 'button green',
'sigil' => 'create-action',
'mustcapture' => true,
),
pht('New Action')))
->setDescription(pht(
'Take these actions %s this rule matches:',
$repetition_selector))
->setContent(javelin_tag(
'table',
array(
'sigil' => 'rule-actions',
'class' => 'herald-action-table',
),
'')))
->appendChild(
id(new AphrontFormSubmitControl())
->setValue(pht('Save Rule'))
->addCancelButton($cancel_uri));
$this->setupEditorBehavior($rule, $handles, $adapter);
$title = $rule->getID()
? pht('Edit Herald Rule')
: pht('Create Herald Rule');
$form_box = id(new PHUIObjectBoxView())
->setHeaderText($title)
->setFormError($error_view)
->setForm($form);
$crumbs = $this
->buildApplicationCrumbs()
->addTextCrumb($title);
return $this->buildApplicationPage(
array(
$crumbs,
$form_box,
),
array(
'title' => pht('Edit Rule'),
'device' => true,
));
}
private function saveRule(HeraldAdapter $adapter, $rule, $request) {
$rule->setName($request->getStr('name'));
$match_all = ($request->getStr('must_match') == 'all');
$rule->setMustMatchAll((int)$match_all);
$repetition_policy_param = $request->getStr('repetition_policy');
$rule->setRepetitionPolicy(
HeraldRepetitionPolicyConfig::toInt($repetition_policy_param));
$e_name = true;
$errors = array();
if (!strlen($rule->getName())) {
$e_name = pht("Required");
$errors[] = pht("Rule must have a name.");
}
$data = json_decode($request->getStr('rule'), true);
if (!is_array($data) ||
!$data['conditions'] ||
!$data['actions']) {
throw new Exception("Failed to decode rule data.");
}
$conditions = array();
foreach ($data['conditions'] as $condition) {
if ($condition === null) {
// We manage this as a sparse array on the client, so may receive
// NULL if conditions have been removed.
continue;
}
$obj = new HeraldCondition();
$obj->setFieldName($condition[0]);
$obj->setFieldCondition($condition[1]);
if (is_array($condition[2])) {
$obj->setValue(array_keys($condition[2]));
} else {
$obj->setValue($condition[2]);
}
try {
$adapter->willSaveCondition($obj);
} catch (HeraldInvalidConditionException $ex) {
$errors[] = $ex->getMessage();
}
$conditions[] = $obj;
}
$actions = array();
foreach ($data['actions'] as $action) {
if ($action === null) {
// Sparse on the client; removals can give us NULLs.
continue;
}
if (!isset($action[1])) {
// Legitimate for any action which doesn't need a target, like
// "Do nothing".
$action[1] = null;
}
$obj = new HeraldAction();
$obj->setAction($action[0]);
$obj->setTarget($action[1]);
try {
$adapter->willSaveAction($rule, $obj);
} catch (HeraldInvalidActionException $ex) {
$errors[] = $ex;
}
$actions[] = $obj;
}
$rule->attachConditions($conditions);
$rule->attachActions($actions);
if (!$errors) {
try {
$edit_action = $rule->getID() ? 'edit' : 'create';
$rule->openTransaction();
$rule->save();
$rule->saveConditions($conditions);
$rule->saveActions($actions);
$rule->logEdit($request->getUser()->getPHID(), $edit_action);
$rule->saveTransaction();
} catch (AphrontQueryDuplicateKeyException $ex) {
$e_name = pht("Not Unique");
$errors[] = pht("Rule name is not unique. Choose a unique name.");
}
}
return array($e_name, $errors);
}
private function setupEditorBehavior(
HeraldRule $rule,
array $handles,
HeraldAdapter $adapter) {
$serial_conditions = array(
array('default', 'default', ''),
);
if ($rule->getConditions()) {
$serial_conditions = array();
foreach ($rule->getConditions() as $condition) {
$value = $condition->getValue();
if (is_array($value)) {
$value_map = array();
foreach ($value as $k => $fbid) {
$value_map[$fbid] = $handles[$fbid]->getName();
}
$value = $value_map;
}
$serial_conditions[] = array(
$condition->getFieldName(),
$condition->getFieldCondition(),
$value,
);
}
}
$serial_actions = array(
array('default', ''),
);
if ($rule->getActions()) {
$serial_actions = array();
foreach ($rule->getActions() as $action) {
switch ($action->getAction()) {
case HeraldAdapter::ACTION_FLAG:
case HeraldAdapter::ACTION_BLOCK:
$current_value = $action->getTarget();
break;
default:
$target_map = array();
foreach ((array)$action->getTarget() as $fbid) {
$target_map[$fbid] = $handles[$fbid]->getName();
}
$current_value = $target_map;
break;
}
$serial_actions[] = array(
$action->getAction(),
$current_value,
);
}
}
$all_rules = $this->loadRulesThisRuleMayDependUpon($rule);
$all_rules = mpull($all_rules, 'getName', 'getID');
asort($all_rules);
$all_fields = $adapter->getFieldNameMap();
$all_conditions = $adapter->getConditionNameMap();
$all_actions = $adapter->getActionNameMap($rule->getRuleType());
$fields = $adapter->getFields();
$field_map = array_select_keys($all_fields, $fields);
$actions = $adapter->getActions($rule->getRuleType());
$action_map = array_select_keys($all_actions, $actions);
$config_info = array();
$config_info['fields'] = $field_map;
$config_info['conditions'] = $all_conditions;
$config_info['actions'] = $action_map;
foreach ($config_info['fields'] as $field => $name) {
$field_conditions = $adapter->getConditionsForField($field);
$config_info['conditionMap'][$field] = $field_conditions;
}
foreach ($config_info['fields'] as $field => $fname) {
foreach ($config_info['conditionMap'][$field] as $condition) {
$value_type = $adapter->getValueTypeForFieldAndCondition(
$field,
$condition);
$config_info['values'][$field][$condition] = $value_type;
}
}
$config_info['rule_type'] = $rule->getRuleType();
foreach ($config_info['actions'] as $action => $name) {
$config_info['targets'][$action] = $adapter->getValueTypeForAction(
$action,
$rule->getRuleType());
}
Javelin::initBehavior(
'herald-rule-editor',
array(
'root' => 'herald-rule-edit-form',
'conditions' => (object)$serial_conditions,
'actions' => (object)$serial_actions,
'select' => array(
HeraldAdapter::VALUE_CONTENT_SOURCE => array(
'options' => PhabricatorContentSource::getSourceNameMap(),
'default' => PhabricatorContentSource::SOURCE_WEB,
),
HeraldAdapter::VALUE_FLAG_COLOR => array(
'options' => PhabricatorFlagColor::getColorNameMap(),
'default' => PhabricatorFlagColor::COLOR_BLUE,
),
HeraldPreCommitRefAdapter::VALUE_REF_TYPE => array(
'options' => array(
PhabricatorRepositoryPushLog::REFTYPE_BRANCH
=> pht('branch (git/hg)'),
PhabricatorRepositoryPushLog::REFTYPE_TAG
=> pht('tag (git)'),
PhabricatorRepositoryPushLog::REFTYPE_BOOKMARK
=> pht('bookmark (hg)'),
),
'default' => PhabricatorRepositoryPushLog::REFTYPE_BRANCH,
),
HeraldPreCommitRefAdapter::VALUE_REF_CHANGE => array(
'options' => array(
PhabricatorRepositoryPushLog::CHANGEFLAG_ADD =>
pht('change creates ref'),
PhabricatorRepositoryPushLog::CHANGEFLAG_DELETE =>
pht('change deletes ref'),
PhabricatorRepositoryPushLog::CHANGEFLAG_REWRITE =>
pht('change rewrites ref'),
PhabricatorRepositoryPushLog::CHANGEFLAG_DANGEROUS =>
pht('dangerous change'),
),
'default' => PhabricatorRepositoryPushLog::CHANGEFLAG_ADD,
),
),
'template' => $this->buildTokenizerTemplates() + array(
'rules' => $all_rules,
),
'author' => array($rule->getAuthorPHID() =>
$handles[$rule->getAuthorPHID()]->getName()),
'info' => $config_info,
));
}
private function loadHandlesForRule($rule) {
$phids = array();
foreach ($rule->getActions() as $action) {
if (!is_array($action->getTarget())) {
continue;
}
foreach ($action->getTarget() as $target) {
$target = (array)$target;
foreach ($target as $phid) {
$phids[] = $phid;
}
}
}
foreach ($rule->getConditions() as $condition) {
$value = $condition->getValue();
if (is_array($value)) {
foreach ($value as $phid) {
$phids[] = $phid;
}
}
}
$phids[] = $rule->getAuthorPHID();
return $this->loadViewerHandles($phids);
}
/**
* Render the selector for the "When (all of | any of) these conditions are
* met:" element.
*/
private function renderMustMatchSelector($rule) {
return AphrontFormSelectControl::renderSelectTag(
$rule->getMustMatchAll() ? 'all' : 'any',
array(
'all' => pht('all of'),
'any' => pht('any of'),
),
array(
'name' => 'must_match',
));
}
/**
* Render the selector for "Take these actions (every time | only the first
* time) this rule matches..." element.
*/
private function renderRepetitionSelector($rule, HeraldAdapter $adapter) {
$repetition_policy = HeraldRepetitionPolicyConfig::toString(
$rule->getRepetitionPolicy());
$repetition_options = $adapter->getRepetitionOptions();
$repetition_names = HeraldRepetitionPolicyConfig::getMap();
$repetition_map = array_select_keys($repetition_names, $repetition_options);
if (count($repetition_map) < 2) {
return head($repetition_names);
} else {
return AphrontFormSelectControl::renderSelectTag(
$repetition_policy,
$repetition_map,
array(
'name' => 'repetition_policy',
));
}
}
protected function buildTokenizerTemplates() {
$template = new AphrontTokenizerTemplateView();
$template = $template->render();
return array(
'source' => array(
'email' => '/typeahead/common/mailable/',
'user' => '/typeahead/common/accounts/',
'repository' => '/typeahead/common/repositories/',
'package' => '/typeahead/common/packages/',
'project' => '/typeahead/common/projects/',
'userorproject' => '/typeahead/common/accountsorprojects/',
'buildplan' => '/typeahead/common/buildplans/',
),
'markup' => $template,
);
}
/**
* Load rules for the "Another Herald rule..." condition dropdown, which
* allows one rule to depend upon the success or failure of another rule.
*/
private function loadRulesThisRuleMayDependUpon(HeraldRule $rule) {
$viewer = $this->getRequest()->getUser();
// Any rule can depend on a global rule.
$all_rules = id(new HeraldRuleQuery())
->setViewer($viewer)
->withRuleTypes(array(HeraldRuleTypeConfig::RULE_TYPE_GLOBAL))
->withContentTypes(array($rule->getContentType()))
->execute();
- if ($rule->getRuleType() == HeraldRuleTypeConfig::RULE_TYPE_PERSONAL) {
+ if ($rule->isObjectRule()) {
+ // Object rules may depend on other rules for the same object.
+ $all_rules += id(new HeraldRuleQuery())
+ ->setViewer($viewer)
+ ->withRuleTypes(array(HeraldRuleTypeConfig::RULE_TYPE_OBJECT))
+ ->withContentTypes(array($rule->getContentType()))
+ ->withTriggerObjectPHIDs(array($rule->getTriggerObjectPHID()))
+ ->execute();
+ }
+
+ if ($rule->isPersonalRule()) {
// Personal rules may depend upon your other personal rules.
$all_rules += id(new HeraldRuleQuery())
->setViewer($viewer)
->withRuleTypes(array(HeraldRuleTypeConfig::RULE_TYPE_PERSONAL))
->withContentTypes(array($rule->getContentType()))
->withAuthorPHIDs(array($rule->getAuthorPHID()))
->execute();
}
// A rule can not depend upon itself.
unset($all_rules[$rule->getID()]);
return $all_rules;
}
}
diff --git a/src/applications/herald/engine/HeraldEngine.php b/src/applications/herald/engine/HeraldEngine.php
index 685285b0b7..d3d3899b98 100644
--- a/src/applications/herald/engine/HeraldEngine.php
+++ b/src/applications/herald/engine/HeraldEngine.php
@@ -1,408 +1,434 @@
<?php
final class HeraldEngine {
protected $rules = array();
protected $results = array();
protected $stack = array();
protected $activeRule = null;
protected $fieldCache = array();
protected $object = null;
private $dryRun;
public function setDryRun($dry_run) {
$this->dryRun = $dry_run;
return $this;
}
public function getDryRun() {
return $this->dryRun;
}
public function getRule($id) {
return idx($this->rules, $id);
}
public function loadRulesForAdapter(HeraldAdapter $adapter) {
return id(new HeraldRuleQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withDisabled(false)
->withContentTypes(array($adapter->getAdapterContentType()))
->needConditionsAndActions(true)
->needAppliedToPHIDs(array($adapter->getPHID()))
->needValidateAuthors(true)
->execute();
}
public static function loadAndApplyRules(HeraldAdapter $adapter) {
$engine = new HeraldEngine();
$rules = $engine->loadRulesForAdapter($adapter);
$effects = $engine->applyRules($rules, $adapter);
$engine->applyEffects($effects, $adapter, $rules);
return $engine->getTranscript();
}
public function applyRules(array $rules, HeraldAdapter $object) {
assert_instances_of($rules, 'HeraldRule');
$t_start = microtime(true);
$rules = mpull($rules, null, 'getID');
$this->transcript = new HeraldTranscript();
$this->transcript->setObjectPHID((string)$object->getPHID());
$this->fieldCache = array();
$this->results = array();
$this->rules = $rules;
$this->object = $object;
$effects = array();
foreach ($rules as $id => $rule) {
$this->stack = array();
try {
if (!$this->getDryRun() &&
($rule->getRepetitionPolicy() ==
HeraldRepetitionPolicyConfig::FIRST) &&
$rule->getRuleApplied($object->getPHID())) {
// This is not a dry run, and this rule is only supposed to be
// applied a single time, and it's already been applied...
// That means automatic failure.
$xscript = id(new HeraldRuleTranscript())
->setRuleID($id)
->setResult(false)
->setRuleName($rule->getName())
->setRuleOwner($rule->getAuthorPHID())
->setReason(
"This rule is only supposed to be repeated a single time, ".
"and it has already been applied.");
$this->transcript->addRuleTranscript($xscript);
$rule_matches = false;
} else {
$rule_matches = $this->doesRuleMatch($rule, $object);
}
} catch (HeraldRecursiveConditionsException $ex) {
$names = array();
foreach ($this->stack as $rule_id => $ignored) {
$names[] = '"'.$rules[$rule_id]->getName().'"';
}
$names = implode(', ', $names);
foreach ($this->stack as $rule_id => $ignored) {
$xscript = new HeraldRuleTranscript();
$xscript->setRuleID($rule_id);
$xscript->setResult(false);
$xscript->setReason(
"Rules {$names} are recursively dependent upon one another! ".
"Don't do this! You have formed an unresolvable cycle in the ".
"dependency graph!");
$xscript->setRuleName($rules[$rule_id]->getName());
$xscript->setRuleOwner($rules[$rule_id]->getAuthorPHID());
$this->transcript->addRuleTranscript($xscript);
}
$rule_matches = false;
}
$this->results[$id] = $rule_matches;
if ($rule_matches) {
foreach ($this->getRuleEffects($rule, $object) as $effect) {
$effects[] = $effect;
}
}
}
$object_transcript = new HeraldObjectTranscript();
$object_transcript->setPHID($object->getPHID());
$object_transcript->setName($object->getHeraldName());
$object_transcript->setType($object->getAdapterContentType());
$object_transcript->setFields($this->fieldCache);
$this->transcript->setObjectTranscript($object_transcript);
$t_end = microtime(true);
$this->transcript->setDuration($t_end - $t_start);
return $effects;
}
public function applyEffects(
array $effects,
HeraldAdapter $adapter,
array $rules) {
assert_instances_of($effects, 'HeraldEffect');
assert_instances_of($rules, 'HeraldRule');
$this->transcript->setDryRun((int)$this->getDryRun());
if ($this->getDryRun()) {
$xscripts = array();
foreach ($effects as $effect) {
$xscripts[] = new HeraldApplyTranscript(
$effect,
false,
pht('This was a dry run, so no actions were actually taken.'));
}
} else {
$xscripts = $adapter->applyHeraldEffects($effects);
}
assert_instances_of($xscripts, 'HeraldApplyTranscript');
foreach ($xscripts as $apply_xscript) {
$this->transcript->addApplyTranscript($apply_xscript);
}
// For dry runs, don't mark the rule as having applied to the object.
if ($this->getDryRun()) {
return;
}
$rules = mpull($rules, null, 'getID');
$applied_ids = array();
$first_policy = HeraldRepetitionPolicyConfig::toInt(
HeraldRepetitionPolicyConfig::FIRST);
// Mark all the rules that have had their effects applied as having been
// executed for the current object.
$rule_ids = mpull($xscripts, 'getRuleID');
foreach ($rule_ids as $rule_id) {
if (!$rule_id) {
// Some apply transcripts are purely informational and not associated
// with a rule, e.g. carryover emails from earlier revisions.
continue;
}
$rule = idx($rules, $rule_id);
if (!$rule) {
continue;
}
if ($rule->getRepetitionPolicy() == $first_policy) {
$applied_ids[] = $rule_id;
}
}
if ($applied_ids) {
$conn_w = id(new HeraldRule())->establishConnection('w');
$sql = array();
foreach ($applied_ids as $id) {
$sql[] = qsprintf(
$conn_w,
'(%s, %d)',
$adapter->getPHID(),
$id);
}
queryfx(
$conn_w,
'INSERT IGNORE INTO %T (phid, ruleID) VALUES %Q',
HeraldRule::TABLE_RULE_APPLIED,
implode(', ', $sql));
}
}
public function getTranscript() {
$this->transcript->save();
return $this->transcript;
}
public function doesRuleMatch(
HeraldRule $rule,
HeraldAdapter $object) {
$id = $rule->getID();
if (isset($this->results[$id])) {
// If we've already evaluated this rule because another rule depends
// on it, we don't need to reevaluate it.
return $this->results[$id];
}
if (isset($this->stack[$id])) {
// We've recursed, fail all of the rules on the stack. This happens when
// there's a dependency cycle with "Rule conditions match for rule ..."
// conditions.
foreach ($this->stack as $rule_id => $ignored) {
$this->results[$rule_id] = false;
}
throw new HeraldRecursiveConditionsException();
}
$this->stack[$id] = true;
$all = $rule->getMustMatchAll();
$conditions = $rule->getConditions();
$result = null;
$local_version = id(new HeraldRule())->getConfigVersion();
if ($rule->getConfigVersion() > $local_version) {
$reason = pht(
"Rule could not be processed, it was created with a newer version ".
"of Herald.");
$result = false;
} else if (!$conditions) {
$reason = pht(
"Rule failed automatically because it has no conditions.");
$result = false;
} else if (!$rule->hasValidAuthor()) {
$reason = pht(
"Rule failed automatically because its owner is invalid ".
"or disabled.");
$result = false;
} else if (!$this->canAuthorViewObject($rule, $object)) {
$reason = pht(
"Rule failed automatically because it is a personal rule and its ".
"owner can not see the object.");
$result = false;
+ } else if (!$this->canRuleApplyToObject($rule, $object)) {
+ $reason = pht(
+ "Rule failed automatically because it is an object rule which is ".
+ "not relevant for this object.");
+ $result = false;
} else {
foreach ($conditions as $condition) {
$match = $this->doesConditionMatch($rule, $condition, $object);
if (!$all && $match) {
$reason = "Any condition matched.";
$result = true;
break;
}
if ($all && !$match) {
$reason = "Not all conditions matched.";
$result = false;
break;
}
}
if ($result === null) {
if ($all) {
$reason = "All conditions matched.";
$result = true;
} else {
$reason = "No conditions matched.";
$result = false;
}
}
}
$rule_transcript = new HeraldRuleTranscript();
$rule_transcript->setRuleID($rule->getID());
$rule_transcript->setResult($result);
$rule_transcript->setReason($reason);
$rule_transcript->setRuleName($rule->getName());
$rule_transcript->setRuleOwner($rule->getAuthorPHID());
$this->transcript->addRuleTranscript($rule_transcript);
return $result;
}
protected function doesConditionMatch(
HeraldRule $rule,
HeraldCondition $condition,
HeraldAdapter $object) {
$object_value = $this->getConditionObjectValue($condition, $object);
$test_value = $condition->getValue();
$cond = $condition->getFieldCondition();
$transcript = new HeraldConditionTranscript();
$transcript->setRuleID($rule->getID());
$transcript->setConditionID($condition->getID());
$transcript->setFieldName($condition->getFieldName());
$transcript->setCondition($cond);
$transcript->setTestValue($test_value);
try {
$result = $object->doesConditionMatch(
$this,
$rule,
$condition,
$object_value);
} catch (HeraldInvalidConditionException $ex) {
$result = false;
$transcript->setNote($ex->getMessage());
}
$transcript->setResult($result);
$this->transcript->addConditionTranscript($transcript);
return $result;
}
protected function getConditionObjectValue(
HeraldCondition $condition,
HeraldAdapter $object) {
$field = $condition->getFieldName();
return $this->getObjectFieldValue($field);
}
public function getObjectFieldValue($field) {
if (isset($this->fieldCache[$field])) {
return $this->fieldCache[$field];
}
$result = $this->object->getHeraldField($field);
$this->fieldCache[$field] = $result;
return $result;
}
protected function getRuleEffects(
HeraldRule $rule,
HeraldAdapter $object) {
$effects = array();
foreach ($rule->getActions() as $action) {
$effect = new HeraldEffect();
$effect->setObjectPHID($object->getPHID());
$effect->setAction($action->getAction());
$effect->setTarget($action->getTarget());
$effect->setRuleID($rule->getID());
$effect->setRulePHID($rule->getPHID());
$name = $rule->getName();
$id = $rule->getID();
$effect->setReason(
pht(
'Conditions were met for %s',
"H{$id} {$name}"));
$effects[] = $effect;
}
return $effects;
}
private function canAuthorViewObject(
HeraldRule $rule,
HeraldAdapter $adapter) {
- // Authorship is irrelevant for global rules.
- if ($rule->isGlobalRule()) {
+ // Authorship is irrelevant for global rules and object rules.
+ if ($rule->isGlobalRule() || $rule->isObjectRule()) {
return true;
}
// The author must be able to create rules for the adapter's content type.
// In particular, this means that the application must be installed and
// accessible to the user. For example, if a user writes a Differential
// rule and then loses access to Differential, this disables the rule.
$enabled = HeraldAdapter::getEnabledAdapterMap($rule->getAuthor());
if (empty($enabled[$adapter->getAdapterContentType()])) {
return false;
}
// Finally, the author must be able to see the object itself. You can't
// write a personal rule that CC's you on revisions you wouldn't otherwise
// be able to see, for example.
$object = $adapter->getObject();
return PhabricatorPolicyFilter::hasCapability(
$rule->getAuthor(),
$object,
PhabricatorPolicyCapability::CAN_VIEW);
}
+ private function canRuleApplyToObject(
+ HeraldRule $rule,
+ HeraldAdapter $adapter) {
+
+ // Rules which are not object rules can apply to anything.
+ if (!$rule->isObjectRule()) {
+ return true;
+ }
+
+ $trigger_phid = $rule->getTriggerObjectPHID();
+ $object_phid = $adapter->getPHID();
+
+ if ($trigger_phid == $object_phid) {
+ return true;
+ }
+
+ // TODO: We should also handle projects.
+
+ return false;
+ }
+
}
diff --git a/src/applications/herald/query/HeraldRuleQuery.php b/src/applications/herald/query/HeraldRuleQuery.php
index 2b29248745..c509c62023 100644
--- a/src/applications/herald/query/HeraldRuleQuery.php
+++ b/src/applications/herald/query/HeraldRuleQuery.php
@@ -1,237 +1,279 @@
<?php
final class HeraldRuleQuery
extends PhabricatorCursorPagedPolicyAwareQuery {
private $ids;
private $phids;
private $authorPHIDs;
private $ruleTypes;
private $contentTypes;
private $disabled;
+ private $triggerObjectPHIDs;
private $needConditionsAndActions;
private $needAppliedToPHIDs;
private $needValidateAuthors;
public function withIDs(array $ids) {
$this->ids = $ids;
return $this;
}
public function withPHIDs(array $phids) {
$this->phids = $phids;
return $this;
}
public function withAuthorPHIDs(array $author_phids) {
$this->authorPHIDs = $author_phids;
return $this;
}
public function withRuleTypes(array $types) {
$this->ruleTypes = $types;
return $this;
}
public function withContentTypes(array $types) {
$this->contentTypes = $types;
return $this;
}
public function withExecutableRules($executable) {
$this->executable = $executable;
return $this;
}
public function withDisabled($disabled) {
$this->disabled = $disabled;
return $this;
}
+ public function withTriggerObjectPHIDs(array $phids) {
+ $this->triggerObjectPHIDs = $phids;
+ return $this;
+ }
+
public function needConditionsAndActions($need) {
$this->needConditionsAndActions = $need;
return $this;
}
public function needAppliedToPHIDs(array $phids) {
$this->needAppliedToPHIDs = $phids;
return $this;
}
public function needValidateAuthors($need) {
$this->needValidateAuthors = $need;
return $this;
}
public function loadPage() {
$table = new HeraldRule();
$conn_r = $table->establishConnection('r');
$data = queryfx_all(
$conn_r,
'SELECT rule.* FROM %T rule %Q %Q %Q',
$table->getTableName(),
$this->buildWhereClause($conn_r),
$this->buildOrderClause($conn_r),
$this->buildLimitClause($conn_r));
return $table->loadAllFromArray($data);
}
public function willFilterPage(array $rules) {
$rule_ids = mpull($rules, 'getID');
// Filter out any rules that have invalid adapters, or have adapters the
// viewer isn't permitted to see or use (for example, Differential rules
// if the user can't use Differential or Differential is not installed).
$types = HeraldAdapter::getEnabledAdapterMap($this->getViewer());
foreach ($rules as $key => $rule) {
if (empty($types[$rule->getContentType()])) {
$this->didRejectResult($rule);
unset($rules[$key]);
}
}
if ($this->needValidateAuthors) {
$this->validateRuleAuthors($rules);
}
if ($this->needConditionsAndActions) {
$conditions = id(new HeraldCondition())->loadAllWhere(
'ruleID IN (%Ld)',
$rule_ids);
$conditions = mgroup($conditions, 'getRuleID');
$actions = id(new HeraldAction())->loadAllWhere(
'ruleID IN (%Ld)',
$rule_ids);
$actions = mgroup($actions, 'getRuleID');
foreach ($rules as $rule) {
$rule->attachActions(idx($actions, $rule->getID(), array()));
$rule->attachConditions(idx($conditions, $rule->getID(), array()));
}
}
if ($this->needAppliedToPHIDs) {
$conn_r = id(new HeraldRule())->establishConnection('r');
$applied = queryfx_all(
$conn_r,
'SELECT * FROM %T WHERE ruleID IN (%Ld) AND phid IN (%Ls)',
HeraldRule::TABLE_RULE_APPLIED,
$rule_ids,
$this->needAppliedToPHIDs);
$map = array();
foreach ($applied as $row) {
$map[$row['ruleID']][$row['phid']] = true;
}
foreach ($rules as $rule) {
foreach ($this->needAppliedToPHIDs as $phid) {
$rule->setRuleApplied(
$phid,
isset($map[$rule->getID()][$phid]));
}
}
}
+ $object_phids = array();
+ foreach ($rules as $rule) {
+ if ($rule->isObjectRule()) {
+ $object_phids[] = $rule->getTriggerObjectPHID();
+ }
+ }
+
+ if ($object_phids) {
+ $objects = id(new PhabricatorObjectQuery())
+ ->setParentQuery($this)
+ ->setViewer($this->getViewer())
+ ->withPHIDs($object_phids)
+ ->execute();
+ $objects = mpull($objects, null, 'getPHID');
+ } else {
+ $objects = array();
+ }
+
+ foreach ($rules as $key => $rule) {
+ if ($rule->isObjectRule()) {
+ $object = idx($objects, $rule->getTriggerObjectPHID());
+ if (!$object) {
+ unset($rules[$key]);
+ continue;
+ }
+ $rule->attachTriggerObject($object);
+ }
+ }
+
return $rules;
}
private function buildWhereClause($conn_r) {
$where = array();
if ($this->ids) {
$where[] = qsprintf(
$conn_r,
'rule.id IN (%Ld)',
$this->ids);
}
if ($this->phids) {
$where[] = qsprintf(
$conn_r,
'rule.phid IN (%Ls)',
$this->phids);
}
if ($this->authorPHIDs) {
$where[] = qsprintf(
$conn_r,
'rule.authorPHID IN (%Ls)',
$this->authorPHIDs);
}
if ($this->ruleTypes) {
$where[] = qsprintf(
$conn_r,
'rule.ruleType IN (%Ls)',
$this->ruleTypes);
}
if ($this->contentTypes) {
$where[] = qsprintf(
$conn_r,
'rule.contentType IN (%Ls)',
$this->contentTypes);
}
if ($this->disabled !== null) {
$where[] = qsprintf(
$conn_r,
'rule.isDisabled = %d',
(int)$this->disabled);
}
+ if ($this->triggerObjectPHIDs) {
+ $where[] = qsprintf(
+ $conn_r,
+ 'rule.triggerObjectPHID IN (%Ls)',
+ $this->triggerObjectPHIDs);
+ }
+
$where[] = $this->buildPagingClause($conn_r);
return $this->formatWhereClause($where);
}
private function validateRuleAuthors(array $rules) {
- // "Global" rules always have valid authors.
+ // "Global" and "Object" rules always have valid authors.
foreach ($rules as $key => $rule) {
- if ($rule->isGlobalRule()) {
+ if ($rule->isGlobalRule() || $rule->isObjectRule()) {
$rule->attachValidAuthor(true);
unset($rules[$key]);
continue;
}
}
if (!$rules) {
return;
}
// For personal rules, the author needs to exist and not be disabled.
$user_phids = mpull($rules, 'getAuthorPHID');
$users = id(new PhabricatorPeopleQuery())
->setViewer($this->getViewer())
->withPHIDs($user_phids)
->execute();
$users = mpull($users, null, 'getPHID');
foreach ($rules as $key => $rule) {
$author_phid = $rule->getAuthorPHID();
if (empty($users[$author_phid])) {
$rule->attachValidAuthor(false);
continue;
}
if (!$users[$author_phid]->isUserActivated()) {
$rule->attachValidAuthor(false);
continue;
}
$rule->attachValidAuthor(true);
$rule->attachAuthor($users[$author_phid]);
}
}
public function getQueryApplicationClass() {
return 'PhabricatorApplicationHerald';
}
}
diff --git a/src/applications/herald/storage/HeraldRule.php b/src/applications/herald/storage/HeraldRule.php
index b7e061c520..a441dab770 100644
--- a/src/applications/herald/storage/HeraldRule.php
+++ b/src/applications/herald/storage/HeraldRule.php
@@ -1,235 +1,254 @@
<?php
final class HeraldRule extends HeraldDAO
implements
PhabricatorFlaggableInterface,
PhabricatorPolicyInterface {
const TABLE_RULE_APPLIED = 'herald_ruleapplied';
protected $name;
protected $authorPHID;
protected $contentType;
protected $mustMatchAll;
protected $repetitionPolicy;
protected $ruleType;
protected $isDisabled = 0;
+ protected $triggerObjectPHID;
- protected $configVersion = 21;
+ protected $configVersion = 22;
// phids for which this rule has been applied
private $ruleApplied = self::ATTACHABLE;
private $validAuthor = self::ATTACHABLE;
private $author = self::ATTACHABLE;
private $conditions;
private $actions;
+ private $triggerObject = self::ATTACHABLE;
public function getConfiguration() {
return array(
self::CONFIG_AUX_PHID => true,
) + parent::getConfiguration();
}
public function generatePHID() {
return PhabricatorPHID::generateNewPHID(HeraldPHIDTypeRule::TYPECONST);
}
public function getRuleApplied($phid) {
return $this->assertAttachedKey($this->ruleApplied, $phid);
}
public function setRuleApplied($phid, $applied) {
if ($this->ruleApplied === self::ATTACHABLE) {
$this->ruleApplied = array();
}
$this->ruleApplied[$phid] = $applied;
return $this;
}
public function loadConditions() {
if (!$this->getID()) {
return array();
}
return id(new HeraldCondition())->loadAllWhere(
'ruleID = %d',
$this->getID());
}
public function attachConditions(array $conditions) {
assert_instances_of($conditions, 'HeraldCondition');
$this->conditions = $conditions;
return $this;
}
public function getConditions() {
// TODO: validate conditions have been attached.
return $this->conditions;
}
public function loadActions() {
if (!$this->getID()) {
return array();
}
return id(new HeraldAction())->loadAllWhere(
'ruleID = %d',
$this->getID());
}
public function attachActions(array $actions) {
// TODO: validate actions have been attached.
assert_instances_of($actions, 'HeraldAction');
$this->actions = $actions;
return $this;
}
public function getActions() {
return $this->actions;
}
public function loadEdits() {
if (!$this->getID()) {
return array();
}
$edits = id(new HeraldRuleEdit())->loadAllWhere(
'ruleID = %d ORDER BY dateCreated DESC',
$this->getID());
return $edits;
}
public function logEdit($editor_phid, $action) {
id(new HeraldRuleEdit())
->setRuleID($this->getID())
->setRuleName($this->getName())
->setEditorPHID($editor_phid)
->setAction($action)
->save();
}
public function saveConditions(array $conditions) {
assert_instances_of($conditions, 'HeraldCondition');
return $this->saveChildren(
id(new HeraldCondition())->getTableName(),
$conditions);
}
public function saveActions(array $actions) {
assert_instances_of($actions, 'HeraldAction');
return $this->saveChildren(
id(new HeraldAction())->getTableName(),
$actions);
}
protected function saveChildren($table_name, array $children) {
assert_instances_of($children, 'HeraldDAO');
if (!$this->getID()) {
throw new Exception("Save rule before saving children.");
}
foreach ($children as $child) {
$child->setRuleID($this->getID());
}
// TODO:
// $this->openTransaction();
queryfx(
$this->establishConnection('w'),
'DELETE FROM %T WHERE ruleID = %d',
$table_name,
$this->getID());
foreach ($children as $child) {
$child->save();
}
// $this->saveTransaction();
}
public function delete() {
-
-// TODO:
-// $this->openTransaction();
+ $this->openTransaction();
queryfx(
$this->establishConnection('w'),
'DELETE FROM %T WHERE ruleID = %d',
id(new HeraldCondition())->getTableName(),
$this->getID());
queryfx(
$this->establishConnection('w'),
'DELETE FROM %T WHERE ruleID = %d',
id(new HeraldAction())->getTableName(),
$this->getID());
- parent::delete();
-// $this->saveTransaction();
+ $result = parent::delete();
+ $this->saveTransaction();
+
+ return $result;
}
public function hasValidAuthor() {
return $this->assertAttached($this->validAuthor);
}
public function attachValidAuthor($valid) {
$this->validAuthor = $valid;
return $this;
}
public function getAuthor() {
return $this->assertAttached($this->author);
}
public function attachAuthor(PhabricatorUser $user) {
$this->author = $user;
return $this;
}
public function isGlobalRule() {
return ($this->getRuleType() === HeraldRuleTypeConfig::RULE_TYPE_GLOBAL);
}
public function isPersonalRule() {
return ($this->getRuleType() === HeraldRuleTypeConfig::RULE_TYPE_PERSONAL);
}
+ public function isObjectRule() {
+ return ($this->getRuleType() == HeraldRuleTypeConfig::RULE_TYPE_OBJECT);
+ }
+
+ public function attachTriggerObject($trigger_object) {
+ $this->triggerObject = $trigger_object;
+ return $this;
+ }
+
+ public function getTriggerObject() {
+ return $this->assertAttached($this->triggerObject);
+ }
+
/* -( PhabricatorPolicyInterface )----------------------------------------- */
public function getCapabilities() {
return array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
);
}
public function getPolicy($capability) {
if ($this->isGlobalRule()) {
switch ($capability) {
case PhabricatorPolicyCapability::CAN_VIEW:
return PhabricatorPolicies::POLICY_USER;
case PhabricatorPolicyCapability::CAN_EDIT:
$app = 'PhabricatorApplicationHerald';
$herald = PhabricatorApplication::getByClass($app);
$global = HeraldCapabilityManageGlobalRules::CAPABILITY;
return $herald->getPolicy($global);
}
+ } else if ($this->isObjectRule()) {
+ return $this->getTriggerObject()->getPolicy($capability);
} else {
return PhabricatorPolicies::POLICY_NOONE;
}
}
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
if ($this->isPersonalRule()) {
return ($viewer->getPHID() == $this->getAuthorPHID());
} else {
return false;
}
}
public function describeAutomaticCapability($capability) {
if ($this->isPersonalRule()) {
return pht("A personal rule's owner can always view and edit it.");
+ } else if ($this->isObjectRule()) {
+ return pht("Object rules inherit the policies of their objects.");
}
return null;
}
}
diff --git a/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php b/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php
index bec34235d7..404b505b7f 100644
--- a/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php
+++ b/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php
@@ -1,1857 +1,1861 @@
<?php
final class PhabricatorBuiltinPatchList extends PhabricatorSQLPatchList {
public function getNamespace() {
return 'phabricator';
}
private function getPatchPath($file) {
$root = dirname(phutil_get_library_root('phabricator'));
$path = $root.'/resources/sql/patches/'.$file;
// Make sure it exists.
Filesystem::readFile($path);
return $path;
}
public function getPatches() {
return array(
'db.audit' => array(
'type' => 'db',
'name' => 'audit',
'after' => array( /* First Patch */ ),
),
'db.calendar' => array(
'type' => 'db',
'name' => 'calendar',
),
'db.chatlog' => array(
'type' => 'db',
'name' => 'chatlog',
),
'db.conduit' => array(
'type' => 'db',
'name' => 'conduit',
),
'db.countdown' => array(
'type' => 'db',
'name' => 'countdown',
),
'db.daemon' => array(
'type' => 'db',
'name' => 'daemon',
),
'db.differential' => array(
'type' => 'db',
'name' => 'differential',
),
'db.draft' => array(
'type' => 'db',
'name' => 'draft',
),
'db.drydock' => array(
'type' => 'db',
'name' => 'drydock',
),
'db.feed' => array(
'type' => 'db',
'name' => 'feed',
),
'db.file' => array(
'type' => 'db',
'name' => 'file',
),
'db.flag' => array(
'type' => 'db',
'name' => 'flag',
),
'db.harbormaster' => array(
'type' => 'db',
'name' => 'harbormaster',
),
'db.herald' => array(
'type' => 'db',
'name' => 'herald',
),
'db.maniphest' => array(
'type' => 'db',
'name' => 'maniphest',
),
'db.meta_data' => array(
'type' => 'db',
'name' => 'meta_data',
),
'db.metamta' => array(
'type' => 'db',
'name' => 'metamta',
),
'db.oauth_server' => array(
'type' => 'db',
'name' => 'oauth_server',
),
'db.owners' => array(
'type' => 'db',
'name' => 'owners',
),
'db.pastebin' => array(
'type' => 'db',
'name' => 'pastebin',
),
'db.phame' => array(
'type' => 'db',
'name' => 'phame',
),
'db.phriction' => array(
'type' => 'db',
'name' => 'phriction',
),
'db.project' => array(
'type' => 'db',
'name' => 'project',
),
'db.repository' => array(
'type' => 'db',
'name' => 'repository',
),
'db.search' => array(
'type' => 'db',
'name' => 'search',
),
'db.slowvote' => array(
'type' => 'db',
'name' => 'slowvote',
),
'db.timeline' => array(
'type' => 'db',
'name' => 'timeline',
'dead' => true,
),
'db.user' => array(
'type' => 'db',
'name' => 'user',
),
'db.worker' => array(
'type' => 'db',
'name' => 'worker',
),
'db.xhpastview' => array(
'type' => 'db',
'name' => 'xhpastview',
),
'db.cache' => array(
'type' => 'db',
'name' => 'cache',
),
'db.fact' => array(
'type' => 'db',
'name' => 'fact',
),
'db.ponder' => array(
'type' => 'db',
'name' => 'ponder',
),
'db.xhprof' => array(
'type' => 'db',
'name' => 'xhprof',
),
'db.pholio' => array(
'type' => 'db',
'name' => 'pholio',
),
'db.conpherence' => array(
'type' => 'db',
'name' => 'conpherence',
),
'db.config' => array(
'type' => 'db',
'name' => 'config',
),
'db.token' => array(
'type' => 'db',
'name' => 'token',
),
'db.releeph' => array(
'type' => 'db',
'name' => 'releeph',
),
'db.phlux' => array(
'type' => 'db',
'name' => 'phlux',
),
'db.phortune' => array(
'type' => 'db',
'name' => 'phortune',
),
'db.phrequent' => array(
'type' => 'db',
'name' => 'phrequent',
),
'db.diviner' => array(
'type' => 'db',
'name' => 'diviner',
),
'db.auth' => array(
'type' => 'db',
'name' => 'auth',
),
'db.doorkeeper' => array(
'type' => 'db',
'name' => 'doorkeeper',
),
'db.legalpad' => array(
'type' => 'db',
'name' => 'legalpad',
),
'db.policy' => array(
'type' => 'db',
'name' => 'policy',
),
'db.nuance' => array(
'type' => 'db',
'name' => 'nuance',
),
'db.passphrase' => array(
'type' => 'db',
'name' => 'passphrase',
),
'db.phragment' => array(
'type' => 'db',
'name' => 'phragment',
),
'0000.legacy.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('0000.legacy.sql'),
'legacy' => 0,
),
'000.project.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('000.project.sql'),
'legacy' => 0,
),
'001.maniphest_projects.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('001.maniphest_projects.sql'),
'legacy' => 1,
),
'002.oauth.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('002.oauth.sql'),
'legacy' => 2,
),
'003.more_oauth.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('003.more_oauth.sql'),
'legacy' => 3,
),
'004.daemonrepos.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('004.daemonrepos.sql'),
'legacy' => 4,
),
'005.workers.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('005.workers.sql'),
'legacy' => 5,
),
'006.repository.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('006.repository.sql'),
'legacy' => 6,
),
'007.daemonlog.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('007.daemonlog.sql'),
'legacy' => 7,
),
'008.repoopt.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('008.repoopt.sql'),
'legacy' => 8,
),
'009.repo_summary.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('009.repo_summary.sql'),
'legacy' => 9,
),
'010.herald.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('010.herald.sql'),
'legacy' => 10,
),
'011.badcommit.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('011.badcommit.sql'),
'legacy' => 11,
),
'012.dropphidtype.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('012.dropphidtype.sql'),
'legacy' => 12,
),
'013.commitdetail.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('013.commitdetail.sql'),
'legacy' => 13,
),
'014.shortcuts.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('014.shortcuts.sql'),
'legacy' => 14,
),
'015.preferences.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('015.preferences.sql'),
'legacy' => 15,
),
'016.userrealnameindex.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('016.userrealnameindex.sql'),
'legacy' => 16,
),
'017.sessionkeys.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('017.sessionkeys.sql'),
'legacy' => 17,
),
'018.owners.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('018.owners.sql'),
'legacy' => 18,
),
'019.arcprojects.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('019.arcprojects.sql'),
'legacy' => 19,
),
'020.pathcapital.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('020.pathcapital.sql'),
'legacy' => 20,
),
'021.xhpastview.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('021.xhpastview.sql'),
'legacy' => 21,
),
'022.differentialcommit.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('022.differentialcommit.sql'),
'legacy' => 22,
),
'023.dxkeys.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('023.dxkeys.sql'),
'legacy' => 23,
),
'024.mlistkeys.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('024.mlistkeys.sql'),
'legacy' => 24,
),
'025.commentopt.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('025.commentopt.sql'),
'legacy' => 25,
),
'026.diffpropkey.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('026.diffpropkey.sql'),
'legacy' => 26,
),
'027.metamtakeys.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('027.metamtakeys.sql'),
'legacy' => 27,
),
'028.systemagent.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('028.systemagent.sql'),
'legacy' => 28,
),
'029.cursors.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('029.cursors.sql'),
'legacy' => 29,
),
'030.imagemacro.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('030.imagemacro.sql'),
'legacy' => 30,
),
'031.workerrace.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('031.workerrace.sql'),
'legacy' => 31,
),
'032.viewtime.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('032.viewtime.sql'),
'legacy' => 32,
),
'033.privtest.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('033.privtest.sql'),
'legacy' => 33,
),
'034.savedheader.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('034.savedheader.sql'),
'legacy' => 34,
),
'035.proxyimage.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('035.proxyimage.sql'),
'legacy' => 35,
),
'036.mailkey.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('036.mailkey.sql'),
'legacy' => 36,
),
'037.setuptest.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('037.setuptest.sql'),
'legacy' => 37,
),
'038.admin.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('038.admin.sql'),
'legacy' => 38,
),
'039.userlog.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('039.userlog.sql'),
'legacy' => 39,
),
'040.transform.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('040.transform.sql'),
'legacy' => 40,
),
'041.heraldrepetition.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('041.heraldrepetition.sql'),
'legacy' => 41,
),
'042.commentmetadata.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('042.commentmetadata.sql'),
'legacy' => 42,
),
'043.pastebin.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('043.pastebin.sql'),
'legacy' => 43,
),
'044.countdown.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('044.countdown.sql'),
'legacy' => 44,
),
'045.timezone.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('045.timezone.sql'),
'legacy' => 45,
),
'046.conduittoken.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('046.conduittoken.sql'),
'legacy' => 46,
),
'047.projectstatus.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('047.projectstatus.sql'),
'legacy' => 47,
),
'048.relationshipkeys.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('048.relationshipkeys.sql'),
'legacy' => 48,
),
'049.projectowner.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('049.projectowner.sql'),
'legacy' => 49,
),
'050.taskdenormal.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('050.taskdenormal.sql'),
'legacy' => 50,
),
'051.projectfilter.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('051.projectfilter.sql'),
'legacy' => 51,
),
'052.pastelanguage.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('052.pastelanguage.sql'),
'legacy' => 52,
),
'053.feed.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('053.feed.sql'),
'legacy' => 53,
),
'054.subscribers.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('054.subscribers.sql'),
'legacy' => 54,
),
'055.add_author_to_files.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('055.add_author_to_files.sql'),
'legacy' => 55,
),
'056.slowvote.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('056.slowvote.sql'),
'legacy' => 56,
),
'057.parsecache.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('057.parsecache.sql'),
'legacy' => 57,
),
'058.missingkeys.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('058.missingkeys.sql'),
'legacy' => 58,
),
'059.engines.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('059.engines.php'),
'legacy' => 59,
),
'060.phriction.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('060.phriction.sql'),
'legacy' => 60,
),
'061.phrictioncontent.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('061.phrictioncontent.sql'),
'legacy' => 61,
),
'062.phrictionmenu.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('062.phrictionmenu.sql'),
'legacy' => 62,
),
'063.pasteforks.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('063.pasteforks.sql'),
'legacy' => 63,
),
'064.subprojects.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('064.subprojects.sql'),
'legacy' => 64,
),
'065.sshkeys.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('065.sshkeys.sql'),
'legacy' => 65,
),
'066.phrictioncontent.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('066.phrictioncontent.sql'),
'legacy' => 66,
),
'067.preferences.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('067.preferences.sql'),
'legacy' => 67,
),
'068.maniphestauxiliarystorage.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('068.maniphestauxiliarystorage.sql'),
'legacy' => 68,
),
'069.heraldxscript.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('069.heraldxscript.sql'),
'legacy' => 69,
),
'070.differentialaux.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('070.differentialaux.sql'),
'legacy' => 70,
),
'071.contentsource.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('071.contentsource.sql'),
'legacy' => 71,
),
'072.blamerevert.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('072.blamerevert.sql'),
'legacy' => 72,
),
'073.reposymbols.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('073.reposymbols.sql'),
'legacy' => 73,
),
'074.affectedpath.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('074.affectedpath.sql'),
'legacy' => 74,
),
'075.revisionhash.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('075.revisionhash.sql'),
'legacy' => 75,
),
'076.indexedlanguages.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('076.indexedlanguages.sql'),
'legacy' => 76,
),
'077.originalemail.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('077.originalemail.sql'),
'legacy' => 77,
),
'078.nametoken.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('078.nametoken.sql'),
'legacy' => 78,
),
'079.nametokenindex.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('079.nametokenindex.php'),
'legacy' => 79,
),
'080.filekeys.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('080.filekeys.sql'),
'legacy' => 80,
),
'081.filekeys.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('081.filekeys.php'),
'legacy' => 81,
),
'082.xactionkey.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('082.xactionkey.sql'),
'legacy' => 82,
),
'083.dxviewtime.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('083.dxviewtime.sql'),
'legacy' => 83,
),
'084.pasteauthorkey.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('084.pasteauthorkey.sql'),
'legacy' => 84,
),
'085.packagecommitrelationship.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('085.packagecommitrelationship.sql'),
'legacy' => 85,
),
'086.formeraffil.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('086.formeraffil.sql'),
'legacy' => 86,
),
'087.phrictiondelete.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('087.phrictiondelete.sql'),
'legacy' => 87,
),
'088.audit.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('088.audit.sql'),
'legacy' => 88,
),
'089.projectwiki.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('089.projectwiki.sql'),
'legacy' => 89,
),
'090.forceuniqueprojectnames.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('090.forceuniqueprojectnames.php'),
'legacy' => 90,
),
'091.uniqueslugkey.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('091.uniqueslugkey.sql'),
'legacy' => 91,
),
'092.dropgithubnotification.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('092.dropgithubnotification.sql'),
'legacy' => 92,
),
'093.gitremotes.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('093.gitremotes.php'),
'legacy' => 93,
),
'094.phrictioncolumn.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('094.phrictioncolumn.sql'),
'legacy' => 94,
),
'095.directory.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('095.directory.sql'),
'legacy' => 95,
),
'096.filename.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('096.filename.sql'),
'legacy' => 96,
),
'097.heraldruletypes.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('097.heraldruletypes.sql'),
'legacy' => 97,
),
'098.heraldruletypemigration.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('098.heraldruletypemigration.php'),
'legacy' => 98,
),
'099.drydock.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('099.drydock.sql'),
'legacy' => 99,
),
'100.projectxaction.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('100.projectxaction.sql'),
'legacy' => 100,
),
'101.heraldruleapplied.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('101.heraldruleapplied.sql'),
'legacy' => 101,
),
'102.heraldcleanup.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('102.heraldcleanup.php'),
'legacy' => 102,
),
'103.heraldedithistory.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('103.heraldedithistory.sql'),
'legacy' => 103,
),
'104.searchkey.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('104.searchkey.sql'),
'legacy' => 104,
),
'105.mimetype.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('105.mimetype.sql'),
'legacy' => 105,
),
'106.chatlog.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('106.chatlog.sql'),
'legacy' => 106,
),
'107.oauthserver.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('107.oauthserver.sql'),
'legacy' => 107,
),
'108.oauthscope.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('108.oauthscope.sql'),
'legacy' => 108,
),
'109.oauthclientphidkey.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('109.oauthclientphidkey.sql'),
'legacy' => 109,
),
'110.commitaudit.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('110.commitaudit.sql'),
'legacy' => 110,
),
'111.commitauditmigration.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('111.commitauditmigration.php'),
'legacy' => 111,
),
'112.oauthaccesscoderedirecturi.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('112.oauthaccesscoderedirecturi.sql'),
'legacy' => 112,
),
'113.lastreviewer.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('113.lastreviewer.sql'),
'legacy' => 113,
),
'114.auditrequest.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('114.auditrequest.sql'),
'legacy' => 114,
),
'115.prepareutf8.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('115.prepareutf8.sql'),
'legacy' => 115,
),
'116.utf8-backup-first-expect-wait.sql' => array(
'type' => 'sql',
'name' =>
$this->getPatchPath('116.utf8-backup-first-expect-wait.sql'),
'legacy' => 116,
),
'117.repositorydescription.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('117.repositorydescription.php'),
'legacy' => 117,
),
'118.auditinline.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('118.auditinline.sql'),
'legacy' => 118,
),
'119.filehash.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('119.filehash.sql'),
'legacy' => 119,
),
'120.noop.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('120.noop.sql'),
'legacy' => 120,
),
'121.drydocklog.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('121.drydocklog.sql'),
'legacy' => 121,
),
'122.flag.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('122.flag.sql'),
'legacy' => 122,
),
'123.heraldrulelog.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('123.heraldrulelog.sql'),
'legacy' => 123,
),
'124.subpriority.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('124.subpriority.sql'),
'legacy' => 124,
),
'125.ipv6.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('125.ipv6.sql'),
'legacy' => 125,
),
'126.edges.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('126.edges.sql'),
'legacy' => 126,
),
'127.userkeybody.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('127.userkeybody.sql'),
'legacy' => 127,
),
'128.phabricatorcom.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('128.phabricatorcom.sql'),
'legacy' => 128,
),
'129.savedquery.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('129.savedquery.sql'),
'legacy' => 129,
),
'130.denormalrevisionquery.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('130.denormalrevisionquery.sql'),
'legacy' => 130,
),
'131.migraterevisionquery.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('131.migraterevisionquery.php'),
'legacy' => 131,
),
'132.phame.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('132.phame.sql'),
'legacy' => 132,
),
'133.imagemacro.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('133.imagemacro.sql'),
'legacy' => 133,
),
'134.emptysearch.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('134.emptysearch.sql'),
'legacy' => 134,
),
'135.datecommitted.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('135.datecommitted.sql'),
'legacy' => 135,
),
'136.sex.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('136.sex.sql'),
'legacy' => 136,
),
'137.auditmetadata.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('137.auditmetadata.sql'),
'legacy' => 137,
),
'138.notification.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('138.notification.sql'),
),
'holidays.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('holidays.sql'),
),
'userstatus.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('userstatus.sql'),
),
'emailtable.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('emailtable.sql'),
),
'emailtableport.sql' => array(
'type' => 'php',
'name' => $this->getPatchPath('emailtableport.php'),
),
'emailtableremove.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('emailtableremove.sql'),
),
'phiddrop.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('phiddrop.sql'),
),
'testdatabase.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('testdatabase.sql'),
),
'ldapinfo.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('ldapinfo.sql'),
),
'threadtopic.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('threadtopic.sql'),
),
'usertranslation.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('usertranslation.sql'),
),
'differentialbookmarks.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('differentialbookmarks.sql'),
),
'harbormasterobject.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('harbormasterobject.sql'),
),
'markupcache.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('markupcache.sql'),
),
'maniphestxcache.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('maniphestxcache.sql'),
),
'migrate-maniphest-dependencies.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('migrate-maniphest-dependencies.php'),
),
'migrate-differential-dependencies.php' => array(
'type' => 'php',
'name' => $this->getPatchPath(
'migrate-differential-dependencies.php'),
),
'phameblog.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('phameblog.sql'),
),
'migrate-maniphest-revisions.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('migrate-maniphest-revisions.php'),
),
'daemonstatus.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('daemonstatus.sql'),
),
'symbolcontexts.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('symbolcontexts.sql'),
),
'migrate-project-edges.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('migrate-project-edges.php'),
),
'fact-raw.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('fact-raw.sql'),
),
'ponder.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('ponder.sql')
),
'policy-project.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('policy-project.sql'),
),
'daemonstatuskey.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('daemonstatuskey.sql'),
),
'edgetype.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('edgetype.sql'),
),
'ponder-comments.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('ponder-comments.sql'),
),
'pastepolicy.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('pastepolicy.sql'),
),
'xhprof.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('xhprof.sql'),
),
'draft-metadata.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('draft-metadata.sql'),
),
'phamedomain.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('phamedomain.sql'),
),
'ponder-mailkey.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('ponder-mailkey.sql'),
),
'ponder-mailkey-populate.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('ponder-mailkey-populate.php'),
),
'phamepolicy.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('phamepolicy.sql'),
),
'phameoneblog.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('phameoneblog.sql'),
),
'statustxt.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('statustxt.sql'),
),
'daemontaskarchive.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('daemontaskarchive.sql'),
),
'drydocktaskid.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('drydocktaskid.sql'),
),
'drydockresoucetype.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('drydockresourcetype.sql'),
),
'liskcounters.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('liskcounters.sql'),
),
'liskcounters.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('liskcounters.php'),
),
'dropfileproxyimage.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('dropfileproxyimage.sql'),
),
'repository-lint.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('repository-lint.sql'),
),
'liskcounters-task.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('liskcounters-task.sql'),
),
'pholio.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('pholio.sql'),
),
'owners-exclude.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('owners-exclude.sql'),
),
'20121209.pholioxactions.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20121209.pholioxactions.sql'),
),
'20121209.xmacroadd.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20121209.xmacroadd.sql'),
),
'20121209.xmacromigrate.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20121209.xmacromigrate.php'),
),
'20121209.xmacromigratekey.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20121209.xmacromigratekey.sql'),
),
'20121220.generalcache.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20121220.generalcache.sql'),
),
'20121226.config.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20121226.config.sql'),
),
'20130101.confxaction.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130101.confxaction.sql'),
),
'20130102.metamtareceivedmailmessageidhash.sql' => array(
'type' => 'sql',
'name' =>
$this->getPatchPath('20130102.metamtareceivedmailmessageidhash.sql'),
),
'20130103.filemetadata.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130103.filemetadata.sql'),
),
'20130111.conpherence.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130111.conpherence.sql'),
),
'20130127.altheraldtranscript.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130127.altheraldtranscript.sql'),
),
'20130201.revisionunsubscribed.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130201.revisionunsubscribed.php'),
),
'20130201.revisionunsubscribed.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130201.revisionunsubscribed.sql'),
),
'20130131.conpherencepics.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130131.conpherencepics.sql'),
),
'20130214.chatlogchannel.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130214.chatlogchannel.sql'),
),
'20130214.chatlogchannelid.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130214.chatlogchannelid.sql'),
),
'20130214.token.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130214.token.sql'),
),
'20130215.phabricatorfileaddttl.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130215.phabricatorfileaddttl.sql'),
),
'20130217.cachettl.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130217.cachettl.sql'),
),
'20130218.updatechannelid.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130218.updatechannelid.php'),
),
'20130218.longdaemon.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130218.longdaemon.sql'),
),
'20130219.commitsummary.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130219.commitsummary.sql'),
),
'20130219.commitsummarymig.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130219.commitsummarymig.php'),
),
'20130222.dropchannel.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130222.dropchannel.sql'),
),
'20130226.commitkey.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130226.commitkey.sql'),
),
'20131302.maniphestvalue.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131302.maniphestvalue.sql'),
),
'20130304.lintauthor.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130304.lintauthor.sql'),
),
'releeph.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('releeph.sql'),
),
'20130319.phabricatorfileexplicitupload.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath(
'20130319.phabricatorfileexplicitupload.sql')
),
'20130319.conpherence.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130319.conpherence.sql'),
),
'20130320.phlux.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130320.phlux.sql'),
),
'20130317.phrictionedge.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130317.phrictionedge.sql'),
),
'20130321.token.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130321.token.sql'),
),
'20130310.xactionmeta.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130310.xactionmeta.sql'),
),
'20130322.phortune.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130322.phortune.sql'),
),
'20130323.phortunepayment.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130323.phortunepayment.sql'),
),
'20130324.phortuneproduct.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130324.phortuneproduct.sql'),
),
'20130330.phrequent.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130330.phrequent.sql'),
),
'20130403.conpherencecache.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130403.conpherencecache.sql'),
),
'20130403.conpherencecachemig.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130403.conpherencecachemig.php'),
),
'20130409.commitdrev.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130409.commitdrev.php'),
),
'20130417.externalaccount.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130417.externalaccount.sql'),
),
'20130423.updateexternalaccount.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130423.updateexternalaccount.sql'),
),
'20130423.phortunepaymentrevised.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130423.phortunepaymentrevised.sql'),
),
'20130423.conpherenceindices.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130423.conpherenceindices.sql'),
),
'20130426.search_savedquery.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130426.search_savedquery.sql'),
),
'20130502.countdownrevamp1.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130502.countdownrevamp1.sql'),
),
'20130502.countdownrevamp2.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130502.countdownrevamp2.php'),
),
'20130502.countdownrevamp3.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130502.countdownrevamp3.sql'),
),
'20130507.releephrqsimplifycols.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130507.releephrqsimplifycols.sql'),
),
'20130507.releephrqmailkey.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130507.releephrqmailkey.sql'),
),
'20130507.releephrqmailkeypop.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130507.releephrqmailkeypop.php'),
),
'20130508.search_namedquery.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130508.search_namedquery.sql'),
),
'20130508.releephtransactions.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130508.releephtransactions.sql'),
),
'20130508.releephtransactionsmig.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130508.releephtransactionsmig.php'),
),
'20130513.receviedmailstatus.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130513.receviedmailstatus.sql'),
),
'20130519.diviner.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130519.diviner.sql'),
),
'20130521.dropconphimages.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130521.dropconphimages.sql'),
),
'20130523.maniphest_owners.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130523.maniphest_owners.sql'),
),
'20130524.repoxactions.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130524.repoxactions.sql'),
),
'20130529.macroauthor.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130529.macroauthor.sql'),
),
'20130529.macroauthormig.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130529.macroauthormig.php'),
),
'20130530.sessionhash.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130530.sessionhash.php'),
),
'20130530.macrodatekey.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130530.macrodatekey.sql'),
),
'20130530.pastekeys.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130530.pastekeys.sql'),
),
'20130531.filekeys.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130531.filekeys.sql'),
),
'20130602.morediviner.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130602.morediviner.sql'),
),
'20130602.namedqueries.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130602.namedqueries.sql'),
),
'20130606.userxactions.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130606.userxactions.sql'),
),
'20130607.xaccount.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130607.xaccount.sql'),
),
'20130611.migrateoauth.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130611.migrateoauth.php'),
),
'20130611.nukeldap.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130611.nukeldap.php'),
),
'20130613.authdb.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130613.authdb.sql'),
),
'20130619.authconf.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130619.authconf.php'),
),
'20130620.diffxactions.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130620.diffxactions.sql'),
),
'20130621.diffcommentphid.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130621.diffcommentphid.sql'),
),
'20130621.diffcommentphidmig.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130621.diffcommentphidmig.php'),
),
'20130621.diffcommentunphid.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130621.diffcommentunphid.sql'),
),
'20130622.doorkeeper.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130622.doorkeeper.sql'),
),
'20130628.legalpadv0.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130628.legalpadv0.sql'),
),
'20130701.conduitlog.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130701.conduitlog.sql'),
),
'legalpad-mailkey.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('legalpad-mailkey.sql'),
),
'legalpad-mailkey-populate.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('legalpad-mailkey-populate.php'),
),
'20130703.legalpaddocdenorm.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130703.legalpaddocdenorm.sql'),
),
'20130703.legalpaddocdenorm.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130703.legalpaddocdenorm.php'),
),
'20130709.legalpadsignature.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130709.legalpadsignature.sql'),
),
'20130709.droptimeline.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130709.droptimeline.sql'),
),
'20130711.trimrealnames.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130711.trimrealnames.php'),
),
'20130714.votexactions.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130714.votexactions.sql'),
),
'20130715.votecomments.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130715.votecomments.php'),
),
'20130715.voteedges.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130715.voteedges.sql'),
),
'20130711.pholioimageobsolete.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130711.pholioimageobsolete.sql'),
),
'20130711.pholioimageobsolete.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130711.pholioimageobsolete.php'),
),
'20130711.pholioimageobsolete2.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130711.pholioimageobsolete2.sql'),
),
'20130716.archivememberlessprojects.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130716.archivememberlessprojects.php'),
),
'20130722.pholioreplace.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130722.pholioreplace.sql'),
),
'20130723.taskstarttime.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130723.taskstarttime.sql'),
),
'20130727.ponderquestionstatus.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130727.ponderquestionstatus.sql'),
),
'20130726.ponderxactions.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130726.ponderxactions.sql'),
),
'20130728.ponderunique.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130728.ponderunique.php'),
),
'20130728.ponderuniquekey.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130728.ponderuniquekey.sql'),
),
'20130728.ponderxcomment.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130728.ponderxcomment.php'),
),
'20130801.pastexactions.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130801.pastexactions.sql'),
),
'20130801.pastexactions.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130801.pastexactions.php'),
),
'20130805.pastemailkey.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130805.pastemailkey.sql'),
),
'20130805.pasteedges.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130805.pasteedges.sql'),
),
'20130805.pastemailkeypop.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130805.pastemailkeypop.php'),
),
'20130802.heraldphid.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130802.heraldphid.sql'),
),
'20130802.heraldphids.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130802.heraldphids.php'),
),
'20130802.heraldphidukey.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130802.heraldphidukey.sql'),
),
'20130802.heraldxactions.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130802.heraldxactions.sql'),
),
'20130731.releephrepoid.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130731.releephrepoid.sql'),
),
'20130731.releephproject.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130731.releephproject.sql'),
),
'20130731.releephcutpointidentifier.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130731.releephcutpointidentifier.sql'),
),
'20130814.usercustom.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130814.usercustom.sql'),
),
'20130820.releephxactions.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130820.releephxactions.sql'),
),
'20130826.divinernode.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130826.divinernode.sql'),
),
'20130820.filexactions.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130820.filexactions.sql'),
),
'20130820.filemailkey.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130820.filemailkey.sql'),
),
'20130820.file-mailkey-populate.php' => array(
'type' => 'php',
'name' =>
$this->getPatchPath('20130820.file-mailkey-populate.php'),
),
'20130912.maniphest.1.touch.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130912.maniphest.1.touch.sql'),
),
'20130912.maniphest.2.created.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130912.maniphest.2.created.sql'),
),
'20130912.maniphest.3.nameindex.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130912.maniphest.3.nameindex.sql'),
),
'20130912.maniphest.4.fillindex.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130912.maniphest.4.fillindex.php'),
),
'20130913.maniphest.1.migratesearch.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130913.maniphest.1.migratesearch.php'),
),
'20130914.usercustom.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130914.usercustom.sql'),
),
'20130915.maniphestcustom.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130915.maniphestcustom.sql'),
),
'20130915.maniphestmigrate.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130915.maniphestmigrate.php'),
),
'20130919.mfieldconf.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130919.mfieldconf.php'),
),
'20130920.repokeyspolicy.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130920.repokeyspolicy.sql'),
),
'20130921.mtransactions.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130921.mtransactions.sql'),
),
'20130921.xmigratemaniphest.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130921.xmigratemaniphest.php'),
),
'20130923.mrename.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130923.mrename.sql'),
),
'20130924.mdraftkey.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130924.mdraftkey.sql'),
),
'20130925.mpolicy.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130925.mpolicy.sql'),
),
'20130925.xpolicy.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130925.xpolicy.sql'),
),
'20130926.dcustom.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130926.dcustom.sql'),
),
'20130926.dinkeys.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130926.dinkeys.sql'),
),
'20130927.audiomacro.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130927.audiomacro.sql'),
),
'20130929.filepolicy.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130929.filepolicy.sql'),
),
'20131004.dxedgekey.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131004.dxedgekey.sql'),
),
'20131004.dxreviewers.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20131004.dxreviewers.php'),
),
'20131006.hdisable.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131006.hdisable.sql'),
),
'20131010.pstorage.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131010.pstorage.sql'),
),
'20131015.cpolicy.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131015.cpolicy.sql'),
),
'20130915.maniphestqdrop.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130915.maniphestqdrop.sql'),
),
'20130926.dinline.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20130926.dinline.php'),
),
'20131020.pcustom.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131020.pcustom.sql'),
),
'20131020.col1.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131020.col1.sql'),
),
'20131020.pxaction.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131020.pxaction.sql'),
),
'20131020.pxactionmig.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20131020.pxactionmig.php'),
),
'20131020.harbormaster.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131020.harbormaster.sql'),
),
'20131025.repopush.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131025.repopush.sql'),
),
'20131026.commitstatus.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131026.commitstatus.sql'),
),
'20131030.repostatusmessage.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131030.repostatusmessage.sql'),
),
'20131031.vcspassword.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131031.vcspassword.sql'),
),
'20131105.buildstep.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131105.buildstep.sql'),
),
'20131106.diffphid.1.col.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131106.diffphid.1.col.sql'),
),
'20131106.diffphid.2.mig.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20131106.diffphid.2.mig.php'),
),
'20131106.diffphid.3.key.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131106.diffphid.3.key.sql'),
),
'20131106.nuance-v0.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131106.nuance-v0.sql'),
),
'20131107.buildlog.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131107.buildlog.sql'),
),
'20131112.userverified.1.col.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131112.userverified.1.col.sql'),
),
'20131112.userverified.2.mig.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20131112.userverified.2.mig.php'),
),
'20131118.ownerorder.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20131118.ownerorder.php'),
),
'20131119.passphrase.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131119.passphrase.sql'),
),
'20131120.nuancesourcetype.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131120.nuancesourcetype.sql'),
),
'20131121.passphraseedge.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131121.passphraseedge.sql'),
),
'20131121.repocredentials.1.col.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131121.repocredentials.1.col.sql'),
),
'20131121.repocredentials.2.mig.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20131121.repocredentials.2.mig.php'),
),
'20131122.repomirror.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131122.repomirror.sql'),
),
'20131123.drydockblueprintpolicy.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131123.drydockblueprintpolicy.sql'),
),
'20131129.drydockresourceblueprint.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131129.drydockresourceblueprint.sql'),
),
'20131205.buildtargets.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131205.buildtargets.sql'),
),
'20131204.pushlog.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131204.pushlog.sql'),
),
'20131205.buildsteporder.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131205.buildsteporder.sql'),
),
'20131205.buildstepordermig.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20131205.buildstepordermig.php'),
),
'20131206.phragment.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131206.phragment.sql'),
),
'20131206.phragmentnull.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131206.phragmentnull.sql'),
),
'20131208.phragmentsnapshot.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131208.phragmentsnapshot.sql'),
),
'20131211.phragmentedges.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131211.phragmentedges.sql'),
),
'20131217.pushlogphid.1.col.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131217.pushlogphid.1.col.sql'),
),
'20131217.pushlogphid.2.mig.php' => array(
'type' => 'php',
'name' => $this->getPatchPath('20131217.pushlogphid.2.mig.php'),
),
'20131217.pushlogphid.3.key.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131217.pushlogphid.3.key.sql'),
),
'20131219.pxdrop.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131219.pxdrop.sql'),
),
'20131224.harbormanual.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20131224.harbormanual.sql'),
),
+ '20131227.heraldobject.sql' => array(
+ 'type' => 'sql',
+ 'name' => $this->getPatchPath('20131227.heraldobject.sql'),
+ ),
);
}
}

File Metadata

Mime Type
text/x-diff
Expires
Wed, Dec 3, 5:36 PM (3 h, 3 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
433824
Default Alt Text
(120 KB)

Event Timeline