1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-09-20 09:18:48 +02: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:
epriestley 2016-03-22 15:36:59 -07:00
parent 4a6589524b
commit 6cd747f77c
4 changed files with 196 additions and 26 deletions

View file

@ -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);
}
}

View file

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

View file

@ -5,6 +5,8 @@ final class NuanceGitHubEventItemType
const ITEMTYPE = 'github.event';
private $externalObject;
public function getItemTypeDisplayName() {
return pht('GitHub Event');
}
@ -79,29 +81,13 @@ 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();
$xobj = $this->reloadExternalObject($item);
if ($ref->getSyncFailed()) {
$xobj = null;
} else {
$xobj = $ref->getExternalObject();
}
if ($xobj) {
$item->setItemProperty('doorkeeper.xobj.phid', $xobj->getPHID());
$is_dirty = true;
}
if ($xobj) {
$item->setItemProperty('doorkeeper.xobj.phid', $xobj->getPHID());
$is_dirty = true;
}
if ($item->getStatus() == NuanceItem::STATUS_IMPORTING) {
@ -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'),
);
}
}

View file

@ -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;
}