mirror of
https://we.phorge.it/source/phorge.git
synced 2025-01-01 18:30:59 +01:00
Implement "Wait for Previous Builds" build step
Summary: This adds a build step which will block a build from continuing if there are previous builds of the build plan still running. Test Plan: Configured a build plan with a wait of 60 seconds and a "wait for previous builds", then started a build. While that was still building, reconfigured the plan to have a wait time of 3 seconds, started it, and saw it move into the "Waiting" status. When the 60 second build finished, both builds passed. Reviewers: epriestley, #blessed_reviewers Reviewed By: epriestley CC: Korvin, epriestley, aran Maniphest Tasks: T1049 Differential Revision: https://secure.phabricator.com/D7745
This commit is contained in:
parent
de969ab540
commit
270c8d27ab
6 changed files with 144 additions and 5 deletions
|
@ -2366,6 +2366,7 @@ phutil_register_library_map(array(
|
||||||
'SlowvoteRemarkupRule' => 'applications/slowvote/remarkup/SlowvoteRemarkupRule.php',
|
'SlowvoteRemarkupRule' => 'applications/slowvote/remarkup/SlowvoteRemarkupRule.php',
|
||||||
'UploadArtifactBuildStepImplementation' => 'applications/harbormaster/step/UploadArtifactBuildStepImplementation.php',
|
'UploadArtifactBuildStepImplementation' => 'applications/harbormaster/step/UploadArtifactBuildStepImplementation.php',
|
||||||
'VariableBuildStepImplementation' => 'applications/harbormaster/step/VariableBuildStepImplementation.php',
|
'VariableBuildStepImplementation' => 'applications/harbormaster/step/VariableBuildStepImplementation.php',
|
||||||
|
'WaitForPreviousBuildStepImplementation' => 'applications/harbormaster/step/WaitForPreviousBuildStepImplementation.php',
|
||||||
),
|
),
|
||||||
'function' =>
|
'function' =>
|
||||||
array(
|
array(
|
||||||
|
@ -5056,5 +5057,6 @@ phutil_register_library_map(array(
|
||||||
'SlowvoteRemarkupRule' => 'PhabricatorRemarkupRuleObject',
|
'SlowvoteRemarkupRule' => 'PhabricatorRemarkupRuleObject',
|
||||||
'UploadArtifactBuildStepImplementation' => 'VariableBuildStepImplementation',
|
'UploadArtifactBuildStepImplementation' => 'VariableBuildStepImplementation',
|
||||||
'VariableBuildStepImplementation' => 'BuildStepImplementation',
|
'VariableBuildStepImplementation' => 'BuildStepImplementation',
|
||||||
|
'WaitForPreviousBuildStepImplementation' => 'BuildStepImplementation',
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
|
|
|
@ -49,7 +49,10 @@ final class HarbormasterBuildViewController
|
||||||
$targets = array();
|
$targets = array();
|
||||||
foreach ($build_targets as $build_target) {
|
foreach ($build_targets as $build_target) {
|
||||||
$header = id(new PHUIHeaderView())
|
$header = id(new PHUIHeaderView())
|
||||||
->setHeader(pht('Build Target %d', $build_target->getID()))
|
->setHeader(pht(
|
||||||
|
'Build Target %d (%s)',
|
||||||
|
$build_target->getID(),
|
||||||
|
$build_target->getImplementation()->getName()))
|
||||||
->setUser($viewer);
|
->setUser($viewer);
|
||||||
$properties = new PHUIPropertyListView();
|
$properties = new PHUIPropertyListView();
|
||||||
|
|
||||||
|
@ -280,7 +283,7 @@ final class HarbormasterBuildViewController
|
||||||
case HarbormasterBuild::STATUS_PENDING:
|
case HarbormasterBuild::STATUS_PENDING:
|
||||||
return pht('Pending');
|
return pht('Pending');
|
||||||
case HarbormasterBuild::STATUS_WAITING:
|
case HarbormasterBuild::STATUS_WAITING:
|
||||||
return pht('Waiting on Resource');
|
return pht('Waiting');
|
||||||
case HarbormasterBuild::STATUS_BUILDING:
|
case HarbormasterBuild::STATUS_BUILDING:
|
||||||
return pht('Building');
|
return pht('Building');
|
||||||
case HarbormasterBuild::STATUS_PASSED:
|
case HarbormasterBuild::STATUS_PASSED:
|
||||||
|
|
|
@ -52,8 +52,8 @@ final class HarbormasterBuildableViewController
|
||||||
$item->addAttribute(pht('Pending'));
|
$item->addAttribute(pht('Pending'));
|
||||||
break;
|
break;
|
||||||
case HarbormasterBuild::STATUS_WAITING:
|
case HarbormasterBuild::STATUS_WAITING:
|
||||||
$item->setBarColor('blue');
|
$item->setBarColor('violet');
|
||||||
$item->addAttribute(pht('Waiting on Resource'));
|
$item->addAttribute(pht('Waiting'));
|
||||||
break;
|
break;
|
||||||
case HarbormasterBuild::STATUS_BUILDING:
|
case HarbormasterBuild::STATUS_BUILDING:
|
||||||
$item->setBarColor('yellow');
|
$item->setBarColor('yellow');
|
||||||
|
|
|
@ -53,7 +53,7 @@ abstract class BuildStepImplementation {
|
||||||
/**
|
/**
|
||||||
* Validate the current settings of this build step.
|
* Validate the current settings of this build step.
|
||||||
*/
|
*/
|
||||||
public function validate() {
|
public function validateSettings() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,127 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class WaitForPreviousBuildStepImplementation
|
||||||
|
extends BuildStepImplementation {
|
||||||
|
|
||||||
|
public function getName() {
|
||||||
|
return pht('Wait for Previous Commits to Build');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getGenericDescription() {
|
||||||
|
return pht(
|
||||||
|
'Wait for previous commits to finish building the current plan '.
|
||||||
|
'before continuing.');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDescription() {
|
||||||
|
return pht(
|
||||||
|
'Wait for previous commits to finish building the current plan '.
|
||||||
|
'before continuing.');
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We are blocked until all previous builds finish.
|
||||||
|
$build->setBuildStatus(HarbormasterBuild::STATUS_WAITING);
|
||||||
|
$build->save();
|
||||||
|
|
||||||
|
// Block until all previous builds of the same build plan have
|
||||||
|
// finished.
|
||||||
|
$plan = $build->getBuildPlan();
|
||||||
|
|
||||||
|
$log = null;
|
||||||
|
$log_start = null;
|
||||||
|
$blockers = $this->getBlockers($object, $plan, $build);
|
||||||
|
while (count($blockers) > 0) {
|
||||||
|
if ($build->checkForCancellation()) {
|
||||||
|
if ($log !== null) {
|
||||||
|
$log->finalize($log_start);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($log === null) {
|
||||||
|
$log = $build->createLog($build_target, "waiting", "blockers");
|
||||||
|
$log_start = $log->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
$log->append("Blocked by: ".implode(",", $blockers)."\n");
|
||||||
|
|
||||||
|
sleep(1);
|
||||||
|
$blockers = $this->getBlockers($object, $plan, $build);
|
||||||
|
}
|
||||||
|
if ($log !== null) {
|
||||||
|
$log->finalize($log_start);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move back into building status.
|
||||||
|
$build->setBuildStatus(HarbormasterBuild::STATUS_BUILDING);
|
||||||
|
$build->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getBlockers(
|
||||||
|
PhabricatorRepositoryCommit $commit,
|
||||||
|
HarbormasterBuildPlan $plan,
|
||||||
|
HarbormasterBuild $source) {
|
||||||
|
|
||||||
|
$call = new ConduitCall(
|
||||||
|
'diffusion.commitparentsquery',
|
||||||
|
array(
|
||||||
|
'commit' => $commit->getCommitIdentifier(),
|
||||||
|
'callsign' => $commit->getRepository()->getCallsign()
|
||||||
|
));
|
||||||
|
$call->setUser(PhabricatorUser::getOmnipotentUser());
|
||||||
|
$parents = $call->execute();
|
||||||
|
|
||||||
|
$hashes = array();
|
||||||
|
foreach ($parents as $parent => $obj) {
|
||||||
|
$hashes[] = $parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
$parents = id(new DiffusionCommitQuery())
|
||||||
|
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||||
|
->withRepository($commit->getRepository())
|
||||||
|
->withIdentifiers($hashes)
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$blockers = array();
|
||||||
|
|
||||||
|
$build_objects = array();
|
||||||
|
foreach ($parents as $parent) {
|
||||||
|
if (!$parent->isImported()) {
|
||||||
|
$blockers[] = pht('Commit %s', $parent->getCommitIdentifier());
|
||||||
|
} else {
|
||||||
|
$build_objects[] = $parent->getPHID();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$buildables = id(new HarbormasterBuildableQuery())
|
||||||
|
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||||
|
->withBuildablePHIDs($build_objects)
|
||||||
|
->execute();
|
||||||
|
$buildable_phids = mpull($buildables, 'getPHID');
|
||||||
|
|
||||||
|
$builds = id(new HarbormasterBuildQuery())
|
||||||
|
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||||
|
->withBuildablePHIDs($buildable_phids)
|
||||||
|
->withBuildPlanPHIDs(array($plan->getPHID()))
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
foreach ($builds as $build) {
|
||||||
|
if ($build->isBuilding()) {
|
||||||
|
$blockers[] = pht('Build %d', $build->getID());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $blockers;
|
||||||
|
}
|
||||||
|
}
|
|
@ -94,6 +94,13 @@ final class HarbormasterBuild extends HarbormasterDAO
|
||||||
return $this->assertAttached($this->buildPlan);
|
return $this->assertAttached($this->buildPlan);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function isBuilding() {
|
||||||
|
return $this->getBuildStatus() === self::STATUS_PENDING ||
|
||||||
|
$this->getBuildStatus() === self::STATUS_WAITING ||
|
||||||
|
$this->getBuildStatus() === self::STATUS_BUILDING ||
|
||||||
|
$this->getCancelRequested();
|
||||||
|
}
|
||||||
|
|
||||||
public function createLog(
|
public function createLog(
|
||||||
HarbormasterBuildTarget $build_target,
|
HarbormasterBuildTarget $build_target,
|
||||||
$log_source,
|
$log_source,
|
||||||
|
|
Loading…
Reference in a new issue