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

Add Nuance daemons and item types

Summary:
Ref T10537. This adds an update daemon for pulling item data (e.g., figuring out who the author of a GitHub comment is) and routing items (e.g., sending them to a queue or applying them directly to a task).

Also adds `bin/nuance update --item X` for doing this manually for debugging.

And adds item types, for specializing item behavior. Previously, sources completely dictated item behavior, but I think we want something a little more flexible.

Test Plan:
- This still does nothing.
- Ran `bin/nuance update --item 15`.
- Saw an item route to a default queue.

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T10537

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

+259 -10
+10
src/__phutil_library_map__.php
··· 1420 1420 'NuanceConsoleController' => 'applications/nuance/controller/NuanceConsoleController.php', 1421 1421 'NuanceController' => 'applications/nuance/controller/NuanceController.php', 1422 1422 'NuanceDAO' => 'applications/nuance/storage/NuanceDAO.php', 1423 + 'NuanceGitHubEventItemType' => 'applications/nuance/item/NuanceGitHubEventItemType.php', 1423 1424 'NuanceGitHubRepositoryImportCursor' => 'applications/nuance/cursor/NuanceGitHubRepositoryImportCursor.php', 1424 1425 'NuanceGitHubRepositorySourceDefinition' => 'applications/nuance/source/NuanceGitHubRepositorySourceDefinition.php', 1425 1426 'NuanceImportCursor' => 'applications/nuance/cursor/NuanceImportCursor.php', ··· 1437 1438 'NuanceItemTransaction' => 'applications/nuance/storage/NuanceItemTransaction.php', 1438 1439 'NuanceItemTransactionComment' => 'applications/nuance/storage/NuanceItemTransactionComment.php', 1439 1440 'NuanceItemTransactionQuery' => 'applications/nuance/query/NuanceItemTransactionQuery.php', 1441 + 'NuanceItemType' => 'applications/nuance/item/NuanceItemType.php', 1442 + 'NuanceItemUpdateWorker' => 'applications/nuance/worker/NuanceItemUpdateWorker.php', 1440 1443 'NuanceItemViewController' => 'applications/nuance/controller/NuanceItemViewController.php', 1441 1444 'NuanceManagementImportWorkflow' => 'applications/nuance/management/NuanceManagementImportWorkflow.php', 1445 + 'NuanceManagementUpdateWorkflow' => 'applications/nuance/management/NuanceManagementUpdateWorkflow.php', 1442 1446 'NuanceManagementWorkflow' => 'applications/nuance/management/NuanceManagementWorkflow.php', 1443 1447 'NuancePhabricatorFormSourceDefinition' => 'applications/nuance/source/NuancePhabricatorFormSourceDefinition.php', 1444 1448 'NuanceQuery' => 'applications/nuance/query/NuanceQuery.php', ··· 1488 1492 'NuanceSourceTransactionQuery' => 'applications/nuance/query/NuanceSourceTransactionQuery.php', 1489 1493 'NuanceSourceViewController' => 'applications/nuance/controller/NuanceSourceViewController.php', 1490 1494 'NuanceTransaction' => 'applications/nuance/storage/NuanceTransaction.php', 1495 + 'NuanceWorker' => 'applications/nuance/worker/NuanceWorker.php', 1491 1496 'OwnersConduitAPIMethod' => 'applications/owners/conduit/OwnersConduitAPIMethod.php', 1492 1497 'OwnersEditConduitAPIMethod' => 'applications/owners/conduit/OwnersEditConduitAPIMethod.php', 1493 1498 'OwnersPackageReplyHandler' => 'applications/owners/mail/OwnersPackageReplyHandler.php', ··· 5671 5676 'NuanceConsoleController' => 'NuanceController', 5672 5677 'NuanceController' => 'PhabricatorController', 5673 5678 'NuanceDAO' => 'PhabricatorLiskDAO', 5679 + 'NuanceGitHubEventItemType' => 'NuanceItemType', 5674 5680 'NuanceGitHubRepositoryImportCursor' => 'NuanceImportCursor', 5675 5681 'NuanceGitHubRepositorySourceDefinition' => 'NuanceSourceDefinition', 5676 5682 'NuanceImportCursor' => 'Phobject', ··· 5695 5701 'NuanceItemTransaction' => 'NuanceTransaction', 5696 5702 'NuanceItemTransactionComment' => 'PhabricatorApplicationTransactionComment', 5697 5703 'NuanceItemTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 5704 + 'NuanceItemType' => 'Phobject', 5705 + 'NuanceItemUpdateWorker' => 'NuanceWorker', 5698 5706 'NuanceItemViewController' => 'NuanceController', 5699 5707 'NuanceManagementImportWorkflow' => 'NuanceManagementWorkflow', 5708 + 'NuanceManagementUpdateWorkflow' => 'NuanceManagementWorkflow', 5700 5709 'NuanceManagementWorkflow' => 'PhabricatorManagementWorkflow', 5701 5710 'NuancePhabricatorFormSourceDefinition' => 'NuanceSourceDefinition', 5702 5711 'NuanceQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', ··· 5759 5768 'NuanceSourceTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 5760 5769 'NuanceSourceViewController' => 'NuanceSourceController', 5761 5770 'NuanceTransaction' => 'PhabricatorApplicationTransaction', 5771 + 'NuanceWorker' => 'PhabricatorWorker', 5762 5772 'OwnersConduitAPIMethod' => 'ConduitAPIMethod', 5763 5773 'OwnersEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod', 5764 5774 'OwnersPackageReplyHandler' => 'PhabricatorMailReplyHandler',
+2 -9
src/applications/nuance/cursor/NuanceGitHubRepositoryImportCursor.php
··· 166 166 $source->saveTransaction(); 167 167 168 168 foreach ($new_items as $new_item) { 169 - PhabricatorWorker::scheduleTask( 170 - 'NuanceImportWorker', 171 - array( 172 - 'itemPHID' => $new_item->getPHID(), 173 - ), 174 - array( 175 - 'objectPHID' => $new_item->getPHID(), 176 - )); 169 + $new_item->scheduleUpdate(); 177 170 } 178 171 179 172 return false; ··· 256 249 return NuanceItem::initializeNewItem() 257 250 ->setStatus(NuanceItem::STATUS_IMPORTING) 258 251 ->setSourcePHID($source->getPHID()) 259 - ->setItemType('github.event') 252 + ->setItemType(NuanceGitHubEventItemType::ITEMTYPE) 260 253 ->setItemKey($item_key) 261 254 ->setItemContainerKey($container_key) 262 255 ->setItemProperty('api.raw', $record);
+22
src/applications/nuance/item/NuanceGitHubEventItemType.php
··· 1 + <?php 2 + 3 + final class NuanceGitHubEventItemType 4 + extends NuanceItemType { 5 + 6 + const ITEMTYPE = 'github.event'; 7 + 8 + public function canUpdateItems() { 9 + return true; 10 + } 11 + 12 + protected function updateItemFromSource(NuanceItem $item) { 13 + // TODO: Link up the requestor, etc. 14 + 15 + if ($item->getStatus() == NuanceItem::STATUS_IMPORTING) { 16 + $item 17 + ->setStatus(NuanceItem::STATUS_ROUTING) 18 + ->save(); 19 + } 20 + } 21 + 22 + }
+37
src/applications/nuance/item/NuanceItemType.php
··· 1 + <?php 2 + 3 + abstract class NuanceItemType 4 + extends Phobject { 5 + 6 + public function canUpdateItems() { 7 + return false; 8 + } 9 + 10 + final public function updateItem(NuanceItem $item) { 11 + if (!$this->canUpdateItems()) { 12 + throw new Exception( 13 + pht( 14 + 'This item type ("%s", of class "%s") can not update items.', 15 + $this->getItemTypeConstant(), 16 + get_class($this))); 17 + } 18 + 19 + $this->updateItemFromSource($item); 20 + } 21 + 22 + protected function updateItemFromSource(NuanceItem $item) { 23 + throw new PhutilMethodNotImplementedException(); 24 + } 25 + 26 + final public function getItemTypeConstant() { 27 + return $this->getPhobjectClassConstant('ITEMTYPE', 64); 28 + } 29 + 30 + final public static function getAllItemTypes() { 31 + return id(new PhutilClassMapQuery()) 32 + ->setAncestorClass(__CLASS__) 33 + ->setUniqueMethod('getItemTypeConstant') 34 + ->execute(); 35 + } 36 + 37 + }
+1 -1
src/applications/nuance/management/NuanceManagementImportWorkflow.php
··· 6 6 protected function didConstruct() { 7 7 $this 8 8 ->setName('import') 9 - ->setExamples('**import** [__options__]') 9 + ->setExamples('**import** --source __source__ [__options__]') 10 10 ->setSynopsis(pht('Import data from a source.')) 11 11 ->setArguments( 12 12 array(
+30
src/applications/nuance/management/NuanceManagementUpdateWorkflow.php
··· 1 + <?php 2 + 3 + final class NuanceManagementUpdateWorkflow 4 + extends NuanceManagementWorkflow { 5 + 6 + protected function didConstruct() { 7 + $this 8 + ->setName('update') 9 + ->setExamples('**update** --item __item__ [__options__]') 10 + ->setSynopsis(pht('Update or route an item.')) 11 + ->setArguments( 12 + array( 13 + array( 14 + 'name' => 'item', 15 + 'param' => 'item', 16 + 'help' => pht('Choose which item to route.'), 17 + ), 18 + )); 19 + } 20 + 21 + public function execute(PhutilArgumentParser $args) { 22 + $item = $this->loadItem($args, 'item'); 23 + 24 + PhabricatorWorker::setRunAllTasksInProcess(true); 25 + $item->scheduleUpdate(); 26 + 27 + return 0; 28 + } 29 + 30 + }
+50
src/applications/nuance/management/NuanceManagementWorkflow.php
··· 64 64 return head($sources); 65 65 } 66 66 67 + protected function loadITem(PhutilArgumentParser $argv, $key) { 68 + $item = $argv->getArg($key); 69 + if (!strlen($item)) { 70 + throw new PhutilArgumentUsageException( 71 + pht( 72 + 'Specify a item with %s.', 73 + '--'.$key)); 74 + } 75 + 76 + $query = id(new NuanceItemQuery()) 77 + ->setViewer($this->getViewer()) 78 + ->setRaisePolicyExceptions(true); 79 + 80 + $type_unknown = PhabricatorPHIDConstants::PHID_TYPE_UNKNOWN; 81 + 82 + if (ctype_digit($item)) { 83 + $kind = 'id'; 84 + $query->withIDs(array($item)); 85 + } else if (phid_get_type($item) !== $type_unknown) { 86 + $kind = 'phid'; 87 + $query->withPHIDs($item); 88 + } else { 89 + throw new PhutilArgumentUsageException( 90 + pht( 91 + 'Specify the ID or PHID of an item to update. Parameter "%s" '. 92 + 'is not an ID or PHID.', 93 + $item)); 94 + } 95 + 96 + $items = $query->execute(); 97 + 98 + if (!$items) { 99 + switch ($kind) { 100 + case 'id': 101 + $message = pht( 102 + 'No item exists with ID "%s".', 103 + $item); 104 + break; 105 + case 'phid': 106 + $message = pht( 107 + 'No item exists with PHID "%s".', 108 + $item); 109 + break; 110 + } 111 + 112 + throw new PhutilArgumentUsageException($message); 113 + } 114 + 115 + return head($items); 116 + } 67 117 }
+11
src/applications/nuance/query/NuanceItemQuery.php
··· 70 70 $item->attachSource($source); 71 71 } 72 72 73 + $type_map = NuanceItemType::getAllItemTypes(); 74 + foreach ($items as $key => $item) { 75 + $type = idx($type_map, $item->getItemType()); 76 + if (!$type) { 77 + $this->didRejectResult($items[$key]); 78 + unset($items[$key]); 79 + continue; 80 + } 81 + $item->attachImplementation($type); 82 + } 83 + 73 84 return $items; 74 85 } 75 86
+22
src/applications/nuance/storage/NuanceItem.php
··· 7 7 PhabricatorApplicationTransactionInterface { 8 8 9 9 const STATUS_IMPORTING = 'importing'; 10 + const STATUS_ROUTING = 'routing'; 10 11 const STATUS_OPEN = 'open'; 11 12 const STATUS_ASSIGNED = 'assigned'; 12 13 const STATUS_CLOSED = 'closed'; ··· 23 24 protected $mailKey; 24 25 25 26 private $source = self::ATTACHABLE; 27 + private $implementation = self::ATTACHABLE; 26 28 27 29 public static function initializeNewItem() { 28 30 return id(new NuanceItem()) ··· 143 145 144 146 public function getDisplayName() { 145 147 return pht('An Item'); 148 + } 149 + 150 + public function scheduleUpdate() { 151 + PhabricatorWorker::scheduleTask( 152 + 'NuanceItemUpdateWorker', 153 + array( 154 + 'itemPHID' => $this->getPHID(), 155 + ), 156 + array( 157 + 'objectPHID' => $this->getPHID(), 158 + )); 159 + } 160 + 161 + public function getImplementation() { 162 + return $this->assertAttached($this->implementation); 163 + } 164 + 165 + public function attachImplementation(NuanceItemType $type) { 166 + $this->implementation = $type; 167 + return $this; 146 168 } 147 169 148 170
+49
src/applications/nuance/worker/NuanceItemUpdateWorker.php
··· 1 + <?php 2 + 3 + final class NuanceItemUpdateWorker 4 + extends NuanceWorker { 5 + 6 + protected function doWork() { 7 + $item_phid = $this->getTaskDataValue('itemPHID'); 8 + 9 + $hash = PhabricatorHash::digestForIndex($item_phid); 10 + $lock_key = "nuance.item.{$hash}"; 11 + $lock = PhabricatorGlobalLock::newLock($lock_key); 12 + 13 + $lock->lock(1); 14 + try { 15 + $item = $this->loadItem($item_phid); 16 + $this->updateItem($item); 17 + $this->routeItem($item); 18 + } catch (Exception $ex) { 19 + $lock->unlock(); 20 + throw $ex; 21 + } 22 + 23 + $lock->unlock(); 24 + } 25 + 26 + private function updateItem(NuanceItem $item) { 27 + $impl = $item->getImplementation(); 28 + if ($impl->canUpdateItems()) { 29 + $impl->updateItem($item); 30 + } 31 + } 32 + 33 + private function routeItem(NuanceItem $item) { 34 + $status = $item->getStatus(); 35 + if ($status != NuanceItem::STATUS_ROUTING) { 36 + return; 37 + } 38 + 39 + $source = $item->getSource(); 40 + 41 + // For now, always route items into the source's default queue. 42 + 43 + $item 44 + ->setQueuePHID($source->getDefaultQueuePHID()) 45 + ->setStatus(NuanceItem::STATUS_OPEN) 46 + ->save(); 47 + } 48 + 49 + }
+25
src/applications/nuance/worker/NuanceWorker.php
··· 1 + <?php 2 + 3 + abstract class NuanceWorker extends PhabricatorWorker { 4 + 5 + protected function getViewer() { 6 + return PhabricatorUser::getOmnipotentUser(); 7 + } 8 + 9 + protected function loadItem($item_phid) { 10 + $item = id(new NuanceItemQuery()) 11 + ->setViewer($this->getViewer()) 12 + ->withPHIDs(array($item_phid)) 13 + ->executeOne(); 14 + 15 + if (!$item) { 16 + throw new PhabricatorWorkerPermanentFailureException( 17 + pht( 18 + 'There is no Nuance item with PHID "%s".', 19 + $item_phid)); 20 + } 21 + 22 + return $item; 23 + } 24 + 25 + }