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
0
Merge Requests
0
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
Jérome Perrin
gitlab-ce
Commits
f2a4420d
Commit
f2a4420d
authored
Apr 16, 2017
by
Kamil Trzcinski
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Store retried in database for CI builds
parent
6ad3814e
Changes
18
Hide whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
158 additions
and
41 deletions
+158
-41
app/models/ci/build.rb
app/models/ci/build.rb
+2
-2
app/models/commit_status.rb
app/models/commit_status.rb
+3
-8
app/services/ci/process_pipeline_service.rb
app/services/ci/process_pipeline_service.rb
+20
-0
app/services/ci/retry_build_service.rb
app/services/ci/retry_build_service.rb
+10
-3
app/services/ci/retry_pipeline_service.rb
app/services/ci/retry_pipeline_service.rb
+1
-1
changelogs/unreleased/store-retried-in-database-for-ci-builds.yml
...gs/unreleased/store-retried-in-database-for-ci-builds.yml
+4
-0
db/migrate/20170503004426_add_retried_to_ci_build.rb
db/migrate/20170503004426_add_retried_to_ci_build.rb
+15
-0
db/post_migrate/20170503004427_upate_retried_for_ci_build.rb
db/post_migrate/20170503004427_upate_retried_for_ci_build.rb
+29
-0
db/schema.rb
db/schema.rb
+1
-0
spec/lib/gitlab/import_export/safe_model_attributes.yml
spec/lib/gitlab/import_export/safe_model_attributes.yml
+1
-0
spec/models/ci/pipeline_spec.rb
spec/models/ci/pipeline_spec.rb
+20
-14
spec/models/ci/stage_spec.rb
spec/models/ci/stage_spec.rb
+4
-0
spec/models/commit_status_spec.rb
spec/models/commit_status_spec.rb
+20
-4
spec/requests/api/commit_statuses_spec.rb
spec/requests/api/commit_statuses_spec.rb
+2
-2
spec/services/ci/process_pipeline_service_spec.rb
spec/services/ci/process_pipeline_service_spec.rb
+15
-0
spec/services/ci/retry_build_service_spec.rb
spec/services/ci/retry_build_service_spec.rb
+8
-3
spec/services/ci/retry_pipeline_service_spec.rb
spec/services/ci/retry_pipeline_service_spec.rb
+1
-1
spec/views/projects/pipelines/_stage.html.haml_spec.rb
spec/views/projects/pipelines/_stage.html.haml_spec.rb
+2
-3
No files found.
app/models/ci/build.rb
View file @
f2a4420d
...
...
@@ -124,8 +124,8 @@ module Ci
success?
||
failed?
||
canceled?
end
def
retried
?
!
self
.
pipeline
.
statuses
.
latest
.
include?
(
self
)
def
latest
?
!
retried?
end
def
expanded_environment_name
...
...
app/models/commit_status.rb
View file @
f2a4420d
...
...
@@ -18,13 +18,7 @@ class CommitStatus < ActiveRecord::Base
validates
:name
,
presence:
true
alias_attribute
:author
,
:user
scope
:latest
,
->
do
max_id
=
unscope
(
:select
).
select
(
"max(
#{
quoted_table_name
}
.id)"
)
where
(
id:
max_id
.
group
(
:name
,
:commit_id
))
end
scope
:failed_but_allowed
,
->
do
where
(
allow_failure:
true
,
status:
[
:failed
,
:canceled
])
end
...
...
@@ -37,7 +31,8 @@ class CommitStatus < ActiveRecord::Base
false
,
all_state_names
-
[
:failed
,
:canceled
,
:manual
])
end
scope
:retried
,
->
{
where
.
not
(
id:
latest
)
}
scope
:latest
,
->
{
where
(
retried:
false
)
}
scope
:retried
,
->
{
where
(
retried:
true
)
}
scope
:ordered
,
->
{
order
(
:name
)
}
scope
:latest_ordered
,
->
{
latest
.
ordered
.
includes
(
project: :namespace
)
}
scope
:retried_ordered
,
->
{
retried
.
ordered
.
includes
(
project: :namespace
)
}
...
...
app/services/ci/process_pipeline_service.rb
View file @
f2a4420d
...
...
@@ -5,6 +5,8 @@ module Ci
def
execute
(
pipeline
)
@pipeline
=
pipeline
update_retried
new_builds
=
stage_indexes_of_created_builds
.
map
do
|
index
|
process_stage
(
index
)
...
...
@@ -71,5 +73,23 @@ module Ci
def
created_builds
pipeline
.
builds
.
created
end
# This method is for compatibility and data consistency and should be removed with 9.3 version of GitLab
# This replicates what is db/post_migrate/20170416103934_upate_retried_for_ci_build.rb
# and ensures that functionality will not be broken before migration is run
# this updates only when there are data that needs to be updated, there are two groups with no retried flag
def
update_retried
# find the latest builds for each name
latest_statuses
=
pipeline
.
statuses
.
latest
.
group
(
:name
)
.
having
(
'count(*) > 1'
)
.
pluck
(
'max(id)'
,
'name'
)
# mark builds that are retried
pipeline
.
statuses
.
latest
.
where
(
name:
latest_statuses
.
map
(
&
:second
))
.
where
.
not
(
id:
latest_statuses
.
map
(
&
:first
))
.
update_all
(
retried:
true
)
if
latest_statuses
.
any?
end
end
end
app/services/ci/retry_build_service.rb
View file @
f2a4420d
...
...
@@ -6,7 +6,7 @@ module Ci
description tag_list]
.
freeze
def
execute
(
build
)
reprocess
(
build
).
tap
do
|
new_build
|
reprocess
!
(
build
).
tap
do
|
new_build
|
build
.
pipeline
.
mark_as_processable_after_stage
(
build
.
stage_idx
)
new_build
.
enqueue!
...
...
@@ -17,7 +17,7 @@ module Ci
end
end
def
reprocess
(
build
)
def
reprocess
!
(
build
)
unless
can?
(
current_user
,
:update_build
,
build
)
raise
Gitlab
::
Access
::
AccessDeniedError
end
...
...
@@ -28,7 +28,14 @@ module Ci
attributes
.
push
([
:user
,
current_user
])
project
.
builds
.
create
(
Hash
[
attributes
])
Ci
::
Build
.
transaction
do
# mark all other builds of that name as retried
build
.
pipeline
.
builds
.
where
(
name:
build
.
name
)
.
where
.
not
(
retried:
true
)
.
update_all
(
retried:
true
)
project
.
builds
.
create!
(
Hash
[
attributes
])
end
end
end
end
app/services/ci/retry_pipeline_service.rb
View file @
f2a4420d
...
...
@@ -11,7 +11,7 @@ module Ci
next
unless
can?
(
current_user
,
:update_build
,
build
)
Ci
::
RetryBuildService
.
new
(
project
,
current_user
)
.
reprocess
(
build
)
.
reprocess
!
(
build
)
end
pipeline
.
builds
.
latest
.
skipped
.
find_each
do
|
skipped
|
...
...
changelogs/unreleased/store-retried-in-database-for-ci-builds.yml
0 → 100644
View file @
f2a4420d
---
title
:
Store retried in database for CI Builds
merge_request
:
author
:
db/migrate/20170503004426_add_retried_to_ci_build.rb
0 → 100644
View file @
f2a4420d
class
AddRetriedToCiBuild
<
ActiveRecord
::
Migration
include
Gitlab
::
Database
::
MigrationHelpers
DOWNTIME
=
false
disable_ddl_transaction!
def
up
add_column_with_default
(
:ci_builds
,
:retried
,
:boolean
,
default:
false
)
end
def
down
remove_column
(
:ci_builds
,
:retried
)
end
end
db/post_migrate/20170503004427_upate_retried_for_ci_build.rb
0 → 100644
View file @
f2a4420d
class
UpateRetriedForCiBuild
<
ActiveRecord
::
Migration
include
Gitlab
::
Database
::
MigrationHelpers
DOWNTIME
=
false
disable_ddl_transaction!
def
up
disable_statement_timeout
latest_id
=
<<-
SQL
.
strip_heredoc
SELECT MAX(ci_builds2.id)
FROM ci_builds ci_builds2
WHERE ci_builds.commit_id=ci_builds2.commit_id
AND ci_builds.name=ci_builds2.name
SQL
# This is slow update as it does single-row query
# This is designed to be run as idle, or a post deployment migration
is_retried
=
Arel
.
sql
(
"((
#{
latest_id
}
) != ci_builds.id)"
)
update_column_in_batches
(
:ci_builds
,
:retried
,
is_retried
)
do
|
table
,
query
|
query
.
where
(
table
[
:retried
].
eq
(
false
))
end
end
def
down
end
end
db/schema.rb
View file @
f2a4420d
...
...
@@ -232,6 +232,7 @@ ActiveRecord::Schema.define(version: 20170504102911) do
t
.
integer
"lock_version"
t
.
string
"coverage_regex"
t
.
integer
"auto_canceled_by_id"
t
.
boolean
"retried"
,
default:
false
,
null:
false
end
add_index
"ci_builds"
,
[
"commit_id"
,
"stage_idx"
,
"created_at"
],
name:
"index_ci_builds_on_commit_id_and_stage_idx_and_created_at"
,
using: :btree
...
...
spec/lib/gitlab/import_export/safe_model_attributes.yml
View file @
f2a4420d
...
...
@@ -229,6 +229,7 @@ CommitStatus:
-
lock_version
-
coverage_regex
-
auto_canceled_by_id
-
retried
Ci::Variable:
-
id
-
project_id
...
...
spec/models/ci/pipeline_spec.rb
View file @
f2a4420d
...
...
@@ -59,8 +59,8 @@ describe Ci::Pipeline, models: true do
subject
{
pipeline
.
retried
}
before
do
@build1
=
FactoryGirl
.
create
:ci_build
,
pipeline:
pipeline
,
name:
'deploy'
@build2
=
FactoryGirl
.
create
:ci_build
,
pipeline:
pipeline
,
name:
'deploy'
@build1
=
create
(
:ci_build
,
pipeline:
pipeline
,
name:
'deploy'
,
retried:
true
)
@build2
=
create
(
:ci_build
,
pipeline:
pipeline
,
name:
'deploy'
)
end
it
'returns old builds'
do
...
...
@@ -69,31 +69,31 @@ describe Ci::Pipeline, models: true do
end
describe
"coverage"
do
let
(
:project
)
{
FactoryGirl
.
create
:empty_project
,
build_coverage_regex:
"/.*/"
}
let
(
:pipeline
)
{
FactoryGirl
.
create
:ci_empty_pipeline
,
project:
project
}
let
(
:project
)
{
create
(
:empty_project
,
build_coverage_regex:
"/.*/"
)
}
let
(
:pipeline
)
{
create
(
:ci_empty_pipeline
,
project:
project
)
}
it
"calculates average when there are two builds with coverage"
do
FactoryGirl
.
create
:ci_build
,
name:
"rspec"
,
coverage:
30
,
pipeline:
pipeline
FactoryGirl
.
create
:ci_build
,
name:
"rubocop"
,
coverage:
40
,
pipeline:
pipeline
create
(
:ci_build
,
name:
"rspec"
,
coverage:
30
,
pipeline:
pipeline
)
create
(
:ci_build
,
name:
"rubocop"
,
coverage:
40
,
pipeline:
pipeline
)
expect
(
pipeline
.
coverage
).
to
eq
(
"35.00"
)
end
it
"calculates average when there are two builds with coverage and one with nil"
do
FactoryGirl
.
create
:ci_build
,
name:
"rspec"
,
coverage:
30
,
pipeline:
pipeline
FactoryGirl
.
create
:ci_build
,
name:
"rubocop"
,
coverage:
40
,
pipeline:
pipeline
FactoryGirl
.
create
:ci_build
,
pipeline:
pipeline
create
(
:ci_build
,
name:
"rspec"
,
coverage:
30
,
pipeline:
pipeline
)
create
(
:ci_build
,
name:
"rubocop"
,
coverage:
40
,
pipeline:
pipeline
)
create
(
:ci_build
,
pipeline:
pipeline
)
expect
(
pipeline
.
coverage
).
to
eq
(
"35.00"
)
end
it
"calculates average when there are two builds with coverage and one is retried"
do
FactoryGirl
.
create
:ci_build
,
name:
"rspec"
,
coverage:
30
,
pipeline:
pipeline
FactoryGirl
.
create
:ci_build
,
name:
"rubocop"
,
coverage:
30
,
pipeline:
pipeline
FactoryGirl
.
create
:ci_build
,
name:
"rubocop"
,
coverage:
40
,
pipeline:
pipeline
create
(
:ci_build
,
name:
"rspec"
,
coverage:
30
,
pipeline:
pipeline
)
create
(
:ci_build
,
name:
"rubocop"
,
coverage:
30
,
pipeline:
pipeline
,
retried:
true
)
create
(
:ci_build
,
name:
"rubocop"
,
coverage:
40
,
pipeline:
pipeline
)
expect
(
pipeline
.
coverage
).
to
eq
(
"35.00"
)
end
it
"calculates average when there is one build without coverage"
do
FactoryGirl
.
create
:ci_build
,
pipeline:
pipeline
FactoryGirl
.
create
(
:ci_build
,
pipeline:
pipeline
)
expect
(
pipeline
.
coverage
).
to
be_nil
end
end
...
...
@@ -221,13 +221,15 @@ describe Ci::Pipeline, models: true do
%w(deploy running)
])
end
context
'when commit status
is retried'
do
context
'when commit status is retried'
do
before
do
create
(
:commit_status
,
pipeline:
pipeline
,
stage:
'build'
,
name:
'mac'
,
stage_idx:
0
,
status:
'success'
)
pipeline
.
process!
end
it
'ignores the previous state'
do
...
...
@@ -488,6 +490,10 @@ describe Ci::Pipeline, models: true do
context
'there are multiple of the same name'
do
let!
(
:manual2
)
{
create
(
:ci_build
,
:manual
,
pipeline:
pipeline
,
name:
'deploy'
)
}
before
do
manual
.
update
(
retried:
true
)
end
it
'returns latest one'
do
is_expected
.
to
contain_exactly
(
manual2
)
end
...
...
spec/models/ci/stage_spec.rb
View file @
f2a4420d
...
...
@@ -102,6 +102,10 @@ describe Ci::Stage, models: true do
context
'and builds are retried'
do
let!
(
:new_build
)
{
create_job
(
:ci_build
,
status: :success
)
}
before
do
stage_build
.
update
(
retried:
true
)
end
it
"returns status of latest build"
do
is_expected
.
to
eq
(
'success'
)
end
...
...
spec/models/commit_status_spec.rb
View file @
f2a4420d
...
...
@@ -157,9 +157,9 @@ describe CommitStatus, :models do
subject
{
described_class
.
latest
.
order
(
:id
)
}
let
(
:statuses
)
do
[
create_status
(
name:
'aa'
,
ref:
'bb'
,
status:
'running'
),
create_status
(
name:
'cc'
,
ref:
'cc'
,
status:
'pending'
),
create_status
(
name:
'aa'
,
ref:
'cc'
,
status:
'success'
),
[
create_status
(
name:
'aa'
,
ref:
'bb'
,
status:
'running'
,
retried:
true
),
create_status
(
name:
'cc'
,
ref:
'cc'
,
status:
'pending'
,
retried:
true
),
create_status
(
name:
'aa'
,
ref:
'cc'
,
status:
'success'
,
retried:
true
),
create_status
(
name:
'cc'
,
ref:
'bb'
,
status:
'success'
),
create_status
(
name:
'aa'
,
ref:
'bb'
,
status:
'success'
)]
end
...
...
@@ -169,6 +169,22 @@ describe CommitStatus, :models do
end
end
describe
'.retried'
do
subject
{
described_class
.
retried
.
order
(
:id
)
}
let
(
:statuses
)
do
[
create_status
(
name:
'aa'
,
ref:
'bb'
,
status:
'running'
,
retried:
true
),
create_status
(
name:
'cc'
,
ref:
'cc'
,
status:
'pending'
,
retried:
true
),
create_status
(
name:
'aa'
,
ref:
'cc'
,
status:
'success'
,
retried:
true
),
create_status
(
name:
'cc'
,
ref:
'bb'
,
status:
'success'
),
create_status
(
name:
'aa'
,
ref:
'bb'
,
status:
'success'
)]
end
it
'returns unique statuses'
do
is_expected
.
to
contain_exactly
(
*
statuses
.
values_at
(
0
,
1
,
2
))
end
end
describe
'.running_or_pending'
do
subject
{
described_class
.
running_or_pending
.
order
(
:id
)
}
...
...
@@ -181,7 +197,7 @@ describe CommitStatus, :models do
end
it
'returns statuses that are running or pending'
do
is_expected
.
to
eq
(
statuses
.
values_at
(
0
,
1
))
is_expected
.
to
contain_exactly
(
*
statuses
.
values_at
(
0
,
1
))
end
end
...
...
spec/requests/api/commit_statuses_spec.rb
View file @
f2a4420d
...
...
@@ -26,8 +26,8 @@ describe API::CommitStatuses do
create
(
:commit_status
,
{
pipeline:
commit
,
ref:
commit
.
ref
}.
merge
(
opts
))
end
let!
(
:status1
)
{
create_status
(
master
,
status:
'running'
)
}
let!
(
:status2
)
{
create_status
(
master
,
name:
'coverage'
,
status:
'pending'
)
}
let!
(
:status1
)
{
create_status
(
master
,
status:
'running'
,
retried:
true
)
}
let!
(
:status2
)
{
create_status
(
master
,
name:
'coverage'
,
status:
'pending'
,
retried:
true
)
}
let!
(
:status3
)
{
create_status
(
develop
,
status:
'running'
,
allow_failure:
true
)
}
let!
(
:status4
)
{
create_status
(
master
,
name:
'coverage'
,
status:
'success'
)
}
let!
(
:status5
)
{
create_status
(
develop
,
name:
'coverage'
,
status:
'success'
)
}
...
...
spec/services/ci/process_pipeline_service_spec.rb
View file @
f2a4420d
...
...
@@ -425,6 +425,21 @@ describe Ci::ProcessPipelineService, '#execute', :services do
end
end
context
'updates a list of retried builds'
do
subject
{
described_class
.
retried
.
order
(
:id
)
}
let!
(
:build_retried
)
{
create_build
(
'build'
)
}
let!
(
:build
)
{
create_build
(
'build'
)
}
let!
(
:test
)
{
create_build
(
'test'
)
}
it
'returns unique statuses'
do
process_pipeline
expect
(
all_builds
.
latest
).
to
contain_exactly
(
build
,
test
)
expect
(
all_builds
.
retried
).
to
contain_exactly
(
build_retried
)
end
end
def
process_pipeline
described_class
.
new
(
pipeline
.
project
,
user
).
execute
(
pipeline
)
end
...
...
spec/services/ci/retry_build_service_spec.rb
View file @
f2a4420d
...
...
@@ -22,7 +22,7 @@ describe Ci::RetryBuildService, :services do
%i[type lock_version target_url base_tags
commit_id deployments erased_by_id last_deployment project_id
runner_id tag_taggings taggings tags trigger_request_id
user_id auto_canceled_by_id]
.
freeze
user_id auto_canceled_by_id
retried
]
.
freeze
shared_examples
'build duplication'
do
let
(
:build
)
do
...
...
@@ -115,7 +115,7 @@ describe Ci::RetryBuildService, :services do
end
describe
'#reprocess'
do
let
(
:new_build
)
{
service
.
reprocess
(
build
)
}
let
(
:new_build
)
{
service
.
reprocess
!
(
build
)
}
context
'when user has ability to execute build'
do
before
do
...
...
@@ -131,11 +131,16 @@ describe Ci::RetryBuildService, :services do
it
'does not enqueue the new build'
do
expect
(
new_build
).
to
be_created
end
it
'does mark old build as retried'
do
expect
(
new_build
).
to
be_latest
expect
(
build
.
reload
).
to
be_retried
end
end
context
'when user does not have ability to execute build'
do
it
'raises an error'
do
expect
{
service
.
reprocess
(
build
)
}
expect
{
service
.
reprocess
!
(
build
)
}
.
to
raise_error
Gitlab
::
Access
::
AccessDeniedError
end
end
...
...
spec/services/ci/retry_pipeline_service_spec.rb
View file @
f2a4420d
...
...
@@ -13,7 +13,7 @@ describe Ci::RetryPipelineService, '#execute', :services do
context
'when there are already retried jobs present'
do
before
do
create_build
(
'rspec'
,
:canceled
,
0
)
create_build
(
'rspec'
,
:canceled
,
0
,
retried:
true
)
create_build
(
'rspec'
,
:failed
,
0
)
end
...
...
spec/views/projects/pipelines/_stage.html.haml_spec.rb
View file @
f2a4420d
...
...
@@ -39,9 +39,8 @@ describe 'projects/pipelines/_stage', :view do
context
'when there are retried builds present'
do
before
do
create_list
(
:ci_build
,
2
,
name:
'test:build'
,
stage:
stage
.
name
,
pipeline:
pipeline
)
create
(
:ci_build
,
name:
'test:build'
,
stage:
stage
.
name
,
pipeline:
pipeline
,
retried:
true
)
create
(
:ci_build
,
name:
'test:build'
,
stage:
stage
.
name
,
pipeline:
pipeline
)
end
it
'shows only latest builds'
do
...
...
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