From 0efcc2d77da52a044b90ae6bcc3b54b3f579dcda Mon Sep 17 00:00:00 2001 From: MBorne Date: Sat, 24 Nov 2018 11:07:25 +0100 Subject: [PATCH] experimental github support (refs #24) --- .gitignore | 2 +- README.md | 17 ++++ .../Command/GitlabToConfigCommand.php | 3 +- src/MBO/SatisGitlab/Git/ClientFactory.php | 65 +++++++++++++++ src/MBO/SatisGitlab/Git/GithubClient.php | 83 +++++++++++++++++++ src/MBO/SatisGitlab/Git/GithubProject.php | 53 ++++++++++++ src/MBO/SatisGitlab/Git/GitlabClient.php | 31 +------ tests/Git/GithubClientTest.php | 65 +++++++++++++++ tests/Git/GitlabClientTest.php | 5 +- 9 files changed, 290 insertions(+), 34 deletions(-) create mode 100644 src/MBO/SatisGitlab/Git/ClientFactory.php create mode 100644 src/MBO/SatisGitlab/Git/GithubClient.php create mode 100644 src/MBO/SatisGitlab/Git/GithubProject.php create mode 100644 tests/Git/GithubClientTest.php diff --git a/.gitignore b/.gitignore index a1edbef..9b7ff2d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,7 @@ /nbproject/ /vendor/ /satis.json -/web +/web/ /output/ /composer.phar diff --git a/README.md b/README.md index 05f8102..d79ed60 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,23 @@ Some command line options provide a basic customization options. You may also us [default-template.json](src/MBO/SatisGitlab/Resources/default-template.json) +## Experimental support for github + +Experimental support for github allows to perform : + +```bash +bin/satis-gitlab gitlab-to-config https://api.github.com/orgs/symfony/repos $GITHUB_TOKEN +bin/satis-gitlab gitlab-to-config https://api.github.com/users/mborne/repos $GITHUB_TOKEN +bin/satis-gitlab build --skip-errors satis.json web +``` + +Note that : + +* GITHUB_TOKEN is required to avoid rate request limitation +* Config may change (maybe better to support `--orgs=symfony,FriendsOfSymfony --users=mborne`) +* `src/MBO/SatisGitlab/Git` will probably be moved to a dedicated project `hosted-git-client` (avoid using this classes) + + ## Requirements * GITLAB API v4 diff --git a/src/MBO/SatisGitlab/Command/GitlabToConfigCommand.php b/src/MBO/SatisGitlab/Command/GitlabToConfigCommand.php index 03c3c01..a2068d4 100644 --- a/src/MBO/SatisGitlab/Command/GitlabToConfigCommand.php +++ b/src/MBO/SatisGitlab/Command/GitlabToConfigCommand.php @@ -24,6 +24,7 @@ use MBO\SatisGitlab\Filter\IgnoreRegexpFilter; use MBO\SatisGitlab\Filter\IncludeIfHasFileFilter; use MBO\SatisGitlab\Filter\ProjectTypeFilter; +use MBO\SatisGitlab\Git\ClientFactory; @@ -97,7 +98,7 @@ protected function execute(InputInterface $input, OutputInterface $output) { * see https://github.com/mborne/satis-gitlab/issues/2 */ $clientOptions->setUnsafeSsl(true); - $client = GitlabClient::createClient( + $client = ClientFactory::createClient( $clientOptions, $logger ); diff --git a/src/MBO/SatisGitlab/Git/ClientFactory.php b/src/MBO/SatisGitlab/Git/ClientFactory.php new file mode 100644 index 0000000..99c1264 --- /dev/null +++ b/src/MBO/SatisGitlab/Git/ClientFactory.php @@ -0,0 +1,65 @@ +getUrl()); + + /* common http options */ + $guzzleOptions = array( + 'base_uri' => $options->getUrl(), + 'timeout' => 10.0, + 'headers' => [] + ); + if ( $options->isUnsafeSsl() ){ + $guzzleOptions['verify'] = false; + } + if ( $options->hasToken() ){ + if ( GitlabClient::class === $clientClass ){ + $guzzleOptions['headers']['Private-Token'] = $options->getToken(); + }else if ( GithubClient::class === $clientClass ){ + $guzzleOptions['headers']['Authorization'] = 'token '.$options->getToken(); + } + } + + $httpClient = new GuzzleHttpClient($guzzleOptions); + + /* create gitlab client */ + return new $clientClass($httpClient,$logger); + } + + /** + * Get client class according to URL content + * + * @param string $url + * @return string + */ + public static function detectClientClass($url){ + $hostname = parse_url($url, PHP_URL_HOST); + if ( 'api.github.com' === $hostname ){ + return GithubClient::class; + }else{ + return GitlabClient::class; + } + } + +} + diff --git a/src/MBO/SatisGitlab/Git/GithubClient.php b/src/MBO/SatisGitlab/Git/GithubClient.php new file mode 100644 index 0000000..764a35d --- /dev/null +++ b/src/MBO/SatisGitlab/Git/GithubClient.php @@ -0,0 +1,83 @@ +httpClient = $httpClient ; + $this->logger = $logger ; + } + + /* + * @{inheritDoc} + */ + public function find(array $options){ + /* https://developer.github.com/v3/#pagination */ + $page = empty($options['page']) ? 1 : $options['page']; + $perPage = empty($options['per_page']) ? self::DEFAULT_PER_PAGE : $options['per_page']; + $uri = '?page='.$page.'&per_page='.$perPage; + + $this->logger->debug('GET '.$uri); + $response = $this->httpClient->get($uri); + $projects = json_decode( (string)$response->getBody(), true ) ; + + $result = array(); + foreach ( $projects as $project ){ + $result[] = new GithubProject($project); + } + return $result; + } + + /* + * @{inheritDoc} + */ + public function getRawFile( + ProjectInterface $project, + $filePath, + $ref + ){ + $metadata = $project->getRawMetadata(); + $uri = str_replace( + '{+path}', + urlencode($filePath), + $metadata['contents_url'] + ); + $uri .= '?ref='.$ref; + $this->logger->debug('GET '.$uri); + $response = $this->httpClient->get($uri,[ + 'headers' => [ + 'Accept' => 'application/vnd.github.v3.raw' + ] + ]); + return (string)$response->getBody(); + } + + +} \ No newline at end of file diff --git a/src/MBO/SatisGitlab/Git/GithubProject.php b/src/MBO/SatisGitlab/Git/GithubProject.php new file mode 100644 index 0000000..7fe3cc3 --- /dev/null +++ b/src/MBO/SatisGitlab/Git/GithubProject.php @@ -0,0 +1,53 @@ +rawMetadata = $rawMetadata; + } + + /* + * @{inheritDoc} + */ + public function getId(){ + return $this->rawMetadata['id']; + } + + /* + * @{inheritDoc} + */ + public function getName(){ + return $this->rawMetadata['full_name']; + } + + /* + * @{inheritDoc} + */ + public function getDefaultBranch(){ + return $this->rawMetadata['default_branch']; + } + + /* + * @{inheritDoc} + */ + public function getHttpUrl(){ + return $this->rawMetadata['clone_url']; + } + + /* + * @{inheritDoc} + */ + public function getRawMetadata(){ + return $this->rawMetadata; + } + + +} diff --git a/src/MBO/SatisGitlab/Git/GitlabClient.php b/src/MBO/SatisGitlab/Git/GitlabClient.php index 6f20a3b..5ed24c2 100644 --- a/src/MBO/SatisGitlab/Git/GitlabClient.php +++ b/src/MBO/SatisGitlab/Git/GitlabClient.php @@ -13,7 +13,7 @@ */ class GitlabClient implements ClientInterface { - const DEFAULT_PER_PAGE = 50; + const DEFAULT_PER_PAGE = 100; /** * @var GuzzleHttpClient @@ -38,35 +38,6 @@ public function __construct( $this->logger = $logger ; } - /** - * Create GitlabClient with options - * - * @param ClientOptions $options - * @param LoggerInterface $logger - * @return GitlabClient - */ - public static function createClient( - ClientOptions $options, - LoggerInterface $logger - ) { - /* create http client for gitlab */ - $guzzleOptions = array( - 'base_uri' => $options->getUrl(), - 'timeout' => 10.0, - 'headers' => [] - ); - if ( $options->isUnsafeSsl() ){ - $guzzleOptions['verify'] = false; - } - if ( $options->hasToken() ){ - $guzzleOptions['headers']['Private-Token'] = $options->getToken(); - } - $httpClient = new GuzzleHttpClient($guzzleOptions); - - /* create gitlab client */ - return new GitlabClient($httpClient,$logger); - } - /* * @{inheritDoc} */ diff --git a/tests/Git/GithubClientTest.php b/tests/Git/GithubClientTest.php new file mode 100644 index 0000000..1487f28 --- /dev/null +++ b/tests/Git/GithubClientTest.php @@ -0,0 +1,65 @@ +setUrl('https://api.github.com/users/mborne/repos') + ; + + /* create client */ + $client = ClientFactory::createClient( + $clientOptions, + new NullLogger() + ); + $this->assertInstanceOf(GithubClient::class,$client); + + /* search projects */ + $options = array(); + $projects = $client->find($options); + $projectsByName = array(); + foreach ( $projects as $project ){ + $this->assertInstanceOf(GithubProject::class,$project); + $projectsByName[$project->getName()] = $project; + } + + /* check project found */ + $this->assertArrayHasKey( + 'mborne/satis-gitlab', + $projectsByName + ); + + $project = $projectsByName['mborne/satis-gitlab']; + $composer = $client->getRawFile( + $project, + 'composer.json', + $project->getDefaultBranch() + ); + $this->assertContains('mborne@users.noreply.github.com',$composer); + + $testFileInSubdirectory = $client->getRawFile( + $project, + 'tests/TestCase.php', + $project->getDefaultBranch() + ); + $this->assertContains('class TestCase',$testFileInSubdirectory); + } + +} diff --git a/tests/Git/GitlabClientTest.php b/tests/Git/GitlabClientTest.php index 6a38667..f2fe78a 100644 --- a/tests/Git/GitlabClientTest.php +++ b/tests/Git/GitlabClientTest.php @@ -8,8 +8,8 @@ use MBO\SatisGitlab\Git\GitlabClient; use Psr\Log\NullLogger; -use MBO\SatisGitlab\Git\ClientclientOptions; use MBO\SatisGitlab\Git\ClientOptions; +use MBO\SatisGitlab\Git\ClientFactory; class GitlabClientTest extends TestCase { @@ -32,10 +32,11 @@ public function testGitlabDotComAuthenticated(){ /* create client */ - $client = GitlabClient::createClient( + $client = ClientFactory::createClient( $clientOptions, new NullLogger() ); + $this->assertInstanceOf(GitlabClient::class,$client); /* search projects */ $projects = $client->find(array(