init
This commit is contained in:
200
backend/vendor/symfony/flex/src/GithubApi.php
vendored
Normal file
200
backend/vendor/symfony/flex/src/GithubApi.php
vendored
Normal file
@@ -0,0 +1,200 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Flex;
|
||||
|
||||
use Composer\Util\HttpDownloader;
|
||||
use Composer\Util\RemoteFilesystem;
|
||||
|
||||
class GithubApi
|
||||
{
|
||||
/** @var HttpDownloader|RemoteFilesystem */
|
||||
private $downloader;
|
||||
|
||||
public function __construct($downloader)
|
||||
{
|
||||
$this->downloader = $downloader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to find data about when the recipe was installed.
|
||||
*
|
||||
* Returns an array containing:
|
||||
* commit: The git sha of the last commit of the recipe
|
||||
* date: The date of the commit
|
||||
* new_commits: An array of commit sha's in this recipe's directory+version since the commit
|
||||
* The key is the sha & the value is the date
|
||||
*/
|
||||
public function findRecipeCommitDataFromTreeRef(string $package, string $repo, string $branch, string $version, string $lockRef): ?array
|
||||
{
|
||||
$repositoryName = $this->getRepositoryName($repo);
|
||||
if (!$repositoryName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$recipePath = \sprintf('%s/%s', $package, $version);
|
||||
$commitsData = $this->requestGitHubApi(\sprintf(
|
||||
'https://api.github.com/repos/%s/commits?path=%s&sha=%s',
|
||||
$repositoryName,
|
||||
$recipePath,
|
||||
$branch
|
||||
));
|
||||
|
||||
$commitShas = [];
|
||||
foreach ($commitsData as $commitData) {
|
||||
$commitShas[$commitData['sha']] = $commitData['commit']['committer']['date'];
|
||||
// go back the commits one-by-one
|
||||
$treeUrl = $commitData['commit']['tree']['url'].'?recursive=true';
|
||||
|
||||
// fetch the full tree, then look for the tree for the package path
|
||||
$treeData = $this->requestGitHubApi($treeUrl);
|
||||
foreach ($treeData['tree'] as $treeItem) {
|
||||
if ($treeItem['path'] !== $recipePath) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($treeItem['sha'] === $lockRef) {
|
||||
// remove *this* commit from the new commits list
|
||||
array_pop($commitShas);
|
||||
|
||||
return [
|
||||
// shorten for brevity
|
||||
'commit' => substr($commitData['sha'], 0, 7),
|
||||
'date' => $commitData['commit']['committer']['date'],
|
||||
'new_commits' => $commitShas,
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getVersionsOfRecipe(string $repo, string $branch, string $recipePath): ?array
|
||||
{
|
||||
$repositoryName = $this->getRepositoryName($repo);
|
||||
if (!$repositoryName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$url = \sprintf(
|
||||
'https://api.github.com/repos/%s/contents/%s?ref=%s',
|
||||
$repositoryName,
|
||||
$recipePath,
|
||||
$branch
|
||||
);
|
||||
$contents = $this->requestGitHubApi($url);
|
||||
$versions = [];
|
||||
foreach ($contents as $fileData) {
|
||||
if ('dir' !== $fileData['type']) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$versions[] = $fileData['name'];
|
||||
}
|
||||
|
||||
return $versions;
|
||||
}
|
||||
|
||||
public function getCommitDataForPath(string $repo, string $path, string $branch): array
|
||||
{
|
||||
$repositoryName = $this->getRepositoryName($repo);
|
||||
if (!$repositoryName) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$commitsData = $this->requestGitHubApi(\sprintf(
|
||||
'https://api.github.com/repos/%s/commits?path=%s&sha=%s',
|
||||
$repositoryName,
|
||||
$path,
|
||||
$branch
|
||||
));
|
||||
|
||||
$data = [];
|
||||
foreach ($commitsData as $commitData) {
|
||||
$data[$commitData['sha']] = $commitData['commit']['committer']['date'];
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function getPullRequestForCommit(string $commit, string $repo): ?array
|
||||
{
|
||||
$data = $this->requestGitHubApi('https://api.github.com/search/issues?q='.$commit.'+is:pull-request');
|
||||
|
||||
if (0 === \count($data['items'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$repositoryName = $this->getRepositoryName($repo);
|
||||
if (!$repositoryName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$bestItem = null;
|
||||
foreach ($data['items'] as $item) {
|
||||
// make sure the PR referenced isn't from a different repository
|
||||
if (!str_contains($item['html_url'], \sprintf('%s/pull', $repositoryName))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (null === $bestItem) {
|
||||
$bestItem = $item;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// find the first PR to reference - avoids rare cases where an invalid
|
||||
// PR that references *many* commits is first
|
||||
// e.g. https://api.github.com/search/issues?q=a1a70353f64f405cfbacfc4ce860af623442d6e5
|
||||
if ($item['number'] < $bestItem['number']) {
|
||||
$bestItem = $item;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$bestItem) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return [
|
||||
'number' => $bestItem['number'],
|
||||
'url' => $bestItem['html_url'],
|
||||
'title' => $bestItem['title'],
|
||||
];
|
||||
}
|
||||
|
||||
private function requestGitHubApi(string $path)
|
||||
{
|
||||
$contents = $this->downloader->get($path)->getBody();
|
||||
|
||||
return json_decode($contents, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the "repo" stored in symfony.lock to a repository name.
|
||||
*
|
||||
* For example: "github.com/symfony/recipes" => "symfony/recipes"
|
||||
*/
|
||||
private function getRepositoryName(string $repo): ?string
|
||||
{
|
||||
// only supports public repository placement
|
||||
if (!str_starts_with($repo, 'github.com')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$parts = explode('/', $repo);
|
||||
if (3 !== \count($parts)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return implode('/', [$parts[1], $parts[2]]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user