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

Record build success or failure on buildable objects

Summary:
Fixes T4810. When a buildable completes, make an effort to update the corresponding object with a success or failure message. Commits don't support this yet, but revisions do.

{F144614}

Test Plan:
- Used `bin/harbormaster build` and `bin/harbormaster update` to run a pile of builds.
- Tried good/bad builds.
- Sent some normal mail to make sure the mail reentrancy change didn't break stuff.

Reviewers: btrahan

Reviewed By: btrahan

Subscribers: epriestley

Maniphest Tasks: T4810

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

+161 -8
+54 -2
src/applications/harbormaster/engine/HarbormasterBuildEngine.php
··· 360 360 * @return void 361 361 */ 362 362 private function updateBuildable(HarbormasterBuildable $buildable) { 363 + $viewer = $this->getViewer(); 364 + 363 365 $lock_key = 'harbormaster.buildable:'.$buildable->getID(); 364 366 $lock = PhabricatorGlobalLock::newLock($lock_key)->lock(15); 365 367 366 368 $buildable = id(new HarbormasterBuildableQuery()) 367 - ->setViewer($this->getViewer()) 369 + ->setViewer($viewer) 368 370 ->withIDs(array($buildable->getID())) 369 371 ->needBuilds(true) 370 372 ->executeOne(); ··· 389 391 $new_status = HarbormasterBuildable::STATUS_BUILDING; 390 392 } 391 393 392 - if ($buildable->getBuildableStatus() != $new_status) { 394 + $old_status = $buildable->getBuildableStatus(); 395 + $did_update = ($old_status != $new_status); 396 + if ($did_update) { 393 397 $buildable->setBuildableStatus($new_status); 394 398 $buildable->save(); 395 399 } 396 400 397 401 $lock->unlock(); 402 + 403 + // If we changed the buildable status, try to post a transaction to the 404 + // object about it. We can safely do this outside of the locked region. 405 + 406 + // NOTE: We only post transactions for automatic buildables, not for 407 + // manual ones: manual builds are test builds, whoever is doing tests 408 + // can look at the results themselves, and other users generally don't 409 + // care about the outcome. 410 + 411 + if ($did_update && !$buildable->getIsManualBuildable()) { 412 + 413 + $object = id(new PhabricatorObjectQuery()) 414 + ->setViewer($viewer) 415 + ->withPHIDs(array($buildable->getBuildablePHID())) 416 + ->executeOne(); 417 + 418 + if ($object instanceof PhabricatorApplicationTransactionInterface) { 419 + $template = $object->getApplicationTransactionTemplate(); 420 + if ($template) { 421 + $template 422 + ->setTransactionType(PhabricatorTransactions::TYPE_BUILDABLE) 423 + ->setMetadataValue( 424 + 'harbormaster:buildablePHID', 425 + $buildable->getPHID()) 426 + ->setOldValue($old_status) 427 + ->setNewValue($new_status); 428 + 429 + $harbormaster_phid = id(new PhabricatorApplicationHarbormaster()) 430 + ->getPHID(); 431 + 432 + $daemon_source = PhabricatorContentSource::newForSource( 433 + PhabricatorContentSource::SOURCE_DAEMON, 434 + array()); 435 + 436 + $editor = $object->getApplicationTransactionEditor() 437 + ->setActor($viewer) 438 + ->setActingAsPHID($harbormaster_phid) 439 + ->setContentSource($daemon_source) 440 + ->setContinueOnNoEffect(true) 441 + ->setContinueOnMissingFields(true); 442 + 443 + $editor->applyTransactions( 444 + $object->getApplicationTransactionObject(), 445 + array($template)); 446 + } 447 + } 448 + } 449 + 398 450 } 399 451 400 452 }
+19 -6
src/applications/metamta/storage/PhabricatorMetaMTAMail.php
··· 292 292 return $this->save(); 293 293 } 294 294 295 - protected function didWriteData() { 296 - parent::didWriteData(); 295 + public function save() { 296 + if ($this->getID()) { 297 + return parent::save(); 298 + } 299 + 300 + // NOTE: When mail is sent from CLI scripts that run tasks in-process, we 301 + // may re-enter this method from within scheduleTask(). The implementation 302 + // is intended to avoid anything awkward if we end up reentering this 303 + // method. 304 + 305 + $this->openTransaction(); 306 + // Save to generate a task ID. 307 + parent::save(); 297 308 298 - if (!$this->getWorkerTaskID()) { 309 + // Queue a task to send this mail. 299 310 $mailer_task = PhabricatorWorker::scheduleTask( 300 311 'PhabricatorMetaMTAWorker', 301 312 $this->getID()); 302 313 314 + // Save again to update the task ID. 303 315 $this->setWorkerTaskID($mailer_task->getID()); 304 - $this->save(); 305 - } 306 - } 316 + $result = parent::save(); 317 + $this->saveTransaction(); 307 318 319 + return $result; 320 + } 308 321 309 322 public function buildDefaultMailer() { 310 323 return PhabricatorEnv::newObjectFromConfig('metamta.mail-adapter');
+1
src/applications/transactions/constants/PhabricatorTransactions.php
··· 9 9 const TYPE_JOIN_POLICY = 'core:join-policy'; 10 10 const TYPE_EDGE = 'core:edge'; 11 11 const TYPE_CUSTOMFIELD = 'core:customfield'; 12 + const TYPE_BUILDABLE = 'harbormaster:buildable'; 12 13 13 14 const COLOR_RED = 'red'; 14 15 const COLOR_ORANGE = 'orange';
+10
src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php
··· 155 155 $types[] = PhabricatorTransactions::TYPE_CUSTOMFIELD; 156 156 } 157 157 158 + if ($this->object instanceof HarbormasterBuildableInterface) { 159 + $types[] = PhabricatorTransactions::TYPE_BUILDABLE; 160 + } 161 + 158 162 return $types; 159 163 } 160 164 ··· 222 226 case PhabricatorTransactions::TYPE_VIEW_POLICY: 223 227 case PhabricatorTransactions::TYPE_EDIT_POLICY: 224 228 case PhabricatorTransactions::TYPE_JOIN_POLICY: 229 + case PhabricatorTransactions::TYPE_BUILDABLE: 225 230 return $xaction->getNewValue(); 226 231 case PhabricatorTransactions::TYPE_EDGE: 227 232 return $this->getEdgeTransactionNewValue($xaction); ··· 311 316 PhabricatorApplicationTransaction $xaction) { 312 317 313 318 switch ($xaction->getTransactionType()) { 319 + case PhabricatorTransactions::TYPE_BUILDABLE: 320 + return; 314 321 case PhabricatorTransactions::TYPE_VIEW_POLICY: 315 322 $object->setViewPolicy($xaction->getNewValue()); 316 323 break; ··· 321 328 $field = $this->getCustomFieldForTransaction($object, $xaction); 322 329 return $field->applyApplicationTransactionInternalEffects($xaction); 323 330 } 331 + 324 332 return $this->applyCustomInternalTransaction($object, $xaction); 325 333 } 326 334 ··· 328 336 PhabricatorLiskDAO $object, 329 337 PhabricatorApplicationTransaction $xaction) { 330 338 switch ($xaction->getTransactionType()) { 339 + case PhabricatorTransactions::TYPE_BUILDABLE: 340 + return; 331 341 case PhabricatorTransactions::TYPE_SUBSCRIBERS: 332 342 $subeditor = id(new PhabricatorSubscriptionsEditor()) 333 343 ->setObject($object)
+77
src/applications/transactions/storage/PhabricatorApplicationTransaction.php
··· 52 52 53 53 public function shouldGenerateOldValue() { 54 54 switch ($this->getTransactionType()) { 55 + case PhabricatorTransactions::TYPE_BUILDABLE: 56 + return false; 55 57 case PhabricatorTransactions::TYPE_CUSTOMFIELD: 56 58 return false; 57 59 } ··· 234 236 $phids[] = array($new); 235 237 } 236 238 break; 239 + case PhabricatorTransactions::TYPE_BUILDABLE: 240 + $phid = $this->getMetadataValue('harbormaster:buildablePHID'); 241 + if ($phid) { 242 + $phids[] = array($phid); 243 + } 244 + break; 237 245 } 238 246 239 247 return array_mergev($phids); ··· 325 333 return 'lock'; 326 334 case PhabricatorTransactions::TYPE_EDGE: 327 335 return 'link'; 336 + case PhabricatorTransactions::TYPE_BUILDABLE: 337 + return 'wrench'; 328 338 } 329 339 330 340 return 'edit'; 331 341 } 332 342 333 343 public function getColor() { 344 + switch ($this->getTransactionType()) { 345 + case PhabricatorTransactions::TYPE_BUILDABLE: 346 + switch ($this->getNewValue()) { 347 + case HarbormasterBuildable::STATUS_PASSED: 348 + return 'green'; 349 + case HarbormasterBuildable::STATUS_FAILED: 350 + return 'red'; 351 + } 352 + break; 353 + } 334 354 return null; 335 355 } 336 356 ··· 379 399 } 380 400 381 401 public function shouldHideForMail(array $xactions) { 402 + switch ($this->getTransactionType()) { 403 + case PhabricatorTransactions::TYPE_BUILDABLE: 404 + switch ($this->getNewValue()) { 405 + case HarbormasterBuildable::STATUS_PASSED: 406 + // For now, just never send mail when builds pass. We might let 407 + // you customize this later, but in most cases this is probably 408 + // completely uninteresting. 409 + return true; 410 + } 411 + } 412 + 382 413 return $this->shouldHide(); 383 414 } 384 415 ··· 537 568 $this->renderHandleLink($author_phid)); 538 569 } 539 570 571 + case PhabricatorTransactions::TYPE_BUILDABLE: 572 + switch ($this->getNewValue()) { 573 + case HarbormasterBuildable::STATUS_PASSED: 574 + return pht( 575 + '%s completed building %s.', 576 + $this->renderHandleLink($author_phid), 577 + $this->renderHandleLink( 578 + $this->getMetadataValue('harbormaster:buildablePHID'))); 579 + case HarbormasterBuildable::STATUS_FAILED: 580 + return pht( 581 + '%s failed to build %s!', 582 + $this->renderHandleLink($author_phid), 583 + $this->renderHandleLink( 584 + $this->getMetadataValue('harbormaster:buildablePHID'))); 585 + default: 586 + return null; 587 + } 588 + 540 589 default: 541 590 return pht( 542 591 '%s edited this %s.', ··· 596 645 $this->renderHandleLink($author_phid), 597 646 $this->renderHandleLink($object_phid)); 598 647 } 648 + case PhabricatorTransactions::TYPE_BUILDABLE: 649 + switch ($this->getNewValue()) { 650 + case HarbormasterBuildable::STATUS_PASSED: 651 + return pht( 652 + '%s completed building %s for %s.', 653 + $this->renderHandleLink($author_phid), 654 + $this->renderHandleLink( 655 + $this->getMetadataValue('harbormaster:buildablePHID')), 656 + $this->renderHandleLink($object_phid)); 657 + case HarbormasterBuildable::STATUS_FAILED: 658 + return pht( 659 + '%s failed to build %s for %s.', 660 + $this->renderHandleLink($author_phid), 661 + $this->renderHandleLink( 662 + $this->getMetadataValue('harbormaster:buildablePHID')), 663 + $this->renderHandleLink($object_phid)); 664 + default: 665 + return null; 666 + } 599 667 600 668 } 601 669 ··· 649 717 return pht('Changed Policy'); 650 718 case PhabricatorTransactions::TYPE_SUBSCRIBERS: 651 719 return pht('Changed Subscribers'); 720 + case PhabricatorTransactions::TYPE_BUILDABLE: 721 + switch ($this->getNewValue()) { 722 + case HarbormasterBuildable::STATUS_PASSED: 723 + return pht('Build Passed'); 724 + case HarbormasterBuildable::STATUS_FAILED: 725 + return pht('Build Failed'); 726 + default: 727 + return pht('Build Status'); 728 + } 652 729 default: 653 730 return pht('Updated'); 654 731 }