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']);
|
$ref->setAttribute('name', $body['title']);
|
||||||
|
|
||||||
$obj = $ref->getExternalObject();
|
$obj = $ref->getExternalObject();
|
||||||
if ($obj->getID()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->fillObjectFromData($obj, $result);
|
$this->fillObjectFromData($obj, $result);
|
||||||
|
|
||||||
|
@ -92,6 +89,19 @@ final class DoorkeeperBridgeGitHubIssue
|
||||||
$body = $result->getBody();
|
$body = $result->getBody();
|
||||||
$uri = $body['html_url'];
|
$uri = $body['html_url'];
|
||||||
$obj->setObjectURI($uri);
|
$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;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getComment() {
|
||||||
|
return 'TODO: Actually extract comment text.';
|
||||||
|
}
|
||||||
|
|
||||||
public function getURI() {
|
public function getURI() {
|
||||||
$raw = $this->raw;
|
$raw = $this->raw;
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,8 @@ final class NuanceGitHubEventItemType
|
||||||
|
|
||||||
const ITEMTYPE = 'github.event';
|
const ITEMTYPE = 'github.event';
|
||||||
|
|
||||||
|
private $externalObject;
|
||||||
|
|
||||||
public function getItemTypeDisplayName() {
|
public function getItemTypeDisplayName() {
|
||||||
return pht('GitHub Event');
|
return pht('GitHub Event');
|
||||||
}
|
}
|
||||||
|
@ -79,30 +81,14 @@ final class NuanceGitHubEventItemType
|
||||||
|
|
||||||
// TODO: Link up the requestor, etc.
|
// TODO: Link up the requestor, etc.
|
||||||
|
|
||||||
$source = $item->getSource();
|
$is_dirty = false;
|
||||||
$token = $source->getSourceProperty('github.token');
|
|
||||||
$token = new PhutilOpaqueEnvelope($token);
|
|
||||||
|
|
||||||
$ref = $this->getDoorkeeperRef($item);
|
$xobj = $this->reloadExternalObject($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();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($xobj) {
|
if ($xobj) {
|
||||||
$item->setItemProperty('doorkeeper.xobj.phid', $xobj->getPHID());
|
$item->setItemProperty('doorkeeper.xobj.phid', $xobj->getPHID());
|
||||||
$is_dirty = true;
|
$is_dirty = true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if ($item->getStatus() == NuanceItem::STATUS_IMPORTING) {
|
if ($item->getStatus() == NuanceItem::STATUS_IMPORTING) {
|
||||||
$item->setStatus(NuanceItem::STATUS_ROUTING);
|
$item->setStatus(NuanceItem::STATUS_ROUTING);
|
||||||
|
@ -137,6 +123,56 @@ final class NuanceGitHubEventItemType
|
||||||
->setObjectID($full_ref);
|
->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) {
|
private function newRawEvent(NuanceItem $item) {
|
||||||
$type = $item->getItemProperty('api.type');
|
$type = $item->getItemProperty('api.type');
|
||||||
$raw = $item->getItemProperty('api.raw', array());
|
$raw = $item->getItemProperty('api.raw', array());
|
||||||
|
@ -147,6 +183,15 @@ final class NuanceGitHubEventItemType
|
||||||
public function getItemActions(NuanceItem $item) {
|
public function getItemActions(NuanceItem $item) {
|
||||||
$actions = array();
|
$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')
|
$actions[] = $this->newItemAction($item, 'sync')
|
||||||
->setName(pht('Import to Maniphest'))
|
->setName(pht('Import to Maniphest'))
|
||||||
->setIcon('fa-anchor')
|
->setIcon('fa-anchor')
|
||||||
|
@ -189,6 +234,7 @@ final class NuanceGitHubEventItemType
|
||||||
->appendForm($form)
|
->appendForm($form)
|
||||||
->addCancelButton($item->getURI(), pht('Done'));
|
->addCancelButton($item->getURI(), pht('Done'));
|
||||||
case 'sync':
|
case 'sync':
|
||||||
|
case 'reload':
|
||||||
$item->issueCommand($viewer->getPHID(), $action);
|
$item->issueCommand($viewer->getPHID(), $action);
|
||||||
return id(new AphrontRedirectResponse())->setURI($item->getURI());
|
return id(new AphrontRedirectResponse())->setURI($item->getURI());
|
||||||
}
|
}
|
||||||
|
@ -238,9 +284,117 @@ final class NuanceGitHubEventItemType
|
||||||
->appendChild($property_list);
|
->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;
|
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));
|
->applyTransactions($item, array($xaction));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function handleCommand(NuanceItem $item, $action) {
|
protected function handleCommand(
|
||||||
|
NuanceItem $item,
|
||||||
|
NuanceItemCommand $command) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue