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:
parent
3d44a5c253
commit
e5f867e0df
11 changed files with 259 additions and 10 deletions
|
@ -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',
|
||||||
|
|
|
@ -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);
|
||||||
|
|
22
src/applications/nuance/item/NuanceGitHubEventItemType.php
Normal file
22
src/applications/nuance/item/NuanceGitHubEventItemType.php
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
37
src/applications/nuance/item/NuanceItemType.php
Normal file
37
src/applications/nuance/item/NuanceItemType.php
Normal 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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(
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 )------------------------- */
|
||||||
|
|
||||||
|
|
49
src/applications/nuance/worker/NuanceItemUpdateWorker.php
Normal file
49
src/applications/nuance/worker/NuanceItemUpdateWorker.php
Normal 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
25
src/applications/nuance/worker/NuanceWorker.php
Normal file
25
src/applications/nuance/worker/NuanceWorker.php
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue