From 66cec450bef885cf63bb0e5539bf083b5188925f Mon Sep 17 00:00:00 2001 From: Damien Regad Date: Thu, 13 Feb 2020 15:33:19 +0100 Subject: [PATCH] GitHub: allow processing > 29 branches Implement pagination when retrieving data from GitHub REST API, to get over the limit of 30 items returned by default [[1]]. Fixes #327 [1]: https://developer.github.com/v3/#pagination --- SourceGithub/SourceGithub.php | 37 ++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/SourceGithub/SourceGithub.php b/SourceGithub/SourceGithub.php index 8a502d1fb..61c5c1bbb 100644 --- a/SourceGithub/SourceGithub.php +++ b/SourceGithub/SourceGithub.php @@ -446,19 +446,46 @@ private function api_init( $p_repo ) { /** * Retrieves data from the GitHub API for the given repository. * - * The JSON data is returned as an stdClass object, + * The JSON data is returned as an stdClass object. * * @param SourceRepo $p_repo Repository * @param string $p_path GitHub API path * @param string $p_member Optional top-level member to retrieve * - * @return stdClass|false + * @return stdClass|stdClass[]|false */ private function api_get( $p_repo, $p_path, $p_member = '' ) { $this->api_init( $p_repo ); + $t_json = array(); + + # Add pagination parameter, setting page count to maximum authorized by + # GitHub to minimize the number of requests + $t_path = $p_path + . ( parse_url( $p_path, PHP_URL_QUERY ) ? '&' : '?' ) + . 'per_page=100'; + do { + $t_response = $this->githubApi->get( $t_path ); + $t_data = json_decode( $t_response->getBody() ); + + # No need for pagination if returned data is a single object + if( !is_array( $t_data ) ) { + $t_json = $t_data; + break; + } + # Store retrieved data and proceed with next page + $t_json = array_merge( $t_json, $t_data ); + + $t_links = GuzzleHttp\Psr7\parse_header( $t_response->getHeader( 'Link' ) ); + foreach( $t_links as $t_link ) { + if( $t_link['rel'] == 'next' ) { + $t_path = trim( $t_link[0], '<>' ); + continue 2; + } + } - $t_response = $this->githubApi->get( $p_path ); - $t_json = json_decode( (string) $t_response->getBody() ); + # There is no "next" link - all pages have been processed + break; + } while( true ); if( empty( $p_member ) ) { return $t_json; @@ -585,7 +612,7 @@ public function import_full( $p_repo ) { $t_username = $p_repo->info['hub_username']; $t_reponame = $p_repo->info['hub_reponame']; - $t_json = $this->api_json_url( $p_repo, "repos/$t_username/$t_reponame/branches" ); + $t_json = $this->api_json_url( $p_repo, "repos/$t_username/$t_reponame/branches?per_page=" ); $t_branches = array(); foreach ($t_json as $t_branch) {