diff --git a/src/applications/harbormaster/controller/HarbormasterBuildableViewController.php b/src/applications/harbormaster/controller/HarbormasterBuildableViewController.php index 91fb45176f..42f2572266 100644 --- a/src/applications/harbormaster/controller/HarbormasterBuildableViewController.php +++ b/src/applications/harbormaster/controller/HarbormasterBuildableViewController.php @@ -1,366 +1,367 @@ getViewer(); $buildable = id(new HarbormasterBuildableQuery()) ->setViewer($viewer) ->withIDs(array($request->getURIData('id'))) - ->needBuildableHandles(true) - ->needContainerHandles(true) ->executeOne(); if (!$buildable) { return new Aphront404Response(); } $id = $buildable->getID(); // Pull builds and build targets. $builds = id(new HarbormasterBuildQuery()) ->setViewer($viewer) ->withBuildablePHIDs(array($buildable->getPHID())) ->needBuildTargets(true) ->execute(); list($lint, $unit) = $this->renderLintAndUnit($buildable, $builds); $buildable->attachBuilds($builds); $object = $buildable->getBuildableObject(); $build_list = $this->buildBuildList($buildable); $title = pht('Buildable %d', $id); $header = id(new PHUIHeaderView()) ->setHeader($title) ->setUser($viewer) ->setPolicyObject($buildable); $box = id(new PHUIObjectBoxView()) ->setHeader($header); $timeline = $this->buildTransactionTimeline( $buildable, new HarbormasterBuildableTransactionQuery()); $timeline->setShouldTerminate(true); $actions = $this->buildActionList($buildable); $this->buildPropertyLists($box, $buildable, $actions); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb($buildable->getMonogram()); return $this->buildApplicationPage( array( $crumbs, $box, $lint, $unit, $build_list, $timeline, ), array( 'title' => $title, )); } private function buildActionList(HarbormasterBuildable $buildable) { $request = $this->getRequest(); $viewer = $request->getUser(); $id = $buildable->getID(); $list = id(new PhabricatorActionListView()) ->setUser($viewer) ->setObject($buildable); $can_edit = PhabricatorPolicyFilter::hasCapability( $viewer, $buildable, PhabricatorPolicyCapability::CAN_EDIT); $can_restart = false; $can_resume = false; $can_pause = false; $can_abort = false; $command_restart = HarbormasterBuildCommand::COMMAND_RESTART; $command_resume = HarbormasterBuildCommand::COMMAND_RESUME; $command_pause = HarbormasterBuildCommand::COMMAND_PAUSE; $command_abort = HarbormasterBuildCommand::COMMAND_ABORT; foreach ($buildable->getBuilds() as $build) { if ($build->canRestartBuild()) { if ($build->canIssueCommand($viewer, $command_restart)) { $can_restart = true; } } if ($build->canResumeBuild()) { if ($build->canIssueCommand($viewer, $command_resume)) { $can_resume = true; } } if ($build->canPauseBuild()) { if ($build->canIssueCommand($viewer, $command_pause)) { $can_pause = true; } } if ($build->canAbortBuild()) { if ($build->canIssueCommand($viewer, $command_abort)) { $can_abort = true; } } } $restart_uri = "buildable/{$id}/restart/"; $pause_uri = "buildable/{$id}/pause/"; $resume_uri = "buildable/{$id}/resume/"; $abort_uri = "buildable/{$id}/abort/"; $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($pause_uri)) ->setWorkflow(true) ->setDisabled(!$can_pause || !$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)); $list->addAction( id(new PhabricatorActionView()) ->setIcon('fa-exclamation-triangle') ->setName(pht('Abort All Builds')) ->setHref($this->getApplicationURI($abort_uri)) ->setWorkflow(true) ->setDisabled(!$can_abort || !$can_edit)); return $list; } private function buildPropertyLists( PHUIObjectBoxView $box, HarbormasterBuildable $buildable, PhabricatorActionListView $actions) { $request = $this->getRequest(); $viewer = $request->getUser(); $properties = id(new PHUIPropertyListView()) ->setUser($viewer) ->setObject($buildable) ->setActionList($actions); $box->addPropertyList($properties); - if ($buildable->getContainerHandle() !== null) { + $container_phid = $buildable->getContainerPHID(); + $buildable_phid = $buildable->getBuildablePHID(); + + if ($container_phid) { $properties->addProperty( pht('Container'), - $buildable->getContainerHandle()->renderLink()); + $viewer->renderHandle($container_phid)); } $properties->addProperty( pht('Buildable'), - $buildable->getBuildableHandle()->renderLink()); + $viewer->renderHandle($buildable_phid)); $properties->addProperty( pht('Origin'), $buildable->getIsManualBuildable() ? pht('Manual Buildable') : pht('Automatic Buildable')); } 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; } 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) ->setIcon('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) ->setIcon('fa-list-ul') ->setText('View All')); $unit = id(new PHUIObjectBoxView()) ->setHeader($unit_header) ->setTable($unit_table); } else { $unit = null; } return array($lint, $unit); } } diff --git a/src/applications/harbormaster/interface/HarbormasterBuildableInterface.php b/src/applications/harbormaster/interface/HarbormasterBuildableInterface.php index a5517a6b2b..d2b2d332aa 100644 --- a/src/applications/harbormaster/interface/HarbormasterBuildableInterface.php +++ b/src/applications/harbormaster/interface/HarbormasterBuildableInterface.php @@ -1,12 +1,11 @@ withPHIDs($phids) - ->needBuildableHandles(true); + ->withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { + $viewer = $this->getViewer(); + + $target_phids = array(); + foreach ($objects as $phid => $object) { + $target_phids[] = $object->getBuildablePHID(); + } + $target_handles = $viewer->loadHandles($target_phids); + foreach ($handles as $phid => $handle) { $buildable = $objects[$phid]; $id = $buildable->getID(); - $target = $buildable->getBuildableHandle()->getFullName(); + $buildable_phid = $buildable->getBuildablePHID(); + + $target = $target_handles[$buildable_phid]; + $target_name = $target->getFullName(); + + $uri = $buildable->getURI(); + $monogram = $buildable->getMonogram(); - $handle->setURI("/B{$id}"); - $handle->setName("B{$id}"); - $handle->setFullName("B{$id}: ".$target); + $handle + ->setURI($uri) + ->setName($monogram) + ->setFullName("{$monogram}: {$target_name}"); } } public function canLoadNamedObject($name) { return preg_match('/^B\d*[1-9]\d*$/i', $name); } public function loadNamedObjects( PhabricatorObjectQuery $query, array $names) { $id_map = array(); foreach ($names as $name) { $id = (int)substr($name, 1); $id_map[$id][] = $name; } $objects = id(new HarbormasterBuildableQuery()) ->setViewer($query->getViewer()) ->withIDs(array_keys($id_map)) ->execute(); $results = array(); foreach ($objects as $id => $object) { foreach (idx($id_map, $id, array()) as $name) { $results[$name] = $object; } } return $results; } } diff --git a/src/applications/harbormaster/query/HarbormasterBuildableQuery.php b/src/applications/harbormaster/query/HarbormasterBuildableQuery.php index 2986bb45b7..fc069bd031 100644 --- a/src/applications/harbormaster/query/HarbormasterBuildableQuery.php +++ b/src/applications/harbormaster/query/HarbormasterBuildableQuery.php @@ -1,220 +1,171 @@ ids = $ids; return $this; } public function withPHIDs(array $phids) { $this->phids = $phids; return $this; } public function withBuildablePHIDs(array $buildable_phids) { $this->buildablePHIDs = $buildable_phids; return $this; } public function withContainerPHIDs(array $container_phids) { $this->containerPHIDs = $container_phids; return $this; } public function withManualBuildables($manual) { $this->manualBuildables = $manual; return $this; } public function needContainerObjects($need) { $this->needContainerObjects = $need; return $this; } - public function needContainerHandles($need) { - $this->needContainerHandles = $need; - return $this; - } - - public function needBuildableHandles($need) { - $this->needBuildableHandles = $need; - return $this; - } - public function needBuilds($need) { $this->needBuilds = $need; return $this; } public function needTargets($need) { $this->needTargets = $need; return $this; } public function newResultObject() { return new HarbormasterBuildable(); } protected function loadPage() { return $this->loadStandardPage($this->newResultObject()); } protected function willFilterPage(array $page) { $buildables = array(); $buildable_phids = array_filter(mpull($page, 'getBuildablePHID')); if ($buildable_phids) { $buildables = id(new PhabricatorObjectQuery()) ->setViewer($this->getViewer()) ->withPHIDs($buildable_phids) ->setParentQuery($this) ->execute(); $buildables = mpull($buildables, null, 'getPHID'); } foreach ($page as $key => $buildable) { $buildable_phid = $buildable->getBuildablePHID(); if (empty($buildables[$buildable_phid])) { unset($page[$key]); continue; } $buildable->attachBuildableObject($buildables[$buildable_phid]); } return $page; } protected function didFilterPage(array $page) { - if ($this->needContainerObjects || $this->needContainerHandles) { + if ($this->needContainerObjects) { $container_phids = array_filter(mpull($page, 'getContainerPHID')); - if ($this->needContainerObjects) { - $containers = array(); - - if ($container_phids) { - $containers = id(new PhabricatorObjectQuery()) - ->setViewer($this->getViewer()) - ->withPHIDs($container_phids) - ->setParentQuery($this) - ->execute(); - $containers = mpull($containers, null, 'getPHID'); - } - - foreach ($page as $key => $buildable) { - $container_phid = $buildable->getContainerPHID(); - $buildable->attachContainerObject(idx($containers, $container_phid)); - } - } - - if ($this->needContainerHandles) { - $handles = array(); - - if ($container_phids) { - $handles = id(new PhabricatorHandleQuery()) - ->setViewer($this->getViewer()) - ->withPHIDs($container_phids) - ->setParentQuery($this) - ->execute(); - } - - foreach ($page as $key => $buildable) { - $container_phid = $buildable->getContainerPHID(); - $buildable->attachContainerHandle(idx($handles, $container_phid)); - } - } - } - - if ($this->needBuildableHandles) { - $handles = array(); - - $handle_phids = array_filter(mpull($page, 'getBuildablePHID')); - if ($handle_phids) { - $handles = id(new PhabricatorHandleQuery()) + if ($container_phids) { + $containers = id(new PhabricatorObjectQuery()) ->setViewer($this->getViewer()) - ->withPHIDs($handle_phids) + ->withPHIDs($container_phids) ->setParentQuery($this) ->execute(); + $containers = mpull($containers, null, 'getPHID'); + } else { + $containers = array(); } foreach ($page as $key => $buildable) { - $handle_phid = $buildable->getBuildablePHID(); - $buildable->attachBuildableHandle(idx($handles, $handle_phid)); + $container_phid = $buildable->getContainerPHID(); + $buildable->attachContainerObject(idx($containers, $container_phid)); } } if ($this->needBuilds || $this->needTargets) { $builds = id(new HarbormasterBuildQuery()) ->setViewer($this->getViewer()) ->setParentQuery($this) ->withBuildablePHIDs(mpull($page, 'getPHID')) ->needBuildTargets($this->needTargets) ->execute(); $builds = mgroup($builds, 'getBuildablePHID'); foreach ($page as $key => $buildable) { $buildable->attachBuilds(idx($builds, $buildable->getPHID(), array())); } } return $page; } protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); if ($this->ids !== null) { $where[] = qsprintf( $conn, 'id IN (%Ld)', $this->ids); } if ($this->phids !== null) { $where[] = qsprintf( $conn, 'phid IN (%Ls)', $this->phids); } if ($this->buildablePHIDs !== null) { $where[] = qsprintf( $conn, 'buildablePHID IN (%Ls)', $this->buildablePHIDs); } if ($this->containerPHIDs !== null) { $where[] = qsprintf( $conn, 'containerPHID in (%Ls)', $this->containerPHIDs); } if ($this->manualBuildables !== null) { $where[] = qsprintf( $conn, 'isManualBuildable = %d', (int)$this->manualBuildables); } return $where; } public function getQueryApplicationClass() { return 'PhabricatorHarbormasterApplication'; } } diff --git a/src/applications/harbormaster/query/HarbormasterBuildableSearchEngine.php b/src/applications/harbormaster/query/HarbormasterBuildableSearchEngine.php index 195a68a695..982db3dd39 100644 --- a/src/applications/harbormaster/query/HarbormasterBuildableSearchEngine.php +++ b/src/applications/harbormaster/query/HarbormasterBuildableSearchEngine.php @@ -1,226 +1,237 @@ readPHIDsFromRequest( $request, 'revisions', array( DifferentialRevisionPHIDType::TYPECONST, )); $repositories = $this->readPHIDsFromRequest( $request, 'repositories', array( PhabricatorRepositoryRepositoryPHIDType::TYPECONST, )); $container_phids = array_merge($revisions, $repositories); $saved->setParameter('containerPHIDs', $container_phids); $commits = $this->readPHIDsFromRequest( $request, 'commits', array( PhabricatorRepositoryCommitPHIDType::TYPECONST, )); $diffs = $this->readListFromRequest($request, 'diffs'); if ($diffs) { $diffs = id(new DifferentialDiffQuery()) ->setViewer($this->requireViewer()) ->withIDs($diffs) ->execute(); $diffs = mpull($diffs, 'getPHID', 'getPHID'); } $buildable_phids = array_merge($commits, $diffs); $saved->setParameter('buildablePHIDs', $buildable_phids); $saved->setParameter( 'manual', $this->readBoolFromRequest($request, 'manual')); return $saved; } public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) { - $query = id(new HarbormasterBuildableQuery()) - ->needContainerHandles(true) - ->needBuildableHandles(true); + $query = id(new HarbormasterBuildableQuery()); $container_phids = $saved->getParameter('containerPHIDs', array()); if ($container_phids) { $query->withContainerPHIDs($container_phids); } $buildable_phids = $saved->getParameter('buildablePHIDs', array()); if ($buildable_phids) { $query->withBuildablePHIDs($buildable_phids); } $manual = $saved->getParameter('manual'); if ($manual !== null) { $query->withManualBuildables($manual); } return $query; } public function buildSearchForm( AphrontFormView $form, PhabricatorSavedQuery $saved_query) { $container_phids = $saved_query->getParameter('containerPHIDs', array()); $buildable_phids = $saved_query->getParameter('buildablePHIDs', array()); $all_phids = array_merge($container_phids, $buildable_phids); $revision_names = array(); $diff_names = array(); $repository_names = array(); $commit_names = array(); if ($all_phids) { $objects = id(new PhabricatorObjectQuery()) ->setViewer($this->requireViewer()) ->withPHIDs($all_phids) ->execute(); foreach ($all_phids as $phid) { $object = idx($objects, $phid); if (!$object) { continue; } if ($object instanceof DifferentialRevision) { $revision_names[] = 'D'.$object->getID(); } else if ($object instanceof DifferentialDiff) { $diff_names[] = $object->getID(); } else if ($object instanceof PhabricatorRepository) { $repository_names[] = $object->getMonogram(); } else if ($object instanceof PhabricatorRepositoryCommit) { $repository = $object->getRepository(); $commit_names[] = $repository->formatCommitName( $object->getCommitIdentifier()); } } } $form ->appendChild( id(new AphrontFormTextControl()) ->setLabel(pht('Differential Revisions')) ->setName('revisions') ->setValue(implode(', ', $revision_names))) ->appendChild( id(new AphrontFormTextControl()) ->setLabel(pht('Differential Diffs')) ->setName('diffs') ->setValue(implode(', ', $diff_names))) ->appendChild( id(new AphrontFormTextControl()) ->setLabel(pht('Repositories')) ->setName('repositories') ->setValue(implode(', ', $repository_names))) ->appendChild( id(new AphrontFormTextControl()) ->setLabel(pht('Commits')) ->setName('commits') ->setValue(implode(', ', $commit_names))) ->appendChild( id(new AphrontFormSelectControl()) ->setLabel(pht('Origin')) ->setName('manual') ->setValue($this->getBoolFromQuery($saved_query, 'manual')) ->setOptions( array( '' => pht('(All Origins)'), 'true' => pht('Manual Buildables'), 'false' => pht('Automatic Buildables'), ))); } protected function getURI($path) { return '/harbormaster/'.$path; } protected function getBuiltinQueryNames() { return array( 'all' => pht('All Buildables'), ); } public function buildSavedQueryFromBuiltin($query_key) { $query = $this->newSavedQuery(); $query->setQueryKey($query_key); switch ($query_key) { case 'all': return $query; } return parent::buildSavedQueryFromBuiltin($query_key); } protected function renderResultList( array $buildables, PhabricatorSavedQuery $query, array $handles) { assert_instances_of($buildables, 'HarbormasterBuildable'); $viewer = $this->requireViewer(); + $phids = array(); + foreach ($buildables as $buildable) { + $phids[] = $buildable->getContainerPHID(); + $phids[] = $buildable->getBuildablePHID(); + } + $handles = $viewer->loadHandles($phids); + + $list = new PHUIObjectItemListView(); foreach ($buildables as $buildable) { $id = $buildable->getID(); + $container_phid = $buildable->getContainerPHID(); + $buildable_phid = $buildable->getBuildablePHID(); + $item = id(new PHUIObjectItemView()) ->setHeader(pht('Buildable %d', $buildable->getID())); - if ($buildable->getContainerHandle() !== null) { - $item->addAttribute($buildable->getContainerHandle()->getName()); - } - if ($buildable->getBuildableHandle() !== null) { - $item->addAttribute($buildable->getBuildableHandle()->getFullName()); + + if ($container_phid) { + $handle = $handles[$container_phid]; + $item->addAttribute($handle->getName()); } - if ($id) { - $item->setHref("/B{$id}"); + if ($buildable_phid) { + $handle = $handles[$buildable_phid]; + $item->addAttribute($handle->getFullName()); } + $item->setHref($buildable->getURI()); + if ($buildable->getIsManualBuildable()) { $item->addIcon('fa-wrench grey', pht('Manual')); } $item->setStatusIcon('fa-wrench '. HarbormasterBuildable::getBuildableStatusColor( $buildable->getBuildableStatus())); $item->addByline(HarbormasterBuildable::getBuildableStatusName( $buildable->getBuildableStatus())); $list->addItem($item); } $result = new PhabricatorApplicationSearchResultView(); $result->setObjectList($list); $result->setNoDataString(pht('No buildables found.')); return $result; } } diff --git a/src/applications/harbormaster/storage/HarbormasterBuildable.php b/src/applications/harbormaster/storage/HarbormasterBuildable.php index 6286072b42..7ee6981477 100644 --- a/src/applications/harbormaster/storage/HarbormasterBuildable.php +++ b/src/applications/harbormaster/storage/HarbormasterBuildable.php @@ -1,341 +1,325 @@ setIsManualBuildable(0) ->setBuildableStatus(self::STATUS_BUILDING); } public function getMonogram() { return 'B'.$this->getID(); } + public function getURI() { + return '/'.$this->getMonogram(); + } + /** * Returns an existing buildable for the object's PHID or creates a * new buildable implicitly if needed. */ public static function createOrLoadExisting( PhabricatorUser $actor, $buildable_object_phid, $container_object_phid) { $buildable = id(new HarbormasterBuildableQuery()) ->setViewer($actor) ->withBuildablePHIDs(array($buildable_object_phid)) ->withManualBuildables(false) ->setLimit(1) ->executeOne(); if ($buildable) { return $buildable; } $buildable = self::initializeNewBuildable($actor) ->setBuildablePHID($buildable_object_phid) ->setContainerPHID($container_object_phid); $buildable->save(); return $buildable; } /** * Start builds for a given buildable. * * @param phid PHID of the object to build. * @param phid Container PHID for the buildable. * @param list List of builds to perform. * @return void */ public static function applyBuildPlans( $phid, $container_phid, array $requests) { assert_instances_of($requests, 'HarbormasterBuildRequest'); if (!$requests) { return; } // Skip all of this logic if the Harbormaster application // isn't currently installed. $harbormaster_app = 'PhabricatorHarbormasterApplication'; if (!PhabricatorApplication::isClassInstalled($harbormaster_app)) { return; } $viewer = PhabricatorUser::getOmnipotentUser(); $buildable = self::createOrLoadExisting( $viewer, $phid, $container_phid); $plan_phids = mpull($requests, 'getBuildPlanPHID'); $plans = id(new HarbormasterBuildPlanQuery()) ->setViewer($viewer) ->withPHIDs($plan_phids) ->execute(); $plans = mpull($plans, null, 'getPHID'); foreach ($requests as $request) { $plan_phid = $request->getBuildPlanPHID(); $plan = idx($plans, $plan_phid); if (!$plan) { throw new Exception( pht( 'Failed to load build plan ("%s").', $plan_phid)); } if ($plan->isDisabled()) { // TODO: This should be communicated more clearly -- maybe we should // create the build but set the status to "disabled" or "derelict". continue; } $parameters = $request->getBuildParameters(); $buildable->applyPlan($plan, $parameters, $request->getInitiatorPHID()); } } 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(HarbormasterBuild::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; } protected function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, self::CONFIG_COLUMN_SCHEMA => array( 'containerPHID' => 'phid?', 'buildableStatus' => 'text32', 'isManualBuildable' => 'bool', ), self::CONFIG_KEY_SCHEMA => array( 'key_buildable' => array( 'columns' => array('buildablePHID'), ), 'key_container' => array( 'columns' => array('containerPHID'), ), 'key_manual' => array( 'columns' => array('isManualBuildable'), ), ), ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( HarbormasterBuildablePHIDType::TYPECONST); } public function attachBuildableObject($buildable_object) { $this->buildableObject = $buildable_object; return $this; } public function getBuildableObject() { return $this->assertAttached($this->buildableObject); } public function attachContainerObject($container_object) { $this->containerObject = $container_object; return $this; } public function getContainerObject() { return $this->assertAttached($this->containerObject); } - public function attachContainerHandle($container_handle) { - $this->containerHandle = $container_handle; - return $this; - } - - public function getContainerHandle() { - return $this->assertAttached($this->containerHandle); - } - - public function attachBuildableHandle($buildable_handle) { - $this->buildableHandle = $buildable_handle; - return $this; - } - - public function getBuildableHandle() { - return $this->assertAttached($this->buildableHandle); - } - public function attachBuilds(array $builds) { assert_instances_of($builds, 'HarbormasterBuild'); $this->builds = $builds; return $this; } public function getBuilds() { return $this->assertAttached($this->builds); } /* -( PhabricatorApplicationTransactionInterface )------------------------- */ public function getApplicationTransactionEditor() { return new HarbormasterBuildableTransactionEditor(); } public function getApplicationTransactionObject() { return $this; } public function getApplicationTransactionTemplate() { return new HarbormasterBuildableTransaction(); } public function willRenderTimeline( PhabricatorApplicationTransactionView $timeline, AphrontRequest $request) { return $timeline; } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, ); } public function getPolicy($capability) { return $this->getBuildableObject()->getPolicy($capability); } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { return $this->getBuildableObject()->hasAutomaticCapability( $capability, $viewer); } public function describeAutomaticCapability($capability) { return pht('A buildable inherits policies from the underlying object.'); } /* -( HarbormasterBuildableInterface )------------------------------------- */ public function getHarbormasterBuildablePHID() { // NOTE: This is essentially just for convenience, as it allows you create // a copy of a buildable by specifying `B123` without bothering to go // look up the underlying object. return $this->getBuildablePHID(); } public function getHarbormasterContainerPHID() { return $this->getContainerPHID(); } public function getBuildVariables() { return array(); } public function getAvailableBuildVariables() { return array(); } }