private function buildActionList(HarbormasterBuildable $buildable) { $request = $this->getRequest(); $viewer = $request->getUser(); $id = $buildable->getID(); $list = id(new PhabricatorActionListView())->setUser($viewer)->setObject($buildable)->setObjectURI($buildable->getMonogram()); $can_edit = PhabricatorPolicyFilter::hasCapability($viewer, $buildable, PhabricatorPolicyCapability::CAN_EDIT); $can_restart = false; $can_resume = false; $can_stop = false; foreach ($buildable->getBuilds() as $build) { if ($build->canRestartBuild()) { $can_restart = true; } if ($build->canResumeBuild()) { $can_resume = true; } if ($build->canStopBuild()) { $can_stop = true; } } $restart_uri = "buildable/{$id}/restart/"; $stop_uri = "buildable/{$id}/stop/"; $resume_uri = "buildable/{$id}/resume/"; $list->addAction(id(new PhabricatorActionView())->setIcon('fa-repeat')->setName(pht('Restart All Builds'))->setHref($this->getApplicationURI($restart_uri))->setWorkflow(true)->setDisabled(!$can_restart || !$can_edit)); $list->addAction(id(new PhabricatorActionView())->setIcon('fa-pause')->setName(pht('Pause All Builds'))->setHref($this->getApplicationURI($stop_uri))->setWorkflow(true)->setDisabled(!$can_stop || !$can_edit)); $list->addAction(id(new PhabricatorActionView())->setIcon('fa-play')->setName(pht('Resume All Builds'))->setHref($this->getApplicationURI($resume_uri))->setWorkflow(true)->setDisabled(!$can_resume || !$can_edit)); return $list; }
private function renderLintAndUnit(HarbormasterBuildable $buildable, 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)', $target_phids); $unit_data = id(new HarbormasterBuildUnitMessage())->loadAllWhere('buildTargetPHID IN (%Ls)', $target_phids); if ($lint_data) { $lint_table = id(new HarbormasterLintPropertyView())->setUser($viewer)->setLimit(10)->setLintMessages($lint_data); $lint_href = $this->getApplicationURI('lint/' . $buildable->getID() . '/'); $lint_header = id(new PHUIHeaderView())->setHeader(pht('Lint Messages'))->addActionLink(id(new PHUIButtonView())->setTag('a')->setHref($lint_href)->setIconFont('fa-list-ul')->setText('View All')); $lint = id(new PHUIObjectBoxView())->setHeader($lint_header)->setTable($lint_table); } else { $lint = null; } if ($unit_data) { $unit_table = id(new HarbormasterUnitPropertyView())->setUser($viewer)->setLimit(25)->setUnitMessages($unit_data); $unit_href = $this->getApplicationURI('unit/' . $buildable->getID() . '/'); $unit_header = id(new PHUIHeaderView())->setHeader(pht('Unit Tests'))->addActionLink(id(new PHUIButtonView())->setTag('a')->setHref($unit_href)->setIconFont('fa-list-ul')->setText('View All')); $unit = id(new PHUIObjectBoxView())->setHeader($unit_header)->setTable($unit_table); } else { $unit = null; } return array($lint, $unit); }
/** * 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) { $viewer = $this->getViewer(); $lock_key = 'harbormaster.buildable:' . $buildable->getID(); $lock = PhabricatorGlobalLock::newLock($lock_key)->lock(15); $buildable = id(new HarbormasterBuildableQuery())->setViewer($viewer)->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 || $build->getBuildStatus() == HarbormasterBuild::STATUS_DEADLOCKED) { $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; } } $old_status = $buildable->getBuildableStatus(); $did_update = $old_status != $new_status; if ($did_update) { $buildable->setBuildableStatus($new_status); $buildable->save(); } $lock->unlock(); // If we changed the buildable status, try to post a transaction to the // object about it. We can safely do this outside of the locked region. // NOTE: We only post transactions for automatic buildables, not for // manual ones: manual builds are test builds, whoever is doing tests // can look at the results themselves, and other users generally don't // care about the outcome. $should_publish = $did_update && $new_status != HarbormasterBuildable::STATUS_BUILDING && !$buildable->getIsManualBuildable(); if (!$should_publish) { return; } $object = id(new PhabricatorObjectQuery())->setViewer($viewer)->withPHIDs(array($buildable->getBuildablePHID()))->executeOne(); if (!$object) { return; } if (!$object instanceof PhabricatorApplicationTransactionInterface) { return; } // TODO: Publishing these transactions is causing a race. See T8650. // We shouldn't be publishing to diffs anyway. if ($object instanceof DifferentialDiff) { return; } $template = $object->getApplicationTransactionTemplate(); if (!$template) { return; } $template->setTransactionType(PhabricatorTransactions::TYPE_BUILDABLE)->setMetadataValue('harbormaster:buildablePHID', $buildable->getPHID())->setOldValue($old_status)->setNewValue($new_status); $harbormaster_phid = id(new PhabricatorHarbormasterApplication())->getPHID(); $daemon_source = PhabricatorContentSource::newForSource(PhabricatorContentSource::SOURCE_DAEMON, array()); $editor = $object->getApplicationTransactionEditor()->setActor($viewer)->setActingAsPHID($harbormaster_phid)->setContentSource($daemon_source)->setContinueOnNoEffect(true)->setContinueOnMissingFields(true); $editor->applyTransactions($object->getApplicationTransactionObject(), array($template)); }