Skip to content

Commit 623eb68

Browse files
committed
Add new API endpoint - list jobs of a specified runner
1 parent 8e7e2ae commit 623eb68

File tree

3 files changed

+161
-0
lines changed

3 files changed

+161
-0
lines changed

doc/api/runners.md

+51
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,57 @@ DELETE /runners/:id
215215
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/runners/6"
216216
```
217217

218+
## List runner's running jobs
219+
220+
List running jobs assigned to the specified Runner.
221+
222+
```
223+
GET /runners/:id/jobs
224+
```
225+
226+
| Attribute | Type | Required | Description |
227+
|-----------|---------|----------|---------------------|
228+
| `id` | integer | yes | The ID of a runner |
229+
230+
```
231+
curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/runners/1/jobs"
232+
```
233+
234+
Example response:
235+
236+
```json
237+
[
238+
{
239+
"id": 2,
240+
"status": "running",
241+
"stage": "test",
242+
"name": "test",
243+
"ref": "master",
244+
"tag": false,
245+
"coverage": null,
246+
"created_at": "2017-11-16T08:50:29.000Z",
247+
"started_at": "2017-11-16T08:51:29.000Z",
248+
"finished_at": "2017-11-16T08:53:29.000Z",
249+
"duration": 120,
250+
"user": null,
251+
"commit": null,
252+
"runner": {
253+
"id": 1,
254+
"description": "My runner1",
255+
"active": true,
256+
"is_shared": true,
257+
"name": null
258+
},
259+
"pipeline": {
260+
"id": 2,
261+
"sha": "97de212e80737a608d939f648d959671fb0a0142",
262+
"ref": "master",
263+
"status": "pending"
264+
}
265+
}
266+
]
267+
```
268+
218269
## List project's runners
219270

220271
List all runners (specific and shared) available in the project. Shared runners

lib/api/runners.rb

+18
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,18 @@ class Runners < Grape::API
8484

8585
destroy_conditionally!(runner)
8686
end
87+
88+
desc 'List jobs running on a runner'
89+
params do
90+
requires :id, type: Integer, desc: 'The ID of the runner'
91+
use :pagination
92+
end
93+
get ':id/jobs' do
94+
runner = get_runner(params[:id])
95+
authenticate_list_runners_jobs!(runner)
96+
97+
present paginate(runner.builds.running), with: Entities::Job
98+
end
8799
end
88100

89101
params do
@@ -192,6 +204,12 @@ def authenticate_enable_runner!(runner)
192204
forbidden!("No access granted") unless user_can_access_runner?(runner)
193205
end
194206

207+
def authenticate_list_runners_jobs!(runner)
208+
return if current_user.admin?
209+
210+
forbidden!("No access granted") unless user_can_access_runner?(runner)
211+
end
212+
195213
def user_can_access_runner?(runner)
196214
current_user.ci_authorized_runners.exists?(runner.id)
197215
end

spec/requests/api/runners_spec.rb

+92
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,98 @@ def update_runner(id, user, args)
354354
end
355355
end
356356

357+
describe 'GET /runners/:id/jobs' do
358+
let!(:job_1) { create(:ci_build) }
359+
let!(:job_2) { create(:ci_build, :running, runner: shared_runner) }
360+
let!(:job_3) { create(:ci_build, :failed, runner: shared_runner) }
361+
let!(:job_4) { create(:ci_build, :running, runner: specific_runner) }
362+
let!(:job_5) { create(:ci_build, :failed, runner: specific_runner) }
363+
364+
context 'admin user' do
365+
context 'when runner exists' do
366+
context 'when runner is shared' do
367+
it 'return jobs' do
368+
get api("/runners/#{shared_runner.id}/jobs", admin)
369+
370+
expect(response).to have_gitlab_http_status(200)
371+
expect(response).to include_pagination_headers
372+
373+
expect(json_response.length).to eq(1)
374+
expect(json_response[0]).to include('id' => job_2.id)
375+
end
376+
end
377+
378+
context 'when runner is specific' do
379+
it 'return jobs' do
380+
get api("/runners/#{specific_runner.id}/jobs", admin)
381+
382+
expect(response).to have_gitlab_http_status(200)
383+
expect(response).to include_pagination_headers
384+
385+
expect(json_response.length).to eq(1)
386+
expect(json_response[0]).to include('id' => job_4.id)
387+
end
388+
end
389+
end
390+
391+
context "when runner doesn't exist" do
392+
it 'returns 404' do
393+
get api('/runners/9999/jobs', admin)
394+
395+
expect(response).to have_gitlab_http_status(404)
396+
end
397+
end
398+
end
399+
400+
context "runner project's administrative user" do
401+
context 'when runner exists' do
402+
context 'when runner is shared' do
403+
it 'returns 403' do
404+
get api("/runners/#{shared_runner.id}/jobs", user)
405+
406+
expect(response).to have_gitlab_http_status(403)
407+
end
408+
end
409+
410+
context 'when runner is specific' do
411+
it 'return jobs' do
412+
get api("/runners/#{specific_runner.id}/jobs", user)
413+
414+
expect(response).to have_gitlab_http_status(200)
415+
expect(response).to include_pagination_headers
416+
417+
expect(json_response.length).to eq(1)
418+
expect(json_response[0]).to include('id' => job_4.id)
419+
end
420+
end
421+
end
422+
423+
context "when runner doesn't exist" do
424+
it 'returns 404' do
425+
get api('/runners/9999/jobs', user)
426+
427+
expect(response).to have_gitlab_http_status(404)
428+
end
429+
end
430+
end
431+
432+
context 'other authorized user' do
433+
it 'does not return jobs' do
434+
get api("/runners/#{specific_runner.id}/jobs", user2)
435+
436+
expect(response).to have_gitlab_http_status(403)
437+
end
438+
end
439+
440+
context 'unauthorized user' do
441+
it 'does not return jobs' do
442+
get api("/runners/#{specific_runner.id}/jobs")
443+
444+
expect(response).to have_gitlab_http_status(401)
445+
end
446+
end
447+
end
448+
357449
describe 'GET /projects/:id/runners' do
358450
context 'authorized user with master privileges' do
359451
it "returns project's runners" do

0 commit comments

Comments
 (0)