Page MenuHomePhabricator

D8799.id20880.diff
No OneTemporary

D8799.id20880.diff

diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -744,6 +744,7 @@
'HarbormasterHTTPRequestBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterHTTPRequestBuildStepImplementation.php',
'HarbormasterLeaseHostBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterLeaseHostBuildStepImplementation.php',
'HarbormasterManagementBuildWorkflow' => 'applications/harbormaster/management/HarbormasterManagementBuildWorkflow.php',
+ 'HarbormasterManagementUpdateWorkflow' => 'applications/harbormaster/management/HarbormasterManagementUpdateWorkflow.php',
'HarbormasterManagementWorkflow' => 'applications/harbormaster/management/HarbormasterManagementWorkflow.php',
'HarbormasterObject' => 'applications/harbormaster/storage/HarbormasterObject.php',
'HarbormasterPHIDTypeBuild' => 'applications/harbormaster/phid/HarbormasterPHIDTypeBuild.php',
@@ -3411,6 +3412,7 @@
'HarbormasterHTTPRequestBuildStepImplementation' => 'HarbormasterBuildStepImplementation',
'HarbormasterLeaseHostBuildStepImplementation' => 'HarbormasterBuildStepImplementation',
'HarbormasterManagementBuildWorkflow' => 'HarbormasterManagementWorkflow',
+ 'HarbormasterManagementUpdateWorkflow' => 'HarbormasterManagementWorkflow',
'HarbormasterManagementWorkflow' => 'PhabricatorManagementWorkflow',
'HarbormasterObject' => 'HarbormasterDAO',
'HarbormasterPHIDTypeBuild' => 'PhabricatorPHIDType',
diff --git a/src/applications/harbormaster/conduit/ConduitAPI_harbormaster_querybuildables_Method.php b/src/applications/harbormaster/conduit/ConduitAPI_harbormaster_querybuildables_Method.php
--- a/src/applications/harbormaster/conduit/ConduitAPI_harbormaster_querybuildables_Method.php
+++ b/src/applications/harbormaster/conduit/ConduitAPI_harbormaster_querybuildables_Method.php
@@ -64,11 +64,16 @@
foreach ($buildables as $buildable) {
$monogram = $buildable->getMonogram();
+ $status = $buildable->getBuildableStatus();
+ $status_name = HarbormasterBuildable::getBuildableStatusName($status);
+
$data[] = array(
'id' => $buildable->getID(),
'phid' => $buildable->getPHID(),
'monogram' => $monogram,
'uri' => PhabricatorEnv::getProductionURI('/'.$monogram),
+ 'buildableStatus' => $status,
+ 'buildableStatusName' => $status_name,
'buildablePHID' => $buildable->getBuildablePHID(),
'containerPHID' => $buildable->getContainerPHID(),
'isManualBuildable' => (bool)$buildable->getIsManualBuildable(),
diff --git a/src/applications/harbormaster/conduit/ConduitAPI_harbormaster_sendmessage_Method.php b/src/applications/harbormaster/conduit/ConduitAPI_harbormaster_sendmessage_Method.php
--- a/src/applications/harbormaster/conduit/ConduitAPI_harbormaster_sendmessage_Method.php
+++ b/src/applications/harbormaster/conduit/ConduitAPI_harbormaster_sendmessage_Method.php
@@ -45,10 +45,11 @@
// If the build has completely paused because all steps are blocked on
// waiting targets, this will resume it.
- id(new HarbormasterBuildEngine())
- ->setViewer($viewer)
- ->setBuild($build_target->getBuild())
- ->continueBuild();
+ PhabricatorWorker::scheduleTask(
+ 'HarbormasterBuildWorker',
+ array(
+ 'buildID' => $build_target->getBuild()->getID(),
+ ));
return null;
}
diff --git a/src/applications/harbormaster/controller/HarbormasterBuildableListController.php b/src/applications/harbormaster/controller/HarbormasterBuildableListController.php
--- a/src/applications/harbormaster/controller/HarbormasterBuildableListController.php
+++ b/src/applications/harbormaster/controller/HarbormasterBuildableListController.php
@@ -54,28 +54,13 @@
$list->addItem($item);
-
-
- // TODO: This is proof-of-concept for getting meaningful status
- // information into this list, and should get an improvement pass
- // once we're a little farther along.
-
- $all_pass = true;
- $any_fail = false;
- foreach ($buildable->getBuilds() as $build) {
- if ($build->getBuildStatus() != HarbormasterBuild::STATUS_PASSED) {
- $all_pass = false;
- }
- if ($build->getBuildStatus() == HarbormasterBuild::STATUS_FAILED ||
- $build->getBuildStatus() == HarbormasterBuild::STATUS_ERROR) {
- $any_fail = true;
- }
- }
-
- if ($any_fail) {
- $item->setBarColor('red');
- } else if ($all_pass) {
- $item->setBarColor('green');
+ switch ($buildable->getBuildableStatus()) {
+ case HarbormasterBuildable::STATUS_PASSED:
+ $item->setBarColor('green');
+ break;
+ case HarbormasterBuildable::STATUS_FAILED:
+ $item->setBarColor('red');
+ break;
}
}
diff --git a/src/applications/harbormaster/engine/HarbormasterBuildEngine.php b/src/applications/harbormaster/engine/HarbormasterBuildEngine.php
--- a/src/applications/harbormaster/engine/HarbormasterBuildEngine.php
+++ b/src/applications/harbormaster/engine/HarbormasterBuildEngine.php
@@ -9,6 +9,16 @@
private $build;
private $viewer;
private $newBuildTargets = array();
+ private $forceBuildableUpdate;
+
+ public function setForceBuildableUpdate($force_buildable_update) {
+ $this->forceBuildableUpdate = $force_buildable_update;
+ return $this;
+ }
+
+ public function shouldForceBuildableUpdate() {
+ return $this->forceBuildableUpdate;
+ }
public function queueNewBuildTarget(HarbormasterBuildTarget $target) {
$this->newBuildTargets[] = $target;
@@ -44,6 +54,7 @@
$lock = PhabricatorGlobalLock::newLock($lock_key)->lock(15);
$build->reload();
+ $old_status = $build->getBuildStatus();
try {
$this->updateBuild($build);
@@ -69,6 +80,13 @@
'targetID' => $target->getID(),
));
}
+
+ // If the build changed status, we might need to update the overall status
+ // on the buildable.
+ $new_status = $build->getBuildStatus();
+ if ($new_status != $old_status || $this->shouldForceBuildableUpdate()) {
+ $this->updateBuildable($build->getBuildable());
+ }
}
private function updateBuild(HarbormasterBuild $build) {
@@ -330,4 +348,53 @@
}
}
+
+ /**
+ * Update the overall status of the buildable this build is attached to.
+ *
+ * After a build changes state (for example, passes or fails) it may affect
+ * the overall state of the associated buildable. Compute the new aggregate
+ * state and save it on the buildable.
+ *
+ * @param HarbormasterBuild The buildable to update.
+ * @return void
+ */
+ private function updateBuildable(HarbormasterBuildable $buildable) {
+ $lock_key = 'harbormaster.buildable:'.$buildable->getID();
+ $lock = PhabricatorGlobalLock::newLock($lock_key)->lock(15);
+
+ $buildable = id(new HarbormasterBuildableQuery())
+ ->setViewer($this->getViewer())
+ ->withIDs(array($buildable->getID()))
+ ->needBuilds(true)
+ ->executeOne();
+
+ $all_pass = true;
+ $any_fail = false;
+ foreach ($buildable->getBuilds() as $build) {
+ if ($build->getBuildStatus() != HarbormasterBuild::STATUS_PASSED) {
+ $all_pass = false;
+ }
+ if ($build->getBuildStatus() == HarbormasterBuild::STATUS_FAILED ||
+ $build->getBuildStatus() == HarbormasterBuild::STATUS_ERROR) {
+ $any_fail = true;
+ }
+ }
+
+ if ($any_fail) {
+ $new_status = HarbormasterBuildable::STATUS_FAILED;
+ } else if ($all_pass) {
+ $new_status = HarbormasterBuildable::STATUS_PASSED;
+ } else {
+ $new_status = HarbormasterBuildable::STATUS_BUILDING;
+ }
+
+ if ($buildable->getBuildableStatus() != $new_status) {
+ $buildable->setBuildableStatus($new_status);
+ $buildable->save();
+ }
+
+ $lock->unlock();
+ }
+
}
diff --git a/src/applications/harbormaster/management/HarbormasterManagementBuildWorkflow.php b/src/applications/harbormaster/management/HarbormasterManagementBuildWorkflow.php
--- a/src/applications/harbormaster/management/HarbormasterManagementBuildWorkflow.php
+++ b/src/applications/harbormaster/management/HarbormasterManagementBuildWorkflow.php
@@ -28,7 +28,7 @@
$names = $args->getArg('buildable');
if (count($names) != 1) {
throw new PhutilArgumentUsageException(
- pht('Specify exactly one buildable, by object name.'));
+ pht('Specify exactly one buildable object, by object name.'));
}
$name = head($names);
diff --git a/src/applications/harbormaster/management/HarbormasterManagementUpdateWorkflow.php b/src/applications/harbormaster/management/HarbormasterManagementUpdateWorkflow.php
new file mode 100644
--- /dev/null
+++ b/src/applications/harbormaster/management/HarbormasterManagementUpdateWorkflow.php
@@ -0,0 +1,114 @@
+<?php
+
+final class HarbormasterManagementUpdateWorkflow
+ extends HarbormasterManagementWorkflow {
+
+ public function didConstruct() {
+ $this
+ ->setName('update')
+ ->setExamples('**update** [__options__] __buildable__')
+ ->setSynopsis(pht('Explicitly update the builds for __buildable__.'))
+ ->setArguments(
+ array(
+ array(
+ 'name' => 'build',
+ 'param' => 'id',
+ 'help' => pht('Update only this build.'),
+ ),
+ array(
+ 'name' => 'force',
+ 'help' => pht(
+ 'Force the buildable to update even if no build status '.
+ 'changes occur during normal update.'),
+ ),
+ array(
+ 'name' => 'background',
+ 'help' => pht(
+ 'If updating generates tasks, queue them for the daemons '.
+ 'instead of executing them in this process.'),
+ ),
+ array(
+ 'name' => 'buildable',
+ 'wildcard' => true,
+ ),
+ ));
+ }
+
+ public function execute(PhutilArgumentParser $args) {
+ $viewer = $this->getViewer();
+
+ $force_update = $args->getArg('force');
+
+ $names = $args->getArg('buildable');
+ if (count($names) != 1) {
+ throw new PhutilArgumentUsageException(
+ pht('Specify exactly one buildable, by object name.'));
+ }
+
+ $buildable = id(new PhabricatorObjectQuery())
+ ->setViewer($viewer)
+ ->withNames($names)
+ ->executeOne();
+
+ if (!$buildable) {
+ throw new PhutilArgumentUsageException(
+ pht('No such buildable "%s"!', head($names)));
+ }
+
+ if (!($buildable instanceof HarbormasterBuildable)) {
+ throw new PhutilArgumentUsageException(
+ pht('Object "%s" is not a Harbormaster Buildable!', head($names)));
+ }
+
+ // Reload the buildable directly to get builds.
+ $buildable = id(new HarbormasterBuildableQuery())
+ ->setViewer($viewer)
+ ->withIDs(array($buildable->getID()))
+ ->needBuilds(true)
+ ->executeOne();
+
+ $builds = $buildable->getBuilds();
+ $builds = mpull($builds, null, 'getID');
+
+ $build_id = $args->getArg('build');
+ if ($build_id) {
+ $builds = array_select_keys($builds, array($build_id));
+ if (!$builds) {
+ throw new PhutilArgumentUsageException(
+ pht(
+ 'The specified buildable does not have a build with ID "%s".',
+ $build_id));
+ }
+ }
+
+ $console = PhutilConsole::getConsole();
+
+ if (!$args->getArg('background')) {
+ PhabricatorWorker::setRunAllTasksInProcess(true);
+ }
+
+ foreach ($builds as $build) {
+ $console->writeOut(
+ "%s\n",
+ pht(
+ 'Updating build %d of buildable %s...',
+ $build->getID(),
+ $buildable->getMonogram()));
+
+ $engine = id(new HarbormasterBuildEngine())
+ ->setViewer($viewer)
+ ->setBuild($build);
+
+ if ($force_update) {
+ $engine->setForceBuildableUpdate(true);
+ }
+
+ $engine->continueBuild();
+ }
+
+ $console->writeOut("%s\n", pht('Done.'));
+
+ return 0;
+ }
+
+}
diff --git a/src/applications/harbormaster/query/HarbormasterBuildableSearchEngine.php b/src/applications/harbormaster/query/HarbormasterBuildableSearchEngine.php
--- a/src/applications/harbormaster/query/HarbormasterBuildableSearchEngine.php
+++ b/src/applications/harbormaster/query/HarbormasterBuildableSearchEngine.php
@@ -52,8 +52,7 @@
public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) {
$query = id(new HarbormasterBuildableQuery())
->needContainerHandles(true)
- ->needBuildableHandles(true)
- ->needBuilds(true);
+ ->needBuildableHandles(true);
$container_phids = $saved->getParameter('containerPHIDs', array());
if ($container_phids) {
diff --git a/src/applications/harbormaster/storage/HarbormasterBuildable.php b/src/applications/harbormaster/storage/HarbormasterBuildable.php
--- a/src/applications/harbormaster/storage/HarbormasterBuildable.php
+++ b/src/applications/harbormaster/storage/HarbormasterBuildable.php
@@ -16,12 +16,27 @@
private $containerHandle = self::ATTACHABLE;
private $builds = self::ATTACHABLE;
- const STATUS_WHATEVER = 'whatever';
+ const STATUS_BUILDING = 'building';
+ const STATUS_PASSED = 'passed';
+ const STATUS_FAILED = 'failed';
+
+ public static function getBuildableStatusName($status) {
+ switch ($status) {
+ case self::STATUS_BUILDING:
+ return pht('Building');
+ case self::STATUS_PASSED:
+ return pht('Passed');
+ case self::STATUS_FAILED:
+ return pht('Failed');
+ default:
+ return pht('Unknown');
+ }
+ }
public static function initializeNewBuildable(PhabricatorUser $actor) {
return id(new HarbormasterBuildable())
->setIsManualBuildable(0)
- ->setBuildableStatus(self::STATUS_WHATEVER);
+ ->setBuildableStatus(self::STATUS_BUILDING);
}
public function getMonogram() {

File Metadata

Mime Type
text/plain
Expires
Sun, Dec 22, 6:16 PM (7 h, 48 m)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6919360
Default Alt Text
D8799.id20880.diff (13 KB)

Event Timeline