@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.

Tailor "Restart All Builds" for the complex realities of modern build restart rules

Summary:
Fixes T13348. Currently, the Harbormaster UI shows "Restart All Builds", but it really means "Restart Restartable Builds", which is often fewer than "All" builds (because of autobuilds, permissions, and/or configuration).

Remove the misleading term "All" and make the workflow preview exactly which builds will and will not be affected, and why.

Test Plan:
{F6636313}

{F6636314}

{F6636315}

Reviewers: amckinley

Reviewed By: amckinley

Subscribers: PHID-OPKG-gm6ozazyms6q6i22gyam

Maniphest Tasks: T13348

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

+138 -25
+134 -21
src/applications/harbormaster/controller/HarbormasterBuildableActionController.php
··· 24 24 25 25 $issuable = array(); 26 26 27 - foreach ($buildable->getBuilds() as $build) { 27 + $builds = $buildable->getBuilds(); 28 + foreach ($builds as $key => $build) { 28 29 switch ($action) { 29 30 case HarbormasterBuildCommand::COMMAND_RESTART: 30 31 if ($build->canRestartBuild()) { 31 - $issuable[] = $build; 32 + $issuable[$key] = $build; 32 33 } 33 34 break; 34 35 case HarbormasterBuildCommand::COMMAND_PAUSE: 35 36 if ($build->canPauseBuild()) { 36 - $issuable[] = $build; 37 + $issuable[$key] = $build; 37 38 } 38 39 break; 39 40 case HarbormasterBuildCommand::COMMAND_RESUME: 40 41 if ($build->canResumeBuild()) { 41 - $issuable[] = $build; 42 + $issuable[$key] = $build; 42 43 } 43 44 break; 44 45 case HarbormasterBuildCommand::COMMAND_ABORT: 45 46 if ($build->canAbortBuild()) { 46 - $issuable[] = $build; 47 + $issuable[$key] = $build; 47 48 } 48 49 break; 49 50 default: ··· 56 57 if (!$build->canIssueCommand($viewer, $action)) { 57 58 $restricted = true; 58 59 unset($issuable[$key]); 60 + } 61 + } 62 + 63 + $building = false; 64 + foreach ($issuable as $key => $build) { 65 + if ($build->isBuilding()) { 66 + $building = true; 67 + break; 59 68 } 60 69 } 61 70 ··· 89 98 return id(new AphrontRedirectResponse())->setURI($return_uri); 90 99 } 91 100 101 + $width = AphrontDialogView::WIDTH_DEFAULT; 102 + 92 103 switch ($action) { 93 104 case HarbormasterBuildCommand::COMMAND_RESTART: 105 + // See T13348. The "Restart Builds" action may restart only a subset 106 + // of builds, so show the user a preview of which builds will actually 107 + // restart. 108 + 109 + $body = array(); 110 + 94 111 if ($issuable) { 95 - $title = pht('Really restart builds?'); 112 + $title = pht('Restart Builds'); 113 + $submit = pht('Restart Builds'); 114 + } else { 115 + $title = pht('Unable to Restart Builds'); 116 + } 117 + 118 + if ($builds) { 119 + $width = AphrontDialogView::WIDTH_FORM; 120 + 121 + $body[] = pht('Builds for this buildable:'); 122 + 123 + $rows = array(); 124 + foreach ($builds as $key => $build) { 125 + if (isset($issuable[$key])) { 126 + $icon = id(new PHUIIconView()) 127 + ->setIcon('fa-repeat green'); 128 + $build_note = pht('Will Restart'); 129 + } else { 130 + $icon = null; 131 + 132 + try { 133 + $build->assertCanRestartBuild(); 134 + } catch (HarbormasterRestartException $ex) { 135 + $icon = id(new PHUIIconView()) 136 + ->setIcon('fa-times red'); 137 + $build_note = pht( 138 + '%s: %s', 139 + phutil_tag('strong', array(), pht('Not Restartable')), 140 + $ex->getTitle()); 141 + } 142 + 143 + if (!$icon) { 144 + try { 145 + $build->assertCanIssueCommand($viewer, $action); 146 + } catch (PhabricatorPolicyException $ex) { 147 + $icon = id(new PHUIIconView()) 148 + ->setIcon('fa-lock red'); 149 + $build_note = pht( 150 + '%s: %s', 151 + phutil_tag('strong', array(), pht('Not Restartable')), 152 + pht('You do not have permission to restart this build.')); 153 + } 154 + } 155 + 156 + if (!$icon) { 157 + $icon = id(new PHUIIconView()) 158 + ->setIcon('fa-times red'); 159 + $build_note = pht('Will Not Restart'); 160 + } 161 + } 162 + 163 + $build_name = phutil_tag( 164 + 'a', 165 + array( 166 + 'href' => $build->getURI(), 167 + 'target' => '_blank', 168 + ), 169 + pht('%s %s', $build->getObjectName(), $build->getName())); 170 + 171 + $rows[] = array( 172 + $icon, 173 + $build_name, 174 + $build_note, 175 + ); 176 + } 177 + 178 + $table = id(new AphrontTableView($rows)) 179 + ->setHeaders( 180 + array( 181 + null, 182 + pht('Build'), 183 + pht('Action'), 184 + )) 185 + ->setColumnClasses( 186 + array( 187 + null, 188 + 'pri', 189 + 'wide', 190 + )); 191 + 192 + $table = phutil_tag( 193 + 'div', 194 + array( 195 + 'class' => 'mlt mlb', 196 + ), 197 + $table); 198 + 199 + $body[] = $table; 200 + } 201 + 202 + if ($issuable) { 203 + $warnings = array(); 96 204 97 205 if ($restricted) { 98 - $body = pht( 99 - 'You only have permission to restart some builds. Progress '. 100 - 'on builds you have permission to restart will be discarded '. 101 - 'and they will restart. Side effects of these builds will '. 102 - 'occur again. Really restart all builds?'); 103 - } else { 104 - $body = pht( 105 - 'Progress on all builds will be discarded, and all builds will '. 106 - 'restart. Side effects of the builds will occur again. Really '. 107 - 'restart all builds?'); 206 + $warnings[] = pht( 207 + 'You only have permission to restart some builds.'); 108 208 } 109 209 110 - $submit = pht('Restart Builds'); 111 - } else { 112 - $title = pht('Unable to Restart Builds'); 210 + if ($building) { 211 + $warnings[] = pht( 212 + 'Progress on running builds will be discarded.'); 213 + } 113 214 215 + $warnings[] = pht( 216 + 'When a build is restarted, side effects associated with '. 217 + 'the build may occur again.'); 218 + 219 + $body[] = id(new PHUIInfoView()) 220 + ->setSeverity(PHUIInfoView::SEVERITY_WARNING) 221 + ->setErrors($warnings); 222 + 223 + $body[] = pht('Really restart builds?'); 224 + } else { 114 225 if ($restricted) { 115 - $body = pht('You do not have permission to restart any builds.'); 226 + $body[] = pht('You do not have permission to restart any builds.'); 116 227 } else { 117 - $body = pht('No builds can be restarted.'); 228 + $body[] = pht('No builds can be restarted.'); 118 229 } 119 230 } 231 + 120 232 break; 121 233 case HarbormasterBuildCommand::COMMAND_PAUSE: 122 234 if ($issuable) { ··· 193 305 194 306 $dialog = id(new AphrontDialogView()) 195 307 ->setUser($viewer) 308 + ->setWidth($width) 196 309 ->setTitle($title) 197 310 ->appendChild($body) 198 311 ->addCancelButton($return_uri);
+4 -4
src/applications/harbormaster/controller/HarbormasterBuildableViewController.php
··· 128 128 $curtain->addAction( 129 129 id(new PhabricatorActionView()) 130 130 ->setIcon('fa-repeat') 131 - ->setName(pht('Restart All Builds')) 131 + ->setName(pht('Restart Builds')) 132 132 ->setHref($this->getApplicationURI($restart_uri)) 133 133 ->setWorkflow(true) 134 134 ->setDisabled(!$can_restart || !$can_edit)); ··· 136 136 $curtain->addAction( 137 137 id(new PhabricatorActionView()) 138 138 ->setIcon('fa-pause') 139 - ->setName(pht('Pause All Builds')) 139 + ->setName(pht('Pause Builds')) 140 140 ->setHref($this->getApplicationURI($pause_uri)) 141 141 ->setWorkflow(true) 142 142 ->setDisabled(!$can_pause || !$can_edit)); ··· 144 144 $curtain->addAction( 145 145 id(new PhabricatorActionView()) 146 146 ->setIcon('fa-play') 147 - ->setName(pht('Resume All Builds')) 147 + ->setName(pht('Resume Builds')) 148 148 ->setHref($this->getApplicationURI($resume_uri)) 149 149 ->setWorkflow(true) 150 150 ->setDisabled(!$can_resume || !$can_edit)); ··· 152 152 $curtain->addAction( 153 153 id(new PhabricatorActionView()) 154 154 ->setIcon('fa-exclamation-triangle') 155 - ->setName(pht('Abort All Builds')) 155 + ->setName(pht('Abort Builds')) 156 156 ->setHref($this->getApplicationURI($abort_uri)) 157 157 ->setWorkflow(true) 158 158 ->setDisabled(!$can_abort || !$can_edit));