Summary: Ref T8095. Two general problems: - I want Harbormaster to own all lint and unit test results. - I don't want users to have to configure anything for `arc` to keep working automatically. These are in conflict because generic lint/unit test ownership in Harbormaster requires that build targets exist which we can attach build results to. However, we can't currently create build targets on demand: Harbormaster assumes it is responsible for creating targets, then running code or making third-party service calls to actually run the builds. I considered two broad approaches to let `arc` push results into Harbormaster without requiring administrators to configure some kind of "arc results" build plan: # Add magic target PHIDs like `PHID-MAGIC-this-is-really-arc-unit`. # Add new code to build real targets with real PHIDs. (1) is probably a bit less work to get off the ground, but I think it's worse overall and very likely to create more problems in the long run. I particularly worry that it will lead to a small amount of special casing in a very large number of places, which seems more fragile. (2) is more work upfront but I think does a better job of putting all the special casing in one place that we can, e.g., more reasonably unit test, and letting the rest of the code rarely/never care about this case since it's just dealing with normal plans/steps/targets as far as it can tell. This diff introduces "autoplans", which are source templates for plans/steps. This let us "push" these targets into Harbormaster. Hypthetically, any process "like" arc can use autoplans to upload test/lint/etc results. In practice, probably only `arc` will ever use this, but I think it's still quite a bit cleaner than the alternative despite all the generality. Workflow is basically: - `arc` creates a diff. - `arc` calls `harbormaster.queryautotargets`, passing the diff PHID and saying "I have some lint and unit results I want to stick on this thing". - Harbormaster builds the plan, steps, and targets (if any of them don't already exist), and hands back the target PHIDs so `arc` has a completely standard-looking place to put results. - `arc` uploads the test results to the right targets, as though Harbormaster had asked it to run unit/lint in the first place. (This doesn't actually do any of that yet, just sets things up.) I'll maybe doc turn that ^^^^^^ into a doc for posterity since I think it's hard to guess what an "autotarget" is, but I'm going to grab some lunch first. Test Plan: - Added unit tests to make sure we can build these things properly. - Used `harbormaster.queryautotargets` to build autotargets for a bunch of diffs. - Verified targets come up in "waiting for message" state. - Verified plans and steps are not editable. Reviewers: btrahan Reviewed By: btrahan Subscribers: hach-que, epriestley Maniphest Tasks: T8095 Differential Revision: https://secure.phabricator.com/D13345
71 lines
1.9 KiB
PHP
71 lines
1.9 KiB
PHP
<?php
|
|
|
|
final class HarbormasterStepAddController extends HarbormasterController {
|
|
|
|
public function handleRequest(AphrontRequest $request) {
|
|
$viewer = $this->getViewer();
|
|
|
|
$this->requireApplicationCapability(
|
|
HarbormasterManagePlansCapability::CAPABILITY);
|
|
|
|
$plan = id(new HarbormasterBuildPlanQuery())
|
|
->setViewer($viewer)
|
|
->withIDs(array($request->getURIData('id')))
|
|
->requireCapabilities(
|
|
array(
|
|
PhabricatorPolicyCapability::CAN_VIEW,
|
|
PhabricatorPolicyCapability::CAN_EDIT,
|
|
))
|
|
->executeOne();
|
|
if (!$plan) {
|
|
return new Aphront404Response();
|
|
}
|
|
|
|
$plan_id = $plan->getID();
|
|
$cancel_uri = $this->getApplicationURI("plan/{$plan_id}/");
|
|
|
|
$all = HarbormasterBuildStepImplementation::getImplementations();
|
|
foreach ($all as $key => $impl) {
|
|
if ($impl->shouldRequireAutotargeting()) {
|
|
unset($all[$key]);
|
|
}
|
|
}
|
|
|
|
$errors = array();
|
|
if ($request->isFormPost()) {
|
|
$class = $request->getStr('class');
|
|
if (empty($all[$class])) {
|
|
$errors[] = pht('Choose the type of build step you want to add.');
|
|
}
|
|
if (!$errors) {
|
|
$new_uri = $this->getApplicationURI("step/new/{$plan_id}/{$class}/");
|
|
return id(new AphrontRedirectResponse())->setURI($new_uri);
|
|
}
|
|
}
|
|
|
|
$control = id(new AphrontFormRadioButtonControl())
|
|
->setName('class');
|
|
|
|
foreach ($all as $class => $implementation) {
|
|
$control->addButton(
|
|
$class,
|
|
$implementation->getName(),
|
|
$implementation->getGenericDescription());
|
|
}
|
|
|
|
if ($errors) {
|
|
$errors = id(new PHUIInfoView())
|
|
->setErrors($errors);
|
|
}
|
|
|
|
return $this->newDialog()
|
|
->setTitle(pht('Add New Step'))
|
|
->addSubmitButton(pht('Add Build Step'))
|
|
->addCancelButton($cancel_uri)
|
|
->appendChild($errors)
|
|
->appendParagraph(pht('Choose a type of build step to add:'))
|
|
->appendChild($control);
|
|
}
|
|
|
|
}
|