Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15483962
D8775.id20822.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
7 KB
Referenced Files
None
Subscribers
None
D8775.id20822.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D8775: [DRAFT] Integrate GitHub pull requests as Differential reviews
Attached
Detach File
Event Timeline
Log In to Comment