Commit 59e7d04b authored by Toon Claes's avatar Toon Claes

Expose pipelines as PipelineBasic `projects/:id/pipelines`

The `projects/:id/pipelines` exposed a lot of extra details
that are superfluous and it was taking extra resources to fetch them.

To get more details about a pipeline, use
`projects/:id/pipelines/:pipeline_id`.
parent b1864604
---
title: Expose pipelines as PipelineBasic `api/v3/projects/:id/pipelines`
merge_request: 8875
author:
...@@ -24,49 +24,13 @@ Example of response ...@@ -24,49 +24,13 @@ Example of response
"id": 47, "id": 47,
"status": "pending", "status": "pending",
"ref": "new-pipeline", "ref": "new-pipeline",
"sha": "a91957a858320c0e17f3a0eca7cfacbff50ea29a", "sha": "a91957a858320c0e17f3a0eca7cfacbff50ea29a"
"before_sha": "a91957a858320c0e17f3a0eca7cfacbff50ea29a",
"tag": false,
"yaml_errors": null,
"user": {
"name": "Administrator",
"username": "root",
"id": 1,
"state": "active",
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
"web_url": "http://localhost:3000/root"
},
"created_at": "2016-08-16T10:23:19.007Z",
"updated_at": "2016-08-16T10:23:19.216Z",
"started_at": null,
"finished_at": null,
"committed_at": null,
"duration": null,
"coverage": "30.0"
}, },
{ {
"id": 48, "id": 48,
"status": "pending", "status": "pending",
"ref": "new-pipeline", "ref": "new-pipeline",
"sha": "eb94b618fb5865b26e80fdd8ae531b7a63ad851a", "sha": "eb94b618fb5865b26e80fdd8ae531b7a63ad851a"
"before_sha": "eb94b618fb5865b26e80fdd8ae531b7a63ad851a",
"tag": false,
"yaml_errors": null,
"user": {
"name": "Administrator",
"username": "root",
"id": 1,
"state": "active",
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
"web_url": "http://localhost:3000/root"
},
"created_at": "2016-08-16T10:23:21.184Z",
"updated_at": "2016-08-16T10:23:21.314Z",
"started_at": null,
"finished_at": null,
"committed_at": null,
"duration": null,
"coverage": null
} }
] ]
``` ```
......
...@@ -53,3 +53,4 @@ changes are in V4: ...@@ -53,3 +53,4 @@ changes are in V4:
- Remove `GET /groups/owned`. Use `GET /groups?owned=true` instead [!9505](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9505) - Remove `GET /groups/owned`. Use `GET /groups?owned=true` instead [!9505](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9505)
- Return 202 with JSON body on async removals on V4 API (DELETE `/projects/:id/repository/merged_branches` and DELETE `/projects/:id`) [!9449](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9449) - Return 202 with JSON body on async removals on V4 API (DELETE `/projects/:id/repository/merged_branches` and DELETE `/projects/:id`) [!9449](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9449)
- `projects/:id/milestones?iid[]=x&iid[]=y` array filter has been renamed to `iids` [!9096](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9096) - `projects/:id/milestones?iid[]=x&iid[]=y` array filter has been renamed to `iids` [!9096](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9096)
- Return basic info about pipeline in `GET /projects/:id/pipelines` [!8875](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8875)
...@@ -20,6 +20,7 @@ module API ...@@ -20,6 +20,7 @@ module API
mount ::API::V3::MergeRequestDiffs mount ::API::V3::MergeRequestDiffs
mount ::API::V3::MergeRequests mount ::API::V3::MergeRequests
mount ::API::V3::Notes mount ::API::V3::Notes
mount ::API::V3::Pipelines
mount ::API::V3::ProjectHooks mount ::API::V3::ProjectHooks
mount ::API::V3::Milestones mount ::API::V3::Milestones
mount ::API::V3::Projects mount ::API::V3::Projects
......
...@@ -10,7 +10,7 @@ module API ...@@ -10,7 +10,7 @@ module API
resource :projects do resource :projects do
desc 'Get all Pipelines of the project' do desc 'Get all Pipelines of the project' do
detail 'This feature was introduced in GitLab 8.11.' detail 'This feature was introduced in GitLab 8.11.'
success Entities::Pipeline success Entities::PipelineBasic
end end
params do params do
use :pagination use :pagination
...@@ -21,7 +21,7 @@ module API ...@@ -21,7 +21,7 @@ module API
authorize! :read_pipeline, user_project authorize! :read_pipeline, user_project
pipelines = PipelinesFinder.new(user_project).execute(scope: params[:scope]) pipelines = PipelinesFinder.new(user_project).execute(scope: params[:scope])
present paginate(pipelines), with: Entities::Pipeline present paginate(pipelines), with: Entities::PipelineBasic
end end
desc 'Create a new pipeline' do desc 'Create a new pipeline' do
......
module API
module V3
class Pipelines < Grape::API
include PaginationParams
before { authenticate! }
params do
requires :id, type: String, desc: 'The project ID'
end
resource :projects do
desc 'Get all Pipelines of the project' do
detail 'This feature was introduced in GitLab 8.11.'
success ::API::Entities::Pipeline
end
params do
use :pagination
optional :scope, type: String, values: %w(running branches tags),
desc: 'Either running, branches, or tags'
end
get ':id/pipelines' do
authorize! :read_pipeline, user_project
pipelines = PipelinesFinder.new(user_project).execute(scope: params[:scope])
present paginate(pipelines), with: ::API::Entities::Pipeline
end
end
helpers do
def pipeline
@pipeline ||= user_project.pipelines.find(params[:pipeline_id])
end
end
end
end
end
...@@ -24,6 +24,7 @@ describe API::Pipelines, api: true do ...@@ -24,6 +24,7 @@ describe API::Pipelines, api: true do
expect(json_response).to be_an Array expect(json_response).to be_an Array
expect(json_response.first['sha']).to match /\A\h{40}\z/ expect(json_response.first['sha']).to match /\A\h{40}\z/
expect(json_response.first['id']).to eq pipeline.id expect(json_response.first['id']).to eq pipeline.id
expect(json_response.first.keys).to contain_exactly(*%w[id sha ref status])
end end
end end
......
require 'spec_helper'
describe API::V3::Pipelines, api: true do
include ApiHelpers
let(:user) { create(:user) }
let(:non_member) { create(:user) }
let(:project) { create(:project, :repository, creator: user) }
let!(:pipeline) do
create(:ci_empty_pipeline, project: project, sha: project.commit.id,
ref: project.default_branch)
end
before { project.team << [user, :master] }
shared_examples 'a paginated resources' do
before do
# Fires the request
request
end
it 'has pagination headers' do
expect(response).to include_pagination_headers
end
end
describe 'GET /projects/:id/pipelines ' do
it_behaves_like 'a paginated resources' do
let(:request) { get v3_api("/projects/#{project.id}/pipelines", user) }
end
context 'authorized user' do
it 'returns project pipelines' do
get v3_api("/projects/#{project.id}/pipelines", user)
expect(response).to have_http_status(200)
expect(json_response).to be_an Array
expect(json_response.first['sha']).to match(/\A\h{40}\z/)
expect(json_response.first['id']).to eq pipeline.id
expect(json_response.first.keys).to contain_exactly(*%w[id sha ref status before_sha tag yaml_errors user created_at updated_at started_at finished_at committed_at duration coverage])
end
end
context 'unauthorized user' do
it 'does not return project pipelines' do
get v3_api("/projects/#{project.id}/pipelines", non_member)
expect(response).to have_http_status(404)
expect(json_response['message']).to eq '404 Project Not Found'
expect(json_response).not_to be_an Array
end
end
end
describe 'POST /projects/:id/pipeline ' do
context 'authorized user' do
context 'with gitlab-ci.yml' do
before { stub_ci_pipeline_to_return_yaml_file }
it 'creates and returns a new pipeline' do
expect do
post v3_api("/projects/#{project.id}/pipeline", user), ref: project.default_branch
end.to change { Ci::Pipeline.count }.by(1)
expect(response).to have_http_status(201)
expect(json_response).to be_a Hash
expect(json_response['sha']).to eq project.commit.id
end
it 'fails when using an invalid ref' do
post v3_api("/projects/#{project.id}/pipeline", user), ref: 'invalid_ref'
expect(response).to have_http_status(400)
expect(json_response['message']['base'].first).to eq 'Reference not found'
expect(json_response).not_to be_an Array
end
end
context 'without gitlab-ci.yml' do
it 'fails to create pipeline' do
post v3_api("/projects/#{project.id}/pipeline", user), ref: project.default_branch
expect(response).to have_http_status(400)
expect(json_response['message']['base'].first).to eq 'Missing .gitlab-ci.yml file'
expect(json_response).not_to be_an Array
end
end
end
context 'unauthorized user' do
it 'does not create pipeline' do
post v3_api("/projects/#{project.id}/pipeline", non_member), ref: project.default_branch
expect(response).to have_http_status(404)
expect(json_response['message']).to eq '404 Project Not Found'
expect(json_response).not_to be_an Array
end
end
end
describe 'GET /projects/:id/pipelines/:pipeline_id' do
context 'authorized user' do
it 'returns project pipelines' do
get v3_api("/projects/#{project.id}/pipelines/#{pipeline.id}", user)
expect(response).to have_http_status(200)
expect(json_response['sha']).to match /\A\h{40}\z/
end
it 'returns 404 when it does not exist' do
get v3_api("/projects/#{project.id}/pipelines/123456", user)
expect(response).to have_http_status(404)
expect(json_response['message']).to eq '404 Not found'
expect(json_response['id']).to be nil
end
context 'with coverage' do
before do
create(:ci_build, coverage: 30, pipeline: pipeline)
end
it 'exposes the coverage' do
get v3_api("/projects/#{project.id}/pipelines/#{pipeline.id}", user)
expect(json_response["coverage"].to_i).to eq(30)
end
end
end
context 'unauthorized user' do
it 'should not return a project pipeline' do
get v3_api("/projects/#{project.id}/pipelines/#{pipeline.id}", non_member)
expect(response).to have_http_status(404)
expect(json_response['message']).to eq '404 Project Not Found'
expect(json_response['id']).to be nil
end
end
end
describe 'POST /projects/:id/pipelines/:pipeline_id/retry' do
context 'authorized user' do
let!(:pipeline) do
create(:ci_pipeline, project: project, sha: project.commit.id,
ref: project.default_branch)
end
let!(:build) { create(:ci_build, :failed, pipeline: pipeline) }
it 'retries failed builds' do
expect do
post v3_api("/projects/#{project.id}/pipelines/#{pipeline.id}/retry", user)
end.to change { pipeline.builds.count }.from(1).to(2)
expect(response).to have_http_status(201)
expect(build.reload.retried?).to be true
end
end
context 'unauthorized user' do
it 'should not return a project pipeline' do
post v3_api("/projects/#{project.id}/pipelines/#{pipeline.id}/retry", non_member)
expect(response).to have_http_status(404)
expect(json_response['message']).to eq '404 Project Not Found'
expect(json_response['id']).to be nil
end
end
end
describe 'POST /projects/:id/pipelines/:pipeline_id/cancel' do
let!(:pipeline) do
create(:ci_empty_pipeline, project: project, sha: project.commit.id,
ref: project.default_branch)
end
let!(:build) { create(:ci_build, :running, pipeline: pipeline) }
context 'authorized user' do
it 'retries failed builds' do
post v3_api("/projects/#{project.id}/pipelines/#{pipeline.id}/cancel", user)
expect(response).to have_http_status(200)
expect(json_response['status']).to eq('canceled')
end
end
context 'user without proper access rights' do
let!(:reporter) { create(:user) }
before { project.team << [reporter, :reporter] }
it 'rejects the action' do
post v3_api("/projects/#{project.id}/pipelines/#{pipeline.id}/cancel", reporter)
expect(response).to have_http_status(403)
expect(pipeline.reload.status).to eq('pending')
end
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment