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
b66233f9
Commit
b66233f9
authored
Feb 19, 2018
by
Tomasz Maczukin
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Port of add-per-runner-job-timeout to EE
parent
bbede12a
Changes
35
Show whitespace changes
Inline
Side-by-side
Showing
35 changed files
with
645 additions
and
30 deletions
+645
-30
app/assets/javascripts/jobs/components/sidebar_detail_row.vue
...assets/javascripts/jobs/components/sidebar_detail_row.vue
+24
-0
app/assets/javascripts/jobs/components/sidebar_details_block.vue
...ets/javascripts/jobs/components/sidebar_details_block.vue
+27
-0
app/assets/javascripts/jobs/job_details_bundle.js
app/assets/javascripts/jobs/job_details_bundle.js
+1
-0
app/models/ci/build.rb
app/models/ci/build.rb
+12
-4
app/models/ci/build_metadata.rb
app/models/ci/build_metadata.rb
+35
-0
app/models/ci/runner.rb
app/models/ci/runner.rb
+8
-1
app/models/concerns/chronic_duration_attribute.rb
app/models/concerns/chronic_duration_attribute.rb
+39
-0
app/presenters/ci/build_metadata_presenter.rb
app/presenters/ci/build_metadata_presenter.rb
+18
-0
app/serializers/build_details_entity.rb
app/serializers/build_details_entity.rb
+2
-0
app/serializers/build_metadata_entity.rb
app/serializers/build_metadata_entity.rb
+9
-0
app/views/projects/jobs/show.html.haml
app/views/projects/jobs/show.html.haml
+1
-1
app/views/projects/runners/_form.html.haml
app/views/projects/runners/_form.html.haml
+6
-0
app/views/projects/runners/show.html.haml
app/views/projects/runners/show.html.haml
+3
-0
changelogs/unreleased/add-per-runner-job-timeout.yml
changelogs/unreleased/add-per-runner-job-timeout.yml
+5
-0
db/migrate/20180219153455_add_maximum_timeout_to_ci_runners.rb
...grate/20180219153455_add_maximum_timeout_to_ci_runners.rb
+9
-0
db/migrate/20180301010859_create_ci_builds_metadata_table.rb
db/migrate/20180301010859_create_ci_builds_metadata_table.rb
+20
-0
db/schema.rb
db/schema.rb
+13
-0
doc/api/runners.md
doc/api/runners.md
+5
-2
doc/ci/runners/README.md
doc/ci/runners/README.md
+39
-6
doc/user/project/pipelines/settings.md
doc/user/project/pipelines/settings.md
+9
-0
lib/api/entities.rb
lib/api/entities.rb
+2
-1
lib/api/runner.rb
lib/api/runner.rb
+2
-1
lib/api/runners.rb
lib/api/runners.rb
+1
-0
lib/gitlab/ci/build/step.rb
lib/gitlab/ci/build/step.rb
+2
-2
spec/factories/ci/build_metadata.rb
spec/factories/ci/build_metadata.rb
+9
-0
spec/javascripts/jobs/mock_data.js
spec/javascripts/jobs/mock_data.js
+4
-0
spec/javascripts/jobs/sidebar_detail_row_spec.js
spec/javascripts/jobs/sidebar_detail_row_spec.js
+21
-0
spec/javascripts/jobs/sidebar_details_block_spec.js
spec/javascripts/jobs/sidebar_details_block_spec.js
+6
-0
spec/lib/gitlab/ci/build/step_spec.rb
spec/lib/gitlab/ci/build/step_spec.rb
+10
-2
spec/models/ci/build_metadata_spec.rb
spec/models/ci/build_metadata_spec.rb
+61
-0
spec/models/ci/build_spec.rb
spec/models/ci/build_spec.rb
+64
-6
spec/models/concerns/chronic_duration_attribute_spec.rb
spec/models/concerns/chronic_duration_attribute_spec.rb
+115
-0
spec/requests/api/runner_spec.rb
spec/requests/api/runner_spec.rb
+57
-2
spec/requests/api/runners_spec.rb
spec/requests/api/runners_spec.rb
+4
-1
spec/services/ci/retry_build_service_spec.rb
spec/services/ci/retry_build_service_spec.rb
+2
-1
No files found.
app/assets/javascripts/jobs/components/sidebar_detail_row.vue
View file @
b66233f9
...
@@ -11,11 +11,19 @@
...
@@ -11,11 +11,19 @@
type
:
String
,
type
:
String
,
required
:
true
,
required
:
true
,
},
},
helpUrl
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
},
},
computed
:
{
computed
:
{
hasTitle
()
{
hasTitle
()
{
return
this
.
title
.
length
>
0
;
return
this
.
title
.
length
>
0
;
},
},
hasHelpURL
()
{
return
this
.
helpUrl
.
length
>
0
;
},
},
},
};
};
</
script
>
</
script
>
...
@@ -28,5 +36,21 @@
...
@@ -28,5 +36,21 @@
{{
title
}}
:
{{
title
}}
:
</span>
</span>
{{
value
}}
{{
value
}}
<span
v-if=
"hasHelpURL"
class=
"help-button pull-right"
>
<a
:href=
"helpUrl"
target=
"_blank"
rel=
"noopener noreferrer nofollow"
>
<i
class=
"fa fa-question-circle"
aria-hidden=
"true"
></i>
</a>
</span>
</p>
</p>
</
template
>
</
template
>
app/assets/javascripts/jobs/components/sidebar_details_block.vue
View file @
b66233f9
...
@@ -22,6 +22,11 @@
...
@@ -22,6 +22,11 @@
type
:
Boolean
,
type
:
Boolean
,
required
:
true
,
required
:
true
,
},
},
runnerHelpUrl
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
},
},
computed
:
{
computed
:
{
shouldRenderContent
()
{
shouldRenderContent
()
{
...
@@ -39,6 +44,21 @@
...
@@ -39,6 +44,21 @@
runnerId
()
{
runnerId
()
{
return
`#
${
this
.
job
.
runner
.
id
}
`
;
return
`#
${
this
.
job
.
runner
.
id
}
`
;
},
},
hasTimeout
()
{
return
this
.
job
.
metadata
!=
null
&&
this
.
job
.
metadata
.
timeout_human_readable
!==
''
;
},
timeout
()
{
if
(
this
.
job
.
metadata
==
null
)
{
return
''
;
}
let
t
=
this
.
job
.
metadata
.
timeout_human_readable
;
if
(
this
.
job
.
metadata
.
timeout_source
!==
''
)
{
t
+=
` (from
${
this
.
job
.
metadata
.
timeout_source
}
)`
;
}
return
t
;
},
renderBlock
()
{
renderBlock
()
{
return
this
.
job
.
merge_request
||
return
this
.
job
.
merge_request
||
this
.
job
.
duration
||
this
.
job
.
duration
||
...
@@ -114,6 +134,13 @@
...
@@ -114,6 +134,13 @@
title=
"Queued"
title=
"Queued"
:value=
"queued"
:value=
"queued"
/>
/>
<detail-row
class=
"js-job-timeout"
v-if=
"hasTimeout"
title=
"Timeout"
:help-url=
"runnerHelpUrl"
:value=
"timeout"
/>
<detail-row
<detail-row
class=
"js-job-runner"
class=
"js-job-runner"
v-if=
"job.runner"
v-if=
"job.runner"
...
...
app/assets/javascripts/jobs/job_details_bundle.js
View file @
b66233f9
...
@@ -51,6 +51,7 @@ export default () => {
...
@@ -51,6 +51,7 @@ export default () => {
props
:
{
props
:
{
isLoading
:
this
.
mediator
.
state
.
isLoading
,
isLoading
:
this
.
mediator
.
state
.
isLoading
,
job
:
this
.
mediator
.
store
.
state
.
job
,
job
:
this
.
mediator
.
store
.
state
.
job
,
runnerHelpUrl
:
dataset
.
runnerHelpUrl
,
},
},
});
});
},
},
...
...
app/models/ci/build.rb
View file @
b66233f9
...
@@ -27,6 +27,10 @@ module Ci
...
@@ -27,6 +27,10 @@ module Ci
has_one
:job_artifacts_metadata
,
->
{
where
(
file_type:
Ci
::
JobArtifact
.
file_types
[
:metadata
])
},
class_name:
'Ci::JobArtifact'
,
inverse_of: :job
,
foreign_key: :job_id
has_one
:job_artifacts_metadata
,
->
{
where
(
file_type:
Ci
::
JobArtifact
.
file_types
[
:metadata
])
},
class_name:
'Ci::JobArtifact'
,
inverse_of: :job
,
foreign_key: :job_id
has_one
:job_artifacts_trace
,
->
{
where
(
file_type:
Ci
::
JobArtifact
.
file_types
[
:trace
])
},
class_name:
'Ci::JobArtifact'
,
inverse_of: :job
,
foreign_key: :job_id
has_one
:job_artifacts_trace
,
->
{
where
(
file_type:
Ci
::
JobArtifact
.
file_types
[
:trace
])
},
class_name:
'Ci::JobArtifact'
,
inverse_of: :job
,
foreign_key: :job_id
has_one
:metadata
,
class_name:
'Ci::BuildMetadata'
delegate
:timeout
,
to: :metadata
,
prefix:
true
,
allow_nil:
true
# The "environment" field for builds is a String, and is the unexpanded name
# The "environment" field for builds is a String, and is the unexpanded name
def
persisted_environment
def
persisted_environment
@persisted_environment
||=
Environment
.
find_by
(
@persisted_environment
||=
Environment
.
find_by
(
...
@@ -156,6 +160,14 @@ module Ci
...
@@ -156,6 +160,14 @@ module Ci
before_transition
any
=>
[
:running
]
do
|
build
|
before_transition
any
=>
[
:running
]
do
|
build
|
build
.
validates_dependencies!
unless
Feature
.
enabled?
(
'ci_disable_validates_dependencies'
)
build
.
validates_dependencies!
unless
Feature
.
enabled?
(
'ci_disable_validates_dependencies'
)
end
end
before_transition
pending: :running
do
|
build
|
build
.
ensure_metadata
.
update_timeout_state
end
end
def
ensure_metadata
metadata
||
build_metadata
(
project:
project
)
end
end
def
detailed_status
(
current_user
)
def
detailed_status
(
current_user
)
...
@@ -234,10 +246,6 @@ module Ci
...
@@ -234,10 +246,6 @@ module Ci
latest_builds
.
where
(
'stage_idx < ?'
,
stage_idx
)
latest_builds
.
where
(
'stage_idx < ?'
,
stage_idx
)
end
end
def
timeout
project
.
build_timeout
end
def
triggered_by?
(
current_user
)
def
triggered_by?
(
current_user
)
user
==
current_user
user
==
current_user
end
end
...
...
app/models/ci/build_metadata.rb
0 → 100644
View file @
b66233f9
module
Ci
# The purpose of this class is to store Build related data that can be disposed.
# Data that should be persisted forever, should be stored with Ci::Build model.
class
BuildMetadata
<
ActiveRecord
::
Base
extend
Gitlab
::
Ci
::
Model
include
Presentable
include
ChronicDurationAttribute
self
.
table_name
=
'ci_builds_metadata'
belongs_to
:build
,
class_name:
'Ci::Build'
belongs_to
:project
validates
:build
,
presence:
true
validates
:project
,
presence:
true
chronic_duration_attr_reader
:timeout_human_readable
,
:timeout
enum
timeout_source:
{
unknown_timeout_source:
1
,
project_timeout_source:
2
,
runner_timeout_source:
3
}
def
update_timeout_state
return
unless
build
.
runner
.
present?
project_timeout
=
project
&
.
build_timeout
timeout
=
[
project_timeout
,
build
.
runner
.
maximum_timeout
].
compact
.
min
timeout_source
=
timeout
<
project_timeout
?
:runner_timeout_source
:
:project_timeout_source
update
(
timeout:
timeout
,
timeout_source:
timeout_source
)
end
end
end
app/models/ci/runner.rb
View file @
b66233f9
...
@@ -3,13 +3,14 @@ module Ci
...
@@ -3,13 +3,14 @@ module Ci
extend
Gitlab
::
Ci
::
Model
extend
Gitlab
::
Ci
::
Model
include
Gitlab
::
SQL
::
Pattern
include
Gitlab
::
SQL
::
Pattern
include
RedisCacheable
include
RedisCacheable
include
ChronicDurationAttribute
prepend
EE
::
Ci
::
Runner
prepend
EE
::
Ci
::
Runner
RUNNER_QUEUE_EXPIRY_TIME
=
60
.
minutes
RUNNER_QUEUE_EXPIRY_TIME
=
60
.
minutes
ONLINE_CONTACT_TIMEOUT
=
1
.
hour
ONLINE_CONTACT_TIMEOUT
=
1
.
hour
UPDATE_DB_RUNNER_INFO_EVERY
=
40
.
minutes
UPDATE_DB_RUNNER_INFO_EVERY
=
40
.
minutes
AVAILABLE_SCOPES
=
%w[specific shared active paused online]
.
freeze
AVAILABLE_SCOPES
=
%w[specific shared active paused online]
.
freeze
FORM_EDITABLE
=
%i[description tag_list active run_untagged locked access_level]
.
freeze
FORM_EDITABLE
=
%i[description tag_list active run_untagged locked access_level
maximum_timeout_human_readable
]
.
freeze
has_many
:builds
has_many
:builds
has_many
:runner_projects
,
dependent: :destroy
# rubocop:disable Cop/ActiveRecordDependent
has_many
:runner_projects
,
dependent: :destroy
# rubocop:disable Cop/ActiveRecordDependent
...
@@ -52,6 +53,12 @@ module Ci
...
@@ -52,6 +53,12 @@ module Ci
cached_attr_reader
:version
,
:revision
,
:platform
,
:architecture
,
:contacted_at
,
:ip_address
cached_attr_reader
:version
,
:revision
,
:platform
,
:architecture
,
:contacted_at
,
:ip_address
chronic_duration_attr
:maximum_timeout_human_readable
,
:maximum_timeout
validates
:maximum_timeout
,
allow_nil:
true
,
numericality:
{
greater_than_or_equal_to:
600
,
message:
'needs to be at least 10 minutes'
}
# Searches for runners matching the given query.
# Searches for runners matching the given query.
#
#
# This method uses ILIKE on PostgreSQL and LIKE on MySQL.
# This method uses ILIKE on PostgreSQL and LIKE on MySQL.
...
...
app/models/concerns/chronic_duration_attribute.rb
0 → 100644
View file @
b66233f9
module
ChronicDurationAttribute
extend
ActiveSupport
::
Concern
class_methods
do
def
chronic_duration_attr_reader
(
virtual_attribute
,
source_attribute
)
define_method
(
virtual_attribute
)
do
chronic_duration_attributes
[
virtual_attribute
]
||
output_chronic_duration_attribute
(
source_attribute
)
end
end
def
chronic_duration_attr_writer
(
virtual_attribute
,
source_attribute
)
chronic_duration_attr_reader
(
virtual_attribute
,
source_attribute
)
define_method
(
"
#{
virtual_attribute
}
="
)
do
|
value
|
chronic_duration_attributes
[
virtual_attribute
]
=
value
.
presence
||
''
begin
new_value
=
ChronicDuration
.
parse
(
value
).
to_i
if
value
.
present?
assign_attributes
(
source_attribute
=>
new_value
)
rescue
ChronicDuration
::
DurationParseError
# ignore error as it will be caught by validation
end
end
validates
virtual_attribute
,
allow_nil:
true
,
duration:
true
end
alias_method
:chronic_duration_attr
,
:chronic_duration_attr_writer
end
def
chronic_duration_attributes
@chronic_duration_attributes
||=
{}
end
def
output_chronic_duration_attribute
(
source_attribute
)
value
=
attributes
[
source_attribute
.
to_s
]
ChronicDuration
.
output
(
value
,
format: :short
)
if
value
end
end
app/presenters/ci/build_metadata_presenter.rb
0 → 100644
View file @
b66233f9
module
Ci
class
BuildMetadataPresenter
<
Gitlab
::
View
::
Presenter
::
Delegated
TIMEOUT_SOURCES
=
{
unknown_timeout_source:
nil
,
project_timeout_source:
'project'
,
runner_timeout_source:
'runner'
}.
freeze
presents
:metadata
def
timeout_source
return
unless
metadata
.
timeout_source?
TIMEOUT_SOURCES
[
metadata
.
timeout_source
.
to_sym
]
||
metadata
.
timeout_source
end
end
end
app/serializers/build_details_entity.rb
View file @
b66233f9
...
@@ -5,6 +5,8 @@ class BuildDetailsEntity < JobEntity
...
@@ -5,6 +5,8 @@ class BuildDetailsEntity < JobEntity
expose
:runner
,
using:
RunnerEntity
expose
:runner
,
using:
RunnerEntity
expose
:pipeline
,
using:
PipelineEntity
expose
:pipeline
,
using:
PipelineEntity
expose
:metadata
,
using:
BuildMetadataEntity
expose
:erased_by
,
if:
->
(
*
)
{
build
.
erased?
},
using:
UserEntity
expose
:erased_by
,
if:
->
(
*
)
{
build
.
erased?
},
using:
UserEntity
expose
:erase_path
,
if:
->
(
*
)
{
build
.
erasable?
&&
can?
(
current_user
,
:erase_build
,
build
)
}
do
|
build
|
expose
:erase_path
,
if:
->
(
*
)
{
build
.
erasable?
&&
can?
(
current_user
,
:erase_build
,
build
)
}
do
|
build
|
erase_project_job_path
(
project
,
build
)
erase_project_job_path
(
project
,
build
)
...
...
app/serializers/build_metadata_entity.rb
0 → 100644
View file @
b66233f9
class
BuildMetadataEntity
<
Grape
::
Entity
expose
:timeout_human_readable
do
|
metadata
|
metadata
.
timeout_human_readable
unless
metadata
.
timeout
.
nil?
end
expose
:timeout_source
do
|
metadata
|
metadata
.
present
.
timeout_source
end
end
app/views/projects/jobs/show.html.haml
View file @
b66233f9
...
@@ -113,4 +113,4 @@
...
@@ -113,4 +113,4 @@
.js-build-options
{
data:
javascript_build_options
}
.js-build-options
{
data:
javascript_build_options
}
#js-job-details-vue
{
data:
{
endpoint:
project_job_path
(
@project
,
@build
,
format: :json
)
}
}
#js-job-details-vue
{
data:
{
endpoint:
project_job_path
(
@project
,
@build
,
format: :json
)
,
runner_help_url:
help_page_path
(
'ci/runners/README.html'
,
anchor:
'setting-maximum-job-timeout-for-a-runner'
)
}
}
app/views/projects/runners/_form.html.haml
View file @
b66233f9
...
@@ -39,6 +39,12 @@
...
@@ -39,6 +39,12 @@
Description
Description
.col-sm-10
.col-sm-10
=
f
.
text_field
:description
,
class:
'form-control'
=
f
.
text_field
:description
,
class:
'form-control'
.form-group
=
label_tag
:maximum_timeout_human_readable
,
class:
'control-label'
do
Maximum job timeout
.col-sm-10
=
f
.
text_field
:maximum_timeout_human_readable
,
class:
'form-control'
.help-block
This timeout will take precedence when lower than Project-defined timeout
.form-group
.form-group
=
label_tag
:tag_list
,
class:
'control-label'
do
=
label_tag
:tag_list
,
class:
'control-label'
do
Tags
Tags
...
...
app/views/projects/runners/show.html.haml
View file @
b66233f9
...
@@ -55,6 +55,9 @@
...
@@ -55,6 +55,9 @@
%tr
%tr
%td
Description
%td
Description
%td
=
@runner
.
description
%td
=
@runner
.
description
%tr
%td
Maximum job timeout
%td
=
@runner
.
maximum_timeout_human_readable
%tr
%tr
%td
Last contact
%td
Last contact
%td
%td
...
...
changelogs/unreleased/add-per-runner-job-timeout.yml
0 → 100644
View file @
b66233f9
---
title
:
Add per-runner configured job timeout
merge_request
:
17221
author
:
type
:
added
db/migrate/20180219153455_add_maximum_timeout_to_ci_runners.rb
0 → 100644
View file @
b66233f9
class
AddMaximumTimeoutToCiRunners
<
ActiveRecord
::
Migration
include
Gitlab
::
Database
::
MigrationHelpers
DOWNTIME
=
false
def
change
add_column
:ci_runners
,
:maximum_timeout
,
:integer
end
end
db/migrate/20180301010859_create_ci_builds_metadata_table.rb
0 → 100644
View file @
b66233f9
class
CreateCiBuildsMetadataTable
<
ActiveRecord
::
Migration
include
Gitlab
::
Database
::
MigrationHelpers
DOWNTIME
=
false
def
change
create_table
:ci_builds_metadata
do
|
t
|
t
.
integer
:build_id
,
null:
false
t
.
integer
:project_id
,
null:
false
t
.
integer
:timeout
t
.
integer
:timeout_source
,
null:
false
,
default:
1
t
.
foreign_key
:ci_builds
,
column: :build_id
,
on_delete: :cascade
t
.
foreign_key
:projects
,
column: :project_id
,
on_delete: :cascade
t
.
index
:build_id
,
unique:
true
t
.
index
:project_id
end
end
end
db/schema.rb
View file @
b66233f9
...
@@ -411,6 +411,16 @@ ActiveRecord::Schema.define(version: 20180327101207) do
...
@@ -411,6 +411,16 @@ ActiveRecord::Schema.define(version: 20180327101207) do
add_index
"ci_builds"
,
[
"updated_at"
],
name:
"index_ci_builds_on_updated_at"
,
using: :btree
add_index
"ci_builds"
,
[
"updated_at"
],
name:
"index_ci_builds_on_updated_at"
,
using: :btree
add_index
"ci_builds"
,
[
"user_id"
],
name:
"index_ci_builds_on_user_id"
,
using: :btree
add_index
"ci_builds"
,
[
"user_id"
],
name:
"index_ci_builds_on_user_id"
,
using: :btree
create_table
"ci_builds_metadata"
,
force: :cascade
do
|
t
|
t
.
integer
"build_id"
,
null:
false
t
.
integer
"project_id"
,
null:
false
t
.
integer
"timeout"
t
.
integer
"timeout_source"
,
default:
1
,
null:
false
end
add_index
"ci_builds_metadata"
,
[
"build_id"
],
name:
"index_ci_builds_metadata_on_build_id"
,
unique:
true
,
using: :btree
add_index
"ci_builds_metadata"
,
[
"project_id"
],
name:
"index_ci_builds_metadata_on_project_id"
,
using: :btree
create_table
"ci_group_variables"
,
force: :cascade
do
|
t
|
create_table
"ci_group_variables"
,
force: :cascade
do
|
t
|
t
.
string
"key"
,
null:
false
t
.
string
"key"
,
null:
false
t
.
text
"value"
t
.
text
"value"
...
@@ -549,6 +559,7 @@ ActiveRecord::Schema.define(version: 20180327101207) do
...
@@ -549,6 +559,7 @@ ActiveRecord::Schema.define(version: 20180327101207) do
t
.
boolean
"locked"
,
default:
false
,
null:
false
t
.
boolean
"locked"
,
default:
false
,
null:
false
t
.
integer
"access_level"
,
default:
0
,
null:
false
t
.
integer
"access_level"
,
default:
0
,
null:
false
t
.
string
"ip_address"
t
.
string
"ip_address"
t
.
integer
"maximum_timeout"
end
end
add_index
"ci_runners"
,
[
"contacted_at"
],
name:
"index_ci_runners_on_contacted_at"
,
using: :btree
add_index
"ci_runners"
,
[
"contacted_at"
],
name:
"index_ci_runners_on_contacted_at"
,
using: :btree
...
@@ -2605,6 +2616,8 @@ ActiveRecord::Schema.define(version: 20180327101207) do
...
@@ -2605,6 +2616,8 @@ ActiveRecord::Schema.define(version: 20180327101207) do
add_foreign_key
"ci_builds"
,
"ci_pipelines"
,
column:
"auto_canceled_by_id"
,
name:
"fk_a2141b1522"
,
on_delete: :nullify
add_foreign_key
"ci_builds"
,
"ci_pipelines"
,
column:
"auto_canceled_by_id"
,
name:
"fk_a2141b1522"
,
on_delete: :nullify
add_foreign_key
"ci_builds"
,
"ci_stages"
,
column:
"stage_id"
,
name:
"fk_3a9eaa254d"
,
on_delete: :cascade
add_foreign_key
"ci_builds"
,
"ci_stages"
,
column:
"stage_id"
,
name:
"fk_3a9eaa254d"
,
on_delete: :cascade
add_foreign_key
"ci_builds"
,
"projects"
,
name:
"fk_befce0568a"
,
on_delete: :cascade
add_foreign_key
"ci_builds"
,
"projects"
,
name:
"fk_befce0568a"
,
on_delete: :cascade
add_foreign_key
"ci_builds_metadata"
,
"ci_builds"
,
column:
"build_id"
,
on_delete: :cascade
add_foreign_key
"ci_builds_metadata"
,
"projects"
,
on_delete: :cascade
add_foreign_key
"ci_group_variables"
,
"namespaces"
,
column:
"group_id"
,
name:
"fk_33ae4d58d8"
,
on_delete: :cascade
add_foreign_key
"ci_group_variables"
,
"namespaces"
,
column:
"group_id"
,
name:
"fk_33ae4d58d8"
,
on_delete: :cascade
add_foreign_key
"ci_job_artifacts"
,
"ci_builds"
,
column:
"job_id"
,
on_delete: :cascade
add_foreign_key
"ci_job_artifacts"
,
"ci_builds"
,
column:
"job_id"
,
on_delete: :cascade
add_foreign_key
"ci_job_artifacts"
,
"projects"
,
on_delete: :cascade
add_foreign_key
"ci_job_artifacts"
,
"projects"
,
on_delete: :cascade
...
...
doc/api/runners.md
View file @
b66233f9
...
@@ -153,7 +153,8 @@ Example response:
...
@@ -153,7 +153,8 @@ Example response:
"mysql"
"mysql"
],
],
"version"
:
null
,
"version"
:
null
,
"access_level"
:
"ref_protected"
"access_level"
:
"ref_protected"
,
"maximum_timeout"
:
3600
}
}
```
```
...
@@ -174,6 +175,7 @@ PUT /runners/:id
...
@@ -174,6 +175,7 @@ PUT /runners/:id
|
`run_untagged`
| boolean | no | Flag indicating the runner can execute untagged jobs |
|
`run_untagged`
| boolean | no | Flag indicating the runner can execute untagged jobs |
|
`locked`
| boolean | no | Flag indicating the runner is locked |
|
`locked`
| boolean | no | Flag indicating the runner is locked |
|
`access_level`
| string | no | The access_level of the runner;
`not_protected`
or
`ref_protected`
|
|
`access_level`
| string | no | The access_level of the runner;
`not_protected`
or
`ref_protected`
|
|
`maximum_timeout`
| integer | no | Maximum timeout set when this Runner will handle the job |
```
```
curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/runners/6" --form "description=test-1-20150125-test" --form "tag_list=ruby,mysql,tag1,tag2"
curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/runners/6" --form "description=test-1-20150125-test" --form "tag_list=ruby,mysql,tag1,tag2"
...
@@ -211,7 +213,8 @@ Example response:
...
@@ -211,7 +213,8 @@ Example response:
"tag2"
"tag2"
],
],
"version"
:
null
,
"version"
:
null
,
"access_level"
:
"ref_protected"
"access_level"
:
"ref_protected"
,
"maximum_timeout"
:
null
}
}
```
```
...
...
doc/ci/runners/README.md
View file @
b66233f9
...
@@ -231,6 +231,38 @@ To make a Runner pick tagged/untagged jobs:
...
@@ -231,6 +231,38 @@ To make a Runner pick tagged/untagged jobs:
1.
Check the
**Run untagged jobs**
option
1.
Check the
**Run untagged jobs**
option
1.
Click
**Save changes**
for the changes to take effect
1.
Click
**Save changes**
for the changes to take effect
### Setting maximum job timeout for a Runner
For each Runner you can specify a _maximum job timeout_. Such timeout,
if smaller than [project defined timeout], will take the precedence. This
feature can be used to prevent Shared Runner from being appropriated
by a project by setting a ridiculous big timeout (e.g. one week).
When not configured, Runner will not override project timeout.
How this feature will work:
**Example 1 - Runner timeout bigger than project timeout**
1.
You set the _maximum job timeout_ for a Runner to 24 hours
1.
You set the _CI/CD Timeout_ for a project to
**2 hours**
1.
You start a job
1.
The job, if running longer, will be timeouted after
**2 hours**
**Example 2 - Runner timeout not configured**
1.
You remove the _maximum job timeout_ configuration from a Runner
1.
You set the _CI/CD Timeout_ for a project to
**2 hours**
1.
You start a job
1.
The job, if running longer, will be timeouted after
**2 hours**
**Example 3 - Runner timeout smaller than project timeout**
1.
You set the _maximum job timeout_ for a Runner to
**30 minutes**
1.
You set the _CI/CD Timeout_ for a project to 2 hours
1.
You start a job
1.
The job, if running longer, will be timeouted after
**30 minutes**
### Be careful with sensitive information
### Be careful with sensitive information
With some
[
Runner Executors
](
https://docs.gitlab.com/runner/executors/README.html
)
,
With some
[
Runner Executors
](
https://docs.gitlab.com/runner/executors/README.html
)
,
...
@@ -259,12 +291,6 @@ Mentioned briefly earlier, but the following things of Runners can be exploited.
...
@@ -259,12 +291,6 @@ Mentioned briefly earlier, but the following things of Runners can be exploited.
We're always looking for contributions that can mitigate these
We're always looking for contributions that can mitigate these
[
Security Considerations
](
https://docs.gitlab.com/runner/security/
)
.
[
Security Considerations
](
https://docs.gitlab.com/runner/security/
)
.
[
install
]:
http://docs.gitlab.com/runner/install/
[
fifo
]:
https://en.wikipedia.org/wiki/FIFO_(computing_and_electronics)
[
register
]:
http://docs.gitlab.com/runner/register/
[
protected branches
]:
../../user/project/protected_branches.md
[
protected tags
]:
../../user/project/protected_tags.md
## Determining the IP address of a Runner
## Determining the IP address of a Runner
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/17286) in GitLab 10.6.
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/17286) in GitLab 10.6.
...
@@ -297,3 +323,10 @@ You can find the IP address of a Runner for a specific project by:
...
@@ -297,3 +323,10 @@ You can find the IP address of a Runner for a specific project by:
1.
On the details page you should see a row for "IP Address"
1.
On the details page you should see a row for "IP Address"
![
specific Runner IP address
](
img/specific_runner_ip_address.png
)
![
specific Runner IP address
](
img/specific_runner_ip_address.png
)
[
install
]:
http://docs.gitlab.com/runner/install/
[
fifo
]:
https://en.wikipedia.org/wiki/FIFO_(computing_and_electronics)
[
register
]:
http://docs.gitlab.com/runner/register/
[
protected branches
]:
../../user/project/protected_branches.md
[
protected tags
]:
../../user/project/protected_tags.md
[
project defined timeout
]:
../../user/project/pipelines/settings.html#timeout
doc/user/project/pipelines/settings.md
View file @
b66233f9
...
@@ -27,6 +27,13 @@ The default value is 60 minutes. Decrease the time limit if you want to impose
...
@@ -27,6 +27,13 @@ The default value is 60 minutes. Decrease the time limit if you want to impose
a hard limit on your jobs' running time or increase it otherwise. In any case,
a hard limit on your jobs' running time or increase it otherwise. In any case,
if the job surpasses the threshold, it is marked as failed.
if the job surpasses the threshold, it is marked as failed.
### Timeout overriding on Runner level
> - [Introduced][ce-17221] in GitLab 10.6.
Project defined timeout (either specific timeout set by user or the default
60 minutes timeout) may be
[
overridden on Runner level
][
timeout overriding
]
.
## Custom CI config path
## Custom CI config path
> - [Introduced][ce-12509] in GitLab 9.4.
> - [Introduced][ce-12509] in GitLab 9.4.
...
@@ -152,5 +159,7 @@ into your `README.md`:
...
@@ -152,5 +159,7 @@ into your `README.md`:
[
var
]:
../../../ci/yaml/README.md#git-strategy
[
var
]:
../../../ci/yaml/README.md#git-strategy
[
coverage report
]:
#test-coverage-parsing
[
coverage report
]:
#test-coverage-parsing
[
timeout overriding
]:
../../../ci/runners/README.html#setting-maximum-job-timeout-for-a-runner
[
ce-9362
]:
https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9362
[
ce-9362
]:
https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9362
[
ce-12509
]:
https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/12509
[
ce-12509
]:
https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/12509
[
ce-17221
]:
https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/17221
lib/api/entities.rb
View file @
b66233f9
...
@@ -979,6 +979,7 @@ module API
...
@@ -979,6 +979,7 @@ module API
expose
:tag_list
expose
:tag_list
expose
:run_untagged
expose
:run_untagged
expose
:locked
expose
:locked
expose
:maximum_timeout
expose
:access_level
expose
:access_level
expose
:version
,
:revision
,
:platform
,
:architecture
expose
:version
,
:revision
,
:platform
,
:architecture
expose
:contacted_at
expose
:contacted_at
...
@@ -1147,7 +1148,7 @@ module API
...
@@ -1147,7 +1148,7 @@ module API
end
end
class
RunnerInfo
<
Grape
::
Entity
class
RunnerInfo
<
Grape
::
Entity
expose
:timeout
expose
:
metadata_timeout
,
as: :
timeout
end
end
class
Step
<
Grape
::
Entity
class
Step
<
Grape
::
Entity
...
...
lib/api/runner.rb
View file @
b66233f9
...
@@ -14,9 +14,10 @@ module API
...
@@ -14,9 +14,10 @@ module API
optional
:locked
,
type:
Boolean
,
desc:
'Should Runner be locked for current project'
optional
:locked
,
type:
Boolean
,
desc:
'Should Runner be locked for current project'
optional
:run_untagged
,
type:
Boolean
,
desc:
'Should Runner handle untagged jobs'
optional
:run_untagged
,
type:
Boolean
,
desc:
'Should Runner handle untagged jobs'
optional
:tag_list
,
type:
Array
[
String
],
desc:
%q(List of Runner's tags)
optional
:tag_list
,
type:
Array
[
String
],
desc:
%q(List of Runner's tags)
optional
:maximum_timeout
,
type:
Integer
,
desc:
'Maximum timeout set when this Runner will handle the job'
end
end
post
'/'
do
post
'/'
do
attributes
=
attributes_for_keys
([
:description
,
:locked
,
:run_untagged
,
:tag_list
])
attributes
=
attributes_for_keys
([
:description
,
:locked
,
:run_untagged
,
:tag_list
,
:maximum_timeout
])
.
merge
(
get_runner_details_from_request
)
.
merge
(
get_runner_details_from_request
)
runner
=
runner
=
...
...
lib/api/runners.rb
View file @
b66233f9
...
@@ -57,6 +57,7 @@ module API
...
@@ -57,6 +57,7 @@ module API
optional
:locked
,
type:
Boolean
,
desc:
'Flag indicating the runner is locked'
optional
:locked
,
type:
Boolean
,
desc:
'Flag indicating the runner is locked'
optional
:access_level
,
type:
String
,
values:
Ci
::
Runner
.
access_levels
.
keys
,
optional
:access_level
,
type:
String
,
values:
Ci
::
Runner
.
access_levels
.
keys
,
desc:
'The access_level of the runner'
desc:
'The access_level of the runner'
optional
:maximum_timeout
,
type:
Integer
,
desc:
'Maximum timeout set when this Runner will handle the job'
at_least_one_of
:description
,
:active
,
:tag_list
,
:run_untagged
,
:locked
,
:access_level
at_least_one_of
:description
,
:active
,
:tag_list
,
:run_untagged
,
:locked
,
:access_level
end
end
put
':id'
do
put
':id'
do
...
...
lib/gitlab/ci/build/step.rb
View file @
b66233f9
...
@@ -14,7 +14,7 @@ module Gitlab
...
@@ -14,7 +14,7 @@ module Gitlab
self
.
new
(
:script
).
tap
do
|
step
|
self
.
new
(
:script
).
tap
do
|
step
|
step
.
script
=
job
.
options
[
:before_script
].
to_a
+
job
.
options
[
:script
].
to_a
step
.
script
=
job
.
options
[
:before_script
].
to_a
+
job
.
options
[
:script
].
to_a
step
.
script
=
job
.
commands
.
split
(
"
\n
"
)
if
step
.
script
.
empty?
step
.
script
=
job
.
commands
.
split
(
"
\n
"
)
if
step
.
script
.
empty?
step
.
timeout
=
job
.
timeout
step
.
timeout
=
job
.
metadata_
timeout
step
.
when
=
WHEN_ON_SUCCESS
step
.
when
=
WHEN_ON_SUCCESS
end
end
end
end
...
@@ -25,7 +25,7 @@ module Gitlab
...
@@ -25,7 +25,7 @@ module Gitlab
self
.
new
(
:after_script
).
tap
do
|
step
|
self
.
new
(
:after_script
).
tap
do
|
step
|
step
.
script
=
after_script
step
.
script
=
after_script
step
.
timeout
=
job
.
timeout
step
.
timeout
=
job
.
metadata_
timeout
step
.
when
=
WHEN_ALWAYS
step
.
when
=
WHEN_ALWAYS
step
.
allow_failure
=
true
step
.
allow_failure
=
true
end
end
...
...
spec/factories/ci/build_metadata.rb
0 → 100644
View file @
b66233f9
FactoryBot
.
define
do
factory
:ci_build_metadata
,
class:
Ci
::
BuildMetadata
do
build
factory: :ci_build
after
(
:build
)
do
|
build_metadata
,
_
|
build_metadata
.
project
||=
build_metadata
.
build
.
project
end
end
end
spec/javascripts/jobs/mock_data.js
View file @
b66233f9
...
@@ -115,6 +115,10 @@ export default {
...
@@ -115,6 +115,10 @@ export default {
commit_path
:
'
/root/ci-mock/commit/c58647773a6b5faf066d4ad6ff2c9fbba5f180f6
'
,
commit_path
:
'
/root/ci-mock/commit/c58647773a6b5faf066d4ad6ff2c9fbba5f180f6
'
,
},
},
},
},
metadata
:
{
timeout_human_readable
:
'
1m 40s
'
,
timeout_source
:
'
runner
'
,
},
merge_request
:
{
merge_request
:
{
iid
:
2
,
iid
:
2
,
path
:
'
/root/ci-mock/merge_requests/2
'
,
path
:
'
/root/ci-mock/merge_requests/2
'
,
...
...
spec/javascripts/jobs/sidebar_detail_row_spec.js
View file @
b66233f9
...
@@ -37,4 +37,25 @@ describe('Sidebar detail row', () => {
...
@@ -37,4 +37,25 @@ describe('Sidebar detail row', () => {
vm
.
$el
.
textContent
.
replace
(
/
\s
+/g
,
'
'
).
trim
(),
vm
.
$el
.
textContent
.
replace
(
/
\s
+/g
,
'
'
).
trim
(),
).
toEqual
(
'
this is the title: this is the value
'
);
).
toEqual
(
'
this is the title: this is the value
'
);
});
});
describe
(
'
when helpUrl not provided
'
,
()
=>
{
it
(
'
should not render help
'
,
()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.help-button
'
)).
toBeNull
();
});
});
describe
(
'
when helpUrl provided
'
,
()
=>
{
beforeEach
(()
=>
{
vm
=
new
SidebarDetailRow
({
propsData
:
{
helpUrl
:
'
help url
'
,
value
:
'
foo
'
,
},
}).
$mount
();
});
it
(
'
should render help
'
,
()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.help-button a
'
).
getAttribute
(
'
href
'
)).
toEqual
(
'
help url
'
);
});
});
});
});
spec/javascripts/jobs/sidebar_details_block_spec.js
View file @
b66233f9
...
@@ -96,6 +96,12 @@ describe('Sidebar details block', () => {
...
@@ -96,6 +96,12 @@ describe('Sidebar details block', () => {
).
toEqual
(
'
Runner: #1
'
);
).
toEqual
(
'
Runner: #1
'
);
});
});
it
(
'
should render timeout information
'
,
()
=>
{
expect
(
trimWhitespace
(
vm
.
$el
.
querySelector
(
'
.js-job-timeout
'
)),
).
toEqual
(
'
Timeout: 1m 40s (from runner)
'
);
});
it
(
'
should render coverage
'
,
()
=>
{
it
(
'
should render coverage
'
,
()
=>
{
expect
(
expect
(
trimWhitespace
(
vm
.
$el
.
querySelector
(
'
.js-job-coverage
'
)),
trimWhitespace
(
vm
.
$el
.
querySelector
(
'
.js-job-coverage
'
)),
...
...
spec/lib/gitlab/ci/build/step_spec.rb
View file @
b66233f9
...
@@ -5,10 +5,14 @@ describe Gitlab::Ci::Build::Step do
...
@@ -5,10 +5,14 @@ describe Gitlab::Ci::Build::Step do
shared_examples
'has correct script'
do
shared_examples
'has correct script'
do
subject
{
described_class
.
from_commands
(
job
)
}
subject
{
described_class
.
from_commands
(
job
)
}
before
do
job
.
run!
end
it
'fabricates an object'
do
it
'fabricates an object'
do
expect
(
subject
.
name
).
to
eq
(
:script
)
expect
(
subject
.
name
).
to
eq
(
:script
)
expect
(
subject
.
script
).
to
eq
(
script
)
expect
(
subject
.
script
).
to
eq
(
script
)
expect
(
subject
.
timeout
).
to
eq
(
job
.
timeout
)
expect
(
subject
.
timeout
).
to
eq
(
job
.
metadata_
timeout
)
expect
(
subject
.
when
).
to
eq
(
'on_success'
)
expect
(
subject
.
when
).
to
eq
(
'on_success'
)
expect
(
subject
.
allow_failure
).
to
be_falsey
expect
(
subject
.
allow_failure
).
to
be_falsey
end
end
...
@@ -47,6 +51,10 @@ describe Gitlab::Ci::Build::Step do
...
@@ -47,6 +51,10 @@ describe Gitlab::Ci::Build::Step do
subject
{
described_class
.
from_after_script
(
job
)
}
subject
{
described_class
.
from_after_script
(
job
)
}
before
do
job
.
run!
end
context
'when after_script is empty'
do
context
'when after_script is empty'
do
it
'doesn not fabricate an object'
do
it
'doesn not fabricate an object'
do
is_expected
.
to
be_nil
is_expected
.
to
be_nil
...
@@ -59,7 +67,7 @@ describe Gitlab::Ci::Build::Step do
...
@@ -59,7 +67,7 @@ describe Gitlab::Ci::Build::Step do
it
'fabricates an object'
do
it
'fabricates an object'
do
expect
(
subject
.
name
).
to
eq
(
:after_script
)
expect
(
subject
.
name
).
to
eq
(
:after_script
)
expect
(
subject
.
script
).
to
eq
([
'ls -la'
,
'date'
])
expect
(
subject
.
script
).
to
eq
([
'ls -la'
,
'date'
])
expect
(
subject
.
timeout
).
to
eq
(
job
.
timeout
)
expect
(
subject
.
timeout
).
to
eq
(
job
.
metadata_
timeout
)
expect
(
subject
.
when
).
to
eq
(
'always'
)
expect
(
subject
.
when
).
to
eq
(
'always'
)
expect
(
subject
.
allow_failure
).
to
be_truthy
expect
(
subject
.
allow_failure
).
to
be_truthy
end
end
...
...
spec/models/ci/build_metadata_spec.rb
0 → 100644
View file @
b66233f9
require
'spec_helper'
describe
Ci
::
BuildMetadata
do
set
(
:user
)
{
create
(
:user
)
}
set
(
:group
)
{
create
(
:group
,
:access_requestable
)
}
set
(
:project
)
{
create
(
:project
,
:repository
,
group:
group
,
build_timeout:
2000
)
}
set
(
:pipeline
)
do
create
(
:ci_pipeline
,
project:
project
,
sha:
project
.
commit
.
id
,
ref:
project
.
default_branch
,
status:
'success'
)
end
let
(
:build
)
{
create
(
:ci_build
,
pipeline:
pipeline
)
}
let
(
:build_metadata
)
{
create
(
:ci_build_metadata
,
build:
build
)
}
describe
'#update_timeout_state'
do
subject
{
build_metadata
}
context
'when runner is not assigned to the job'
do
it
"doesn't change timeout value"
do
expect
{
subject
.
update_timeout_state
}.
not_to
change
{
subject
.
reload
.
timeout
}
end
it
"doesn't change timeout_source value"
do
expect
{
subject
.
update_timeout_state
}.
not_to
change
{
subject
.
reload
.
timeout_source
}
end
end
context
'when runner is assigned to the job'
do
before
do
build
.
update_attributes
(
runner:
runner
)
end
context
'when runner timeout is lower than project timeout'
do
let
(
:runner
)
{
create
(
:ci_runner
,
maximum_timeout:
1900
)
}
it
'sets runner timeout'
do
expect
{
subject
.
update_timeout_state
}.
to
change
{
subject
.
reload
.
timeout
}.
to
(
1900
)
end
it
'sets runner_timeout_source'
do
expect
{
subject
.
update_timeout_state
}.
to
change
{
subject
.
reload
.
timeout_source
}.
to
(
'runner_timeout_source'
)
end
end
context
'when runner timeout is higher than project timeout'
do
let
(
:runner
)
{
create
(
:ci_runner
,
maximum_timeout:
2100
)
}
it
'sets project timeout'
do
expect
{
subject
.
update_timeout_state
}.
to
change
{
subject
.
reload
.
timeout
}.
to
(
2000
)
end
it
'sets project_timeout_source'
do
expect
{
subject
.
update_timeout_state
}.
to
change
{
subject
.
reload
.
timeout_source
}.
to
(
'project_timeout_source'
)
end
end
end
end
end
spec/models/ci/build_spec.rb
View file @
b66233f9
...
@@ -1290,12 +1290,6 @@ describe Ci::Build do
...
@@ -1290,12 +1290,6 @@ describe Ci::Build do
end
end
describe
'project settings'
do
describe
'project settings'
do
describe
'#timeout'
do
it
'returns project timeout configuration'
do
expect
(
build
.
timeout
).
to
eq
(
project
.
build_timeout
)
end
end
describe
'#allow_git_fetch'
do
describe
'#allow_git_fetch'
do
it
'return project allow_git_fetch configuration'
do
it
'return project allow_git_fetch configuration'
do
expect
(
build
.
allow_git_fetch
).
to
eq
(
project
.
build_allow_git_fetch
)
expect
(
build
.
allow_git_fetch
).
to
eq
(
project
.
build_allow_git_fetch
)
...
@@ -2031,6 +2025,70 @@ describe Ci::Build do
...
@@ -2031,6 +2025,70 @@ describe Ci::Build do
end
end
end
end
describe
'state transition: pending: :running'
do
let
(
:runner
)
{
create
(
:ci_runner
)
}
let
(
:job
)
{
create
(
:ci_build
,
:pending
,
runner:
runner
)
}
before
do
job
.
project
.
update_attribute
(
:build_timeout
,
1800
)
end
def
run_job_without_exception
job
.
run!
rescue
StateMachines
::
InvalidTransition
end
shared_examples
'saves data on transition'
do
it
'saves timeout'
do
expect
{
job
.
run!
}.
to
change
{
job
.
reload
.
ensure_metadata
.
timeout
}.
from
(
nil
).
to
(
expected_timeout
)
end
it
'saves timeout_source'
do
expect
{
job
.
run!
}.
to
change
{
job
.
reload
.
ensure_metadata
.
timeout_source
}.
from
(
'unknown_timeout_source'
).
to
(
expected_timeout_source
)
end
context
'when Ci::BuildMetadata#update_timeout_state fails update'
do
before
do
allow_any_instance_of
(
Ci
::
BuildMetadata
).
to
receive
(
:update_timeout_state
).
and_return
(
false
)
end
it
"doesn't save timeout"
do
expect
{
run_job_without_exception
}.
not_to
change
{
job
.
reload
.
ensure_metadata
.
timeout_source
}
end
it
"doesn't save timeout_source"
do
expect
{
run_job_without_exception
}.
not_to
change
{
job
.
reload
.
ensure_metadata
.
timeout_source
}
end
it
'raises an exception'
do
expect
{
job
.
run!
}.
to
raise_error
(
StateMachines
::
InvalidTransition
)
end
end
end
context
'when runner timeout overrides project timeout'
do
let
(
:expected_timeout
)
{
900
}
let
(
:expected_timeout_source
)
{
'runner_timeout_source'
}
before
do
runner
.
update_attribute
(
:maximum_timeout
,
900
)
end
it_behaves_like
'saves data on transition'
end
context
"when runner timeout doesn't override project timeout"
do
let
(
:expected_timeout
)
{
1800
}
let
(
:expected_timeout_source
)
{
'project_timeout_source'
}
before
do
runner
.
update_attribute
(
:maximum_timeout
,
3600
)
end
it_behaves_like
'saves data on transition'
end
end
describe
'state transition: any => [:running]'
do
describe
'state transition: any => [:running]'
do
shared_examples
'validation is active'
do
shared_examples
'validation is active'
do
context
'when depended job has not been completed yet'
do
context
'when depended job has not been completed yet'
do
...
...
spec/models/concerns/chronic_duration_attribute_spec.rb
0 → 100644
View file @
b66233f9
require
'spec_helper'
shared_examples
'ChronicDurationAttribute reader'
do
it
'contains dynamically created reader method'
do
expect
(
subject
.
class
).
to
be_public_method_defined
(
virtual_field
)
end
it
'outputs chronic duration formatted value'
do
subject
.
send
(
"
#{
source_field
}
="
,
120
)
expect
(
subject
.
send
(
virtual_field
)).
to
eq
(
'2m'
)
end
context
'when value is set to nil'
do
it
'outputs nil'
do
subject
.
send
(
"
#{
source_field
}
="
,
nil
)
expect
(
subject
.
send
(
virtual_field
)).
to
be_nil
end
end
end
shared_examples
'ChronicDurationAttribute writer'
do
it
'contains dynamically created writer method'
do
expect
(
subject
.
class
).
to
be_public_method_defined
(
"
#{
virtual_field
}
="
)
end
before
do
subject
.
send
(
"
#{
virtual_field
}
="
,
'10m'
)
end
it
'parses chronic duration input'
do
expect
(
subject
.
send
(
source_field
)).
to
eq
(
600
)
end
it
'passes validation'
do
expect
(
subject
.
valid?
).
to
be_truthy
end
context
'when negative input is used'
do
before
do
subject
.
send
(
"
#{
source_field
}
="
,
3600
)
end
it
"doesn't raise exception"
do
expect
{
subject
.
send
(
"
#{
virtual_field
}
="
,
'-10m'
)
}.
not_to
raise_error
(
ChronicDuration
::
DurationParseError
)
end
it
"doesn't change value"
do
expect
{
subject
.
send
(
"
#{
virtual_field
}
="
,
'-10m'
)
}.
not_to
change
{
subject
.
send
(
source_field
)
}
end
it
"doesn't pass validation"
do
subject
.
send
(
"
#{
virtual_field
}
="
,
'-10m'
)
expect
(
subject
.
valid?
).
to
be_falsey
expect
(
subject
.
errors
&
.
messages
).
to
include
(
virtual_field
=>
[
'is not a correct duration'
])
end
end
context
'when empty input is used'
do
before
do
subject
.
send
(
"
#{
virtual_field
}
="
,
''
)
end
it
'writes nil'
do
expect
(
subject
.
send
(
source_field
)).
to
be_nil
end
it
'passes validation'
do
expect
(
subject
.
valid?
).
to
be_truthy
end
end
context
'when nil input is used'
do
before
do
subject
.
send
(
"
#{
virtual_field
}
="
,
nil
)
end
it
'writes nil'
do
expect
(
subject
.
send
(
source_field
)).
to
be_nil
end
it
'passes validation'
do
expect
(
subject
.
valid?
).
to
be_truthy
end
it
"doesn't raise exception"
do
expect
{
subject
.
send
(
"
#{
virtual_field
}
="
,
nil
)
}.
not_to
raise_error
(
NoMethodError
)
end
end
end
describe
'ChronicDurationAttribute'
do
let
(
:source_field
)
{
:maximum_timeout
}
let
(
:virtual_field
)
{
:maximum_timeout_human_readable
}
subject
{
Ci
::
Runner
.
new
}
it_behaves_like
'ChronicDurationAttribute reader'
it_behaves_like
'ChronicDurationAttribute writer'
end
describe
'ChronicDurationAttribute - reader'
do
let
(
:source_field
)
{
:timeout
}
let
(
:virtual_field
)
{
:timeout_human_readable
}
subject
{
Ci
::
BuildMetadata
.
new
}
it
"doesn't contain dynamically created writer method"
do
expect
(
subject
.
class
).
not_to
be_public_method_defined
(
"
#{
virtual_field
}
="
)
end
it_behaves_like
'ChronicDurationAttribute reader'
end
spec/requests/api/runner_spec.rb
View file @
b66233f9
...
@@ -109,6 +109,26 @@ describe API::Runner do
...
@@ -109,6 +109,26 @@ describe API::Runner do
end
end
end
end
context
'when maximum job timeout is specified'
do
it
'creates runner'
do
post
api
(
'/runners'
),
token:
registration_token
,
maximum_timeout:
9000
expect
(
response
).
to
have_gitlab_http_status
201
expect
(
Ci
::
Runner
.
first
.
maximum_timeout
).
to
eq
(
9000
)
end
context
'when maximum job timeout is empty'
do
it
'creates runner'
do
post
api
(
'/runners'
),
token:
registration_token
,
maximum_timeout:
''
expect
(
response
).
to
have_gitlab_http_status
201
expect
(
Ci
::
Runner
.
first
.
maximum_timeout
).
to
be_nil
end
end
end
%w(name version revision platform architecture)
.
each
do
|
param
|
%w(name version revision platform architecture)
.
each
do
|
param
|
context
"when info parameter '
#{
param
}
' info is present"
do
context
"when info parameter '
#{
param
}
' info is present"
do
let
(
:value
)
{
"
#{
param
}
_value"
}
let
(
:value
)
{
"
#{
param
}
_value"
}
...
@@ -342,12 +362,12 @@ describe API::Runner do
...
@@ -342,12 +362,12 @@ describe API::Runner do
let
(
:expected_steps
)
do
let
(
:expected_steps
)
do
[{
'name'
=>
'script'
,
[{
'name'
=>
'script'
,
'script'
=>
%w(ls date)
,
'script'
=>
%w(ls date)
,
'timeout'
=>
job
.
timeout
,
'timeout'
=>
job
.
metadata_
timeout
,
'when'
=>
'on_success'
,
'when'
=>
'on_success'
,
'allow_failure'
=>
false
},
'allow_failure'
=>
false
},
{
'name'
=>
'after_script'
,
{
'name'
=>
'after_script'
,
'script'
=>
%w(ls date)
,
'script'
=>
%w(ls date)
,
'timeout'
=>
job
.
timeout
,
'timeout'
=>
job
.
metadata_
timeout
,
'when'
=>
'always'
,
'when'
=>
'always'
,
'allow_failure'
=>
true
}]
'allow_failure'
=>
true
}]
end
end
...
@@ -650,6 +670,41 @@ describe API::Runner do
...
@@ -650,6 +670,41 @@ describe API::Runner do
end
end
end
end
end
end
describe
'timeout support'
do
context
'when project specifies job timeout'
do
let
(
:project
)
{
create
(
:project
,
shared_runners_enabled:
false
,
build_timeout:
1234
)
}
it
'contains info about timeout taken from project'
do
request_job
expect
(
response
).
to
have_gitlab_http_status
(
201
)
expect
(
json_response
[
'runner_info'
]).
to
include
({
'timeout'
=>
1234
})
end
context
'when runner specifies lower timeout'
do
let
(
:runner
)
{
create
(
:ci_runner
,
maximum_timeout:
1000
)
}
it
'contains info about timeout overridden by runner'
do
request_job
expect
(
response
).
to
have_gitlab_http_status
(
201
)
expect
(
json_response
[
'runner_info'
]).
to
include
({
'timeout'
=>
1000
})
end
end
context
'when runner specifies bigger timeout'
do
let
(
:runner
)
{
create
(
:ci_runner
,
maximum_timeout:
2000
)
}
it
'contains info about timeout not overridden by runner'
do
request_job
expect
(
response
).
to
have_gitlab_http_status
(
201
)
expect
(
json_response
[
'runner_info'
]).
to
include
({
'timeout'
=>
1234
})
end
end
end
end
end
end
def
request_job
(
token
=
runner
.
token
,
**
params
)
def
request_job
(
token
=
runner
.
token
,
**
params
)
...
...
spec/requests/api/runners_spec.rb
View file @
b66233f9
...
@@ -123,6 +123,7 @@ describe API::Runners do
...
@@ -123,6 +123,7 @@ describe API::Runners do
expect
(
response
).
to
have_gitlab_http_status
(
200
)
expect
(
response
).
to
have_gitlab_http_status
(
200
)
expect
(
json_response
[
'description'
]).
to
eq
(
shared_runner
.
description
)
expect
(
json_response
[
'description'
]).
to
eq
(
shared_runner
.
description
)
expect
(
json_response
[
'maximum_timeout'
]).
to
be_nil
end
end
end
end
...
@@ -192,7 +193,8 @@ describe API::Runners do
...
@@ -192,7 +193,8 @@ describe API::Runners do
tag_list:
[
'ruby2.1'
,
'pgsql'
,
'mysql'
],
tag_list:
[
'ruby2.1'
,
'pgsql'
,
'mysql'
],
run_untagged:
'false'
,
run_untagged:
'false'
,
locked:
'true'
,
locked:
'true'
,
access_level:
'ref_protected'
)
access_level:
'ref_protected'
,
maximum_timeout:
1234
)
shared_runner
.
reload
shared_runner
.
reload
expect
(
response
).
to
have_gitlab_http_status
(
200
)
expect
(
response
).
to
have_gitlab_http_status
(
200
)
...
@@ -204,6 +206,7 @@ describe API::Runners do
...
@@ -204,6 +206,7 @@ describe API::Runners do
expect
(
shared_runner
.
ref_protected?
).
to
be_truthy
expect
(
shared_runner
.
ref_protected?
).
to
be_truthy
expect
(
shared_runner
.
ensure_runner_queue_value
)
expect
(
shared_runner
.
ensure_runner_queue_value
)
.
not_to
eq
(
runner_queue_value
)
.
not_to
eq
(
runner_queue_value
)
expect
(
shared_runner
.
maximum_timeout
).
to
eq
(
1234
)
end
end
end
end
...
...
spec/services/ci/retry_build_service_spec.rb
View file @
b66233f9
...
@@ -29,7 +29,8 @@ describe Ci::RetryBuildService do
...
@@ -29,7 +29,8 @@ describe Ci::RetryBuildService do
commit_id deployments erased_by_id last_deployment project_id
commit_id deployments erased_by_id last_deployment project_id
runner_id tag_taggings taggings tags trigger_request_id
runner_id tag_taggings taggings tags trigger_request_id
user_id auto_canceled_by_id retried failure_reason
user_id auto_canceled_by_id retried failure_reason
sourced_pipelines artifacts_file_store artifacts_metadata_store]
.
freeze
# EE
sourced_pipelines artifacts_file_store artifacts_metadata_store
metadata]
.
freeze
# EE
shared_examples
'build duplication'
do
shared_examples
'build duplication'
do
let
(
:another_pipeline
)
{
create
(
:ci_empty_pipeline
,
project:
project
)
}
let
(
:another_pipeline
)
{
create
(
:ci_empty_pipeline
,
project:
project
)
}
...
...
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