2011-03-25 05:32:26 +01:00
|
|
|
<?php
|
|
|
|
|
2012-03-10 00:46:25 +01:00
|
|
|
final class HeraldTranscriptController extends HeraldController {
|
2011-03-25 05:32:26 +01:00
|
|
|
|
|
|
|
const FILTER_AFFECTED = 'affected';
|
|
|
|
const FILTER_OWNED = 'owned';
|
|
|
|
const FILTER_ALL = 'all';
|
|
|
|
|
|
|
|
private $id;
|
|
|
|
private $filter;
|
|
|
|
private $handles;
|
2013-08-02 21:23:13 +02:00
|
|
|
private $adapter;
|
2011-03-25 05:32:26 +01:00
|
|
|
|
|
|
|
public function willProcessRequest(array $data) {
|
|
|
|
$this->id = $data['id'];
|
|
|
|
$map = $this->getFilterMap();
|
|
|
|
$this->filter = idx($data, 'filter');
|
|
|
|
if (empty($map[$this->filter])) {
|
2013-12-31 01:48:14 +01:00
|
|
|
$this->filter = self::FILTER_ALL;
|
2011-03-25 05:32:26 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-02 21:23:13 +02:00
|
|
|
private function getAdapter() {
|
|
|
|
return $this->adapter;
|
|
|
|
}
|
|
|
|
|
2011-03-25 05:32:26 +01:00
|
|
|
public function processRequest() {
|
2013-10-05 00:17:18 +02:00
|
|
|
$request = $this->getRequest();
|
|
|
|
$viewer = $request->getUser();
|
2011-03-25 05:32:26 +01:00
|
|
|
|
2013-10-05 00:17:18 +02:00
|
|
|
$xscript = id(new HeraldTranscriptQuery())
|
|
|
|
->setViewer($viewer)
|
|
|
|
->withIDs(array($this->id))
|
|
|
|
->executeOne();
|
2011-03-25 05:32:26 +01:00
|
|
|
if (!$xscript) {
|
2013-10-05 00:17:18 +02:00
|
|
|
return new Aphront404Response();
|
2011-03-25 05:32:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
require_celerity_resource('herald-test-css');
|
|
|
|
|
|
|
|
$nav = $this->buildSideNav();
|
|
|
|
|
2011-07-03 18:47:31 +02:00
|
|
|
$object_xscript = $xscript->getObjectTranscript();
|
|
|
|
if (!$object_xscript) {
|
|
|
|
$notice = id(new AphrontErrorView())
|
|
|
|
->setSeverity(AphrontErrorView::SEVERITY_NOTICE)
|
2013-05-20 17:24:07 +02:00
|
|
|
->setTitle(pht('Old Transcript'))
|
2013-02-07 01:53:49 +01:00
|
|
|
->appendChild(phutil_tag(
|
|
|
|
'p',
|
|
|
|
array(),
|
2013-05-20 17:24:07 +02:00
|
|
|
pht('Details of this transcript have been garbage collected.')));
|
2011-07-03 18:47:31 +02:00
|
|
|
$nav->appendChild($notice);
|
|
|
|
} else {
|
2013-10-05 00:17:18 +02:00
|
|
|
$map = HeraldAdapter::getEnabledAdapterMap($viewer);
|
|
|
|
$object_type = $object_xscript->getType();
|
|
|
|
if (empty($map[$object_type])) {
|
|
|
|
// TODO: We should filter these out in the Query, but we have to load
|
|
|
|
// the objectTranscript right now, which is potentially enormous. We
|
|
|
|
// should denormalize the object type, or move the data into a separate
|
|
|
|
// table, and then filter this earlier (and thus raise a better error).
|
|
|
|
// For now, just block access so we don't violate policies.
|
|
|
|
throw new Exception(
|
2014-06-09 20:36:49 +02:00
|
|
|
pht('This transcript has an invalid or inaccessible adapter.'));
|
2013-10-05 00:17:18 +02:00
|
|
|
}
|
2013-08-02 21:23:13 +02:00
|
|
|
|
2013-10-05 00:17:18 +02:00
|
|
|
$this->adapter = HeraldAdapter::getAdapterForContentType($object_type);
|
2013-08-02 21:23:13 +02:00
|
|
|
|
2011-07-03 18:47:31 +02:00
|
|
|
$filter = $this->getFilterPHIDs();
|
|
|
|
$this->filterTranscript($xscript, $filter);
|
|
|
|
$phids = array_merge($filter, $this->getTranscriptPHIDs($xscript));
|
|
|
|
$phids = array_unique($phids);
|
|
|
|
$phids = array_filter($phids);
|
|
|
|
|
2012-09-05 04:02:56 +02:00
|
|
|
$handles = $this->loadViewerHandles($phids);
|
2011-07-03 18:47:31 +02:00
|
|
|
$this->handles = $handles;
|
|
|
|
|
General Herald refactoring pass
Summary:
**Who can delete global rules?**: I discussed this with @jungejason. The current behavior is that the rule author or any administrator can delete a global rule, but this
isn't consistent with who can edit a rule (anyone) and doesn't really make much sense (it's an artifact of the global/personal split). I proposed that anyone can delete a
rule but we don't actually delete them, and log the deletion. However, when it came time to actually write the code for this I backed off a bit and continued actually
deleting the rules -- I think this does a reasonable job of balancing accountability with complexity. So the new impelmentation is:
- Personal rules can be deleted only by their owners.
- Global rules can be deleted by any user.
- All deletes are logged.
- Logs are more detailed.
- All logged actions can be viewed in aggregate.
**Minor Cleanup**
- Merged `HomeController` and `AllController`.
- Moved most queries to Query classes.
- Use AphrontFormSelectControl::renderSelectTag() where appropriate (this is a fairly recent addition).
- Use an AphrontErrorView to render the dry run notice (this didn't exist when I ported).
- Reenable some transaction code (this works again now).
- Removed the ability for admins to change rule authors (this was a little buggy, messy, and doesn't make tons of sense after the personal/global rule split).
- Rules which depend on other rules now display the right options (all global rules, all your personal rules for personal rules).
- Fix a bug in AphrontTableView where the "no data" cell would be rendered too wide if some columns are not visible.
- Allow selectFilter() in AphrontNavFilterView to be called without a 'default' argument.
Test Plan:
- Browsed, created, edited, deleted personal and gules.
- Verified generated logs.
- Did some dry runs.
- Verified transcript list and transcript details.
- Created/edited all/any rules; created/edited once/every time rules.
- Filtered admin views by users.
Reviewers: jungejason, btrahan
Reviewed By: btrahan
CC: aran, epriestley
Differential Revision: https://secure.phabricator.com/D2040
2012-03-30 19:49:55 +02:00
|
|
|
if ($xscript->getDryRun()) {
|
|
|
|
$notice = new AphrontErrorView();
|
|
|
|
$notice->setSeverity(AphrontErrorView::SEVERITY_NOTICE);
|
2013-05-20 17:24:07 +02:00
|
|
|
$notice->setTitle(pht('Dry Run'));
|
|
|
|
$notice->appendChild(pht('This was a dry run to test Herald '.
|
|
|
|
'rules, no actions were executed.'));
|
General Herald refactoring pass
Summary:
**Who can delete global rules?**: I discussed this with @jungejason. The current behavior is that the rule author or any administrator can delete a global rule, but this
isn't consistent with who can edit a rule (anyone) and doesn't really make much sense (it's an artifact of the global/personal split). I proposed that anyone can delete a
rule but we don't actually delete them, and log the deletion. However, when it came time to actually write the code for this I backed off a bit and continued actually
deleting the rules -- I think this does a reasonable job of balancing accountability with complexity. So the new impelmentation is:
- Personal rules can be deleted only by their owners.
- Global rules can be deleted by any user.
- All deletes are logged.
- Logs are more detailed.
- All logged actions can be viewed in aggregate.
**Minor Cleanup**
- Merged `HomeController` and `AllController`.
- Moved most queries to Query classes.
- Use AphrontFormSelectControl::renderSelectTag() where appropriate (this is a fairly recent addition).
- Use an AphrontErrorView to render the dry run notice (this didn't exist when I ported).
- Reenable some transaction code (this works again now).
- Removed the ability for admins to change rule authors (this was a little buggy, messy, and doesn't make tons of sense after the personal/global rule split).
- Rules which depend on other rules now display the right options (all global rules, all your personal rules for personal rules).
- Fix a bug in AphrontTableView where the "no data" cell would be rendered too wide if some columns are not visible.
- Allow selectFilter() in AphrontNavFilterView to be called without a 'default' argument.
Test Plan:
- Browsed, created, edited, deleted personal and gules.
- Verified generated logs.
- Did some dry runs.
- Verified transcript list and transcript details.
- Created/edited all/any rules; created/edited once/every time rules.
- Filtered admin views by users.
Reviewers: jungejason, btrahan
Reviewed By: btrahan
CC: aran, epriestley
Differential Revision: https://secure.phabricator.com/D2040
2012-03-30 19:49:55 +02:00
|
|
|
$nav->appendChild($notice);
|
|
|
|
}
|
|
|
|
|
2014-04-30 00:07:00 +02:00
|
|
|
$warning_panel = $this->buildWarningPanel($xscript);
|
|
|
|
$nav->appendChild($warning_panel);
|
|
|
|
|
2011-07-03 18:47:31 +02:00
|
|
|
$apply_xscript_panel = $this->buildApplyTranscriptPanel(
|
|
|
|
$xscript);
|
|
|
|
$nav->appendChild($apply_xscript_panel);
|
|
|
|
|
|
|
|
$action_xscript_panel = $this->buildActionTranscriptPanel(
|
|
|
|
$xscript);
|
|
|
|
$nav->appendChild($action_xscript_panel);
|
|
|
|
|
|
|
|
$object_xscript_panel = $this->buildObjectTranscriptPanel(
|
|
|
|
$xscript);
|
|
|
|
$nav->appendChild($object_xscript_panel);
|
|
|
|
}
|
2011-03-25 05:32:26 +01:00
|
|
|
|
2013-01-21 16:46:13 +01:00
|
|
|
$crumbs = id($this->buildApplicationCrumbs())
|
2013-12-19 02:47:34 +01:00
|
|
|
->addTextCrumb(
|
|
|
|
pht('Transcripts'),
|
|
|
|
$this->getApplicationURI('/transcript/'))
|
|
|
|
->addTextCrumb($xscript->getID());
|
2013-01-21 16:46:13 +01:00
|
|
|
$nav->setCrumbs($crumbs);
|
2011-03-25 05:32:26 +01:00
|
|
|
|
2013-05-20 17:24:07 +02:00
|
|
|
return $this->buildApplicationPage(
|
2013-01-21 16:46:13 +01:00
|
|
|
$nav,
|
2011-03-25 05:32:26 +01:00
|
|
|
array(
|
2013-05-20 17:24:07 +02:00
|
|
|
'title' => pht('Transcript'),
|
2011-03-25 05:32:26 +01:00
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function renderConditionTestValue($condition, $handles) {
|
2014-04-02 20:59:50 +02:00
|
|
|
switch ($condition->getFieldName()) {
|
|
|
|
case HeraldAdapter::FIELD_RULE:
|
|
|
|
$value = array($condition->getTestValue());
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
$value = $condition->getTestValue();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2011-03-25 05:32:26 +01:00
|
|
|
if (!is_scalar($value) && $value !== null) {
|
|
|
|
foreach ($value as $key => $phid) {
|
|
|
|
$handle = idx($handles, $phid);
|
|
|
|
if ($handle) {
|
|
|
|
$value[$key] = $handle->getName();
|
|
|
|
} else {
|
|
|
|
// This shouldn't ever really happen as we are supposed to have
|
|
|
|
// grabbed handles for everything, but be super liberal in what
|
|
|
|
// we accept here since we expect all sorts of weird issues as we
|
|
|
|
// version the system.
|
|
|
|
$value[$key] = 'Unknown Object #'.$phid;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
sort($value);
|
|
|
|
$value = implode(', ', $value);
|
|
|
|
}
|
|
|
|
|
2013-11-11 18:23:23 +01:00
|
|
|
return phutil_tag('span', array('class' => 'condition-test-value'), $value);
|
2011-03-25 05:32:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private function buildSideNav() {
|
2012-12-07 22:30:31 +01:00
|
|
|
$nav = new AphrontSideNavFilterView();
|
|
|
|
$nav->setBaseURI(new PhutilURI('/herald/transcript/'.$this->id.'/'));
|
2011-03-25 05:32:26 +01:00
|
|
|
|
|
|
|
$items = array();
|
|
|
|
$filters = $this->getFilterMap();
|
|
|
|
foreach ($filters as $key => $name) {
|
2012-12-07 22:30:31 +01:00
|
|
|
$nav->addFilter($key, $name);
|
2011-03-25 05:32:26 +01:00
|
|
|
}
|
2012-12-07 22:30:31 +01:00
|
|
|
$nav->selectFilter($this->filter, null);
|
2011-03-25 05:32:26 +01:00
|
|
|
|
|
|
|
return $nav;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function getFilterMap() {
|
|
|
|
return array(
|
2013-05-20 17:24:07 +02:00
|
|
|
self::FILTER_ALL => pht('All Rules'),
|
2013-12-31 01:48:14 +01:00
|
|
|
self::FILTER_OWNED => pht('Rules I Own'),
|
|
|
|
self::FILTER_AFFECTED => pht('Rules that Affected Me'),
|
2011-03-25 05:32:26 +01:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
protected function getFilterPHIDs() {
|
|
|
|
return array($this->getRequest()->getUser()->getPHID());
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function getTranscriptPHIDs($xscript) {
|
|
|
|
$phids = array();
|
|
|
|
|
|
|
|
$object_xscript = $xscript->getObjectTranscript();
|
|
|
|
if (!$object_xscript) {
|
|
|
|
return array();
|
|
|
|
}
|
|
|
|
|
|
|
|
$phids[] = $object_xscript->getPHID();
|
|
|
|
|
|
|
|
foreach ($xscript->getApplyTranscripts() as $apply_xscript) {
|
|
|
|
// TODO: This is total hacks. Add another amazing layer of abstraction.
|
|
|
|
$target = (array)$apply_xscript->getTarget();
|
|
|
|
foreach ($target as $phid) {
|
|
|
|
if ($phid) {
|
|
|
|
$phids[] = $phid;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach ($xscript->getRuleTranscripts() as $rule_xscript) {
|
|
|
|
$phids[] = $rule_xscript->getRuleOwner();
|
|
|
|
}
|
|
|
|
|
|
|
|
$condition_xscripts = $xscript->getConditionTranscripts();
|
|
|
|
if ($condition_xscripts) {
|
|
|
|
$condition_xscripts = call_user_func_array(
|
|
|
|
'array_merge',
|
|
|
|
$condition_xscripts);
|
|
|
|
}
|
|
|
|
foreach ($condition_xscripts as $condition_xscript) {
|
2014-04-02 20:59:50 +02:00
|
|
|
switch ($condition_xscript->getFieldName()) {
|
|
|
|
case HeraldAdapter::FIELD_RULE:
|
|
|
|
$phids[] = $condition_xscript->getTestValue();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
$value = $condition_xscript->getTestValue();
|
|
|
|
// TODO: Also total hacks.
|
|
|
|
if (is_array($value)) {
|
|
|
|
foreach ($value as $phid) {
|
|
|
|
if ($phid) { // TODO: Probably need to make sure this
|
|
|
|
// "looks like" a PHID or decrease the level of hacks here;
|
|
|
|
// this used to be an is_numeric() check in Facebook land.
|
|
|
|
$phids[] = $phid;
|
|
|
|
}
|
|
|
|
}
|
2011-03-25 05:32:26 +01:00
|
|
|
}
|
2014-04-02 20:59:50 +02:00
|
|
|
break;
|
2011-03-25 05:32:26 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $phids;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function filterTranscript($xscript, $filter_phids) {
|
|
|
|
$filter_owned = ($this->filter == self::FILTER_OWNED);
|
|
|
|
$filter_affected = ($this->filter == self::FILTER_AFFECTED);
|
|
|
|
|
|
|
|
if (!$filter_owned && !$filter_affected) {
|
|
|
|
// No filtering to be done.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!$xscript->getObjectTranscript()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
$user_phid = $this->getRequest()->getUser()->getPHID();
|
|
|
|
|
|
|
|
$keep_apply_xscripts = array();
|
|
|
|
$keep_rule_xscripts = array();
|
|
|
|
|
|
|
|
$filter_phids = array_fill_keys($filter_phids, true);
|
|
|
|
|
|
|
|
$rule_xscripts = $xscript->getRuleTranscripts();
|
|
|
|
foreach ($xscript->getApplyTranscripts() as $id => $apply_xscript) {
|
|
|
|
$rule_id = $apply_xscript->getRuleID();
|
|
|
|
if ($filter_owned) {
|
2011-07-03 18:47:31 +02:00
|
|
|
if (empty($rule_xscripts[$rule_id])) {
|
2011-03-25 05:32:26 +01:00
|
|
|
// No associated rule so you can't own this effect.
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if ($rule_xscripts[$rule_id]->getRuleOwner() != $user_phid) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
} else if ($filter_affected) {
|
|
|
|
$targets = (array)$apply_xscript->getTarget();
|
|
|
|
if (!array_select_keys($filter_phids, $targets)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$keep_apply_xscripts[$id] = true;
|
|
|
|
if ($rule_id) {
|
|
|
|
$keep_rule_xscripts[$rule_id] = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach ($rule_xscripts as $rule_id => $rule_xscript) {
|
|
|
|
if ($filter_owned && $rule_xscript->getRuleOwner() == $user_phid) {
|
|
|
|
$keep_rule_xscripts[$rule_id] = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$xscript->setRuleTranscripts(
|
|
|
|
array_intersect_key(
|
|
|
|
$xscript->getRuleTranscripts(),
|
|
|
|
$keep_rule_xscripts));
|
|
|
|
|
|
|
|
$xscript->setApplyTranscripts(
|
|
|
|
array_intersect_key(
|
|
|
|
$xscript->getApplyTranscripts(),
|
|
|
|
$keep_apply_xscripts));
|
|
|
|
|
|
|
|
$xscript->setConditionTranscripts(
|
|
|
|
array_intersect_key(
|
|
|
|
$xscript->getConditionTranscripts(),
|
|
|
|
$keep_rule_xscripts));
|
|
|
|
}
|
|
|
|
|
2014-04-30 00:07:00 +02:00
|
|
|
private function buildWarningPanel(HeraldTranscript $xscript) {
|
|
|
|
$request = $this->getRequest();
|
|
|
|
$panel = null;
|
|
|
|
if ($xscript->getObjectTranscript()) {
|
|
|
|
$handles = $this->handles;
|
|
|
|
$object_xscript = $xscript->getObjectTranscript();
|
|
|
|
$handle = $handles[$object_xscript->getPHID()];
|
|
|
|
if ($handle->getType() ==
|
|
|
|
PhabricatorRepositoryPHIDTypeCommit::TYPECONST) {
|
|
|
|
$commit = id(new DiffusionCommitQuery())
|
|
|
|
->setViewer($request->getUser())
|
|
|
|
->withPHIDs(array($handle->getPHID()))
|
|
|
|
->executeOne();
|
|
|
|
if ($commit) {
|
|
|
|
$repository = $commit->getRepository();
|
|
|
|
if ($repository->isImporting()) {
|
|
|
|
$title = pht(
|
|
|
|
'The %s repository is still importing.',
|
|
|
|
$repository->getMonogram());
|
|
|
|
$body = pht(
|
|
|
|
'Herald rules will not trigger until import completes.');
|
|
|
|
} else if (!$repository->isTracked()) {
|
|
|
|
$title = pht(
|
|
|
|
'The %s repository is not tracked.',
|
|
|
|
$repository->getMonogram());
|
|
|
|
$body = pht(
|
|
|
|
'Herald rules will not trigger until tracking is enabled.');
|
|
|
|
} else {
|
|
|
|
return $panel;
|
|
|
|
}
|
|
|
|
$panel = id(new AphrontErrorView())
|
|
|
|
->setSeverity(AphrontErrorView::SEVERITY_WARNING)
|
|
|
|
->setTitle($title)
|
|
|
|
->appendChild($body);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return $panel;
|
|
|
|
}
|
|
|
|
|
|
|
|
private function buildApplyTranscriptPanel(HeraldTranscript $xscript) {
|
2011-03-25 05:32:26 +01:00
|
|
|
$handles = $this->handles;
|
2013-08-02 21:23:13 +02:00
|
|
|
$adapter = $this->getAdapter();
|
2011-03-25 05:32:26 +01:00
|
|
|
|
2013-08-02 21:23:13 +02:00
|
|
|
$rule_type_global = HeraldRuleTypeConfig::RULE_TYPE_GLOBAL;
|
|
|
|
$action_names = $adapter->getActionNameMap($rule_type_global);
|
2011-03-25 05:32:26 +01:00
|
|
|
|
2014-04-29 19:14:18 +02:00
|
|
|
$list = new PHUIObjectItemListView();
|
|
|
|
$list->setStates(true);
|
|
|
|
$list->setNoDataString(pht('No actions were taken.'));
|
2011-03-25 05:32:26 +01:00
|
|
|
foreach ($xscript->getApplyTranscripts() as $apply_xscript) {
|
2012-03-30 22:51:54 +02:00
|
|
|
|
|
|
|
$target = $apply_xscript->getTarget();
|
|
|
|
switch ($apply_xscript->getAction()) {
|
2013-08-06 20:23:01 +02:00
|
|
|
case HeraldAdapter::ACTION_NOTHING:
|
2014-04-29 19:14:18 +02:00
|
|
|
$target = null;
|
2012-03-30 22:51:54 +02:00
|
|
|
break;
|
2013-08-06 20:23:01 +02:00
|
|
|
case HeraldAdapter::ACTION_FLAG:
|
2012-03-30 22:51:54 +02:00
|
|
|
$target = PhabricatorFlagColor::getColorName($target);
|
|
|
|
break;
|
Add Herald support for blocking ref changes
Summary: Ref T4195. Allows users to write Herald rules which block ref changes. For example, you can write a rule like `alincoln can not create branches`, or `no one can push to the branch "frozen"`.
Test Plan:
This covers a lot of ground. I created and pushed a bunch of rules, then looked at transcripts, in general. Here are some bits in detail:
Here's a hook-based reject message:
>>> orbital ~/repos/POEMS $ git push
Counting objects: 5, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 274 bytes, done.
Total 3 (delta 2), reused 0 (delta 0)
remote: +---------------------------------------------------------------+
remote: | * * * PUSH REJECTED BY EVIL DRAGON BUREAUCRATS * * * |
remote: +---------------------------------------------------------------+
remote: \
remote: \ ^ /^
remote: \ / \ // \
remote: \ |\___/| / \// .\
remote: \ /V V \__ / // | \ \ *----*
remote: / / \/_/ // | \ \ \ |
remote: @___@` \/_ // | \ \ \/\ \
remote: 0/0/| \/_ // | \ \ \ \
remote: 0/0/0/0/| \/// | \ \ | |
remote: 0/0/0/0/0/_|_ / ( // | \ _\ | /
remote: 0/0/0/0/0/0/`/,_ _ _/ ) ; -. | _ _\.-~ / /
remote: ,-} _ *-.|.-~-. .~ ~
remote: \ \__/ `/\ / ~-. _ .-~ /
remote: \____(Oo) *. } { /
remote: ( (--) .----~-.\ \-` .~
remote: //__\\ \ DENIED! ///.----..< \ _ -~
remote: // \\ ///-._ _ _ _ _ _ _{^ - - - - ~
remote:
remote:
remote: This commit was rejected by Herald pre-commit rule H24.
remote: Rule: No Branches Called Blarp
remote: Reason: "blarp" is a bad branch name
remote:
To ssh://dweller@localhost/diffusion/POEMS/
! [remote rejected] blarp -> blarp (pre-receive hook declined)
error: failed to push some refs to 'ssh://dweller@localhost/diffusion/POEMS/'
Here's a transcript, showing that all the field values populate sensibly:
{F90453}
Here's a rule:
{F90454}
Reviewers: btrahan
Reviewed By: btrahan
CC: aran
Maniphest Tasks: T4195
Differential Revision: https://secure.phabricator.com/D7782
2013-12-18 00:23:55 +01:00
|
|
|
case HeraldAdapter::ACTION_BLOCK:
|
|
|
|
// Target is a text string.
|
|
|
|
$target = $target;
|
|
|
|
break;
|
2012-03-30 22:51:54 +02:00
|
|
|
default:
|
Support custom actions in Herald
Summary:
This was significantly easier than expected. Here's an example of what an extension class might look like:
```
<?php
final class AddRiskReviewHeraldCustomAction extends HeraldCustomAction {
public function appliesToAdapter(HeraldAdapter $adapter) {
return $adapter instanceof HeraldDifferentialRevisionAdapter;
}
public function appliesToRuleType($rule_type) {
return $rule_type == HeraldRuleTypeConfig::RULE_TYPE_GLOBAL ||
$rule_type == HeraldRuleTypeConfig::RULE_TYPE_OBJECT;
}
public function getActionKey() {
return 'custom:add-risk';
}
public function getActionName() {
return 'Add risk rating (JSON)';
}
public function getActionType() {
return HeraldAdapter::VALUE_TEXT;
}
public function applyEffect(
HeraldAdapter $adapter,
$object,
HeraldEffect $effect) {
$key = "phragile:risk-rating";
// Read existing value.
$field_list = PhabricatorCustomField::getObjectFields(
$object,
PhabricatorCustomField::ROLE_VIEW);
$field_list->readFieldsFromStorage($object);
$field_list = mpull($field_list->getFields(), null, 'getFieldKey');
$field = $field_list[$key];
$field->setObject($object);
$field->setViewer(PhabricatorUser::getOmnipotentUser());
$risk = $field->getValue();
$old_risk = $risk; // PHP copies arrays by default!
// Add new value to array.
$herald_args = phutil_json_decode($effect->getTarget());
$risk[$herald_args['key']] = array(
'value' => $herald_args['value'],
'reason' => $herald_args['reason']);
$risk_key = $herald_args['key'];
// Set new value.
$adapter->queueTransaction(
id(new DifferentialTransaction())
->setTransactionType(PhabricatorTransactions::TYPE_CUSTOMFIELD)
->setMetadataValue('customfield:key', $key)
->setOldValue($old_risk)
->setNewValue($risk));
return new HeraldApplyTranscript(
$effect,
true,
pht(
'Modifying automatic risk ratings (key: %s)!',
$risk_key));
}
}
```
Test Plan: Created a custom action for differential revisions, set up a Herald rule to match and trigger the custom action, did 'arc diff' and saw the action trigger in the transcripts.
Reviewers: epriestley, #blessed_reviewers
Reviewed By: epriestley, #blessed_reviewers
Subscribers: locutus, edutibau, ite-klass, epriestley, Korvin
Maniphest Tasks: T4884
Differential Revision: https://secure.phabricator.com/D8784
2014-07-02 06:29:46 +02:00
|
|
|
if (is_array($target) && $target) {
|
2012-03-30 22:51:54 +02:00
|
|
|
foreach ($target as $k => $phid) {
|
2014-03-17 23:02:10 +01:00
|
|
|
if (isset($handles[$phid])) {
|
|
|
|
$target[$k] = $handles[$phid]->getName();
|
|
|
|
}
|
2012-03-30 22:51:54 +02:00
|
|
|
}
|
2014-06-09 20:36:49 +02:00
|
|
|
$target = implode(', ', $target);
|
Support custom actions in Herald
Summary:
This was significantly easier than expected. Here's an example of what an extension class might look like:
```
<?php
final class AddRiskReviewHeraldCustomAction extends HeraldCustomAction {
public function appliesToAdapter(HeraldAdapter $adapter) {
return $adapter instanceof HeraldDifferentialRevisionAdapter;
}
public function appliesToRuleType($rule_type) {
return $rule_type == HeraldRuleTypeConfig::RULE_TYPE_GLOBAL ||
$rule_type == HeraldRuleTypeConfig::RULE_TYPE_OBJECT;
}
public function getActionKey() {
return 'custom:add-risk';
}
public function getActionName() {
return 'Add risk rating (JSON)';
}
public function getActionType() {
return HeraldAdapter::VALUE_TEXT;
}
public function applyEffect(
HeraldAdapter $adapter,
$object,
HeraldEffect $effect) {
$key = "phragile:risk-rating";
// Read existing value.
$field_list = PhabricatorCustomField::getObjectFields(
$object,
PhabricatorCustomField::ROLE_VIEW);
$field_list->readFieldsFromStorage($object);
$field_list = mpull($field_list->getFields(), null, 'getFieldKey');
$field = $field_list[$key];
$field->setObject($object);
$field->setViewer(PhabricatorUser::getOmnipotentUser());
$risk = $field->getValue();
$old_risk = $risk; // PHP copies arrays by default!
// Add new value to array.
$herald_args = phutil_json_decode($effect->getTarget());
$risk[$herald_args['key']] = array(
'value' => $herald_args['value'],
'reason' => $herald_args['reason']);
$risk_key = $herald_args['key'];
// Set new value.
$adapter->queueTransaction(
id(new DifferentialTransaction())
->setTransactionType(PhabricatorTransactions::TYPE_CUSTOMFIELD)
->setMetadataValue('customfield:key', $key)
->setOldValue($old_risk)
->setNewValue($risk));
return new HeraldApplyTranscript(
$effect,
true,
pht(
'Modifying automatic risk ratings (key: %s)!',
$risk_key));
}
}
```
Test Plan: Created a custom action for differential revisions, set up a Herald rule to match and trigger the custom action, did 'arc diff' and saw the action trigger in the transcripts.
Reviewers: epriestley, #blessed_reviewers
Reviewed By: epriestley, #blessed_reviewers
Subscribers: locutus, edutibau, ite-klass, epriestley, Korvin
Maniphest Tasks: T4884
Differential Revision: https://secure.phabricator.com/D8784
2014-07-02 06:29:46 +02:00
|
|
|
} else if (is_string($target)) {
|
|
|
|
$target = $target;
|
2012-03-30 22:51:54 +02:00
|
|
|
} else {
|
|
|
|
$target = '<empty>';
|
|
|
|
}
|
|
|
|
break;
|
2011-03-25 05:32:26 +01:00
|
|
|
}
|
|
|
|
|
2014-04-29 19:14:18 +02:00
|
|
|
$item = new PHUIObjectItemView();
|
|
|
|
|
2011-03-25 05:32:26 +01:00
|
|
|
if ($apply_xscript->getApplied()) {
|
2014-04-29 19:14:18 +02:00
|
|
|
$item->setState(PHUIObjectItemView::STATE_SUCCESS);
|
2011-03-25 05:32:26 +01:00
|
|
|
} else {
|
2014-04-29 19:14:18 +02:00
|
|
|
$item->setState(PHUIObjectItemView::STATE_FAIL);
|
2011-03-25 05:32:26 +01:00
|
|
|
}
|
|
|
|
|
2014-04-29 19:14:18 +02:00
|
|
|
$rule = idx($action_names, $apply_xscript->getAction(), pht('Unknown'));
|
2011-03-25 05:32:26 +01:00
|
|
|
|
2014-04-29 19:14:18 +02:00
|
|
|
$item->setHeader(pht('%s: %s', $rule, $target));
|
|
|
|
$item->addAttribute($apply_xscript->getReason());
|
|
|
|
$item->addAttribute(
|
|
|
|
pht('Outcome: %s', $apply_xscript->getAppliedReason()));
|
|
|
|
|
|
|
|
$list->addItem($item);
|
|
|
|
}
|
2011-03-25 05:32:26 +01:00
|
|
|
|
2014-04-27 20:18:48 +02:00
|
|
|
$box = new PHUIObjectBoxView();
|
|
|
|
$box->setHeaderText(pht('Actions Taken'));
|
2014-04-29 19:14:18 +02:00
|
|
|
$box->appendChild($list);
|
2011-03-25 05:32:26 +01:00
|
|
|
|
2014-04-27 20:18:48 +02:00
|
|
|
return $box;
|
2011-03-25 05:32:26 +01:00
|
|
|
}
|
|
|
|
|
2014-04-30 00:07:00 +02:00
|
|
|
private function buildActionTranscriptPanel(HeraldTranscript $xscript) {
|
2011-03-25 05:32:26 +01:00
|
|
|
$action_xscript = mgroup($xscript->getApplyTranscripts(), 'getRuleID');
|
|
|
|
|
2013-08-02 21:23:13 +02:00
|
|
|
$adapter = $this->getAdapter();
|
|
|
|
|
|
|
|
|
|
|
|
$field_names = $adapter->getFieldNameMap();
|
|
|
|
$condition_names = $adapter->getConditionNameMap();
|
2011-03-25 05:32:26 +01:00
|
|
|
|
|
|
|
$handles = $this->handles;
|
|
|
|
|
|
|
|
$rule_markup = array();
|
|
|
|
foreach ($xscript->getRuleTranscripts() as $rule_id => $rule) {
|
|
|
|
$cond_markup = array();
|
|
|
|
foreach ($xscript->getConditionTranscriptsForRule($rule_id) as $cond) {
|
|
|
|
if ($cond->getNote()) {
|
2013-11-11 18:23:23 +01:00
|
|
|
$note = phutil_tag_div('herald-condition-note', $cond->getNote());
|
2011-03-25 05:32:26 +01:00
|
|
|
} else {
|
|
|
|
$note = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($cond->getResult()) {
|
2013-11-11 18:23:23 +01:00
|
|
|
$result = phutil_tag(
|
|
|
|
'span',
|
|
|
|
array('class' => 'herald-outcome condition-pass'),
|
|
|
|
"\xE2\x9C\x93");
|
2011-03-25 05:32:26 +01:00
|
|
|
} else {
|
2013-11-11 18:23:23 +01:00
|
|
|
$result = phutil_tag(
|
|
|
|
'span',
|
|
|
|
array('class' => 'herald-outcome condition-fail'),
|
|
|
|
"\xE2\x9C\x98");
|
2011-03-25 05:32:26 +01:00
|
|
|
}
|
|
|
|
|
2013-02-08 21:07:44 +01:00
|
|
|
$cond_markup[] = phutil_tag(
|
|
|
|
'li',
|
|
|
|
array(),
|
2013-05-20 17:24:07 +02:00
|
|
|
pht(
|
2013-02-08 21:07:44 +01:00
|
|
|
'%s Condition: %s %s %s%s',
|
|
|
|
$result,
|
2013-08-02 21:23:13 +02:00
|
|
|
idx($field_names, $cond->getFieldName(), pht('Unknown')),
|
|
|
|
idx($condition_names, $cond->getCondition(), pht('Unknown')),
|
2013-02-08 21:07:44 +01:00
|
|
|
$this->renderConditionTestValue($cond, $handles),
|
|
|
|
$note));
|
2011-03-25 05:32:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if ($rule->getResult()) {
|
2013-11-11 18:23:23 +01:00
|
|
|
$result = phutil_tag(
|
|
|
|
'span',
|
|
|
|
array('class' => 'herald-outcome rule-pass'),
|
|
|
|
pht('PASS'));
|
2011-03-25 05:32:26 +01:00
|
|
|
$class = 'herald-rule-pass';
|
|
|
|
} else {
|
2013-11-11 18:23:23 +01:00
|
|
|
$result = phutil_tag(
|
|
|
|
'span',
|
|
|
|
array('class' => 'herald-outcome rule-fail'),
|
|
|
|
pht('FAIL'));
|
2011-03-25 05:32:26 +01:00
|
|
|
$class = 'herald-rule-fail';
|
|
|
|
}
|
|
|
|
|
2013-11-11 18:23:23 +01:00
|
|
|
$cond_markup[] = phutil_tag(
|
|
|
|
'li',
|
|
|
|
array(),
|
|
|
|
array($result, $rule->getReason()));
|
2011-03-25 05:32:26 +01:00
|
|
|
$user_phid = $this->getRequest()->getUser()->getPHID();
|
|
|
|
|
|
|
|
$name = $rule->getRuleName();
|
|
|
|
|
|
|
|
$rule_markup[] =
|
2013-02-08 21:07:44 +01:00
|
|
|
phutil_tag(
|
2011-03-25 05:32:26 +01:00
|
|
|
'li',
|
|
|
|
array(
|
|
|
|
'class' => $class,
|
|
|
|
),
|
2013-11-11 18:23:23 +01:00
|
|
|
phutil_tag_div('rule-name', array(
|
|
|
|
phutil_tag('strong', array(), $name),
|
|
|
|
' ',
|
|
|
|
phutil_tag('ul', array(), $cond_markup),
|
|
|
|
)));
|
2011-03-25 05:32:26 +01:00
|
|
|
}
|
|
|
|
|
2014-04-27 20:18:48 +02:00
|
|
|
$box = null;
|
2013-05-20 17:24:07 +02:00
|
|
|
if ($rule_markup) {
|
2014-04-27 20:18:48 +02:00
|
|
|
$box = new PHUIObjectBoxView();
|
|
|
|
$box->setHeaderText(pht('Rule Details'));
|
|
|
|
$box->appendChild(phutil_tag(
|
2013-05-20 17:24:07 +02:00
|
|
|
'ul',
|
|
|
|
array('class' => 'herald-explain-list'),
|
|
|
|
$rule_markup));
|
|
|
|
}
|
2014-04-27 20:18:48 +02:00
|
|
|
return $box;
|
2011-03-25 05:32:26 +01:00
|
|
|
}
|
|
|
|
|
2014-04-30 00:07:00 +02:00
|
|
|
private function buildObjectTranscriptPanel(HeraldTranscript $xscript) {
|
2011-03-25 05:32:26 +01:00
|
|
|
|
2013-08-02 21:23:13 +02:00
|
|
|
$adapter = $this->getAdapter();
|
|
|
|
$field_names = $adapter->getFieldNameMap();
|
2011-03-25 05:32:26 +01:00
|
|
|
|
|
|
|
$object_xscript = $xscript->getObjectTranscript();
|
|
|
|
|
|
|
|
$data = array();
|
|
|
|
if ($object_xscript) {
|
2011-04-12 04:32:46 +02:00
|
|
|
$phid = $object_xscript->getPHID();
|
2014-04-30 00:07:00 +02:00
|
|
|
$handles = $this->handles;
|
2011-04-12 04:32:46 +02:00
|
|
|
|
2011-03-25 05:32:26 +01:00
|
|
|
$data += array(
|
2013-05-20 17:24:07 +02:00
|
|
|
pht('Object Name') => $object_xscript->getName(),
|
|
|
|
pht('Object Type') => $object_xscript->getType(),
|
|
|
|
pht('Object PHID') => $phid,
|
|
|
|
pht('Object Link') => $handles[$phid]->renderLink(),
|
2011-03-25 05:32:26 +01:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
$data += $xscript->getMetadataMap();
|
|
|
|
|
|
|
|
if ($object_xscript) {
|
|
|
|
foreach ($object_xscript->getFields() as $field => $value) {
|
|
|
|
$field = idx($field_names, $field, '['.$field.'?]');
|
|
|
|
$data['Field: '.$field] = $value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$rows = array();
|
|
|
|
foreach ($data as $name => $value) {
|
Fix every HTML issue I could find
Summary:
I attempted to test every interface. I probably missed some stuff, but I at least have some level of confidence that the `phutil_tag` branch is fairly stable.
Fixed these issues:
[1] Fixed a Herald issue with object links in transcripts. Some actions return
links; this was previously hard-coded.
[2] DarkConsole refactoring created an issue where the "`" event handler registered too many times.
[3] Fixed a bug where `strlen($value)` was being checked, but fields may now return array(). Possibly we should implement phutil_is_empty_html() or similar.
[4] Fixed a undefined variable issue for image edit transactions.
[5] Fixed an issue with rendering participant transactions. This required phutil_safe_html() because `pht()` can't handle `array()` for `%s`.
[6] Fixed an issue where feed was entirely overescaped by reverting an overly ambitious render_tag -> tag.
[7] Fixed an issue with strict tables and inserting `''` instead of `0` into an integer column.
[8] Fixed an issue where • was shown escaped.
[9] Fixed an issue where "no data" was overescaped.
[10] Fixed an issue with strict tables and inserting `''` instead of `0` into an integer column.
[11] Fixed an issue with strict tables and inserting `''`.
[12] Fixed an issue with missing space after ":" for mini panels.
Encountered (but did not fix) these issues:
[X1] "e" works incorrectly on comments you are not allowed to edit. Did not fix.
[X2] Coverage currently interacts incorrectly with "--everything" for Phutil tests.
Test Plan:
- Viewed Differential.
- Created a diff via copy/paste.
- Viewed standalone diff.
- Jumped to diff via changeset table.
- Created a revision.
- Updated revision.
- Added a comment.
- Edited revision dependencies.
- Edited revision tasks.
- Viewed MetaMTA transcripts.
- Viewed Herald transcripts [1].
- Downloaded raw diff.
- Flagged / unflagged revision.
- Added/edited/deleted inline comment.
- Collapsed/expanded file.
- Did show raw left.
- Did show raw right.
- Checked previews for available actions.
- Clicked remarkup buttons
- Used filetree view.
- Used keyboard: F, j, k, J, K, n, p, t, h, "?" [2] [X1].
- Created a meme.
- Uploaded a file via drag and drop.
- Viewed a revision with no reviewers.
- Viewed a revision with >100 files.
- Viewed various other revisions [3].
- Viewed an image diff.
- Added image diff inline comments.
- Viewed Maniphest.
- Ran various queries.
- Created task.
- Created similar task.
- Added comments to tasks.
- Ran custom query.
- Saved custom query.
- Edited custom queries.
- Drag-reordered tasks.
- Batch edited tasks.
- Exported tasks to excel.
- Looked at reports (issue in T2311 notwithstanding).
- Viewed Diffusion.
- Browsed Git, SVN, HG repositories.
- Looked at history, browse, change, commit views.
- Viewed audit.
- Performed various audit searches.
- Viewed Paste.
- Performed paste searches.
- Created, edited, forked paste.
- Viewed Phriction.
- Edited a page.
- Viewed edit history.
- Used search typeahead to search for user / application.
- Used search to search for text.
- Viewed Phame.
- Viewed Blog, Post.
- Viewed live post.
- Published/unpublished post.
- Previewed post.
- Viewed Pholio.
- Edited/commented mock.
- Viewed ponder.
- Viewed question.
- Added answer/comment.
- Viewed Diviner.
- Viewed Conpherence [4] [5].
- Made Conpherence updates.
- Viewed calendar.
- Created status.
- Viewed status.
- Viewed Feed [6].
- Viewed Projects.
- Viewed project detail.
- Edited project.
- Viewed Owners.
- Viewed package detail.
- Edited package [7].
- Viewed flags.
- Edited flag.
- Deleted flag.
- Viewed Herald.
- Viewed rules.
- Created rule.
- Edited rule.
- Viewed edit log.
- Viewed transcripts.
- Inspected a transcript.
- Viewed People.
- Viewed list.
- Administrated user.
- Checked username/delete stuff.
- Looked at create/import LDAP/activity logs.
- Looked at a user profile.
- Looked at user about page.
- Looked at Repositories.
- Edited repository.
- Edited arcanist project.
- Looked at daemons.
- Looked at all daemons [8].
- Viewed combined log.
- Looked at configuration.
- Edited configuration.
- Looked at setup issues [9].
- Looked at current settings.
- Looked at application list.
- Installed / uninstalled applications [10].
- Looked at mailing lists.
- Created a mailing list.
- Edited a mailing list.
- Looked at sent mail.
- Looked at received mail.
- Looked at send/receive tests.
- Looked at settings.
- Clicked through all the panels.
- Looked at slowvote.
- Created a slowvote [11].
- Voted in a slowvote.
- Looked at Macro.
- Created a macro.
- Edited a macro.
- Commented on a macro.
- Looked at Countdown.
- Created a Countdown.
- Looked at it.
- Looked at Drydock.
- Poked around a bit.
- Looked at Fact.
- Poked around a bit.
- Looked at files.
- Looked at a file.
- Uploaded a file.
- Looked at Conduit.
- Made a Conduit call.
- Looked at UIExamples.
- Looked at PHPAST.
- Looked at PHIDs.
- Looked at notification menu.
- Looked at notification detail.
- Logged out.
- Logged in.
- Looked at homepage [12].
- Ran `arc unit --everything --no-coverage` [X2].
Reviewers: vrana, btrahan
Reviewed By: vrana
CC: aran
Maniphest Tasks: T2432
Differential Revision: https://secure.phabricator.com/D4807
2013-02-05 02:06:34 +01:00
|
|
|
if (!($value instanceof PhutilSafeHTML)) {
|
|
|
|
if (!is_scalar($value) && !is_null($value)) {
|
|
|
|
$value = implode("\n", $value);
|
|
|
|
}
|
2011-03-25 05:32:26 +01:00
|
|
|
|
Fix every HTML issue I could find
Summary:
I attempted to test every interface. I probably missed some stuff, but I at least have some level of confidence that the `phutil_tag` branch is fairly stable.
Fixed these issues:
[1] Fixed a Herald issue with object links in transcripts. Some actions return
links; this was previously hard-coded.
[2] DarkConsole refactoring created an issue where the "`" event handler registered too many times.
[3] Fixed a bug where `strlen($value)` was being checked, but fields may now return array(). Possibly we should implement phutil_is_empty_html() or similar.
[4] Fixed a undefined variable issue for image edit transactions.
[5] Fixed an issue with rendering participant transactions. This required phutil_safe_html() because `pht()` can't handle `array()` for `%s`.
[6] Fixed an issue where feed was entirely overescaped by reverting an overly ambitious render_tag -> tag.
[7] Fixed an issue with strict tables and inserting `''` instead of `0` into an integer column.
[8] Fixed an issue where • was shown escaped.
[9] Fixed an issue where "no data" was overescaped.
[10] Fixed an issue with strict tables and inserting `''` instead of `0` into an integer column.
[11] Fixed an issue with strict tables and inserting `''`.
[12] Fixed an issue with missing space after ":" for mini panels.
Encountered (but did not fix) these issues:
[X1] "e" works incorrectly on comments you are not allowed to edit. Did not fix.
[X2] Coverage currently interacts incorrectly with "--everything" for Phutil tests.
Test Plan:
- Viewed Differential.
- Created a diff via copy/paste.
- Viewed standalone diff.
- Jumped to diff via changeset table.
- Created a revision.
- Updated revision.
- Added a comment.
- Edited revision dependencies.
- Edited revision tasks.
- Viewed MetaMTA transcripts.
- Viewed Herald transcripts [1].
- Downloaded raw diff.
- Flagged / unflagged revision.
- Added/edited/deleted inline comment.
- Collapsed/expanded file.
- Did show raw left.
- Did show raw right.
- Checked previews for available actions.
- Clicked remarkup buttons
- Used filetree view.
- Used keyboard: F, j, k, J, K, n, p, t, h, "?" [2] [X1].
- Created a meme.
- Uploaded a file via drag and drop.
- Viewed a revision with no reviewers.
- Viewed a revision with >100 files.
- Viewed various other revisions [3].
- Viewed an image diff.
- Added image diff inline comments.
- Viewed Maniphest.
- Ran various queries.
- Created task.
- Created similar task.
- Added comments to tasks.
- Ran custom query.
- Saved custom query.
- Edited custom queries.
- Drag-reordered tasks.
- Batch edited tasks.
- Exported tasks to excel.
- Looked at reports (issue in T2311 notwithstanding).
- Viewed Diffusion.
- Browsed Git, SVN, HG repositories.
- Looked at history, browse, change, commit views.
- Viewed audit.
- Performed various audit searches.
- Viewed Paste.
- Performed paste searches.
- Created, edited, forked paste.
- Viewed Phriction.
- Edited a page.
- Viewed edit history.
- Used search typeahead to search for user / application.
- Used search to search for text.
- Viewed Phame.
- Viewed Blog, Post.
- Viewed live post.
- Published/unpublished post.
- Previewed post.
- Viewed Pholio.
- Edited/commented mock.
- Viewed ponder.
- Viewed question.
- Added answer/comment.
- Viewed Diviner.
- Viewed Conpherence [4] [5].
- Made Conpherence updates.
- Viewed calendar.
- Created status.
- Viewed status.
- Viewed Feed [6].
- Viewed Projects.
- Viewed project detail.
- Edited project.
- Viewed Owners.
- Viewed package detail.
- Edited package [7].
- Viewed flags.
- Edited flag.
- Deleted flag.
- Viewed Herald.
- Viewed rules.
- Created rule.
- Edited rule.
- Viewed edit log.
- Viewed transcripts.
- Inspected a transcript.
- Viewed People.
- Viewed list.
- Administrated user.
- Checked username/delete stuff.
- Looked at create/import LDAP/activity logs.
- Looked at a user profile.
- Looked at user about page.
- Looked at Repositories.
- Edited repository.
- Edited arcanist project.
- Looked at daemons.
- Looked at all daemons [8].
- Viewed combined log.
- Looked at configuration.
- Edited configuration.
- Looked at setup issues [9].
- Looked at current settings.
- Looked at application list.
- Installed / uninstalled applications [10].
- Looked at mailing lists.
- Created a mailing list.
- Edited a mailing list.
- Looked at sent mail.
- Looked at received mail.
- Looked at send/receive tests.
- Looked at settings.
- Clicked through all the panels.
- Looked at slowvote.
- Created a slowvote [11].
- Voted in a slowvote.
- Looked at Macro.
- Created a macro.
- Edited a macro.
- Commented on a macro.
- Looked at Countdown.
- Created a Countdown.
- Looked at it.
- Looked at Drydock.
- Poked around a bit.
- Looked at Fact.
- Poked around a bit.
- Looked at files.
- Looked at a file.
- Uploaded a file.
- Looked at Conduit.
- Made a Conduit call.
- Looked at UIExamples.
- Looked at PHPAST.
- Looked at PHIDs.
- Looked at notification menu.
- Looked at notification detail.
- Logged out.
- Logged in.
- Looked at homepage [12].
- Ran `arc unit --everything --no-coverage` [X2].
Reviewers: vrana, btrahan
Reviewed By: vrana
CC: aran
Maniphest Tasks: T2432
Differential Revision: https://secure.phabricator.com/D4807
2013-02-05 02:06:34 +01:00
|
|
|
if (strlen($value) > 256) {
|
|
|
|
$value = phutil_tag(
|
|
|
|
'textarea',
|
|
|
|
array(
|
|
|
|
'class' => 'herald-field-value-transcript',
|
|
|
|
),
|
|
|
|
$value);
|
|
|
|
}
|
2011-03-25 05:32:26 +01:00
|
|
|
}
|
|
|
|
|
2013-02-13 23:50:15 +01:00
|
|
|
$rows[] = array($name, $value);
|
2011-03-25 05:32:26 +01:00
|
|
|
}
|
|
|
|
|
2014-04-27 20:18:48 +02:00
|
|
|
$property_list = new PHUIPropertyListView();
|
2014-04-29 16:04:22 +02:00
|
|
|
$property_list->setStacked(true);
|
2014-04-27 20:18:48 +02:00
|
|
|
foreach ($rows as $row) {
|
|
|
|
$property_list->addProperty($row[0], $row[1]);
|
|
|
|
}
|
2011-03-25 05:32:26 +01:00
|
|
|
|
2014-04-27 20:18:48 +02:00
|
|
|
$box = new PHUIObjectBoxView();
|
|
|
|
$box->setHeaderText(pht('Object Transcript'));
|
|
|
|
$box->appendChild($property_list);
|
2011-03-25 05:32:26 +01:00
|
|
|
|
2014-04-27 20:18:48 +02:00
|
|
|
return $box;
|
2011-03-25 05:32:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|