Page MenuHomestyx hydra

No OneTemporary

diff --git a/src/applications/harbormaster/storage/build/HarbormasterBuildUnitMessage.php b/src/applications/harbormaster/storage/build/HarbormasterBuildUnitMessage.php
index 9e437efaba..f2632153c3 100644
--- a/src/applications/harbormaster/storage/build/HarbormasterBuildUnitMessage.php
+++ b/src/applications/harbormaster/storage/build/HarbormasterBuildUnitMessage.php
@@ -1,313 +1,385 @@
<?php
final class HarbormasterBuildUnitMessage
extends HarbormasterDAO
implements PhabricatorPolicyInterface {
protected $buildTargetPHID;
protected $engine;
protected $namespace;
protected $name;
protected $nameIndex;
protected $result;
protected $duration;
protected $properties = array();
private $buildTarget = self::ATTACHABLE;
const FORMAT_TEXT = 'text';
const FORMAT_REMARKUP = 'remarkup';
public static function initializeNewUnitMessage(
HarbormasterBuildTarget $build_target) {
return id(new HarbormasterBuildUnitMessage())
->setBuildTargetPHID($build_target->getPHID());
}
public static function getParameterSpec() {
return array(
'name' => array(
'type' => 'string',
'description' => pht(
'Short test name, like "ExampleTest".'),
),
'result' => array(
'type' => 'string',
'description' => pht(
'Result of the test.'),
),
'namespace' => array(
'type' => 'optional string',
'description' => pht(
'Optional namespace for this test. This is organizational and '.
'is often a class or module name, like "ExampleTestCase".'),
),
'engine' => array(
'type' => 'optional string',
'description' => pht(
'Test engine running the test, like "JavascriptTestEngine". This '.
'primarily prevents collisions between tests with the same name '.
'in different test suites (for example, a Javascript test and a '.
'Python test).'),
),
'duration' => array(
'type' => 'optional float|int',
'description' => pht(
'Runtime duration of the test, in seconds.'),
),
'path' => array(
'type' => 'optional string',
'description' => pht(
'Path to the file where the test is declared, relative to the '.
'project root.'),
),
'coverage' => array(
'type' => 'optional map<string, wild>',
'description' => pht(
'Coverage information for this test.'),
),
'details' => array(
'type' => 'optional string',
'description' => pht(
'Additional human-readable information about the failure.'),
),
'format' => array(
'type' => 'optional string',
'description' => pht(
'Format for the text provided in "details". Valid values are '.
'"text" (default) or "remarkup". This controls how test details '.
'are rendered when shown to users.'),
),
);
}
public static function newFromDictionary(
HarbormasterBuildTarget $build_target,
array $dict) {
$obj = self::initializeNewUnitMessage($build_target);
$spec = self::getParameterSpec();
$spec = ipull($spec, 'type');
// We're just going to ignore extra keys for now, to make it easier to
// add stuff here later on.
$dict = array_select_keys($dict, array_keys($spec));
PhutilTypeSpec::checkMap($dict, $spec);
$obj->setEngine(idx($dict, 'engine', ''));
$obj->setNamespace(idx($dict, 'namespace', ''));
$obj->setName($dict['name']);
$obj->setResult($dict['result']);
$obj->setDuration((float)idx($dict, 'duration'));
$path = idx($dict, 'path');
if (strlen($path)) {
$obj->setProperty('path', $path);
}
$coverage = idx($dict, 'coverage');
if ($coverage) {
$obj->setProperty('coverage', $coverage);
}
$details = idx($dict, 'details');
if ($details) {
$obj->setProperty('details', $details);
}
$format = idx($dict, 'format');
if ($format) {
$obj->setProperty('format', $format);
}
return $obj;
}
protected function getConfiguration() {
return array(
self::CONFIG_SERIALIZATION => array(
'properties' => self::SERIALIZATION_JSON,
),
self::CONFIG_COLUMN_SCHEMA => array(
'engine' => 'text255',
'namespace' => 'text255',
'name' => 'text255',
'nameIndex' => 'bytes12',
'result' => 'text32',
'duration' => 'double?',
),
self::CONFIG_KEY_SCHEMA => array(
'key_target' => array(
'columns' => array('buildTargetPHID'),
),
),
) + parent::getConfiguration();
}
public function attachBuildTarget(HarbormasterBuildTarget $build_target) {
$this->buildTarget = $build_target;
return $this;
}
public function getBuildTarget() {
return $this->assertAttached($this->buildTarget);
}
public function getProperty($key, $default = null) {
return idx($this->properties, $key, $default);
}
public function setProperty($key, $value) {
$this->properties[$key] = $value;
return $this;
}
public function getUnitMessageDetails() {
return $this->getProperty('details', '');
}
public function getUnitMessageDetailsFormat() {
return $this->getProperty('format', self::FORMAT_TEXT);
}
public function newUnitMessageDetailsView(
PhabricatorUser $viewer,
$summarize = false) {
$format = $this->getUnitMessageDetailsFormat();
$is_text = ($format !== self::FORMAT_REMARKUP);
$is_remarkup = ($format === self::FORMAT_REMARKUP);
+ $message = null;
$full_details = $this->getUnitMessageDetails();
+ $byte_length = strlen($full_details);
- if (!strlen($full_details)) {
+ $text_limit = 1024 * 2;
+ $remarkup_limit = 1024 * 8;
+
+ if (!$byte_length) {
if ($summarize) {
return null;
}
- $details = phutil_tag('em', array(), pht('No details provided.'));
+ $message = phutil_tag('em', array(), pht('No details provided.'));
} else if ($summarize) {
if ($is_text) {
$details = id(new PhutilUTF8StringTruncator())
- ->setMaximumBytes(2048)
+ ->setMaximumBytes($text_limit)
->truncateString($full_details);
$details = phutil_split_lines($details);
$limit = 3;
if (count($details) > $limit) {
$details = array_slice($details, 0, $limit);
}
$details = implode('', $details);
} else {
- $details = $full_details;
+ if ($byte_length > $remarkup_limit) {
+ $uri = $this->getURI();
+
+ if ($uri) {
+ $link = phutil_tag(
+ 'a',
+ array(
+ 'href' => $uri,
+ 'target' => '_blank',
+ ),
+ pht('View Details'));
+ } else {
+ $link = null;
+ }
+
+ $message = array();
+ $message[] = phutil_tag(
+ 'em',
+ array(),
+ pht('This test has too much data to display inline.'));
+ if ($link) {
+ $message[] = $link;
+ }
+
+ $message = phutil_implode_html(" \xC2\xB7 ", $message);
+ } else {
+ $details = $full_details;
+ }
}
} else {
$details = $full_details;
}
require_celerity_resource('harbormaster-css');
$classes = array();
$classes[] = 'harbormaster-unit-details';
- if ($is_remarkup) {
+ if ($message !== null) {
+ // If we have a message, show that instead of rendering any test details.
+ $details = $message;
+ } else if ($is_remarkup) {
$details = new PHUIRemarkupView($viewer, $details);
} else {
$classes[] = 'harbormaster-unit-details-text';
$classes[] = 'PhabricatorMonospaced';
}
- return phutil_tag(
+ $warning = null;
+ if (!$summarize) {
+ $warnings = array();
+
+ if ($is_remarkup && ($byte_length > $remarkup_limit)) {
+ $warnings[] = pht(
+ 'This test result has %s bytes of Remarkup test details. Remarkup '.
+ 'blocks longer than %s bytes are not rendered inline when showing '.
+ 'test summaries.',
+ new PhutilNumber($byte_length),
+ new PhutilNumber($remarkup_limit));
+ }
+
+ if ($warnings) {
+ $warning = id(new PHUIInfoView())
+ ->setSeverity(PHUIInfoView::SEVERITY_WARNING)
+ ->setErrors($warnings);
+ }
+ }
+
+ $content = phutil_tag(
'div',
array(
'class' => implode(' ', $classes),
),
$details);
+
+ return array(
+ $warning,
+ $content,
+ );
}
public function getUnitMessageDisplayName() {
$name = $this->getName();
$namespace = $this->getNamespace();
if (strlen($namespace)) {
$name = $namespace.'::'.$name;
}
$engine = $this->getEngine();
if (strlen($engine)) {
$name = $engine.' > '.$name;
}
if (!strlen($name)) {
return pht('Nameless Test (%d)', $this->getID());
}
return $name;
}
public function getSortKey() {
$status = $this->getResult();
$sort = HarbormasterUnitStatus::getUnitStatusSort($status);
$parts = array(
$sort,
$this->getEngine(),
$this->getNamespace(),
$this->getName(),
$this->getID(),
);
return implode("\0", $parts);
}
+ public function getURI() {
+ $id = $this->getID();
+
+ if (!$id) {
+ return null;
+ }
+
+ return urisprintf(
+ '/harbormaster/unit/view/%d/',
+ $id);
+ }
+
public function save() {
if ($this->nameIndex === null) {
$this->nameIndex = HarbormasterString::newIndex($this->getName());
}
// See T13088. While we're letting installs do online migrations to avoid
// downtime, don't populate the "name" column for new writes. New writes
// use the "HarbormasterString" table instead.
$old_name = $this->name;
$this->name = '';
$caught = null;
try {
$result = parent::save();
} catch (Exception $ex) {
$caught = $ex;
}
$this->name = $old_name;
if ($caught) {
throw $caught;
}
return $result;
}
/* -( PhabricatorPolicyInterface )----------------------------------------- */
public function getCapabilities() {
return array(
PhabricatorPolicyCapability::CAN_VIEW,
);
}
public function getPolicy($capability) {
switch ($capability) {
case PhabricatorPolicyCapability::CAN_VIEW:
return PhabricatorPolicies::getMostOpenPolicy();
}
}
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
return false;
}
}
diff --git a/src/applications/harbormaster/view/HarbormasterUnitPropertyView.php b/src/applications/harbormaster/view/HarbormasterUnitPropertyView.php
index ee8b80a7a7..2306f5ba64 100644
--- a/src/applications/harbormaster/view/HarbormasterUnitPropertyView.php
+++ b/src/applications/harbormaster/view/HarbormasterUnitPropertyView.php
@@ -1,157 +1,157 @@
<?php
final class HarbormasterUnitPropertyView extends AphrontView {
private $pathURIMap = array();
private $unitMessages = array();
private $limit;
private $fullResultsURI;
private $notice;
public function setPathURIMap(array $map) {
$this->pathURIMap = $map;
return $this;
}
public function setUnitMessages(array $messages) {
assert_instances_of($messages, 'HarbormasterBuildUnitMessage');
$this->unitMessages = $messages;
return $this;
}
public function setLimit($limit) {
$this->limit = $limit;
return $this;
}
public function setFullResultsURI($full_results_uri) {
$this->fullResultsURI = $full_results_uri;
return $this;
}
public function setNotice($notice) {
$this->notice = $notice;
return $this;
}
public function render() {
$viewer = $this->getViewer();
$messages = $this->unitMessages;
$messages = msort($messages, 'getSortKey');
$limit = $this->limit;
if ($this->limit) {
$display_messages = array_slice($messages, 0, $limit);
} else {
$display_messages = $messages;
}
$rows = array();
$any_duration = false;
foreach ($display_messages as $message) {
$status = $message->getResult();
$icon_icon = HarbormasterUnitStatus::getUnitStatusIcon($status);
$icon_color = HarbormasterUnitStatus::getUnitStatusColor($status);
$icon_label = HarbormasterUnitStatus::getUnitStatusLabel($status);
$result_icon = id(new PHUIIconView())
->setIcon("{$icon_icon} {$icon_color}")
->addSigil('has-tooltip')
->setMetadata(
array(
'tip' => $icon_label,
));
$duration = $message->getDuration();
if ($duration !== null) {
$any_duration = true;
$duration = pht('%s ms', new PhutilNumber((int)(1000 * $duration)));
}
$name = $message->getUnitMessageDisplayName();
- $id = $message->getID();
+ $uri = $message->getURI();
- if ($id) {
+ if ($uri) {
$name = phutil_tag(
'a',
array(
- 'href' => "/harbormaster/unit/view/{$id}/",
+ 'href' => $uri,
),
$name);
}
$name = array(
$name,
$message->newUnitMessageDetailsView($viewer, true),
);
$rows[] = array(
$result_icon,
$duration,
$name,
);
}
$full_uri = $this->fullResultsURI;
if ($full_uri && (count($messages) > $limit)) {
$counts = array();
$groups = mgroup($messages, 'getResult');
foreach ($groups as $status => $group) {
$counts[] = HarbormasterUnitStatus::getUnitStatusCountLabel(
$status,
count($group));
}
$link_text = pht(
'View Full Test Results (%s)',
implode(" \xC2\xB7 ", $counts));
$full_link = phutil_tag(
'a',
array(
'href' => $full_uri,
),
$link_text);
$link_icon = id(new PHUIIconView())
->setIcon('fa-ellipsis-h lightgreytext');
$rows[] = array($link_icon, null, $full_link);
}
$table = id(new AphrontTableView($rows))
->setHeaders(
array(
null,
pht('Time'),
pht('Test'),
))
->setColumnClasses(
array(
'top center',
'top right',
'top wide',
))
->setColumnWidths(
array(
'32px',
'64px',
))
->setColumnVisibility(
array(
true,
$any_duration,
));
if ($this->notice) {
$table->setNotice($this->notice);
}
return $table;
}
}

File Metadata

Mime Type
text/x-diff
Expires
Fri, Mar 14, 7:24 AM (3 h, 43 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
71676
Default Alt Text
(14 KB)

Event Timeline