From c4f19e51d843533c88d3e3ded92bc00f4f966560 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 28 Feb 2020 09:09:23 +0100 Subject: [PATCH] Rework the funding info parsing to avoid requiring graphql permissions --- src/Composer/Repository/Vcs/GitHubDriver.php | 87 +++++++++++++++----- 1 file changed, 68 insertions(+), 19 deletions(-) diff --git a/src/Composer/Repository/Vcs/GitHubDriver.php b/src/Composer/Repository/Vcs/GitHubDriver.php index 58afe605d..8194b196d 100644 --- a/src/Composer/Repository/Vcs/GitHubDriver.php +++ b/src/Composer/Repository/Vcs/GitHubDriver.php @@ -167,7 +167,6 @@ class GitHubDriver extends VcsDriver if (!isset($composer['abandoned']) && $this->isArchived) { $composer['abandoned'] = true; } - if (!isset($composer['funding']) && $funding = $this->getFundingInfo()) { $composer['funding'] = $funding; } @@ -193,28 +192,78 @@ class GitHubDriver extends VcsDriver return $this->fundingInfo = false; } - $graphql = 'query{repository(owner:"'.$this->owner.'",name:"'.$this->repository.'"){fundingLinks{platform,url}}}'; - try { - $result = $this->remoteFilesystem->getContents($this->originUrl, 'https://api.github.com/graphql', false, array( - 'http' => array( - 'method' => 'POST', - 'content' => json_encode(array('query' => $graphql)), - 'header' => array('Content-Type: application/json'), - ), - 'retry-auth-failure' => false, - )); - } catch (TransportException $e) { - return $this->fundingInfo = false; - } - $result = json_decode($result, true); + foreach (array($this->getApiUrl() . '/repos/'.$this->owner.'/'.$this->repository.'/contents/.github/FUNDING.yml', $this->getApiUrl() . '/repos/'.$this->owner.'/.github/contents/FUNDING.yml') as $file) { - if (empty($result['data']['repository']['fundingLinks'])) { + try { + $result = $this->remoteFilesystem->getContents($this->originUrl, $file, false, array( + 'retry-auth-failure' => false, + )); + $response = json_decode($result, true); + } catch (TransportException $e) { + continue; + } + if (empty($response['content']) || $response['encoding'] !== 'base64' || !($funding = base64_decode($response['content']))) { + continue; + } + } + if (empty($funding)) { return $this->fundingInfo = false; } - return $this->fundingInfo = array_map(function ($link) { - return array('type' => strtolower($link['platform']), 'url' => $link['url']); - }, $result['data']['repository']['fundingLinks']); + $result = array(); + $key = null; + foreach (preg_split('{\r?\n}', $funding) as $line) { + $line = preg_replace('{#.*}', '', $line); + $line = trim($line); + if (preg_match('{^(\w+)\s*:\s*(.+)$}', $line, $match)) { + if (preg_match('{^\[.*\]$}', $match[2])) { + foreach (array_map('trim', preg_split('{[\'"]?\s*,\s*[\'"]?}', substr($match[2], 1, -1))) as $item) { + $result[] = array('type' => $match[1], 'url' => trim($item, '"\'')); + } + } else { + $result[] = array('type' => $match[1], 'url' => $match[2]); + } + $key = null; + } elseif (preg_match('{^(\w+)\s*:$}', $line, $match)) { + $key = $match[1]; + } elseif ($key && preg_match('{^-\s*(.+)$}', $line, $match)) { + $result[] = array('type' => $key, 'url' => $match[1]); + } + } + + foreach ($result as $key => $item) { + switch ($item['type']) { + case 'tidelift': + $result[$key]['url'] = 'https://tidelift.com/funding/github/' . $item['url']; + break; + case 'github': + $result[$key]['url'] = 'https://github.com/' . basename($item['url']); + break; + case 'patreon': + $result[$key]['url'] = 'https://www.patreon.com/' . basename($item['url']); + break; + case 'otechie': + $result[$key]['url'] = 'https://otechie.com/' . basename($item['url']); + break; + case 'open_collective': + $result[$key]['url'] = 'https://opencollective.com/' . basename($item['url']); + break; + case 'liberapay': + $result[$key]['url'] = 'https://liberapay.com/' . basename($item['url']); + break; + case 'ko_fi': + $result[$key]['url'] = 'https://ko-fi.com/' . basename($item['url']); + break; + case 'issuehunt': + $result[$key]['url'] = 'https://issuehunt.io/r/' . $item['url']; + break; + case 'community_bridge': + $result[$key]['url'] = 'https://funding.communitybridge.org/projects/' . basename($item['url']); + break; + } + } + + return $this->fundingInfo = $result; } /**