@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Lump Harbormaster build steps into groups

Summary:
Ref T8089. We have a lot of broken/confusing/prototype build steps that I want to hide from users when we unprototype Harbormaster.

The dialog is also just kind of unwieldy.

Organize this UI a little better and put all the sketchy junk in a "prototypes" group that you can't see unless prototypes are enabled.

This doesn't break anything (the old steps will still work fine), but should reduce user confusion.

Test Plan:
Old UI:

{F691439}

New UI (prototypes off):

{F691440}

New UI (prototypes on):

{F691441}

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T8089

Differential Revision: https://secure.phabricator.com/D13803

+272 -31
+12
src/__phutil_library_map__.php
··· 951 951 'HarbormasterBuildStepCoreCustomField' => 'applications/harbormaster/customfield/HarbormasterBuildStepCoreCustomField.php', 952 952 'HarbormasterBuildStepCustomField' => 'applications/harbormaster/customfield/HarbormasterBuildStepCustomField.php', 953 953 'HarbormasterBuildStepEditor' => 'applications/harbormaster/editor/HarbormasterBuildStepEditor.php', 954 + 'HarbormasterBuildStepGroup' => 'applications/harbormaster/stepgroup/HarbormasterBuildStepGroup.php', 954 955 'HarbormasterBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterBuildStepImplementation.php', 955 956 'HarbormasterBuildStepImplementationTestCase' => 'applications/harbormaster/step/__tests__/HarbormasterBuildStepImplementationTestCase.php', 956 957 'HarbormasterBuildStepPHIDType' => 'applications/harbormaster/phid/HarbormasterBuildStepPHIDType.php', ··· 978 979 'HarbormasterBuildableTransactionEditor' => 'applications/harbormaster/editor/HarbormasterBuildableTransactionEditor.php', 979 980 'HarbormasterBuildableTransactionQuery' => 'applications/harbormaster/query/HarbormasterBuildableTransactionQuery.php', 980 981 'HarbormasterBuildableViewController' => 'applications/harbormaster/controller/HarbormasterBuildableViewController.php', 982 + 'HarbormasterBuiltinBuildStepGroup' => 'applications/harbormaster/stepgroup/HarbormasterBuiltinBuildStepGroup.php', 981 983 'HarbormasterCommandBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterCommandBuildStepImplementation.php', 982 984 'HarbormasterConduitAPIMethod' => 'applications/harbormaster/conduit/HarbormasterConduitAPIMethod.php', 983 985 'HarbormasterController' => 'applications/harbormaster/controller/HarbormasterController.php', 984 986 'HarbormasterDAO' => 'applications/harbormaster/storage/HarbormasterDAO.php', 987 + 'HarbormasterExternalBuildStepGroup' => 'applications/harbormaster/stepgroup/HarbormasterExternalBuildStepGroup.php', 985 988 'HarbormasterHTTPRequestBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterHTTPRequestBuildStepImplementation.php', 986 989 'HarbormasterLeaseHostBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterLeaseHostBuildStepImplementation.php', 987 990 'HarbormasterLintMessagesController' => 'applications/harbormaster/controller/HarbormasterLintMessagesController.php', ··· 992 995 'HarbormasterManagementWorkflow' => 'applications/harbormaster/management/HarbormasterManagementWorkflow.php', 993 996 'HarbormasterMessageType' => 'applications/harbormaster/engine/HarbormasterMessageType.php', 994 997 'HarbormasterObject' => 'applications/harbormaster/storage/HarbormasterObject.php', 998 + 'HarbormasterOtherBuildStepGroup' => 'applications/harbormaster/stepgroup/HarbormasterOtherBuildStepGroup.php', 995 999 'HarbormasterPlanController' => 'applications/harbormaster/controller/HarbormasterPlanController.php', 996 1000 'HarbormasterPlanDisableController' => 'applications/harbormaster/controller/HarbormasterPlanDisableController.php', 997 1001 'HarbormasterPlanEditController' => 'applications/harbormaster/controller/HarbormasterPlanEditController.php', 998 1002 'HarbormasterPlanListController' => 'applications/harbormaster/controller/HarbormasterPlanListController.php', 999 1003 'HarbormasterPlanRunController' => 'applications/harbormaster/controller/HarbormasterPlanRunController.php', 1000 1004 'HarbormasterPlanViewController' => 'applications/harbormaster/controller/HarbormasterPlanViewController.php', 1005 + 'HarbormasterPrototypeBuildStepGroup' => 'applications/harbormaster/stepgroup/HarbormasterPrototypeBuildStepGroup.php', 1001 1006 'HarbormasterPublishFragmentBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterPublishFragmentBuildStepImplementation.php', 1002 1007 'HarbormasterQueryAutotargetsConduitAPIMethod' => 'applications/harbormaster/conduit/HarbormasterQueryAutotargetsConduitAPIMethod.php', 1003 1008 'HarbormasterQueryBuildablesConduitAPIMethod' => 'applications/harbormaster/conduit/HarbormasterQueryBuildablesConduitAPIMethod.php', ··· 1013 1018 'HarbormasterStepEditController' => 'applications/harbormaster/controller/HarbormasterStepEditController.php', 1014 1019 'HarbormasterTargetEngine' => 'applications/harbormaster/engine/HarbormasterTargetEngine.php', 1015 1020 'HarbormasterTargetWorker' => 'applications/harbormaster/worker/HarbormasterTargetWorker.php', 1021 + 'HarbormasterTestBuildStepGroup' => 'applications/harbormaster/stepgroup/HarbormasterTestBuildStepGroup.php', 1016 1022 'HarbormasterThrowExceptionBuildStep' => 'applications/harbormaster/step/HarbormasterThrowExceptionBuildStep.php', 1017 1023 'HarbormasterUIEventListener' => 'applications/harbormaster/event/HarbormasterUIEventListener.php', 1018 1024 'HarbormasterUnitMessagesController' => 'applications/harbormaster/controller/HarbormasterUnitMessagesController.php', ··· 4660 4666 ), 4661 4667 'HarbormasterBuildStepCustomField' => 'PhabricatorCustomField', 4662 4668 'HarbormasterBuildStepEditor' => 'PhabricatorApplicationTransactionEditor', 4669 + 'HarbormasterBuildStepGroup' => 'Phobject', 4663 4670 'HarbormasterBuildStepImplementation' => 'Phobject', 4664 4671 'HarbormasterBuildStepImplementationTestCase' => 'PhabricatorTestCase', 4665 4672 'HarbormasterBuildStepPHIDType' => 'PhabricatorPHIDType', ··· 4693 4700 'HarbormasterBuildableTransactionEditor' => 'PhabricatorApplicationTransactionEditor', 4694 4701 'HarbormasterBuildableTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 4695 4702 'HarbormasterBuildableViewController' => 'HarbormasterController', 4703 + 'HarbormasterBuiltinBuildStepGroup' => 'HarbormasterBuildStepGroup', 4696 4704 'HarbormasterCommandBuildStepImplementation' => 'HarbormasterBuildStepImplementation', 4697 4705 'HarbormasterConduitAPIMethod' => 'ConduitAPIMethod', 4698 4706 'HarbormasterController' => 'PhabricatorController', 4699 4707 'HarbormasterDAO' => 'PhabricatorLiskDAO', 4708 + 'HarbormasterExternalBuildStepGroup' => 'HarbormasterBuildStepGroup', 4700 4709 'HarbormasterHTTPRequestBuildStepImplementation' => 'HarbormasterBuildStepImplementation', 4701 4710 'HarbormasterLeaseHostBuildStepImplementation' => 'HarbormasterBuildStepImplementation', 4702 4711 'HarbormasterLintMessagesController' => 'HarbormasterController', ··· 4707 4716 'HarbormasterManagementWorkflow' => 'PhabricatorManagementWorkflow', 4708 4717 'HarbormasterMessageType' => 'Phobject', 4709 4718 'HarbormasterObject' => 'HarbormasterDAO', 4719 + 'HarbormasterOtherBuildStepGroup' => 'HarbormasterBuildStepGroup', 4710 4720 'HarbormasterPlanController' => 'HarbormasterController', 4711 4721 'HarbormasterPlanDisableController' => 'HarbormasterPlanController', 4712 4722 'HarbormasterPlanEditController' => 'HarbormasterPlanController', 4713 4723 'HarbormasterPlanListController' => 'HarbormasterPlanController', 4714 4724 'HarbormasterPlanRunController' => 'HarbormasterController', 4715 4725 'HarbormasterPlanViewController' => 'HarbormasterPlanController', 4726 + 'HarbormasterPrototypeBuildStepGroup' => 'HarbormasterBuildStepGroup', 4716 4727 'HarbormasterPublishFragmentBuildStepImplementation' => 'HarbormasterBuildStepImplementation', 4717 4728 'HarbormasterQueryAutotargetsConduitAPIMethod' => 'HarbormasterConduitAPIMethod', 4718 4729 'HarbormasterQueryBuildablesConduitAPIMethod' => 'HarbormasterConduitAPIMethod', ··· 4728 4739 'HarbormasterStepEditController' => 'HarbormasterController', 4729 4740 'HarbormasterTargetEngine' => 'Phobject', 4730 4741 'HarbormasterTargetWorker' => 'HarbormasterWorker', 4742 + 'HarbormasterTestBuildStepGroup' => 'HarbormasterBuildStepGroup', 4731 4743 'HarbormasterThrowExceptionBuildStep' => 'HarbormasterBuildStepImplementation', 4732 4744 'HarbormasterUIEventListener' => 'PhabricatorEventListener', 4733 4745 'HarbormasterUnitMessagesController' => 'HarbormasterController',
+1 -1
src/applications/harbormaster/controller/HarbormasterPlanViewController.php
··· 235 235 id(new PHUIIconView()) 236 236 ->setIconFont('fa-plus')) 237 237 ->setDisabled(!$can_edit) 238 - ->setWorkflow(true)); 238 + ->setWorkflow(!$can_edit)); 239 239 240 240 $step_box = id(new PHUIObjectBoxView()) 241 241 ->setHeader($header)
+65 -30
src/applications/harbormaster/controller/HarbormasterStepAddController.php
··· 23 23 24 24 $plan_id = $plan->getID(); 25 25 $cancel_uri = $this->getApplicationURI("plan/{$plan_id}/"); 26 + $plan_title = pht('Plan %d', $plan_id); 26 27 27 28 $all = HarbormasterBuildStepImplementation::getImplementations(); 28 - foreach ($all as $key => $impl) { 29 - if ($impl->shouldRequireAutotargeting()) { 30 - unset($all[$key]); 29 + $all = msort($all, 'getName'); 30 + 31 + $all_groups = HarbormasterBuildStepGroup::getAllGroups(); 32 + foreach ($all as $impl) { 33 + $group_key = $impl->getBuildStepGroupKey(); 34 + if (empty($all_groups[$group_key])) { 35 + throw new Exception( 36 + pht( 37 + 'Build step "%s" has step group key "%s", but no step group '. 38 + 'with that key exists.', 39 + get_class($impl), 40 + $group_key)); 31 41 } 32 42 } 33 43 34 - $errors = array(); 35 - if ($request->isFormPost()) { 36 - $class = $request->getStr('class'); 37 - if (empty($all[$class])) { 38 - $errors[] = pht('Choose the type of build step you want to add.'); 44 + $groups = mgroup($all, 'getBuildStepGroupKey'); 45 + $lists = array(); 46 + 47 + $enabled_groups = HarbormasterBuildStepGroup::getAllEnabledGroups(); 48 + foreach ($enabled_groups as $group) { 49 + $list = id(new PHUIObjectItemListView()) 50 + ->setHeader($group->getGroupName()) 51 + ->setNoDataString( 52 + pht( 53 + 'This group has no available build steps.')); 54 + 55 + $steps = idx($groups, $group->getGroupKey(), array()); 56 + 57 + foreach ($steps as $key => $impl) { 58 + if ($impl->shouldRequireAutotargeting()) { 59 + unset($steps[$key]); 60 + continue; 61 + } 39 62 } 40 - if (!$errors) { 63 + 64 + if (!$steps && !$group->shouldShowIfEmpty()) { 65 + continue; 66 + } 67 + 68 + foreach ($steps as $key => $impl) { 69 + $class = get_class($impl); 70 + 41 71 $new_uri = $this->getApplicationURI("step/new/{$plan_id}/{$class}/"); 42 - return id(new AphrontRedirectResponse())->setURI($new_uri); 72 + 73 + $item = id(new PHUIObjectItemView()) 74 + ->setHeader($impl->getName()) 75 + ->setHref($new_uri) 76 + ->addAttribute($impl->getGenericDescription()); 77 + 78 + $list->addItem($item); 43 79 } 80 + 81 + $lists[] = $list; 44 82 } 45 83 46 - $control = id(new AphrontFormRadioButtonControl()) 47 - ->setName('class'); 84 + $crumbs = $this->buildApplicationCrumbs() 85 + ->addTextCrumb($plan_title, $cancel_uri) 86 + ->addTextCrumb(pht('Add Build Step')); 48 87 49 - foreach ($all as $class => $implementation) { 50 - $control->addButton( 51 - $class, 52 - $implementation->getName(), 53 - $implementation->getGenericDescription()); 54 - } 88 + $box = id(new PHUIObjectBoxView()) 89 + ->setHeaderText(pht('Add Build Step')) 90 + ->appendChild($lists); 55 91 56 - if ($errors) { 57 - $errors = id(new PHUIInfoView()) 58 - ->setErrors($errors); 59 - } 60 - 61 - return $this->newDialog() 62 - ->setTitle(pht('Add New Step')) 63 - ->addSubmitButton(pht('Add Build Step')) 64 - ->addCancelButton($cancel_uri) 65 - ->appendChild($errors) 66 - ->appendParagraph(pht('Choose a type of build step to add:')) 67 - ->appendChild($control); 92 + return $this->buildApplicationPage( 93 + array( 94 + $crumbs, 95 + $box, 96 + ), 97 + array( 98 + 'title' => array( 99 + $plan_title, 100 + pht('Add Build Step'), 101 + ), 102 + )); 68 103 } 69 104 70 105 }
+4
src/applications/harbormaster/step/HarbormasterArcLintBuildStepImplementation.php
··· 25 25 return pht('Automatic `arc lint` step.'); 26 26 } 27 27 28 + public function getBuildStepGroupKey() { 29 + return HarbormasterBuiltinBuildStepGroup::GROUPKEY; 30 + } 31 + 28 32 public function execute( 29 33 HarbormasterBuild $build, 30 34 HarbormasterBuildTarget $build_target) {
+4
src/applications/harbormaster/step/HarbormasterArcUnitBuildStepImplementation.php
··· 25 25 return pht('Automatic `arc unit` step.'); 26 26 } 27 27 28 + public function getBuildStepGroupKey() { 29 + return HarbormasterBuiltinBuildStepGroup::GROUPKEY; 30 + } 31 + 28 32 public function execute( 29 33 HarbormasterBuild $build, 30 34 HarbormasterBuildTarget $build_target) {
+4
src/applications/harbormaster/step/HarbormasterBuildStepImplementation.php
··· 41 41 */ 42 42 abstract public function getName(); 43 43 44 + public function getBuildStepGroupKey() { 45 + return HarbormasterOtherBuildStepGroup::GROUPKEY; 46 + } 47 + 44 48 /** 45 49 * The generic description of the implementation. 46 50 */
+4
src/applications/harbormaster/step/HarbormasterCommandBuildStepImplementation.php
··· 13 13 return pht('Run a command on Drydock host.'); 14 14 } 15 15 16 + public function getBuildStepGroupKey() { 17 + return HarbormasterPrototypeBuildStepGroup::GROUPKEY; 18 + } 19 + 16 20 public function getDescription() { 17 21 return pht( 18 22 'Run command %s on host %s.',
+4
src/applications/harbormaster/step/HarbormasterHTTPRequestBuildStepImplementation.php
··· 11 11 return pht('Make an HTTP request.'); 12 12 } 13 13 14 + public function getBuildStepGroupKey() { 15 + return HarbormasterExternalBuildStepGroup::GROUPKEY; 16 + } 17 + 14 18 public function getDescription() { 15 19 $domain = null; 16 20 $uri = $this->getSetting('uri');
+4
src/applications/harbormaster/step/HarbormasterLeaseHostBuildStepImplementation.php
··· 11 11 return pht('Obtain a lease on a Drydock host for performing builds.'); 12 12 } 13 13 14 + public function getBuildStepGroupKey() { 15 + return HarbormasterPrototypeBuildStepGroup::GROUPKEY; 16 + } 17 + 14 18 public function execute( 15 19 HarbormasterBuild $build, 16 20 HarbormasterBuildTarget $build_target) {
+5
src/applications/harbormaster/step/HarbormasterPublishFragmentBuildStepImplementation.php
··· 11 11 return pht('Publish a fragment based on a file artifact.'); 12 12 } 13 13 14 + 15 + public function getBuildStepGroupKey() { 16 + return HarbormasterPrototypeBuildStepGroup::GROUPKEY; 17 + } 18 + 14 19 public function getDescription() { 15 20 return pht( 16 21 'Publish file artifact %s as fragment %s.',
+5
src/applications/harbormaster/step/HarbormasterSleepBuildStepImplementation.php
··· 11 11 return pht('Sleep for a specified number of seconds.'); 12 12 } 13 13 14 + 15 + public function getBuildStepGroupKey() { 16 + return HarbormasterTestBuildStepGroup::GROUPKEY; 17 + } 18 + 14 19 public function getDescription() { 15 20 return pht( 16 21 'Sleep for %s seconds.',
+4
src/applications/harbormaster/step/HarbormasterThrowExceptionBuildStep.php
··· 11 11 return pht('Throw an exception.'); 12 12 } 13 13 14 + public function getBuildStepGroupKey() { 15 + return HarbormasterTestBuildStepGroup::GROUPKEY; 16 + } 17 + 14 18 public function execute( 15 19 HarbormasterBuild $build, 16 20 HarbormasterBuildTarget $build_target) {
+4
src/applications/harbormaster/step/HarbormasterUploadArtifactBuildStepImplementation.php
··· 11 11 return pht('Upload a file from a host to Phabricator.'); 12 12 } 13 13 14 + public function getBuildStepGroupKey() { 15 + return HarbormasterPrototypeBuildStepGroup::GROUPKEY; 16 + } 17 + 14 18 public function getDescription() { 15 19 return pht( 16 20 'Upload %s from %s.',
+4
src/applications/harbormaster/step/HarbormasterWaitForPreviousBuildStepImplementation.php
··· 13 13 'before continuing.'); 14 14 } 15 15 16 + public function getBuildStepGroupKey() { 17 + return HarbormasterPrototypeBuildStepGroup::GROUPKEY; 18 + } 19 + 16 20 public function execute( 17 21 HarbormasterBuild $build, 18 22 HarbormasterBuildTarget $build_target) {
+52
src/applications/harbormaster/stepgroup/HarbormasterBuildStepGroup.php
··· 1 + <?php 2 + 3 + abstract class HarbormasterBuildStepGroup extends Phobject { 4 + 5 + abstract public function getGroupName(); 6 + abstract public function getGroupOrder(); 7 + 8 + public function isEnabled() { 9 + return true; 10 + } 11 + 12 + public function shouldShowIfEmpty() { 13 + return true; 14 + } 15 + 16 + final public function getGroupKey() { 17 + $class = new ReflectionClass($this); 18 + 19 + $const = $class->getConstant('GROUPKEY'); 20 + if ($const === false) { 21 + throw new Exception( 22 + pht( 23 + '"%s" class "%s" must define a "%s" property.', 24 + __CLASS__, 25 + get_class($this), 26 + 'GROUPKEY')); 27 + } 28 + 29 + return $const; 30 + } 31 + 32 + final public static function getAllGroups() { 33 + return id(new PhutilClassMapQuery()) 34 + ->setAncestorClass(__CLASS__) 35 + ->setUniqueMethod('getGroupKey') 36 + ->setSortMethod('getGroupOrder') 37 + ->execute(); 38 + } 39 + 40 + final public static function getAllEnabledGroups() { 41 + $groups = self::getAllGroups(); 42 + 43 + foreach ($groups as $key => $group) { 44 + if (!$group->isEnabled()) { 45 + unset($groups[$key]); 46 + } 47 + } 48 + 49 + return $groups; 50 + } 51 + 52 + }
+20
src/applications/harbormaster/stepgroup/HarbormasterBuiltinBuildStepGroup.php
··· 1 + <?php 2 + 3 + final class HarbormasterBuiltinBuildStepGroup 4 + extends HarbormasterBuildStepGroup { 5 + 6 + const GROUPKEY = 'harbormaster.builtin'; 7 + 8 + public function getGroupName() { 9 + return pht('Builtins'); 10 + } 11 + 12 + public function getGroupOrder() { 13 + return 0; 14 + } 15 + 16 + public function shouldShowIfEmpty() { 17 + return false; 18 + } 19 + 20 + }
+16
src/applications/harbormaster/stepgroup/HarbormasterExternalBuildStepGroup.php
··· 1 + <?php 2 + 3 + final class HarbormasterExternalBuildStepGroup 4 + extends HarbormasterBuildStepGroup { 5 + 6 + const GROUPKEY = 'harbormaster.external'; 7 + 8 + public function getGroupName() { 9 + return pht('Interacting with External Build Sytems'); 10 + } 11 + 12 + public function getGroupOrder() { 13 + return 4000; 14 + } 15 + 16 + }
+20
src/applications/harbormaster/stepgroup/HarbormasterOtherBuildStepGroup.php
··· 1 + <?php 2 + 3 + final class HarbormasterOtherBuildStepGroup 4 + extends HarbormasterBuildStepGroup { 5 + 6 + const GROUPKEY = 'harbormaster.other'; 7 + 8 + public function getGroupName() { 9 + return pht('Other Build Steps'); 10 + } 11 + 12 + public function getGroupOrder() { 13 + return 9000; 14 + } 15 + 16 + public function shouldShowIfEmpty() { 17 + return false; 18 + } 19 + 20 + }
+24
src/applications/harbormaster/stepgroup/HarbormasterPrototypeBuildStepGroup.php
··· 1 + <?php 2 + 3 + final class HarbormasterPrototypeBuildStepGroup 4 + extends HarbormasterBuildStepGroup { 5 + 6 + const GROUPKEY = 'harbormaster.prototype'; 7 + 8 + public function getGroupName() { 9 + return pht('Prototypes'); 10 + } 11 + 12 + public function getGroupOrder() { 13 + return 8000; 14 + } 15 + 16 + public function isEnabled() { 17 + return PhabricatorEnv::getEnvConfig('phabricator.show-prototypes'); 18 + } 19 + 20 + public function shouldShowIfEmpty() { 21 + return false; 22 + } 23 + 24 + }
+16
src/applications/harbormaster/stepgroup/HarbormasterTestBuildStepGroup.php
··· 1 + <?php 2 + 3 + final class HarbormasterTestBuildStepGroup 4 + extends HarbormasterBuildStepGroup { 5 + 6 + const GROUPKEY = 'harbormaster.test'; 7 + 8 + public function getGroupName() { 9 + return pht('Testing Utilities'); 10 + } 11 + 12 + public function getGroupOrder() { 13 + return 7000; 14 + } 15 + 16 + }