Commit f3724006 authored by Toon Claes's avatar Toon Claes

Add GET /projects/:id/pipelines/:pipeline_id/jobs endpoint

Add endpoint to get the jobs scoped to a pipeline.
parent 7f2819b7
---
title: Add GET /projects/:id/pipelines/:pipeline_id/jobs endpoint
merge_request: 9727
author:
# Jobs API
## List project jobs
## List project jobs
Get a list of jobs in a project.
......@@ -115,6 +115,122 @@ Example of response
]
```
## List pipeline jobs
Get a list of jobs for a pipeline.
```
GET /projects/:id/pipeline/:pipeline_id/jobs
```
| Attribute | Type | Required | Description |
|--------------|--------------------------------|----------|----------------------|
| `id` | integer | yes | The ID of a project |
| `pipelin_id` | integer | yes | The ID of a pipeline |
| `scope` | string **or** array of strings | no | The scope of jobs to show, one or array of: `created`, `pending`, `running`, `failed`, `success`, `canceled`, `skipped`; showing all jobs if none provided |
```
curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" 'https://gitlab.example.com/api/v4/projects/1/pipelines/6/jobs?scope%5B0%5D=pending&scope%5B1%5D=running'
```
Example of response
```json
[
{
"commit": {
"author_email": "admin@example.com",
"author_name": "Administrator",
"created_at": "2015-12-24T16:51:14.000+01:00",
"id": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd",
"message": "Test the CI integration.",
"short_id": "0ff3ae19",
"title": "Test the CI integration."
},
"coverage": null,
"created_at": "2015-12-24T15:51:21.802Z",
"artifacts_file": {
"filename": "artifacts.zip",
"size": 1000
},
"finished_at": "2015-12-24T17:54:27.895Z",
"id": 7,
"name": "teaspoon",
"pipeline": {
"id": 6,
"ref": "master",
"sha": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd",
"status": "pending"
},
"ref": "master",
"runner": null,
"stage": "test",
"started_at": "2015-12-24T17:54:27.722Z",
"status": "failed",
"tag": false,
"user": {
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
"bio": null,
"created_at": "2015-12-21T13:14:24.077Z",
"id": 1,
"is_admin": true,
"linkedin": "",
"name": "Administrator",
"skype": "",
"state": "active",
"twitter": "",
"username": "root",
"web_url": "http://gitlab.dev/root",
"website_url": ""
}
},
{
"commit": {
"author_email": "admin@example.com",
"author_name": "Administrator",
"created_at": "2015-12-24T16:51:14.000+01:00",
"id": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd",
"message": "Test the CI integration.",
"short_id": "0ff3ae19",
"title": "Test the CI integration."
},
"coverage": null,
"created_at": "2015-12-24T15:51:21.727Z",
"artifacts_file": null,
"finished_at": "2015-12-24T17:54:24.921Z",
"id": 6,
"name": "spinach:other",
"pipeline": {
"id": 6,
"ref": "master",
"sha": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd",
"status": "pending"
},
"ref": "master",
"runner": null,
"stage": "test",
"started_at": "2015-12-24T17:54:24.729Z",
"status": "failed",
"tag": false,
"user": {
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
"bio": null,
"created_at": "2015-12-21T13:14:24.077Z",
"id": 1,
"is_admin": true,
"linkedin": "",
"name": "Administrator",
"skype": "",
"state": "active",
"twitter": "",
"username": "root",
"web_url": "http://gitlab.dev/root",
"website_url": ""
}
}
]
```
## Get a single job
Get a single job of a project
......
......@@ -40,6 +40,23 @@ module API
user_can_download_artifacts: can?(current_user, :read_build, user_project)
end
desc 'Get pipeline jobs' do
success Entities::Job
end
params do
requires :pipeline_id, type: Integer, desc: 'The pipeline ID'
use :optional_scope
use :pagination
end
get ':id/pipelines/:pipeline_id/jobs' do
pipeline = user_project.pipelines.find(params[:pipeline_id])
builds = pipeline.builds
builds = filter_builds(builds, params[:scope])
present paginate(builds), with: Entities::Job,
user_can_download_artifacts: can?(current_user, :read_build, user_project)
end
desc 'Get a specific job of a project' do
success Entities::Job
end
......
......@@ -75,6 +75,78 @@ describe API::Jobs, api: true do
end
end
describe 'GET /projects/:id/pipelines/:pipeline_id/jobs' do
let(:query) { Hash.new }
before do
get api("/projects/#{project.id}/pipelines/#{pipeline.id}/jobs", api_user), query
end
context 'authorized user' do
it 'returns pipeline jobs' do
expect(response).to have_http_status(200)
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
end
it 'returns correct values' do
expect(json_response).not_to be_empty
expect(json_response.first['commit']['id']).to eq project.commit.id
end
it 'returns pipeline data' do
json_build = json_response.first
expect(json_build['pipeline']).not_to be_empty
expect(json_build['pipeline']['id']).to eq build.pipeline.id
expect(json_build['pipeline']['ref']).to eq build.pipeline.ref
expect(json_build['pipeline']['sha']).to eq build.pipeline.sha
expect(json_build['pipeline']['status']).to eq build.pipeline.status
end
context 'filter jobs with one scope element' do
let(:query) { { 'scope' => 'pending' } }
it do
expect(response).to have_http_status(200)
expect(json_response).to be_an Array
end
end
context 'filter jobs with array of scope elements' do
let(:query) { { 'scope[0]' => 'pending', 'scope[1]' => 'running' } }
it do
expect(response).to have_http_status(200)
expect(json_response).to be_an Array
end
end
context 'respond 400 when scope contains invalid state' do
let(:query) { { 'scope[0]' => 'unknown', 'scope[1]' => 'running' } }
it { expect(response).to have_http_status(400) }
end
context 'jobs in different pipelines' do
let!(:pipeline2) { create(:ci_empty_pipeline, project: project) }
let!(:build2) { create(:ci_build, pipeline: pipeline2) }
it 'excludes jobs from other pipelines' do
json_response.each { |job| expect(job['pipeline']['id']).to eq(pipeline.id) }
end
end
end
context 'unauthorized user' do
let(:api_user) { nil }
it 'does not return jobs' do
expect(response).to have_http_status(401)
end
end
end
describe 'GET /projects/:id/jobs/:job_id' do
before do
get api("/projects/#{project.id}/jobs/#{build.id}", api_user)
......
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