/** * Get a list of @{class:HarbormasterBuildTarget} objects for a list of * autotarget keys. * * If some targets or builds do not exist, they are created. * * @param HarbormasterBuildable A buildable. * @param map<string, object> Map of keys to steps. * @return map<string, object> Map of keys to targets. */ private function generateBuildTargetMap(HarbormasterBuildable $buildable, array $step_map) { $viewer = $this->getViewer(); $plan_map = mgroup($step_map, 'getBuildPlanPHID'); $builds = id(new HarbormasterBuildQuery())->setViewer($viewer)->withBuildablePHIDs(array($buildable->getPHID()))->withBuildPlanPHIDs(array_keys($plan_map))->needBuildTargets(true)->execute(); $autobuilds = array(); foreach ($builds as $build) { $plan_key = $build->getBuildPlan()->getPlanAutoKey(); $autobuilds[$plan_key] = $build; } $new_builds = array(); foreach ($plan_map as $plan_phid => $steps) { $plan = head($steps)->getBuildPlan(); $plan_key = $plan->getPlanAutoKey(); $build = idx($autobuilds, $plan_key); if ($build) { // We already have a build for this set of targets, so we don't need // to do any work. (It's possible the build is an older build that // doesn't have all of the right targets if new autotargets were // recently introduced, but we don't currently try to construct them.) continue; } // NOTE: Normally, `applyPlan()` does not actually generate targets. // We need to apply the plan in-process to perform target generation. // This is fine as long as autotargets are empty containers that don't // do any work, which they always should be. PhabricatorWorker::setRunAllTasksInProcess(true); try { // NOTE: We might race another process here to create the same build // with the same `planAutoKey`. The database will prevent this and // using autotargets only currently makes sense if you just created the // resource and "own" it, so we don't try to handle this, but may need // to be more careful here if use of autotargets expands. $build = $buildable->applyPlan($plan, array()); PhabricatorWorker::setRunAllTasksInProcess(false); } catch (Exception $ex) { PhabricatorWorker::setRunAllTasksInProcess(false); throw $ex; } $new_builds[] = $build; } if ($new_builds) { $all_targets = id(new HarbormasterBuildTargetQuery())->setViewer($viewer)->withBuildPHIDs(mpull($new_builds, 'getPHID'))->execute(); } else { $all_targets = array(); } foreach ($builds as $build) { foreach ($build->getBuildTargets() as $target) { $all_targets[] = $target; } } $target_map = array(); foreach ($all_targets as $target) { $target_key = $target->getImplementation()->getBuildStepAutotargetStepKey(); if (!$target_key) { continue; } $target_map[$target_key] = $target; } $target_map = array_select_keys($target_map, array_keys($step_map)); return $target_map; }