Page MenuHomePhabricator

D8775.id20822.diff
No OneTemporary

D8775.id20822.diff

diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -612,6 +612,7 @@
'DivinerWorkflow' => 'applications/diviner/workflow/DivinerWorkflow.php',
'DoorkeeperBridge' => 'applications/doorkeeper/bridge/DoorkeeperBridge.php',
'DoorkeeperBridgeAsana' => 'applications/doorkeeper/bridge/DoorkeeperBridgeAsana.php',
+ 'DoorkeeperBridgeGitHub' => 'applications/doorkeeper/bridge/DoorkeeperBridgeGitHub.php',
'DoorkeeperBridgeJIRA' => 'applications/doorkeeper/bridge/DoorkeeperBridgeJIRA.php',
'DoorkeeperDAO' => 'applications/doorkeeper/storage/DoorkeeperDAO.php',
'DoorkeeperExternalObject' => 'applications/doorkeeper/storage/DoorkeeperExternalObject.php',
@@ -620,6 +621,7 @@
'DoorkeeperFeedWorker' => 'applications/doorkeeper/worker/DoorkeeperFeedWorker.php',
'DoorkeeperFeedWorkerAsana' => 'applications/doorkeeper/worker/DoorkeeperFeedWorkerAsana.php',
'DoorkeeperFeedWorkerJIRA' => 'applications/doorkeeper/worker/DoorkeeperFeedWorkerJIRA.php',
+ 'DoorkeeperGitHubHookController' => 'applications/doorkeeper/controller/DoorkeeperGitHubHookController.php',
'DoorkeeperImportEngine' => 'applications/doorkeeper/engine/DoorkeeperImportEngine.php',
'DoorkeeperMissingLinkException' => 'applications/doorkeeper/exception/DoorkeeperMissingLinkException.php',
'DoorkeeperObjectRef' => 'applications/doorkeeper/engine/DoorkeeperObjectRef.php',
@@ -3203,6 +3205,7 @@
'DivinerWorkflow' => 'PhabricatorManagementWorkflow',
'DoorkeeperBridge' => 'Phobject',
'DoorkeeperBridgeAsana' => 'DoorkeeperBridge',
+ 'DoorkeeperBridgeGitHub' => 'DoorkeeperBridge',
'DoorkeeperBridgeJIRA' => 'DoorkeeperBridge',
'DoorkeeperDAO' => 'PhabricatorLiskDAO',
'DoorkeeperExternalObject' =>
@@ -3214,6 +3217,7 @@
'DoorkeeperFeedWorker' => 'FeedPushWorker',
'DoorkeeperFeedWorkerAsana' => 'DoorkeeperFeedWorker',
'DoorkeeperFeedWorkerJIRA' => 'DoorkeeperFeedWorker',
+ 'DoorkeeperGitHubHookController' => 'PhabricatorController',
'DoorkeeperImportEngine' => 'Phobject',
'DoorkeeperMissingLinkException' => 'Exception',
'DoorkeeperObjectRef' => 'Phobject',
diff --git a/src/applications/doorkeeper/application/PhabricatorApplicationDoorkeeper.php b/src/applications/doorkeeper/application/PhabricatorApplicationDoorkeeper.php
--- a/src/applications/doorkeeper/application/PhabricatorApplicationDoorkeeper.php
+++ b/src/applications/doorkeeper/application/PhabricatorApplicationDoorkeeper.php
@@ -25,6 +25,7 @@
return array(
'/doorkeeper/' => array(
'tags/' => 'DoorkeeperTagsController',
+ 'github-hook/' => 'DoorkeeperGitHubHookController',
),
);
}
diff --git a/src/applications/doorkeeper/bridge/DoorkeeperBridgeGitHub.php b/src/applications/doorkeeper/bridge/DoorkeeperBridgeGitHub.php
new file mode 100644
--- /dev/null
+++ b/src/applications/doorkeeper/bridge/DoorkeeperBridgeGitHub.php
@@ -0,0 +1,119 @@
+<?php
+
+final class DoorkeeperBridgeGitHub extends DoorkeeperBridge {
+
+ const APPTYPE_GITHUB = 'github';
+ const OBJTYPE_PULL_REQUEST = 'github:pull-request';
+
+ public function canPullRef(DoorkeeperObjectRef $ref) {
+ if ($ref->getApplicationType() != self::APPTYPE_GITHUB) {
+ return false;
+ }
+
+ $types = array(
+ self::OBJTYPE_PULL_REQUEST => true,
+ );
+
+ return isset($types[$ref->getObjectType()]);
+ }
+
+ public function pullRefs(array $refs) {
+
+ $id_map = mpull($refs, 'getObjectID', 'getObjectKey');
+
+ // Object IDs for pull requests are formatted as:
+ //
+ // user:repo:pullid
+ //
+ // since we need both the user and repo name to retrieve
+ // data about a pull request.
+ $data_map = array();
+ foreach ($id_map as $key => $id) {
+ $split = explode(':', $id);
+ $user = str_replace($split[0], '/', '');
+ $repo = str_replace($split[1], '/', '');
+ $pull_id = (int)$split[2];
+ $data_map[$key] = array(
+ 'id' => $id,
+ 'user' => $user,
+ 'repo' => $repo,
+ 'pullID' => $pull_id,
+ 'getURI' =>
+ 'https://api.github.com/repos/'.$user.'/'.$repo.'/pulls/'.$pull_id);
+ }
+
+ // Query the GitHub public API, retrieving all of the information.
+ $futures = array();
+ foreach ($data_map as $key => $data) {
+ $futures[$key] = id(new HTTPSFuture($data['getURI']))
+ ->setMethod('GET')
+ ->setTimeout(30);
+ }
+
+ $results = array();
+ $failed = array();
+ foreach (Futures($futures) as $key => $future) {
+ try {
+ $results[$key] = $future->resolveJSON();
+ } catch (Exception $ex) {
+ if (($ex instanceof HTTPFutureResponseStatus) &&
+ ($ex->getStatusCode() == 404)) {
+ // This indicates that the object has been deleted (or never existed,
+ // or isn't visible to the current user) but it's a successful sync of
+ // an object which isn't visible.
+ } else {
+ // This is something else, so consider it a synchronization failure.
+ phlog($ex);
+ $failed[$key] = $ex;
+ }
+ }
+ }
+
+ // Set all the associated data.
+ foreach ($refs as $ref) {
+ $did_fail = idx($failed, $ref->getObjectKey());
+ if ($did_fail) {
+ // Set at least the key to identify, normally the
+ // name is the name of the PR.
+ $ref->setAttribute('name', 'GitHub PR '.$ref->getObjectID());
+ $ref->setSyncFailed(true);
+ continue;
+ }
+
+ $result = idx($results, $ref->getObjectKey());
+ if (!$result) {
+ continue;
+ }
+
+ $ref->setIsVisible(true);
+ $ref->setAttribute('name', $result['title']);
+ $ref->setAttribute('url', $result['url']);
+ $ref->setAttribute('diffURL', $result['diff_url']);
+ $ref->setAttribute('state', $result['state']);
+ $ref->setAttribute('userLogin', $result['user']['login']);
+ $ref->setAttribute('body', $result['body']);
+ $ref->setAttribute('headGitURL', $result['head']['repo']['git_url']);
+ $ref->setAttribute('headGitSHA', $result['head']['sha']);
+ $ref->setAttribute('headLabel', $result['head']['label']);
+ $ref->setAttribute('baseGitURL', $result['base']['repo']['git_url']);
+ $ref->setAttribute('baseGitSHA', $result['base']['sha']);
+ $ref->setAttribute('baseLabel', $result['base']['label']);
+ $ref->setAttribute('merged', $result['merged']);
+
+ // TODO: Does the data belong on the ref attributes or the
+ // object properties??
+
+ $obj = $ref->getExternalObject();
+ if ($obj->getID()) {
+ continue;
+ }
+
+ $obj->setObjectURI($result['url']);
+
+ $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
+ $obj->save();
+ unset($unguarded);
+ }
+ }
+
+}
diff --git a/src/applications/doorkeeper/controller/DoorkeeperGitHubHookController.php b/src/applications/doorkeeper/controller/DoorkeeperGitHubHookController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/doorkeeper/controller/DoorkeeperGitHubHookController.php
@@ -0,0 +1,37 @@
+<?php
+
+final class DoorkeeperGitHubHookController extends PhabricatorController {
+
+ // Only allow anonymous access when the page
+ // is being POST'd to (since this is what
+ // GitHub will post to).
+
+ public function shouldRequireLogin() {
+ return $_SERVER['REQUEST_METHOD'] != 'POST';
+ }
+
+ public function shouldRequireEnabledUser() {
+ return $_SERVER['REQUEST_METHOD'] != 'POST';
+ }
+
+ public function shouldAllowPublic() {
+ return $_SERVER['REQUEST_METHOD'] == 'POST';
+ }
+
+ public function processRequest() {
+ $request = $this->getRequest();
+
+ $is_get = $_SERVER['REQUEST_METHOD'] == 'GET';
+
+ if ($is_get) {
+ return id(new AphrontPlainTextResponse())
+ ->setContent('GET test');
+ } else {
+ $payload = json_decode($_POST['payload']);
+
+ return id(new AphrontPlainTextResponse())
+ ->setContent($_POST['payload']);
+ }
+ }
+
+}

File Metadata

Mime Type
text/plain
Expires
Thu, Apr 10, 3:29 PM (6 d, 6 h ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7704678
Default Alt Text
D8775.id20822.diff (7 KB)

Event Timeline