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

at recaptime-dev/main 425 lines 12 kB view raw
1<?php 2 3final class HarbormasterBuildable 4 extends HarbormasterDAO 5 implements 6 PhabricatorApplicationTransactionInterface, 7 PhabricatorPolicyInterface, 8 HarbormasterBuildableInterface, 9 PhabricatorConduitResultInterface, 10 PhabricatorDestructibleInterface { 11 12 protected $buildablePHID; 13 protected $containerPHID; 14 protected $buildableStatus; 15 protected $isManualBuildable; 16 17 private $buildableObject = self::ATTACHABLE; 18 private $containerObject = self::ATTACHABLE; 19 private $builds = self::ATTACHABLE; 20 21 public static function initializeNewBuildable(PhabricatorUser $actor) { 22 return id(new HarbormasterBuildable()) 23 ->setIsManualBuildable(0) 24 ->setBuildableStatus(HarbormasterBuildableStatus::STATUS_PREPARING); 25 } 26 27 public function getMonogram() { 28 return 'B'.$this->getID(); 29 } 30 31 public function getURI() { 32 return '/'.$this->getMonogram(); 33 } 34 35 /** 36 * Returns an existing buildable for the object's PHID or creates a 37 * new buildable implicitly if needed. 38 */ 39 public static function createOrLoadExisting( 40 PhabricatorUser $actor, 41 $buildable_object_phid, 42 $container_object_phid) { 43 44 $buildable = id(new HarbormasterBuildableQuery()) 45 ->setViewer($actor) 46 ->withBuildablePHIDs(array($buildable_object_phid)) 47 ->withManualBuildables(false) 48 ->setLimit(1) 49 ->executeOne(); 50 if ($buildable) { 51 return $buildable; 52 } 53 $buildable = self::initializeNewBuildable($actor) 54 ->setBuildablePHID($buildable_object_phid) 55 ->setContainerPHID($container_object_phid); 56 $buildable->save(); 57 return $buildable; 58 } 59 60 /** 61 * Start builds for a given buildable. 62 * 63 * @param string $phid PHID of the object to build. 64 * @param string $container_phid Container PHID for the buildable. 65 * @param array<HarbormasterBuildRequest> $requests List of builds to 66 * perform. 67 * @return void 68 */ 69 public static function applyBuildPlans( 70 $phid, 71 $container_phid, 72 array $requests) { 73 74 assert_instances_of($requests, HarbormasterBuildRequest::class); 75 76 if (!$requests) { 77 return; 78 } 79 80 // Skip all of this logic if the Harbormaster application 81 // isn't currently enabled. 82 83 $harbormaster_app = PhabricatorHarbormasterApplication::class; 84 if (!PhabricatorApplication::isClassInstalled($harbormaster_app)) { 85 return; 86 } 87 88 $viewer = PhabricatorUser::getOmnipotentUser(); 89 90 $buildable = self::createOrLoadExisting( 91 $viewer, 92 $phid, 93 $container_phid); 94 95 $plan_phids = mpull($requests, 'getBuildPlanPHID'); 96 $plans = id(new HarbormasterBuildPlanQuery()) 97 ->setViewer($viewer) 98 ->withPHIDs($plan_phids) 99 ->execute(); 100 $plans = mpull($plans, null, 'getPHID'); 101 102 foreach ($requests as $request) { 103 $plan_phid = $request->getBuildPlanPHID(); 104 $plan = idx($plans, $plan_phid); 105 106 if (!$plan) { 107 throw new Exception( 108 pht( 109 'Failed to load build plan ("%s").', 110 $plan_phid)); 111 } 112 113 if ($plan->isDisabled()) { 114 // TODO: This should be communicated more clearly -- maybe we should 115 // create the build but set the status to "disabled" or "derelict". 116 continue; 117 } 118 119 $parameters = $request->getBuildParameters(); 120 $buildable->applyPlan($plan, $parameters, $request->getInitiatorPHID()); 121 } 122 } 123 124 public function applyPlan( 125 HarbormasterBuildPlan $plan, 126 array $parameters, 127 $initiator_phid) { 128 129 $viewer = PhabricatorUser::getOmnipotentUser(); 130 $build = HarbormasterBuild::initializeNewBuild($viewer) 131 ->setBuildablePHID($this->getPHID()) 132 ->setBuildPlanPHID($plan->getPHID()) 133 ->setBuildParameters($parameters) 134 ->setBuildStatus(HarbormasterBuildStatus::STATUS_PENDING); 135 if ($initiator_phid) { 136 $build->setInitiatorPHID($initiator_phid); 137 } 138 139 $auto_key = $plan->getPlanAutoKey(); 140 if ($auto_key) { 141 $build->setPlanAutoKey($auto_key); 142 } 143 144 $build->save(); 145 146 $steps = id(new HarbormasterBuildStepQuery()) 147 ->setViewer($viewer) 148 ->withBuildPlanPHIDs(array($plan->getPHID())) 149 ->execute(); 150 151 foreach ($steps as $step) { 152 $step->willStartBuild($viewer, $this, $build, $plan); 153 } 154 155 PhabricatorWorker::scheduleTask( 156 'HarbormasterBuildWorker', 157 array( 158 'buildID' => $build->getID(), 159 ), 160 array( 161 'objectPHID' => $build->getPHID(), 162 )); 163 164 return $build; 165 } 166 167 protected function getConfiguration() { 168 return array( 169 self::CONFIG_AUX_PHID => true, 170 self::CONFIG_COLUMN_SCHEMA => array( 171 'containerPHID' => 'phid?', 172 'buildableStatus' => 'text32', 173 'isManualBuildable' => 'bool', 174 ), 175 self::CONFIG_KEY_SCHEMA => array( 176 'key_buildable' => array( 177 'columns' => array('buildablePHID'), 178 ), 179 'key_container' => array( 180 'columns' => array('containerPHID'), 181 ), 182 'key_manual' => array( 183 'columns' => array('isManualBuildable'), 184 ), 185 ), 186 ) + parent::getConfiguration(); 187 } 188 189 public function generatePHID() { 190 return PhabricatorPHID::generateNewPHID( 191 HarbormasterBuildablePHIDType::TYPECONST); 192 } 193 194 public function attachBuildableObject($buildable_object) { 195 $this->buildableObject = $buildable_object; 196 return $this; 197 } 198 199 public function getBuildableObject() { 200 return $this->assertAttached($this->buildableObject); 201 } 202 203 public function attachContainerObject($container_object) { 204 $this->containerObject = $container_object; 205 return $this; 206 } 207 208 public function getContainerObject() { 209 return $this->assertAttached($this->containerObject); 210 } 211 212 /** 213 * @param array<HarbormasterBuild> $builds 214 */ 215 public function attachBuilds(array $builds) { 216 assert_instances_of($builds, HarbormasterBuild::class); 217 $this->builds = $builds; 218 return $this; 219 } 220 221 public function getBuilds() { 222 return $this->assertAttached($this->builds); 223 } 224 225 226/* -( Status )------------------------------------------------------------- */ 227 228 229 public function getBuildableStatusObject() { 230 $status = $this->getBuildableStatus(); 231 return HarbormasterBuildableStatus::newBuildableStatusObject($status); 232 } 233 234 public function getStatusIcon() { 235 return $this->getBuildableStatusObject()->getIcon(); 236 } 237 238 public function getStatusDisplayName() { 239 return $this->getBuildableStatusObject()->getDisplayName(); 240 } 241 242 public function getStatusColor() { 243 return $this->getBuildableStatusObject()->getColor(); 244 } 245 246 public function isPreparing() { 247 return $this->getBuildableStatusObject()->isPreparing(); 248 } 249 250 public function isBuilding() { 251 return $this->getBuildableStatusObject()->isBuilding(); 252 } 253 254 255/* -( Messages )----------------------------------------------------------- */ 256 257 258 public function sendMessage( 259 PhabricatorUser $viewer, 260 $message_type, 261 $queue_update) { 262 263 $message = HarbormasterBuildMessage::initializeNewMessage($viewer) 264 ->setReceiverPHID($this->getPHID()) 265 ->setType($message_type) 266 ->save(); 267 268 if ($queue_update) { 269 PhabricatorWorker::scheduleTask( 270 'HarbormasterBuildWorker', 271 array( 272 'buildablePHID' => $this->getPHID(), 273 ), 274 array( 275 'objectPHID' => $this->getPHID(), 276 )); 277 } 278 279 return $message; 280 } 281 282 283/* -( PhabricatorApplicationTransactionInterface )------------------------- */ 284 285 286 public function getApplicationTransactionEditor() { 287 return new HarbormasterBuildableTransactionEditor(); 288 } 289 290 public function getApplicationTransactionTemplate() { 291 return new HarbormasterBuildableTransaction(); 292 } 293 294 295/* -( PhabricatorPolicyInterface )----------------------------------------- */ 296 297 298 public function getCapabilities() { 299 return array( 300 PhabricatorPolicyCapability::CAN_VIEW, 301 PhabricatorPolicyCapability::CAN_EDIT, 302 ); 303 } 304 305 public function getPolicy($capability) { 306 return $this->getBuildableObject()->getPolicy($capability); 307 } 308 309 public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { 310 return $this->getBuildableObject()->hasAutomaticCapability( 311 $capability, 312 $viewer); 313 } 314 315 public function describeAutomaticCapability($capability) { 316 return pht('A buildable inherits policies from the underlying object.'); 317 } 318 319 320 321/* -( HarbormasterBuildableInterface )------------------------------------- */ 322 323 324 public function getHarbormasterBuildableDisplayPHID() { 325 return $this->getBuildableObject()->getHarbormasterBuildableDisplayPHID(); 326 } 327 328 public function getHarbormasterBuildablePHID() { 329 // NOTE: This is essentially just for convenience, as it allows you create 330 // a copy of a buildable by specifying `B123` without bothering to go 331 // look up the underlying object. 332 return $this->getBuildablePHID(); 333 } 334 335 public function getHarbormasterContainerPHID() { 336 return $this->getContainerPHID(); 337 } 338 339 public function getBuildVariables() { 340 return array(); 341 } 342 343 public function getAvailableBuildVariables() { 344 return array(); 345 } 346 347 public function newBuildableEngine() { 348 return $this->getBuildableObject()->newBuildableEngine(); 349 } 350 351 352/* -( PhabricatorConduitResultInterface )---------------------------------- */ 353 354 355 public function getFieldSpecificationsForConduit() { 356 return array( 357 id(new PhabricatorConduitSearchFieldSpecification()) 358 ->setKey('objectPHID') 359 ->setType('phid') 360 ->setDescription(pht('PHID of the object that is built.')), 361 id(new PhabricatorConduitSearchFieldSpecification()) 362 ->setKey('containerPHID') 363 ->setType('phid') 364 ->setDescription(pht('PHID of the object containing this buildable.')), 365 id(new PhabricatorConduitSearchFieldSpecification()) 366 ->setKey('buildableStatus') 367 ->setType('map<string, wild>') 368 ->setDescription(pht('The current status of this buildable.')), 369 id(new PhabricatorConduitSearchFieldSpecification()) 370 ->setKey('isManual') 371 ->setType('bool') 372 ->setDescription(pht('True if this is a manual buildable.')), 373 id(new PhabricatorConduitSearchFieldSpecification()) 374 ->setKey('uri') 375 ->setType('uri') 376 ->setDescription(pht('View URI for the buildable.')), 377 ); 378 } 379 380 public function getFieldValuesForConduit() { 381 return array( 382 'objectPHID' => $this->getBuildablePHID(), 383 'containerPHID' => $this->getContainerPHID(), 384 'buildableStatus' => array( 385 'value' => $this->getBuildableStatus(), 386 ), 387 'isManual' => (bool)$this->getIsManualBuildable(), 388 'uri' => PhabricatorEnv::getURI($this->getURI()), 389 ); 390 } 391 392 public function getConduitSearchAttachments() { 393 return array(); 394 } 395 396 397/* -( PhabricatorDestructibleInterface )----------------------------------- */ 398 399 400 public function destroyObjectPermanently( 401 PhabricatorDestructionEngine $engine) { 402 $viewer = $engine->getViewer(); 403 404 $this->openTransaction(); 405 $builds = id(new HarbormasterBuildQuery()) 406 ->setViewer($viewer) 407 ->withBuildablePHIDs(array($this->getPHID())) 408 ->execute(); 409 foreach ($builds as $build) { 410 $engine->destroyObject($build); 411 } 412 413 $messages = id(new HarbormasterBuildMessageQuery()) 414 ->setViewer($viewer) 415 ->withReceiverPHIDs(array($this->getPHID())) 416 ->execute(); 417 foreach ($messages as $message) { 418 $engine->destroyObject($message); 419 } 420 421 $this->delete(); 422 $this->saveTransaction(); 423 } 424 425}