Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
f6e4eed3
Commit
f6e4eed3
authored
Jan 25, 2022
by
Pedro Pombeiro
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
GraphQL: Add jobs field to CiRunner
Changelog: added
parent
bf33d5e5
Changes
10
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
191 additions
and
5 deletions
+191
-5
app/finders/ci/jobs_finder.rb
app/finders/ci/jobs_finder.rb
+11
-3
app/graphql/resolvers/ci/runner_jobs_resolver.rb
app/graphql/resolvers/ci/runner_jobs_resolver.rb
+45
-0
app/graphql/resolvers/project_jobs_resolver.rb
app/graphql/resolvers/project_jobs_resolver.rb
+2
-1
app/graphql/types/ci/runner_type.rb
app/graphql/types/ci/runner_type.rb
+4
-0
app/policies/ci/runner_policy.rb
app/policies/ci/runner_policy.rb
+4
-0
doc/api/graphql/reference/index.md
doc/api/graphql/reference/index.md
+16
-0
spec/finders/ci/jobs_finder_spec.rb
spec/finders/ci/jobs_finder_spec.rb
+37
-0
spec/graphql/resolvers/ci/runner_jobs_resolver_spec.rb
spec/graphql/resolvers/ci/runner_jobs_resolver_spec.rb
+49
-0
spec/graphql/types/ci/runner_type_spec.rb
spec/graphql/types/ci/runner_type_spec.rb
+1
-1
spec/requests/api/graphql/ci/runner_spec.rb
spec/requests/api/graphql/ci/runner_spec.rb
+22
-0
No files found.
app/finders/ci/jobs_finder.rb
View file @
f6e4eed3
...
...
@@ -4,10 +4,11 @@ module Ci
class
JobsFinder
include
Gitlab
::
Allowable
def
initialize
(
current_user
:,
pipeline:
nil
,
project:
nil
,
params:
{},
type:
::
Ci
::
Build
)
def
initialize
(
current_user
:,
pipeline:
nil
,
project:
nil
,
runner:
nil
,
params:
{},
type:
::
Ci
::
Build
)
@pipeline
=
pipeline
@current_user
=
current_user
@project
=
project
@runner
=
runner
@params
=
params
@type
=
type
raise
ArgumentError
'type must be a subclass of Ci::Processable'
unless
type
<
::
Ci
::
Processable
...
...
@@ -22,10 +23,10 @@ module Ci
private
attr_reader
:current_user
,
:pipeline
,
:project
,
:params
,
:type
attr_reader
:current_user
,
:pipeline
,
:project
,
:
runner
,
:
params
,
:type
def
init_collection
pipeline_jobs
||
project_jobs
||
all_jobs
pipeline_jobs
||
project_jobs
||
runner_jobs
||
all_jobs
end
def
all_jobs
...
...
@@ -34,6 +35,13 @@ module Ci
type
.
all
end
def
runner_jobs
return
unless
runner
raise
Gitlab
::
Access
::
AccessDeniedError
unless
can?
(
current_user
,
:read_builds
,
runner
)
jobs_by_type
(
runner
,
type
).
relevant
end
def
project_jobs
return
unless
project
raise
Gitlab
::
Access
::
AccessDeniedError
unless
can?
(
current_user
,
:read_build
,
project
)
...
...
app/graphql/resolvers/ci/runner_jobs_resolver.rb
0 → 100644
View file @
f6e4eed3
# frozen_string_literal: true
module
Resolvers
module
Ci
class
RunnerJobsResolver
<
BaseResolver
include
Gitlab
::
Graphql
::
Authorize
::
AuthorizeResource
include
LooksAhead
type
::
Types
::
Ci
::
JobType
.
connection_type
,
null:
true
authorize
:read_builds
authorizes_object!
argument
:statuses
,
[
::
Types
::
Ci
::
JobStatusEnum
],
required:
false
,
description:
'Filter jobs by status.'
alias_method
:runner
,
:object
def
ready?
(
**
args
)
context
[
self
.
class
]
||=
{
executions:
0
}
context
[
self
.
class
][
:executions
]
+=
1
raise
GraphQL
::
ExecutionError
,
"Jobs can be requested for only one runner at a time"
if
context
[
self
.
class
][
:executions
]
>
1
super
end
def
resolve_with_lookahead
(
statuses:
nil
)
jobs
=
::
Ci
::
JobsFinder
.
new
(
current_user:
current_user
,
runner:
runner
,
params:
{
scope:
statuses
}).
execute
apply_lookahead
(
jobs
)
end
private
def
preloads
{
previous_stage_jobs_and_needs:
[
:needs
,
:pipeline
],
artifacts:
[
:job_artifacts
],
pipeline:
[
:user
]
}
end
end
end
end
app/graphql/resolvers/project_jobs_resolver.rb
View file @
f6e4eed3
...
...
@@ -18,7 +18,8 @@ module Resolvers
def
ready?
(
**
args
)
context
[
self
.
class
]
||=
{
executions:
0
}
context
[
self
.
class
][
:executions
]
+=
1
raise
GraphQL
::
ExecutionError
,
"Jobs can only be requested for one project at a time"
if
context
[
self
.
class
][
:executions
]
>
1
raise
GraphQL
::
ExecutionError
,
"Jobs can be requested for only one project at a time"
if
context
[
self
.
class
][
:executions
]
>
1
super
end
...
...
app/graphql/types/ci/runner_type.rb
View file @
f6e4eed3
...
...
@@ -70,6 +70,10 @@ module Types
description:
'Groups the runner is associated with. For group runners only.'
field
:projects
,
::
Types
::
ProjectType
.
connection_type
,
null:
true
,
description:
'Projects the runner is associated with. For project runners only.'
field
:jobs
,
::
Types
::
Ci
::
JobType
.
connection_type
,
null:
true
,
description:
'Jobs assigned to the runner.'
,
authorize: :read_builds
,
resolver:
::
Resolvers
::
Ci
::
RunnerJobsResolver
def
job_count
# We limit to 1 above the JOB_COUNT_LIMIT to indicate that more items exist after JOB_COUNT_LIMIT
...
...
app/policies/ci/runner_policy.rb
View file @
f6e4eed3
...
...
@@ -11,6 +11,10 @@ module Ci
rule
{
anonymous
}.
prevent_all
rule
{
admin
}.
policy
do
enable
:read_builds
end
rule
{
admin
|
owned_runner
}.
policy
do
enable
:assign_runner
enable
:read_runner
...
...
doc/api/graphql/reference/index.md
View file @
f6e4eed3
...
...
@@ -9084,6 +9084,22 @@ Represents the total number of issues and their weights for a particular day.
#### Fields with arguments
##### `CiRunner.jobs`
Jobs assigned to the runner.
Returns [`CiJobConnection`](#cijobconnection).
This field returns a [connection](#connections). It accepts the
four standard [pagination arguments](#connection-pagination-arguments):
`before: String`, `after: String`, `first: Int`, `last: Int`.
###### Arguments
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="cirunnerjobsstatuses"></a>`statuses` | [`[CiJobStatus!]`](#cijobstatus) | Filter jobs by status. |
##### `CiRunner.status`
Status of the runner.
spec/finders/ci/jobs_finder_spec.rb
View file @
f6e4eed3
...
...
@@ -126,4 +126,41 @@ RSpec.describe Ci::JobsFinder, '#execute' do
end
end
end
context
'a runner is present'
do
let_it_be
(
:runner
)
{
create
(
:ci_runner
,
:project
,
projects:
[
project
])
}
let_it_be
(
:job_4
)
{
create
(
:ci_build
,
:success
,
runner:
runner
)
}
subject
{
described_class
.
new
(
current_user:
user
,
runner:
runner
,
params:
params
).
execute
}
context
'user has access to the runner'
,
:enable_admin_mode
do
let
(
:user
)
{
admin
}
it
'returns jobs for the specified project'
do
expect
(
subject
).
to
match_array
([
job_4
])
end
end
context
'user has no access to project builds'
do
let_it_be
(
:guest
)
{
create
(
:user
)
}
let
(
:user
)
{
guest
}
before
do
project
.
add_guest
(
guest
)
end
it
'returns no jobs'
do
expect
(
subject
).
to
be_empty
end
end
context
'without user'
do
let
(
:user
)
{
nil
}
it
'returns no jobs'
do
expect
(
subject
).
to
be_empty
end
end
end
end
spec/graphql/resolvers/ci/runner_jobs_resolver_spec.rb
0 → 100644
View file @
f6e4eed3
# frozen_string_literal: true
require
'spec_helper'
RSpec
.
describe
Resolvers
::
Ci
::
RunnerJobsResolver
do
include
GraphqlHelpers
let_it_be
(
:project
)
{
create
(
:project
,
:repository
)
}
let_it_be
(
:pipeline
)
{
create
(
:ci_pipeline
,
project:
project
)
}
let_it_be
(
:irrelevant_pipeline
)
{
create
(
:ci_pipeline
,
project:
project
)
}
let!
(
:build_one
)
{
create
(
:ci_build
,
:success
,
name:
'Build One'
,
runner:
runner
,
pipeline:
pipeline
)
}
let!
(
:build_two
)
{
create
(
:ci_build
,
:success
,
name:
'Build Two'
,
runner:
runner
,
pipeline:
pipeline
)
}
let!
(
:build_three
)
{
create
(
:ci_build
,
:failed
,
name:
'Build Three'
,
runner:
runner
,
pipeline:
pipeline
)
}
let!
(
:irrelevant_build
)
{
create
(
:ci_build
,
name:
'Irrelevant Build'
,
pipeline:
irrelevant_pipeline
)}
let
(
:args
)
{
{}
}
let
(
:runner
)
{
create
(
:ci_runner
,
:project
,
projects:
[
project
])
}
subject
{
resolve_jobs
(
args
)
}
describe
'#resolve'
do
context
'with authorized user'
,
:enable_admin_mode
do
let
(
:current_user
)
{
create
(
:user
,
:admin
)
}
context
'with statuses argument'
do
let
(
:args
)
{
{
statuses:
[
Types
::
Ci
::
JobStatusEnum
.
coerce_isolated_input
(
'SUCCESS'
)]
}
}
it
{
is_expected
.
to
contain_exactly
(
build_one
,
build_two
)
}
end
context
'without statuses argument'
do
it
{
is_expected
.
to
contain_exactly
(
build_one
,
build_two
,
build_three
)
}
end
end
context
'with unauthorized user'
do
let
(
:current_user
)
{
nil
}
it
{
is_expected
.
to
be_nil
}
end
end
private
def
resolve_jobs
(
args
=
{},
context
=
{
current_user:
current_user
})
resolve
(
described_class
,
obj:
runner
,
args:
args
,
ctx:
context
)
end
end
spec/graphql/types/ci/runner_type_spec.rb
View file @
f6e4eed3
...
...
@@ -12,7 +12,7 @@ RSpec.describe GitlabSchema.types['CiRunner'] do
id description created_at contacted_at maximum_timeout access_level active paused status
version short_sha revision locked run_untagged ip_address runner_type tag_list
project_count job_count admin_url edit_admin_url user_permissions executor_name
groups projects
groups projects
jobs
]
expect
(
described_class
).
to
include_graphql_fields
(
*
expected_fields
)
...
...
spec/requests/api/graphql/ci/runner_spec.rb
View file @
f6e4eed3
...
...
@@ -77,6 +77,7 @@ RSpec.describe 'Query.runner(id)' do
'runnerType'
=>
runner
.
instance_type?
?
'INSTANCE_TYPE'
:
'PROJECT_TYPE'
,
'executorName'
=>
runner
.
executor_type
&
.
dasherize
,
'jobCount'
=>
0
,
'jobs'
=>
a_hash_including
(
"count"
=>
0
,
"nodes"
=>
[],
"pageInfo"
=>
anything
),
'projectCount'
=>
nil
,
'adminUrl'
=>
"http://localhost/admin/runners/
#{
runner
.
id
}
"
,
'userPermissions'
=>
{
...
...
@@ -308,12 +309,25 @@ RSpec.describe 'Query.runner(id)' do
let!
(
:job
)
{
create
(
:ci_build
,
runner:
project_runner1
)
}
context
'requesting projects and counts for projects and jobs'
do
let
(
:jobs_fragment
)
do
%(
jobs {
count
nodes {
id
status
}
}
)
end
let
(
:query
)
do
%(
query {
projectRunner1: runner(id: "#{project_runner1.to_global_id}") {
projectCount
jobCount
#{jobs_fragment}
projects {
nodes {
id
...
...
@@ -323,6 +337,7 @@ RSpec.describe 'Query.runner(id)' do
projectRunner2: runner(id: "#{project_runner2.to_global_id}") {
projectCount
jobCount
#{jobs_fragment}
projects {
nodes {
id
...
...
@@ -332,6 +347,7 @@ RSpec.describe 'Query.runner(id)' do
activeInstanceRunner: runner(id: "#{active_instance_runner.to_global_id}") {
projectCount
jobCount
#{jobs_fragment}
projects {
nodes {
id
...
...
@@ -355,6 +371,10 @@ RSpec.describe 'Query.runner(id)' do
expect
(
runner1_data
).
to
match
a_hash_including
(
'jobCount'
=>
1
,
'jobs'
=>
a_hash_including
(
"count"
=>
1
,
"nodes"
=>
[{
"id"
=>
job
.
to_global_id
.
to_s
,
"status"
=>
job
.
status
.
upcase
}]
),
'projectCount'
=>
2
,
'projects'
=>
{
'nodes'
=>
[
...
...
@@ -364,12 +384,14 @@ RSpec.describe 'Query.runner(id)' do
})
expect
(
runner2_data
).
to
match
a_hash_including
(
'jobCount'
=>
0
,
'jobs'
=>
nil
,
# returning jobs not allowed for more than 1 runner (see RunnerJobsResolver)
'projectCount'
=>
0
,
'projects'
=>
{
'nodes'
=>
[]
})
expect
(
runner3_data
).
to
match
a_hash_including
(
'jobCount'
=>
0
,
'jobs'
=>
nil
,
# returning jobs not allowed for more than 1 runner (see RunnerJobsResolver)
'projectCount'
=>
nil
,
'projects'
=>
nil
)
end
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment