From 866532d5701bc06a12a122b4b5ca79444a5cf741 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=83=C2=83=C3=82=C2=A9grier?= Date: Mon, 19 Jun 2017 15:55:32 +0200 Subject: [PATCH 1/4] Adding the Jobs API --- lib/Gitlab/Api/Jobs.php | 131 ++++++++++++++++++ lib/Gitlab/Client.php | 5 + lib/Gitlab/Model/Job.php | 83 ++++++++++++ lib/Gitlab/Model/Pipeline.php | 49 +++++++ lib/Gitlab/Model/Project.php | 45 +++++++ test/Gitlab/Tests/Api/JobsTest.php | 210 +++++++++++++++++++++++++++++ 6 files changed, 523 insertions(+) create mode 100644 lib/Gitlab/Api/Jobs.php create mode 100644 lib/Gitlab/Model/Job.php create mode 100644 lib/Gitlab/Model/Pipeline.php create mode 100644 test/Gitlab/Tests/Api/JobsTest.php diff --git a/lib/Gitlab/Api/Jobs.php b/lib/Gitlab/Api/Jobs.php new file mode 100644 index 000000000..03d2f63cb --- /dev/null +++ b/lib/Gitlab/Api/Jobs.php @@ -0,0 +1,131 @@ +get("projects/".$this->encodePath($project_id)."/jobs", array( + 'scope' => $scope + )); + } + + /** + * @param int|string $project_id + * @param int $pipeline_id + * @param array $scope + * @return mixed + */ + public function pipelineJobs($project_id, $pipeline_id, array $scope = []) + { + return $this->get("projects/".$this->encodePath($project_id)."/pipelines/".$this->encodePath($pipeline_id)."/jobs", array( + 'scope' => $scope + )); + } + + /** + * @param int|string $project_id + * @param int $job_id + * @return mixed + */ + public function show($project_id, $job_id) + { + return $this->get("projects/".$this->encodePath($project_id)."/jobs/".$this->encodePath($job_id)); + } + + /** + * @param int|string $project_id + * @param int $job_id + * @return string + */ + public function artifacts($project_id, $job_id) + { + return $this->get("projects/".$this->encodePath($project_id)."/jobs/".$this->encodePath($job_id)."/artifacts"); + } + + /** + * @param int|string $project_id + * @param string $ref_name + * @param string $job_name + * @return string + */ + public function artifactsByRefName($project_id, $ref_name, $job_name) + { + return $this->get("projects/".$this->encodePath($project_id)."/jobs/artifacts/".$this->encodePath($ref_name)."/download", array( + 'job' => $job_name + )); + } + + /** + * @param int|string $project_id + * @param int $job_id + * @return string + */ + public function trace($project_id, $job_id) + { + return $this->get("projects/".$this->encodePath($project_id)."/jobs/".$this->encodePath($job_id)."/trace"); + } + + /** + * @param int|string $project_id + * @param int $job_id + * @return mixed + */ + public function cancel($project_id, $job_id) + { + return $this->post("projects/".$this->encodePath($project_id)."/jobs/".$this->encodePath($job_id)."/cancel"); + } + + /** + * @param int|string $project_id + * @param int $job_id + * @return mixed + */ + public function retry($project_id, $job_id) + { + return $this->post("projects/".$this->encodePath($project_id)."/jobs/".$this->encodePath($job_id)."/retry"); + } + + /** + * @param int|string $project_id + * @param int $job_id + * @return mixed + */ + public function erase($project_id, $job_id) + { + return $this->post("projects/".$this->encodePath($project_id)."/jobs/".$this->encodePath($job_id)."/erase"); + } + + /** + * @param int|string $project_id + * @param int $job_id + * @return mixed + */ + public function keepArtifacts($project_id, $job_id) + { + return $this->post("projects/".$this->encodePath($project_id)."/jobs/".$this->encodePath($job_id)."/artifacts/keep"); + } + + /** + * @param int|string $project_id + * @param int $job_id + * @return mixed + */ + public function play($project_id, $job_id) + { + return $this->post("projects/".$this->encodePath($project_id)."/jobs/".$this->encodePath($job_id)."/play"); + } +} diff --git a/lib/Gitlab/Client.php b/lib/Gitlab/Client.php index b2cefa372..2cb2e4e49 100644 --- a/lib/Gitlab/Client.php +++ b/lib/Gitlab/Client.php @@ -21,6 +21,7 @@ * * @property-read \Gitlab\Api\Groups $groups * @property-read \Gitlab\Api\Issues $issues + * @property-read \Gitlab\Api\Jobs $jobs * @property-read \Gitlab\Api\MergeRequests $merge_requests * @property-read \Gitlab\Api\MergeRequests $mr * @property-read \Gitlab\Api\Milestones $milestones @@ -138,6 +139,10 @@ public function api($name) $api = new Api\Issues($this); break; + case 'jobs': + $api = new Api\Jobs($this); + break; + case 'mr': case 'merge_requests': $api = new Api\MergeRequests($this); diff --git a/lib/Gitlab/Model/Job.php b/lib/Gitlab/Model/Job.php new file mode 100644 index 000000000..586e3a311 --- /dev/null +++ b/lib/Gitlab/Model/Job.php @@ -0,0 +1,83 @@ +hydrate($data); + } + + /** + * @param Project $project + * @param int $id + * @param Client $client + */ + public function __construct(Project $project, $id = null, Client $client = null) + { + $this->setClient($client); + $this->setData('project', $project); + $this->setData('id', $id); + } +} diff --git a/lib/Gitlab/Model/Pipeline.php b/lib/Gitlab/Model/Pipeline.php new file mode 100644 index 000000000..58ec521bd --- /dev/null +++ b/lib/Gitlab/Model/Pipeline.php @@ -0,0 +1,49 @@ +hydrate($data); + } + + /** + * @param Project $project + * @param int $id + * @param Client $client + */ + public function __construct(Project $project, $id = null, Client $client = null) + { + $this->setClient($client); + $this->setData('project', $project); + $this->setData('id', $id); + } +} diff --git a/lib/Gitlab/Model/Project.php b/lib/Gitlab/Model/Project.php index 44fa9a7ee..031cb9def 100644 --- a/lib/Gitlab/Model/Project.php +++ b/lib/Gitlab/Model/Project.php @@ -1092,4 +1092,49 @@ public function contributors() return $contributors; } + + /** + * @param array $scopes + * @return Job[] + */ + public function jobs(array $scopes) + { + $data = $this->api('jobs')->jobs($this->id, $scopes); + + $jobs = array(); + foreach ($data as $job) { + $jobs[] = Job::fromArray($this->getClient(), $this, $job); + } + + return $jobs; + } + + /** + * @param int $pipeline_id + * @param array $scopes + * @return Job[] + */ + public function pipelineJobs($pipeline_id, array $scopes = []) + { + $data = $this->api('jobs')->pipelineJobs($this->id, $pipeline_id, $scopes); + + $jobs = array(); + foreach ($data as $job) { + $jobs[] = Job::fromArray($this->getClient(), $this, $job); + } + + return $jobs; + } + + /** + * @param int $job_id + * @return Job + */ + public function job($job_id) + { + $data = $this->api('jobs')->show($this->id, $job_id); + + return Job::fromArray($this->getClient(), $this, $data); + } + } diff --git a/test/Gitlab/Tests/Api/JobsTest.php b/test/Gitlab/Tests/Api/JobsTest.php new file mode 100644 index 000000000..d13880664 --- /dev/null +++ b/test/Gitlab/Tests/Api/JobsTest.php @@ -0,0 +1,210 @@ + 1, 'name' => 'A job'), + array('id' => 2, 'name' => 'Another job'), + ); + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('projects/1/jobs', array( + 'scope' => ['pending'] + )) + ->will($this->returnValue($expectedArray)) + ; + + $this->assertEquals($expectedArray, $api->jobs(1, [Jobs::SCOPE_PENDING])); + } + + /** + * @test + */ + public function shouldGetPipelineJobs() + { + $expectedArray = array( + array('id' => 1, 'name' => 'A job'), + array('id' => 2, 'name' => 'Another job'), + ); + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('projects/1/pipelines/2/jobs', array( + 'scope' => ['pending'] + )) + ->will($this->returnValue($expectedArray)) + ; + + $this->assertEquals($expectedArray, $api->pipelineJobs(1, 2, [Jobs::SCOPE_PENDING])); + } + + /** + * @test + */ + public function shouldGetJob() + { + $expectedArray = array('id' => 3, 'name' => 'A job'); + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('projects/1/jobs/3') + ->will($this->returnValue($expectedArray)) + ; + + $this->assertEquals($expectedArray, $api->show(1, 3)); + } + + /** + * @test + */ + public function shouldGetArtifacts() + { + $expectedString = "some file content"; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('projects/1/jobs/3/artifacts') + ->will($this->returnValue($expectedString)) + ; + + $this->assertEquals($expectedString, $api->artifacts(1, 3)); + } + + /** + * @test + */ + public function shouldGetArtifactsByRefName() + { + $expectedString = "some file content"; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('projects/1/jobs/artifacts/master/download', array( + 'job' => 'job_name' + )) + ->will($this->returnValue($expectedString)) + ; + + $this->assertEquals($expectedString, $api->artifactsByRefName(1, 'master', 'job_name')); + } + + /** + * @test + */ + public function shouldGetTrace() + { + $expectedString = "some trace"; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('projects/1/jobs/3/trace') + ->will($this->returnValue($expectedString)) + ; + + $this->assertEquals($expectedString, $api->trace(1, 3)); + } + + /** + * @test + */ + public function shouldCancel() + { + $expectedArray = array('id' => 3, 'name' => 'A job'); + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('post') + ->with('projects/1/jobs/3/cancel') + ->will($this->returnValue($expectedArray)) + ; + + $this->assertEquals($expectedArray, $api->cancel(1, 3)); + } + + /** + * @test + */ + public function shouldRetry() + { + $expectedArray = array('id' => 3, 'name' => 'A job'); + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('post') + ->with('projects/1/jobs/3/retry') + ->will($this->returnValue($expectedArray)) + ; + + $this->assertEquals($expectedArray, $api->retry(1, 3)); + } + + /** + * @test + */ + public function shouldErase() + { + $expectedArray = array('id' => 3, 'name' => 'A job'); + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('post') + ->with('projects/1/jobs/3/erase') + ->will($this->returnValue($expectedArray)) + ; + + $this->assertEquals($expectedArray, $api->erase(1, 3)); + } + + /** + * @test + */ + public function shouldKeepArtifacts() + { + $expectedArray = array('id' => 3, 'name' => 'A job'); + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('post') + ->with('projects/1/jobs/3/artifacts/keep') + ->will($this->returnValue($expectedArray)) + ; + + $this->assertEquals($expectedArray, $api->keepArtifacts(1, 3)); + } + + /** + * @test + */ + public function shouldPlay() + { + $expectedArray = array('id' => 3, 'name' => 'A job'); + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('post') + ->with('projects/1/jobs/3/play') + ->will($this->returnValue($expectedArray)) + ; + + $this->assertEquals($expectedArray, $api->play(1, 3)); + } + + protected function getApiClass() + { + return 'Gitlab\Api\Jobs'; + } +} From a1174d700a6d513dabb70b3ca04e4849f01ee2ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Fri, 7 Jul 2017 11:33:53 +0200 Subject: [PATCH 2/4] Migrating JobsAPI to use new HTTPlug. Now returning a StreamInterface instead of a string for artifact files. --- lib/Gitlab/Api/AbstractApi.php | 20 ++++++++++++++++---- lib/Gitlab/Api/Jobs.php | 12 +++++++----- test/Gitlab/Tests/Api/JobsTest.php | 19 ++++++++++--------- test/Gitlab/Tests/Api/TestCase.php | 2 +- 4 files changed, 34 insertions(+), 19 deletions(-) diff --git a/lib/Gitlab/Api/AbstractApi.php b/lib/Gitlab/Api/AbstractApi.php index e08996973..7aab58d0e 100644 --- a/lib/Gitlab/Api/AbstractApi.php +++ b/lib/Gitlab/Api/AbstractApi.php @@ -5,6 +5,7 @@ use Http\Discovery\StreamFactoryDiscovery; use Http\Message\MultipartStream\MultipartStreamBuilder; use Http\Message\StreamFactory; +use Psr\Http\Message\ResponseInterface; /** * Abstract class for Api classes @@ -52,18 +53,29 @@ public function configure() } /** + * Performs a GET query and returns the response as a PSR-7 response object. + * * @param string $path * @param array $parameters * @param array $requestHeaders - * @return mixed + * @return ResponseInterface */ - protected function get($path, array $parameters = array(), $requestHeaders = array()) + protected function getAsResponse($path, array $parameters = array(), $requestHeaders = array()) { $path = $this->preparePath($path, $parameters); - $response = $this->client->getHttpClient()->get($path, $requestHeaders); + return $this->client->getHttpClient()->get($path, $requestHeaders); + } - return ResponseMediator::getContent($response); + /** + * @param string $path + * @param array $parameters + * @param array $requestHeaders + * @return mixed + */ + protected function get($path, array $parameters = array(), $requestHeaders = array()) + { + return ResponseMediator::getContent($this->getAsResponse($path, $parameters, $requestHeaders)); } /** diff --git a/lib/Gitlab/Api/Jobs.php b/lib/Gitlab/Api/Jobs.php index 03d2f63cb..580a69f14 100644 --- a/lib/Gitlab/Api/Jobs.php +++ b/lib/Gitlab/Api/Jobs.php @@ -1,5 +1,7 @@ get("projects/".$this->encodePath($project_id)."/jobs/".$this->encodePath($job_id)."/artifacts"); + return $this->getAsResponse("projects/".$this->encodePath($project_id)."/jobs/".$this->encodePath($job_id)."/artifacts")->getBody(); } /** * @param int|string $project_id * @param string $ref_name * @param string $job_name - * @return string + * @return StreamInterface */ public function artifactsByRefName($project_id, $ref_name, $job_name) { - return $this->get("projects/".$this->encodePath($project_id)."/jobs/artifacts/".$this->encodePath($ref_name)."/download", array( + return $this->getAsResponse("projects/".$this->encodePath($project_id)."/jobs/artifacts/".$this->encodePath($ref_name)."/download", array( 'job' => $job_name - )); + ))->getBody(); } /** diff --git a/test/Gitlab/Tests/Api/JobsTest.php b/test/Gitlab/Tests/Api/JobsTest.php index d13880664..556856a8e 100644 --- a/test/Gitlab/Tests/Api/JobsTest.php +++ b/test/Gitlab/Tests/Api/JobsTest.php @@ -1,8 +1,9 @@ getApiMock(); $api->expects($this->once()) - ->method('get') + ->method('getAsResponse') ->with('projects/1/jobs/3/artifacts') - ->will($this->returnValue($expectedString)) + ->will($this->returnValue($returnedStream)) ; - $this->assertEquals($expectedString, $api->artifacts(1, 3)); + $this->assertEquals('foobar', $api->artifacts(1, 3)->getContents()); } /** @@ -87,18 +88,18 @@ public function shouldGetArtifacts() */ public function shouldGetArtifactsByRefName() { - $expectedString = "some file content"; + $returnedStream = new Response(200, [], 'foobar'); $api = $this->getApiMock(); $api->expects($this->once()) - ->method('get') + ->method('getAsResponse') ->with('projects/1/jobs/artifacts/master/download', array( 'job' => 'job_name' )) - ->will($this->returnValue($expectedString)) + ->will($this->returnValue($returnedStream)) ; - $this->assertEquals($expectedString, $api->artifactsByRefName(1, 'master', 'job_name')); + $this->assertEquals('foobar', $api->artifactsByRefName(1, 'master', 'job_name')->getContents()); } /** diff --git a/test/Gitlab/Tests/Api/TestCase.php b/test/Gitlab/Tests/Api/TestCase.php index b3dadeb6f..a48c1a01a 100644 --- a/test/Gitlab/Tests/Api/TestCase.php +++ b/test/Gitlab/Tests/Api/TestCase.php @@ -28,7 +28,7 @@ protected function getApiMock(array $methods = []) $client = Client::createWithHttpClient($httpClient); return $this->getMockBuilder($this->getApiClass()) - ->setMethods(array_merge(array('get', 'post', 'postRaw', 'patch', 'delete', 'put', 'head'), $methods)) + ->setMethods(array_merge(array('getAsResponse', 'get', 'post', 'postRaw', 'patch', 'delete', 'put', 'head'), $methods)) ->setConstructorArgs(array($client)) ->getMock(); } From 0bd3cd4a35f0cf992ebe90b96a6eefde70eab3dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=83=C2=A9grier?= Date: Sat, 8 Jul 2017 18:44:37 +0200 Subject: [PATCH 3/4] Changing method name from "jobs" to "all" --- lib/Gitlab/Api/Jobs.php | 2 +- test/Gitlab/Tests/Api/JobsTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Gitlab/Api/Jobs.php b/lib/Gitlab/Api/Jobs.php index 580a69f14..246f8f148 100644 --- a/lib/Gitlab/Api/Jobs.php +++ b/lib/Gitlab/Api/Jobs.php @@ -18,7 +18,7 @@ class Jobs extends AbstractApi * @param array $scope * @return mixed */ - public function jobs($project_id, array $scope = []) + public function all($project_id, array $scope = []) { return $this->get("projects/".$this->encodePath($project_id)."/jobs", array( 'scope' => $scope diff --git a/test/Gitlab/Tests/Api/JobsTest.php b/test/Gitlab/Tests/Api/JobsTest.php index 556856a8e..c002437dc 100644 --- a/test/Gitlab/Tests/Api/JobsTest.php +++ b/test/Gitlab/Tests/Api/JobsTest.php @@ -24,7 +24,7 @@ public function shouldGetAllJobs() ->will($this->returnValue($expectedArray)) ; - $this->assertEquals($expectedArray, $api->jobs(1, [Jobs::SCOPE_PENDING])); + $this->assertEquals($expectedArray, $api->all(1, [Jobs::SCOPE_PENDING])); } /** From 52f2b20caad4b4a2daaed2840d44a07f4c1f3ec4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Sat, 8 Jul 2017 18:45:28 +0200 Subject: [PATCH 4/4] Default value for jobs method and fixing bug in pipeline class --- lib/Gitlab/Model/Pipeline.php | 2 +- lib/Gitlab/Model/Project.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Gitlab/Model/Pipeline.php b/lib/Gitlab/Model/Pipeline.php index 58ec521bd..b2129c8de 100644 --- a/lib/Gitlab/Model/Pipeline.php +++ b/lib/Gitlab/Model/Pipeline.php @@ -32,7 +32,7 @@ public static function fromArray(Client $client, Project $project, array $data) { $pipeline = new static($project, $data['id'], $client); - return $job->hydrate($data); + return $pipeline->hydrate($data); } /** diff --git a/lib/Gitlab/Model/Project.php b/lib/Gitlab/Model/Project.php index 031cb9def..60d470318 100644 --- a/lib/Gitlab/Model/Project.php +++ b/lib/Gitlab/Model/Project.php @@ -1097,7 +1097,7 @@ public function contributors() * @param array $scopes * @return Job[] */ - public function jobs(array $scopes) + public function jobs(array $scopes = []) { $data = $this->api('jobs')->jobs($this->id, $scopes);