mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-22 21:40:55 +01:00
Allow "harbormaster.sendmessage" to send control command (pause, restart, abort, resume) to Builds/Buildables
Summary: Ref T13072. Expand the role of "harbormaster.sendmessage" and allow it to send control messages to Builds and Buildables. Test Plan: Read documentation, sent commands to Builds and Buildables, hit a bunch of error cases, will deploy to catch full-lifecycle Build Target use cases. Subscribers: PHID-OPKG-gm6ozazyms6q6i22gyam Maniphest Tasks: T13072 Differential Revision: https://secure.phabricator.com/D21698
This commit is contained in:
parent
3df1e17527
commit
4c4123f98b
7 changed files with 559 additions and 113 deletions
|
@ -9,18 +9,222 @@ final class HarbormasterSendMessageConduitAPIMethod
|
|||
|
||||
public function getMethodSummary() {
|
||||
return pht(
|
||||
'Send a message about the status of a build target to Harbormaster, '.
|
||||
'notifying the application of build results in an external system.');
|
||||
'Modify running builds, and report build results.');
|
||||
}
|
||||
|
||||
public function getMethodDescription() {
|
||||
return pht(<<<EOREMARKUP
|
||||
Pause, abort, restart, and report results for builds.
|
||||
EOREMARKUP
|
||||
);
|
||||
}
|
||||
|
||||
protected function newDocumentationPages(PhabricatorUser $viewer) {
|
||||
$pages = array();
|
||||
|
||||
$pages[] = $this->newSendingDocumentationBoxPage($viewer);
|
||||
$pages[] = $this->newBuildsDocumentationBoxPage($viewer);
|
||||
$pages[] = $this->newCommandsDocumentationBoxPage($viewer);
|
||||
$pages[] = $this->newTargetsDocumentationBoxPage($viewer);
|
||||
$pages[] = $this->newUnitDocumentationBoxPage($viewer);
|
||||
$pages[] = $this->newLintDocumentationBoxPage($viewer);
|
||||
|
||||
return $pages;
|
||||
}
|
||||
|
||||
private function newSendingDocumentationBoxPage(PhabricatorUser $viewer) {
|
||||
$title = pht('Sending Messages');
|
||||
$content = pht(<<<EOREMARKUP
|
||||
Harbormaster build objects work somewhat differently from objects in many other
|
||||
applications. Most application objects can be edited directly using synchronous
|
||||
APIs (like `maniphest.edit`, `differential.revision.edit`, and so on).
|
||||
|
||||
However, builds require long-running background processing and Habormaster
|
||||
objects have a more complex lifecycle than most other application objects and
|
||||
may spend significant periods of time locked by daemon processes during build
|
||||
execition. A synchronous edit might need to wait an arbitrarily long amount of
|
||||
time for this lock to become available so the edit could be applied.
|
||||
|
||||
Additionally, some edits may also require an arbitrarily long amount of time to
|
||||
//complete//. For example, aborting a build may execute cleanup steps which
|
||||
take minutes (or even hours) to complete.
|
||||
|
||||
Since a synchronous API could not guarantee it could return results to the
|
||||
caller in a reasonable amount of time, the edit API for Harbormaster build
|
||||
objects is asynchronous: to update a Harbormaster build or build target, use
|
||||
this API (`harbormaster.sendmessage`) to send it a message describing an edit
|
||||
you would like to effect or additional information you want to provide.
|
||||
The message will be processed by the daemons once the build or target reaches
|
||||
a suitable state to receive messages.
|
||||
|
||||
Select an object to send a message to using the `receiver` parameter. This
|
||||
API method can send messages to multiple types of objects:
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Object Type</th>
|
||||
<th>PHID Example</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Harbormaster Buildable</td>
|
||||
<td>`PHID-HMBB-...`</td>
|
||||
<td>%s</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Harbormaster Build</td>
|
||||
<td>`PHID-HMBD-...`</td>
|
||||
<td>%s</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Harbormaster Build Target</td>
|
||||
<td>`PHID-HMBT-...`</td>
|
||||
<td>%s</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
See below for specifics on sending messages to different object types.
|
||||
EOREMARKUP
|
||||
,
|
||||
pht(
|
||||
'Buildables may receive control commands like "abort" and "restart". '.
|
||||
'Sending a control command to a Buildable is the same as sending it '.
|
||||
'to each Build for the Buildable.'),
|
||||
pht(
|
||||
'Builds may receive control commands like "pause", "resume", "abort", '.
|
||||
'and "restart".'),
|
||||
pht(
|
||||
'Build Targets may receive build status and result messages, like '.
|
||||
'"pass" or "fail".'));
|
||||
|
||||
$content = $this->newRemarkupDocumentationView($content);
|
||||
|
||||
return $this->newDocumentationBoxPage($viewer, $title, $content)
|
||||
->setAnchor('sending')
|
||||
->setIconIcon('fa-envelope-o');
|
||||
}
|
||||
|
||||
private function newBuildsDocumentationBoxPage(PhabricatorUser $viewer) {
|
||||
$title = pht('Updating Builds');
|
||||
|
||||
$content = pht(<<<EOREMARKUP
|
||||
You can use this method (`harbormaster.sendmessage`) to send control commands
|
||||
to Buildables and Builds.
|
||||
|
||||
Specify the Build or Buildable to receive the control command by providing its
|
||||
PHID in the `receiver` parameter.
|
||||
|
||||
Sending a control command to a Buildable has the same effect as sending it to
|
||||
each Build for the Buildable. For example, sending a "Pause" message to a
|
||||
Buildable will pause all builds for the Buildable (or at least attempt to).
|
||||
|
||||
When sending control commands, the `unit` and `lint` parameters of this API
|
||||
method must be omitted. You can not report lint or unit results directly to
|
||||
a Build or Buildable, and can not report them alongside a control command.
|
||||
|
||||
More broadly, you can not report build results directly to a Build or
|
||||
Buildable. Instead, report results to a Build Target.
|
||||
|
||||
See below for a list of control commands.
|
||||
|
||||
EOREMARKUP
|
||||
);
|
||||
|
||||
$content = $this->newRemarkupDocumentationView($content);
|
||||
|
||||
return $this->newDocumentationBoxPage($viewer, $title, $content)
|
||||
->setAnchor('builds')
|
||||
->setIconIcon('fa-cubes');
|
||||
}
|
||||
|
||||
private function newCommandsDocumentationBoxPage(PhabricatorUser $viewer) {
|
||||
$messages = HarbormasterBuildMessageTransaction::getAllMessages();
|
||||
|
||||
$rows = array();
|
||||
|
||||
$rows[] = '<tr>';
|
||||
$rows[] = '<th>'.pht('Message Type').'</th>';
|
||||
$rows[] = '<th>'.pht('Description').'</th>';
|
||||
$rows[] = '</tr>';
|
||||
|
||||
foreach ($messages as $message) {
|
||||
$row = array();
|
||||
|
||||
$row[] = sprintf(
|
||||
'<td>`%s`</td>',
|
||||
$message->getHarbormasterBuildMessageType());
|
||||
|
||||
$row[] = sprintf(
|
||||
'<td>%s</td>',
|
||||
$message->getHarbormasterBuildMessageDescription());
|
||||
|
||||
$rows[] = sprintf(
|
||||
'<tr>%s</tr>',
|
||||
implode("\n", $row));
|
||||
}
|
||||
|
||||
$message_table = sprintf(
|
||||
'<table>%s</table>',
|
||||
implode("\n", $rows));
|
||||
|
||||
$title = pht('Control Commands');
|
||||
|
||||
$content = pht(<<<EOREMARKUP
|
||||
You can use this method to send control commands to Buildables and Builds.
|
||||
|
||||
This table summarizes which object types may receive control commands:
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Object Type</th>
|
||||
<th>PHID Example</th>
|
||||
<th />
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Harbormaster Buildable</td>
|
||||
<td>`PHID-HMBB-...`</td>
|
||||
<td>{icon check color=green}</td>
|
||||
<td>Buildables may receive control commands.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Harbormaster Build</td>
|
||||
<td>`PHID-HMBD-...`</td>
|
||||
<td>{icon check color=green}</td>
|
||||
<td>Builds may receive control commands.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Harbormaster Build Target</td>
|
||||
<td>`PHID-HMBT-...`</td>
|
||||
<td>{icon times color=red}</td>
|
||||
<td>You may **NOT** send control commands to build targets.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
You can send these commands:
|
||||
|
||||
%s
|
||||
|
||||
To send a command message, specify the PHID of the object you would like to
|
||||
receive the message using the `receiver` parameter, and specify the message
|
||||
type using the `type` parameter.
|
||||
|
||||
EOREMARKUP
|
||||
,
|
||||
$message_table);
|
||||
|
||||
$content = $this->newRemarkupDocumentationView($content);
|
||||
|
||||
return $this->newDocumentationBoxPage($viewer, $title, $content)
|
||||
->setAnchor('commands')
|
||||
->setIconIcon('fa-exclamation-triangle');
|
||||
}
|
||||
|
||||
private function newTargetsDocumentationBoxPage(PhabricatorUser $viewer) {
|
||||
$messages = HarbormasterMessageType::getAllMessages();
|
||||
|
||||
$head_type = pht('Constant');
|
||||
$head_desc = pht('Description');
|
||||
$head_key = pht('Key');
|
||||
$head_type = pht('Type');
|
||||
$head_name = pht('Name');
|
||||
$head_desc = pht('Description');
|
||||
|
||||
$rows = array();
|
||||
$rows[] = "| {$head_type} | {$head_desc} |";
|
||||
|
@ -31,6 +235,84 @@ final class HarbormasterSendMessageConduitAPIMethod
|
|||
}
|
||||
$message_table = implode("\n", $rows);
|
||||
|
||||
$content = pht(<<<EOREMARKUP
|
||||
If you run external builds, you can use this method to publish build results
|
||||
back into Harbormaster after the external system finishes work (or as it makes
|
||||
progress).
|
||||
|
||||
To report build status or results, you must send a message to the appropriate
|
||||
Build Target. This table summarizes which object types may receive build status
|
||||
and result messages:
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Object Type</th>
|
||||
<th>PHID Example</th>
|
||||
<th />
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Harbormaster Buildable</td>
|
||||
<td>`PHID-HMBB-...`</td>
|
||||
<td>{icon times color=red}</td>
|
||||
<td>Buildables may **NOT** receive status or result messages.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Harbormaster Build</td>
|
||||
<td>`PHID-HMBD-...`</td>
|
||||
<td>{icon times color=red}</td>
|
||||
<td>Builds may **NOT** receive status or result messages.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Harbormaster Build Target</td>
|
||||
<td>`PHID-HMBT-...`</td>
|
||||
<td>{icon check color=green}</td>
|
||||
<td>Report build status and results to Build Targets.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
The simplest way to use this method to report build results is to call it once
|
||||
after the build finishes with a `pass` or `fail` message. This will record the
|
||||
build result, and continue the next step in the build if the build was waiting
|
||||
for a result.
|
||||
|
||||
When you send a status message about a build target, you can optionally include
|
||||
detailed `lint` or `unit` results alongside the message. See below for details.
|
||||
|
||||
If you want to report intermediate results but a build hasn't completed yet,
|
||||
you can use the `work` message. This message doesn't have any direct effects,
|
||||
but allows you to send additional data to update the progress of the build
|
||||
target. The target will continue waiting for a completion message, but the UI
|
||||
will update to show the progress which has been made.
|
||||
|
||||
When sending a message to a build target to report the status or results of
|
||||
a build, your message must include a `type` which describes the overall state
|
||||
of the build. For example, use `pass` to tell Harbormaster that a build target
|
||||
completed successfully.
|
||||
|
||||
Supported message types are:
|
||||
|
||||
%s
|
||||
|
||||
EOREMARKUP
|
||||
,
|
||||
$message_table);
|
||||
|
||||
$title = pht('Updating Build Targets');
|
||||
|
||||
$content = $this->newRemarkupDocumentationView($content);
|
||||
|
||||
return $this->newDocumentationBoxPage($viewer, $title, $content)
|
||||
->setAnchor('targets')
|
||||
->setIconIcon('fa-bullseye');
|
||||
}
|
||||
|
||||
private function newUnitDocumentationBoxPage(PhabricatorUser $viewer) {
|
||||
$head_key = pht('Key');
|
||||
$head_desc = pht('Description');
|
||||
$head_name = pht('Name');
|
||||
$head_type = pht('Type');
|
||||
|
||||
$rows = array();
|
||||
$rows[] = "| {$head_key} | {$head_type} | {$head_desc} |";
|
||||
$rows[] = '|-------------|--------------|--------------|';
|
||||
|
@ -55,6 +337,64 @@ final class HarbormasterSendMessageConduitAPIMethod
|
|||
}
|
||||
$result_table = implode("\n", $rows);
|
||||
|
||||
$valid_unit = array(
|
||||
array(
|
||||
'name' => 'PassingTest',
|
||||
'result' => ArcanistUnitTestResult::RESULT_PASS,
|
||||
),
|
||||
array(
|
||||
'name' => 'FailingTest',
|
||||
'result' => ArcanistUnitTestResult::RESULT_FAIL,
|
||||
),
|
||||
);
|
||||
|
||||
$json = new PhutilJSON();
|
||||
$valid_unit = $json->encodeAsList($valid_unit);
|
||||
|
||||
|
||||
$title = pht('Reporting Unit Results');
|
||||
|
||||
$content = pht(<<<EOREMARKUP
|
||||
You can report test results when updating the state of a build target. The
|
||||
simplest way to do this is to report all the results alongside a `pass` or
|
||||
`fail` message, but you can also send a `work` message to report intermediate
|
||||
results.
|
||||
|
||||
|
||||
To provide unit test results, pass a list of results in the `unit`
|
||||
parameter. Each result should be a dictionary with these keys:
|
||||
|
||||
%s
|
||||
|
||||
The `result` parameter recognizes these test results:
|
||||
|
||||
%s
|
||||
|
||||
This is a simple, valid value for the `unit` parameter. It reports one passing
|
||||
test and one failing test:
|
||||
|
||||
```lang=json
|
||||
%s
|
||||
```
|
||||
EOREMARKUP
|
||||
,
|
||||
$unit_table,
|
||||
$result_table,
|
||||
$valid_unit);
|
||||
|
||||
$content = $this->newRemarkupDocumentationView($content);
|
||||
|
||||
return $this->newDocumentationBoxPage($viewer, $title, $content)
|
||||
->setAnchor('unit');
|
||||
}
|
||||
|
||||
private function newLintDocumentationBoxPage(PhabricatorUser $viewer) {
|
||||
|
||||
$head_key = pht('Key');
|
||||
$head_desc = pht('Description');
|
||||
$head_name = pht('Name');
|
||||
$head_type = pht('Type');
|
||||
|
||||
$rows = array();
|
||||
$rows[] = "| {$head_key} | {$head_type} | {$head_desc} |";
|
||||
$rows[] = '|-------------|--------------|--------------|';
|
||||
|
@ -76,17 +416,6 @@ final class HarbormasterSendMessageConduitAPIMethod
|
|||
}
|
||||
$severity_table = implode("\n", $rows);
|
||||
|
||||
$valid_unit = array(
|
||||
array(
|
||||
'name' => 'PassingTest',
|
||||
'result' => ArcanistUnitTestResult::RESULT_PASS,
|
||||
),
|
||||
array(
|
||||
'name' => 'FailingTest',
|
||||
'result' => ArcanistUnitTestResult::RESULT_FAIL,
|
||||
),
|
||||
);
|
||||
|
||||
$valid_lint = array(
|
||||
array(
|
||||
'name' => pht('Syntax Error'),
|
||||
|
@ -109,104 +438,58 @@ final class HarbormasterSendMessageConduitAPIMethod
|
|||
);
|
||||
|
||||
$json = new PhutilJSON();
|
||||
$valid_unit = $json->encodeAsList($valid_unit);
|
||||
$valid_lint = $json->encodeAsList($valid_lint);
|
||||
|
||||
return pht(
|
||||
"Send a message about the status of a build target to Harbormaster, ".
|
||||
"notifying the application of build results in an external system.".
|
||||
"\n\n".
|
||||
"Sending Messages\n".
|
||||
"================\n".
|
||||
"If you run external builds, you can use this method to publish build ".
|
||||
"results back into Harbormaster after the external system finishes work ".
|
||||
"or as it makes progress.".
|
||||
"\n\n".
|
||||
"The simplest way to use this method is to call it once after the ".
|
||||
"build finishes with a `pass` or `fail` message. This will record the ".
|
||||
"build result, and continue the next step in the build if the build was ".
|
||||
"waiting for a result.".
|
||||
"\n\n".
|
||||
"When you send a status message about a build target, you can ".
|
||||
"optionally include detailed `lint` or `unit` results alongside the ".
|
||||
"message. See below for details.".
|
||||
"\n\n".
|
||||
"If you want to report intermediate results but a build hasn't ".
|
||||
"completed yet, you can use the `work` message. This message doesn't ".
|
||||
"have any direct effects, but allows you to send additional data to ".
|
||||
"update the progress of the build target. The target will continue ".
|
||||
"waiting for a completion message, but the UI will update to show the ".
|
||||
"progress which has been made.".
|
||||
"\n\n".
|
||||
"Message Types\n".
|
||||
"=============\n".
|
||||
"When you send Harbormaster a message, you must include a `type`, ".
|
||||
"which describes the overall state of the build. For example, use ".
|
||||
"`pass` to tell Harbormaster that a build completed successfully.".
|
||||
"\n\n".
|
||||
"Supported message types are:".
|
||||
"\n\n".
|
||||
"%s".
|
||||
"\n\n".
|
||||
"Unit Results\n".
|
||||
"============\n".
|
||||
"You can report test results alongside a message. The simplest way to ".
|
||||
"do this is to report all the results alongside a `pass` or `fail` ".
|
||||
"message, but you can also send a `work` message to report intermediate ".
|
||||
"results.\n\n".
|
||||
"To provide unit test results, pass a list of results in the `unit` ".
|
||||
"parameter. Each result should be a dictionary with these keys:".
|
||||
"\n\n".
|
||||
"%s".
|
||||
"\n\n".
|
||||
"The `result` parameter recognizes these test results:".
|
||||
"\n\n".
|
||||
"%s".
|
||||
"\n\n".
|
||||
"This is a simple, valid value for the `unit` parameter. It reports ".
|
||||
"one passing test and one failing test:\n\n".
|
||||
"\n\n".
|
||||
"```lang=json\n".
|
||||
"%s".
|
||||
"```".
|
||||
"\n\n".
|
||||
"Lint Results\n".
|
||||
"============\n".
|
||||
"Like unit test results, you can report lint results alongside a ".
|
||||
"message. The `lint` parameter should contain results as a list of ".
|
||||
"dictionaries with these keys:".
|
||||
"\n\n".
|
||||
"%s".
|
||||
"\n\n".
|
||||
"The `severity` parameter recognizes these severity levels:".
|
||||
"\n\n".
|
||||
"%s".
|
||||
"\n\n".
|
||||
"This is a simple, valid value for the `lint` parameter. It reports one ".
|
||||
"error and one warning:".
|
||||
"\n\n".
|
||||
"```lang=json\n".
|
||||
"%s".
|
||||
"```".
|
||||
"\n\n",
|
||||
$message_table,
|
||||
$unit_table,
|
||||
$result_table,
|
||||
$valid_unit,
|
||||
$title = pht('Reporting Lint Results');
|
||||
$content = pht(<<<EOREMARKUP
|
||||
Like unit test results, you can report lint results when updating the state
|
||||
of a build target. The `lint` parameter should contain results as a list of
|
||||
dictionaries with these keys:
|
||||
|
||||
%s
|
||||
|
||||
The `severity` parameter recognizes these severity levels:
|
||||
|
||||
%s
|
||||
|
||||
This is a simple, valid value for the `lint` parameter. It reports one error
|
||||
and one warning:
|
||||
|
||||
```lang=json
|
||||
%s
|
||||
```
|
||||
|
||||
EOREMARKUP
|
||||
,
|
||||
$lint_table,
|
||||
$severity_table,
|
||||
$valid_lint);
|
||||
|
||||
$content = $this->newRemarkupDocumentationView($content);
|
||||
|
||||
return $this->newDocumentationBoxPage($viewer, $title, $content)
|
||||
->setAnchor('lint');
|
||||
}
|
||||
|
||||
protected function defineParamTypes() {
|
||||
$messages = HarbormasterMessageType::getAllMessages();
|
||||
|
||||
$more_messages = HarbormasterBuildMessageTransaction::getAllMessages();
|
||||
$more_messages = mpull($more_messages, 'getHarbormasterBuildMessageType');
|
||||
|
||||
$messages = array_merge($messages, $more_messages);
|
||||
$messages = array_unique($messages);
|
||||
|
||||
sort($messages);
|
||||
|
||||
$type_const = $this->formatStringConstants($messages);
|
||||
|
||||
return array(
|
||||
'buildTargetPHID' => 'required phid',
|
||||
'receiver' => 'required string|phid',
|
||||
'type' => 'required '.$type_const,
|
||||
'unit' => 'optional list<wild>',
|
||||
'lint' => 'optional list<wild>',
|
||||
'buildTargetPHID' => 'deprecated optional phid',
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -215,19 +498,90 @@ final class HarbormasterSendMessageConduitAPIMethod
|
|||
}
|
||||
|
||||
protected function execute(ConduitAPIRequest $request) {
|
||||
$viewer = $request->getUser();
|
||||
$viewer = $request->getViewer();
|
||||
|
||||
$receiver_name = $request->getValue('receiver');
|
||||
|
||||
$build_target_phid = $request->getValue('buildTargetPHID');
|
||||
$message_type = $request->getValue('type');
|
||||
|
||||
$build_target = id(new HarbormasterBuildTargetQuery())
|
||||
->setViewer($viewer)
|
||||
->withPHIDs(array($build_target_phid))
|
||||
->executeOne();
|
||||
if (!$build_target) {
|
||||
throw new Exception(pht('No such build target!'));
|
||||
if ($build_target_phid !== null) {
|
||||
if ($receiver_name === null) {
|
||||
$receiver_name = $build_target_phid;
|
||||
} else {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Call specifies both "receiver" and "buildTargetPHID". '.
|
||||
'When using the modern "receiver" parameter, omit the '.
|
||||
'deprecated "buildTargetPHID" parameter.'));
|
||||
}
|
||||
}
|
||||
|
||||
if (!strlen($receiver_name)) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Call omits required "receiver" parameter. Specify the PHID '.
|
||||
'of the object you want to send a message to.'));
|
||||
}
|
||||
|
||||
$message_type = $request->getValue('type');
|
||||
if (!strlen($message_type)) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Call omits required "type" parameter. Specify the type of '.
|
||||
'message you want to send.'));
|
||||
}
|
||||
|
||||
$receiver_object = id(new PhabricatorObjectQuery())
|
||||
->setViewer($viewer)
|
||||
->withNames(array($receiver_name))
|
||||
->executeOne();
|
||||
if (!$receiver_object) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Unable to load object "%s" to receive message.',
|
||||
$receiver_name));
|
||||
}
|
||||
|
||||
$is_target = ($receiver_object instanceof HarbormasterBuildTarget);
|
||||
if ($is_target) {
|
||||
return $this->sendToTarget($request, $message_type, $receiver_object);
|
||||
}
|
||||
|
||||
if ($request->getValue('unit') !== null) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Call includes "unit" parameter. This parameter must be omitted '.
|
||||
'when the receiver is not a Build Target.'));
|
||||
}
|
||||
|
||||
if ($request->getValue('lint') !== null) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Call includes "lint" parameter. This parameter must be omitted '.
|
||||
'when the receiver is not a Build Target.'));
|
||||
}
|
||||
|
||||
$is_build = ($receiver_object instanceof HarbormasterBuild);
|
||||
if ($is_build) {
|
||||
return $this->sendToBuild($request, $message_type, $receiver_object);
|
||||
}
|
||||
|
||||
$is_buildable = ($receiver_object instanceof HarbormasterBuildable);
|
||||
if ($is_buildable) {
|
||||
return $this->sendToBuildable($request, $message_type, $receiver_object);
|
||||
}
|
||||
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Receiver object (of class "%s") is not a valid receiver.',
|
||||
get_class($receiver_object)));
|
||||
}
|
||||
|
||||
private function sendToTarget(
|
||||
ConduitAPIRequest $request,
|
||||
$message_type,
|
||||
HarbormasterBuildTarget $build_target) {
|
||||
$viewer = $request->getViewer();
|
||||
|
||||
$save = array();
|
||||
|
||||
$lint_messages = $request->getValue('lint', array());
|
||||
|
@ -270,4 +624,67 @@ final class HarbormasterSendMessageConduitAPIMethod
|
|||
return null;
|
||||
}
|
||||
|
||||
private function sendToBuild(
|
||||
ConduitAPIRequest $request,
|
||||
$message_type,
|
||||
HarbormasterBuild $build) {
|
||||
$viewer = $request->getViewer();
|
||||
|
||||
$xaction =
|
||||
HarbormasterBuildMessageTransaction::getTransactionObjectForMessageType(
|
||||
$message_type);
|
||||
if (!$xaction) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Message type "%s" is not supported.',
|
||||
$message_type));
|
||||
}
|
||||
|
||||
// NOTE: This is a slightly weaker check than we perform in the web UI.
|
||||
// We allow API callers to send a "pause" message to a pausing build,
|
||||
// for example, even though the message will have no effect.
|
||||
$xaction->assertCanApplyMessage($viewer, $build);
|
||||
|
||||
$build->sendMessage($viewer, $xaction->getHarbormasterBuildMessageType());
|
||||
}
|
||||
|
||||
private function sendToBuildable(
|
||||
ConduitAPIRequest $request,
|
||||
$message_type,
|
||||
HarbormasterBuildable $buildable) {
|
||||
$viewer = $request->getViewer();
|
||||
|
||||
$xaction =
|
||||
HarbormasterBuildMessageTransaction::getTransactionObjectForMessageType(
|
||||
$message_type);
|
||||
if (!$xaction) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Message type "%s" is not supported.',
|
||||
$message_type));
|
||||
}
|
||||
|
||||
// Reload the Buildable to load Builds.
|
||||
$buildable = id(new HarbormasterBuildableQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($buildable->getID()))
|
||||
->needBuilds(true)
|
||||
->executeOne();
|
||||
|
||||
$can_send = array();
|
||||
foreach ($buildable->getBuilds() as $build) {
|
||||
if ($xaction->canApplyMessage($viewer, $build)) {
|
||||
$can_send[] = $build;
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: This doesn't actually apply a transaction to the Buildable,
|
||||
// but that transaction is purely informational and should probably be
|
||||
// implemented as a Message.
|
||||
|
||||
foreach ($can_send as $build) {
|
||||
$build->sendMessage($viewer, $xaction->getHarbormasterBuildMessageType());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -9,7 +9,11 @@ final class HarbormasterRestartException extends Exception {
|
|||
$this->setTitle($title);
|
||||
$this->appendParagraph($body);
|
||||
|
||||
parent::__construct($title);
|
||||
parent::__construct(
|
||||
pht(
|
||||
'%s: %s',
|
||||
$title,
|
||||
$body));
|
||||
}
|
||||
|
||||
public function setTitle($title) {
|
||||
|
|
|
@ -27,6 +27,10 @@ final class HarbormasterBuildMessageAbortTransaction
|
|||
'Progress on this build will be discarded. Really abort build?');
|
||||
}
|
||||
|
||||
public function getHarbormasterBuildMessageDescription() {
|
||||
return pht('Abort the build, discarding progress.');
|
||||
}
|
||||
|
||||
public function newBuildableConfirmPromptTitle(
|
||||
array $builds,
|
||||
array $sendable) {
|
||||
|
|
|
@ -28,6 +28,11 @@ final class HarbormasterBuildMessagePauseTransaction
|
|||
'complete. You can resume the build later.');
|
||||
}
|
||||
|
||||
|
||||
public function getHarbormasterBuildMessageDescription() {
|
||||
return pht('Pause the build.');
|
||||
}
|
||||
|
||||
public function newBuildableConfirmPromptTitle(
|
||||
array $builds,
|
||||
array $sendable) {
|
||||
|
|
|
@ -28,6 +28,11 @@ final class HarbormasterBuildMessageRestartTransaction
|
|||
'Side effects of the build will occur again. Really restart build?');
|
||||
}
|
||||
|
||||
|
||||
public function getHarbormasterBuildMessageDescription() {
|
||||
return pht('Restart the build, discarding all progress.');
|
||||
}
|
||||
|
||||
public function newBuildableConfirmPromptTitle(
|
||||
array $builds,
|
||||
array $sendable) {
|
||||
|
|
|
@ -27,6 +27,10 @@ final class HarbormasterBuildMessageResumeTransaction
|
|||
'Work will continue on the build. Really resume?');
|
||||
}
|
||||
|
||||
public function getHarbormasterBuildMessageDescription() {
|
||||
return pht('Resume work on a previously paused build.');
|
||||
}
|
||||
|
||||
public function newBuildableConfirmPromptTitle(
|
||||
array $builds,
|
||||
array $sendable) {
|
||||
|
@ -77,7 +81,7 @@ final class HarbormasterBuildMessageResumeTransaction
|
|||
'You can not resume a build that uses an autoplan.'));
|
||||
}
|
||||
|
||||
if (!$build->isPaused()) {
|
||||
if (!$build->isPaused() && !$build->isPausing()) {
|
||||
throw new HarbormasterRestartException(
|
||||
pht('Unable to Resume Build'),
|
||||
pht(
|
||||
|
|
|
@ -8,6 +8,7 @@ abstract class HarbormasterBuildMessageTransaction
|
|||
}
|
||||
|
||||
abstract public function getHarbormasterBuildMessageName();
|
||||
abstract public function getHarbormasterBuildMessageDescription();
|
||||
abstract public function getHarbormasterBuildableMessageName();
|
||||
abstract public function getHarbormasterBuildableMessageEffect();
|
||||
|
||||
|
@ -42,12 +43,18 @@ abstract class HarbormasterBuildMessageTransaction
|
|||
);
|
||||
}
|
||||
|
||||
final public static function getTransactionObjectForMessageType(
|
||||
$message_type) {
|
||||
final public static function getAllMessages() {
|
||||
$message_xactions = id(new PhutilClassMapQuery())
|
||||
->setAncestorClass(__CLASS__)
|
||||
->execute();
|
||||
|
||||
return $message_xactions;
|
||||
}
|
||||
|
||||
final public static function getTransactionObjectForMessageType(
|
||||
$message_type) {
|
||||
$message_xactions = self::getAllMessages();
|
||||
|
||||
foreach ($message_xactions as $message_xaction) {
|
||||
$xaction_type = $message_xaction->getHarbormasterBuildMessageType();
|
||||
if ($xaction_type === $message_type) {
|
||||
|
|
Loading…
Reference in a new issue