Page MenuHomePhorge

No OneTemporary

diff --git a/src/applications/diffusion/controller/DiffusionController.php b/src/applications/diffusion/controller/DiffusionController.php
index 14c819614e..25cc6513a4 100644
--- a/src/applications/diffusion/controller/DiffusionController.php
+++ b/src/applications/diffusion/controller/DiffusionController.php
@@ -1,238 +1,274 @@
<?php
abstract class DiffusionController extends PhabricatorController {
protected $diffusionRequest;
+ public function setDiffusionRequest(DiffusionRequest $request) {
+ $this->diffusionRequest = $request;
+ return $this;
+ }
+
+ protected function getDiffusionRequest() {
+ if (!$this->diffusionRequest) {
+ throw new Exception("No Diffusion request object!");
+ }
+ return $this->diffusionRequest;
+ }
+
public function willBeginExecution() {
$request = $this->getRequest();
// Check if this is a VCS request, e.g. from "git clone", "hg clone", or
// "svn checkout". If it is, we jump off into repository serving code to
// process the request.
if (DiffusionServeController::isVCSRequest($request)) {
$serve_controller = id(new DiffusionServeController($request))
->setCurrentApplication($this->getCurrentApplication());
return $this->delegateToController($serve_controller);
}
return parent::willBeginExecution();
}
public function willProcessRequest(array $data) {
if (isset($data['callsign'])) {
$drequest = DiffusionRequest::newFromAphrontRequestDictionary(
$data,
$this->getRequest());
- $this->diffusionRequest = $drequest;
+ $this->setDiffusionRequest($drequest);
}
}
- public function setDiffusionRequest(DiffusionRequest $request) {
- $this->diffusionRequest = $request;
- return $this;
- }
-
- protected function getDiffusionRequest() {
- if (!$this->diffusionRequest) {
- throw new Exception("No Diffusion request object!");
+ public function buildApplicationPage($view, array $options) {
+ $drequest = $this->getDiffusionRequest();
+ $repository = $drequest->getRepository();
+ $error_view = $this->buildRepositoryWarning($repository);
+
+ $views = array();
+ $not_inserted = true;
+ foreach ($view as $view_object_or_array) {
+ $views[] = $view_object_or_array;
+ if ($not_inserted &&
+ $view_object_or_array instanceof PhabricatorCrumbsView) {
+ $views[] = $error_view;
+ $not_inserted = false;
+ }
}
- return $this->diffusionRequest;
+ return parent::buildApplicationPage($views, $options);
}
public function buildCrumbs(array $spec = array()) {
$crumbs = $this->buildApplicationCrumbs();
$crumb_list = $this->buildCrumbList($spec);
foreach ($crumb_list as $crumb) {
$crumbs->addCrumb($crumb);
}
return $crumbs;
}
private function buildCrumbList(array $spec = array()) {
$spec = $spec + array(
'commit' => null,
'tags' => null,
'branches' => null,
'view' => null,
);
$crumb_list = array();
// On the home page, we don't have a DiffusionRequest.
if ($this->diffusionRequest) {
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
} else {
$drequest = null;
$repository = null;
}
if (!$repository) {
return $crumb_list;
}
$callsign = $repository->getCallsign();
$repository_name = $repository->getName();
if (!$spec['commit'] && !$spec['tags'] && !$spec['branches']) {
$branch_name = $drequest->getBranch();
if ($branch_name) {
$repository_name .= ' ('.$branch_name.')';
}
}
$crumb = id(new PhabricatorCrumbView())
->setName($repository_name);
if (!$spec['view'] && !$spec['commit'] &&
!$spec['tags'] && !$spec['branches']) {
$crumb_list[] = $crumb;
return $crumb_list;
}
$crumb->setHref(
$drequest->generateURI(
array(
'action' => 'branch',
'path' => '/',
)));
$crumb_list[] = $crumb;
$raw_commit = $drequest->getRawCommit();
if ($spec['tags']) {
$crumb = new PhabricatorCrumbView();
if ($spec['commit']) {
$crumb->setName(
pht("Tags for %s", 'r'.$callsign.$raw_commit));
$crumb->setHref($drequest->generateURI(
array(
'action' => 'commit',
'commit' => $raw_commit,
)));
} else {
$crumb->setName(pht('Tags'));
}
$crumb_list[] = $crumb;
return $crumb_list;
}
if ($spec['branches']) {
$crumb = id(new PhabricatorCrumbView())
->setName(pht('Branches'));
$crumb_list[] = $crumb;
return $crumb_list;
}
if ($spec['commit']) {
$crumb = id(new PhabricatorCrumbView())
->setName("r{$callsign}{$raw_commit}")
->setHref("r{$callsign}{$raw_commit}");
$crumb_list[] = $crumb;
return $crumb_list;
}
$crumb = new PhabricatorCrumbView();
$view = $spec['view'];
switch ($view) {
case 'history':
$view_name = pht('History');
break;
case 'browse':
$view_name = pht('Browse');
break;
case 'lint':
$view_name = pht('Lint');
break;
case 'change':
$view_name = pht('Change');
break;
}
$crumb = id(new PhabricatorCrumbView())
->setName($view_name);
$crumb_list[] = $crumb;
return $crumb_list;
}
protected function callConduitWithDiffusionRequest(
$method,
array $params = array()) {
$user = $this->getRequest()->getUser();
$drequest = $this->getDiffusionRequest();
return DiffusionQuery::callConduitWithDiffusionRequest(
$user,
$drequest,
$method,
$params);
}
protected function getRepositoryControllerURI(
PhabricatorRepository $repository,
$path) {
return $this->getApplicationURI($repository->getCallsign().'/'.$path);
}
protected function renderPathLinks(DiffusionRequest $drequest, $action) {
$path = $drequest->getPath();
$path_parts = array_filter(explode('/', trim($path, '/')));
$divider = phutil_tag(
'span',
array(
'class' => 'phui-header-divider'),
'/');
$links = array();
if ($path_parts) {
$links[] = phutil_tag(
'a',
array(
'href' => $drequest->generateURI(
array(
'action' => $action,
'path' => '',
)),
),
'r'.$drequest->getRepository()->getCallsign());
$links[] = $divider;
$accum = '';
$last_key = last_key($path_parts);
foreach ($path_parts as $key => $part) {
$accum .= '/'.$part;
if ($key === $last_key) {
$links[] = $part;
} else {
$links[] = phutil_tag(
'a',
array(
'href' => $drequest->generateURI(
array(
'action' => $action,
'path' => $accum.'/',
)),
),
$part);
$links[] = $divider;
}
}
} else {
$links[] = 'r'.$drequest->getRepository()->getCallsign();
$links[] = $divider;
}
return $links;
}
protected function renderStatusMessage($title, $body) {
return id(new AphrontErrorView())
->setSeverity(AphrontErrorView::SEVERITY_WARNING)
->setTitle($title)
->appendChild($body);
}
+ private function buildRepositoryWarning(PhabricatorRepository $repository) {
+ $error_view = null;
+ if ($repository->isImporting()) {
+ $title = pht('This repository is still importing.');
+ $body = pht('Things may not work properly until the import finishes.');
+ } else if (!$repository->isTracked()) {
+ $title = pht('This repository is not tracked.');
+ $body = pht(
+ 'Things may not work properly until tracking is enabled and '.
+ 'importing finishes.');
+ }
+
+ if ($title) {
+ $error_view = $this->renderStatusMessage($title, $body);
+ }
+
+ return $error_view;
+ }
}
diff --git a/src/applications/herald/controller/HeraldTranscriptController.php b/src/applications/herald/controller/HeraldTranscriptController.php
index 14a2d04cd3..8a44face99 100644
--- a/src/applications/herald/controller/HeraldTranscriptController.php
+++ b/src/applications/herald/controller/HeraldTranscriptController.php
@@ -1,508 +1,551 @@
<?php
final class HeraldTranscriptController extends HeraldController {
const FILTER_AFFECTED = 'affected';
const FILTER_OWNED = 'owned';
const FILTER_ALL = 'all';
private $id;
private $filter;
private $handles;
private $adapter;
public function willProcessRequest(array $data) {
$this->id = $data['id'];
$map = $this->getFilterMap();
$this->filter = idx($data, 'filter');
if (empty($map[$this->filter])) {
$this->filter = self::FILTER_ALL;
}
}
private function getAdapter() {
return $this->adapter;
}
public function processRequest() {
$request = $this->getRequest();
$viewer = $request->getUser();
$xscript = id(new HeraldTranscriptQuery())
->setViewer($viewer)
->withIDs(array($this->id))
->executeOne();
if (!$xscript) {
return new Aphront404Response();
}
require_celerity_resource('herald-test-css');
$nav = $this->buildSideNav();
$object_xscript = $xscript->getObjectTranscript();
if (!$object_xscript) {
$notice = id(new AphrontErrorView())
->setSeverity(AphrontErrorView::SEVERITY_NOTICE)
->setTitle(pht('Old Transcript'))
->appendChild(phutil_tag(
'p',
array(),
pht('Details of this transcript have been garbage collected.')));
$nav->appendChild($notice);
} else {
$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(
pht("This transcript has an invalid or inaccessible adapter."));
}
$this->adapter = HeraldAdapter::getAdapterForContentType($object_type);
$filter = $this->getFilterPHIDs();
$this->filterTranscript($xscript, $filter);
$phids = array_merge($filter, $this->getTranscriptPHIDs($xscript));
$phids = array_unique($phids);
$phids = array_filter($phids);
$handles = $this->loadViewerHandles($phids);
$this->handles = $handles;
if ($xscript->getDryRun()) {
$notice = new AphrontErrorView();
$notice->setSeverity(AphrontErrorView::SEVERITY_NOTICE);
$notice->setTitle(pht('Dry Run'));
$notice->appendChild(pht('This was a dry run to test Herald '.
'rules, no actions were executed.'));
$nav->appendChild($notice);
}
+ $warning_panel = $this->buildWarningPanel($xscript);
+ $nav->appendChild($warning_panel);
+
$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);
}
$crumbs = id($this->buildApplicationCrumbs())
->addTextCrumb(
pht('Transcripts'),
$this->getApplicationURI('/transcript/'))
->addTextCrumb($xscript->getID());
$nav->setCrumbs($crumbs);
return $this->buildApplicationPage(
$nav,
array(
'title' => pht('Transcript'),
'device' => true,
));
}
protected function renderConditionTestValue($condition, $handles) {
switch ($condition->getFieldName()) {
case HeraldAdapter::FIELD_RULE:
$value = array($condition->getTestValue());
break;
default:
$value = $condition->getTestValue();
break;
}
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);
}
return phutil_tag('span', array('class' => 'condition-test-value'), $value);
}
private function buildSideNav() {
$nav = new AphrontSideNavFilterView();
$nav->setBaseURI(new PhutilURI('/herald/transcript/'.$this->id.'/'));
$items = array();
$filters = $this->getFilterMap();
foreach ($filters as $key => $name) {
$nav->addFilter($key, $name);
}
$nav->selectFilter($this->filter, null);
return $nav;
}
protected function getFilterMap() {
return array(
self::FILTER_ALL => pht('All Rules'),
self::FILTER_OWNED => pht('Rules I Own'),
self::FILTER_AFFECTED => pht('Rules that Affected Me'),
);
}
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) {
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;
}
}
}
break;
}
}
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) {
if (empty($rule_xscripts[$rule_id])) {
// 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));
}
- private function buildApplyTranscriptPanel($xscript) {
+ 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) {
$handles = $this->handles;
$adapter = $this->getAdapter();
$rule_type_global = HeraldRuleTypeConfig::RULE_TYPE_GLOBAL;
$action_names = $adapter->getActionNameMap($rule_type_global);
$list = new PHUIObjectItemListView();
$list->setStates(true);
$list->setNoDataString(pht('No actions were taken.'));
foreach ($xscript->getApplyTranscripts() as $apply_xscript) {
$target = $apply_xscript->getTarget();
switch ($apply_xscript->getAction()) {
case HeraldAdapter::ACTION_NOTHING:
$target = null;
break;
case HeraldAdapter::ACTION_FLAG:
$target = PhabricatorFlagColor::getColorName($target);
break;
case HeraldAdapter::ACTION_BLOCK:
// Target is a text string.
$target = $target;
break;
default:
if ($target) {
foreach ($target as $k => $phid) {
if (isset($handles[$phid])) {
$target[$k] = $handles[$phid]->getName();
}
}
$target = implode(", ", $target);
} else {
$target = '<empty>';
}
break;
}
$item = new PHUIObjectItemView();
if ($apply_xscript->getApplied()) {
$item->setState(PHUIObjectItemView::STATE_SUCCESS);
} else {
$item->setState(PHUIObjectItemView::STATE_FAIL);
}
$rule = idx($action_names, $apply_xscript->getAction(), pht('Unknown'));
$item->setHeader(pht('%s: %s', $rule, $target));
$item->addAttribute($apply_xscript->getReason());
$item->addAttribute(
pht('Outcome: %s', $apply_xscript->getAppliedReason()));
$list->addItem($item);
}
$box = new PHUIObjectBoxView();
$box->setHeaderText(pht('Actions Taken'));
$box->appendChild($list);
return $box;
}
- private function buildActionTranscriptPanel($xscript) {
+ private function buildActionTranscriptPanel(HeraldTranscript $xscript) {
$action_xscript = mgroup($xscript->getApplyTranscripts(), 'getRuleID');
$adapter = $this->getAdapter();
$field_names = $adapter->getFieldNameMap();
$condition_names = $adapter->getConditionNameMap();
$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()) {
$note = phutil_tag_div('herald-condition-note', $cond->getNote());
} else {
$note = null;
}
if ($cond->getResult()) {
$result = phutil_tag(
'span',
array('class' => 'herald-outcome condition-pass'),
"\xE2\x9C\x93");
} else {
$result = phutil_tag(
'span',
array('class' => 'herald-outcome condition-fail'),
"\xE2\x9C\x98");
}
$cond_markup[] = phutil_tag(
'li',
array(),
pht(
'%s Condition: %s %s %s%s',
$result,
idx($field_names, $cond->getFieldName(), pht('Unknown')),
idx($condition_names, $cond->getCondition(), pht('Unknown')),
$this->renderConditionTestValue($cond, $handles),
$note));
}
if ($rule->getResult()) {
$result = phutil_tag(
'span',
array('class' => 'herald-outcome rule-pass'),
pht('PASS'));
$class = 'herald-rule-pass';
} else {
$result = phutil_tag(
'span',
array('class' => 'herald-outcome rule-fail'),
pht('FAIL'));
$class = 'herald-rule-fail';
}
$cond_markup[] = phutil_tag(
'li',
array(),
array($result, $rule->getReason()));
$user_phid = $this->getRequest()->getUser()->getPHID();
$name = $rule->getRuleName();
$rule_markup[] =
phutil_tag(
'li',
array(
'class' => $class,
),
phutil_tag_div('rule-name', array(
phutil_tag('strong', array(), $name),
' ',
phutil_tag('ul', array(), $cond_markup),
)));
}
$box = null;
if ($rule_markup) {
$box = new PHUIObjectBoxView();
$box->setHeaderText(pht('Rule Details'));
$box->appendChild(phutil_tag(
'ul',
array('class' => 'herald-explain-list'),
$rule_markup));
}
return $box;
}
- private function buildObjectTranscriptPanel($xscript) {
+ private function buildObjectTranscriptPanel(HeraldTranscript $xscript) {
$adapter = $this->getAdapter();
$field_names = $adapter->getFieldNameMap();
$object_xscript = $xscript->getObjectTranscript();
$data = array();
if ($object_xscript) {
$phid = $object_xscript->getPHID();
- $handles = $this->loadViewerHandles(array($phid));
+ $handles = $this->handles;
$data += array(
pht('Object Name') => $object_xscript->getName(),
pht('Object Type') => $object_xscript->getType(),
pht('Object PHID') => $phid,
pht('Object Link') => $handles[$phid]->renderLink(),
);
}
$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) {
if (!($value instanceof PhutilSafeHTML)) {
if (!is_scalar($value) && !is_null($value)) {
$value = implode("\n", $value);
}
if (strlen($value) > 256) {
$value = phutil_tag(
'textarea',
array(
'class' => 'herald-field-value-transcript',
),
$value);
}
}
$rows[] = array($name, $value);
}
$property_list = new PHUIPropertyListView();
$property_list->setStacked(true);
foreach ($rows as $row) {
$property_list->addProperty($row[0], $row[1]);
}
$box = new PHUIObjectBoxView();
$box->setHeaderText(pht('Object Transcript'));
$box->appendChild($property_list);
return $box;
}
}

File Metadata

Mime Type
text/x-diff
Expires
Sun, Jan 19, 17:28 (1 w, 5 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1126968
Default Alt Text
(25 KB)

Event Timeline