mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-18 11:30:55 +01:00
Merge branch 'master' into redesign-2015
This commit is contained in:
commit
524aa39aa2
25 changed files with 669 additions and 676 deletions
|
@ -10,7 +10,7 @@ return array(
|
|||
'core.pkg.css' => '7f0d6232',
|
||||
'core.pkg.js' => 'a590b451',
|
||||
'darkconsole.pkg.js' => 'e7393ebb',
|
||||
'differential.pkg.css' => 'fe951924',
|
||||
'differential.pkg.css' => '27498de3',
|
||||
'differential.pkg.js' => 'ebef29b1',
|
||||
'diffusion.pkg.css' => '385e85b3',
|
||||
'diffusion.pkg.js' => '0115b37c',
|
||||
|
@ -61,7 +61,6 @@ return array(
|
|||
'rsrc/css/application/differential/changeset-view.css' => '9b8e8bb7',
|
||||
'rsrc/css/application/differential/core.css' => '7ac3cabc',
|
||||
'rsrc/css/application/differential/phui-inline-comment.css' => 'fa5b8d1f',
|
||||
'rsrc/css/application/differential/results-table.css' => '181aa9d9',
|
||||
'rsrc/css/application/differential/revision-comment.css' => '14b8565a',
|
||||
'rsrc/css/application/differential/revision-history.css' => '0e8eb855',
|
||||
'rsrc/css/application/differential/revision-list.css' => 'f3c47d33',
|
||||
|
@ -357,7 +356,6 @@ return array(
|
|||
'rsrc/js/application/differential/behavior-edit-inline-comments.js' => '037b59eb',
|
||||
'rsrc/js/application/differential/behavior-keyboard-nav.js' => '2c426492',
|
||||
'rsrc/js/application/differential/behavior-populate.js' => '8694b1df',
|
||||
'rsrc/js/application/differential/behavior-show-field-details.js' => 'bba9eedf',
|
||||
'rsrc/js/application/differential/behavior-toggle-files.js' => 'ca3f91eb',
|
||||
'rsrc/js/application/differential/behavior-user-select.js' => 'a8d8459d',
|
||||
'rsrc/js/application/diffusion/DiffusionLocateFileSource.js' => 'b42eddc7',
|
||||
|
@ -511,7 +509,6 @@ return array(
|
|||
'differential-changeset-view-css' => '9b8e8bb7',
|
||||
'differential-core-view-css' => '7ac3cabc',
|
||||
'differential-inline-comment-editor' => 'd4c87bf4',
|
||||
'differential-results-table-css' => '181aa9d9',
|
||||
'differential-revision-add-comment-css' => 'c47f8c40',
|
||||
'differential-revision-comment-css' => '14b8565a',
|
||||
'differential-revision-history-css' => '0e8eb855',
|
||||
|
@ -565,7 +562,6 @@ return array(
|
|||
'javelin-behavior-differential-feedback-preview' => 'b064af76',
|
||||
'javelin-behavior-differential-keyboard-navigation' => '2c426492',
|
||||
'javelin-behavior-differential-populate' => '8694b1df',
|
||||
'javelin-behavior-differential-show-field-details' => 'bba9eedf',
|
||||
'javelin-behavior-differential-toggle-files' => 'ca3f91eb',
|
||||
'javelin-behavior-differential-user-select' => 'a8d8459d',
|
||||
'javelin-behavior-diffusion-commit-branches' => 'bdaf4d04',
|
||||
|
@ -1711,11 +1707,6 @@ return array(
|
|||
'javelin-workflow',
|
||||
'phabricator-draggable-list',
|
||||
),
|
||||
'bba9eedf' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-stratcom',
|
||||
'javelin-dom',
|
||||
),
|
||||
'bd4c8dca' => array(
|
||||
'javelin-install',
|
||||
'javelin-util',
|
||||
|
@ -2192,7 +2183,6 @@ return array(
|
|||
'differential.pkg.css' => array(
|
||||
'differential-core-view-css',
|
||||
'differential-changeset-view-css',
|
||||
'differential-results-table-css',
|
||||
'differential-revision-history-css',
|
||||
'differential-revision-list-css',
|
||||
'differential-table-of-contents-css',
|
||||
|
|
|
@ -141,7 +141,6 @@ return array(
|
|||
'differential.pkg.css' => array(
|
||||
'differential-core-view-css',
|
||||
'differential-changeset-view-css',
|
||||
'differential-results-table-css',
|
||||
'differential-revision-history-css',
|
||||
'differential-revision-list-css',
|
||||
'differential-table-of-contents-css',
|
||||
|
|
|
@ -419,7 +419,6 @@ phutil_register_library_map(array(
|
|||
'DifferentialRepositoryField' => 'applications/differential/customfield/DifferentialRepositoryField.php',
|
||||
'DifferentialRepositoryLookup' => 'applications/differential/query/DifferentialRepositoryLookup.php',
|
||||
'DifferentialRequiredSignaturesField' => 'applications/differential/customfield/DifferentialRequiredSignaturesField.php',
|
||||
'DifferentialResultsTableView' => 'applications/differential/view/DifferentialResultsTableView.php',
|
||||
'DifferentialRevertPlanField' => 'applications/differential/customfield/DifferentialRevertPlanField.php',
|
||||
'DifferentialReviewedByField' => 'applications/differential/customfield/DifferentialReviewedByField.php',
|
||||
'DifferentialReviewer' => 'applications/differential/storage/DifferentialReviewer.php',
|
||||
|
@ -894,6 +893,7 @@ phutil_register_library_map(array(
|
|||
'HarbormasterDAO' => 'applications/harbormaster/storage/HarbormasterDAO.php',
|
||||
'HarbormasterHTTPRequestBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterHTTPRequestBuildStepImplementation.php',
|
||||
'HarbormasterLeaseHostBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterLeaseHostBuildStepImplementation.php',
|
||||
'HarbormasterLintPropertyView' => 'applications/harbormaster/view/HarbormasterLintPropertyView.php',
|
||||
'HarbormasterManagePlansCapability' => 'applications/harbormaster/capability/HarbormasterManagePlansCapability.php',
|
||||
'HarbormasterManagementBuildWorkflow' => 'applications/harbormaster/management/HarbormasterManagementBuildWorkflow.php',
|
||||
'HarbormasterManagementUpdateWorkflow' => 'applications/harbormaster/management/HarbormasterManagementUpdateWorkflow.php',
|
||||
|
@ -921,6 +921,7 @@ phutil_register_library_map(array(
|
|||
'HarbormasterTargetWorker' => 'applications/harbormaster/worker/HarbormasterTargetWorker.php',
|
||||
'HarbormasterThrowExceptionBuildStep' => 'applications/harbormaster/step/HarbormasterThrowExceptionBuildStep.php',
|
||||
'HarbormasterUIEventListener' => 'applications/harbormaster/event/HarbormasterUIEventListener.php',
|
||||
'HarbormasterUnitPropertyView' => 'applications/harbormaster/view/HarbormasterUnitPropertyView.php',
|
||||
'HarbormasterUploadArtifactBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterUploadArtifactBuildStepImplementation.php',
|
||||
'HarbormasterWaitForPreviousBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterWaitForPreviousBuildStepImplementation.php',
|
||||
'HarbormasterWorker' => 'applications/harbormaster/worker/HarbormasterWorker.php',
|
||||
|
@ -3789,7 +3790,6 @@ phutil_register_library_map(array(
|
|||
'DifferentialRepositoryField' => 'DifferentialCoreCustomField',
|
||||
'DifferentialRepositoryLookup' => 'Phobject',
|
||||
'DifferentialRequiredSignaturesField' => 'DifferentialCoreCustomField',
|
||||
'DifferentialResultsTableView' => 'AphrontView',
|
||||
'DifferentialRevertPlanField' => 'DifferentialStoredCustomField',
|
||||
'DifferentialReviewedByField' => 'DifferentialCoreCustomField',
|
||||
'DifferentialReviewer' => 'Phobject',
|
||||
|
@ -4356,6 +4356,7 @@ phutil_register_library_map(array(
|
|||
'HarbormasterDAO' => 'PhabricatorLiskDAO',
|
||||
'HarbormasterHTTPRequestBuildStepImplementation' => 'HarbormasterBuildStepImplementation',
|
||||
'HarbormasterLeaseHostBuildStepImplementation' => 'HarbormasterBuildStepImplementation',
|
||||
'HarbormasterLintPropertyView' => 'AphrontView',
|
||||
'HarbormasterManagePlansCapability' => 'PhabricatorPolicyCapability',
|
||||
'HarbormasterManagementBuildWorkflow' => 'HarbormasterManagementWorkflow',
|
||||
'HarbormasterManagementUpdateWorkflow' => 'HarbormasterManagementWorkflow',
|
||||
|
@ -4383,6 +4384,7 @@ phutil_register_library_map(array(
|
|||
'HarbormasterTargetWorker' => 'HarbormasterWorker',
|
||||
'HarbormasterThrowExceptionBuildStep' => 'HarbormasterBuildStepImplementation',
|
||||
'HarbormasterUIEventListener' => 'PhabricatorEventListener',
|
||||
'HarbormasterUnitPropertyView' => 'AphrontView',
|
||||
'HarbormasterUploadArtifactBuildStepImplementation' => 'HarbormasterBuildStepImplementation',
|
||||
'HarbormasterWaitForPreviousBuildStepImplementation' => 'HarbormasterBuildStepImplementation',
|
||||
'HarbormasterWorker' => 'PhabricatorWorker',
|
||||
|
@ -6730,6 +6732,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorProjectInterface',
|
||||
'PhabricatorDestructibleInterface',
|
||||
'PhabricatorSpacesInterface',
|
||||
'PhabricatorMentionableInterface',
|
||||
),
|
||||
'PholioMockCommentController' => 'PholioController',
|
||||
'PholioMockEditController' => 'PholioController',
|
||||
|
|
|
@ -264,11 +264,11 @@ final class PhabricatorCalendarEventSearchEngine
|
|||
$list = new PHUIObjectItemListView();
|
||||
|
||||
foreach ($events as $event) {
|
||||
$from = phabricator_datetime($event->getDateFrom(), $viewer);
|
||||
$duration = '';
|
||||
$event_date_info = $this->getEventDateLabel($event);
|
||||
$creator_handle = $handles[$event->getUserPHID()];
|
||||
|
||||
$attendees = array();
|
||||
|
||||
foreach ($event->getInvitees() as $invitee) {
|
||||
$attendees[] = $invitee->getInviteePHID();
|
||||
}
|
||||
|
@ -287,8 +287,8 @@ final class PhabricatorCalendarEventSearchEngine
|
|||
|
||||
$item = id(new PHUIObjectItemView())
|
||||
->setHeader($viewer->renderHandle($event->getPHID())->render())
|
||||
->addAttribute($event_date_info)
|
||||
->addAttribute($attendees)
|
||||
->addIcon('none', $from)
|
||||
->addIcon('none', $duration);
|
||||
|
||||
$list->addItem($item);
|
||||
|
@ -520,4 +520,41 @@ final class PhabricatorCalendarEventSearchEngine
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function getEventDateLabel($event) {
|
||||
$viewer = $this->requireViewer();
|
||||
|
||||
$from_datetime = PhabricatorTime::getDateTimeFromEpoch(
|
||||
$event->getDateFrom(),
|
||||
$viewer);
|
||||
$to_datetime = PhabricatorTime::getDateTimeFromEpoch(
|
||||
$event->getDateTo(),
|
||||
$viewer);
|
||||
|
||||
$from_date_formatted = $from_datetime->format('Y m d');
|
||||
$to_date_formatted = $to_datetime->format('Y m d');
|
||||
|
||||
if ($event->getIsAllDay()) {
|
||||
if ($from_date_formatted == $to_date_formatted) {
|
||||
return pht(
|
||||
'%s, All Day',
|
||||
phabricator_date($event->getDateFrom(), $viewer));
|
||||
} else {
|
||||
return pht(
|
||||
'%s - %s, All Day',
|
||||
phabricator_date($event->getDateFrom(), $viewer),
|
||||
phabricator_date($event->getDateTo(), $viewer));
|
||||
}
|
||||
} else if ($from_date_formatted == $to_date_formatted) {
|
||||
return pht(
|
||||
'%s - %s',
|
||||
phabricator_datetime($event->getDateFrom(), $viewer),
|
||||
phabricator_time($event->getDateTo(), $viewer));
|
||||
} else {
|
||||
return pht(
|
||||
'%s - %s',
|
||||
phabricator_datetime($event->getDateFrom(), $viewer),
|
||||
phabricator_datetime($event->getDateTo(), $viewer));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -160,7 +160,8 @@ final class DifferentialCreateDiffConduitAPIMethod
|
|||
|
||||
return array(
|
||||
'diffid' => $diff->getID(),
|
||||
'uri' => $uri,
|
||||
'phid' => $diff->getPHID(),
|
||||
'uri' => $uri,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -265,8 +265,25 @@ final class DifferentialRevisionViewController extends DifferentialController {
|
|||
$revision_detail_box->setInfoView($revision_warnings);
|
||||
}
|
||||
|
||||
$detail_diffs = array_select_keys(
|
||||
$diffs,
|
||||
array($diff_vs, $target->getID()));
|
||||
$detail_diffs = mpull($detail_diffs, null, 'getPHID');
|
||||
|
||||
$buildables = id(new HarbormasterBuildableQuery())
|
||||
->setViewer($user)
|
||||
->withBuildablePHIDs(array_keys($detail_diffs))
|
||||
->withManualBuildables(false)
|
||||
->needBuilds(true)
|
||||
->needTargets(true)
|
||||
->execute();
|
||||
$buildables = mpull($buildables, null, 'getBuildablePHID');
|
||||
foreach ($detail_diffs as $diff_phid => $detail_diff) {
|
||||
$detail_diff->attachBuildable(idx($buildables, $diff_phid));
|
||||
}
|
||||
|
||||
$diff_detail_box = $this->buildDiffDetailView(
|
||||
array_select_keys($diffs, array($diff_vs, $target->getID())),
|
||||
$detail_diffs,
|
||||
$revision,
|
||||
$field_list);
|
||||
|
||||
|
|
|
@ -38,7 +38,6 @@ final class DifferentialLintField
|
|||
$keys = array(
|
||||
'arc:lint',
|
||||
'arc:lint-excuse',
|
||||
'arc:lint-postponed',
|
||||
);
|
||||
|
||||
$properties = id(new DifferentialDiffProperty())->loadAllWhere(
|
||||
|
@ -51,208 +50,72 @@ final class DifferentialLintField
|
|||
$diff->attachProperty($key, idx($properties, $key));
|
||||
}
|
||||
|
||||
$path_changesets = mpull($diff->loadChangesets(), 'getID', 'getFilename');
|
||||
$status = $this->renderLintStatus($diff);
|
||||
|
||||
$lstar = DifferentialRevisionUpdateHistoryView::renderDiffLintStar($diff);
|
||||
$lmsg = DifferentialRevisionUpdateHistoryView::getDiffLintMessage($diff);
|
||||
$ldata = $diff->getProperty('arc:lint');
|
||||
$ltail = null;
|
||||
$lint = array();
|
||||
|
||||
$rows = array();
|
||||
$buildable = $diff->getBuildable();
|
||||
if ($buildable) {
|
||||
$target_phids = array();
|
||||
foreach ($buildable->getBuilds() as $build) {
|
||||
foreach ($build->getBuildTargets() as $target) {
|
||||
$target_phids[] = $target->getPHID();
|
||||
}
|
||||
}
|
||||
|
||||
$rows[] = array(
|
||||
'style' => 'star',
|
||||
'name' => $lstar,
|
||||
'value' => $lmsg,
|
||||
'show' => true,
|
||||
);
|
||||
|
||||
$excuse = $diff->getProperty('arc:lint-excuse');
|
||||
if ($excuse) {
|
||||
$rows[] = array(
|
||||
'style' => 'excuse',
|
||||
'name' => 'Excuse',
|
||||
'value' => phutil_escape_html_newlines($excuse),
|
||||
'show' => true,
|
||||
);
|
||||
$lint = id(new HarbormasterBuildLintMessage())->loadAllWhere(
|
||||
'buildTargetPHID IN (%Ls) LIMIT 25',
|
||||
$target_phids);
|
||||
}
|
||||
|
||||
$show_limit = 10;
|
||||
$hidden = array();
|
||||
if (!$lint) {
|
||||
// No Harbormaster messages, so look for legacy messages and make them
|
||||
// look like modern messages.
|
||||
$legacy_lint = $diff->getProperty('arc:lint');
|
||||
if ($legacy_lint) {
|
||||
// Show the top 100 legacy lint messages. Previously, we showed some
|
||||
// by default and let the user toggle the rest. With modern messages,
|
||||
// we can send the user to the Harbormaster detail page. Just show
|
||||
// "a lot" of messages in legacy cases to try to strike a balance
|
||||
// between implementation simplicitly and compatibility.
|
||||
$legacy_lint = array_slice($legacy_lint, 0, 100);
|
||||
|
||||
if ($ldata) {
|
||||
$ldata = igroup($ldata, 'path');
|
||||
foreach ($ldata as $path => $messages) {
|
||||
|
||||
$rows[] = array(
|
||||
'style' => 'section',
|
||||
'name' => $path,
|
||||
'show' => $show_limit,
|
||||
);
|
||||
|
||||
foreach ($messages as $message) {
|
||||
$path = idx($message, 'path');
|
||||
$line = idx($message, 'line');
|
||||
|
||||
$code = idx($message, 'code');
|
||||
$severity = idx($message, 'severity');
|
||||
|
||||
$name = idx($message, 'name');
|
||||
$description = idx($message, 'description');
|
||||
|
||||
$line_link = pht('line %d', intval($line));
|
||||
if (isset($path_changesets[$path])) {
|
||||
$href = '#C'.$path_changesets[$path].'NL'.max(1, $line);
|
||||
|
||||
// TODO: We are always showing the active diff
|
||||
// if ($diff->getID() != $this->getDiff()->getID()) {
|
||||
// $href = '/D'.$diff->getRevisionID().'?id='.$diff->getID().$href;
|
||||
// }
|
||||
|
||||
$line_link = phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => $href,
|
||||
),
|
||||
$line_link);
|
||||
}
|
||||
|
||||
if ($show_limit) {
|
||||
--$show_limit;
|
||||
$show = true;
|
||||
} else {
|
||||
$show = false;
|
||||
if (empty($hidden[$severity])) {
|
||||
$hidden[$severity] = 0;
|
||||
}
|
||||
$hidden[$severity]++;
|
||||
}
|
||||
|
||||
$rows[] = array(
|
||||
'style' => $this->getSeverityStyle($severity),
|
||||
'name' => ucwords($severity),
|
||||
'value' => hsprintf(
|
||||
'(%s) %s at %s',
|
||||
$code,
|
||||
$name,
|
||||
$line_link),
|
||||
'show' => $show,
|
||||
);
|
||||
|
||||
if (!empty($message['locations'])) {
|
||||
$locations = array();
|
||||
foreach ($message['locations'] as $location) {
|
||||
$other_line = idx($location, 'line');
|
||||
$locations[] =
|
||||
idx($location, 'path', $path).
|
||||
($other_line ? ":{$other_line}" : '');
|
||||
}
|
||||
$description .= "\n".pht(
|
||||
'Other locations: %s',
|
||||
implode(', ', $locations));
|
||||
}
|
||||
|
||||
if (strlen($description)) {
|
||||
$rows[] = array(
|
||||
'style' => 'details',
|
||||
'value' => phutil_escape_html_newlines($description),
|
||||
'show' => false,
|
||||
);
|
||||
if (empty($hidden['details'])) {
|
||||
$hidden['details'] = 0;
|
||||
}
|
||||
$hidden['details']++;
|
||||
$target = new HarbormasterBuildTarget();
|
||||
foreach ($legacy_lint as $message) {
|
||||
try {
|
||||
$modern = HarbormasterBuildLintMessage::newFromDictionary(
|
||||
$target,
|
||||
$this->getModernLintMessageDictionary($message));
|
||||
$lint[] = $modern;
|
||||
} catch (Exception $ex) {
|
||||
// Ignore any poorly formatted messages.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$postponed = $diff->getProperty('arc:lint-postponed');
|
||||
if ($postponed) {
|
||||
foreach ($postponed as $linter) {
|
||||
$rows[] = array(
|
||||
'style' => $this->getPostponedStyle(),
|
||||
'name' => 'Postponed',
|
||||
'value' => $linter,
|
||||
'show' => false,
|
||||
);
|
||||
if (empty($hidden['postponed'])) {
|
||||
$hidden['postponed'] = 0;
|
||||
}
|
||||
$hidden['postponed']++;
|
||||
if ($lint) {
|
||||
$path_map = mpull($diff->loadChangesets(), 'getID', 'getFilename');
|
||||
foreach ($path_map as $path => $id) {
|
||||
$href = '#C'.$id.'NL';
|
||||
|
||||
// TODO: When the diff is not the right-hand-size diff, we should
|
||||
// ideally adjust this URI to be absolute.
|
||||
|
||||
$path_map[$path] = $href;
|
||||
}
|
||||
|
||||
$view = id(new HarbormasterLintPropertyView())
|
||||
->setPathURIMap($path_map)
|
||||
->setLintMessages($lint);
|
||||
} else {
|
||||
$view = null;
|
||||
}
|
||||
|
||||
$show_string = $this->renderShowString($hidden);
|
||||
|
||||
$view = new DifferentialResultsTableView();
|
||||
$view->setRows($rows);
|
||||
$view->setShowMoreString($show_string);
|
||||
|
||||
return $view->render();
|
||||
}
|
||||
|
||||
private function getSeverityStyle($severity) {
|
||||
$map = array(
|
||||
ArcanistLintSeverity::SEVERITY_ERROR => 'red',
|
||||
ArcanistLintSeverity::SEVERITY_WARNING => 'yellow',
|
||||
ArcanistLintSeverity::SEVERITY_AUTOFIX => 'yellow',
|
||||
ArcanistLintSeverity::SEVERITY_ADVICE => 'yellow',
|
||||
return array(
|
||||
$status,
|
||||
$view,
|
||||
);
|
||||
return idx($map, $severity);
|
||||
}
|
||||
|
||||
private function getPostponedStyle() {
|
||||
return 'blue';
|
||||
}
|
||||
|
||||
private function renderShowString(array $hidden) {
|
||||
if (!$hidden) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Reorder hidden things by severity.
|
||||
$hidden = array_select_keys(
|
||||
$hidden,
|
||||
array(
|
||||
ArcanistLintSeverity::SEVERITY_ERROR,
|
||||
ArcanistLintSeverity::SEVERITY_WARNING,
|
||||
ArcanistLintSeverity::SEVERITY_AUTOFIX,
|
||||
ArcanistLintSeverity::SEVERITY_ADVICE,
|
||||
'details',
|
||||
'postponed',
|
||||
)) + $hidden;
|
||||
|
||||
$show = array();
|
||||
foreach ($hidden as $key => $value) {
|
||||
switch ($key) {
|
||||
case ArcanistLintSeverity::SEVERITY_ERROR:
|
||||
$show[] = pht('%d Error(s)', $value);
|
||||
break;
|
||||
case ArcanistLintSeverity::SEVERITY_WARNING:
|
||||
$show[] = pht('%d Warning(s)', $value);
|
||||
break;
|
||||
case ArcanistLintSeverity::SEVERITY_AUTOFIX:
|
||||
$show[] = pht('%d Auto-Fix(es)', $value);
|
||||
break;
|
||||
case ArcanistLintSeverity::SEVERITY_ADVICE:
|
||||
$show[] = pht('%d Advice(s)', $value);
|
||||
break;
|
||||
case 'details':
|
||||
$show[] = pht('%d Detail(s)', $value);
|
||||
break;
|
||||
case 'postponed':
|
||||
$show[] = pht('%d Postponed', $value);
|
||||
break;
|
||||
default:
|
||||
$show[] = $value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return pht(
|
||||
'Show Full Lint Results (%s)',
|
||||
implode(', ', $show));
|
||||
}
|
||||
|
||||
public function getWarningsForDetailView() {
|
||||
|
@ -278,4 +141,50 @@ final class DifferentialLintField
|
|||
return $warnings;
|
||||
}
|
||||
|
||||
private function renderLintStatus(DifferentialDiff $diff) {
|
||||
$colors = array(
|
||||
DifferentialLintStatus::LINT_NONE => 'grey',
|
||||
DifferentialLintStatus::LINT_OKAY => 'green',
|
||||
DifferentialLintStatus::LINT_WARN => 'yellow',
|
||||
DifferentialLintStatus::LINT_FAIL => 'red',
|
||||
DifferentialLintStatus::LINT_SKIP => 'blue',
|
||||
DifferentialLintStatus::LINT_AUTO_SKIP => 'blue',
|
||||
DifferentialLintStatus::LINT_POSTPONED => 'blue',
|
||||
);
|
||||
$icon_color = idx($colors, $diff->getLintStatus(), 'grey');
|
||||
|
||||
$message = DifferentialRevisionUpdateHistoryView::getDiffLintMessage($diff);
|
||||
|
||||
$excuse = $diff->getProperty('arc:lint-excuse');
|
||||
if (strlen($excuse)) {
|
||||
$excuse = array(
|
||||
phutil_tag('strong', array(), pht('Excuse:')),
|
||||
' ',
|
||||
phutil_escape_html_newlines($excuse),
|
||||
);
|
||||
}
|
||||
|
||||
$status = id(new PHUIStatusListView())
|
||||
->addItem(
|
||||
id(new PHUIStatusItemView())
|
||||
->setIcon(PHUIStatusItemView::ICON_STAR, $icon_color)
|
||||
->setTarget($message)
|
||||
->setNote($excuse));
|
||||
|
||||
return $status;
|
||||
}
|
||||
|
||||
private function getModernLintMessageDictionary(array $map) {
|
||||
// Strip out `null` values to satisfy stricter typechecks.
|
||||
foreach ($map as $key => $value) {
|
||||
if ($value === null) {
|
||||
unset($map[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: We might need to remap some stuff here?
|
||||
return $map;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -48,182 +48,67 @@ final class DifferentialUnitField
|
|||
$diff->attachProperty($key, idx($properties, $key));
|
||||
}
|
||||
|
||||
$ustar = DifferentialRevisionUpdateHistoryView::renderDiffUnitStar($diff);
|
||||
$umsg = DifferentialRevisionUpdateHistoryView::getDiffUnitMessage($diff);
|
||||
$status = $this->renderUnitStatus($diff);
|
||||
|
||||
$rows = array();
|
||||
$unit = array();
|
||||
|
||||
$rows[] = array(
|
||||
'style' => 'star',
|
||||
'name' => $ustar,
|
||||
'value' => $umsg,
|
||||
'show' => true,
|
||||
);
|
||||
$buildable = $diff->getBuildable();
|
||||
if ($buildable) {
|
||||
$target_phids = array();
|
||||
foreach ($buildable->getBuilds() as $build) {
|
||||
foreach ($build->getBuildTargets() as $target) {
|
||||
$target_phids[] = $target->getPHID();
|
||||
}
|
||||
}
|
||||
|
||||
$excuse = $diff->getProperty('arc:unit-excuse');
|
||||
if ($excuse) {
|
||||
$rows[] = array(
|
||||
'style' => 'excuse',
|
||||
'name' => pht('Excuse'),
|
||||
'value' => phutil_escape_html_newlines($excuse),
|
||||
'show' => true,
|
||||
);
|
||||
$unit = id(new HarbormasterBuildUnitMessage())->loadAllWhere(
|
||||
'buildTargetPHID IN (%Ls) LIMIT 25',
|
||||
$target_phids);
|
||||
}
|
||||
|
||||
$show_limit = 10;
|
||||
$hidden = array();
|
||||
if (!$unit) {
|
||||
$legacy_unit = $diff->getProperty('arc:unit');
|
||||
if ($legacy_unit) {
|
||||
// Show the top 100 legacy unit messages.
|
||||
$legacy_unit = array_slice($legacy_unit, 0, 100);
|
||||
|
||||
$udata = $diff->getProperty('arc:unit');
|
||||
if ($udata) {
|
||||
$sort_map = array(
|
||||
ArcanistUnitTestResult::RESULT_BROKEN => 0,
|
||||
ArcanistUnitTestResult::RESULT_FAIL => 1,
|
||||
ArcanistUnitTestResult::RESULT_UNSOUND => 2,
|
||||
ArcanistUnitTestResult::RESULT_SKIP => 3,
|
||||
ArcanistUnitTestResult::RESULT_POSTPONED => 4,
|
||||
ArcanistUnitTestResult::RESULT_PASS => 5,
|
||||
);
|
||||
|
||||
foreach ($udata as $key => $test) {
|
||||
$udata[$key]['sort'] = idx($sort_map, idx($test, 'result'));
|
||||
}
|
||||
$udata = isort($udata, 'sort');
|
||||
$engine = new PhabricatorMarkupEngine();
|
||||
$engine->setViewer($this->getViewer());
|
||||
$markup_objects = array();
|
||||
foreach ($udata as $key => $test) {
|
||||
$userdata = idx($test, 'userdata');
|
||||
if ($userdata) {
|
||||
if ($userdata !== false) {
|
||||
$userdata = str_replace("\000", '', $userdata);
|
||||
$target = new HarbormasterBuildTarget();
|
||||
foreach ($legacy_unit as $message) {
|
||||
try {
|
||||
$modern = HarbormasterBuildUnitMessage::newFromDictionary(
|
||||
$target,
|
||||
$this->getModernUnitMessageDictionary($message));
|
||||
$unit[] = $modern;
|
||||
} catch (Exception $ex) {
|
||||
// Just ignore it if legacy messages aren't formatted like
|
||||
// we expect.
|
||||
}
|
||||
$markup_object = id(new PhabricatorMarkupOneOff())
|
||||
->setContent($userdata)
|
||||
->setPreserveLinebreaks(true);
|
||||
$engine->addObject($markup_object, 'default');
|
||||
$markup_objects[$key] = $markup_object;
|
||||
}
|
||||
}
|
||||
$engine->process();
|
||||
foreach ($udata as $key => $test) {
|
||||
$result = idx($test, 'result');
|
||||
|
||||
$default_hide = false;
|
||||
switch ($result) {
|
||||
case ArcanistUnitTestResult::RESULT_POSTPONED:
|
||||
case ArcanistUnitTestResult::RESULT_PASS:
|
||||
$default_hide = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if ($show_limit && !$default_hide) {
|
||||
--$show_limit;
|
||||
$show = true;
|
||||
} else {
|
||||
$show = false;
|
||||
if (empty($hidden[$result])) {
|
||||
$hidden[$result] = 0;
|
||||
}
|
||||
$hidden[$result]++;
|
||||
}
|
||||
|
||||
$value = idx($test, 'name');
|
||||
|
||||
$namespace = idx($test, 'namespace');
|
||||
if ($namespace) {
|
||||
$value = $namespace.'::'.$value;
|
||||
}
|
||||
|
||||
if (!empty($test['link'])) {
|
||||
$value = phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => $test['link'],
|
||||
'target' => '_blank',
|
||||
),
|
||||
$value);
|
||||
}
|
||||
$rows[] = array(
|
||||
'style' => $this->getResultStyle($result),
|
||||
'name' => ucwords($result),
|
||||
'value' => $value,
|
||||
'show' => $show,
|
||||
);
|
||||
|
||||
if (isset($markup_objects[$key])) {
|
||||
$rows[] = array(
|
||||
'style' => 'details',
|
||||
'value' => $engine->getOutput($markup_objects[$key], 'default'),
|
||||
'show' => false,
|
||||
);
|
||||
if (empty($hidden['details'])) {
|
||||
$hidden['details'] = 0;
|
||||
}
|
||||
$hidden['details']++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$show_string = $this->renderShowString($hidden);
|
||||
if ($unit) {
|
||||
$path_map = mpull($diff->loadChangesets(), 'getID', 'getFilename');
|
||||
foreach ($path_map as $path => $id) {
|
||||
$href = '#C'.$id.'NL';
|
||||
|
||||
$view = new DifferentialResultsTableView();
|
||||
$view->setRows($rows);
|
||||
$view->setShowMoreString($show_string);
|
||||
// TODO: When the diff is not the right-hand-size diff, we should
|
||||
// ideally adjust this URI to be absolute.
|
||||
|
||||
return $view->render();
|
||||
}
|
||||
$path_map[$path] = $href;
|
||||
}
|
||||
|
||||
private function getResultStyle($result) {
|
||||
$map = array(
|
||||
ArcanistUnitTestResult::RESULT_PASS => 'green',
|
||||
ArcanistUnitTestResult::RESULT_FAIL => 'red',
|
||||
ArcanistUnitTestResult::RESULT_SKIP => 'blue',
|
||||
ArcanistUnitTestResult::RESULT_BROKEN => 'red',
|
||||
ArcanistUnitTestResult::RESULT_UNSOUND => 'yellow',
|
||||
ArcanistUnitTestResult::RESULT_POSTPONED => 'blue',
|
||||
$view = id(new HarbormasterUnitPropertyView())
|
||||
->setPathURIMap($path_map)
|
||||
->setUnitMessages($unit);
|
||||
} else {
|
||||
$view = null;
|
||||
}
|
||||
|
||||
return array(
|
||||
$status,
|
||||
$view,
|
||||
);
|
||||
return idx($map, $result);
|
||||
}
|
||||
|
||||
private function renderShowString(array $hidden) {
|
||||
if (!$hidden) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Reorder hidden things by severity.
|
||||
$hidden = array_select_keys(
|
||||
$hidden,
|
||||
array(
|
||||
ArcanistUnitTestResult::RESULT_BROKEN,
|
||||
ArcanistUnitTestResult::RESULT_FAIL,
|
||||
ArcanistUnitTestResult::RESULT_UNSOUND,
|
||||
ArcanistUnitTestResult::RESULT_SKIP,
|
||||
ArcanistUnitTestResult::RESULT_POSTPONED,
|
||||
ArcanistUnitTestResult::RESULT_PASS,
|
||||
'details',
|
||||
)) + $hidden;
|
||||
|
||||
$noun = array(
|
||||
ArcanistUnitTestResult::RESULT_BROKEN => pht('Broken'),
|
||||
ArcanistUnitTestResult::RESULT_FAIL => pht('Failed'),
|
||||
ArcanistUnitTestResult::RESULT_UNSOUND => pht('Unsound'),
|
||||
ArcanistUnitTestResult::RESULT_SKIP => pht('Skipped'),
|
||||
ArcanistUnitTestResult::RESULT_POSTPONED => pht('Postponed'),
|
||||
ArcanistUnitTestResult::RESULT_PASS => pht('Passed'),
|
||||
);
|
||||
|
||||
$show = array();
|
||||
foreach ($hidden as $key => $value) {
|
||||
if ($key == 'details') {
|
||||
$show[] = pht('%d Detail(s)', $value);
|
||||
} else {
|
||||
$show[] = $value.' '.idx($noun, $key);
|
||||
}
|
||||
}
|
||||
|
||||
return pht(
|
||||
'Show Full Unit Results (%s)',
|
||||
implode(', ', $show));
|
||||
}
|
||||
|
||||
public function getWarningsForDetailView() {
|
||||
|
@ -248,4 +133,51 @@ final class DifferentialUnitField
|
|||
}
|
||||
|
||||
|
||||
private function renderUnitStatus(DifferentialDiff $diff) {
|
||||
$colors = array(
|
||||
DifferentialUnitStatus::UNIT_NONE => 'grey',
|
||||
DifferentialUnitStatus::UNIT_OKAY => 'green',
|
||||
DifferentialUnitStatus::UNIT_WARN => 'yellow',
|
||||
DifferentialUnitStatus::UNIT_FAIL => 'red',
|
||||
DifferentialUnitStatus::UNIT_SKIP => 'blue',
|
||||
DifferentialUnitStatus::UNIT_AUTO_SKIP => 'blue',
|
||||
DifferentialUnitStatus::UNIT_POSTPONED => 'blue',
|
||||
);
|
||||
$icon_color = idx($colors, $diff->getUnitStatus(), 'grey');
|
||||
|
||||
$message = DifferentialRevisionUpdateHistoryView::getDiffUnitMessage($diff);
|
||||
|
||||
$excuse = $diff->getProperty('arc:unit-excuse');
|
||||
if (strlen($excuse)) {
|
||||
$excuse = array(
|
||||
phutil_tag('strong', array(), pht('Excuse:')),
|
||||
' ',
|
||||
phutil_escape_html_newlines($excuse),
|
||||
);
|
||||
}
|
||||
|
||||
$status = id(new PHUIStatusListView())
|
||||
->addItem(
|
||||
id(new PHUIStatusItemView())
|
||||
->setIcon(PHUIStatusItemView::ICON_STAR, $icon_color)
|
||||
->setTarget($message)
|
||||
->setNote($excuse));
|
||||
|
||||
return $status;
|
||||
}
|
||||
|
||||
private function getModernUnitMessageDictionary(array $map) {
|
||||
// Strip out `null` values to satisfy stricter typechecks.
|
||||
foreach ($map as $key => $value) {
|
||||
if ($value === null) {
|
||||
unset($map[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Remap more stuff here?
|
||||
|
||||
return $map;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -587,6 +587,21 @@ final class DifferentialTransactionEditor
|
|||
|
||||
$diff->setRevisionID($object->getID());
|
||||
$diff->save();
|
||||
|
||||
// Update Harbormaster to set the containerPHID correctly for any
|
||||
// existing buildables. We may otherwise have buildables stuck with
|
||||
// the old (`null`) container.
|
||||
|
||||
// TODO: This is a bit iffy, maybe we can find a cleaner approach?
|
||||
$table = new HarbormasterBuildable();
|
||||
$conn_w = $table->establishConnection('w');
|
||||
queryfx(
|
||||
$conn_w,
|
||||
'UPDATE %T SET containerPHID = %s WHERE buildablePHID = %s',
|
||||
$table->getTableName(),
|
||||
$object->getPHID(),
|
||||
$diff->getPHID());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@ final class DifferentialDiff
|
|||
private $changesets = self::ATTACHABLE;
|
||||
private $revision = self::ATTACHABLE;
|
||||
private $properties = array();
|
||||
private $buildable = self::ATTACHABLE;
|
||||
|
||||
protected function getConfiguration() {
|
||||
return array(
|
||||
|
@ -323,6 +324,15 @@ final class DifferentialDiff
|
|||
return $this->assertAttachedKey($this->properties, $key);
|
||||
}
|
||||
|
||||
public function attachBuildable(HarbormasterBuildable $buildable = null) {
|
||||
$this->buildable = $buildable;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getBuildable() {
|
||||
return $this->assertAttached($this->buildable);
|
||||
}
|
||||
|
||||
|
||||
/* -( PhabricatorPolicyInterface )----------------------------------------- */
|
||||
|
||||
|
|
|
@ -1,115 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class DifferentialResultsTableView extends AphrontView {
|
||||
|
||||
private $rows;
|
||||
private $showMoreString;
|
||||
|
||||
public function setRows(array $rows) {
|
||||
$this->rows = $rows;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setShowMoreString($show_more_string) {
|
||||
$this->showMoreString = $show_more_string;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function render() {
|
||||
|
||||
$rows = array();
|
||||
|
||||
$any_hidden = false;
|
||||
foreach ($this->rows as $row) {
|
||||
|
||||
$style = idx($row, 'style');
|
||||
switch ($style) {
|
||||
case 'section':
|
||||
$cells = phutil_tag(
|
||||
'th',
|
||||
array(
|
||||
'colspan' => 2,
|
||||
),
|
||||
idx($row, 'name'));
|
||||
break;
|
||||
default:
|
||||
$name = phutil_tag(
|
||||
'th',
|
||||
array(
|
||||
),
|
||||
idx($row, 'name'));
|
||||
$value = phutil_tag(
|
||||
'td',
|
||||
array(
|
||||
),
|
||||
idx($row, 'value'));
|
||||
$cells = array($name, $value);
|
||||
break;
|
||||
}
|
||||
|
||||
$show = idx($row, 'show');
|
||||
|
||||
$rows[] = javelin_tag(
|
||||
'tr',
|
||||
array(
|
||||
'style' => $show ? null : 'display: none',
|
||||
'sigil' => $show ? null : 'differential-results-row-toggle',
|
||||
'class' => 'differential-results-row-'.$style,
|
||||
),
|
||||
$cells);
|
||||
|
||||
if (!$show) {
|
||||
$any_hidden = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($any_hidden) {
|
||||
$show_more = javelin_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => '#',
|
||||
'mustcapture' => true,
|
||||
),
|
||||
$this->showMoreString);
|
||||
|
||||
$hide_more = javelin_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => '#',
|
||||
'mustcapture' => true,
|
||||
),
|
||||
pht('Hide'));
|
||||
|
||||
$rows[] = javelin_tag(
|
||||
'tr',
|
||||
array(
|
||||
'class' => 'differential-results-row-show',
|
||||
'sigil' => 'differential-results-row-show',
|
||||
),
|
||||
phutil_tag('th', array('colspan' => 2), $show_more));
|
||||
|
||||
$rows[] = javelin_tag(
|
||||
'tr',
|
||||
array(
|
||||
'class' => 'differential-results-row-show',
|
||||
'sigil' => 'differential-results-row-hide',
|
||||
'style' => 'display: none',
|
||||
),
|
||||
phutil_tag('th', array('colspan' => 2), $hide_more));
|
||||
|
||||
$this->initBehavior('differential-show-field-details');
|
||||
}
|
||||
|
||||
$this->requireResource('differential-results-table-css');
|
||||
|
||||
return javelin_tag(
|
||||
'table',
|
||||
array(
|
||||
'class' => 'differential-results-table',
|
||||
'sigil' => 'differential-results-table',
|
||||
),
|
||||
$rows);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -18,7 +18,9 @@ final class HarbormasterSendMessageConduitAPIMethod
|
|||
|
||||
return array(
|
||||
'buildTargetPHID' => 'required phid',
|
||||
'type' => 'required '.$type_const,
|
||||
'lint' => 'optional list<wild>',
|
||||
'unit' => 'optional list<wild>',
|
||||
'type' => 'required '.$type_const,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -40,10 +42,31 @@ final class HarbormasterSendMessageConduitAPIMethod
|
|||
throw new Exception(pht('No such build target!'));
|
||||
}
|
||||
|
||||
$message = HarbormasterBuildMessage::initializeNewMessage($viewer)
|
||||
$save = array();
|
||||
|
||||
$lint_messages = $request->getValue('lint', array());
|
||||
foreach ($lint_messages as $lint) {
|
||||
$save[] = HarbormasterBuildLintMessage::newFromDictionary(
|
||||
$build_target,
|
||||
$lint);
|
||||
}
|
||||
|
||||
$unit_messages = $request->getValue('unit', array());
|
||||
foreach ($unit_messages as $unit) {
|
||||
$save[] = HarbormasterBuildUnitMessage::newFromDictionary(
|
||||
$build_target,
|
||||
$unit);
|
||||
}
|
||||
|
||||
$save[] = HarbormasterBuildMessage::initializeNewMessage($viewer)
|
||||
->setBuildTargetPHID($build_target->getPHID())
|
||||
->setType($message_type)
|
||||
->save();
|
||||
->setType($message_type);
|
||||
|
||||
$build_target->openTransaction();
|
||||
foreach ($save as $object) {
|
||||
$object->save();
|
||||
}
|
||||
$build_target->saveTransaction();
|
||||
|
||||
// If the build has completely paused because all steps are blocked on
|
||||
// waiting targets, this will resume it.
|
||||
|
|
|
@ -48,9 +48,7 @@ final class HarbormasterBuildViewController
|
|||
$this->buildPropertyLists($box, $build, $actions);
|
||||
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
$crumbs->addTextCrumb(
|
||||
$build->getBuildable()->getMonogram(),
|
||||
'/'.$build->getBuildable()->getMonogram());
|
||||
$this->addBuildableCrumb($crumbs, $build->getBuildable());
|
||||
$crumbs->addTextCrumb($title);
|
||||
|
||||
if ($generation === null || $generation > $build->getBuildGeneration() ||
|
||||
|
@ -99,29 +97,52 @@ final class HarbormasterBuildViewController
|
|||
$item->setIcon($icon, $color);
|
||||
$status_view->addItem($item);
|
||||
|
||||
$properties->addProperty(pht('Name'), $build_target->getName());
|
||||
$when = array();
|
||||
$started = $build_target->getDateStarted();
|
||||
$now = PhabricatorTime::getNow();
|
||||
if ($started) {
|
||||
$ended = $build_target->getDateCompleted();
|
||||
if ($ended) {
|
||||
$when[] = pht(
|
||||
'Completed at %s',
|
||||
phabricator_datetime($started, $viewer));
|
||||
|
||||
if ($build_target->getDateStarted() !== null) {
|
||||
$properties->addProperty(
|
||||
pht('Started'),
|
||||
phabricator_datetime($build_target->getDateStarted(), $viewer));
|
||||
if ($build_target->isComplete()) {
|
||||
$properties->addProperty(
|
||||
pht('Completed'),
|
||||
phabricator_datetime($build_target->getDateCompleted(), $viewer));
|
||||
$properties->addProperty(
|
||||
pht('Duration'),
|
||||
phutil_format_relative_time_detailed(
|
||||
$build_target->getDateCompleted() -
|
||||
$build_target->getDateStarted()));
|
||||
$duration = ($ended - $started);
|
||||
if ($duration) {
|
||||
$when[] = pht(
|
||||
'Built for %s',
|
||||
phutil_format_relative_time_detailed($duration));
|
||||
} else {
|
||||
$when[] = pht('Built instantly');
|
||||
}
|
||||
} else {
|
||||
$properties->addProperty(
|
||||
pht('Elapsed'),
|
||||
phutil_format_relative_time_detailed(
|
||||
time() - $build_target->getDateStarted()));
|
||||
$when[] = pht(
|
||||
'Started at %s',
|
||||
phabricator_datetime($started, $viewer));
|
||||
$duration = ($now - $started);
|
||||
if ($duration) {
|
||||
$when[] = pht(
|
||||
'Running for %s',
|
||||
phutil_format_relative_time_detailed($duration));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$created = $build_target->getDateCreated();
|
||||
$when[] = pht(
|
||||
'Queued at %s',
|
||||
phabricator_datetime($started, $viewer));
|
||||
$duration = ($now - $created);
|
||||
if ($duration) {
|
||||
$when[] = pht(
|
||||
'Waiting for %s',
|
||||
phutil_format_relative_time_detailed($duration));
|
||||
}
|
||||
}
|
||||
|
||||
$properties->addProperty(
|
||||
pht('When'),
|
||||
phutil_implode_html(" \xC2\xB7 ", $when));
|
||||
|
||||
$properties->addProperty(pht('Status'), $status_view);
|
||||
|
||||
$target_box->addPropertyList($properties, pht('Overview'));
|
||||
|
@ -162,9 +183,7 @@ final class HarbormasterBuildViewController
|
|||
$variables = $build_target->getVariables();
|
||||
if ($variables) {
|
||||
$properties = new PHUIPropertyListView();
|
||||
foreach ($variables as $key => $value) {
|
||||
$properties->addProperty($key, $value);
|
||||
}
|
||||
$properties->addRawContent($this->buildProperties($variables));
|
||||
$target_box->addPropertyList($properties, pht('Variables'));
|
||||
}
|
||||
|
||||
|
@ -183,7 +202,12 @@ final class HarbormasterBuildViewController
|
|||
}
|
||||
|
||||
$properties = new PHUIPropertyListView();
|
||||
$properties->addProperty(pht('Build Target ID'), $build_target->getID());
|
||||
$properties->addProperty(
|
||||
pht('Build Target ID'),
|
||||
$build_target->getID());
|
||||
$properties->addProperty(
|
||||
pht('Build Target PHID'),
|
||||
$build_target->getPHID());
|
||||
$target_box->addPropertyList($properties, pht('Metadata'));
|
||||
|
||||
$targets[] = $target_box;
|
||||
|
@ -528,4 +552,30 @@ final class HarbormasterBuildViewController
|
|||
return $table;
|
||||
}
|
||||
|
||||
private function buildProperties(array $properties) {
|
||||
ksort($properties);
|
||||
|
||||
$rows = array();
|
||||
foreach ($properties as $key => $value) {
|
||||
$rows[] = array(
|
||||
$key,
|
||||
$value,
|
||||
);
|
||||
}
|
||||
|
||||
$table = id(new AphrontTableView($rows))
|
||||
->setHeaders(
|
||||
array(
|
||||
pht('Key'),
|
||||
pht('Value'),
|
||||
))
|
||||
->setColumnClasses(
|
||||
array(
|
||||
'pri right',
|
||||
'wide',
|
||||
));
|
||||
|
||||
return $table;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,21 +3,12 @@
|
|||
final class HarbormasterBuildableViewController
|
||||
extends HarbormasterController {
|
||||
|
||||
private $id;
|
||||
|
||||
public function willProcessRequest(array $data) {
|
||||
$this->id = $data['id'];
|
||||
}
|
||||
|
||||
public function processRequest() {
|
||||
$request = $this->getRequest();
|
||||
$viewer = $request->getUser();
|
||||
|
||||
$id = $this->id;
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$buildable = id(new HarbormasterBuildableQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($id))
|
||||
->withIDs(array($request->getURIData('id')))
|
||||
->needBuildableHandles(true)
|
||||
->needContainerHandles(true)
|
||||
->executeOne();
|
||||
|
@ -25,6 +16,8 @@ final class HarbormasterBuildableViewController
|
|||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$id = $buildable->getID();
|
||||
|
||||
// Pull builds and build targets.
|
||||
$builds = id(new HarbormasterBuildQuery())
|
||||
->setViewer($viewer)
|
||||
|
@ -32,7 +25,10 @@ final class HarbormasterBuildableViewController
|
|||
->needBuildTargets(true)
|
||||
->execute();
|
||||
|
||||
list($lint, $unit) = $this->renderLintAndUnit($builds);
|
||||
|
||||
$buildable->attachBuilds($builds);
|
||||
$object = $buildable->getBuildableObject();
|
||||
|
||||
$build_list = $this->buildBuildList($buildable);
|
||||
|
||||
|
@ -55,12 +51,14 @@ final class HarbormasterBuildableViewController
|
|||
$this->buildPropertyLists($box, $buildable, $actions);
|
||||
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
$crumbs->addTextCrumb("B{$id}");
|
||||
$crumbs->addTextCrumb($buildable->getMonogram());
|
||||
|
||||
return $this->buildApplicationPage(
|
||||
array(
|
||||
$crumbs,
|
||||
$box,
|
||||
$lint,
|
||||
$unit,
|
||||
$build_list,
|
||||
$timeline,
|
||||
),
|
||||
|
@ -144,16 +142,16 @@ final class HarbormasterBuildableViewController
|
|||
->setActionList($actions);
|
||||
$box->addPropertyList($properties);
|
||||
|
||||
$properties->addProperty(
|
||||
pht('Buildable'),
|
||||
$buildable->getBuildableHandle()->renderLink());
|
||||
|
||||
if ($buildable->getContainerHandle() !== null) {
|
||||
$properties->addProperty(
|
||||
pht('Container'),
|
||||
$buildable->getContainerHandle()->renderLink());
|
||||
}
|
||||
|
||||
$properties->addProperty(
|
||||
pht('Buildable'),
|
||||
$buildable->getBuildableHandle()->renderLink());
|
||||
|
||||
$properties->addProperty(
|
||||
pht('Origin'),
|
||||
$buildable->getIsManualBuildable()
|
||||
|
@ -250,7 +248,66 @@ final class HarbormasterBuildableViewController
|
|||
$build_list->addItem($item);
|
||||
}
|
||||
|
||||
return $build_list;
|
||||
$build_list->setFlush(true);
|
||||
|
||||
$box = id(new PHUIObjectBoxView())
|
||||
->setHeaderText(pht('Builds'))
|
||||
->appendChild($build_list);
|
||||
|
||||
return $box;
|
||||
}
|
||||
|
||||
private function renderLintAndUnit(array $builds) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$targets = array();
|
||||
foreach ($builds as $build) {
|
||||
foreach ($build->getBuildTargets() as $target) {
|
||||
$targets[] = $target;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$targets) {
|
||||
return;
|
||||
}
|
||||
|
||||
$target_phids = mpull($targets, 'getPHID');
|
||||
|
||||
$lint_data = id(new HarbormasterBuildLintMessage())->loadAllWhere(
|
||||
'buildTargetPHID IN (%Ls) LIMIT 25',
|
||||
$target_phids);
|
||||
|
||||
$unit_data = id(new HarbormasterBuildUnitMessage())->loadAllWhere(
|
||||
'buildTargetPHID IN (%Ls) LIMIT 25',
|
||||
$target_phids);
|
||||
|
||||
if ($lint_data) {
|
||||
$lint_table = id(new HarbormasterLintPropertyView())
|
||||
->setUser($viewer)
|
||||
->setLintMessages($lint_data);
|
||||
|
||||
$lint = id(new PHUIObjectBoxView())
|
||||
->setHeaderText(pht('Lint Messages'))
|
||||
->appendChild($lint_table);
|
||||
} else {
|
||||
$lint = null;
|
||||
}
|
||||
|
||||
if ($unit_data) {
|
||||
$unit_table = id(new HarbormasterUnitPropertyView())
|
||||
->setUser($viewer)
|
||||
->setUnitMessages($unit_data);
|
||||
|
||||
$unit = id(new PHUIObjectBoxView())
|
||||
->setHeaderText(pht('Unit Tests'))
|
||||
->appendChild($unit_table);
|
||||
} else {
|
||||
$unit = null;
|
||||
}
|
||||
|
||||
return array($lint, $unit);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -2,4 +2,14 @@
|
|||
|
||||
abstract class HarbormasterController extends PhabricatorController {
|
||||
|
||||
protected function addBuildableCrumb(
|
||||
PHUICrumbsView $crumbs,
|
||||
HarbormasterBuildable $buildable) {
|
||||
|
||||
$monogram = $buildable->getMonogram();
|
||||
$uri = '/'.$monogram;
|
||||
|
||||
$crumbs->addTextCrumb($monogram, $uri);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -332,6 +332,11 @@ final class HarbormasterBuildEngine extends Phobject {
|
|||
$message->save();
|
||||
|
||||
$target->setTargetStatus($new_status);
|
||||
|
||||
if ($target->isComplete()) {
|
||||
$target->setDateCompleted(PhabricatorTime::getNow());
|
||||
}
|
||||
|
||||
$target->save();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ final class HarbormasterBuildableQuery
|
|||
private $needContainerHandles;
|
||||
private $needBuildableHandles;
|
||||
private $needBuilds;
|
||||
private $needTargets;
|
||||
|
||||
public function withIDs(array $ids) {
|
||||
$this->ids = $ids;
|
||||
|
@ -59,19 +60,17 @@ final class HarbormasterBuildableQuery
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function needTargets($need) {
|
||||
$this->needTargets = $need;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function newResultObject() {
|
||||
return new HarbormasterBuildable();
|
||||
}
|
||||
|
||||
protected function loadPage() {
|
||||
$table = new HarbormasterBuildable();
|
||||
$conn_r = $table->establishConnection('r');
|
||||
|
||||
$data = queryfx_all(
|
||||
$conn_r,
|
||||
'SELECT * FROM %T %Q %Q %Q',
|
||||
$table->getTableName(),
|
||||
$this->buildWhereClause($conn_r),
|
||||
$this->buildOrderClause($conn_r),
|
||||
$this->buildLimitClause($conn_r));
|
||||
|
||||
return $table->loadAllFromArray($data);
|
||||
return $this->loadStandardPage($this->newResultObject());
|
||||
}
|
||||
|
||||
protected function willFilterPage(array $page) {
|
||||
|
@ -157,11 +156,12 @@ final class HarbormasterBuildableQuery
|
|||
}
|
||||
}
|
||||
|
||||
if ($this->needBuilds) {
|
||||
if ($this->needBuilds || $this->needTargets) {
|
||||
$builds = id(new HarbormasterBuildQuery())
|
||||
->setViewer($this->getViewer())
|
||||
->setParentQuery($this)
|
||||
->withBuildablePHIDs(mpull($page, 'getPHID'))
|
||||
->needBuildTargets($this->needTargets)
|
||||
->execute();
|
||||
$builds = mgroup($builds, 'getBuildablePHID');
|
||||
foreach ($page as $key => $buildable) {
|
||||
|
@ -172,47 +172,45 @@ final class HarbormasterBuildableQuery
|
|||
return $page;
|
||||
}
|
||||
|
||||
protected function buildWhereClause(AphrontDatabaseConnection $conn_r) {
|
||||
$where = array();
|
||||
protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
|
||||
$where = parent::buildWhereClauseParts($conn);
|
||||
|
||||
if ($this->ids !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
$conn,
|
||||
'id IN (%Ld)',
|
||||
$this->ids);
|
||||
}
|
||||
|
||||
if ($this->phids !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
$conn,
|
||||
'phid IN (%Ls)',
|
||||
$this->phids);
|
||||
}
|
||||
|
||||
if ($this->buildablePHIDs !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
$conn,
|
||||
'buildablePHID IN (%Ls)',
|
||||
$this->buildablePHIDs);
|
||||
}
|
||||
|
||||
if ($this->containerPHIDs !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
$conn,
|
||||
'containerPHID in (%Ls)',
|
||||
$this->containerPHIDs);
|
||||
}
|
||||
|
||||
if ($this->manualBuildables !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
$conn,
|
||||
'isManualBuildable = %d',
|
||||
(int)$this->manualBuildables);
|
||||
}
|
||||
|
||||
$where[] = $this->buildPagingClause($conn_r);
|
||||
|
||||
return $this->formatWhereClause($where);
|
||||
return $where;
|
||||
}
|
||||
|
||||
public function getQueryApplicationClass() {
|
||||
|
|
|
@ -15,7 +15,7 @@ final class HarbormasterBuildUnitMessage
|
|||
|
||||
public static function initializeNewUnitMessage(
|
||||
HarbormasterBuildTarget $build_target) {
|
||||
return id(new HarbormasterBuildLintMessage())
|
||||
return id(new HarbormasterBuildUnitMessage())
|
||||
->setBuildTargetPHID($build_target->getPHID());
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
<?php
|
||||
|
||||
final class HarbormasterLintPropertyView extends AphrontView {
|
||||
|
||||
private $pathURIMap = array();
|
||||
private $lintMessages = array();
|
||||
|
||||
public function setPathURIMap(array $map) {
|
||||
$this->pathURIMap = $map;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setLintMessages(array $messages) {
|
||||
assert_instances_of($messages, 'HarbormasterBuildLintMessage');
|
||||
$this->lintMessages = $messages;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function render() {
|
||||
$rows = array();
|
||||
foreach ($this->lintMessages as $message) {
|
||||
$path = $message->getPath();
|
||||
$line = $message->getLine();
|
||||
|
||||
$href = null;
|
||||
if (strlen(idx($this->pathURIMap, $path))) {
|
||||
$href = $this->pathURIMap[$path].max($line, 1);
|
||||
}
|
||||
|
||||
$severity = $this->renderSeverity($message->getSeverity());
|
||||
|
||||
$location = $path.':'.$line;
|
||||
if (strlen($href)) {
|
||||
$location = phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => $href,
|
||||
),
|
||||
$location);
|
||||
}
|
||||
|
||||
$rows[] = array(
|
||||
$location,
|
||||
$severity,
|
||||
$message->getCode(),
|
||||
$message->getName(),
|
||||
);
|
||||
}
|
||||
|
||||
$table = id(new AphrontTableView($rows))
|
||||
->setHeaders(
|
||||
array(
|
||||
pht('Location'),
|
||||
pht('Severity'),
|
||||
pht('Code'),
|
||||
pht('Message'),
|
||||
))
|
||||
->setColumnClasses(
|
||||
array(
|
||||
'pri',
|
||||
null,
|
||||
null,
|
||||
'wide',
|
||||
));
|
||||
|
||||
return $table;
|
||||
}
|
||||
|
||||
private function renderSeverity($severity) {
|
||||
$names = ArcanistLintSeverity::getLintSeverities();
|
||||
$name = idx($names, $severity, $severity);
|
||||
|
||||
// TODO: Add some color here?
|
||||
|
||||
return $name;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
<?php
|
||||
|
||||
final class HarbormasterUnitPropertyView extends AphrontView {
|
||||
|
||||
private $pathURIMap = array();
|
||||
private $unitMessages = array();
|
||||
|
||||
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 render() {
|
||||
|
||||
$rows = array();
|
||||
$any_duration = false;
|
||||
foreach ($this->unitMessages as $message) {
|
||||
$result = $this->renderResult($message->getResult());
|
||||
|
||||
$duration = $message->getDuration();
|
||||
if ($duration !== null) {
|
||||
$any_duration = true;
|
||||
$duration = pht('%s ms', new PhutilNumber((int)(1000 * $duration)));
|
||||
}
|
||||
|
||||
$name = $message->getName();
|
||||
|
||||
$namespace = $message->getNamespace();
|
||||
if (strlen($namespace)) {
|
||||
$name = $namespace.'::'.$name;
|
||||
}
|
||||
|
||||
$engine = $message->getEngine();
|
||||
if (strlen($engine)) {
|
||||
$name = $engine.' > '.$name;
|
||||
}
|
||||
|
||||
$rows[] = array(
|
||||
$result,
|
||||
$duration,
|
||||
$name,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
$table = id(new AphrontTableView($rows))
|
||||
->setHeaders(
|
||||
array(
|
||||
pht('Result'),
|
||||
pht('Time'),
|
||||
pht('Test'),
|
||||
))
|
||||
->setColumnClasses(
|
||||
array(
|
||||
null,
|
||||
null,
|
||||
'pri wide',
|
||||
))
|
||||
->setColumnVisibility(
|
||||
array(
|
||||
true,
|
||||
$any_duration,
|
||||
));
|
||||
|
||||
return $table;
|
||||
}
|
||||
|
||||
private function renderResult($result) {
|
||||
$names = array(
|
||||
ArcanistUnitTestResult::RESULT_BROKEN => pht('Broken'),
|
||||
ArcanistUnitTestResult::RESULT_FAIL => pht('Failed'),
|
||||
ArcanistUnitTestResult::RESULT_UNSOUND => pht('Unsound'),
|
||||
ArcanistUnitTestResult::RESULT_SKIP => pht('Skipped'),
|
||||
ArcanistUnitTestResult::RESULT_POSTPONED => pht('Postponed'),
|
||||
ArcanistUnitTestResult::RESULT_PASS => pht('Passed'),
|
||||
);
|
||||
$result = idx($names, $result, $result);
|
||||
|
||||
// TODO: Add some color.
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
|
@ -59,7 +59,7 @@ final class HarbormasterTargetWorker extends HarbormasterWorker {
|
|||
$target->setTargetStatus($next_status);
|
||||
|
||||
if ($target->isComplete()) {
|
||||
$target->setDateCompleted(time());
|
||||
$target->setDateCompleted(PhabricatorTime::getNow());
|
||||
}
|
||||
|
||||
$target->save();
|
||||
|
@ -70,12 +70,12 @@ final class HarbormasterTargetWorker extends HarbormasterWorker {
|
|||
} catch (HarbormasterBuildFailureException $ex) {
|
||||
// A build step wants to fail explicitly.
|
||||
$target->setTargetStatus(HarbormasterBuildTarget::STATUS_FAILED);
|
||||
$target->setDateCompleted(time());
|
||||
$target->setDateCompleted(PhabricatorTime::getNow());
|
||||
$target->save();
|
||||
} catch (HarbormasterBuildAbortedException $ex) {
|
||||
// A build step is aborting because the build has been restarted.
|
||||
$target->setTargetStatus(HarbormasterBuildTarget::STATUS_ABORTED);
|
||||
$target->setDateCompleted(time());
|
||||
$target->setDateCompleted(PhabricatorTime::getNow());
|
||||
$target->save();
|
||||
} catch (Exception $ex) {
|
||||
phlog($ex);
|
||||
|
|
|
@ -10,7 +10,8 @@ final class PholioMock extends PholioDAO
|
|||
PhabricatorApplicationTransactionInterface,
|
||||
PhabricatorProjectInterface,
|
||||
PhabricatorDestructibleInterface,
|
||||
PhabricatorSpacesInterface {
|
||||
PhabricatorSpacesInterface,
|
||||
PhabricatorMentionableInterface {
|
||||
|
||||
const MARKUP_FIELD_DESCRIPTION = 'markup:description';
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ final class PHUIStatusItemView extends AphrontTagView {
|
|||
const ICON_MINUS = 'fa-minus-circle';
|
||||
const ICON_OPEN = 'fa-circle-o';
|
||||
const ICON_CLOCK = 'fa-clock-o';
|
||||
const ICON_STAR = 'fa-star';
|
||||
|
||||
/* render_textarea */
|
||||
public function setIcon($icon, $color = null, $label = null) {
|
||||
|
|
|
@ -1,78 +0,0 @@
|
|||
/**
|
||||
* @provides differential-results-table-css
|
||||
*/
|
||||
|
||||
table.differential-results-table {
|
||||
border-collapse: separate;
|
||||
width: 96%;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.differential-results-table th {
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
vertical-align: middle;
|
||||
padding: 2px 4px;
|
||||
width: 50px;
|
||||
border-right: 1px solid #fff;
|
||||
background: #f7f7f7;
|
||||
}
|
||||
|
||||
.device .differential-results-table th {
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.differential-results-table td {
|
||||
padding: 0 8px;
|
||||
margin: 0;
|
||||
vertical-align: middle;
|
||||
background: #f7f7f7;
|
||||
}
|
||||
|
||||
.differential-results-table tr.differential-results-row-star th,
|
||||
.differential-results-table tr.differential-results-row-star td {
|
||||
background: {$greybackground};
|
||||
}
|
||||
|
||||
.differential-results-table tr.differential-results-row-section th {
|
||||
padding-top: 4px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.differential-results-table tr.differential-results-row-excuse th {
|
||||
background: #3399ff;
|
||||
}
|
||||
|
||||
.differential-results-table tr.differential-results-row-excuse td {
|
||||
padding-top: 8px;
|
||||
padding-right: 8px;
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
.differential-results-table tr.differential-results-row-red th {
|
||||
background: #ff4422;
|
||||
}
|
||||
|
||||
.differential-results-table tr.differential-results-row-yellow th {
|
||||
background: #ffdd66;
|
||||
}
|
||||
|
||||
.differential-results-table tr.differential-results-row-green th {
|
||||
background: #22dd44;
|
||||
}
|
||||
|
||||
.differential-results-table tr.differential-results-row-blue th {
|
||||
background: #88bbff;
|
||||
}
|
||||
|
||||
.differential-results-table tr.differential-results-row-details td {
|
||||
color: {$lightgreytext};
|
||||
}
|
||||
|
||||
.differential-results-table tr.differential-results-row-show th {
|
||||
border-top: 1px solid #fff;
|
||||
border-right: none;
|
||||
padding: 2px;
|
||||
color: {$bluetext};
|
||||
background: {$greybackground};
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
/**
|
||||
* @provides javelin-behavior-differential-show-field-details
|
||||
* @requires javelin-behavior
|
||||
* javelin-stratcom
|
||||
* javelin-dom
|
||||
*/
|
||||
|
||||
JX.behavior('differential-show-field-details', function() {
|
||||
|
||||
JX.Stratcom.listen(
|
||||
'click',
|
||||
['differential-results-row-show', 'tag:a'],
|
||||
function(e) {
|
||||
toggle(e, true);
|
||||
});
|
||||
|
||||
JX.Stratcom.listen(
|
||||
'click',
|
||||
['differential-results-row-hide', 'tag:a'],
|
||||
function(e) {
|
||||
toggle(e, false);
|
||||
});
|
||||
|
||||
function toggle(e, show) {
|
||||
e.kill();
|
||||
|
||||
var f = show ? JX.DOM.show : JX.DOM.hide;
|
||||
var g = show ? JX.DOM.hide : JX.DOM.show;
|
||||
|
||||
var table = e.getNode('differential-results-table');
|
||||
var rows = JX.DOM.scry(table, 'tr', 'differential-results-row-toggle');
|
||||
for (var ii = 0; ii < rows.length; ii++) {
|
||||
f(rows[ii]);
|
||||
}
|
||||
|
||||
g(JX.DOM.find(table, 'tr', 'differential-results-row-show'));
|
||||
f(JX.DOM.find(table, 'tr', 'differential-results-row-hide'));
|
||||
}
|
||||
|
||||
});
|
Loading…
Reference in a new issue