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

Move structural build publishing logic to BuildEngine, provide "bin/harbormaster publish"

Summary:
Depends on D19278. Ref T13110. This moves most of the structural logic for publishing builds to BuildableEngine and provides a `bin/harbormaster publish` to make publishing easy to retry/debug.

This intentionally removes the bit which actually does anything when builds publish. Followup changes will implement application-specific versions of the publishing logic in Differential and Diffusion.

Test Plan: Ran `bin/harbormaster publish Bxxx`, saw it do nothing (but not crash).

Subscribers: PHID-OPKG-gm6ozazyms6q6i22gyam

Maniphest Tasks: T13110

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

+211 -60
+2
src/__phutil_library_map__.php
··· 1324 1324 'HarbormasterLogWorker' => 'applications/harbormaster/worker/HarbormasterLogWorker.php', 1325 1325 'HarbormasterManagementArchiveLogsWorkflow' => 'applications/harbormaster/management/HarbormasterManagementArchiveLogsWorkflow.php', 1326 1326 'HarbormasterManagementBuildWorkflow' => 'applications/harbormaster/management/HarbormasterManagementBuildWorkflow.php', 1327 + 'HarbormasterManagementPublishWorkflow' => 'applications/harbormaster/management/HarbormasterManagementPublishWorkflow.php', 1327 1328 'HarbormasterManagementRebuildLogWorkflow' => 'applications/harbormaster/management/HarbormasterManagementRebuildLogWorkflow.php', 1328 1329 'HarbormasterManagementRestartWorkflow' => 'applications/harbormaster/management/HarbormasterManagementRestartWorkflow.php', 1329 1330 'HarbormasterManagementUpdateWorkflow' => 'applications/harbormaster/management/HarbormasterManagementUpdateWorkflow.php', ··· 6675 6676 'HarbormasterLogWorker' => 'HarbormasterWorker', 6676 6677 'HarbormasterManagementArchiveLogsWorkflow' => 'HarbormasterManagementWorkflow', 6677 6678 'HarbormasterManagementBuildWorkflow' => 'HarbormasterManagementWorkflow', 6679 + 'HarbormasterManagementPublishWorkflow' => 'HarbormasterManagementWorkflow', 6678 6680 'HarbormasterManagementRebuildLogWorkflow' => 'HarbormasterManagementWorkflow', 6679 6681 'HarbormasterManagementRestartWorkflow' => 'HarbormasterManagementWorkflow', 6680 6682 'HarbormasterManagementUpdateWorkflow' => 'HarbormasterManagementWorkflow',
+24 -59
src/applications/harbormaster/engine/HarbormasterBuildEngine.php
··· 489 489 } 490 490 } 491 491 492 + $old = clone $buildable; 493 + 492 494 // Don't update the buildable status if we're still preparing builds: more 493 495 // builds may still be scheduled shortly, so even if every build we know 494 496 // about so far has passed, that doesn't mean the buildable has actually ··· 515 517 $new_status = HarbormasterBuildableStatus::STATUS_BUILDING; 516 518 } 517 519 518 - $old_status = $buildable->getBuildableStatus(); 519 - $did_update = ($old_status != $new_status); 520 + $did_update = ($old->getBuildableStatus() !== $new_status); 520 521 if ($did_update) { 521 522 $buildable->setBuildableStatus($new_status); 522 523 $buildable->save(); ··· 530 531 return; 531 532 } 532 533 533 - // If we changed the buildable status, try to post a transaction to the 534 - // object about it. We can safely do this outside of the locked region. 534 + $this->publishBuildable($old, $buildable); 535 + } 535 536 536 - // NOTE: We only post transactions for automatic buildables, not for 537 - // manual ones: manual builds are test builds, whoever is doing tests 538 - // can look at the results themselves, and other users generally don't 539 - // care about the outcome. 537 + public function publishBuildable( 538 + HarbormasterBuildable $old, 539 + HarbormasterBuildable $new) { 540 540 541 - $should_publish = 542 - ($did_update) && 543 - ($new_status != HarbormasterBuildableStatus::STATUS_BUILDING) && 544 - (!$buildable->getIsManualBuildable()); 541 + $viewer = $this->getViewer(); 545 542 546 - if (!$should_publish) { 547 - return; 548 - } 543 + // Publish the buildable. We publish buildables even if they haven't 544 + // changed status in Harbormaster because applications may care about 545 + // different things than Harbormaster does. For example, Differential 546 + // does not care about local lint and unit tests when deciding whether 547 + // a revision should move out of draft or not. 548 + 549 + // NOTE: We're publishing both automatic and manual buildables. Buildable 550 + // objects should generally ignore manual buildables, but it's up to them 551 + // to decide. 549 552 550 553 $object = id(new PhabricatorObjectQuery()) 551 554 ->setViewer($viewer) 552 - ->withPHIDs(array($buildable->getBuildablePHID())) 555 + ->withPHIDs(array($new->getBuildablePHID())) 553 556 ->executeOne(); 554 557 if (!$object) { 555 558 return; 556 559 } 557 560 558 - $publish_phid = $object->getHarbormasterPublishablePHID(); 559 - if (!$publish_phid) { 560 - return; 561 - } 561 + $engine = HarbormasterBuildableEngine::newForObject($object, $viewer); 562 562 563 - if ($publish_phid === $object->getPHID()) { 564 - $publish = $object; 565 - } else { 566 - $publish = id(new PhabricatorObjectQuery()) 567 - ->setViewer($viewer) 568 - ->withPHIDs(array($publish_phid)) 569 - ->executeOne(); 570 - if (!$publish) { 571 - return; 572 - } 573 - } 574 - 575 - if (!($publish instanceof PhabricatorApplicationTransactionInterface)) { 576 - return; 577 - } 578 - 579 - $template = $publish->getApplicationTransactionTemplate(); 580 - if (!$template) { 581 - return; 582 - } 583 - 584 - $template 585 - ->setTransactionType(PhabricatorTransactions::TYPE_BUILDABLE) 586 - ->setMetadataValue( 587 - 'harbormaster:buildablePHID', 588 - $buildable->getPHID()) 589 - ->setOldValue($old_status) 590 - ->setNewValue($new_status); 563 + $daemon_source = PhabricatorContentSource::newForSource( 564 + PhabricatorDaemonContentSource::SOURCECONST); 591 565 592 566 $harbormaster_phid = id(new PhabricatorHarbormasterApplication()) 593 567 ->getPHID(); 594 568 595 - $daemon_source = PhabricatorContentSource::newForSource( 596 - PhabricatorDaemonContentSource::SOURCECONST); 597 - 598 - $editor = $publish->getApplicationTransactionEditor() 599 - ->setActor($viewer) 569 + $engine 600 570 ->setActingAsPHID($harbormaster_phid) 601 571 ->setContentSource($daemon_source) 602 - ->setContinueOnNoEffect(true) 603 - ->setContinueOnMissingFields(true); 604 - 605 - $editor->applyTransactions( 606 - $publish->getApplicationTransactionObject(), 607 - array($template)); 572 + ->publishBuildable($old, $new); 608 573 } 609 574 610 575 private function releaseAllArtifacts(HarbormasterBuild $build) {
+98 -1
src/applications/harbormaster/engine/HarbormasterBuildableEngine.php
··· 1 1 <?php 2 2 3 3 abstract class HarbormasterBuildableEngine 4 - extends Phobject {} 4 + extends Phobject { 5 + 6 + private $viewer; 7 + private $actingAsPHID; 8 + private $contentSource; 9 + private $object; 10 + 11 + final public function setViewer(PhabricatorUser $viewer) { 12 + $this->viewer = $viewer; 13 + return $this; 14 + } 15 + 16 + final public function getViewer() { 17 + return $this->viewer; 18 + } 19 + 20 + final public function setActingAsPHID($acting_as_phid) { 21 + $this->actingAsPHID = $acting_as_phid; 22 + return $this; 23 + } 24 + 25 + final public function getActingAsPHID() { 26 + return $this->actingAsPHID; 27 + } 28 + 29 + final public function setContentSource( 30 + PhabricatorContentSource $content_source) { 31 + $this->contentSource = $content_source; 32 + return $this; 33 + } 34 + 35 + final public function getContentSource() { 36 + return $this->contentSource; 37 + } 38 + 39 + final public function setObject(HarbormasterBuildableInterface $object) { 40 + $this->object = $object; 41 + return $this; 42 + } 43 + 44 + final public function getObject() { 45 + return $this->object; 46 + } 47 + 48 + final public function publishBuildable( 49 + HarbormasterBuildable $old, 50 + HarbormasterBuildable $new) { 51 + return; 52 + } 53 + 54 + final public static function newForObject( 55 + HarbormasterBuildableInterface $object, 56 + PhabricatorUser $viewer) { 57 + return $object->newBuildableEngine() 58 + ->setViewer($viewer) 59 + ->setObject($object); 60 + } 61 + 62 + final protected function newEditor() { 63 + $publishable = $this->getObject(); 64 + 65 + $viewer = $this->getViewer(); 66 + 67 + $editor = $publishable->getApplicationTransactionEditor() 68 + ->setActor($viewer) 69 + ->setContinueOnNoEffect(true) 70 + ->setContinueOnMissingFields(true); 71 + 72 + $acting_as_phid = $this->getActingAsPHID(); 73 + if ($acting_as_phid !== null) { 74 + $editor->setActingAsPHID($acting_as_phid); 75 + } 76 + 77 + $content_source = $this->getContentSource(); 78 + if ($content_source !== null) { 79 + $editor->setContentSource($content_source); 80 + } 81 + 82 + return $editor; 83 + } 84 + 85 + final protected function newTransaction() { 86 + $publishable = $this->getObject(); 87 + 88 + return $publishable->getApplicationTransactionTemplate(); 89 + } 90 + 91 + final protected function applyTransactions(array $xactions) { 92 + $publishable = $this->getObject(); 93 + $editor = $this->newEditor(); 94 + 95 + $editor->applyTransactions( 96 + $publishable->getApplicationTransactionObject(), 97 + $xactions); 98 + } 99 + 100 + 101 + }
+87
src/applications/harbormaster/management/HarbormasterManagementPublishWorkflow.php
··· 1 + <?php 2 + 3 + final class HarbormasterManagementPublishWorkflow 4 + extends HarbormasterManagementWorkflow { 5 + 6 + protected function didConstruct() { 7 + $this 8 + ->setName('publish') 9 + ->setExamples(pht('**publish** __buildable__ ...')) 10 + ->setSynopsis( 11 + pht( 12 + 'Publish a buildable. This is primarily useful for developing '. 13 + 'and debugging applications which have buildable objects.')) 14 + ->setArguments( 15 + array( 16 + array( 17 + 'name' => 'buildable', 18 + 'wildcard' => true, 19 + ), 20 + )); 21 + } 22 + 23 + public function execute(PhutilArgumentParser $args) { 24 + $viewer = $this->getViewer(); 25 + 26 + $buildable_names = $args->getArg('buildable'); 27 + if (!$buildable_names) { 28 + throw new PhutilArgumentUsageException( 29 + pht( 30 + 'Name one or more buildables to publish, like "B123".')); 31 + } 32 + 33 + $query = id(new PhabricatorObjectQuery()) 34 + ->setViewer($viewer) 35 + ->withNames($buildable_names); 36 + 37 + $query->execute(); 38 + 39 + $result_map = $query->getNamedResults(); 40 + 41 + foreach ($buildable_names as $name) { 42 + if (!isset($result_map[$name])) { 43 + throw new PhutilArgumentUsageException( 44 + pht( 45 + 'Argument "%s" does not name a buildable. Provide one or more '. 46 + 'valid buildable monograms or PHIDs.', 47 + $name)); 48 + } 49 + } 50 + 51 + foreach ($result_map as $name => $result) { 52 + if (!($result instanceof HarbormasterBuildable)) { 53 + throw new PhutilArgumentUsageException( 54 + pht( 55 + 'Object "%s" is not a HarbormasterBuildable (it is a "%s"). '. 56 + 'Name one or more buildables to publish, like "B123".', 57 + get_class($result))); 58 + } 59 + } 60 + 61 + foreach ($result_map as $buildable) { 62 + echo tsprintf( 63 + "%s\n", 64 + pht( 65 + 'Publishing "%s"...', 66 + $buildable->getMonogram())); 67 + 68 + // Reload the buildable to pick up builds. 69 + $buildable = id(new HarbormasterBuildableQuery()) 70 + ->setViewer($viewer) 71 + ->withIDs(array($buildable->getID())) 72 + ->needBuilds(true) 73 + ->executeOne(); 74 + 75 + $engine = id(new HarbormasterBuildEngine()) 76 + ->setViewer($viewer) 77 + ->publishBuildable($buildable, $buildable); 78 + } 79 + 80 + echo tsprintf( 81 + "%s\n", 82 + pht('Done.')); 83 + 84 + return 0; 85 + } 86 + 87 + }