1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2025-01-18 18:51:12 +01:00

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
This commit is contained in:
epriestley 2016-03-08 13:07:22 -08:00
parent 3d44a5c253
commit e5f867e0df
11 changed files with 259 additions and 10 deletions

View file

@ -1420,6 +1420,7 @@ phutil_register_library_map(array(
'NuanceConsoleController' => 'applications/nuance/controller/NuanceConsoleController.php', 'NuanceConsoleController' => 'applications/nuance/controller/NuanceConsoleController.php',
'NuanceController' => 'applications/nuance/controller/NuanceController.php', 'NuanceController' => 'applications/nuance/controller/NuanceController.php',
'NuanceDAO' => 'applications/nuance/storage/NuanceDAO.php', 'NuanceDAO' => 'applications/nuance/storage/NuanceDAO.php',
'NuanceGitHubEventItemType' => 'applications/nuance/item/NuanceGitHubEventItemType.php',
'NuanceGitHubRepositoryImportCursor' => 'applications/nuance/cursor/NuanceGitHubRepositoryImportCursor.php', 'NuanceGitHubRepositoryImportCursor' => 'applications/nuance/cursor/NuanceGitHubRepositoryImportCursor.php',
'NuanceGitHubRepositorySourceDefinition' => 'applications/nuance/source/NuanceGitHubRepositorySourceDefinition.php', 'NuanceGitHubRepositorySourceDefinition' => 'applications/nuance/source/NuanceGitHubRepositorySourceDefinition.php',
'NuanceImportCursor' => 'applications/nuance/cursor/NuanceImportCursor.php', 'NuanceImportCursor' => 'applications/nuance/cursor/NuanceImportCursor.php',
@ -1437,8 +1438,11 @@ phutil_register_library_map(array(
'NuanceItemTransaction' => 'applications/nuance/storage/NuanceItemTransaction.php', 'NuanceItemTransaction' => 'applications/nuance/storage/NuanceItemTransaction.php',
'NuanceItemTransactionComment' => 'applications/nuance/storage/NuanceItemTransactionComment.php', 'NuanceItemTransactionComment' => 'applications/nuance/storage/NuanceItemTransactionComment.php',
'NuanceItemTransactionQuery' => 'applications/nuance/query/NuanceItemTransactionQuery.php', 'NuanceItemTransactionQuery' => 'applications/nuance/query/NuanceItemTransactionQuery.php',
'NuanceItemType' => 'applications/nuance/item/NuanceItemType.php',
'NuanceItemUpdateWorker' => 'applications/nuance/worker/NuanceItemUpdateWorker.php',
'NuanceItemViewController' => 'applications/nuance/controller/NuanceItemViewController.php', 'NuanceItemViewController' => 'applications/nuance/controller/NuanceItemViewController.php',
'NuanceManagementImportWorkflow' => 'applications/nuance/management/NuanceManagementImportWorkflow.php', 'NuanceManagementImportWorkflow' => 'applications/nuance/management/NuanceManagementImportWorkflow.php',
'NuanceManagementUpdateWorkflow' => 'applications/nuance/management/NuanceManagementUpdateWorkflow.php',
'NuanceManagementWorkflow' => 'applications/nuance/management/NuanceManagementWorkflow.php', 'NuanceManagementWorkflow' => 'applications/nuance/management/NuanceManagementWorkflow.php',
'NuancePhabricatorFormSourceDefinition' => 'applications/nuance/source/NuancePhabricatorFormSourceDefinition.php', 'NuancePhabricatorFormSourceDefinition' => 'applications/nuance/source/NuancePhabricatorFormSourceDefinition.php',
'NuanceQuery' => 'applications/nuance/query/NuanceQuery.php', 'NuanceQuery' => 'applications/nuance/query/NuanceQuery.php',
@ -1488,6 +1492,7 @@ phutil_register_library_map(array(
'NuanceSourceTransactionQuery' => 'applications/nuance/query/NuanceSourceTransactionQuery.php', 'NuanceSourceTransactionQuery' => 'applications/nuance/query/NuanceSourceTransactionQuery.php',
'NuanceSourceViewController' => 'applications/nuance/controller/NuanceSourceViewController.php', 'NuanceSourceViewController' => 'applications/nuance/controller/NuanceSourceViewController.php',
'NuanceTransaction' => 'applications/nuance/storage/NuanceTransaction.php', 'NuanceTransaction' => 'applications/nuance/storage/NuanceTransaction.php',
'NuanceWorker' => 'applications/nuance/worker/NuanceWorker.php',
'OwnersConduitAPIMethod' => 'applications/owners/conduit/OwnersConduitAPIMethod.php', 'OwnersConduitAPIMethod' => 'applications/owners/conduit/OwnersConduitAPIMethod.php',
'OwnersEditConduitAPIMethod' => 'applications/owners/conduit/OwnersEditConduitAPIMethod.php', 'OwnersEditConduitAPIMethod' => 'applications/owners/conduit/OwnersEditConduitAPIMethod.php',
'OwnersPackageReplyHandler' => 'applications/owners/mail/OwnersPackageReplyHandler.php', 'OwnersPackageReplyHandler' => 'applications/owners/mail/OwnersPackageReplyHandler.php',
@ -5671,6 +5676,7 @@ phutil_register_library_map(array(
'NuanceConsoleController' => 'NuanceController', 'NuanceConsoleController' => 'NuanceController',
'NuanceController' => 'PhabricatorController', 'NuanceController' => 'PhabricatorController',
'NuanceDAO' => 'PhabricatorLiskDAO', 'NuanceDAO' => 'PhabricatorLiskDAO',
'NuanceGitHubEventItemType' => 'NuanceItemType',
'NuanceGitHubRepositoryImportCursor' => 'NuanceImportCursor', 'NuanceGitHubRepositoryImportCursor' => 'NuanceImportCursor',
'NuanceGitHubRepositorySourceDefinition' => 'NuanceSourceDefinition', 'NuanceGitHubRepositorySourceDefinition' => 'NuanceSourceDefinition',
'NuanceImportCursor' => 'Phobject', 'NuanceImportCursor' => 'Phobject',
@ -5695,8 +5701,11 @@ phutil_register_library_map(array(
'NuanceItemTransaction' => 'NuanceTransaction', 'NuanceItemTransaction' => 'NuanceTransaction',
'NuanceItemTransactionComment' => 'PhabricatorApplicationTransactionComment', 'NuanceItemTransactionComment' => 'PhabricatorApplicationTransactionComment',
'NuanceItemTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'NuanceItemTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
'NuanceItemType' => 'Phobject',
'NuanceItemUpdateWorker' => 'NuanceWorker',
'NuanceItemViewController' => 'NuanceController', 'NuanceItemViewController' => 'NuanceController',
'NuanceManagementImportWorkflow' => 'NuanceManagementWorkflow', 'NuanceManagementImportWorkflow' => 'NuanceManagementWorkflow',
'NuanceManagementUpdateWorkflow' => 'NuanceManagementWorkflow',
'NuanceManagementWorkflow' => 'PhabricatorManagementWorkflow', 'NuanceManagementWorkflow' => 'PhabricatorManagementWorkflow',
'NuancePhabricatorFormSourceDefinition' => 'NuanceSourceDefinition', 'NuancePhabricatorFormSourceDefinition' => 'NuanceSourceDefinition',
'NuanceQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'NuanceQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
@ -5759,6 +5768,7 @@ phutil_register_library_map(array(
'NuanceSourceTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'NuanceSourceTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
'NuanceSourceViewController' => 'NuanceSourceController', 'NuanceSourceViewController' => 'NuanceSourceController',
'NuanceTransaction' => 'PhabricatorApplicationTransaction', 'NuanceTransaction' => 'PhabricatorApplicationTransaction',
'NuanceWorker' => 'PhabricatorWorker',
'OwnersConduitAPIMethod' => 'ConduitAPIMethod', 'OwnersConduitAPIMethod' => 'ConduitAPIMethod',
'OwnersEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod', 'OwnersEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod',
'OwnersPackageReplyHandler' => 'PhabricatorMailReplyHandler', 'OwnersPackageReplyHandler' => 'PhabricatorMailReplyHandler',

View file

@ -166,14 +166,7 @@ final class NuanceGitHubRepositoryImportCursor
$source->saveTransaction(); $source->saveTransaction();
foreach ($new_items as $new_item) { foreach ($new_items as $new_item) {
PhabricatorWorker::scheduleTask( $new_item->scheduleUpdate();
'NuanceImportWorker',
array(
'itemPHID' => $new_item->getPHID(),
),
array(
'objectPHID' => $new_item->getPHID(),
));
} }
return false; return false;
@ -256,7 +249,7 @@ final class NuanceGitHubRepositoryImportCursor
return NuanceItem::initializeNewItem() return NuanceItem::initializeNewItem()
->setStatus(NuanceItem::STATUS_IMPORTING) ->setStatus(NuanceItem::STATUS_IMPORTING)
->setSourcePHID($source->getPHID()) ->setSourcePHID($source->getPHID())
->setItemType('github.event') ->setItemType(NuanceGitHubEventItemType::ITEMTYPE)
->setItemKey($item_key) ->setItemKey($item_key)
->setItemContainerKey($container_key) ->setItemContainerKey($container_key)
->setItemProperty('api.raw', $record); ->setItemProperty('api.raw', $record);

View file

@ -0,0 +1,22 @@
<?php
final class NuanceGitHubEventItemType
extends NuanceItemType {
const ITEMTYPE = 'github.event';
public function canUpdateItems() {
return true;
}
protected function updateItemFromSource(NuanceItem $item) {
// TODO: Link up the requestor, etc.
if ($item->getStatus() == NuanceItem::STATUS_IMPORTING) {
$item
->setStatus(NuanceItem::STATUS_ROUTING)
->save();
}
}
}

View file

@ -0,0 +1,37 @@
<?php
abstract class NuanceItemType
extends Phobject {
public function canUpdateItems() {
return false;
}
final public function updateItem(NuanceItem $item) {
if (!$this->canUpdateItems()) {
throw new Exception(
pht(
'This item type ("%s", of class "%s") can not update items.',
$this->getItemTypeConstant(),
get_class($this)));
}
$this->updateItemFromSource($item);
}
protected function updateItemFromSource(NuanceItem $item) {
throw new PhutilMethodNotImplementedException();
}
final public function getItemTypeConstant() {
return $this->getPhobjectClassConstant('ITEMTYPE', 64);
}
final public static function getAllItemTypes() {
return id(new PhutilClassMapQuery())
->setAncestorClass(__CLASS__)
->setUniqueMethod('getItemTypeConstant')
->execute();
}
}

View file

@ -6,7 +6,7 @@ final class NuanceManagementImportWorkflow
protected function didConstruct() { protected function didConstruct() {
$this $this
->setName('import') ->setName('import')
->setExamples('**import** [__options__]') ->setExamples('**import** --source __source__ [__options__]')
->setSynopsis(pht('Import data from a source.')) ->setSynopsis(pht('Import data from a source.'))
->setArguments( ->setArguments(
array( array(

View file

@ -0,0 +1,30 @@
<?php
final class NuanceManagementUpdateWorkflow
extends NuanceManagementWorkflow {
protected function didConstruct() {
$this
->setName('update')
->setExamples('**update** --item __item__ [__options__]')
->setSynopsis(pht('Update or route an item.'))
->setArguments(
array(
array(
'name' => 'item',
'param' => 'item',
'help' => pht('Choose which item to route.'),
),
));
}
public function execute(PhutilArgumentParser $args) {
$item = $this->loadItem($args, 'item');
PhabricatorWorker::setRunAllTasksInProcess(true);
$item->scheduleUpdate();
return 0;
}
}

View file

@ -64,4 +64,54 @@ abstract class NuanceManagementWorkflow
return head($sources); return head($sources);
} }
protected function loadITem(PhutilArgumentParser $argv, $key) {
$item = $argv->getArg($key);
if (!strlen($item)) {
throw new PhutilArgumentUsageException(
pht(
'Specify a item with %s.',
'--'.$key));
}
$query = id(new NuanceItemQuery())
->setViewer($this->getViewer())
->setRaisePolicyExceptions(true);
$type_unknown = PhabricatorPHIDConstants::PHID_TYPE_UNKNOWN;
if (ctype_digit($item)) {
$kind = 'id';
$query->withIDs(array($item));
} else if (phid_get_type($item) !== $type_unknown) {
$kind = 'phid';
$query->withPHIDs($item);
} else {
throw new PhutilArgumentUsageException(
pht(
'Specify the ID or PHID of an item to update. Parameter "%s" '.
'is not an ID or PHID.',
$item));
}
$items = $query->execute();
if (!$items) {
switch ($kind) {
case 'id':
$message = pht(
'No item exists with ID "%s".',
$item);
break;
case 'phid':
$message = pht(
'No item exists with PHID "%s".',
$item);
break;
}
throw new PhutilArgumentUsageException($message);
}
return head($items);
}
} }

View file

@ -70,6 +70,17 @@ final class NuanceItemQuery
$item->attachSource($source); $item->attachSource($source);
} }
$type_map = NuanceItemType::getAllItemTypes();
foreach ($items as $key => $item) {
$type = idx($type_map, $item->getItemType());
if (!$type) {
$this->didRejectResult($items[$key]);
unset($items[$key]);
continue;
}
$item->attachImplementation($type);
}
return $items; return $items;
} }

View file

@ -7,6 +7,7 @@ final class NuanceItem
PhabricatorApplicationTransactionInterface { PhabricatorApplicationTransactionInterface {
const STATUS_IMPORTING = 'importing'; const STATUS_IMPORTING = 'importing';
const STATUS_ROUTING = 'routing';
const STATUS_OPEN = 'open'; const STATUS_OPEN = 'open';
const STATUS_ASSIGNED = 'assigned'; const STATUS_ASSIGNED = 'assigned';
const STATUS_CLOSED = 'closed'; const STATUS_CLOSED = 'closed';
@ -23,6 +24,7 @@ final class NuanceItem
protected $mailKey; protected $mailKey;
private $source = self::ATTACHABLE; private $source = self::ATTACHABLE;
private $implementation = self::ATTACHABLE;
public static function initializeNewItem() { public static function initializeNewItem() {
return id(new NuanceItem()) return id(new NuanceItem())
@ -145,6 +147,26 @@ final class NuanceItem
return pht('An Item'); return pht('An Item');
} }
public function scheduleUpdate() {
PhabricatorWorker::scheduleTask(
'NuanceItemUpdateWorker',
array(
'itemPHID' => $this->getPHID(),
),
array(
'objectPHID' => $this->getPHID(),
));
}
public function getImplementation() {
return $this->assertAttached($this->implementation);
}
public function attachImplementation(NuanceItemType $type) {
$this->implementation = $type;
return $this;
}
/* -( PhabricatorApplicationTransactionInterface )------------------------- */ /* -( PhabricatorApplicationTransactionInterface )------------------------- */

View file

@ -0,0 +1,49 @@
<?php
final class NuanceItemUpdateWorker
extends NuanceWorker {
protected function doWork() {
$item_phid = $this->getTaskDataValue('itemPHID');
$hash = PhabricatorHash::digestForIndex($item_phid);
$lock_key = "nuance.item.{$hash}";
$lock = PhabricatorGlobalLock::newLock($lock_key);
$lock->lock(1);
try {
$item = $this->loadItem($item_phid);
$this->updateItem($item);
$this->routeItem($item);
} catch (Exception $ex) {
$lock->unlock();
throw $ex;
}
$lock->unlock();
}
private function updateItem(NuanceItem $item) {
$impl = $item->getImplementation();
if ($impl->canUpdateItems()) {
$impl->updateItem($item);
}
}
private function routeItem(NuanceItem $item) {
$status = $item->getStatus();
if ($status != NuanceItem::STATUS_ROUTING) {
return;
}
$source = $item->getSource();
// For now, always route items into the source's default queue.
$item
->setQueuePHID($source->getDefaultQueuePHID())
->setStatus(NuanceItem::STATUS_OPEN)
->save();
}
}

View file

@ -0,0 +1,25 @@
<?php
abstract class NuanceWorker extends PhabricatorWorker {
protected function getViewer() {
return PhabricatorUser::getOmnipotentUser();
}
protected function loadItem($item_phid) {
$item = id(new NuanceItemQuery())
->setViewer($this->getViewer())
->withPHIDs(array($item_phid))
->executeOne();
if (!$item) {
throw new PhabricatorWorkerPermanentFailureException(
pht(
'There is no Nuance item with PHID "%s".',
$item_phid));
}
return $item;
}
}