public function execute(HarbormasterBuild $build, HarbormasterBuildTarget $build_target)
 {
     $viewer = PhabricatorUser::getOmnipotentUser();
     $settings = $this->getSettings();
     $variables = $build_target->getVariables();
     $uri = $settings['uri'] . '/httpAuth/app/rest/buildQueue';
     $method = 'POST';
     $contentType = 'application/xml';
     $xmlBuilder = new TeamCityXmlBuildBuilder();
     $payload = $xmlBuilder->addBuildId($settings['buildId'])->addBranchName(implode(array("D", $variables['buildable.diff'])))->addDiffId(implode(array("D", $variables['buildable.diff'])))->addHarbormasterPHID($variables['target.phid'])->addRevisionId($variables['buildable.revision'])->build();
     $future = id(new HTTPFuture($uri, $payload))->setMethod($method)->addHeader('Content-Type', $contentType)->setTimeout(60);
     $credential_phid = $this->getSetting('credential');
     if ($credential_phid) {
         $key = PassphrasePasswordKey::loadFromPHID($credential_phid, $viewer);
         $future->setHTTPBasicAuthCredentials($key->getUsernameEnvelope()->openEnvelope(), $key->getPasswordEnvelope());
     }
     $this->resolveFutures($build, $build_target, array($future));
     list($status, $body, $headers) = $future->resolve();
     $header_lines = array();
     // TODO: We don't currently preserve the entire "HTTP" response header, but
     // should. Once we do, reproduce it here faithfully.
     $status_code = $status->getStatusCode();
     $header_lines[] = "HTTP {$status_code}";
     foreach ($headers as $header) {
         list($head, $tail) = $header;
         $header_lines[] = "{$head}: {$tail}";
     }
     $header_lines = implode("\n", $header_lines);
     $build_target->newLog($uri, 'http.head')->append($header_lines);
     $build_target->newLog($uri, 'http.body')->append($body);
     if ($status->isError()) {
         throw new HarbormasterBuildFailureException();
     }
 }
 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);
     $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());
     }
     $this->resolveFutures($build, $build_target, array($future));
     list($status, $body, $headers) = $future->resolve();
     $header_lines = array();
     // TODO: We don't currently preserve the entire "HTTP" response header, but
     // should. Once we do, reproduce it here faithfully.
     $status_code = $status->getStatusCode();
     $header_lines[] = "HTTP {$status_code}";
     foreach ($headers as $header) {
         list($head, $tail) = $header;
         $header_lines[] = "{$head}: {$tail}";
     }
     $header_lines = implode("\n", $header_lines);
     $build_target->newLog($uri, 'http.head')->append($header_lines);
     $build_target->newLog($uri, 'http.body')->append($body);
     if ($status->isError()) {
         throw new HarbormasterBuildFailureException();
     }
 }
 protected function loadPage()
 {
     $table = new HarbormasterBuildTarget();
     $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);
 }
 public static function getArtifactIndex(HarbormasterBuildTarget $target, $artifact_key)
 {
     $build = $target->getBuild();
     $parts = array($build->getPHID(), $target->getBuildGeneration(), $artifact_key);
     $parts = implode("", $parts);
     return PhabricatorHash::digestForIndex($parts);
 }
 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);
     }
 }
 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();
     }
 }
 public function execute(HarbormasterBuild $build, HarbormasterBuildTarget $build_target)
 {
     $settings = $this->getSettings();
     // Create the lease.
     $lease = id(new DrydockLease())->setResourceType('host')->setOwnerPHID($build_target->getPHID())->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_target->createArtifact(PhabricatorUser::getOmnipotentUser(), $settings['name'], HarbormasterHostArtifact::ARTIFACTCONST, array('drydockLeasePHID' => $lease->getPHID()));
 }
 public function execute(HarbormasterBuild $build, HarbormasterBuildTarget $build_target)
 {
     $settings = $this->getSettings();
     $variables = $build_target->getVariables();
     $path = $this->mergeVariables('vsprintf', $settings['path'], $variables);
     $artifact = $build_target->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_target->createArtifact(PhabricatorUser::getOmnipotentUser(), $settings['name'], HarbormasterFileArtifact::ARTIFACTCONST, array('filePHID' => $file->getPHID()));
 }
 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)
 {
     $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 buildRepositoryMap(HarbormasterBuildTarget $build_target)
 {
     $viewer = PhabricatorUser::getOmnipotentUser();
     $variables = $build_target->getVariables();
     $repository_phid = idx($variables, 'repository.phid');
     if (!$repository_phid) {
         throw new Exception(pht('Unable to determine how to clone the repository for this ' . 'buildable: it is not associated with a tracked repository.'));
     }
     $also_phids = $build_target->getFieldValue('repositoryPHIDs');
     if (!is_array($also_phids)) {
         $also_phids = array();
     }
     $all_phids = $also_phids;
     $all_phids[] = $repository_phid;
     $repositories = id(new PhabricatorRepositoryQuery())->setViewer($viewer)->withPHIDs($all_phids)->execute();
     $repositories = mpull($repositories, null, 'getPHID');
     foreach ($all_phids as $phid) {
         if (empty($repositories[$phid])) {
             throw new PhabricatorWorkerPermanentFailureException(pht('Unable to load repository with PHID "%s".', $phid));
         }
     }
     $map = array();
     foreach ($also_phids as $also_phid) {
         $also_repo = $repositories[$also_phid];
         $map[$also_repo->getCloneName()] = array('phid' => $also_repo->getPHID(), 'branch' => 'master');
     }
     $repository = $repositories[$repository_phid];
     $commit = idx($variables, 'buildable.commit');
     $ref_uri = idx($variables, 'repository.staging.uri');
     $ref_ref = idx($variables, 'repository.staging.ref');
     if ($commit) {
         $spec = array('commit' => $commit);
     } else {
         if ($ref_uri && $ref_ref) {
             $spec = array('ref' => array('uri' => $ref_uri, 'ref' => $ref_ref));
         } else {
             throw new Exception(pht('Unable to determine how to fetch changes: this buildable does not ' . 'identify a commit or a staging ref. You may need to configure a ' . 'repository staging area.'));
         }
     }
     $directory = $repository->getCloneName();
     $map[$directory] = array('phid' => $repository->getPHID(), 'default' => true) + $spec;
     return $map;
 }
 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);
     $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());
     }
     $this->resolveFutures($build, $build_target, array($future));
     $this->logHTTPResponse($build, $build_target, $future, $uri);
     list($status) = $future->resolve();
     if ($status->isError()) {
         throw new HarbormasterBuildFailureException();
     }
 }
 private function updateTarget(HarbormasterBuildTarget $target, array $payload)
 {
     $step = $target->getBuildStep();
     $impl = $step->getStepImplementation();
     if (!$impl instanceof HarbormasterCircleCIBuildStepImplementation) {
         throw new Exception(pht('Build target ("%s") has the wrong type of build step. Only ' . 'CircleCI build steps may be updated via the CircleCI webhook.', $target->getPHID()));
     }
     switch (idx($payload, 'status')) {
         case 'success':
         case 'fixed':
             $message_type = HarbormasterMessageType::MESSAGE_PASS;
             break;
         default:
             $message_type = HarbormasterMessageType::MESSAGE_FAIL;
             break;
     }
     $viewer = PhabricatorUser::getOmnipotentUser();
     $api_method = 'harbormaster.sendmessage';
     $api_params = array('buildTargetPHID' => $target->getPHID(), 'type' => $message_type);
     id(new ConduitCall($api_method, $api_params))->setUser($viewer)->execute();
 }
 public function execute(HarbormasterBuild $build, HarbormasterBuildTarget $build_target)
 {
     $viewer = PhabricatorUser::getOmnipotentUser();
     $settings = $this->getSettings();
     // TODO: We should probably have a separate temporary storage area for
     // execution stuff that doesn't step on configuration state?
     $lease_phid = $build_target->getDetail('exec.leasePHID');
     if ($lease_phid) {
         $lease = id(new DrydockLeaseQuery())->setViewer($viewer)->withPHIDs(array($lease_phid))->executeOne();
         if (!$lease) {
             throw new PhabricatorWorkerPermanentFailureException(pht('Lease "%s" could not be loaded.', $lease_phid));
         }
     } else {
         $working_copy_type = id(new DrydockWorkingCopyBlueprintImplementation())->getType();
         $lease = id(new DrydockLease())->setResourceType($working_copy_type)->setOwnerPHID($build_target->getPHID());
         $variables = $build_target->getVariables();
         $repository_phid = idx($variables, 'repository.phid');
         $commit = idx($variables, 'repository.commit');
         $lease->setAttribute('repositoryPHID', $repository_phid)->setAttribute('commit', $commit);
         $lease->queueForActivation();
         $build_target->setDetail('exec.leasePHID', $lease->getPHID())->save();
     }
     if ($lease->isActivating()) {
         // TODO: Smart backoff?
         throw new PhabricatorWorkerYieldException(15);
     }
     if (!$lease->isActive()) {
         // TODO: We could just forget about this lease and retry?
         throw new PhabricatorWorkerPermanentFailureException(pht('Lease "%s" never activated.', $lease->getPHID()));
     }
     $artifact = $build_target->createArtifact($viewer, $settings['name'], HarbormasterWorkingCopyArtifact::ARTIFACTCONST, array('drydockLeasePHID' => $lease->getPHID()));
 }
 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);
     }
 }
 public function execute(HarbormasterBuild $build, HarbormasterBuildTarget $build_target)
 {
     $viewer = PhabricatorUser::getOmnipotentUser();
     $settings = $this->getSettings();
     $variables = $build_target->getVariables();
     $artifact = $build_target->loadArtifact($settings['artifact']);
     $impl = $artifact->getArtifactImplementation();
     $lease = $impl->loadArtifactLease($viewer);
     // TODO: Require active lease.
     $command = $this->mergeVariables('vcsprintf', $settings['command'], $variables);
     $interface = $lease->getInterface(DrydockCommandInterface::INTERFACE_TYPE);
     $exec_future = $interface->getExecFuture('%C', $command);
     $harbor_future = id(new HarbormasterExecFuture())->setFuture($exec_future)->setLogs($build_target->newLog('remote', 'stdout'), $build_target->newLog('remote', 'stderr'));
     $this->resolveFutures($build, $build_target, array($harbor_future));
     list($err) = $harbor_future->resolve();
     if ($err) {
         throw new HarbormasterBuildFailureException();
     }
 }
Пример #17
0
 private function updateBuildSteps(HarbormasterBuild $build)
 {
     $targets = id(new HarbormasterBuildTargetQuery())->setViewer($this->getViewer())->withBuildPHIDs(array($build->getPHID()))->withBuildGenerations(array($build->getBuildGeneration()))->execute();
     $this->updateWaitingTargets($targets);
     $targets = mgroup($targets, 'getBuildStepPHID');
     $steps = id(new HarbormasterBuildStepQuery())->setViewer($this->getViewer())->withBuildPlanPHIDs(array($build->getBuildPlan()->getPHID()))->execute();
     // Identify steps which are in various states.
     $queued = array();
     $underway = array();
     $waiting = array();
     $complete = array();
     $failed = array();
     foreach ($steps as $step) {
         $step_targets = idx($targets, $step->getPHID(), array());
         if ($step_targets) {
             $is_queued = false;
             $is_underway = false;
             foreach ($step_targets as $target) {
                 if ($target->isUnderway()) {
                     $is_underway = true;
                     break;
                 }
             }
             $is_waiting = false;
             foreach ($step_targets as $target) {
                 if ($target->isWaiting()) {
                     $is_waiting = true;
                     break;
                 }
             }
             $is_complete = true;
             foreach ($step_targets as $target) {
                 if (!$target->isComplete()) {
                     $is_complete = false;
                     break;
                 }
             }
             $is_failed = false;
             foreach ($step_targets as $target) {
                 if ($target->isFailed()) {
                     $is_failed = true;
                     break;
                 }
             }
         } else {
             $is_queued = true;
             $is_underway = false;
             $is_waiting = false;
             $is_complete = false;
             $is_failed = false;
         }
         if ($is_queued) {
             $queued[$step->getPHID()] = true;
         }
         if ($is_underway) {
             $underway[$step->getPHID()] = true;
         }
         if ($is_waiting) {
             $waiting[$step->getPHID()] = true;
         }
         if ($is_complete) {
             $complete[$step->getPHID()] = true;
         }
         if ($is_failed) {
             $failed[$step->getPHID()] = true;
         }
     }
     // If any step failed, fail the whole build, then bail.
     if (count($failed)) {
         $build->setBuildStatus(HarbormasterBuild::STATUS_FAILED);
         $build->save();
         return;
     }
     // If every step is complete, we're done with this build. Mark it passed
     // and bail.
     if (count($complete) == count($steps)) {
         $build->setBuildStatus(HarbormasterBuild::STATUS_PASSED);
         $build->save();
         return;
     }
     // Identify all the steps which are ready to run (because all their
     // dependencies are complete).
     $runnable = array();
     foreach ($steps as $step) {
         $dependencies = $step->getStepImplementation()->getDependencies($step);
         if (isset($queued[$step->getPHID()])) {
             $can_run = true;
             foreach ($dependencies as $dependency) {
                 if (empty($complete[$dependency])) {
                     $can_run = false;
                     break;
                 }
             }
             if ($can_run) {
                 $runnable[] = $step;
             }
         }
     }
     if (!$runnable && !$waiting && !$underway) {
         // This means the build is deadlocked, and the user has configured
         // circular dependencies.
         $build->setBuildStatus(HarbormasterBuild::STATUS_DEADLOCKED);
         $build->save();
         return;
     }
     foreach ($runnable as $runnable_step) {
         $target = HarbormasterBuildTarget::initializeNewBuildTarget($build, $runnable_step, $build->retrieveVariablesFromBuild());
         $target->save();
         $this->queueNewBuildTarget($target);
     }
 }
 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 static function initializeNewLintMessage(HarbormasterBuildTarget $build_target)
 {
     return id(new HarbormasterBuildLintMessage())->setBuildTargetPHID($build_target->getPHID());
 }
 protected function shouldAbort(HarbormasterBuild $build, HarbormasterBuildTarget $target)
 {
     return $build->getBuildGeneration() !== $target->getBuildGeneration();
 }
 private function buildLog(HarbormasterBuild $build, HarbormasterBuildTarget $build_target)
 {
     $request = $this->getRequest();
     $viewer = $request->getUser();
     $limit = $request->getInt('l', 25);
     $logs = id(new HarbormasterBuildLogQuery())->setViewer($viewer)->withBuildTargetPHIDs(array($build_target->getPHID()))->execute();
     $empty_logs = array();
     $log_boxes = array();
     foreach ($logs as $log) {
         $start = 1;
         $lines = preg_split("/\r\n|\r|\n/", $log->getLogText());
         if ($limit !== 0) {
             $start = count($lines) - $limit;
             if ($start >= 1) {
                 $lines = array_slice($lines, -$limit, $limit);
             } else {
                 $start = 1;
             }
         }
         $id = null;
         $is_empty = false;
         if (count($lines) === 1 && trim($lines[0]) === '') {
             // Prevent Harbormaster from showing empty build logs.
             $id = celerity_generate_unique_node_id();
             $empty_logs[] = $id;
             $is_empty = true;
         }
         $log_view = new ShellLogView();
         $log_view->setLines($lines);
         $log_view->setStart($start);
         $header = id(new PHUIHeaderView())->setHeader(pht('Build Log %d (%s - %s)', $log->getID(), $log->getLogSource(), $log->getLogType()))->setSubheader($this->createLogHeader($build, $log))->setUser($viewer);
         $log_box = id(new PHUIObjectBoxView())->setHeader($header)->setForm($log_view);
         if ($is_empty) {
             $log_box = phutil_tag('div', array('style' => 'display: none', 'id' => $id), $log_box);
         }
         $log_boxes[] = $log_box;
     }
     if ($empty_logs) {
         $hide_id = celerity_generate_unique_node_id();
         Javelin::initBehavior('phabricator-reveal-content');
         $expand = phutil_tag('div', array('id' => $hide_id, 'class' => 'harbormaster-empty-logs-are-hidden mlr mlt mll'), array(pht('%s empty logs are hidden.', new PhutilNumber(count($empty_logs))), ' ', javelin_tag('a', array('href' => '#', 'sigil' => 'reveal-content', 'meta' => array('showIDs' => $empty_logs, 'hideIDs' => array($hide_id))), pht('Show all logs.'))));
         array_unshift($log_boxes, $expand);
     }
     return $log_boxes;
 }
Пример #22
0
 public static function initializeNewBuildLog(HarbormasterBuildTarget $build_target)
 {
     return id(new HarbormasterBuildLog())->setBuildTargetPHID($build_target->getPHID())->setDuration(null)->setLive(0);
 }
 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;
 }
 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();
 }
 protected function logHTTPResponse(HarbormasterBuild $build, HarbormasterBuildTarget $build_target, BaseHTTPFuture $future, $label)
 {
     list($status, $body, $headers) = $future->resolve();
     $header_lines = array();
     // TODO: We don't currently preserve the entire "HTTP" response header, but
     // should. Once we do, reproduce it here faithfully.
     $status_code = $status->getStatusCode();
     $header_lines[] = "HTTP {$status_code}";
     foreach ($headers as $header) {
         list($head, $tail) = $header;
         $header_lines[] = "{$head}: {$tail}";
     }
     $header_lines = implode("\n", $header_lines);
     $build_target->newLog($label, 'http.head')->append($header_lines);
     $build_target->newLog($label, 'http.body')->append($body);
 }
 public static function initializeNewBuildArtifact(HarbormasterBuildTarget $build_target)
 {
     return id(new HarbormasterBuildArtifact())->setBuildTargetPHID($build_target->getPHID());
 }