/** * Schedules a build * * @see App\CoreBundle\EventListener\BuildBranchRelationSubscriber for automatic creation of non-existing branches */ public function schedule(Project $project, $ref, $hash, PayloadInterface $payload = null, $options = []) { $logger = $this->logger; $logger->info('scheduling build', ['project' => $project->getId(), 'ref' => $ref, 'hash' => $hash]); $em = $this->doctrine->getManager(); // @todo I guess this should be in a build.scheduled event listener $alreadyRunningBuilds = $em->getRepository('Model:Build')->findPendingByRef($project, $ref); foreach ($alreadyRunningBuilds as $build) { // @todo instead of retrieving then updating builds to be canceled, directly issue an UPDATE // it should avoid most race conditions if ($build->isScheduled()) { $logger->info('canceling same ref build', ['ref' => $ref, 'canceled_build' => $build->getId()]); $build->setStatus(Build::STATUS_CANCELED); $em->persist($build); $em->flush(); } else { $logger->info('killing same ref build', ['ref' => $ref, 'canceled_build' => $build->getId()]); $scheduler->kill($build); } } $build = new Build(); $build->setProject($project); $build->setStatus(Build::STATUS_SCHEDULED); $build->setRef($ref); $build->setHash($hash); $build->setCommitUrl(sprintf('https://github.com/%s/commit/%s', $project->getFullName(), $hash)); if (null !== $payload) { $build->setIsPullRequest($payload->isPullRequest()); $build->setRawPayload($payload->getRawContent()); } else { $build->setIsPullRequest(false); } if (isset($options['force_local_build_yml']) && $options['force_local_build_yml']) { $build->setForceLocalBuildYml(true); } $builderHost = null; $logger->info('electing builder', ['builder_host_allow' => $this->getOption('builder_host_allow')]); if (count($builderHostAllow = $this->getOption('builder_host_allow')) > 0) { $builderHost = $builderHostAllow[array_rand($builderHostAllow)]; } $build->setBuilderHost($builderHost); /** * @todo move this outside, it belongs in a controller * this will allow to remove the $options argument */ $em->persist($build); $em->flush(); $this->logger->info('sending build order', ['build' => $build->getId(), 'builder_host' => $builderHost]); $this->buildProducer->publish(json_encode(['build_id' => $build->getId()]), $build->getRoutingKey()); $message = $this->messageFactory->createBuildScheduled($build); $this->websocketProducer->publish($message); return $build; }