2013-12-10 01:02:34 +01:00
|
|
|
<?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();
|
|
|
|
|
|
|
|
$parents = id(new DiffusionCommitQuery())
|
|
|
|
->setViewer(PhabricatorUser::getOmnipotentUser())
|
|
|
|
->withRepository($commit->getRepository())
|
2013-12-20 21:39:21 +01:00
|
|
|
->withIdentifiers($parents)
|
2013-12-10 01:02:34 +01:00
|
|
|
->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)
|
Formalize "manual" buildables in Harbormaster
Summary:
Ref T1049. Generally, it's useful to separate test/trial/manual runs from production/automatic runs.
For example, you don't want to email a bunch of people that the build is broken just because you messed something up when writing a new build plan. You'd rather try it first, then promote it into production once you have some good runs.
Similarly, test runs generally should not affect the outside world, etc. Finally, some build steps (like "wait for other buildables") may want to behave differently when run in production/automation than when run in a testing environment (where they should probably continue immediately).
So, formalize the distinction between automatic buildables (those created passively by the system in response to events) and manual buildables (those created explicitly by users). Add filtering, and stop the automated parts of the system from interacting with the manual parts (for example, we won't show manual results on revisions).
This also moves the "Apply Build Plan" to a third, new home: instead of the sidebar or Buildables, it's now on plans. I think this generally makes more sense given how things have developed. Broadly, this improves isolation of test environments.
Test Plan: Created some builds, browsed around, used filters, etc.
Reviewers: btrahan
Reviewed By: btrahan
CC: aran
Maniphest Tasks: T1049
Differential Revision: https://secure.phabricator.com/D7824
2013-12-26 19:40:43 +01:00
|
|
|
->withManualBuildables(false)
|
2013-12-10 01:02:34 +01:00
|
|
|
->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;
|
|
|
|
}
|
|
|
|
}
|