public function execute(HarbormasterBuild $build, HarbormasterBuildTarget $build_target)
 {
     // We can only wait when building against commits.
     $buildable = $build->getBuildable();
     $object = $buildable->getBuildableObject();
     if (!$object instanceof PhabricatorRepositoryCommit) {
         return;
     }
     // Block until all previous builds of the same build plan have
     // finished.
     $plan = $build->getBuildPlan();
     $existing_logs = id(new HarbormasterBuildLogQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withBuildTargetPHIDs(array($build_target->getPHID()))->execute();
     if ($existing_logs) {
         $log = head($existing_logs);
     } else {
         $log = $build->createLog($build_target, 'waiting', 'blockers');
     }
     $blockers = $this->getBlockers($object, $plan, $build);
     if ($blockers) {
         $log->start();
         $log->append(pht("Blocked by: %s\n", implode(',', $blockers)));
         $log->finalize();
     }
     if ($blockers) {
         throw new PhabricatorWorkerYieldException(15);
     }
 }
 protected function loadPage()
 {
     $table = new HarbormasterBuild();
     $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);
 }
 private function buildActionView(HarbormasterBuildUnitMessage $message, HarbormasterBuild $build)
 {
     $viewer = $this->getViewer();
     $view = id(new PhabricatorActionListView())->setUser($viewer);
     $view->addAction(id(new PhabricatorActionView())->setName(pht('View Build'))->setHref($build->getURI())->setIcon('fa-wrench'));
     return $view;
 }
 public function execute(HarbormasterBuild $build, HarbormasterBuildTarget $build_target)
 {
     $viewer = PhabricatorUser::getOmnipotentUser();
     $settings = $this->getSettings();
     $variables = $build_target->getVariables();
     $artifact = $build_target->loadArtifact($settings['hostartifact']);
     $impl = $artifact->getArtifactImplementation();
     $lease = $impl->loadArtifactLease($viewer);
     $this->platform = $lease->getAttribute('platform');
     $command = $this->mergeVariables(array($this, 'escapeCommand'), $settings['command'], $variables);
     $this->platform = null;
     $interface = $lease->getInterface('command');
     $future = $interface->getExecFuture('%C', $command);
     $log_stdout = $build->createLog($build_target, 'remote', 'stdout');
     $log_stderr = $build->createLog($build_target, 'remote', 'stderr');
     $start_stdout = $log_stdout->start();
     $start_stderr = $log_stderr->start();
     $build_update = 5;
     // Read the next amount of available output every second.
     $futures = new FutureIterator(array($future));
     foreach ($futures->setUpdateInterval(1) as $key => $future_iter) {
         if ($future_iter === null) {
             // Check to see if we should abort.
             if ($build_update <= 0) {
                 $build->reload();
                 if ($this->shouldAbort($build, $build_target)) {
                     $future->resolveKill();
                     throw new HarbormasterBuildAbortedException();
                 } else {
                     $build_update = 5;
                 }
             } else {
                 $build_update -= 1;
             }
             // Command is still executing.
             // Read more data as it is available.
             list($stdout, $stderr) = $future->read();
             $log_stdout->append($stdout);
             $log_stderr->append($stderr);
             $future->discardBuffers();
         } else {
             // Command execution is complete.
             // Get the return value so we can log that as well.
             list($err) = $future->resolve();
             // Retrieve the last few bits of information.
             list($stdout, $stderr) = $future->read();
             $log_stdout->append($stdout);
             $log_stderr->append($stderr);
             $future->discardBuffers();
             break;
         }
     }
     $log_stdout->finalize($start_stdout);
     $log_stderr->finalize($start_stderr);
     if ($err) {
         throw new HarbormasterBuildFailureException();
     }
 }
 private function executeBuildCommand(HarbormasterBuild $build, HarbormasterBuildTransaction $xaction)
 {
     $command = $xaction->getNewValue();
     switch ($command) {
         case HarbormasterBuildCommand::COMMAND_RESTART:
             $issuable = $build->canRestartBuild();
             break;
         case HarbormasterBuildCommand::COMMAND_PAUSE:
             $issuable = $build->canPauseBuild();
             break;
         case HarbormasterBuildCommand::COMMAND_RESUME:
             $issuable = $build->canResumeBuild();
             break;
         case HarbormasterBuildCommand::COMMAND_ABORT:
             $issuable = $build->canAbortBuild();
             break;
         default:
             throw new Exception(pht('Unknown command %s', $command));
     }
     if (!$issuable) {
         return;
     }
     $actor = $this->getActor();
     if (!$build->canIssueCommand($actor, $command)) {
         return;
     }
     id(new HarbormasterBuildCommand())->setAuthorPHID($xaction->getAuthorPHID())->setTargetPHID($build->getPHID())->setCommand($command)->save();
     PhabricatorWorker::scheduleTask('HarbormasterBuildWorker', array('buildID' => $build->getID()), array('objectPHID' => $build->getPHID()));
 }
 public function execute(HarbormasterBuild $build, HarbormasterBuildTarget $build_target)
 {
     $settings = $this->getSettings();
     // Create the lease.
     $lease = id(new DrydockLease())->setResourceType('host')->setAttributes(array('platform' => $settings['platform']))->queueForActivation();
     // Wait until the lease is fulfilled.
     // TODO: This will throw an exception if the lease can't be fulfilled;
     // we should treat that as build failure not build error.
     $lease->waitUntilActive();
     // Create the associated artifact.
     $artifact = $build->createArtifact($build_target, $settings['name'], HarbormasterBuildArtifact::TYPE_HOST);
     $artifact->setArtifactData(array('drydock-lease' => $lease->getID()));
     $artifact->save();
 }
 public function execute(HarbormasterBuild $build, HarbormasterBuildTarget $build_target)
 {
     $settings = $this->getSettings();
     $variables = $build_target->getVariables();
     $path = $this->mergeVariables('vsprintf', $settings['path'], $variables);
     $artifact = $build->loadArtifact($settings['hostartifact']);
     $lease = $artifact->loadDrydockLease();
     $interface = $lease->getInterface('filesystem');
     // TODO: Handle exceptions.
     $file = $interface->saveFile($path, $settings['name']);
     // Insert the artifact record.
     $artifact = $build->createArtifact($build_target, $settings['name'], HarbormasterBuildArtifact::TYPE_FILE);
     $artifact->setArtifactData(array('filePHID' => $file->getPHID()));
     $artifact->save();
 }
 public function execute(HarbormasterBuild $build, HarbormasterBuildTarget $build_target)
 {
     // We can only wait when building against commits.
     $buildable = $build->getBuildable();
     $object = $buildable->getBuildableObject();
     if (!$object instanceof PhabricatorRepositoryCommit) {
         return;
     }
     // Block until all previous builds of the same build plan have
     // finished.
     $plan = $build->getBuildPlan();
     $blockers = $this->getBlockers($object, $plan, $build);
     if ($blockers) {
         throw new PhabricatorWorkerYieldException(15);
     }
 }
 public function execute(HarbormasterBuild $build, HarbormasterBuildTarget $build_target)
 {
     $settings = $this->getSettings();
     $variables = $build_target->getVariables();
     $path = $this->mergeVariables('vsprintf', $settings['path'], $variables);
     $artifact = $build->loadArtifact($settings['artifact']);
     $file = $artifact->loadPhabricatorFile();
     $fragment = id(new PhragmentFragmentQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withPaths(array($path))->executeOne();
     if ($fragment === null) {
         PhragmentFragment::createFromFile(PhabricatorUser::getOmnipotentUser(), $file, $path, PhabricatorPolicies::getMostOpenPolicy(), PhabricatorPolicies::POLICY_USER);
     } else {
         if ($file->getMimeType() === 'application/zip') {
             $fragment->updateFromZIP(PhabricatorUser::getOmnipotentUser(), $file);
         } else {
             $fragment->updateFromFile(PhabricatorUser::getOmnipotentUser(), $file);
         }
     }
 }
 private function handlePropertyEvent($ui_event)
 {
     $user = $ui_event->getUser();
     $object = $ui_event->getValue('object');
     if (!$object || !$object->getPHID()) {
         // No object, or the object has no PHID yet..
         return;
     }
     if ($object instanceof HarbormasterBuildable) {
         // Although HarbormasterBuildable implements the correct interface, it
         // does not make sense to show a build's build status. In the best case
         // it is meaningless, and in the worst case it's confusing.
         return;
     }
     if ($object instanceof DifferentialRevision) {
         // TODO: This is a bit hacky and we could probably find a cleaner fix
         // eventually, but we show build status on each diff, immediately below
         // this property list, so it's redundant to show it on the revision view.
         return;
     }
     if (!$object instanceof HarbormasterBuildableInterface) {
         return;
     }
     $buildable_phid = $object->getHarbormasterBuildablePHID();
     if (!$buildable_phid) {
         return;
     }
     if (!$this->canUseApplication($ui_event->getUser())) {
         return;
     }
     $buildable = id(new HarbormasterBuildableQuery())->setViewer($user)->withManualBuildables(false)->withBuildablePHIDs(array($buildable_phid))->needBuilds(true)->executeOne();
     if (!$buildable) {
         return;
     }
     $builds = $buildable->getBuilds();
     $build_handles = id(new PhabricatorHandleQuery())->setViewer($user)->withPHIDs(mpull($builds, 'getPHID'))->execute();
     $status_view = new PHUIStatusListView();
     $buildable_status = $buildable->getBuildableStatus();
     $buildable_icon = HarbormasterBuildable::getBuildableStatusIcon($buildable_status);
     $buildable_color = HarbormasterBuildable::getBuildableStatusColor($buildable_status);
     $buildable_name = HarbormasterBuildable::getBuildableStatusName($buildable_status);
     $target = phutil_tag('a', array('href' => '/' . $buildable->getMonogram()), pht('Buildable %d', $buildable->getID()));
     $target = phutil_tag('strong', array(), $target);
     $status_view->addItem(id(new PHUIStatusItemView())->setIcon($buildable_icon, $buildable_color, $buildable_name)->setTarget($target));
     foreach ($builds as $build) {
         $item = new PHUIStatusItemView();
         $item->setTarget($build_handles[$build->getPHID()]->renderLink());
         $status = $build->getBuildStatus();
         $status_name = HarbormasterBuild::getBuildStatusName($status);
         $icon = HarbormasterBuild::getBuildStatusIcon($status);
         $color = HarbormasterBuild::getBuildStatusColor($status);
         $item->setIcon($icon, $color, $status_name);
         $status_view->addItem($item);
     }
     $view = $ui_event->getValue('view');
     $view->addProperty(pht('Build Status'), $status_view);
 }
 public function execute(HarbormasterBuild $build, HarbormasterBuildTarget $build_target)
 {
     $settings = $this->getSettings();
     $target = time() + $settings['seconds'];
     // Use $build_update so that we only reload every 5 seconds, but
     // the sleep mechanism remains accurate.
     $build_update = 5;
     while (time() < $target) {
         sleep(1);
         if ($build_update <= 0) {
             $build->reload();
             $build_update = 5;
             if ($this->shouldAbort($build, $build_target)) {
                 throw new HarbormasterBuildAbortedException();
             }
         } else {
             $build_update -= 1;
         }
     }
 }
 private function buildBuildList(HarbormasterBuildable $buildable)
 {
     $viewer = $this->getRequest()->getUser();
     $build_list = id(new PHUIObjectItemListView())->setUser($viewer);
     foreach ($buildable->getBuilds() as $build) {
         $view_uri = $this->getApplicationURI('/build/' . $build->getID() . '/');
         $item = id(new PHUIObjectItemView())->setObjectName(pht('Build %d', $build->getID()))->setHeader($build->getName())->setHref($view_uri);
         $status = $build->getBuildStatus();
         $item->setStatusIcon('fa-dot-circle-o ' . HarbormasterBuild::getBuildStatusColor($status), HarbormasterBuild::getBuildStatusName($status));
         $item->addAttribute(HarbormasterBuild::getBuildStatusName($status));
         if ($build->isRestarting()) {
             $item->addIcon('fa-repeat', pht('Restarting'));
         } else {
             if ($build->isPausing()) {
                 $item->addIcon('fa-pause', pht('Pausing'));
             } else {
                 if ($build->isResuming()) {
                     $item->addIcon('fa-play', pht('Resuming'));
                 }
             }
         }
         $build_id = $build->getID();
         $restart_uri = "build/restart/{$build_id}/buildable/";
         $resume_uri = "build/resume/{$build_id}/buildable/";
         $pause_uri = "build/pause/{$build_id}/buildable/";
         $abort_uri = "build/abort/{$build_id}/buildable/";
         $item->addAction(id(new PHUIListItemView())->setIcon('fa-repeat')->setName(pht('Restart'))->setHref($this->getApplicationURI($restart_uri))->setWorkflow(true)->setDisabled(!$build->canRestartBuild()));
         if ($build->canResumeBuild()) {
             $item->addAction(id(new PHUIListItemView())->setIcon('fa-play')->setName(pht('Resume'))->setHref($this->getApplicationURI($resume_uri))->setWorkflow(true));
         } else {
             $item->addAction(id(new PHUIListItemView())->setIcon('fa-pause')->setName(pht('Pause'))->setHref($this->getApplicationURI($pause_uri))->setWorkflow(true)->setDisabled(!$build->canPauseBuild()));
         }
         $targets = $build->getBuildTargets();
         if ($targets) {
             $target_list = id(new PHUIStatusListView());
             foreach ($targets as $target) {
                 $status = $target->getTargetStatus();
                 $icon = HarbormasterBuildTarget::getBuildTargetStatusIcon($status);
                 $color = HarbormasterBuildTarget::getBuildTargetStatusColor($status);
                 $status_name = HarbormasterBuildTarget::getBuildTargetStatusName($status);
                 $name = $target->getName();
                 $target_list->addItem(id(new PHUIStatusItemView())->setIcon($icon, $color, $status_name)->setTarget(pht('Target %d', $target->getID()))->setNote($name));
             }
             $target_box = id(new PHUIBoxView())->addPadding(PHUI::PADDING_SMALL)->appendChild($target_list);
             $item->appendChild($target_box);
         }
         $build_list->addItem($item);
     }
     $build_list->setFlush(true);
     $box = id(new PHUIObjectBoxView())->setHeaderText(pht('Builds'))->appendChild($build_list);
     return $box;
 }
 public function execute(HarbormasterBuild $build, HarbormasterBuildTarget $build_target)
 {
     $viewer = PhabricatorUser::getOmnipotentUser();
     $settings = $this->getSettings();
     $variables = $build_target->getVariables();
     $uri = $this->mergeVariables('vurisprintf', $settings['uri'], $variables);
     $log_body = $build->createLog($build_target, $uri, 'http-body');
     $start = $log_body->start();
     $method = nonempty(idx($settings, 'method'), 'POST');
     $future = id(new HTTPSFuture($uri))->setMethod($method)->setTimeout(60);
     $credential_phid = $this->getSetting('credential');
     if ($credential_phid) {
         $key = PassphrasePasswordKey::loadFromPHID($credential_phid, $viewer);
         $future->setHTTPBasicAuthCredentials($key->getUsernameEnvelope()->openEnvelope(), $key->getPasswordEnvelope());
     }
     list($status, $body, $headers) = $this->resolveFuture($build, $build_target, $future);
     $log_body->append($body);
     $log_body->finalize($start);
     if ($status->getStatusCode() != 200) {
         $build->setBuildStatus(HarbormasterBuild::STATUS_FAILED);
     }
 }
 private function handlePropertyEvent($ui_event)
 {
     $user = $ui_event->getUser();
     $object = $ui_event->getValue('object');
     if (!$object || !$object->getPHID()) {
         // No object, or the object has no PHID yet..
         return;
     }
     if ($object instanceof HarbormasterBuildable) {
         // Although HarbormasterBuildable implements the correct interface, it
         // does not make sense to show a build's build status. In the best case
         // it is meaningless, and in the worst case it's confusing.
         return;
     }
     if (!$object instanceof HarbormasterBuildableInterface) {
         return;
     }
     $buildable_phid = $object->getHarbormasterBuildablePHID();
     if (!$buildable_phid) {
         return;
     }
     if (!$this->canUseApplication($ui_event->getUser())) {
         return;
     }
     $buildables = id(new HarbormasterBuildableQuery())->setViewer($user)->withManualBuildables(false)->withBuildablePHIDs(array($buildable_phid))->execute();
     if (!$buildables) {
         return;
     }
     $builds = id(new HarbormasterBuildQuery())->setViewer($user)->withBuildablePHIDs(mpull($buildables, 'getPHID'))->execute();
     if (!$builds) {
         return;
     }
     $build_handles = id(new PhabricatorHandleQuery())->setViewer($user)->withPHIDs(mpull($builds, 'getPHID'))->execute();
     $status_view = new PHUIStatusListView();
     foreach ($builds as $build) {
         $item = new PHUIStatusItemView();
         $item->setTarget($build_handles[$build->getPHID()]->renderLink());
         $status = $build->getBuildStatus();
         $status_name = HarbormasterBuild::getBuildStatusName($status);
         $icon = HarbormasterBuild::getBuildStatusIcon($status);
         $color = HarbormasterBuild::getBuildStatusColor($status);
         $item->setIcon($icon, $color, $status_name);
         $status_view->addItem($item);
     }
     $view = $ui_event->getValue('view');
     $view->addProperty(pht('Build Status'), $status_view);
 }
 protected function execute(ConduitAPIRequest $request)
 {
     $viewer = $request->getUser();
     $query = id(new HarbormasterBuildQuery())->setViewer($viewer);
     $ids = $request->getValue('ids');
     if ($ids !== null) {
         $query->withIDs($ids);
     }
     $phids = $request->getValue('phids');
     if ($phids !== null) {
         $query->withPHIDs($phids);
     }
     $statuses = $request->getValue('buildStatuses');
     if ($statuses !== null) {
         $query->withBuildStatuses($statuses);
     }
     $buildable_phids = $request->getValue('buildablePHIDs');
     if ($buildable_phids !== null) {
         $query->withBuildablePHIDs($buildable_phids);
     }
     $build_plan_phids = $request->getValue('buildPlanPHIDs');
     if ($build_plan_phids !== null) {
         $query->withBuildPlanPHIDs($build_plan_phids);
     }
     $pager = $this->newPager($request);
     $builds = $query->executeWithCursorPager($pager);
     $data = array();
     foreach ($builds as $build) {
         $id = $build->getID();
         $uri = '/harbormaster/build/' . $id . '/';
         $status = $build->getBuildStatus();
         $data[] = array('id' => $id, 'phid' => $build->getPHID(), 'uri' => PhabricatorEnv::getProductionURI($uri), 'name' => $build->getBuildPlan()->getName(), 'buildablePHID' => $build->getBuildablePHID(), 'buildPlanPHID' => $build->getBuildPlanPHID(), 'buildStatus' => $status, 'buildStatusName' => HarbormasterBuild::getBuildStatusName($status));
     }
     $results = array('data' => $data);
     $results = $this->addPagerResults($results, $pager);
     return $results;
 }
 private function executeBuildCommand(HarbormasterBuild $build, HarbormasterBuildTransaction $xaction)
 {
     $command = $xaction->getNewValue();
     switch ($command) {
         case HarbormasterBuildCommand::COMMAND_RESTART:
             $issuable = $build->canRestartBuild();
             break;
         case HarbormasterBuildCommand::COMMAND_STOP:
             $issuable = $build->canStopBuild();
             break;
         case HarbormasterBuildCommand::COMMAND_RESUME:
             $issuable = $build->canResumeBuild();
             break;
         default:
             throw new Exception("Unknown command {$command}");
     }
     if (!$issuable) {
         return;
     }
     id(new HarbormasterBuildCommand())->setAuthorPHID($xaction->getAuthorPHID())->setTargetPHID($build->getPHID())->setCommand($command)->save();
     PhabricatorWorker::scheduleTask('HarbormasterBuildWorker', array('buildID' => $build->getID()));
 }
 protected function resolveFutures(HarbormasterBuild $build, HarbormasterBuildTarget $target, array $futures)
 {
     $futures = new FutureIterator($futures);
     foreach ($futures->setUpdateInterval(5) as $key => $future) {
         if ($future === null) {
             $build->reload();
             if ($this->shouldAbort($build, $target)) {
                 throw new HarbormasterBuildAbortedException();
             }
         }
     }
 }
Esempio n. 18
0
 public function applyPlan(HarbormasterBuildPlan $plan)
 {
     $viewer = PhabricatorUser::getOmnipotentUser();
     $build = HarbormasterBuild::initializeNewBuild($viewer)->setBuildablePHID($this->getPHID())->setBuildPlanPHID($plan->getPHID())->setBuildStatus(HarbormasterBuild::STATUS_PENDING)->save();
     PhabricatorWorker::scheduleTask('HarbormasterBuildWorker', array('buildID' => $build->getID()));
     return $build;
 }
 public function applyPlan(HarbormasterBuildPlan $plan, array $parameters, $initiator_phid)
 {
     $viewer = PhabricatorUser::getOmnipotentUser();
     $build = HarbormasterBuild::initializeNewBuild($viewer)->setBuildablePHID($this->getPHID())->setBuildPlanPHID($plan->getPHID())->setBuildParameters($parameters)->setBuildStatus(HarbormasterBuildStatus::STATUS_PENDING);
     if ($initiator_phid) {
         $build->setInitiatorPHID($initiator_phid);
     }
     $auto_key = $plan->getPlanAutoKey();
     if ($auto_key) {
         $build->setPlanAutoKey($auto_key);
     }
     $build->save();
     PhabricatorWorker::scheduleTask('HarbormasterBuildWorker', array('buildID' => $build->getID()), array('objectPHID' => $build->getPHID()));
     return $build;
 }
 private function releaseAllArtifacts(HarbormasterBuild $build)
 {
     $targets = id(new HarbormasterBuildTargetQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withBuildPHIDs(array($build->getPHID()))->withBuildGenerations(array($build->getBuildGeneration()))->execute();
     if (count($targets) === 0) {
         return;
     }
     $target_phids = mpull($targets, 'getPHID');
     $artifacts = id(new HarbormasterBuildArtifactQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withBuildTargetPHIDs($target_phids)->execute();
     foreach ($artifacts as $artifact) {
         $artifact->releaseArtifact();
     }
 }
 public static function initializeNewBuildTarget(HarbormasterBuild $build, HarbormasterBuildStep $build_step, array $variables)
 {
     return id(new HarbormasterBuildTarget())->setName($build_step->getName())->setBuildPHID($build->getPHID())->setBuildStepPHID($build_step->getPHID())->setClassName($build_step->getClassName())->setDetails($build_step->getDetails())->setTargetStatus(self::STATUS_PENDING)->setVariables($variables)->setBuildGeneration($build->getBuildGeneration());
 }
 private function renderBuildVariablesTable()
 {
     $viewer = $this->getRequest()->getUser();
     $variables = HarbormasterBuild::getAvailableBuildVariables();
     ksort($variables);
     $rows = array();
     $rows[] = pht('The following variables can be used in most fields. To reference ' . 'a variable, use `${name}` in a field.');
     $rows[] = pht('| Variable | Description |');
     $rows[] = '|---|---|';
     foreach ($variables as $name => $description) {
         $rows[] = '| `' . $name . '` | ' . $description . ' |';
     }
     $rows = implode("\n", $rows);
     $form = id(new AphrontFormView())->setUser($viewer)->appendRemarkupInstructions($rows);
     return id(new PHUIObjectBoxView())->setHeaderText(pht('Build Variables'))->appendChild($form);
 }
 private function loadHistoryDiffStatus(array $diffs)
 {
     assert_instances_of($diffs, 'DifferentialDiff');
     $diff_phids = mpull($diffs, 'getPHID');
     $bad_unit_status = array(ArcanistUnitTestResult::RESULT_FAIL, ArcanistUnitTestResult::RESULT_BROKEN);
     $message = new HarbormasterBuildUnitMessage();
     $target = new HarbormasterBuildTarget();
     $build = new HarbormasterBuild();
     $buildable = new HarbormasterBuildable();
     $broken_diffs = queryfx_all($message->establishConnection('r'), 'SELECT distinct a.buildablePHID
     FROM %T m
       JOIN %T t ON m.buildTargetPHID = t.phid
       JOIN %T b ON t.buildPHID = b.phid
       JOIN %T a ON b.buildablePHID = a.phid
     WHERE a.buildablePHID IN (%Ls)
       AND m.result in (%Ls)', $message->getTableName(), $target->getTableName(), $build->getTableName(), $buildable->getTableName(), $diff_phids, $bad_unit_status);
     $unit_status = array();
     foreach ($broken_diffs as $broken) {
         $phid = $broken['buildablePHID'];
         $unit_status[$phid] = DifferentialUnitStatus::UNIT_FAIL;
     }
     return $unit_status;
 }
 private function getStatus(HarbormasterBuild $build)
 {
     $status_view = new PHUIStatusListView();
     $item = new PHUIStatusItemView();
     if ($build->isStopping()) {
         $status_name = pht('Pausing');
         $icon = PHUIStatusItemView::ICON_RIGHT;
         $color = 'dark';
     } else {
         $status = $build->getBuildStatus();
         $status_name = HarbormasterBuild::getBuildStatusName($status);
         $icon = HarbormasterBuild::getBuildStatusIcon($status);
         $color = HarbormasterBuild::getBuildStatusColor($status);
     }
     $item->setTarget($status_name);
     $item->setIcon($icon, $color);
     $status_view->addItem($item);
     return $status_view;
 }
 protected function resolveFuture(HarbormasterBuild $build, HarbormasterBuildTarget $target, Future $future)
 {
     $futures = Futures(array($future));
     foreach ($futures->setUpdateInterval(5) as $key => $future) {
         if ($future === null) {
             $build->reload();
             if ($this->shouldAbort($build, $target)) {
                 throw new HarbormasterBuildAbortedException();
             }
         } else {
             return $future->resolve();
         }
     }
 }
 public function execute(HarbormasterBuild $build, HarbormasterBuildTarget $build_target)
 {
     $viewer = PhabricatorUser::getOmnipotentUser();
     $buildable = $build->getBuildable();
     $object = $buildable->getBuildableObject();
     $object_phid = $object->getPHID();
     if (!$object instanceof HarbormasterCircleCIBuildableInterface) {
         throw new Exception(pht('Object ("%s") does not implement interface "%s". Only objects ' . 'which implement this interface can be built with CircleCI.', $object_phid, 'HarbormasterCircleCIBuildableInterface'));
     }
     $github_uri = $object->getCircleCIGitHubRepositoryURI();
     $build_type = $object->getCircleCIBuildIdentifierType();
     $build_identifier = $object->getCircleCIBuildIdentifier();
     $path = self::getGitHubPath($github_uri);
     if ($path === null) {
         throw new Exception(pht('Object ("%s") claims "%s" is a GitHub repository URI, but the ' . 'domain does not appear to be GitHub.', $object_phid, $github_uri));
     }
     $path_parts = trim($path, '/');
     $path_parts = explode('/', $path_parts);
     if (count($path_parts) < 2) {
         throw new Exception(pht('Object ("%s") claims "%s" is a GitHub repository URI, but the ' . 'path ("%s") does not have enough components (expected at least ' . 'two).', $object_phid, $github_uri, $path));
     }
     list($github_namespace, $github_name) = $path_parts;
     $github_name = preg_replace('(\\.git$)', '', $github_name);
     $credential_phid = $this->getSetting('token');
     $api_token = id(new PassphraseCredentialQuery())->setViewer($viewer)->withPHIDs(array($credential_phid))->needSecrets(true)->executeOne();
     if (!$api_token) {
         throw new Exception(pht('Unable to load API token ("%s")!', $credential_phid));
     }
     // When we pass "revision", the branch is ignored (and does not even need
     // to exist), and only shows up in the UI. Use a cute string which will
     // certainly never break anything or cause any kind of problem.
     $ship = "🚢";
     $branch = "{$ship}Harbormaster";
     $token = $api_token->getSecret()->openEnvelope();
     $parts = array('https://circleci.com/api/v1/project', phutil_escape_uri($github_namespace), phutil_escape_uri($github_name) . "?circle-token={$token}");
     $uri = implode('/', $parts);
     $data_structure = array();
     switch ($build_type) {
         case 'tag':
             $data_structure['tag'] = $build_identifier;
             break;
         case 'revision':
             $data_structure['revision'] = $build_identifier;
             break;
         default:
             throw new Exception(pht('Unknown CircleCI build type "%s". Expected "%s" or "%s".', $build_type, 'tag', 'revision'));
     }
     $data_structure['build_parameters'] = array('HARBORMASTER_BUILD_TARGET_PHID' => $build_target->getPHID());
     $json_data = phutil_json_encode($data_structure);
     $future = id(new HTTPSFuture($uri, $json_data))->setMethod('POST')->addHeader('Content-Type', 'application/json')->addHeader('Accept', 'application/json')->setTimeout(60);
     $this->resolveFutures($build, $build_target, array($future));
     $this->logHTTPResponse($build, $build_target, $future, pht('CircleCI'));
     list($status, $body) = $future->resolve();
     if ($status->isError()) {
         throw new HarbormasterBuildFailureException();
     }
     $response = phutil_json_decode($body);
     $build_uri = idx($response, 'build_url');
     if (!$build_uri) {
         throw new Exception(pht('CircleCI did not return a "%s"!', 'build_url'));
     }
     $target_phid = $build_target->getPHID();
     // Write an artifact to create a link to the external build in CircleCI.
     $api_method = 'harbormaster.createartifact';
     $api_params = array('buildTargetPHID' => $target_phid, 'artifactType' => HarbormasterURIArtifact::ARTIFACTCONST, 'artifactKey' => 'circleci.uri', 'artifactData' => array('uri' => $build_uri, 'name' => pht('View in CircleCI'), 'ui.external' => true));
     id(new ConduitCall($api_method, $api_params))->setUser($viewer)->execute();
 }