@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 506 lines 14 kB view raw
1<?php 2 3final class HarbormasterBuildTarget 4 extends HarbormasterDAO 5 implements 6 PhabricatorPolicyInterface, 7 PhabricatorDestructibleInterface, 8 PhabricatorConduitResultInterface { 9 10 protected $name; 11 protected $buildPHID; 12 protected $buildStepPHID; 13 protected $className; 14 protected $details; 15 protected $variables; 16 protected $targetStatus; 17 protected $dateStarted; 18 protected $dateCompleted; 19 protected $buildGeneration; 20 21 const STATUS_PENDING = 'target/pending'; 22 const STATUS_BUILDING = 'target/building'; 23 const STATUS_WAITING = 'target/waiting'; 24 const STATUS_PASSED = 'target/passed'; 25 const STATUS_FAILED = 'target/failed'; 26 const STATUS_ABORTED = 'target/aborted'; 27 28 private $build = self::ATTACHABLE; 29 private $buildStep = self::ATTACHABLE; 30 private $implementation; 31 32 public static function getBuildTargetStatusName($status) { 33 switch ($status) { 34 case self::STATUS_PENDING: 35 return pht('Pending'); 36 case self::STATUS_BUILDING: 37 return pht('Building'); 38 case self::STATUS_WAITING: 39 return pht('Waiting for Message'); 40 case self::STATUS_PASSED: 41 return pht('Passed'); 42 case self::STATUS_FAILED: 43 return pht('Failed'); 44 case self::STATUS_ABORTED: 45 return pht('Aborted'); 46 default: 47 return pht('Unknown'); 48 } 49 } 50 51 public static function getBuildTargetStatusIcon($status) { 52 switch ($status) { 53 case self::STATUS_PENDING: 54 return PHUIStatusItemView::ICON_OPEN; 55 case self::STATUS_BUILDING: 56 case self::STATUS_WAITING: 57 return PHUIStatusItemView::ICON_RIGHT; 58 case self::STATUS_PASSED: 59 return PHUIStatusItemView::ICON_ACCEPT; 60 case self::STATUS_FAILED: 61 return PHUIStatusItemView::ICON_REJECT; 62 case self::STATUS_ABORTED: 63 return PHUIStatusItemView::ICON_MINUS; 64 default: 65 return PHUIStatusItemView::ICON_QUESTION; 66 } 67 } 68 69 public static function getBuildTargetStatusColor($status) { 70 switch ($status) { 71 case self::STATUS_PENDING: 72 case self::STATUS_BUILDING: 73 case self::STATUS_WAITING: 74 return 'blue'; 75 case self::STATUS_PASSED: 76 return 'green'; 77 case self::STATUS_FAILED: 78 case self::STATUS_ABORTED: 79 return 'red'; 80 default: 81 return 'bluegrey'; 82 } 83 } 84 85 public static function initializeNewBuildTarget( 86 HarbormasterBuild $build, 87 HarbormasterBuildStep $build_step, 88 array $variables) { 89 return id(new HarbormasterBuildTarget()) 90 ->setName($build_step->getName()) 91 ->setBuildPHID($build->getPHID()) 92 ->setBuildStepPHID($build_step->getPHID()) 93 ->setClassName($build_step->getClassName()) 94 ->setDetails($build_step->getDetails()) 95 ->setTargetStatus(self::STATUS_PENDING) 96 ->setVariables($variables) 97 ->setBuildGeneration($build->getBuildGeneration()); 98 } 99 100 protected function getConfiguration() { 101 return array( 102 self::CONFIG_AUX_PHID => true, 103 self::CONFIG_SERIALIZATION => array( 104 'details' => self::SERIALIZATION_JSON, 105 'variables' => self::SERIALIZATION_JSON, 106 ), 107 self::CONFIG_COLUMN_SCHEMA => array( 108 'className' => 'text255', 109 'targetStatus' => 'text64', 110 'dateStarted' => 'epoch?', 111 'dateCompleted' => 'epoch?', 112 'buildGeneration' => 'uint32', 113 114 // T6203/NULLABILITY 115 // This should not be nullable. 116 'name' => 'text255?', 117 ), 118 self::CONFIG_KEY_SCHEMA => array( 119 'key_build' => array( 120 'columns' => array('buildPHID', 'buildStepPHID'), 121 ), 122 'key_started' => array( 123 'columns' => array('dateStarted'), 124 ), 125 'key_completed' => array( 126 'columns' => array('dateCompleted'), 127 ), 128 'key_created' => array( 129 'columns' => array('dateCreated'), 130 ), 131 ), 132 ) + parent::getConfiguration(); 133 } 134 135 public function generatePHID() { 136 return PhabricatorPHID::generateNewPHID( 137 HarbormasterBuildTargetPHIDType::TYPECONST); 138 } 139 140 public function attachBuild(HarbormasterBuild $build) { 141 $this->build = $build; 142 return $this; 143 } 144 145 public function getBuild() { 146 return $this->assertAttached($this->build); 147 } 148 149 public function attachBuildStep(?HarbormasterBuildStep $step = null) { 150 $this->buildStep = $step; 151 return $this; 152 } 153 154 public function getBuildStep() { 155 return $this->assertAttached($this->buildStep); 156 } 157 158 public function getDetail($key, $default = null) { 159 return idx($this->details, $key, $default); 160 } 161 162 public function setDetail($key, $value) { 163 $this->details[$key] = $value; 164 return $this; 165 } 166 167 public function getVariables() { 168 return parent::getVariables() + $this->getBuildTargetVariables(); 169 } 170 171 public function getVariable($key, $default = null) { 172 return idx($this->variables, $key, $default); 173 } 174 175 public function setVariable($key, $value) { 176 $this->variables[$key] = $value; 177 return $this; 178 } 179 180 public function getImplementation() { 181 if ($this->implementation === null) { 182 $obj = HarbormasterBuildStepImplementation::requireImplementation( 183 $this->className); 184 $obj->loadSettings($this); 185 $this->implementation = $obj; 186 } 187 188 return $this->implementation; 189 } 190 191 public function isAutotarget() { 192 try { 193 return (bool)$this->getImplementation()->getBuildStepAutotargetPlanKey(); 194 } catch (Exception $e) { 195 return false; 196 } 197 } 198 199 public function getName() { 200 if (strlen($this->name) && !$this->isAutotarget()) { 201 return $this->name; 202 } 203 204 try { 205 return $this->getImplementation()->getName(); 206 } catch (Exception $e) { 207 return $this->getClassName(); 208 } 209 } 210 211 private function getBuildTargetVariables() { 212 return array( 213 'target.phid' => $this->getPHID(), 214 ); 215 } 216 217 public function createArtifact( 218 PhabricatorUser $actor, 219 $artifact_key, 220 $artifact_type, 221 array $artifact_data) { 222 223 $impl = HarbormasterArtifact::getArtifactType($artifact_type); 224 if (!$impl) { 225 throw new Exception( 226 pht( 227 'There is no implementation available for artifacts of type "%s".', 228 $artifact_type)); 229 } 230 231 $impl->validateArtifactData($artifact_data); 232 233 $artifact = HarbormasterBuildArtifact::initializeNewBuildArtifact($this) 234 ->setArtifactKey($artifact_key) 235 ->setArtifactType($artifact_type) 236 ->setArtifactData($artifact_data); 237 238 $impl = $artifact->getArtifactImplementation(); 239 $impl->willCreateArtifact($actor); 240 241 return $artifact->save(); 242 } 243 244 public function loadArtifact($artifact_key) { 245 $indexes = array(); 246 247 $indexes[] = HarbormasterBuildArtifact::getArtifactIndex( 248 $this, 249 $artifact_key); 250 251 $artifact = id(new HarbormasterBuildArtifactQuery()) 252 ->setViewer(PhabricatorUser::getOmnipotentUser()) 253 ->withArtifactIndexes($indexes) 254 ->executeOne(); 255 if ($artifact === null) { 256 throw new Exception( 257 pht( 258 'Artifact "%s" not found!', 259 $artifact_key)); 260 } 261 262 return $artifact; 263 } 264 265 public function newLog($log_source, $log_type) { 266 $log_source = id(new PhutilUTF8StringTruncator()) 267 ->setMaximumBytes(250) 268 ->truncateString($log_source); 269 270 $log = HarbormasterBuildLog::initializeNewBuildLog($this) 271 ->setLogSource($log_source) 272 ->setLogType($log_type) 273 ->openBuildLog(); 274 275 return $log; 276 } 277 278 public function getFieldValue($key) { 279 $field_list = PhabricatorCustomField::getObjectFields( 280 $this->getBuildStep(), 281 PhabricatorCustomField::ROLE_VIEW); 282 283 $fields = $field_list->getFields(); 284 $full_key = "std:harbormaster:core:{$key}"; 285 286 $field = idx($fields, $full_key); 287 if (!$field) { 288 throw new Exception( 289 pht( 290 'Unknown build step field "%s"!', 291 $key)); 292 } 293 294 $field = clone $field; 295 $field->setValueFromStorage($this->getDetail($key)); 296 return $field->getBuildTargetFieldValue(); 297 } 298 299 300 301/* -( Status )------------------------------------------------------------- */ 302 303 304 public function isComplete() { 305 switch ($this->getTargetStatus()) { 306 case self::STATUS_PASSED: 307 case self::STATUS_FAILED: 308 case self::STATUS_ABORTED: 309 return true; 310 } 311 312 return false; 313 } 314 315 316 public function isFailed() { 317 switch ($this->getTargetStatus()) { 318 case self::STATUS_FAILED: 319 case self::STATUS_ABORTED: 320 return true; 321 } 322 323 return false; 324 } 325 326 327 public function isWaiting() { 328 switch ($this->getTargetStatus()) { 329 case self::STATUS_WAITING: 330 return true; 331 } 332 333 return false; 334 } 335 336 public function isUnderway() { 337 switch ($this->getTargetStatus()) { 338 case self::STATUS_PENDING: 339 case self::STATUS_BUILDING: 340 return true; 341 } 342 343 return false; 344 } 345 346 347/* -( PhabricatorPolicyInterface )----------------------------------------- */ 348 349 350 public function getCapabilities() { 351 return array( 352 PhabricatorPolicyCapability::CAN_VIEW, 353 ); 354 } 355 356 public function getPolicy($capability) { 357 return $this->getBuild()->getPolicy($capability); 358 } 359 360 public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { 361 return $this->getBuild()->hasAutomaticCapability( 362 $capability, 363 $viewer); 364 } 365 366 public function describeAutomaticCapability($capability) { 367 return pht('Users must be able to see a build to view its build targets.'); 368 } 369 370 371/* -( PhabricatorDestructibleInterface )----------------------------------- */ 372 373 374 public function destroyObjectPermanently( 375 PhabricatorDestructionEngine $engine) { 376 $viewer = $engine->getViewer(); 377 378 $this->openTransaction(); 379 380 $lint_message = new HarbormasterBuildLintMessage(); 381 $conn = $lint_message->establishConnection('w'); 382 queryfx( 383 $conn, 384 'DELETE FROM %T WHERE buildTargetPHID = %s', 385 $lint_message->getTableName(), 386 $this->getPHID()); 387 388 $unit_message = new HarbormasterBuildUnitMessage(); 389 $conn = $unit_message->establishConnection('w'); 390 queryfx( 391 $conn, 392 'DELETE FROM %T WHERE buildTargetPHID = %s', 393 $unit_message->getTableName(), 394 $this->getPHID()); 395 396 $logs = id(new HarbormasterBuildLogQuery()) 397 ->setViewer($viewer) 398 ->withBuildTargetPHIDs(array($this->getPHID())) 399 ->execute(); 400 foreach ($logs as $log) { 401 $engine->destroyObject($log); 402 } 403 404 $artifacts = id(new HarbormasterBuildArtifactQuery()) 405 ->setViewer($viewer) 406 ->withBuildTargetPHIDs(array($this->getPHID())) 407 ->execute(); 408 foreach ($artifacts as $artifact) { 409 $engine->destroyObject($artifact); 410 } 411 412 $messages = id(new HarbormasterBuildMessageQuery()) 413 ->setViewer($viewer) 414 ->withReceiverPHIDs(array($this->getPHID())) 415 ->execute(); 416 foreach ($messages as $message) { 417 $engine->destroyObject($message); 418 } 419 420 $this->delete(); 421 $this->saveTransaction(); 422 } 423 424 425/* -( PhabricatorConduitResultInterface )---------------------------------- */ 426 427 428 public function getFieldSpecificationsForConduit() { 429 return array( 430 id(new PhabricatorConduitSearchFieldSpecification()) 431 ->setKey('name') 432 ->setType('string') 433 ->setDescription(pht('The name of the build target.')), 434 id(new PhabricatorConduitSearchFieldSpecification()) 435 ->setKey('buildPHID') 436 ->setType('phid') 437 ->setDescription(pht('The build the target is associated with.')), 438 id(new PhabricatorConduitSearchFieldSpecification()) 439 ->setKey('buildStepPHID') 440 ->setType('phid') 441 ->setDescription(pht('The build step the target runs.')), 442 id(new PhabricatorConduitSearchFieldSpecification()) 443 ->setKey('status') 444 ->setType('map<string, wild>') 445 ->setDescription(pht('Status for the build target.')), 446 id(new PhabricatorConduitSearchFieldSpecification()) 447 ->setKey('epochStarted') 448 ->setType('epoch?') 449 ->setDescription( 450 pht( 451 'Epoch timestamp for target start, if the target '. 452 'has started.')), 453 id(new PhabricatorConduitSearchFieldSpecification()) 454 ->setKey('epochCompleted') 455 ->setType('epoch?') 456 ->setDescription( 457 pht( 458 'Epoch timestamp for target completion, if the target '. 459 'has completed.')), 460 id(new PhabricatorConduitSearchFieldSpecification()) 461 ->setKey('buildGeneration') 462 ->setType('int') 463 ->setDescription( 464 pht( 465 'Build generation this target belongs to. When builds '. 466 'restart, a new generation with new targets is created.')), 467 ); 468 } 469 470 public function getFieldValuesForConduit() { 471 $status = $this->getTargetStatus(); 472 473 $epoch_started = $this->getDateStarted(); 474 if ($epoch_started) { 475 $epoch_started = (int)$epoch_started; 476 } else { 477 $epoch_started = null; 478 } 479 480 $epoch_completed = $this->getDateCompleted(); 481 if ($epoch_completed) { 482 $epoch_completed = (int)$epoch_completed; 483 } else { 484 $epoch_completed = null; 485 } 486 487 return array( 488 'name' => $this->getName(), 489 'buildPHID' => $this->getBuildPHID(), 490 'buildStepPHID' => $this->getBuildStepPHID(), 491 'status' => array( 492 'value' => $status, 493 'name' => self::getBuildTargetStatusName($status), 494 ), 495 'epochStarted' => $epoch_started, 496 'epochCompleted' => $epoch_completed, 497 'buildGeneration' => (int)$this->getBuildGeneration(), 498 ); 499 } 500 501 public function getConduitSearchAttachments() { 502 return array(); 503 } 504 505 506}