2014-01-06 21:32:10 +01:00
|
|
|
<?php
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Moves a build forward by queuing build tasks, canceling or restarting the
|
|
|
|
* build, or failing it in response to task failures.
|
|
|
|
*/
|
|
|
|
final class HarbormasterBuildEngine extends Phobject {
|
|
|
|
|
|
|
|
private $build;
|
|
|
|
private $viewer;
|
|
|
|
private $newBuildTargets = array();
|
2014-04-18 01:01:16 +02:00
|
|
|
private $forceBuildableUpdate;
|
|
|
|
|
|
|
|
public function setForceBuildableUpdate($force_buildable_update) {
|
|
|
|
$this->forceBuildableUpdate = $force_buildable_update;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function shouldForceBuildableUpdate() {
|
|
|
|
return $this->forceBuildableUpdate;
|
|
|
|
}
|
2014-01-06 21:32:10 +01:00
|
|
|
|
|
|
|
public function queueNewBuildTarget(HarbormasterBuildTarget $target) {
|
|
|
|
$this->newBuildTargets[] = $target;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getNewBuildTargets() {
|
|
|
|
return $this->newBuildTargets;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function setViewer(PhabricatorUser $viewer) {
|
|
|
|
$this->viewer = $viewer;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getViewer() {
|
|
|
|
return $this->viewer;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function setBuild(HarbormasterBuild $build) {
|
|
|
|
$this->build = $build;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getBuild() {
|
|
|
|
return $this->build;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function continueBuild() {
|
|
|
|
$build = $this->getBuild();
|
|
|
|
|
|
|
|
$lock_key = 'harbormaster.build:'.$build->getID();
|
|
|
|
$lock = PhabricatorGlobalLock::newLock($lock_key)->lock(15);
|
|
|
|
|
|
|
|
$build->reload();
|
2014-04-18 01:01:16 +02:00
|
|
|
$old_status = $build->getBuildStatus();
|
2014-01-06 21:32:10 +01:00
|
|
|
|
|
|
|
try {
|
|
|
|
$this->updateBuild($build);
|
|
|
|
} catch (Exception $ex) {
|
|
|
|
// If any exception is raised, the build is marked as a failure and the
|
|
|
|
// exception is re-thrown (this ensures we don't leave builds in an
|
|
|
|
// inconsistent state).
|
|
|
|
$build->setBuildStatus(HarbormasterBuild::STATUS_ERROR);
|
|
|
|
$build->save();
|
|
|
|
|
|
|
|
$lock->unlock();
|
2014-08-12 01:15:16 +02:00
|
|
|
|
|
|
|
$this->releaseAllArtifacts($build);
|
|
|
|
|
2014-01-06 21:32:10 +01:00
|
|
|
throw $ex;
|
|
|
|
}
|
|
|
|
|
|
|
|
$lock->unlock();
|
|
|
|
|
|
|
|
// NOTE: We queue new targets after releasing the lock so that in-process
|
|
|
|
// execution via `bin/harbormaster` does not reenter the locked region.
|
|
|
|
foreach ($this->getNewBuildTargets() as $target) {
|
|
|
|
$task = PhabricatorWorker::scheduleTask(
|
|
|
|
'HarbormasterTargetWorker',
|
|
|
|
array(
|
|
|
|
'targetID' => $target->getID(),
|
|
|
|
));
|
|
|
|
}
|
2014-04-18 01:01:16 +02:00
|
|
|
|
|
|
|
// If the build changed status, we might need to update the overall status
|
|
|
|
// on the buildable.
|
|
|
|
$new_status = $build->getBuildStatus();
|
|
|
|
if ($new_status != $old_status || $this->shouldForceBuildableUpdate()) {
|
|
|
|
$this->updateBuildable($build->getBuildable());
|
|
|
|
}
|
2014-08-12 01:15:16 +02:00
|
|
|
|
|
|
|
// If we are no longer building for any reason, release all artifacts.
|
|
|
|
if (!$build->isBuilding()) {
|
|
|
|
$this->releaseAllArtifacts($build);
|
|
|
|
}
|
2014-01-06 21:32:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private function updateBuild(HarbormasterBuild $build) {
|
2015-09-21 21:07:24 +02:00
|
|
|
if ($build->isAborting()) {
|
|
|
|
$this->releaseAllArtifacts($build);
|
|
|
|
$build->setBuildStatus(HarbormasterBuild::STATUS_ABORTED);
|
|
|
|
$build->save();
|
|
|
|
}
|
|
|
|
|
Replace "Cancel Build" with "Stop", "Resume" and "Restart"
Summary:
Ref T1049. Currently you can cancel a build, but now that we're tracking a lot more state we can stop, resume, and restart builds.
When the user issues a command against a build, I'm writing it into an auxiliary queue (`HarbormasterBuildCommand`) and then reading them out in the worker. This is mostly to avoid race messes where we try to `save()` the object in multiple places: basically, the BuildEngine is the //only// thing that writes to Build objects, and it holds a lock while it does it.
Test Plan:
- Created a plan which runs "sleep 2" a bunch of times in a row.
- Stopped, resumed, and restarted it.
Reviewers: btrahan
Reviewed By: btrahan
CC: aran, chad
Maniphest Tasks: T1049
Differential Revision: https://secure.phabricator.com/D7892
2014-01-06 21:32:20 +01:00
|
|
|
if (($build->getBuildStatus() == HarbormasterBuild::STATUS_PENDING) ||
|
2014-01-06 23:11:59 +01:00
|
|
|
($build->isRestarting())) {
|
2014-08-21 14:55:24 +02:00
|
|
|
$this->restartBuild($build);
|
2014-01-06 21:32:10 +01:00
|
|
|
$build->setBuildStatus(HarbormasterBuild::STATUS_BUILDING);
|
|
|
|
$build->save();
|
|
|
|
}
|
|
|
|
|
2014-01-06 23:11:59 +01:00
|
|
|
if ($build->isResuming()) {
|
Replace "Cancel Build" with "Stop", "Resume" and "Restart"
Summary:
Ref T1049. Currently you can cancel a build, but now that we're tracking a lot more state we can stop, resume, and restart builds.
When the user issues a command against a build, I'm writing it into an auxiliary queue (`HarbormasterBuildCommand`) and then reading them out in the worker. This is mostly to avoid race messes where we try to `save()` the object in multiple places: basically, the BuildEngine is the //only// thing that writes to Build objects, and it holds a lock while it does it.
Test Plan:
- Created a plan which runs "sleep 2" a bunch of times in a row.
- Stopped, resumed, and restarted it.
Reviewers: btrahan
Reviewed By: btrahan
CC: aran, chad
Maniphest Tasks: T1049
Differential Revision: https://secure.phabricator.com/D7892
2014-01-06 21:32:20 +01:00
|
|
|
$build->setBuildStatus(HarbormasterBuild::STATUS_BUILDING);
|
|
|
|
$build->save();
|
|
|
|
}
|
|
|
|
|
2015-09-21 21:07:24 +02:00
|
|
|
if ($build->isPausing() && !$build->isComplete()) {
|
|
|
|
$build->setBuildStatus(HarbormasterBuild::STATUS_PAUSED);
|
Replace "Cancel Build" with "Stop", "Resume" and "Restart"
Summary:
Ref T1049. Currently you can cancel a build, but now that we're tracking a lot more state we can stop, resume, and restart builds.
When the user issues a command against a build, I'm writing it into an auxiliary queue (`HarbormasterBuildCommand`) and then reading them out in the worker. This is mostly to avoid race messes where we try to `save()` the object in multiple places: basically, the BuildEngine is the //only// thing that writes to Build objects, and it holds a lock while it does it.
Test Plan:
- Created a plan which runs "sleep 2" a bunch of times in a row.
- Stopped, resumed, and restarted it.
Reviewers: btrahan
Reviewed By: btrahan
CC: aran, chad
Maniphest Tasks: T1049
Differential Revision: https://secure.phabricator.com/D7892
2014-01-06 21:32:20 +01:00
|
|
|
$build->save();
|
|
|
|
}
|
|
|
|
|
2014-01-06 23:11:59 +01:00
|
|
|
$build->deleteUnprocessedCommands();
|
Replace "Cancel Build" with "Stop", "Resume" and "Restart"
Summary:
Ref T1049. Currently you can cancel a build, but now that we're tracking a lot more state we can stop, resume, and restart builds.
When the user issues a command against a build, I'm writing it into an auxiliary queue (`HarbormasterBuildCommand`) and then reading them out in the worker. This is mostly to avoid race messes where we try to `save()` the object in multiple places: basically, the BuildEngine is the //only// thing that writes to Build objects, and it holds a lock while it does it.
Test Plan:
- Created a plan which runs "sleep 2" a bunch of times in a row.
- Stopped, resumed, and restarted it.
Reviewers: btrahan
Reviewed By: btrahan
CC: aran, chad
Maniphest Tasks: T1049
Differential Revision: https://secure.phabricator.com/D7892
2014-01-06 21:32:20 +01:00
|
|
|
|
2014-01-06 21:32:10 +01:00
|
|
|
if ($build->getBuildStatus() == HarbormasterBuild::STATUS_BUILDING) {
|
Replace "Cancel Build" with "Stop", "Resume" and "Restart"
Summary:
Ref T1049. Currently you can cancel a build, but now that we're tracking a lot more state we can stop, resume, and restart builds.
When the user issues a command against a build, I'm writing it into an auxiliary queue (`HarbormasterBuildCommand`) and then reading them out in the worker. This is mostly to avoid race messes where we try to `save()` the object in multiple places: basically, the BuildEngine is the //only// thing that writes to Build objects, and it holds a lock while it does it.
Test Plan:
- Created a plan which runs "sleep 2" a bunch of times in a row.
- Stopped, resumed, and restarted it.
Reviewers: btrahan
Reviewed By: btrahan
CC: aran, chad
Maniphest Tasks: T1049
Differential Revision: https://secure.phabricator.com/D7892
2014-01-06 21:32:20 +01:00
|
|
|
$this->updateBuildSteps($build);
|
2014-01-06 21:32:10 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-21 14:55:24 +02:00
|
|
|
private function restartBuild(HarbormasterBuild $build) {
|
2014-01-29 05:17:03 +01:00
|
|
|
|
2014-08-21 14:55:24 +02:00
|
|
|
// We're restarting the build, so release all previous artifacts.
|
|
|
|
$this->releaseAllArtifacts($build);
|
2014-01-29 05:17:03 +01:00
|
|
|
|
2014-08-21 14:55:24 +02:00
|
|
|
// Increment the build generation counter on the build.
|
|
|
|
$build->setBuildGeneration($build->getBuildGeneration() + 1);
|
2014-01-29 05:17:03 +01:00
|
|
|
|
2014-08-26 12:46:23 +02:00
|
|
|
// Currently running targets should periodically check their build
|
2014-08-21 14:55:24 +02:00
|
|
|
// generation (which won't have changed) against the build's generation.
|
2014-08-26 12:46:23 +02:00
|
|
|
// If it is different, they will automatically stop what they're doing
|
2014-08-21 14:55:24 +02:00
|
|
|
// and abort.
|
2014-01-29 05:17:03 +01:00
|
|
|
|
2014-08-21 14:55:24 +02:00
|
|
|
// Previously we used to delete targets, logs and artifacts here. Instead
|
|
|
|
// leave them around so users can view previous generations of this build.
|
2014-01-06 21:32:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private function updateBuildSteps(HarbormasterBuild $build) {
|
|
|
|
$targets = id(new HarbormasterBuildTargetQuery())
|
|
|
|
->setViewer($this->getViewer())
|
|
|
|
->withBuildPHIDs(array($build->getPHID()))
|
2014-08-21 14:55:24 +02:00
|
|
|
->withBuildGenerations(array($build->getBuildGeneration()))
|
2014-01-06 21:32:10 +01:00
|
|
|
->execute();
|
Allow Harbormaster build targets to wait for messages
Summary:
This hooks up all the pieces of the build pipeline so `harbormaster.sendmessage` actually works. Particularly:
- Candidate build steps (i.e., those which interact with external systems) can now "Wait for Message". This pauses them indefinitely when they complete, until something calls `harbormaster.sendmessage`.
- After processing a target, we check if we should move it to PASSED or WAITING.
- Before updating a build, we move WAITING targets with pending messages to either PASSED or FAILED.
- I added an explicit "Building" state, which doesn't affect workflows but communicates more information to human users.
A big part of this is avoiding races. I believe we get the correct behavior no matter which order events occur in:
- We update builds after targets complete and after we receive messages, so we're guaranteed to update once both these conditions are true. This means messages can't be lost (even if they arrive before a build completes).
- The minor changes to the build engine logic mean that firing additional build updates is always safe, no matter what the current state of the build is.
- The build itself is protected by a lock in the build engine.
- The target is not covered by an explicit lock, but for all states only the engine (waiting) //or// the worker (all other states) can interact with it. All of the interactions also move the target state forward to the same destination and have no other side effects.
- Messages are only consumed inside the engine lock, so they don't need an explicit lock.
Test Plan:
- Made an HTTP request wait after completion, then ran a pile of builds through it using `bin/harbormaster build` and the web UI.
- Passed and failed message-awaiting builds with `harbormaster.sendmessage`.
Reviewers: btrahan
Reviewed By: btrahan
Subscribers: epriestley, zeeg
Differential Revision: https://secure.phabricator.com/D8788
2014-04-16 22:01:46 +02:00
|
|
|
|
|
|
|
$this->updateWaitingTargets($targets);
|
|
|
|
|
2014-01-06 21:32:10 +01:00
|
|
|
$targets = mgroup($targets, 'getBuildStepPHID');
|
|
|
|
|
|
|
|
$steps = id(new HarbormasterBuildStepQuery())
|
|
|
|
->setViewer($this->getViewer())
|
|
|
|
->withBuildPlanPHIDs(array($build->getBuildPlan()->getPHID()))
|
|
|
|
->execute();
|
|
|
|
|
Allow Harbormaster build targets to wait for messages
Summary:
This hooks up all the pieces of the build pipeline so `harbormaster.sendmessage` actually works. Particularly:
- Candidate build steps (i.e., those which interact with external systems) can now "Wait for Message". This pauses them indefinitely when they complete, until something calls `harbormaster.sendmessage`.
- After processing a target, we check if we should move it to PASSED or WAITING.
- Before updating a build, we move WAITING targets with pending messages to either PASSED or FAILED.
- I added an explicit "Building" state, which doesn't affect workflows but communicates more information to human users.
A big part of this is avoiding races. I believe we get the correct behavior no matter which order events occur in:
- We update builds after targets complete and after we receive messages, so we're guaranteed to update once both these conditions are true. This means messages can't be lost (even if they arrive before a build completes).
- The minor changes to the build engine logic mean that firing additional build updates is always safe, no matter what the current state of the build is.
- The build itself is protected by a lock in the build engine.
- The target is not covered by an explicit lock, but for all states only the engine (waiting) //or// the worker (all other states) can interact with it. All of the interactions also move the target state forward to the same destination and have no other side effects.
- Messages are only consumed inside the engine lock, so they don't need an explicit lock.
Test Plan:
- Made an HTTP request wait after completion, then ran a pile of builds through it using `bin/harbormaster build` and the web UI.
- Passed and failed message-awaiting builds with `harbormaster.sendmessage`.
Reviewers: btrahan
Reviewed By: btrahan
Subscribers: epriestley, zeeg
Differential Revision: https://secure.phabricator.com/D8788
2014-04-16 22:01:46 +02:00
|
|
|
// Identify steps which are in various states.
|
2014-01-06 21:32:10 +01:00
|
|
|
|
Allow Harbormaster build targets to wait for messages
Summary:
This hooks up all the pieces of the build pipeline so `harbormaster.sendmessage` actually works. Particularly:
- Candidate build steps (i.e., those which interact with external systems) can now "Wait for Message". This pauses them indefinitely when they complete, until something calls `harbormaster.sendmessage`.
- After processing a target, we check if we should move it to PASSED or WAITING.
- Before updating a build, we move WAITING targets with pending messages to either PASSED or FAILED.
- I added an explicit "Building" state, which doesn't affect workflows but communicates more information to human users.
A big part of this is avoiding races. I believe we get the correct behavior no matter which order events occur in:
- We update builds after targets complete and after we receive messages, so we're guaranteed to update once both these conditions are true. This means messages can't be lost (even if they arrive before a build completes).
- The minor changes to the build engine logic mean that firing additional build updates is always safe, no matter what the current state of the build is.
- The build itself is protected by a lock in the build engine.
- The target is not covered by an explicit lock, but for all states only the engine (waiting) //or// the worker (all other states) can interact with it. All of the interactions also move the target state forward to the same destination and have no other side effects.
- Messages are only consumed inside the engine lock, so they don't need an explicit lock.
Test Plan:
- Made an HTTP request wait after completion, then ran a pile of builds through it using `bin/harbormaster build` and the web UI.
- Passed and failed message-awaiting builds with `harbormaster.sendmessage`.
Reviewers: btrahan
Reviewed By: btrahan
Subscribers: epriestley, zeeg
Differential Revision: https://secure.phabricator.com/D8788
2014-04-16 22:01:46 +02:00
|
|
|
$queued = array();
|
|
|
|
$underway = array();
|
|
|
|
$waiting = array();
|
2014-01-06 21:32:10 +01:00
|
|
|
$complete = array();
|
|
|
|
$failed = array();
|
|
|
|
foreach ($steps as $step) {
|
|
|
|
$step_targets = idx($targets, $step->getPHID(), array());
|
|
|
|
|
|
|
|
if ($step_targets) {
|
Allow Harbormaster build targets to wait for messages
Summary:
This hooks up all the pieces of the build pipeline so `harbormaster.sendmessage` actually works. Particularly:
- Candidate build steps (i.e., those which interact with external systems) can now "Wait for Message". This pauses them indefinitely when they complete, until something calls `harbormaster.sendmessage`.
- After processing a target, we check if we should move it to PASSED or WAITING.
- Before updating a build, we move WAITING targets with pending messages to either PASSED or FAILED.
- I added an explicit "Building" state, which doesn't affect workflows but communicates more information to human users.
A big part of this is avoiding races. I believe we get the correct behavior no matter which order events occur in:
- We update builds after targets complete and after we receive messages, so we're guaranteed to update once both these conditions are true. This means messages can't be lost (even if they arrive before a build completes).
- The minor changes to the build engine logic mean that firing additional build updates is always safe, no matter what the current state of the build is.
- The build itself is protected by a lock in the build engine.
- The target is not covered by an explicit lock, but for all states only the engine (waiting) //or// the worker (all other states) can interact with it. All of the interactions also move the target state forward to the same destination and have no other side effects.
- Messages are only consumed inside the engine lock, so they don't need an explicit lock.
Test Plan:
- Made an HTTP request wait after completion, then ran a pile of builds through it using `bin/harbormaster build` and the web UI.
- Passed and failed message-awaiting builds with `harbormaster.sendmessage`.
Reviewers: btrahan
Reviewed By: btrahan
Subscribers: epriestley, zeeg
Differential Revision: https://secure.phabricator.com/D8788
2014-04-16 22:01:46 +02:00
|
|
|
$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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-06 21:32:10 +01:00
|
|
|
$is_complete = true;
|
|
|
|
foreach ($step_targets as $target) {
|
Replace "Cancel Build" with "Stop", "Resume" and "Restart"
Summary:
Ref T1049. Currently you can cancel a build, but now that we're tracking a lot more state we can stop, resume, and restart builds.
When the user issues a command against a build, I'm writing it into an auxiliary queue (`HarbormasterBuildCommand`) and then reading them out in the worker. This is mostly to avoid race messes where we try to `save()` the object in multiple places: basically, the BuildEngine is the //only// thing that writes to Build objects, and it holds a lock while it does it.
Test Plan:
- Created a plan which runs "sleep 2" a bunch of times in a row.
- Stopped, resumed, and restarted it.
Reviewers: btrahan
Reviewed By: btrahan
CC: aran, chad
Maniphest Tasks: T1049
Differential Revision: https://secure.phabricator.com/D7892
2014-01-06 21:32:20 +01:00
|
|
|
if (!$target->isComplete()) {
|
2014-01-06 21:32:10 +01:00
|
|
|
$is_complete = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$is_failed = false;
|
|
|
|
foreach ($step_targets as $target) {
|
Replace "Cancel Build" with "Stop", "Resume" and "Restart"
Summary:
Ref T1049. Currently you can cancel a build, but now that we're tracking a lot more state we can stop, resume, and restart builds.
When the user issues a command against a build, I'm writing it into an auxiliary queue (`HarbormasterBuildCommand`) and then reading them out in the worker. This is mostly to avoid race messes where we try to `save()` the object in multiple places: basically, the BuildEngine is the //only// thing that writes to Build objects, and it holds a lock while it does it.
Test Plan:
- Created a plan which runs "sleep 2" a bunch of times in a row.
- Stopped, resumed, and restarted it.
Reviewers: btrahan
Reviewed By: btrahan
CC: aran, chad
Maniphest Tasks: T1049
Differential Revision: https://secure.phabricator.com/D7892
2014-01-06 21:32:20 +01:00
|
|
|
if ($target->isFailed()) {
|
2014-01-06 21:32:10 +01:00
|
|
|
$is_failed = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
Allow Harbormaster build targets to wait for messages
Summary:
This hooks up all the pieces of the build pipeline so `harbormaster.sendmessage` actually works. Particularly:
- Candidate build steps (i.e., those which interact with external systems) can now "Wait for Message". This pauses them indefinitely when they complete, until something calls `harbormaster.sendmessage`.
- After processing a target, we check if we should move it to PASSED or WAITING.
- Before updating a build, we move WAITING targets with pending messages to either PASSED or FAILED.
- I added an explicit "Building" state, which doesn't affect workflows but communicates more information to human users.
A big part of this is avoiding races. I believe we get the correct behavior no matter which order events occur in:
- We update builds after targets complete and after we receive messages, so we're guaranteed to update once both these conditions are true. This means messages can't be lost (even if they arrive before a build completes).
- The minor changes to the build engine logic mean that firing additional build updates is always safe, no matter what the current state of the build is.
- The build itself is protected by a lock in the build engine.
- The target is not covered by an explicit lock, but for all states only the engine (waiting) //or// the worker (all other states) can interact with it. All of the interactions also move the target state forward to the same destination and have no other side effects.
- Messages are only consumed inside the engine lock, so they don't need an explicit lock.
Test Plan:
- Made an HTTP request wait after completion, then ran a pile of builds through it using `bin/harbormaster build` and the web UI.
- Passed and failed message-awaiting builds with `harbormaster.sendmessage`.
Reviewers: btrahan
Reviewed By: btrahan
Subscribers: epriestley, zeeg
Differential Revision: https://secure.phabricator.com/D8788
2014-04-16 22:01:46 +02:00
|
|
|
$is_queued = true;
|
|
|
|
$is_underway = false;
|
|
|
|
$is_waiting = false;
|
2014-01-06 21:32:10 +01:00
|
|
|
$is_complete = false;
|
|
|
|
$is_failed = false;
|
|
|
|
}
|
|
|
|
|
Allow Harbormaster build targets to wait for messages
Summary:
This hooks up all the pieces of the build pipeline so `harbormaster.sendmessage` actually works. Particularly:
- Candidate build steps (i.e., those which interact with external systems) can now "Wait for Message". This pauses them indefinitely when they complete, until something calls `harbormaster.sendmessage`.
- After processing a target, we check if we should move it to PASSED or WAITING.
- Before updating a build, we move WAITING targets with pending messages to either PASSED or FAILED.
- I added an explicit "Building" state, which doesn't affect workflows but communicates more information to human users.
A big part of this is avoiding races. I believe we get the correct behavior no matter which order events occur in:
- We update builds after targets complete and after we receive messages, so we're guaranteed to update once both these conditions are true. This means messages can't be lost (even if they arrive before a build completes).
- The minor changes to the build engine logic mean that firing additional build updates is always safe, no matter what the current state of the build is.
- The build itself is protected by a lock in the build engine.
- The target is not covered by an explicit lock, but for all states only the engine (waiting) //or// the worker (all other states) can interact with it. All of the interactions also move the target state forward to the same destination and have no other side effects.
- Messages are only consumed inside the engine lock, so they don't need an explicit lock.
Test Plan:
- Made an HTTP request wait after completion, then ran a pile of builds through it using `bin/harbormaster build` and the web UI.
- Passed and failed message-awaiting builds with `harbormaster.sendmessage`.
Reviewers: btrahan
Reviewed By: btrahan
Subscribers: epriestley, zeeg
Differential Revision: https://secure.phabricator.com/D8788
2014-04-16 22:01:46 +02:00
|
|
|
if ($is_queued) {
|
|
|
|
$queued[$step->getPHID()] = true;
|
2014-01-06 21:32:10 +01:00
|
|
|
}
|
|
|
|
|
Allow Harbormaster build targets to wait for messages
Summary:
This hooks up all the pieces of the build pipeline so `harbormaster.sendmessage` actually works. Particularly:
- Candidate build steps (i.e., those which interact with external systems) can now "Wait for Message". This pauses them indefinitely when they complete, until something calls `harbormaster.sendmessage`.
- After processing a target, we check if we should move it to PASSED or WAITING.
- Before updating a build, we move WAITING targets with pending messages to either PASSED or FAILED.
- I added an explicit "Building" state, which doesn't affect workflows but communicates more information to human users.
A big part of this is avoiding races. I believe we get the correct behavior no matter which order events occur in:
- We update builds after targets complete and after we receive messages, so we're guaranteed to update once both these conditions are true. This means messages can't be lost (even if they arrive before a build completes).
- The minor changes to the build engine logic mean that firing additional build updates is always safe, no matter what the current state of the build is.
- The build itself is protected by a lock in the build engine.
- The target is not covered by an explicit lock, but for all states only the engine (waiting) //or// the worker (all other states) can interact with it. All of the interactions also move the target state forward to the same destination and have no other side effects.
- Messages are only consumed inside the engine lock, so they don't need an explicit lock.
Test Plan:
- Made an HTTP request wait after completion, then ran a pile of builds through it using `bin/harbormaster build` and the web UI.
- Passed and failed message-awaiting builds with `harbormaster.sendmessage`.
Reviewers: btrahan
Reviewed By: btrahan
Subscribers: epriestley, zeeg
Differential Revision: https://secure.phabricator.com/D8788
2014-04-16 22:01:46 +02:00
|
|
|
if ($is_underway) {
|
|
|
|
$underway[$step->getPHID()] = true;
|
2014-01-06 21:32:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if ($is_waiting) {
|
|
|
|
$waiting[$step->getPHID()] = true;
|
|
|
|
}
|
Allow Harbormaster build targets to wait for messages
Summary:
This hooks up all the pieces of the build pipeline so `harbormaster.sendmessage` actually works. Particularly:
- Candidate build steps (i.e., those which interact with external systems) can now "Wait for Message". This pauses them indefinitely when they complete, until something calls `harbormaster.sendmessage`.
- After processing a target, we check if we should move it to PASSED or WAITING.
- Before updating a build, we move WAITING targets with pending messages to either PASSED or FAILED.
- I added an explicit "Building" state, which doesn't affect workflows but communicates more information to human users.
A big part of this is avoiding races. I believe we get the correct behavior no matter which order events occur in:
- We update builds after targets complete and after we receive messages, so we're guaranteed to update once both these conditions are true. This means messages can't be lost (even if they arrive before a build completes).
- The minor changes to the build engine logic mean that firing additional build updates is always safe, no matter what the current state of the build is.
- The build itself is protected by a lock in the build engine.
- The target is not covered by an explicit lock, but for all states only the engine (waiting) //or// the worker (all other states) can interact with it. All of the interactions also move the target state forward to the same destination and have no other side effects.
- Messages are only consumed inside the engine lock, so they don't need an explicit lock.
Test Plan:
- Made an HTTP request wait after completion, then ran a pile of builds through it using `bin/harbormaster build` and the web UI.
- Passed and failed message-awaiting builds with `harbormaster.sendmessage`.
Reviewers: btrahan
Reviewed By: btrahan
Subscribers: epriestley, zeeg
Differential Revision: https://secure.phabricator.com/D8788
2014-04-16 22:01:46 +02:00
|
|
|
|
|
|
|
if ($is_complete) {
|
|
|
|
$complete[$step->getPHID()] = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($is_failed) {
|
|
|
|
$failed[$step->getPHID()] = true;
|
|
|
|
}
|
2014-01-06 21:32:10 +01:00
|
|
|
}
|
|
|
|
|
2014-01-13 21:21:49 +01:00
|
|
|
// If any step failed, fail the whole build, then bail.
|
|
|
|
if (count($failed)) {
|
|
|
|
$build->setBuildStatus(HarbormasterBuild::STATUS_FAILED);
|
2014-01-06 21:32:10 +01:00
|
|
|
$build->save();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-01-13 21:21:49 +01:00
|
|
|
// 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);
|
2014-01-06 21:32:10 +01:00
|
|
|
$build->save();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Identify all the steps which are ready to run (because all their
|
2014-07-23 02:03:09 +02:00
|
|
|
// dependencies are complete).
|
2014-01-06 21:32:10 +01:00
|
|
|
|
|
|
|
$runnable = array();
|
|
|
|
foreach ($steps as $step) {
|
2014-07-31 03:39:49 +02:00
|
|
|
$dependencies = $step->getStepImplementation()->getDependencies($step);
|
2014-01-06 21:32:10 +01:00
|
|
|
|
Allow Harbormaster build targets to wait for messages
Summary:
This hooks up all the pieces of the build pipeline so `harbormaster.sendmessage` actually works. Particularly:
- Candidate build steps (i.e., those which interact with external systems) can now "Wait for Message". This pauses them indefinitely when they complete, until something calls `harbormaster.sendmessage`.
- After processing a target, we check if we should move it to PASSED or WAITING.
- Before updating a build, we move WAITING targets with pending messages to either PASSED or FAILED.
- I added an explicit "Building" state, which doesn't affect workflows but communicates more information to human users.
A big part of this is avoiding races. I believe we get the correct behavior no matter which order events occur in:
- We update builds after targets complete and after we receive messages, so we're guaranteed to update once both these conditions are true. This means messages can't be lost (even if they arrive before a build completes).
- The minor changes to the build engine logic mean that firing additional build updates is always safe, no matter what the current state of the build is.
- The build itself is protected by a lock in the build engine.
- The target is not covered by an explicit lock, but for all states only the engine (waiting) //or// the worker (all other states) can interact with it. All of the interactions also move the target state forward to the same destination and have no other side effects.
- Messages are only consumed inside the engine lock, so they don't need an explicit lock.
Test Plan:
- Made an HTTP request wait after completion, then ran a pile of builds through it using `bin/harbormaster build` and the web UI.
- Passed and failed message-awaiting builds with `harbormaster.sendmessage`.
Reviewers: btrahan
Reviewed By: btrahan
Subscribers: epriestley, zeeg
Differential Revision: https://secure.phabricator.com/D8788
2014-04-16 22:01:46 +02:00
|
|
|
if (isset($queued[$step->getPHID()])) {
|
2014-01-06 21:32:10 +01:00
|
|
|
$can_run = true;
|
|
|
|
foreach ($dependencies as $dependency) {
|
2014-07-31 03:39:49 +02:00
|
|
|
if (empty($complete[$dependency])) {
|
2014-01-06 21:32:10 +01:00
|
|
|
$can_run = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($can_run) {
|
|
|
|
$runnable[] = $step;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Allow Harbormaster build targets to wait for messages
Summary:
This hooks up all the pieces of the build pipeline so `harbormaster.sendmessage` actually works. Particularly:
- Candidate build steps (i.e., those which interact with external systems) can now "Wait for Message". This pauses them indefinitely when they complete, until something calls `harbormaster.sendmessage`.
- After processing a target, we check if we should move it to PASSED or WAITING.
- Before updating a build, we move WAITING targets with pending messages to either PASSED or FAILED.
- I added an explicit "Building" state, which doesn't affect workflows but communicates more information to human users.
A big part of this is avoiding races. I believe we get the correct behavior no matter which order events occur in:
- We update builds after targets complete and after we receive messages, so we're guaranteed to update once both these conditions are true. This means messages can't be lost (even if they arrive before a build completes).
- The minor changes to the build engine logic mean that firing additional build updates is always safe, no matter what the current state of the build is.
- The build itself is protected by a lock in the build engine.
- The target is not covered by an explicit lock, but for all states only the engine (waiting) //or// the worker (all other states) can interact with it. All of the interactions also move the target state forward to the same destination and have no other side effects.
- Messages are only consumed inside the engine lock, so they don't need an explicit lock.
Test Plan:
- Made an HTTP request wait after completion, then ran a pile of builds through it using `bin/harbormaster build` and the web UI.
- Passed and failed message-awaiting builds with `harbormaster.sendmessage`.
Reviewers: btrahan
Reviewed By: btrahan
Subscribers: epriestley, zeeg
Differential Revision: https://secure.phabricator.com/D8788
2014-04-16 22:01:46 +02:00
|
|
|
if (!$runnable && !$waiting && !$underway) {
|
2014-07-31 03:39:49 +02:00
|
|
|
// This means the build is deadlocked, and the user has configured
|
|
|
|
// circular dependencies.
|
|
|
|
$build->setBuildStatus(HarbormasterBuild::STATUS_DEADLOCKED);
|
2014-01-06 21:32:10 +01:00
|
|
|
$build->save();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach ($runnable as $runnable_step) {
|
|
|
|
$target = HarbormasterBuildTarget::initializeNewBuildTarget(
|
|
|
|
$build,
|
Replace "Cancel Build" with "Stop", "Resume" and "Restart"
Summary:
Ref T1049. Currently you can cancel a build, but now that we're tracking a lot more state we can stop, resume, and restart builds.
When the user issues a command against a build, I'm writing it into an auxiliary queue (`HarbormasterBuildCommand`) and then reading them out in the worker. This is mostly to avoid race messes where we try to `save()` the object in multiple places: basically, the BuildEngine is the //only// thing that writes to Build objects, and it holds a lock while it does it.
Test Plan:
- Created a plan which runs "sleep 2" a bunch of times in a row.
- Stopped, resumed, and restarted it.
Reviewers: btrahan
Reviewed By: btrahan
CC: aran, chad
Maniphest Tasks: T1049
Differential Revision: https://secure.phabricator.com/D7892
2014-01-06 21:32:20 +01:00
|
|
|
$runnable_step,
|
2014-01-06 21:32:10 +01:00
|
|
|
$build->retrieveVariablesFromBuild());
|
|
|
|
$target->save();
|
|
|
|
|
|
|
|
$this->queueNewBuildTarget($target);
|
|
|
|
}
|
Allow Harbormaster build targets to wait for messages
Summary:
This hooks up all the pieces of the build pipeline so `harbormaster.sendmessage` actually works. Particularly:
- Candidate build steps (i.e., those which interact with external systems) can now "Wait for Message". This pauses them indefinitely when they complete, until something calls `harbormaster.sendmessage`.
- After processing a target, we check if we should move it to PASSED or WAITING.
- Before updating a build, we move WAITING targets with pending messages to either PASSED or FAILED.
- I added an explicit "Building" state, which doesn't affect workflows but communicates more information to human users.
A big part of this is avoiding races. I believe we get the correct behavior no matter which order events occur in:
- We update builds after targets complete and after we receive messages, so we're guaranteed to update once both these conditions are true. This means messages can't be lost (even if they arrive before a build completes).
- The minor changes to the build engine logic mean that firing additional build updates is always safe, no matter what the current state of the build is.
- The build itself is protected by a lock in the build engine.
- The target is not covered by an explicit lock, but for all states only the engine (waiting) //or// the worker (all other states) can interact with it. All of the interactions also move the target state forward to the same destination and have no other side effects.
- Messages are only consumed inside the engine lock, so they don't need an explicit lock.
Test Plan:
- Made an HTTP request wait after completion, then ran a pile of builds through it using `bin/harbormaster build` and the web UI.
- Passed and failed message-awaiting builds with `harbormaster.sendmessage`.
Reviewers: btrahan
Reviewed By: btrahan
Subscribers: epriestley, zeeg
Differential Revision: https://secure.phabricator.com/D8788
2014-04-16 22:01:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Process messages which were sent to these targets, kicking applicable
|
|
|
|
* targets out of "Waiting" and into either "Passed" or "Failed".
|
|
|
|
*
|
|
|
|
* @param list<HarbormasterBuildTarget> List of targets to process.
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
private function updateWaitingTargets(array $targets) {
|
|
|
|
assert_instances_of($targets, 'HarbormasterBuildTarget');
|
|
|
|
|
|
|
|
// We only care about messages for targets which are actually in a waiting
|
|
|
|
// state.
|
|
|
|
$waiting_targets = array();
|
|
|
|
foreach ($targets as $target) {
|
|
|
|
if ($target->isWaiting()) {
|
|
|
|
$waiting_targets[$target->getPHID()] = $target;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!$waiting_targets) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
$messages = id(new HarbormasterBuildMessageQuery())
|
|
|
|
->setViewer($this->getViewer())
|
|
|
|
->withBuildTargetPHIDs(array_keys($waiting_targets))
|
|
|
|
->withConsumed(false)
|
|
|
|
->execute();
|
|
|
|
|
|
|
|
foreach ($messages as $message) {
|
|
|
|
$target = $waiting_targets[$message->getBuildTargetPHID()];
|
|
|
|
|
|
|
|
switch ($message->getType()) {
|
2015-08-04 22:05:52 +02:00
|
|
|
case HarbormasterMessageType::MESSAGE_PASS:
|
Allow Harbormaster build targets to wait for messages
Summary:
This hooks up all the pieces of the build pipeline so `harbormaster.sendmessage` actually works. Particularly:
- Candidate build steps (i.e., those which interact with external systems) can now "Wait for Message". This pauses them indefinitely when they complete, until something calls `harbormaster.sendmessage`.
- After processing a target, we check if we should move it to PASSED or WAITING.
- Before updating a build, we move WAITING targets with pending messages to either PASSED or FAILED.
- I added an explicit "Building" state, which doesn't affect workflows but communicates more information to human users.
A big part of this is avoiding races. I believe we get the correct behavior no matter which order events occur in:
- We update builds after targets complete and after we receive messages, so we're guaranteed to update once both these conditions are true. This means messages can't be lost (even if they arrive before a build completes).
- The minor changes to the build engine logic mean that firing additional build updates is always safe, no matter what the current state of the build is.
- The build itself is protected by a lock in the build engine.
- The target is not covered by an explicit lock, but for all states only the engine (waiting) //or// the worker (all other states) can interact with it. All of the interactions also move the target state forward to the same destination and have no other side effects.
- Messages are only consumed inside the engine lock, so they don't need an explicit lock.
Test Plan:
- Made an HTTP request wait after completion, then ran a pile of builds through it using `bin/harbormaster build` and the web UI.
- Passed and failed message-awaiting builds with `harbormaster.sendmessage`.
Reviewers: btrahan
Reviewed By: btrahan
Subscribers: epriestley, zeeg
Differential Revision: https://secure.phabricator.com/D8788
2014-04-16 22:01:46 +02:00
|
|
|
$new_status = HarbormasterBuildTarget::STATUS_PASSED;
|
|
|
|
break;
|
2015-08-04 22:05:52 +02:00
|
|
|
case HarbormasterMessageType::MESSAGE_FAIL:
|
Allow Harbormaster build targets to wait for messages
Summary:
This hooks up all the pieces of the build pipeline so `harbormaster.sendmessage` actually works. Particularly:
- Candidate build steps (i.e., those which interact with external systems) can now "Wait for Message". This pauses them indefinitely when they complete, until something calls `harbormaster.sendmessage`.
- After processing a target, we check if we should move it to PASSED or WAITING.
- Before updating a build, we move WAITING targets with pending messages to either PASSED or FAILED.
- I added an explicit "Building" state, which doesn't affect workflows but communicates more information to human users.
A big part of this is avoiding races. I believe we get the correct behavior no matter which order events occur in:
- We update builds after targets complete and after we receive messages, so we're guaranteed to update once both these conditions are true. This means messages can't be lost (even if they arrive before a build completes).
- The minor changes to the build engine logic mean that firing additional build updates is always safe, no matter what the current state of the build is.
- The build itself is protected by a lock in the build engine.
- The target is not covered by an explicit lock, but for all states only the engine (waiting) //or// the worker (all other states) can interact with it. All of the interactions also move the target state forward to the same destination and have no other side effects.
- Messages are only consumed inside the engine lock, so they don't need an explicit lock.
Test Plan:
- Made an HTTP request wait after completion, then ran a pile of builds through it using `bin/harbormaster build` and the web UI.
- Passed and failed message-awaiting builds with `harbormaster.sendmessage`.
Reviewers: btrahan
Reviewed By: btrahan
Subscribers: epriestley, zeeg
Differential Revision: https://secure.phabricator.com/D8788
2014-04-16 22:01:46 +02:00
|
|
|
$new_status = HarbormasterBuildTarget::STATUS_FAILED;
|
|
|
|
break;
|
2015-08-04 22:05:52 +02:00
|
|
|
case HarbormasterMessageType::MESSAGE_WORK:
|
|
|
|
default:
|
|
|
|
$new_status = null;
|
|
|
|
break;
|
Allow Harbormaster build targets to wait for messages
Summary:
This hooks up all the pieces of the build pipeline so `harbormaster.sendmessage` actually works. Particularly:
- Candidate build steps (i.e., those which interact with external systems) can now "Wait for Message". This pauses them indefinitely when they complete, until something calls `harbormaster.sendmessage`.
- After processing a target, we check if we should move it to PASSED or WAITING.
- Before updating a build, we move WAITING targets with pending messages to either PASSED or FAILED.
- I added an explicit "Building" state, which doesn't affect workflows but communicates more information to human users.
A big part of this is avoiding races. I believe we get the correct behavior no matter which order events occur in:
- We update builds after targets complete and after we receive messages, so we're guaranteed to update once both these conditions are true. This means messages can't be lost (even if they arrive before a build completes).
- The minor changes to the build engine logic mean that firing additional build updates is always safe, no matter what the current state of the build is.
- The build itself is protected by a lock in the build engine.
- The target is not covered by an explicit lock, but for all states only the engine (waiting) //or// the worker (all other states) can interact with it. All of the interactions also move the target state forward to the same destination and have no other side effects.
- Messages are only consumed inside the engine lock, so they don't need an explicit lock.
Test Plan:
- Made an HTTP request wait after completion, then ran a pile of builds through it using `bin/harbormaster build` and the web UI.
- Passed and failed message-awaiting builds with `harbormaster.sendmessage`.
Reviewers: btrahan
Reviewed By: btrahan
Subscribers: epriestley, zeeg
Differential Revision: https://secure.phabricator.com/D8788
2014-04-16 22:01:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if ($new_status !== null) {
|
|
|
|
$message->setIsConsumed(true);
|
|
|
|
$message->save();
|
|
|
|
|
|
|
|
$target->setTargetStatus($new_status);
|
2015-06-21 22:45:38 +02:00
|
|
|
|
|
|
|
if ($target->isComplete()) {
|
|
|
|
$target->setDateCompleted(PhabricatorTime::getNow());
|
|
|
|
}
|
|
|
|
|
Allow Harbormaster build targets to wait for messages
Summary:
This hooks up all the pieces of the build pipeline so `harbormaster.sendmessage` actually works. Particularly:
- Candidate build steps (i.e., those which interact with external systems) can now "Wait for Message". This pauses them indefinitely when they complete, until something calls `harbormaster.sendmessage`.
- After processing a target, we check if we should move it to PASSED or WAITING.
- Before updating a build, we move WAITING targets with pending messages to either PASSED or FAILED.
- I added an explicit "Building" state, which doesn't affect workflows but communicates more information to human users.
A big part of this is avoiding races. I believe we get the correct behavior no matter which order events occur in:
- We update builds after targets complete and after we receive messages, so we're guaranteed to update once both these conditions are true. This means messages can't be lost (even if they arrive before a build completes).
- The minor changes to the build engine logic mean that firing additional build updates is always safe, no matter what the current state of the build is.
- The build itself is protected by a lock in the build engine.
- The target is not covered by an explicit lock, but for all states only the engine (waiting) //or// the worker (all other states) can interact with it. All of the interactions also move the target state forward to the same destination and have no other side effects.
- Messages are only consumed inside the engine lock, so they don't need an explicit lock.
Test Plan:
- Made an HTTP request wait after completion, then ran a pile of builds through it using `bin/harbormaster build` and the web UI.
- Passed and failed message-awaiting builds with `harbormaster.sendmessage`.
Reviewers: btrahan
Reviewed By: btrahan
Subscribers: epriestley, zeeg
Differential Revision: https://secure.phabricator.com/D8788
2014-04-16 22:01:46 +02:00
|
|
|
$target->save();
|
|
|
|
}
|
|
|
|
}
|
2014-01-06 21:32:10 +01:00
|
|
|
}
|
|
|
|
|
2014-04-18 01:01:16 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Update the overall status of the buildable this build is attached to.
|
|
|
|
*
|
|
|
|
* After a build changes state (for example, passes or fails) it may affect
|
|
|
|
* the overall state of the associated buildable. Compute the new aggregate
|
|
|
|
* state and save it on the buildable.
|
|
|
|
*
|
|
|
|
* @param HarbormasterBuild The buildable to update.
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
private function updateBuildable(HarbormasterBuildable $buildable) {
|
2014-04-18 01:04:14 +02:00
|
|
|
$viewer = $this->getViewer();
|
|
|
|
|
2014-04-18 01:01:16 +02:00
|
|
|
$lock_key = 'harbormaster.buildable:'.$buildable->getID();
|
|
|
|
$lock = PhabricatorGlobalLock::newLock($lock_key)->lock(15);
|
|
|
|
|
|
|
|
$buildable = id(new HarbormasterBuildableQuery())
|
2014-04-18 01:04:14 +02:00
|
|
|
->setViewer($viewer)
|
2014-04-18 01:01:16 +02:00
|
|
|
->withIDs(array($buildable->getID()))
|
|
|
|
->needBuilds(true)
|
|
|
|
->executeOne();
|
|
|
|
|
|
|
|
$all_pass = true;
|
|
|
|
$any_fail = false;
|
|
|
|
foreach ($buildable->getBuilds() as $build) {
|
|
|
|
if ($build->getBuildStatus() != HarbormasterBuild::STATUS_PASSED) {
|
|
|
|
$all_pass = false;
|
|
|
|
}
|
|
|
|
if ($build->getBuildStatus() == HarbormasterBuild::STATUS_FAILED ||
|
2014-07-31 03:39:49 +02:00
|
|
|
$build->getBuildStatus() == HarbormasterBuild::STATUS_ERROR ||
|
|
|
|
$build->getBuildStatus() == HarbormasterBuild::STATUS_DEADLOCKED) {
|
2014-04-18 01:01:16 +02:00
|
|
|
$any_fail = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($any_fail) {
|
|
|
|
$new_status = HarbormasterBuildable::STATUS_FAILED;
|
|
|
|
} else if ($all_pass) {
|
|
|
|
$new_status = HarbormasterBuildable::STATUS_PASSED;
|
|
|
|
} else {
|
|
|
|
$new_status = HarbormasterBuildable::STATUS_BUILDING;
|
|
|
|
}
|
|
|
|
|
2014-04-18 01:04:14 +02:00
|
|
|
$old_status = $buildable->getBuildableStatus();
|
|
|
|
$did_update = ($old_status != $new_status);
|
|
|
|
if ($did_update) {
|
2014-04-18 01:01:16 +02:00
|
|
|
$buildable->setBuildableStatus($new_status);
|
|
|
|
$buildable->save();
|
|
|
|
}
|
|
|
|
|
|
|
|
$lock->unlock();
|
2014-04-18 01:04:14 +02:00
|
|
|
|
|
|
|
// If we changed the buildable status, try to post a transaction to the
|
|
|
|
// object about it. We can safely do this outside of the locked region.
|
|
|
|
|
|
|
|
// NOTE: We only post transactions for automatic buildables, not for
|
|
|
|
// manual ones: manual builds are test builds, whoever is doing tests
|
|
|
|
// can look at the results themselves, and other users generally don't
|
|
|
|
// care about the outcome.
|
|
|
|
|
2014-05-15 16:02:30 +02:00
|
|
|
$should_publish = $did_update &&
|
|
|
|
$new_status != HarbormasterBuildable::STATUS_BUILDING &&
|
|
|
|
!$buildable->getIsManualBuildable();
|
2015-06-25 19:05:37 +02:00
|
|
|
|
|
|
|
if (!$should_publish) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
$object = id(new PhabricatorObjectQuery())
|
|
|
|
->setViewer($viewer)
|
|
|
|
->withPHIDs(array($buildable->getBuildablePHID()))
|
|
|
|
->executeOne();
|
|
|
|
if (!$object) {
|
|
|
|
return;
|
2014-04-18 01:04:14 +02:00
|
|
|
}
|
2015-06-25 19:05:37 +02:00
|
|
|
|
|
|
|
if (!($object instanceof PhabricatorApplicationTransactionInterface)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: Publishing these transactions is causing a race. See T8650.
|
|
|
|
// We shouldn't be publishing to diffs anyway.
|
|
|
|
if ($object instanceof DifferentialDiff) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
$template = $object->getApplicationTransactionTemplate();
|
|
|
|
if (!$template) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
$template
|
|
|
|
->setTransactionType(PhabricatorTransactions::TYPE_BUILDABLE)
|
|
|
|
->setMetadataValue(
|
|
|
|
'harbormaster:buildablePHID',
|
|
|
|
$buildable->getPHID())
|
|
|
|
->setOldValue($old_status)
|
|
|
|
->setNewValue($new_status);
|
|
|
|
|
|
|
|
$harbormaster_phid = id(new PhabricatorHarbormasterApplication())
|
|
|
|
->getPHID();
|
|
|
|
|
|
|
|
$daemon_source = PhabricatorContentSource::newForSource(
|
|
|
|
PhabricatorContentSource::SOURCE_DAEMON,
|
|
|
|
array());
|
|
|
|
|
|
|
|
$editor = $object->getApplicationTransactionEditor()
|
|
|
|
->setActor($viewer)
|
|
|
|
->setActingAsPHID($harbormaster_phid)
|
|
|
|
->setContentSource($daemon_source)
|
|
|
|
->setContinueOnNoEffect(true)
|
|
|
|
->setContinueOnMissingFields(true);
|
|
|
|
|
|
|
|
$editor->applyTransactions(
|
|
|
|
$object->getApplicationTransactionObject(),
|
|
|
|
array($template));
|
2014-04-18 01:01:16 +02:00
|
|
|
}
|
|
|
|
|
2014-08-12 01:15:16 +02:00
|
|
|
private function releaseAllArtifacts(HarbormasterBuild $build) {
|
|
|
|
$targets = id(new HarbormasterBuildTargetQuery())
|
|
|
|
->setViewer(PhabricatorUser::getOmnipotentUser())
|
|
|
|
->withBuildPHIDs(array($build->getPHID()))
|
2014-08-21 14:55:24 +02:00
|
|
|
->withBuildGenerations(array($build->getBuildGeneration()))
|
2014-08-12 01:15:16 +02:00
|
|
|
->execute();
|
|
|
|
|
|
|
|
if (count($targets) === 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
$target_phids = mpull($targets, 'getPHID');
|
|
|
|
|
|
|
|
$artifacts = id(new HarbormasterBuildArtifactQuery())
|
|
|
|
->setViewer(PhabricatorUser::getOmnipotentUser())
|
|
|
|
->withBuildTargetPHIDs($target_phids)
|
|
|
|
->execute();
|
|
|
|
|
|
|
|
foreach ($artifacts as $artifact) {
|
Add `harbormaster.createartifact`
Summary:
Ref T8659. In the general case, this eventually allows build processes to do things like:
- Upload build results (like a ".app" or ".exe" or other binary).
- Pass complex results between build steps (e.g., build step A does something hard and build step B uses it to do something else).
Today, we're a long way away from having the infrastructure for that. However, it is useful to let third party build processes (like Jenkins) upload URIs that link back to the external build results.
This adds `harbormaster.createartifact` so they can do that. The only useful thing to do with this method today is have your Jenkins build do this:
params = array(
"uri": "https://jenkins.mycompany.com/build/23923/details/",
"name": "View Build Results in Jenkins",
"ui.external": true,
);
harbormaster.createartifact(target, 'uri', params);
Then (after the next diff) we'll show a link in Differential and a prominent link in Harbormaster. I didn't actually do the UI stuff in this diff since it's already pretty big.
This change moves a lot of code around, too:
- Adds PHIDs to artifacts.
- It modularizes build artifact types (currently "file", "host" and "URI").
- It formalizes build artifact parameters and construction:
- This lets me generate usable documentation about how to create artifacts.
- This prevents users from doing dangerous or policy-violating things.
- It does some other general modernization.
Test Plan:
{F715633}
{F715634}
Reviewers: chad
Reviewed By: chad
Maniphest Tasks: T8659
Differential Revision: https://secure.phabricator.com/D13900
2015-08-15 16:28:56 +02:00
|
|
|
$artifact->releaseArtifact();
|
2014-08-12 01:15:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2014-01-06 21:32:10 +01:00
|
|
|
}
|