The harbormaster target logic is this:
try { $status_pending = HarbormasterBuildTarget::STATUS_PENDING; if ($target->getTargetStatus() == $status_pending) { $target->setTargetStatus(HarbormasterBuildTarget::STATUS_BUILDING); $target->save(); } $implementation = $target->getImplementation(); $implementation->execute($build, $target); $next_status = HarbormasterBuildTarget::STATUS_PASSED; if ($implementation->shouldWaitForMessage($target)) { $next_status = HarbormasterBuildTarget::STATUS_WAITING; } $target->setTargetStatus($next_status); $target->save(); } catch (PhabricatorWorkerYieldException $ex) { // If the target wants to yield, let that escape without further // processing. We'll resume after the task retries. throw $ex; } catch (Exception $ex) { phlog($ex); try { $log = $build->createLog($target, 'core', 'exception'); $start = $log->start(); $log->append((string)$ex); $log->finalize($start); } catch (Exception $log_ex) { phlog($log_ex); } $target->setTargetStatus(HarbormasterBuildTarget::STATUS_FAILED); $target->save(); }
Thus the only way to mark a target as failed is to throw an exception.
Marking the build as failed like this:
$build->setBuildStatus(HarbormasterBuild::STATUS_FAILED);
doesn't work either, because the Harbormaster build engine updates the build status based on the targets.