private function checkForBuildablesWithPlanBehaviors()

in src/workflow/ArcanistLandWorkflow.php [1645:1807]


  private function checkForBuildablesWithPlanBehaviors($diff_phid) {
    // Reset ongoing builds value.
    $this->uberOngoingBuildsExist = false;

    // TODO: These queries should page through all results instead of fetching
    // only the first page, but we don't have good primitives to support that
    // in "master" yet.

    $this->writeInfo(
      pht('BUILDS'),
      pht('Checking build status...'));

    $raw_buildables = $this->getConduit()->callMethodSynchronous(
      'harbormaster.buildable.search',
      array(
        'constraints' => array(
          'objectPHIDs' => array(
            $diff_phid,
          ),
          'manual' => false,
        ),
      ));

    if (!$raw_buildables['data']) {
      return;
    }

    $buildables = $raw_buildables['data'];
    $buildable_phids = ipull($buildables, 'phid');

    $raw_builds = $this->getConduit()->callMethodSynchronous(
      'harbormaster.build.search',
      array(
        'constraints' => array(
          'buildables' => $buildable_phids,
        ),
      ));

    if (!$raw_builds['data']) {
      return;
    }

    $builds = array();
    foreach ($raw_builds['data'] as $raw_build) {
      $build_ref = ArcanistBuildRef::newFromConduit($raw_build);
      $build_phid = $build_ref->getPHID();
      $builds[$build_phid] = $build_ref;
    }

    $plan_phids = mpull($builds, 'getBuildPlanPHID');
    $plan_phids = array_values($plan_phids);

    $raw_plans = $this->getConduit()->callMethodSynchronous(
      'harbormaster.buildplan.search',
      array(
        'constraints' => array(
          'phids' => $plan_phids,
        ),
      ));

    $plans = array();
    foreach ($raw_plans['data'] as $raw_plan) {
      $plan_ref = ArcanistBuildPlanRef::newFromConduit($raw_plan);
      $plan_phid = $plan_ref->getPHID();
      $plans[$plan_phid] = $plan_ref;
    }

    $ongoing_builds = array();
    $failed_builds = array();

    $builds = msortv($builds, 'getStatusSortVector');
    foreach ($builds as $build_ref) {
      $plan = idx($plans, $build_ref->getBuildPlanPHID());
      if (!$plan) {
        continue;
      }

      $plan_behavior = $plan->getBehavior('arc-land', 'always');
      $if_building = ($plan_behavior == 'building');
      $if_complete = ($plan_behavior == 'complete');
      $if_never = ($plan_behavior == 'never');

      // If the build plan "Never" warns when landing, skip it.
      if ($if_never) {
        continue;
      }

      // If the build plan warns when landing "If Complete" but the build is
      // not complete, skip it.
      if ($if_complete && !$build_ref->isComplete()) {
        continue;
      }

      // If the build plan warns when landing "If Building" but the build is
      // complete, skip it.
      if ($if_building && $build_ref->isComplete()) {
        continue;
      }

      // Ignore passing builds.
      if ($build_ref->isPassed()) {
        continue;
      }

      if (!$build_ref->isComplete()) {
        $ongoing_builds[] = $build_ref;
      } else {
        $failed_builds[] = $build_ref;
      }
    }

    if (!$ongoing_builds && !$failed_builds) {
      return;
    }

    if ($failed_builds) {
      $this->writeWarn(
        pht('BUILD FAILURES'),
        pht(
          'Harbormaster failed to build the active diff for this revision:'));
      $prompt = pht('Land revision anyway, despite build failures?');
    } else if ($ongoing_builds) {
      $this->writeWarn(
        pht('ONGOING BUILDS'),
        pht(
          'Harbormaster is still building the active diff for this revision:'));
      $this->uberOngoingBuildsExist = true;
      $prompt = pht('Land revision anyway, despite ongoing build?');
    }

    $show_builds = array_merge($failed_builds, $ongoing_builds);
    echo "\n";
    foreach ($show_builds as $build_ref) {
      $ansi_color = $build_ref->getStatusANSIColor();
      $status_name = $build_ref->getStatusName();
      $object_name = $build_ref->getObjectName();
      $build_name = $build_ref->getName();

      echo tsprintf(
        "    **<bg:".$ansi_color."> %s </bg>** %s: %s\n",
        $status_name,
        $object_name,
        $build_name);
    }

    echo tsprintf(
      "\n%s\n\n",
      pht('You can review build details here:'));

    foreach ($buildables as $buildable) {
      $buildable_uri = id(new PhutilURI($this->getConduitURI()))
        ->setPath(sprintf('/B%d', $buildable['id']));

      echo tsprintf(
        "          **%s**: __%s__\n",
        pht('Buildable %d', $buildable['id']),
        $buildable_uri);
    }

    if (!phutil_console_confirm($prompt)) {
      throw new ArcanistUserAbortException();
    }
  }