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
adaee22d
Commit
adaee22d
authored
Mar 23, 2022
by
Laura Montemayor
Committed by
Fabio Pitino
Mar 23, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Removes http_status from ServiceResponse
* Updates one more instance of RetryBuild
parent
05ceec73
Changes
30
Hide whitespace changes
Inline
Side-by-side
Showing
30 changed files
with
375 additions
and
196 deletions
+375
-196
app/controllers/projects/jobs_controller.rb
app/controllers/projects/jobs_controller.rb
+6
-3
app/controllers/projects/web_ide_terminals_controller.rb
app/controllers/projects/web_ide_terminals_controller.rb
+6
-4
app/graphql/mutations/ci/job/retry.rb
app/graphql/mutations/ci/job/retry.rb
+13
-5
app/models/ci/bridge.rb
app/models/ci/bridge.rb
+4
-4
app/models/ci/build.rb
app/models/ci/build.rb
+15
-15
app/models/ci/processable.rb
app/models/ci/processable.rb
+6
-0
app/services/ci/play_build_service.rb
app/services/ci/play_build_service.rb
+1
-4
app/services/ci/retry_job_service.rb
app/services/ci/retry_job_service.rb
+94
-0
app/services/ci/retry_pipeline_service.rb
app/services/ci/retry_pipeline_service.rb
+1
-1
ee/app/models/ee/ci/build.rb
ee/app/models/ee/ci/build.rb
+13
-0
ee/app/services/deployments/auto_rollback_service.rb
ee/app/services/deployments/auto_rollback_service.rb
+8
-3
ee/app/services/ee/ci/retry_job_service.rb
ee/app/services/ee/ci/retry_job_service.rb
+1
-15
ee/spec/models/ci/build_spec.rb
ee/spec/models/ci/build_spec.rb
+6
-0
ee/spec/services/ci/play_build_service_spec.rb
ee/spec/services/ci/play_build_service_spec.rb
+3
-1
ee/spec/services/ci/retry_job_service_spec.rb
ee/spec/services/ci/retry_job_service_spec.rb
+7
-5
ee/spec/services/deployments/auto_rollback_service_spec.rb
ee/spec/services/deployments/auto_rollback_service_spec.rb
+13
-1
ee/spec/support/shared_examples/services/build_execute_shared_examples.rb
...shared_examples/services/build_execute_shared_examples.rb
+3
-6
lib/api/ci/jobs.rb
lib/api/ci/jobs.rb
+6
-3
spec/controllers/projects/jobs_controller_spec.rb
spec/controllers/projects/jobs_controller_spec.rb
+1
-1
spec/models/ci/bridge_spec.rb
spec/models/ci/bridge_spec.rb
+6
-0
spec/models/ci/build_dependencies_spec.rb
spec/models/ci/build_dependencies_spec.rb
+2
-2
spec/models/ci/build_spec.rb
spec/models/ci/build_spec.rb
+6
-101
spec/models/ci/pipeline_spec.rb
spec/models/ci/pipeline_spec.rb
+5
-6
spec/models/ci/processable_spec.rb
spec/models/ci/processable_spec.rb
+94
-0
spec/requests/api/ci/jobs_spec.rb
spec/requests/api/ci/jobs_spec.rb
+9
-0
spec/requests/api/graphql/mutations/ci/job_retry_spec.rb
spec/requests/api/graphql/mutations/ci/job_retry_spec.rb
+17
-3
spec/services/ci/after_requeue_job_service_spec.rb
spec/services/ci/after_requeue_job_service_spec.rb
+2
-2
spec/services/ci/pipeline_processing/atomic_processing_service_spec.rb
.../ci/pipeline_processing/atomic_processing_service_spec.rb
+3
-3
spec/services/ci/retry_job_service_spec.rb
spec/services/ci/retry_job_service_spec.rb
+23
-7
spec/services/ci/retry_pipeline_service_spec.rb
spec/services/ci/retry_pipeline_service_spec.rb
+1
-1
No files found.
app/controllers/projects/jobs_controller.rb
View file @
adaee22d
...
...
@@ -78,10 +78,13 @@ class Projects::JobsController < Projects::ApplicationController
end
def
retry
re
turn
respond_422
unless
@build
.
retryable?
re
sponse
=
Ci
::
RetryJobService
.
new
(
project
,
current_user
).
execute
(
@build
)
build
=
Ci
::
Build
.
retry
(
@build
,
current_user
)
redirect_to
build_path
(
build
)
if
response
.
success?
redirect_to
build_path
(
response
[
:job
])
else
respond_422
end
end
def
play
...
...
app/controllers/projects/web_ide_terminals_controller.rb
View file @
adaee22d
...
...
@@ -57,11 +57,13 @@ class Projects::WebIdeTerminalsController < Projects::ApplicationController
end
def
retry
re
turn
respond_422
unless
build
.
retryable?
re
sponse
=
Ci
::
RetryJobService
.
new
(
build
.
project
,
current_user
).
execute
(
build
)
new_build
=
Ci
::
Build
.
retry
(
build
,
current_user
)
render_terminal
(
new_build
)
if
response
.
success?
render_terminal
(
response
[
:job
])
else
respond_422
end
end
private
...
...
app/graphql/mutations/ci/job/retry.rb
View file @
adaee22d
...
...
@@ -17,11 +17,19 @@ module Mutations
job
=
authorized_find!
(
id:
id
)
project
=
job
.
project
::
Ci
::
RetryBuildService
.
new
(
project
,
current_user
).
execute
(
job
)
{
job:
job
,
errors:
errors_on_object
(
job
)
}
response
=
::
Ci
::
RetryJobService
.
new
(
project
,
current_user
).
execute
(
job
)
if
response
.
success?
{
job:
response
[
:job
],
errors:
[]
}
else
{
job:
nil
,
errors:
[
response
.
message
]
}
end
end
end
end
...
...
app/models/ci/bridge.rb
View file @
adaee22d
...
...
@@ -57,10 +57,6 @@ module Ci
end
end
def
self
.
retry
(
bridge
,
current_user
)
raise
NotImplementedError
end
def
self
.
with_preloads
preload
(
:metadata
,
...
...
@@ -69,6 +65,10 @@ module Ci
)
end
def
retryable?
false
end
def
inherit_status_from_downstream!
(
pipeline
)
case
pipeline
.
status
when
'success'
...
...
app/models/ci/build.rb
View file @
adaee22d
...
...
@@ -218,17 +218,21 @@ module Ci
pending
.
unstarted
.
order
(
'created_at ASC'
).
first
end
def
retry
(
build
,
current_user
)
# rubocop: disable CodeReuse/ServiceClass
Ci
::
RetryBuildService
.
new
(
build
.
project
,
current_user
)
.
execute
(
build
)
# rubocop: enable CodeReuse/ServiceClass
end
def
with_preloads
preload
(
:job_artifacts_archive
,
:job_artifacts
,
:tags
,
project:
[
:namespace
])
end
def
extra_accessors
[]
end
def
clone_accessors
%i[pipeline project ref tag options name
allow_failure stage stage_id stage_idx trigger_request
yaml_variables when environment coverage_regex
description tag_list protected needs_attributes
job_variables_attributes resource_group scheduling_type]
.
freeze
end
end
state_machine
:status
do
...
...
@@ -351,7 +355,9 @@ module Ci
if
build
.
auto_retry_allowed?
begin
Ci
::
Build
.
retry
(
build
,
build
.
user
)
# rubocop: disable CodeReuse/ServiceClass
Ci
::
RetryJobService
.
new
(
build
.
project
,
build
.
user
).
execute
(
build
)
# rubocop: enable CodeReuse/ServiceClass
rescue
Gitlab
::
Access
::
AccessDeniedError
=>
ex
Gitlab
::
AppLogger
.
error
"Unable to auto-retry job
#{
build
.
id
}
:
#{
ex
}
"
end
...
...
@@ -472,12 +478,6 @@ module Ci
active?
||
created?
end
def
retryable?
return
false
if
retried?
||
archived?
||
deployment_rejected?
success?
||
failed?
||
canceled?
end
def
retries_count
pipeline
.
builds
.
retried
.
where
(
name:
self
.
name
).
count
end
...
...
app/models/ci/processable.rb
View file @
adaee22d
...
...
@@ -101,6 +101,12 @@ module Ci
:merge_train_pipeline?
,
to: :pipeline
def
retryable?
return
false
if
retried?
||
archived?
||
deployment_rejected?
success?
||
failed?
||
canceled?
end
def
aggregated_needs_names
read_attribute
(
:aggregated_needs_names
)
end
...
...
app/services/ci/play_build_service.rb
View file @
adaee22d
...
...
@@ -14,10 +14,7 @@ module Ci
AfterRequeueJobService
.
new
(
project
,
current_user
).
execute
(
build
)
end
else
# Retrying in Ci::PlayBuildService is a legacy process that should be removed.
# Instead, callers should explicitly execute Ci::RetryBuildService.
# See https://gitlab.com/gitlab-org/gitlab/-/issues/347493.
build
.
retryable?
?
Ci
::
Build
.
retry
(
build
,
current_user
)
:
build
Ci
::
RetryJobService
.
new
(
project
,
current_user
).
execute
(
build
)[
:job
]
end
end
...
...
app/services/ci/retry_
build
_service.rb
→
app/services/ci/retry_
job
_service.rb
View file @
adaee22d
# frozen_string_literal: true
module
Ci
class
Retry
Build
Service
<
::
BaseService
class
Retry
Job
Service
<
::
BaseService
include
Gitlab
::
Utils
::
StrongMemoize
def
self
.
clone_accessors
%i[pipeline project ref tag options name
allow_failure stage stage_id stage_idx trigger_request
yaml_variables when environment coverage_regex
description tag_list protected needs_attributes
job_variables_attributes resource_group scheduling_type]
.
freeze
end
def
self
.
extra_accessors
[]
end
def
execute
(
build
)
build
.
ensure_scheduling_type!
clone
!
(
build
).
tap
do
|
new_build
|
check_assignable_runners!
(
new_build
)
next
if
new_build
.
failed?
Gitlab
::
OptimisticLocking
.
retry_lock
(
new_build
,
name:
'retry_build'
,
&
:enqueue
)
AfterRequeueJobService
.
new
(
project
,
current_user
).
execute
(
build
)
def
execute
(
job
)
if
job
.
retryable?
job
.
ensure_scheduling_type!
new_job
=
retry_job
(
job
)
ServiceResponse
.
success
(
payload:
{
job:
new_job
})
else
ServiceResponse
.
error
(
message:
'Job cannot be retried'
,
payload:
{
job:
job
,
reason: :not_retryable
}
)
end
end
# rubocop: disable CodeReuse/ActiveRecord
def
clone!
(
build
)
# Cloning a
build
requires a strict type check to ensure
def
clone!
(
job
)
# Cloning a
job
requires a strict type check to ensure
# the attributes being used for the clone are taken straight
# from the model and not overridden by other abstractions.
raise
TypeError
unless
build
.
instance_of?
(
Ci
::
Build
)
raise
TypeError
unless
job
.
instance_of?
(
Ci
::
Build
)
check_access!
(
build
)
check_access!
(
job
)
new_
build
=
clone_build
(
build
)
new_
job
=
clone_job
(
job
)
new_
build
.
run_after_commit
do
::
Ci
::
CopyCrossDatabaseAssociationsService
.
new
.
execute
(
build
,
new_build
)
new_
job
.
run_after_commit
do
::
Ci
::
CopyCrossDatabaseAssociationsService
.
new
.
execute
(
job
,
new_job
)
::
Deployments
::
CreateForBuildService
.
new
.
execute
(
new_
build
)
::
Deployments
::
CreateForBuildService
.
new
.
execute
(
new_
job
)
::
MergeRequests
::
AddTodoWhenBuildFailsService
.
new
(
project:
project
)
.
close
(
new_
build
)
.
close
(
new_
job
)
end
::
Ci
::
Pipelines
::
AddJobService
.
new
(
build
.
pipeline
).
execute!
(
new_build
)
do
|
job
|
::
Ci
::
Pipelines
::
AddJobService
.
new
(
job
.
pipeline
).
execute!
(
new_job
)
do
|
processable
|
BulkInsertableAssociations
.
with_bulk_insert
do
job
.
save!
processable
.
save!
end
end
build
.
reset
# refresh the data to get new values of `retried` and `processed`.
job
.
reset
# refresh the data to get new values of `retried` and `processed`.
new_
build
new_
job
end
# rubocop: enable CodeReuse/ActiveRecord
private
def
check_access!
(
build
)
unless
can?
(
current_user
,
:update_build
,
build
)
def
retry_job
(
job
)
clone
!
(
job
).
tap
do
|
new_job
|
check_assignable_runners!
(
new_job
)
next
if
new_job
.
failed?
Gitlab
::
OptimisticLocking
.
retry_lock
(
new_job
,
name:
'retry_build'
,
&
:enqueue
)
AfterRequeueJobService
.
new
(
project
,
current_user
).
execute
(
job
)
end
end
def
check_access!
(
job
)
unless
can?
(
current_user
,
:update_build
,
job
)
raise
Gitlab
::
Access
::
AccessDeniedError
,
'403 Forbidden'
end
end
def
check_assignable_runners!
(
build
);
end
def
check_assignable_runners!
(
job
);
end
def
clone_
build
(
build
)
project
.
builds
.
new
(
build_attributes
(
build
))
def
clone_
job
(
job
)
project
.
builds
.
new
(
job_attributes
(
job
))
end
def
build_attributes
(
build
)
attributes
=
self
.
class
.
clone_accessors
.
to_h
do
|
attribute
|
[
attribute
,
build
.
public_send
(
attribute
)]
# rubocop:disable GitlabSecurity/PublicSend
def
job_attributes
(
job
)
attributes
=
job
.
class
.
clone_accessors
.
to_h
do
|
attribute
|
[
attribute
,
job
.
public_send
(
attribute
)]
# rubocop:disable GitlabSecurity/PublicSend
end
if
build
.
persisted_environment
.
present?
if
job
.
persisted_environment
.
present?
attributes
[
:metadata_attributes
]
||=
{}
attributes
[
:metadata_attributes
][
:expanded_environment_name
]
=
build
.
expanded_environment_name
attributes
[
:metadata_attributes
][
:expanded_environment_name
]
=
job
.
expanded_environment_name
end
attributes
[
:user
]
=
current_user
...
...
@@ -91,4 +91,4 @@ module Ci
end
end
Ci
::
Retry
BuildService
.
prepend_mod_with
(
'Ci::RetryBuild
Service'
)
Ci
::
Retry
JobService
.
prepend_mod_with
(
'Ci::RetryJob
Service'
)
app/services/ci/retry_pipeline_service.rb
View file @
adaee22d
...
...
@@ -13,7 +13,7 @@ module Ci
builds_relation
(
pipeline
).
find_each
do
|
build
|
next
unless
can_be_retried?
(
build
)
Ci
::
Retry
Build
Service
.
new
(
project
,
current_user
).
clone!
(
build
)
Ci
::
Retry
Job
Service
.
new
(
project
,
current_user
).
clone!
(
build
)
end
pipeline
.
processables
.
latest
.
skipped
.
find_each
do
|
skipped
|
...
...
ee/app/models/ee/ci/build.rb
View file @
adaee22d
...
...
@@ -58,6 +58,19 @@ module EE
end
end
class_methods
do
extend
::
Gitlab
::
Utils
::
Override
override
:clone_accessors
def
clone_accessors
(
super
+
extra_accessors
).
freeze
end
def
extra_accessors
(
super
+
%i[secrets]
).
freeze
end
end
override
:variables
def
variables
strong_memoize
(
:variables
)
do
...
...
ee/app/services/deployments/auto_rollback_service.rb
View file @
adaee22d
...
...
@@ -9,8 +9,13 @@ module Deployments
deployment
=
find_rollback_target
(
environment
)
return
error
(
'Failed to find a rollback target.'
)
unless
deployment
new_deployment
=
rollback_to
(
deployment
)
success
(
deployment:
new_deployment
)
response
=
rollback_to
(
deployment
)
if
response
.
success?
success
(
deployment:
response
[
:job
].
deployment
)
else
error
(
response
.
message
)
end
end
private
...
...
@@ -48,7 +53,7 @@ module Deployments
end
def
rollback_to
(
deployment
)
Ci
::
Build
.
retry
(
deployment
.
deployable
,
deployment
.
deployed_by
).
deployment
Ci
::
RetryJobService
.
new
(
deployment
.
deployable
.
project
,
deployment
.
deployed_by
).
execute
(
deployment
.
deployable
)
end
end
end
ee/app/services/ee/ci/retry_
build
_service.rb
→
ee/app/services/ee/ci/retry_
job
_service.rb
View file @
adaee22d
...
...
@@ -2,24 +2,10 @@
module
EE
module
Ci
module
Retry
Build
Service
module
Retry
Job
Service
extend
ActiveSupport
::
Concern
extend
::
Gitlab
::
Utils
::
Override
class_methods
do
extend
::
Gitlab
::
Utils
::
Override
override
:clone_accessors
def
clone_accessors
(
super
+
extra_accessors
).
freeze
end
override
:extra_accessors
def
extra_accessors
%i[secrets]
.
freeze
end
end
private
override
:check_access!
...
...
ee/spec/models/ci/build_spec.rb
View file @
adaee22d
...
...
@@ -40,6 +40,12 @@ RSpec.describe Ci::Build, :saas do
end
end
describe
'extra_accessors'
do
it
'includes the cloneable extra accessors'
do
expect
(
::
Ci
::
Build
.
extra_accessors
).
to
eq
([
:secrets
])
end
end
describe
'associations'
do
it
{
is_expected
.
to
have_many
(
:security_scans
).
class_name
(
'Security::Scan'
)
}
it
{
is_expected
.
to
have_one
(
:dast_site_profiles_build
).
class_name
(
'Dast::SiteProfilesBuild'
).
with_foreign_key
(
:ci_build_id
)
}
...
...
ee/spec/services/ci/play_build_service_spec.rb
View file @
adaee22d
...
...
@@ -3,7 +3,9 @@
require
'spec_helper'
RSpec
.
describe
Ci
::
PlayBuildService
,
'#execute'
do
it_behaves_like
'restricts access to protected environments'
it_behaves_like
'restricts access to protected environments'
do
subject
{
service
.
execute
(
build
)
}
end
it_behaves_like
'prevents playing job when credit card is required'
do
let
(
:user
)
{
create
(
:user
,
maintainer_projects:
[
project
])
}
...
...
ee/spec/services/ci/retry_
build
_service_spec.rb
→
ee/spec/services/ci/retry_
job
_service_spec.rb
View file @
adaee22d
# frozen_string_literal: true
require
'spec_helper'
RSpec
.
describe
Ci
::
Retry
Build
Service
do
RSpec
.
describe
Ci
::
Retry
Job
Service
do
let_it_be
(
:user
)
{
create
(
:user
)
}
let
(
:pipeline
)
{
create
(
:ci_pipeline
,
project:
project
)
}
let
(
:build
)
{
create
(
:ci_build
,
pipeline:
pipeline
)
}
let
(
:build
)
{
create
(
:ci_build
,
:success
,
pipeline:
pipeline
)
}
subject
(
:service
)
{
described_class
.
new
(
project
,
user
)
}
...
...
@@ -15,14 +15,16 @@ RSpec.describe Ci::RetryBuildService do
project
.
add_developer
(
user
)
end
it_behaves_like
'restricts access to protected environments'
it_behaves_like
'restricts access to protected environments'
do
subject
{
service
.
execute
(
build
)[
:job
]
}
end
describe
'#clone!'
do
context
'when user has ability to execute build'
do
let_it_be
(
:namespace
)
{
create
(
:namespace
)
}
let_it_be
(
:project
)
{
create
(
:project
,
namespace:
namespace
,
creator:
user
)
}
let
(
:new_build
)
{
service
.
clone!
(
build
)}
let
(
:new_build
)
{
service
.
clone!
(
build
)
}
context
'dast'
do
let_it_be
(
:dast_site_profile
)
{
create
(
:dast_site_profile
,
project:
project
)
}
...
...
@@ -127,7 +129,7 @@ RSpec.describe Ci::RetryBuildService do
end
describe
'#execute'
do
let
(
:new_build
)
{
service
.
execute
(
build
)
}
let
(
:new_build
)
{
service
.
execute
(
build
)
[
:job
]
}
context
'when the CI quota is exceeded'
do
let_it_be
(
:namespace
)
{
create
(
:namespace
,
:with_used_build_minutes_limit
)
}
...
...
ee/spec/services/deployments/auto_rollback_service_spec.rb
View file @
adaee22d
...
...
@@ -30,13 +30,25 @@ RSpec.describe Deployments::AutoRollbackService, :clean_gitlab_redis_rate_limiti
commits
.
reverse_each
{
|
commit
|
create_deployment
(
commit
.
id
)
}
end
it
'successfully roll back a deployment'
do
it
'successfully roll
s
back a deployment'
do
expect
{
subject
}.
to
change
{
Deployment
.
count
}.
by
(
1
)
expect
(
subject
[
:status
]).
to
eq
(
:success
)
expect
(
subject
[
:deployment
].
sha
).
to
eq
(
commits
[
1
].
id
)
end
context
'when RetryJobService fails to retry the deployable'
do
before
do
allow_next_instance_of
(
::
Ci
::
RetryJobService
)
do
|
service
|
allow
(
service
).
to
receive
(
:execute
).
and_return
(
ServiceResponse
.
error
(
message:
message
))
end
end
it_behaves_like
'rollback failure'
do
let
(
:message
)
{
'Job cannot be retried.'
}
end
end
context
'when auto_rollback checkbox is disabled on the project'
do
before
do
environment
.
project
.
auto_rollback_enabled
=
false
...
...
ee/spec/support/shared_examples/services/build_execute_shared_examples.rb
View file @
adaee22d
...
...
@@ -6,7 +6,7 @@ RSpec.shared_examples 'restricts access to protected environments' do |developer
let
(
:project
)
{
create
(
:project
,
:repository
)
}
let
(
:pipeline
)
{
create
(
:ci_pipeline
,
project:
project
)
}
let
(
:environment
)
{
create
(
:environment
,
project:
project
,
name:
'production'
)
}
let
(
:build
)
{
create
(
:ci_build
,
:
created
,
pipeline:
pipeline
,
environment:
environment
.
name
,
project:
project
)
}
let
(
:build
)
{
create
(
:ci_build
,
:
success
,
pipeline:
pipeline
,
environment:
environment
.
name
,
project:
project
)
}
let
(
:protected_environment
)
{
create
(
:protected_environment
,
name:
environment
.
name
,
project:
project
)
}
let
(
:service
)
{
described_class
.
new
(
project
,
user
)
}
...
...
@@ -19,8 +19,7 @@ RSpec.shared_examples 'restricts access to protected environments' do |developer
context
'when user does not have access to the environment'
do
it
'raises Gitlab::Access::DeniedError'
do
expect
{
service
.
execute
(
build
)
}
.
to
raise_error
Gitlab
::
Access
::
AccessDeniedError
expect
{
subject
}.
to
raise_error
Gitlab
::
Access
::
AccessDeniedError
end
end
...
...
@@ -30,9 +29,7 @@ RSpec.shared_examples 'restricts access to protected environments' do |developer
end
it
'enqueues the build'
do
build_enqueued
=
service
.
execute
(
build
)
expect
(
build_enqueued
).
to
be_pending
is_expected
.
to
be_pending
end
end
end
...
...
lib/api/ci/jobs.rb
View file @
adaee22d
...
...
@@ -114,11 +114,14 @@ module API
build
=
find_build!
(
params
[
:job_id
])
authorize!
(
:update_build
,
build
)
break
forbidden!
(
'Job is not retryable'
)
unless
build
.
retryable?
build
=
::
Ci
::
Build
.
retry
(
build
,
current_user
)
response
=
::
Ci
::
RetryJobService
.
new
(
@project
,
current_user
).
execute
(
build
)
present
build
,
with:
Entities
::
Ci
::
Job
if
response
.
success?
present
response
[
:job
],
with:
Entities
::
Ci
::
Job
else
forbidden!
(
'Job is not retryable'
)
end
end
desc
'Erase job (remove artifacts and the trace)'
do
...
...
spec/controllers/projects/jobs_controller_spec.rb
View file @
adaee22d
...
...
@@ -796,7 +796,7 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do
retried_build
=
Ci
::
Build
.
last
Ci
::
RetryBuildService
.
clone_accessors
.
each
do
|
accessor
|
Ci
::
Build
.
clone_accessors
.
each
do
|
accessor
|
expect
(
job
.
read_attribute
(
accessor
))
.
to
eq
(
retried_build
.
read_attribute
(
accessor
)),
"Mismatched attribute on
\"
#{
accessor
}
\"
. "
\
...
...
spec/models/ci/bridge_spec.rb
View file @
adaee22d
...
...
@@ -30,6 +30,12 @@ RSpec.describe Ci::Bridge do
expect
(
bridge
).
to
have_one
(
:downstream_pipeline
)
end
describe
'#retryable?'
do
it
'returns false'
do
expect
(
bridge
.
retryable?
).
to
eq
(
false
)
end
end
describe
'#tags'
do
it
'only has a bridge tag'
do
expect
(
bridge
.
tags
).
to
eq
[
:bridge
]
...
...
spec/models/ci/build_dependencies_spec.rb
View file @
adaee22d
...
...
@@ -14,7 +14,7 @@ RSpec.describe Ci::BuildDependencies do
end
let!
(
:build
)
{
create
(
:ci_build
,
pipeline:
pipeline
,
name:
'build'
,
stage_idx:
0
,
stage:
'build'
)
}
let!
(
:rspec_test
)
{
create
(
:ci_build
,
pipeline:
pipeline
,
name:
'rspec'
,
stage_idx:
1
,
stage:
'test'
)
}
let!
(
:rspec_test
)
{
create
(
:ci_build
,
:success
,
pipeline:
pipeline
,
name:
'rspec'
,
stage_idx:
1
,
stage:
'test'
)
}
let!
(
:rubocop_test
)
{
create
(
:ci_build
,
pipeline:
pipeline
,
name:
'rubocop'
,
stage_idx:
1
,
stage:
'test'
)
}
let!
(
:staging
)
{
create
(
:ci_build
,
pipeline:
pipeline
,
name:
'staging'
,
stage_idx:
2
,
stage:
'deploy'
)
}
...
...
@@ -48,7 +48,7 @@ RSpec.describe Ci::BuildDependencies do
project
.
add_developer
(
user
)
end
let!
(
:retried_job
)
{
Ci
::
Build
.
retry
(
rspec_test
,
user
)
}
let!
(
:retried_job
)
{
Ci
::
RetryJobService
.
new
(
rspec_test
.
project
,
user
).
execute
(
rspec_test
)[
:job
]
}
it
'contains the retried job instead of the original one'
do
is_expected
.
to
contain_exactly
(
build
,
retried_job
,
rubocop_test
)
...
...
spec/models/ci/build_spec.rb
View file @
adaee22d
...
...
@@ -1951,90 +1951,6 @@ RSpec.describe Ci::Build do
end
end
describe
'#retryable?'
do
subject
{
build
}
context
'when build is retryable'
do
context
'when build is successful'
do
before
do
build
.
success!
end
it
{
is_expected
.
to
be_retryable
}
end
context
'when build is failed'
do
before
do
build
.
drop!
end
it
{
is_expected
.
to
be_retryable
}
end
context
'when build is canceled'
do
before
do
build
.
cancel!
end
it
{
is_expected
.
to
be_retryable
}
end
end
context
'when build is not retryable'
do
context
'when build is running'
do
before
do
build
.
run!
end
it
{
is_expected
.
not_to
be_retryable
}
end
context
'when build is skipped'
do
before
do
build
.
skip!
end
it
{
is_expected
.
not_to
be_retryable
}
end
context
'when build is degenerated'
do
before
do
build
.
degenerate!
end
it
{
is_expected
.
not_to
be_retryable
}
end
context
'when a canceled build has been retried already'
do
before
do
project
.
add_developer
(
user
)
build
.
cancel!
described_class
.
retry
(
build
,
user
)
end
it
{
is_expected
.
not_to
be_retryable
}
end
context
'when deployment is rejected'
do
before
do
build
.
drop!
(
:deployment_rejected
)
end
it
{
is_expected
.
not_to
be_retryable
}
end
context
'when build is waiting for deployment approval'
do
subject
{
build_stubbed
(
:ci_build
,
:manual
,
environment:
'production'
)
}
before
do
create
(
:deployment
,
:blocked
,
deployable:
subject
)
end
it
{
is_expected
.
not_to
be_retryable
}
end
end
end
describe
'#action?'
do
before
do
build
.
update!
(
when:
value
)
...
...
@@ -2358,24 +2274,12 @@ RSpec.describe Ci::Build do
end
context
'when build is retried'
do
let!
(
:new_build
)
{
described_class
.
retry
(
build
,
user
)
}
let!
(
:new_build
)
{
Ci
::
RetryJobService
.
new
(
project
,
user
).
execute
(
build
)[
:job
]
}
it
'does not return any of them'
do
is_expected
.
not_to
include
(
build
,
new_build
)
end
end
context
'when other build is retried'
do
let!
(
:retried_build
)
{
described_class
.
retry
(
other_build
,
user
)
}
before
do
retried_build
.
success
end
it
'returns a retried build'
do
is_expected
.
to
contain_exactly
(
retried_build
)
end
end
end
describe
'#other_scheduled_actions'
do
...
...
@@ -3962,8 +3866,9 @@ RSpec.describe Ci::Build do
subject
{
create
(
:ci_build
,
:running
,
options:
{
script:
[
"ls -al"
],
retry:
3
},
project:
project
,
user:
user
)
}
it
'retries build and assigns the same user to it'
do
expect
(
described_class
).
to
receive
(
:retry
)
.
with
(
subject
,
user
)
expect_next_instance_of
(
::
Ci
::
RetryJobService
)
do
|
service
|
expect
(
service
).
to
receive
(
:execute
).
with
(
subject
)
end
subject
.
drop!
end
...
...
@@ -3977,10 +3882,10 @@ RSpec.describe Ci::Build do
end
context
'when retry service raises Gitlab::Access::AccessDeniedError exception'
do
let
(
:retry_service
)
{
Ci
::
Retry
Build
Service
.
new
(
subject
.
project
,
subject
.
user
)
}
let
(
:retry_service
)
{
Ci
::
Retry
Job
Service
.
new
(
subject
.
project
,
subject
.
user
)
}
before
do
allow_any_instance_of
(
Ci
::
Retry
Build
Service
)
allow_any_instance_of
(
Ci
::
Retry
Job
Service
)
.
to
receive
(
:execute
)
.
with
(
subject
)
.
and_raise
(
Gitlab
::
Access
::
AccessDeniedError
)
...
...
spec/models/ci/pipeline_spec.rb
View file @
adaee22d
...
...
@@ -1663,7 +1663,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
expect
(
upstream_pipeline
.
reload
).
to
be_failed
Sidekiq
::
Testing
.
inline!
do
new_job
=
Ci
::
Build
.
retry
(
job
,
project
.
users
.
first
)
new_job
=
Ci
::
RetryJobService
.
new
(
project
,
project
.
users
.
first
).
execute
(
job
)[
:job
]
expect
(
downstream_pipeline
.
reload
).
to
be_running
expect
(
upstream_pipeline
.
reload
).
to
be_running
...
...
@@ -1684,7 +1684,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
expect
(
upstream_pipeline
.
reload
).
to
be_success
Sidekiq
::
Testing
.
inline!
do
new_job
=
Ci
::
Build
.
retry
(
job
,
project
.
users
.
first
)
new_job
=
Ci
::
RetryJobService
.
new
(
project
,
project
.
users
.
first
).
execute
(
job
)[
:job
]
expect
(
downstream_pipeline
.
reload
).
to
be_running
expect
(
upstream_pipeline
.
reload
).
to
be_running
...
...
@@ -1715,7 +1715,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
expect
(
upstream_of_upstream_pipeline
.
reload
).
to
be_failed
Sidekiq
::
Testing
.
inline!
do
new_job
=
Ci
::
Build
.
retry
(
job
,
project
.
users
.
first
)
new_job
=
Ci
::
RetryJobService
.
new
(
project
,
project
.
users
.
first
).
execute
(
job
)[
:job
]
expect
(
downstream_pipeline
.
reload
).
to
be_running
expect
(
upstream_pipeline
.
reload
).
to
be_running
...
...
@@ -2583,8 +2583,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
build
.
drop
project
.
add_developer
(
user
)
Ci
::
Build
.
retry
(
build
,
user
)
::
Ci
::
RetryJobService
.
new
(
project
,
user
).
execute
(
build
)[
:job
]
end
# We are changing a state: created > failed > running
...
...
@@ -4688,7 +4687,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
project
.
add_developer
(
user
)
retried_build
.
cancel!
::
Ci
::
Build
.
retry
(
retried_build
,
user
)
Ci
::
RetryJobService
.
new
(
project
,
user
).
execute
(
retried_build
)[
:job
]
end
it
'does not include retried builds'
do
...
...
spec/models/ci/processable_spec.rb
View file @
adaee22d
...
...
@@ -14,6 +14,100 @@ RSpec.describe Ci::Processable do
it
{
is_expected
.
to
delegate_method
(
:legacy_detached_merge_request_pipeline?
).
to
(
:pipeline
)
}
end
describe
'#retryable'
do
shared_examples_for
'retryable processable'
do
context
'when processable is successful'
do
before
do
processable
.
success!
end
it
{
is_expected
.
to
be_retryable
}
end
context
'when processable is failed'
do
before
do
processable
.
drop!
end
it
{
is_expected
.
to
be_retryable
}
end
context
'when processable is canceled'
do
before
do
processable
.
cancel!
end
it
{
is_expected
.
to
be_retryable
}
end
end
shared_examples_for
'non-retryable processable'
do
context
'when processable is skipped'
do
before
do
processable
.
skip!
end
it
{
is_expected
.
not_to
be_retryable
}
end
context
'when processable is degenerated'
do
before
do
processable
.
degenerate!
end
it
{
is_expected
.
not_to
be_retryable
}
end
context
'when a canceled processable has been retried already'
do
before
do
project
.
add_developer
(
create
(
:user
))
processable
.
cancel!
processable
.
update!
(
retried:
true
)
end
it
{
is_expected
.
not_to
be_retryable
}
end
end
context
'when the processable is a build'
do
subject
(
:processable
)
{
create
(
:ci_build
,
pipeline:
pipeline
)
}
context
'when the processable is retryable'
do
it_behaves_like
'retryable processable'
context
'when deployment is rejected'
do
before
do
processable
.
drop!
(
:deployment_rejected
)
end
it
{
is_expected
.
not_to
be_retryable
}
end
context
'when build is waiting for deployment approval'
do
subject
{
build_stubbed
(
:ci_build
,
:manual
,
environment:
'production'
)
}
before
do
create
(
:deployment
,
:blocked
,
deployable:
subject
)
end
it
{
is_expected
.
not_to
be_retryable
}
end
end
context
'when the processable is non-retryable'
do
it_behaves_like
'non-retryable processable'
context
'when processable is running'
do
before
do
processable
.
run!
end
it
{
is_expected
.
not_to
be_retryable
}
end
end
end
end
describe
'#aggregated_needs_names'
do
let
(
:with_aggregated_needs
)
{
pipeline
.
processables
.
select_with_aggregated_needs
(
project
)
}
...
...
spec/requests/api/ci/jobs_spec.rb
View file @
adaee22d
...
...
@@ -623,6 +623,15 @@ RSpec.describe API::Ci::Jobs do
end
end
context
'when a build is not retryable'
do
let
(
:job
)
{
create
(
:ci_build
,
:created
,
pipeline:
pipeline
)
}
it
'responds with unprocessable entity'
do
expect
(
json_response
[
'message'
]).
to
eq
(
'403 Forbidden - Job is not retryable'
)
expect
(
response
).
to
have_gitlab_http_status
(
:forbidden
)
end
end
context
'user without :update_build permission'
do
let
(
:api_user
)
{
reporter
}
...
...
spec/requests/api/graphql/mutations/ci/job_retry_spec.rb
View file @
adaee22d
...
...
@@ -8,7 +8,8 @@ RSpec.describe 'JobRetry' do
let_it_be
(
:user
)
{
create
(
:user
)
}
let_it_be
(
:project
)
{
create
(
:project
)
}
let_it_be
(
:pipeline
)
{
create
(
:ci_pipeline
,
project:
project
,
user:
user
)
}
let_it_be
(
:job
)
{
create
(
:ci_build
,
:success
,
pipeline:
pipeline
,
name:
'build'
)
}
let
(
:job
)
{
create
(
:ci_build
,
:success
,
pipeline:
pipeline
,
name:
'build'
)
}
let
(
:mutation
)
do
variables
=
{
...
...
@@ -37,10 +38,23 @@ RSpec.describe 'JobRetry' do
end
it
'retries a job'
do
job_id
=
::
Gitlab
::
GlobalId
.
build
(
job
,
id:
job
.
id
).
to_s
post_graphql_mutation
(
mutation
,
current_user:
user
)
expect
(
response
).
to
have_gitlab_http_status
(
:success
)
expect
(
mutation_response
[
'job'
][
'id'
]).
to
eq
(
job_id
)
new_job_id
=
GitlabSchema
.
object_from_id
(
mutation_response
[
'job'
][
'id'
]).
sync
.
id
new_job
=
::
Ci
::
Build
.
find
(
new_job_id
)
expect
(
new_job
).
not_to
be_retried
end
context
'when the job is not retryable'
do
let
(
:job
)
{
create
(
:ci_build
,
:retried
,
pipeline:
pipeline
)
}
it
'returns an error'
do
post_graphql_mutation
(
mutation
,
current_user:
user
)
expect
(
mutation_response
[
'job'
]).
to
be
(
nil
)
expect
(
mutation_response
[
'errors'
]).
to
match_array
([
'Job cannot be retried'
])
end
end
end
spec/services/ci/after_requeue_job_service_spec.rb
View file @
adaee22d
...
...
@@ -85,7 +85,7 @@ RSpec.describe Ci::AfterRequeueJobService, :sidekiq_inline do
c2:
'skipped'
)
new_a1
=
Ci
::
Retry
Build
Service
.
new
(
project
,
user
).
clone!
(
a1
)
new_a1
=
Ci
::
Retry
Job
Service
.
new
(
project
,
user
).
clone!
(
a1
)
new_a1
.
enqueue!
check_jobs_statuses
(
a1:
'pending'
,
...
...
@@ -172,7 +172,7 @@ RSpec.describe Ci::AfterRequeueJobService, :sidekiq_inline do
c2:
'skipped'
)
new_a1
=
Ci
::
Retry
Build
Service
.
new
(
project
,
user
).
clone!
(
a1
)
new_a1
=
Ci
::
Retry
Job
Service
.
new
(
project
,
user
).
clone!
(
a1
)
new_a1
.
enqueue!
check_jobs_statuses
(
a1:
'pending'
,
...
...
spec/services/ci/pipeline_processing/atomic_processing_service_spec.rb
View file @
adaee22d
...
...
@@ -725,7 +725,7 @@ RSpec.describe Ci::PipelineProcessing::AtomicProcessingService do
expect
(
builds_names
).
to
eq
[
'build:1'
,
'build:2'
,
'test:1'
,
'test:2'
]
Ci
::
Build
.
retry
(
pipeline
.
builds
.
find_by
(
name:
'test:2'
),
user
)
.
reset
.
success!
Ci
::
RetryJobService
.
new
(
pipeline
.
project
,
user
).
execute
(
pipeline
.
builds
.
find_by
(
name:
'test:2'
))[
:job
]
.
reset
.
success!
expect
(
builds_names
).
to
eq
[
'build:1'
,
'build:2'
,
'test:1'
,
'test:2'
,
'test:2'
,
'deploy:1'
,
'deploy:2'
]
...
...
@@ -1111,11 +1111,11 @@ RSpec.describe Ci::PipelineProcessing::AtomicProcessingService do
end
def
enqueue_scheduled
(
name
)
builds
.
scheduled
.
find_by
(
name:
name
).
enqueue
_scheduled
builds
.
scheduled
.
find_by
(
name:
name
).
enqueue
!
end
def
retry_build
(
name
)
Ci
::
Build
.
retry
(
builds
.
find_by
(
name:
name
),
user
)
Ci
::
RetryJobService
.
new
(
project
,
user
).
execute
(
builds
.
find_by
(
name:
name
)
)
end
def
manual_actions
...
...
spec/services/ci/retry_
build
_service_spec.rb
→
spec/services/ci/retry_
job
_service_spec.rb
View file @
adaee22d
...
...
@@ -2,7 +2,7 @@
require
'spec_helper'
RSpec
.
describe
Ci
::
Retry
Build
Service
do
RSpec
.
describe
Ci
::
Retry
Job
Service
do
let_it_be
(
:reporter
)
{
create
(
:user
)
}
let_it_be
(
:developer
)
{
create
(
:user
)
}
let_it_be
(
:project
)
{
create
(
:project
,
:repository
)
}
...
...
@@ -17,7 +17,7 @@ RSpec.describe Ci::RetryBuildService do
name:
'test'
)
end
let_it_be_with_refind
(
:build
)
{
create
(
:ci_build
,
pipeline:
pipeline
,
stage_id:
stage
.
id
)
}
let_it_be_with_refind
(
:build
)
{
create
(
:ci_build
,
:success
,
pipeline:
pipeline
,
stage_id:
stage
.
id
)
}
let
(
:user
)
{
developer
}
...
...
@@ -30,7 +30,7 @@ RSpec.describe Ci::RetryBuildService do
project
.
add_reporter
(
reporter
)
end
clone_accessors
=
described_class
.
clone_accessors
.
without
(
described_class
.
extra_accessors
)
clone_accessors
=
::
Ci
::
Build
.
clone_accessors
.
without
(
::
Ci
::
Build
.
extra_accessors
)
reject_accessors
=
%i[id status user token token_encrypted coverage trace runner
...
...
@@ -94,6 +94,10 @@ RSpec.describe Ci::RetryBuildService do
create
(
:terraform_state_version
,
build:
build
)
end
before
do
build
.
update!
(
retried:
false
,
status: :success
)
end
describe
'clone accessors'
do
let
(
:forbidden_associations
)
do
Ci
::
Build
.
reflect_on_all_associations
.
each_with_object
(
Set
.
new
)
do
|
assoc
,
memo
|
...
...
@@ -156,8 +160,8 @@ RSpec.describe Ci::RetryBuildService do
Ci
::
Build
.
attribute_aliases
.
keys
.
map
(
&
:to_sym
)
+
Ci
::
Build
.
reflect_on_all_associations
.
map
(
&
:name
)
+
[
:tag_list
,
:needs_attributes
,
:job_variables_attributes
]
-
# ee-specific accessors should be tested in ee/spec/services/ci/retry_
build
_service_spec.rb instead
described_class
.
extra_accessors
-
# ee-specific accessors should be tested in ee/spec/services/ci/retry_
job
_service_spec.rb instead
Ci
::
Build
.
extra_accessors
-
[
:dast_site_profiles_build
,
:dast_scanner_profiles_build
]
# join tables
current_accessors
.
uniq!
...
...
@@ -170,7 +174,7 @@ RSpec.describe Ci::RetryBuildService do
describe
'#execute'
do
let
(
:new_build
)
do
travel_to
(
1
.
second
.
from_now
)
do
service
.
execute
(
build
)
service
.
execute
(
build
)
[
:job
]
end
end
...
...
@@ -248,7 +252,7 @@ RSpec.describe Ci::RetryBuildService do
context
'when build has scheduling_type'
do
it
'does not call populate_scheduling_type!'
do
expect_any_instance_of
(
Ci
::
Pipeline
).
not_to
receive
(
:ensure_scheduling_type!
)
expect_any_instance_of
(
Ci
::
Pipeline
).
not_to
receive
(
:ensure_scheduling_type!
)
# rubocop: disable RSpec/AnyInstanceOf
expect
(
new_build
.
scheduling_type
).
to
eq
(
'stage'
)
end
...
...
@@ -286,6 +290,18 @@ RSpec.describe Ci::RetryBuildService do
expect
{
service
.
execute
(
build
)
}
.
to
raise_error
Gitlab
::
Access
::
AccessDeniedError
end
context
'when the job is not retryable'
do
let
(
:build
)
{
create
(
:ci_build
,
:created
,
pipeline:
pipeline
)
}
it
'returns a ServiceResponse error'
do
response
=
service
.
execute
(
build
)
expect
(
response
).
to
be_a
(
ServiceResponse
)
expect
(
response
).
to
be_error
expect
(
response
.
message
).
to
eq
(
"Job cannot be retried"
)
end
end
end
end
...
...
spec/services/ci/retry_pipeline_service_spec.rb
View file @
adaee22d
...
...
@@ -340,7 +340,7 @@ RSpec.describe Ci::RetryPipelineService, '#execute' do
context
'when user is not allowed to retry build'
do
before
do
build
=
create
(
:ci_build
,
pipeline:
pipeline
,
status: :failed
)
allow_next_instance_of
(
Ci
::
Retry
Build
Service
)
do
|
service
|
allow_next_instance_of
(
Ci
::
Retry
Job
Service
)
do
|
service
|
allow
(
service
).
to
receive
(
:can?
).
with
(
user
,
:update_build
,
build
).
and_return
(
false
)
end
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