diff --git a/src/applications/differential/editor/DifferentialTransactionEditor.php b/src/applications/differential/editor/DifferentialTransactionEditor.php index b9405faff9..fce8e423b4 100644 --- a/src/applications/differential/editor/DifferentialTransactionEditor.php +++ b/src/applications/differential/editor/DifferentialTransactionEditor.php @@ -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; } diff --git a/src/applications/harbormaster/controller/HarbormasterBuildViewController.php b/src/applications/harbormaster/controller/HarbormasterBuildViewController.php index 4af1f34276..2b5d2c7222 100644 --- a/src/applications/harbormaster/controller/HarbormasterBuildViewController.php +++ b/src/applications/harbormaster/controller/HarbormasterBuildViewController.php @@ -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; + } + } diff --git a/src/applications/harbormaster/controller/HarbormasterBuildableViewController.php b/src/applications/harbormaster/controller/HarbormasterBuildableViewController.php index 8fa65d0350..f080961efc 100644 --- a/src/applications/harbormaster/controller/HarbormasterBuildableViewController.php +++ b/src/applications/harbormaster/controller/HarbormasterBuildableViewController.php @@ -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) @@ -33,6 +26,7 @@ final class HarbormasterBuildableViewController ->execute(); $buildable->attachBuilds($builds); + $object = $buildable->getBuildableObject(); $build_list = $this->buildBuildList($buildable); @@ -55,7 +49,7 @@ final class HarbormasterBuildableViewController $this->buildPropertyLists($box, $buildable, $actions); $crumbs = $this->buildApplicationCrumbs(); - $crumbs->addTextCrumb("B{$id}"); + $crumbs->addTextCrumb($buildable->getMonogram()); return $this->buildApplicationPage( array( @@ -144,16 +138,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() diff --git a/src/applications/harbormaster/controller/HarbormasterController.php b/src/applications/harbormaster/controller/HarbormasterController.php index c946cf7002..dea76b36d3 100644 --- a/src/applications/harbormaster/controller/HarbormasterController.php +++ b/src/applications/harbormaster/controller/HarbormasterController.php @@ -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); + } + } diff --git a/src/applications/harbormaster/engine/HarbormasterBuildEngine.php b/src/applications/harbormaster/engine/HarbormasterBuildEngine.php index 98e67635f3..71c14414e7 100644 --- a/src/applications/harbormaster/engine/HarbormasterBuildEngine.php +++ b/src/applications/harbormaster/engine/HarbormasterBuildEngine.php @@ -332,6 +332,11 @@ final class HarbormasterBuildEngine extends Phobject { $message->save(); $target->setTargetStatus($new_status); + + if ($target->isComplete()) { + $target->setDateCompleted(PhabricatorTime::getNow()); + } + $target->save(); } } diff --git a/src/applications/harbormaster/worker/HarbormasterTargetWorker.php b/src/applications/harbormaster/worker/HarbormasterTargetWorker.php index d0d6d168ab..a13a9de163 100644 --- a/src/applications/harbormaster/worker/HarbormasterTargetWorker.php +++ b/src/applications/harbormaster/worker/HarbormasterTargetWorker.php @@ -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);