1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-29 18:22:41 +01:00

Add a link to the main Asana task from Differential

Summary: Ref T2852. When a Differential revision is linked to an Asana task, show the related task in Differential.

Test Plan: {F49234}

Reviewers: btrahan

Reviewed By: btrahan

CC: aran

Maniphest Tasks: T2852

Differential Revision: https://secure.phabricator.com/D6387
This commit is contained in:
epriestley 2013-07-09 16:22:33 -07:00
parent e5f200c654
commit 13e2489739
6 changed files with 118 additions and 23 deletions

View file

@ -305,6 +305,7 @@ phutil_register_library_map(array(
'DifferentialAffectedPath' => 'applications/differential/storage/DifferentialAffectedPath.php', 'DifferentialAffectedPath' => 'applications/differential/storage/DifferentialAffectedPath.php',
'DifferentialApplyPatchFieldSpecification' => 'applications/differential/field/specification/DifferentialApplyPatchFieldSpecification.php', 'DifferentialApplyPatchFieldSpecification' => 'applications/differential/field/specification/DifferentialApplyPatchFieldSpecification.php',
'DifferentialArcanistProjectFieldSpecification' => 'applications/differential/field/specification/DifferentialArcanistProjectFieldSpecification.php', 'DifferentialArcanistProjectFieldSpecification' => 'applications/differential/field/specification/DifferentialArcanistProjectFieldSpecification.php',
'DifferentialAsanaRepresentationFieldSpecification' => 'applications/differential/field/specification/DifferentialAsanaRepresentationFieldSpecification.php',
'DifferentialAuditorsFieldSpecification' => 'applications/differential/field/specification/DifferentialAuditorsFieldSpecification.php', 'DifferentialAuditorsFieldSpecification' => 'applications/differential/field/specification/DifferentialAuditorsFieldSpecification.php',
'DifferentialAuthorFieldSpecification' => 'applications/differential/field/specification/DifferentialAuthorFieldSpecification.php', 'DifferentialAuthorFieldSpecification' => 'applications/differential/field/specification/DifferentialAuthorFieldSpecification.php',
'DifferentialAuxiliaryField' => 'applications/differential/storage/DifferentialAuxiliaryField.php', 'DifferentialAuxiliaryField' => 'applications/differential/storage/DifferentialAuxiliaryField.php',
@ -2239,6 +2240,7 @@ phutil_register_library_map(array(
'DifferentialAffectedPath' => 'DifferentialDAO', 'DifferentialAffectedPath' => 'DifferentialDAO',
'DifferentialApplyPatchFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialApplyPatchFieldSpecification' => 'DifferentialFieldSpecification',
'DifferentialArcanistProjectFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialArcanistProjectFieldSpecification' => 'DifferentialFieldSpecification',
'DifferentialAsanaRepresentationFieldSpecification' => 'DifferentialFieldSpecification',
'DifferentialAuditorsFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialAuditorsFieldSpecification' => 'DifferentialFieldSpecification',
'DifferentialAuthorFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialAuthorFieldSpecification' => 'DifferentialFieldSpecification',
'DifferentialAuxiliaryField' => 'DifferentialDAO', 'DifferentialAuxiliaryField' => 'DifferentialDAO',

View file

@ -32,6 +32,7 @@ final class DifferentialDefaultFieldSelector
new DifferentialDateCreatedFieldSpecification(), new DifferentialDateCreatedFieldSpecification(),
new DifferentialAuditorsFieldSpecification(), new DifferentialAuditorsFieldSpecification(),
new DifferentialDiffViewPolicyFieldSpecification(), new DifferentialDiffViewPolicyFieldSpecification(),
new DifferentialAsanaRepresentationFieldSpecification(),
); );
return $fields; return $fields;

View file

@ -0,0 +1,76 @@
<?php
final class DifferentialAsanaRepresentationFieldSpecification
extends DifferentialFieldSpecification {
public function shouldAppearOnRevisionView() {
return (bool)PhabricatorEnv::getEnvConfig('asana.workspace-id');
}
public function renderLabelForRevisionView() {
return pht('In Asana:');
}
public function renderValueForRevisionView() {
$viewer = $this->getUser();
$src_phid = $this->getRevision()->getPHID();
$edge_type = PhabricatorEdgeConfig::TYPE_PHOB_HAS_ASANATASK;
$query = id(new PhabricatorEdgeQuery())
->withSourcePHIDs(array($src_phid))
->withEdgeTypes(array($edge_type))
->needEdgeData(true);
$edges = $query->execute();
if (!$edges) {
return null;
}
$edge = head($edges[$src_phid][$edge_type]);
if (!empty($edge['data']['gone'])) {
return phutil_tag(
'em',
array(),
pht('Asana Task Deleted'));
}
$ref = id(new DoorkeeperImportEngine())
->setViewer($viewer)
->withPHIDs(array($edge['dst']))
->needLocalOnly(true)
->executeOne();
if (!$ref) {
return null;
}
$tag_id = celerity_generate_unique_node_id();
$xobj = $ref->getExternalObject();
$href = $xobj->getObjectURI();
Javelin::initBehavior(
'doorkeeper-tag',
array(
'tags' => array(
array(
'id' => $tag_id,
'ref' => array(
$ref->getApplicationType(),
$ref->getApplicationDomain(),
$ref->getObjectType(),
$ref->getObjectID(),
),
),
),
));
return id(new PhabricatorTagView())
->setID($tag_id)
->setName($href)
->setHref($href)
->setType(PhabricatorTagView::TYPE_OBJECT)
->setExternal(true);
}
}

View file

@ -5,6 +5,7 @@ final class DoorkeeperImportEngine extends Phobject {
private $viewer; private $viewer;
private $refs = array(); private $refs = array();
private $phids = array(); private $phids = array();
private $localOnly;
public function setViewer(PhabricatorUser $viewer) { public function setViewer(PhabricatorUser $viewer) {
$this->viewer = $viewer; $this->viewer = $viewer;
@ -30,6 +31,11 @@ final class DoorkeeperImportEngine extends Phobject {
return $this; return $this;
} }
public function needLocalOnly($local_only) {
$this->localOnly = $local_only;
return $this;
}
public function execute() { public function execute() {
$refs = $this->getRefs(); $refs = $this->getRefs();
$viewer = $this->getViewer(); $viewer = $this->getViewer();
@ -64,32 +70,38 @@ final class DoorkeeperImportEngine extends Phobject {
} }
} }
$bridges = id(new PhutilSymbolLoader()) if (!$this->localOnly) {
->setAncestorClass('DoorkeeperBridge') $bridges = id(new PhutilSymbolLoader())
->loadObjects(); ->setAncestorClass('DoorkeeperBridge')
->loadObjects();
foreach ($bridges as $key => $bridge) { foreach ($bridges as $key => $bridge) {
if (!$bridge->isEnabled()) { if (!$bridge->isEnabled()) {
unset($bridges[$key]); unset($bridges[$key]);
}
$bridge->setViewer($viewer);
}
$working_set = $refs;
foreach ($bridges as $bridge) {
$bridge_refs = array();
foreach ($working_set as $key => $ref) {
if ($bridge->canPullRef($ref)) {
$bridge_refs[$key] = $ref;
unset($working_set[$key]);
} }
$bridge->setViewer($viewer);
} }
if ($bridge_refs) {
$bridge->pullRefs($bridge_refs); $working_set = $refs;
foreach ($bridges as $bridge) {
$bridge_refs = array();
foreach ($working_set as $key => $ref) {
if ($bridge->canPullRef($ref)) {
$bridge_refs[$key] = $ref;
unset($working_set[$key]);
}
}
if ($bridge_refs) {
$bridge->pullRefs($bridge_refs);
}
} }
} }
return $refs; return $refs;
} }
public function executeOne() {
return head($this->execute());
}
} }

View file

@ -238,6 +238,8 @@ final class DoorkeeperFeedWorkerAsana extends FeedPushWorker {
$extra_data = array(); $extra_data = array();
if ($main_edge) { if ($main_edge) {
$extra_data = $main_edge['data'];
$refs = id(new DoorkeeperImportEngine()) $refs = id(new DoorkeeperImportEngine())
->setViewer($possessed_user) ->setViewer($possessed_user)
->withPHIDs(array($main_edge['dst'])) ->withPHIDs(array($main_edge['dst']))
@ -289,8 +291,6 @@ final class DoorkeeperFeedWorkerAsana extends FeedPushWorker {
"Skipping main task update, cursor is ahead of the story.\n"); "Skipping main task update, cursor is ahead of the story.\n");
} }
} }
$extra_data = $main_edge['data'];
} else { } else {
$parent = $this->makeAsanaAPICall( $parent = $this->makeAsanaAPICall(
$oauth_token, $oauth_token,

View file

@ -19,8 +19,12 @@ final class PhabricatorTaskmasterDaemon extends PhabricatorDaemon {
$task = $task->executeTask(); $task = $task->executeTask();
$ex = $task->getExecutionException(); $ex = $task->getExecutionException();
if ($ex) { if ($ex) {
$this->log("Task {$id} failed!"); if ($ex instanceof PhabricatorWorkerPermanentFailureException) {
throw $ex; $this->log("Task {$id} failed permanently.");
} else {
$this->log("Task {$id} failed!");
throw $ex;
}
} else { } else {
$this->log("Task {$id} complete! Moved to archive."); $this->log("Task {$id} complete! Moved to archive.");
} }