mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-10 08:52:39 +01:00
Kinda start bridging data in from GitHub via Nuance
Summary: Ref T10538. Very sloppy, but starting to sort of work. This sort of gets a piece of framework into a reasonable spot, next couple of diffs are going to be "extract comment text" and "show stuff in the UI" sorts of things. Test Plan: {F1186726} Reviewers: chad Reviewed By: chad Maniphest Tasks: T10538 Differential Revision: https://secure.phabricator.com/D15511
This commit is contained in:
parent
4a6589524b
commit
6cd747f77c
4 changed files with 196 additions and 26 deletions
|
@ -76,9 +76,6 @@ final class DoorkeeperBridgeGitHubIssue
|
|||
$ref->setAttribute('name', $body['title']);
|
||||
|
||||
$obj = $ref->getExternalObject();
|
||||
if ($obj->getID()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->fillObjectFromData($obj, $result);
|
||||
|
||||
|
@ -92,6 +89,19 @@ final class DoorkeeperBridgeGitHubIssue
|
|||
$body = $result->getBody();
|
||||
$uri = $body['html_url'];
|
||||
$obj->setObjectURI($uri);
|
||||
|
||||
$title = idx($body, 'title');
|
||||
$description = idx($body, 'body');
|
||||
|
||||
$created = idx($body, 'created_at');
|
||||
$created = strtotime($created);
|
||||
|
||||
$state = idx($body, 'state');
|
||||
|
||||
$obj->setProperty('task.title', $title);
|
||||
$obj->setProperty('task.description', $description);
|
||||
$obj->setProperty('task.created', $created);
|
||||
$obj->setProperty('task.state', $state);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -90,6 +90,10 @@ final class NuanceGitHubRawEvent extends Phobject {
|
|||
return null;
|
||||
}
|
||||
|
||||
public function getComment() {
|
||||
return 'TODO: Actually extract comment text.';
|
||||
}
|
||||
|
||||
public function getURI() {
|
||||
$raw = $this->raw;
|
||||
|
||||
|
|
|
@ -5,6 +5,8 @@ final class NuanceGitHubEventItemType
|
|||
|
||||
const ITEMTYPE = 'github.event';
|
||||
|
||||
private $externalObject;
|
||||
|
||||
public function getItemTypeDisplayName() {
|
||||
return pht('GitHub Event');
|
||||
}
|
||||
|
@ -79,30 +81,14 @@ final class NuanceGitHubEventItemType
|
|||
|
||||
// TODO: Link up the requestor, etc.
|
||||
|
||||
$source = $item->getSource();
|
||||
$token = $source->getSourceProperty('github.token');
|
||||
$token = new PhutilOpaqueEnvelope($token);
|
||||
$is_dirty = false;
|
||||
|
||||
$ref = $this->getDoorkeeperRef($item);
|
||||
if ($ref) {
|
||||
$ref = id(new DoorkeeperImportEngine())
|
||||
->setViewer($viewer)
|
||||
->setRefs(array($ref))
|
||||
->setThrowOnMissingLink(true)
|
||||
->setContextProperty('github.token', $token)
|
||||
->executeOne();
|
||||
|
||||
if ($ref->getSyncFailed()) {
|
||||
$xobj = null;
|
||||
} else {
|
||||
$xobj = $ref->getExternalObject();
|
||||
}
|
||||
$xobj = $this->reloadExternalObject($item);
|
||||
|
||||
if ($xobj) {
|
||||
$item->setItemProperty('doorkeeper.xobj.phid', $xobj->getPHID());
|
||||
$is_dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($item->getStatus() == NuanceItem::STATUS_IMPORTING) {
|
||||
$item->setStatus(NuanceItem::STATUS_ROUTING);
|
||||
|
@ -137,6 +123,56 @@ final class NuanceGitHubEventItemType
|
|||
->setObjectID($full_ref);
|
||||
}
|
||||
|
||||
private function reloadExternalObject(NuanceItem $item, $local = false) {
|
||||
$ref = $this->getDoorkeeperRef($item);
|
||||
if (!$ref) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$source = $item->getSource();
|
||||
$token = $source->getSourceProperty('github.token');
|
||||
$token = new PhutilOpaqueEnvelope($token);
|
||||
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$ref = id(new DoorkeeperImportEngine())
|
||||
->setViewer($viewer)
|
||||
->setRefs(array($ref))
|
||||
->setThrowOnMissingLink(true)
|
||||
->setContextProperty('github.token', $token)
|
||||
->needLocalOnly($local)
|
||||
->executeOne();
|
||||
|
||||
if ($ref->getSyncFailed()) {
|
||||
$xobj = null;
|
||||
} else {
|
||||
$xobj = $ref->getExternalObject();
|
||||
}
|
||||
|
||||
if ($xobj) {
|
||||
$this->externalObject = $xobj;
|
||||
}
|
||||
|
||||
return $xobj;
|
||||
}
|
||||
|
||||
private function getExternalObject(NuanceItem $item) {
|
||||
if ($this->externalObject === null) {
|
||||
$xobj = $this->reloadExternalObject($item, $local = true);
|
||||
if ($xobj) {
|
||||
$this->externalObject = $xobj;
|
||||
} else {
|
||||
$this->externalObject = false;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->externalObject) {
|
||||
return $this->externalObject;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function newRawEvent(NuanceItem $item) {
|
||||
$type = $item->getItemProperty('api.type');
|
||||
$raw = $item->getItemProperty('api.raw', array());
|
||||
|
@ -147,6 +183,15 @@ final class NuanceGitHubEventItemType
|
|||
public function getItemActions(NuanceItem $item) {
|
||||
$actions = array();
|
||||
|
||||
$xobj = $this->getExternalObject($item);
|
||||
if ($xobj) {
|
||||
$actions[] = $this->newItemAction($item, 'reload')
|
||||
->setName(pht('Reload from GitHub'))
|
||||
->setIcon('fa-refresh')
|
||||
->setWorkflow(true)
|
||||
->setRenderAsForm(true);
|
||||
}
|
||||
|
||||
$actions[] = $this->newItemAction($item, 'sync')
|
||||
->setName(pht('Import to Maniphest'))
|
||||
->setIcon('fa-anchor')
|
||||
|
@ -189,6 +234,7 @@ final class NuanceGitHubEventItemType
|
|||
->appendForm($form)
|
||||
->addCancelButton($item->getURI(), pht('Done'));
|
||||
case 'sync':
|
||||
case 'reload':
|
||||
$item->issueCommand($viewer->getPHID(), $action);
|
||||
return id(new AphrontRedirectResponse())->setURI($item->getURI());
|
||||
}
|
||||
|
@ -238,9 +284,117 @@ final class NuanceGitHubEventItemType
|
|||
->appendChild($property_list);
|
||||
}
|
||||
|
||||
protected function handleCommand(NuanceItem $item, $action) {
|
||||
protected function handleCommand(
|
||||
NuanceItem $item,
|
||||
NuanceItemCommand $command) {
|
||||
|
||||
$action = $command->getCommand();
|
||||
switch ($action) {
|
||||
case 'sync':
|
||||
return $this->syncItem($item, $command);
|
||||
case 'reload':
|
||||
$this->reloadExternalObject($item);
|
||||
return true;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function syncItem(
|
||||
NuanceItem $item,
|
||||
NuanceItemCommand $command) {
|
||||
|
||||
$xobj_phid = $item->getItemProperty('doorkeeper.xobj.phid');
|
||||
if (!$xobj_phid) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Unable to sync: no external object PHID.'));
|
||||
}
|
||||
|
||||
// TODO: Write some kind of marker to prevent double-synchronization.
|
||||
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$xobj = id(new DoorkeeperExternalObjectQuery())
|
||||
->setViewer($viewer)
|
||||
->withPHIDs(array($xobj_phid))
|
||||
->executeOne();
|
||||
if (!$xobj) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Unable to sync: failed to load object "%s".',
|
||||
$xobj_phid));
|
||||
}
|
||||
|
||||
$nuance_phid = id(new PhabricatorNuanceApplication())->getPHID();
|
||||
|
||||
$xactions = array();
|
||||
|
||||
$task = id(new ManiphestTaskQuery())
|
||||
->setViewer($viewer)
|
||||
->withBridgedObjectPHIDs(array($xobj_phid))
|
||||
->executeOne();
|
||||
if (!$task) {
|
||||
$task = ManiphestTask::initializeNewTask($viewer)
|
||||
->setAuthorPHID($nuance_phid)
|
||||
->setBridgedObjectPHID($xobj_phid);
|
||||
|
||||
$title = $xobj->getProperty('task.title');
|
||||
if (!strlen($title)) {
|
||||
$title = pht('Nuance Item %d Task', $item->getID());
|
||||
}
|
||||
|
||||
$description = $xobj->getProperty('task.description');
|
||||
$created = $xobj->getProperty('task.created');
|
||||
$state = $xobj->getProperty('task.state');
|
||||
|
||||
$xactions[] = id(new ManiphestTransaction())
|
||||
->setTransactionType(ManiphestTransaction::TYPE_TITLE)
|
||||
->setNewValue($title)
|
||||
->setDateCreated($created);
|
||||
|
||||
$xactions[] = id(new ManiphestTransaction())
|
||||
->setTransactionType(ManiphestTransaction::TYPE_DESCRIPTION)
|
||||
->setNewValue($description)
|
||||
->setDateCreated($created);
|
||||
|
||||
$task->setDateCreated($created);
|
||||
|
||||
// TODO: Synchronize state.
|
||||
}
|
||||
|
||||
$event = $this->newRawEvent($item);
|
||||
$comment = $event->getComment();
|
||||
if (strlen($comment)) {
|
||||
$xactions[] = id(new ManiphestTransaction())
|
||||
->setTransactionType(PhabricatorTransactions::TYPE_COMMENT)
|
||||
->attachComment(
|
||||
id(new ManiphestTransactionComment())
|
||||
->setContent($comment));
|
||||
}
|
||||
|
||||
// TODO: Preserve the item's original source.
|
||||
$source = PhabricatorContentSource::newForSource(
|
||||
PhabricatorContentSource::SOURCE_DAEMON,
|
||||
array());
|
||||
|
||||
// TOOD: This should really be the external source.
|
||||
$acting_phid = $nuance_phid;
|
||||
|
||||
$editor = id(new ManiphestTransactionEditor())
|
||||
->setActor($viewer)
|
||||
->setActingAsPHID($acting_phid)
|
||||
->setContentSource($source)
|
||||
->setContinueOnNoEffect(true)
|
||||
->setContinueOnMissingFields(true);
|
||||
|
||||
$xactions = $editor->applyTransactions($task, $xactions);
|
||||
|
||||
return array(
|
||||
'objectPHID' => $task->getPHID(),
|
||||
'xactionPHIDs' => mpull($xactions, 'getPHID'),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -131,7 +131,9 @@ abstract class NuanceItemType
|
|||
->applyTransactions($item, array($xaction));
|
||||
}
|
||||
|
||||
protected function handleCommand(NuanceItem $item, $action) {
|
||||
protected function handleCommand(
|
||||
NuanceItem $item,
|
||||
NuanceItemCommand $command) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue