diff --git a/app/Services/Buggregator.php b/app/Services/Buggregator.php new file mode 100644 index 00000000..be517996 --- /dev/null +++ b/app/Services/Buggregator.php @@ -0,0 +1,45 @@ + 'smtp_port', + 'prompt' => 'What is the SMTP port?', + 'default' => '1025', + ], + [ + 'shortname' => 'var_dumper_port', + 'prompt' => 'What is the VarDumper server port?', + 'default' => '9912', + ], + [ + 'shortname' => 'monolog_port', + 'prompt' => 'What is the Monolog port?', + 'default' => '9913', + ], + [ + 'shortname' => 'network_alias', + 'prompt' => 'What network alias to you want to assign to this container? This alias can be used by other services on the same network.', + 'default' => 'buggregator', + ], + ]; + + protected $dockerRunTemplate = '-p "${:port}":8000 \ + -p "${:smtp_port}":1025 \ + -p "${:var_dumper_port}":9912 \ + -p "${:monolog_port}":9913 \ + --network-alias "${:network_alias}" \ + "${:organization}"/"${:image_name}":"${:tag}"'; +} diff --git a/app/Shell/GitHubDockerTags.php b/app/Shell/GitHubDockerTags.php new file mode 100644 index 00000000..b9a64e8e --- /dev/null +++ b/app/Shell/GitHubDockerTags.php @@ -0,0 +1,55 @@ +getTagsResponse(), true)['tags']); + } + + public function getLatestTag(): string + { + return $this->getTags()->first(); + } + + protected function getTagsResponse(): StreamInterface + { + $token = $this->getToken(); + + return $this->guzzle + ->get($this->buildTagsUrl(), [ + 'headers' => [ + 'Authorization' => "Bearer {$token}", + ], + ]) + ->getBody(); + } + + protected function getToken(): string + { + $image = $this->service->imageName(); + + $response = $this->guzzle->get('https://ghcr.io/token?' . http_build_query([ + 'scope' => "repository:{$image}:pull", + ]), [ + 'http_errors' => false, + ]); + + if ($response->getStatusCode() !== 200) { + throw new RuntimeException("Something went wrong getting the Token from GitHub's registry."); + } + + return json_decode($response->getBody(), true)['token']; + } + + protected function tagsUrlTemplate(): string + { + return 'https://%s/v2/%s/tags/list'; + } +} diff --git a/tests/Feature/GitHubTagsTest.php b/tests/Feature/GitHubTagsTest.php new file mode 100644 index 00000000..a7d2b3db --- /dev/null +++ b/tests/Feature/GitHubTagsTest.php @@ -0,0 +1,58 @@ +mockImagesResponseHandler()); + $client = new Client(['handler' => $handlerStack]); + + /** @var GitHubDockerTags $dockerTags */ + $dockerTags = M::mock(GitHubDockerTags::class, [$client, app(Buggregator::class)])->makePartial(); + + $this->assertEquals('latest', $dockerTags->getLatestTag()); + } + + /** @test */ + function it_throws_exception_when_token_request_fails() + { + $handlerStack = HandlerStack::create($this->mockImagesResponseHandler(false)); + $client = new Client(['handler' => $handlerStack]); + + /** @var GitHubDockerTags $dockerTags */ + $dockerTags = M::mock(GitHubDockerTags::class, [$client, app(Buggregator::class)])->makePartial(); + + $this->expectException(RuntimeException::class); + + $dockerTags->getLatestTag(); + } + + private function mockImagesResponseHandler($tokenWorks = true) + { + return new MockHandler([ + new Response($tokenWorks ? 200 : 400, [], json_encode([ + 'token' => 'fake-token', + ])), + new Response(200, [], json_encode([ + 'tags' => [ + 'latest', + '1.0.0', + '1.0.0.rc-1', + ], + ])), + ]); + } +}