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
402898e2
Commit
402898e2
authored
Mar 25, 2020
by
Fabio Pitino
Committed by
Shinya Maeda
Mar 25, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Extract Ci::Processable::Dependencies class
Move all logic related to dependencies to a dedicated class.
parent
4a09d7b3
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
587 additions
and
426 deletions
+587
-426
app/models/ci/build.rb
app/models/ci/build.rb
+11
-43
app/models/ci/processable/dependencies.rb
app/models/ci/processable/dependencies.rb
+87
-0
ee/app/models/ee/ci/build.rb
ee/app/models/ee/ci/build.rb
+0
-37
ee/app/models/ee/ci/processable.rb
ee/app/models/ee/ci/processable.rb
+10
-0
ee/app/models/ee/ci/processable/dependencies.rb
ee/app/models/ee/ci/processable/dependencies.rb
+71
-0
ee/spec/models/ci/build_spec.rb
ee/spec/models/ci/build_spec.rb
+0
-205
ee/spec/models/ee/ci/processable/dependencies_spec.rb
ee/spec/models/ee/ci/processable/dependencies_spec.rb
+235
-0
spec/models/ci/build_spec.rb
spec/models/ci/build_spec.rb
+0
-141
spec/models/ci/processable/dependencies_spec.rb
spec/models/ci/processable/dependencies_spec.rb
+173
-0
No files found.
app/models/ci/build.rb
View file @
402898e2
...
...
@@ -511,14 +511,6 @@ module Ci
success?
&&
!
deployment
.
try
(
:last?
)
end
def
depends_on_builds
# Get builds of the same type
latest_builds
=
self
.
pipeline
.
builds
.
latest
# Return builds from previous stages
latest_builds
.
where
(
'stage_idx < ?'
,
stage_idx
)
end
def
triggered_by?
(
current_user
)
user
==
current_user
end
...
...
@@ -823,41 +815,15 @@ module Ci
end
def
all_dependencies
(
dependencies
+
cross_dependencies
).
uniq
end
def
dependencies
return
[]
if
empty_dependencies?
depended_jobs
=
depends_on_builds
# find all jobs that are needed
if
Feature
.
enabled?
(
:ci_dag_support
,
project
,
default_enabled:
true
)
&&
scheduling_type_dag?
depended_jobs
=
depended_jobs
.
where
(
name:
needs
.
artifacts
.
select
(
:name
))
end
# find all jobs that are dependent on
if
options
[
:dependencies
].
present?
depended_jobs
=
depended_jobs
.
where
(
name:
options
[
:dependencies
])
end
# if both needs and dependencies are used,
# the end result will be an intersection between them
depended_jobs
end
def
cross_dependencies
[]
end
def
empty_dependencies?
options
[
:dependencies
]
&
.
empty?
dependencies
.
all
end
def
has_valid_build_dependencies?
return
true
if
Feature
.
enabled?
(
'ci_disable_validates_dependencies'
)
dependencies
.
valid?
end
dependencies
.
all?
(
&
:valid_dependency?
)
def
invalid_dependencies
dependencies
.
invalid_local
end
def
valid_dependency?
...
...
@@ -867,10 +833,6 @@ module Ci
true
end
def
invalid_dependencies
dependencies
.
reject
(
&
:valid_dependency?
)
end
def
runner_required_feature_names
strong_memoize
(
:runner_required_feature_names
)
do
RUNNER_FEATURES
.
select
do
|
feature
,
method
|
...
...
@@ -948,6 +910,12 @@ module Ci
private
def
dependencies
strong_memoize
(
:dependencies
)
do
Ci
::
Processable
::
Dependencies
.
new
(
self
)
end
end
def
build_data
@build_data
||=
Gitlab
::
DataBuilder
::
Build
.
build
(
self
)
end
...
...
app/models/ci/processable/dependencies.rb
0 → 100644
View file @
402898e2
# frozen_string_literal: true
module
Ci
class
Processable
class
Dependencies
attr_reader
:processable
def
initialize
(
processable
)
@processable
=
processable
end
def
all
(
local
+
cross_pipeline
).
uniq
end
# Dependencies local to the given pipeline
def
local
return
[]
if
no_local_dependencies_specified?
deps
=
model_class
.
where
(
pipeline_id:
processable
.
pipeline_id
).
latest
deps
=
from_previous_stages
(
deps
)
deps
=
from_needs
(
deps
)
deps
=
from_dependencies
(
deps
)
deps
end
# Dependencies that are defined in other pipelines
def
cross_pipeline
[]
end
def
invalid_local
local
.
reject
(
&
:valid_dependency?
)
end
def
valid?
valid_local?
&&
valid_cross_pipeline?
end
private
# Dependencies can only be of Ci::Build type because only builds
# can create artifacts
def
model_class
::
Ci
::
Build
end
def
valid_local?
return
true
if
Feature
.
enabled?
(
'ci_disable_validates_dependencies'
)
local
.
all?
(
&
:valid_dependency?
)
end
def
valid_cross_pipeline?
true
end
def
project
processable
.
project
end
def
no_local_dependencies_specified?
processable
.
options
[
:dependencies
]
&
.
empty?
end
def
from_previous_stages
(
scope
)
scope
.
before_stage
(
processable
.
stage_idx
)
end
def
from_needs
(
scope
)
return
scope
unless
Feature
.
enabled?
(
:ci_dag_support
,
project
,
default_enabled:
true
)
return
scope
unless
processable
.
scheduling_type_dag?
needs_names
=
processable
.
needs
.
artifacts
.
select
(
:name
)
scope
.
where
(
name:
needs_names
)
end
def
from_dependencies
(
scope
)
return
scope
unless
processable
.
options
[
:dependencies
].
present?
scope
.
where
(
name:
processable
.
options
[
:dependencies
])
end
end
end
end
Ci
::
Processable
::
Dependencies
.
prepend_if_ee
(
'EE::Ci::Processable::Dependencies'
)
ee/app/models/ee/ci/build.rb
View file @
402898e2
...
...
@@ -119,45 +119,8 @@ module EE
!
merge_train_pipeline?
&&
super
end
override
:cross_dependencies
def
cross_dependencies
return
[]
unless
user_id
return
[]
unless
project
.
feature_available?
(
:cross_project_pipelines
)
cross_dependencies_relationship
.
preload
(
project:
[
:project_feature
])
.
select
{
|
job
|
user
.
can?
(
:read_build
,
job
)
}
end
private
def
cross_dependencies_relationship
deps
=
Array
(
options
[
:cross_dependencies
])
return
::
Ci
::
Build
.
none
unless
deps
.
any?
relationship_fragments
=
build_cross_dependencies_fragments
(
deps
,
::
Ci
::
Build
.
latest
.
success
)
return
::
Ci
::
Build
.
none
unless
relationship_fragments
.
any?
::
Ci
::
Build
.
from_union
(
relationship_fragments
)
.
limit
(
::
Gitlab
::
Ci
::
Config
::
Entry
::
Needs
::
NEEDS_CROSS_DEPENDENCIES_LIMIT
)
end
def
build_cross_dependencies_fragments
(
deps
,
search_scope
)
deps
.
inject
([])
do
|
fragments
,
dep
|
next
fragments
unless
dep
[
:artifacts
]
fragments
<<
build_cross_dependency_relationship_fragment
(
dep
,
search_scope
)
end
end
def
build_cross_dependency_relationship_fragment
(
dependency
,
search_scope
)
args
=
dependency
.
values_at
(
:job
,
:ref
,
:project
)
dep_id
=
search_scope
.
max_build_id_by
(
*
args
)
::
Ci
::
Build
.
id_in
(
dep_id
)
end
def
parse_security_artifact_blob
(
security_report
,
blob
)
report_clone
=
security_report
.
clone_as_blank
::
Gitlab
::
Ci
::
Parsers
.
fabricate!
(
security_report
.
type
).
parse!
(
blob
,
report_clone
)
...
...
ee/app/models/ee/ci/processable.rb
0 → 100644
View file @
402898e2
# frozen_string_literal: true
module
EE
module
Ci
module
Processable
# this is a placeholder module where to nest
# EE extensions for Processable components
end
end
end
ee/app/models/ee/ci/processable/dependencies.rb
0 → 100644
View file @
402898e2
# frozen_string_literal: true
module
EE
module
Ci
module
Processable
module
Dependencies
extend
ActiveSupport
::
Concern
extend
::
Gitlab
::
Utils
::
Override
include
::
Gitlab
::
Utils
::
StrongMemoize
LIMIT
=
::
Gitlab
::
Ci
::
Config
::
Entry
::
Needs
::
NEEDS_CROSS_DEPENDENCIES_LIMIT
override
:cross_pipeline
def
cross_pipeline
strong_memoize
(
:cross_pipeline
)
do
fetch_cross_pipeline
end
end
private
override
:valid_cross_pipeline?
def
valid_cross_pipeline?
cross_pipeline
.
size
==
specified_cross_pipeline_dependencies
.
size
end
def
fetch_cross_pipeline
return
[]
unless
processable
.
user_id
return
[]
unless
project
.
feature_available?
(
:cross_project_pipelines
)
cross_dependencies_relationship
.
preload
(
project:
[
:project_feature
])
.
select
{
|
job
|
user
.
can?
(
:read_build
,
job
)
}
end
def
cross_dependencies_relationship
deps
=
specified_cross_pipeline_dependencies
return
model_class
.
none
unless
deps
.
any?
relationship_fragments
=
build_cross_dependencies_fragments
(
deps
,
model_class
.
latest
.
success
)
return
model_class
.
none
unless
relationship_fragments
.
any?
model_class
.
from_union
(
relationship_fragments
).
limit
(
LIMIT
)
end
def
build_cross_dependencies_fragments
(
deps
,
search_scope
)
deps
.
inject
([])
do
|
fragments
,
dep
|
next
fragments
unless
dep
[
:artifacts
]
fragments
<<
build_cross_dependency_relationship_fragment
(
dep
,
search_scope
)
end
end
def
build_cross_dependency_relationship_fragment
(
dependency
,
search_scope
)
args
=
dependency
.
values_at
(
:job
,
:ref
,
:project
)
dep_id
=
search_scope
.
max_build_id_by
(
*
args
)
model_class
.
id_in
(
dep_id
)
end
def
user
processable
.
user
end
def
specified_cross_pipeline_dependencies
Array
(
processable
.
options
[
:cross_dependencies
])
end
end
end
end
end
ee/spec/models/ci/build_spec.rb
View file @
402898e2
...
...
@@ -383,209 +383,4 @@ describe Ci::Build do
expect
(
described_class
.
license_scan
).
to
contain_exactly
(
build_with_license_scan
)
end
end
describe
'#cross_dependencies'
do
let
(
:user
)
{
create
(
:user
)
}
let
(
:dependencies
)
{
}
let!
(
:final
)
do
create
(
:ci_build
,
pipeline:
pipeline
,
name:
'final'
,
stage_idx:
3
,
stage:
'deploy'
,
user:
user
,
options:
{
cross_dependencies:
dependencies
}
)
end
subject
{
final
.
cross_dependencies
}
before
do
project
.
add_developer
(
user
)
pipeline
.
update!
(
user:
user
)
stub_licensed_features
(
cross_project_pipelines:
true
)
end
context
'when cross_dependencies are not defined'
do
it
{
is_expected
.
to
be_empty
}
end
context
'with missing dependency'
do
let
(
:dependencies
)
do
[
{
project:
'some/project'
,
job:
'some/job'
,
ref:
'some/ref'
,
artifacts:
true
}
]
end
it
{
is_expected
.
to
be_empty
}
end
context
'with cross_dependencies to the same pipeline'
do
let!
(
:dependency
)
do
create
(
:ci_build
,
:success
,
pipeline:
pipeline
,
name:
'dependency'
,
stage_idx:
1
,
stage:
'build'
,
user:
user
)
end
let
(
:dependencies
)
do
[
{
project:
project
.
full_path
,
job:
'dependency'
,
ref:
pipeline
.
ref
,
artifacts:
artifacts
}
]
end
context
'with artifacts true'
do
let
(
:artifacts
)
{
true
}
it
{
is_expected
.
to
match
(
a_collection_containing_exactly
(
dependency
))
}
end
context
'with artifacts false'
do
let
(
:artifacts
)
{
false
}
it
{
is_expected
.
to
be_empty
}
end
end
context
'with cross_dependencies to other pipeline'
do
let
(
:feature_pipeline
)
do
create
(
:ci_pipeline
,
project:
project
,
sha:
project
.
commit
.
id
,
ref:
'feature'
,
status:
'success'
)
end
let
(
:dependencies
)
do
[
{
project:
project
.
full_path
,
job:
'dependency'
,
ref:
feature_pipeline
.
ref
,
artifacts:
true
}
]
end
let!
(
:dependency
)
do
create
(
:ci_build
,
:success
,
pipeline:
feature_pipeline
,
ref:
feature_pipeline
.
ref
,
name:
'dependency'
,
stage_idx:
4
,
stage:
'deploy'
,
user:
user
)
end
it
{
is_expected
.
to
match
(
a_collection_containing_exactly
(
dependency
))
}
end
context
'with cross_dependencies to two pipelines'
do
let
(
:other_project
)
{
create
(
:project
,
:repository
,
group:
group
)
}
let
(
:other_pipeline
)
do
create
(
:ci_pipeline
,
project:
other_project
,
sha:
other_project
.
commit
.
id
,
ref:
other_project
.
default_branch
,
status:
'success'
,
user:
user
)
end
let
(
:feature_pipeline
)
do
create
(
:ci_pipeline
,
project:
project
,
sha:
project
.
commit
.
id
,
ref:
'feature'
,
status:
'success'
)
end
let
(
:dependencies
)
do
[
{
project:
other_project
.
full_path
,
job:
'other_dependency'
,
ref:
other_pipeline
.
ref
,
artifacts:
true
},
{
project:
project
.
full_path
,
job:
'dependency'
,
ref:
feature_pipeline
.
ref
,
artifacts:
true
}
]
end
let!
(
:other_dependency
)
do
create
(
:ci_build
,
:success
,
pipeline:
other_pipeline
,
ref:
other_pipeline
.
ref
,
name:
'other_dependency'
,
stage_idx:
4
,
stage:
'deploy'
,
user:
user
)
end
let!
(
:dependency
)
do
create
(
:ci_build
,
:success
,
pipeline:
feature_pipeline
,
ref:
feature_pipeline
.
ref
,
name:
'dependency'
,
stage_idx:
4
,
stage:
'deploy'
,
user:
user
)
end
context
'with permissions to other_project'
do
before
do
other_project
.
add_developer
(
user
)
end
it
'contains both dependencies'
do
is_expected
.
to
match
(
a_collection_containing_exactly
(
dependency
,
other_dependency
))
end
context
'when license does not have cross_project_pipelines'
do
before
do
stub_licensed_features
(
cross_project_pipelines:
false
)
end
it
{
is_expected
.
to
be_empty
}
end
end
context
'without permissions to other_project'
do
it
{
is_expected
.
to
match
(
a_collection_containing_exactly
(
dependency
))
}
end
end
context
'with too many cross_dependencies'
do
let
(
:cross_dependencies_limit
)
do
::
Gitlab
::
Ci
::
Config
::
Entry
::
Needs
::
NEEDS_CROSS_DEPENDENCIES_LIMIT
end
before
do
cross_dependencies_limit
.
next
.
times
do
|
index
|
create
(
:ci_build
,
:success
,
pipeline:
pipeline
,
name:
"dependency-
#{
index
}
"
,
stage_idx:
1
,
stage:
'build'
,
user:
user
)
end
end
let
(
:dependencies
)
do
Array
.
new
(
cross_dependencies_limit
.
next
)
do
|
index
|
{
project:
project
.
full_path
,
job:
"dependency-
#{
index
}
"
,
ref:
pipeline
.
ref
,
artifacts:
true
}
end
end
it
'has a limit'
do
expect
(
subject
.
size
).
to
eq
(
cross_dependencies_limit
)
end
end
end
end
ee/spec/models/ee/ci/processable/dependencies_spec.rb
0 → 100644
View file @
402898e2
# frozen_string_literal: true
require
'spec_helper'
describe
Ci
::
Processable
::
Dependencies
do
describe
'#cross_pipeline'
do
let_it_be
(
:user
)
{
create
(
:user
)
}
let_it_be
(
:project
,
refind:
true
)
{
create
(
:project
,
:repository
)
}
let
(
:dependencies
)
{
}
let
(
:pipeline
)
do
create
(
:ci_pipeline
,
project:
project
,
sha:
project
.
commit
.
id
,
ref:
project
.
default_branch
,
status:
'success'
)
end
let!
(
:job
)
do
create
(
:ci_build
,
pipeline:
pipeline
,
name:
'final'
,
stage_idx:
3
,
stage:
'deploy'
,
user:
user
,
options:
{
cross_dependencies:
dependencies
})
end
subject
{
described_class
.
new
(
job
).
cross_pipeline
}
before
do
project
.
add_developer
(
user
)
pipeline
.
update!
(
user:
user
)
stub_licensed_features
(
cross_project_pipelines:
true
)
end
context
'when cross_dependencies are not defined'
do
it
{
is_expected
.
to
be_empty
}
end
context
'with missing dependency'
do
let
(
:dependencies
)
do
[
{
project:
'some/project'
,
job:
'some/job'
,
ref:
'some/ref'
,
artifacts:
true
}
]
end
it
{
is_expected
.
to
be_empty
}
end
context
'with cross_dependencies to the same pipeline'
do
let!
(
:dependency
)
do
create
(
:ci_build
,
:success
,
pipeline:
pipeline
,
name:
'dependency'
,
stage_idx:
1
,
stage:
'build'
,
user:
user
)
end
let
(
:dependencies
)
do
[
{
project:
project
.
full_path
,
job:
'dependency'
,
ref:
pipeline
.
ref
,
artifacts:
artifacts
}
]
end
context
'with artifacts true'
do
let
(
:artifacts
)
{
true
}
it
{
is_expected
.
to
contain_exactly
(
dependency
)
}
end
context
'with artifacts false'
do
let
(
:artifacts
)
{
false
}
it
{
is_expected
.
to
be_empty
}
end
end
context
'with cross_dependencies to another pipeline in same project'
do
let
(
:another_pipeline
)
do
create
(
:ci_pipeline
,
project:
project
,
sha:
project
.
commit
.
id
,
ref:
'feature'
,
status:
'success'
)
end
let
(
:dependencies
)
do
[
{
project:
project
.
full_path
,
job:
'dependency'
,
ref:
another_pipeline
.
ref
,
artifacts:
true
}
]
end
let!
(
:dependency
)
do
create
(
:ci_build
,
:success
,
pipeline:
another_pipeline
,
ref:
another_pipeline
.
ref
,
name:
'dependency'
,
stage_idx:
4
,
stage:
'deploy'
,
user:
user
)
end
it
{
is_expected
.
to
contain_exactly
(
dependency
)
}
end
context
'with cross_dependencies to a pipeline in another project'
do
let
(
:other_project
)
{
create
(
:project
,
:repository
)
}
let
(
:other_pipeline
)
do
create
(
:ci_pipeline
,
project:
other_project
,
sha:
other_project
.
commit
.
id
,
ref:
other_project
.
default_branch
,
status:
'success'
,
user:
user
)
end
let
(
:feature_pipeline
)
do
create
(
:ci_pipeline
,
project:
project
,
sha:
project
.
commit
.
id
,
ref:
'feature'
,
status:
'success'
)
end
let
(
:dependencies
)
do
[
{
project:
other_project
.
full_path
,
job:
'other_dependency'
,
ref:
other_pipeline
.
ref
,
artifacts:
true
},
{
project:
project
.
full_path
,
job:
'dependency'
,
ref:
feature_pipeline
.
ref
,
artifacts:
true
}
]
end
let!
(
:other_dependency
)
do
create
(
:ci_build
,
:success
,
pipeline:
other_pipeline
,
ref:
other_pipeline
.
ref
,
name:
'other_dependency'
,
stage_idx:
4
,
stage:
'deploy'
,
user:
user
)
end
let!
(
:dependency
)
do
create
(
:ci_build
,
:success
,
pipeline:
feature_pipeline
,
ref:
feature_pipeline
.
ref
,
name:
'dependency'
,
stage_idx:
4
,
stage:
'deploy'
,
user:
user
)
end
context
'with permissions to other_project'
do
before
do
other_project
.
add_developer
(
user
)
end
it
'contains both dependencies'
do
is_expected
.
to
contain_exactly
(
dependency
,
other_dependency
)
end
context
'when license does not have cross_project_pipelines'
do
before
do
stub_licensed_features
(
cross_project_pipelines:
false
)
end
it
{
expect
(
subject
).
to
be_empty
}
end
end
context
'without permissions to other_project'
do
it
{
is_expected
.
to
contain_exactly
(
dependency
)
}
end
end
context
'with too many cross_dependencies'
do
let
(
:cross_dependencies_limit
)
do
::
Gitlab
::
Ci
::
Config
::
Entry
::
Needs
::
NEEDS_CROSS_DEPENDENCIES_LIMIT
end
before
do
cross_dependencies_limit
.
next
.
times
do
|
index
|
create
(
:ci_build
,
:success
,
pipeline:
pipeline
,
name:
"dependency-
#{
index
}
"
,
stage_idx:
1
,
stage:
'build'
,
user:
user
)
end
end
let
(
:dependencies
)
do
Array
.
new
(
cross_dependencies_limit
.
next
)
do
|
index
|
{
project:
project
.
full_path
,
job:
"dependency-
#{
index
}
"
,
ref:
pipeline
.
ref
,
artifacts:
true
}
end
end
it
'returns a limited number of dependencies'
do
expect
(
subject
.
size
).
to
eq
(
cross_dependencies_limit
)
end
end
end
end
spec/models/ci/build_spec.rb
View file @
402898e2
...
...
@@ -730,147 +730,6 @@ describe Ci::Build do
end
end
describe
'#depends_on_builds'
do
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!
(
: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'
)
}
it
'expects to have no dependents if this is first build'
do
expect
(
build
.
depends_on_builds
).
to
be_empty
end
it
'expects to have one dependent if this is test'
do
expect
(
rspec_test
.
depends_on_builds
.
map
(
&
:id
)).
to
contain_exactly
(
build
.
id
)
end
it
'expects to have all builds from build and test stage if this is last'
do
expect
(
staging
.
depends_on_builds
.
map
(
&
:id
)).
to
contain_exactly
(
build
.
id
,
rspec_test
.
id
,
rubocop_test
.
id
)
end
it
'expects to have retried builds instead the original ones'
do
project
.
add_developer
(
user
)
retried_rspec
=
described_class
.
retry
(
rspec_test
,
user
)
expect
(
staging
.
depends_on_builds
.
map
(
&
:id
))
.
to
contain_exactly
(
build
.
id
,
retried_rspec
.
id
,
rubocop_test
.
id
)
end
describe
'#dependencies'
do
let
(
:dependencies
)
{
}
let
(
:needs
)
{
}
let!
(
:final
)
do
scheduling_type
=
needs
.
present?
?
:dag
:
:stage
create
(
:ci_build
,
pipeline:
pipeline
,
name:
'final'
,
scheduling_type:
scheduling_type
,
stage_idx:
3
,
stage:
'deploy'
,
options:
{
dependencies:
dependencies
}
)
end
before
do
needs
.
to_a
.
each
do
|
need
|
create
(
:ci_build_need
,
build:
final
,
**
need
)
end
end
subject
{
final
.
dependencies
}
context
'when dependencies are defined'
do
let
(
:dependencies
)
{
%w(rspec staging)
}
it
{
is_expected
.
to
contain_exactly
(
rspec_test
,
staging
)
}
end
context
'when needs are defined'
do
let
(
:needs
)
do
[
{
name:
'build'
,
artifacts:
true
},
{
name:
'rspec'
,
artifacts:
true
},
{
name:
'staging'
,
artifacts:
true
}
]
end
it
{
is_expected
.
to
contain_exactly
(
build
,
rspec_test
,
staging
)
}
context
'when ci_dag_support is disabled'
do
before
do
stub_feature_flags
(
ci_dag_support:
false
)
end
it
{
is_expected
.
to
contain_exactly
(
build
,
rspec_test
,
rubocop_test
,
staging
)
}
end
end
context
'when need artifacts are defined'
do
let
(
:needs
)
do
[
{
name:
'build'
,
artifacts:
true
},
{
name:
'rspec'
,
artifacts:
false
},
{
name:
'staging'
,
artifacts:
true
}
]
end
it
{
is_expected
.
to
contain_exactly
(
build
,
staging
)
}
end
context
'when needs and dependencies are defined'
do
let
(
:dependencies
)
{
%w(rspec staging)
}
let
(
:needs
)
do
[
{
name:
'build'
,
artifacts:
true
},
{
name:
'rspec'
,
artifacts:
true
},
{
name:
'staging'
,
artifacts:
true
}
]
end
it
{
is_expected
.
to
contain_exactly
(
rspec_test
,
staging
)
}
end
context
'when needs and dependencies contradict'
do
let
(
:dependencies
)
{
%w(rspec staging)
}
let
(
:needs
)
do
[
{
name:
'build'
,
artifacts:
true
},
{
name:
'rspec'
,
artifacts:
false
},
{
name:
'staging'
,
artifacts:
true
}
]
end
it
{
is_expected
.
to
contain_exactly
(
staging
)
}
end
context
'when nor dependencies or needs are defined'
do
it
{
is_expected
.
to
contain_exactly
(
build
,
rspec_test
,
rubocop_test
,
staging
)
}
end
end
describe
'#all_dependencies'
do
let!
(
:final_build
)
do
create
(
:ci_build
,
pipeline:
pipeline
,
name:
'deploy'
,
stage_idx:
3
,
stage:
'deploy'
)
end
subject
{
final_build
.
all_dependencies
}
it
'returns dependencies and cross_dependencies'
do
dependencies
=
[
1
,
2
,
3
]
cross_dependencies
=
[
3
,
4
]
allow
(
final_build
).
to
receive
(
:dependencies
).
and_return
(
dependencies
)
allow
(
final_build
).
to
receive
(
:cross_dependencies
).
and_return
(
cross_dependencies
)
is_expected
.
to
match
(
a_collection_containing_exactly
(
1
,
2
,
3
,
4
))
end
end
end
describe
'#triggered_by?'
do
subject
{
build
.
triggered_by?
(
user
)
}
...
...
spec/models/ci/processable/dependencies_spec.rb
0 → 100644
View file @
402898e2
# frozen_string_literal: true
require
'spec_helper'
describe
Ci
::
Processable
::
Dependencies
do
let_it_be
(
:user
)
{
create
(
:user
)
}
let_it_be
(
:project
,
reload:
true
)
{
create
(
:project
,
:repository
)
}
let_it_be
(
:pipeline
,
reload:
true
)
do
create
(
:ci_pipeline
,
project:
project
,
sha:
project
.
commit
.
id
,
ref:
project
.
default_branch
,
status:
'success'
)
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!
(
: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'
)
}
describe
'#local'
do
subject
{
described_class
.
new
(
job
).
local
}
describe
'jobs from previous stages'
do
context
'when job is in the first stage'
do
let
(
:job
)
{
build
}
it
{
is_expected
.
to
be_empty
}
end
context
'when job is in the second stage'
do
let
(
:job
)
{
rspec_test
}
it
'contains all jobs from the first stage'
do
is_expected
.
to
contain_exactly
(
build
)
end
end
context
'when job is in the last stage'
do
let
(
:job
)
{
staging
}
it
'contains all jobs from all previous stages'
do
is_expected
.
to
contain_exactly
(
build
,
rspec_test
,
rubocop_test
)
end
context
'when a job is retried'
do
before
do
project
.
add_developer
(
user
)
end
let
(
:retried_job
)
{
Ci
::
Build
.
retry
(
rspec_test
,
user
)
}
it
'contains the retried job instead of the original one'
do
is_expected
.
to
contain_exactly
(
build
,
retried_job
,
rubocop_test
)
end
end
end
end
describe
'jobs from specified dependencies'
do
let
(
:dependencies
)
{
}
let
(
:needs
)
{
}
let!
(
:job
)
do
scheduling_type
=
needs
.
present?
?
:dag
:
:stage
create
(
:ci_build
,
pipeline:
pipeline
,
name:
'final'
,
scheduling_type:
scheduling_type
,
stage_idx:
3
,
stage:
'deploy'
,
options:
{
dependencies:
dependencies
}
)
end
before
do
needs
.
to_a
.
each
do
|
need
|
create
(
:ci_build_need
,
build:
job
,
**
need
)
end
end
context
'when dependencies are defined'
do
let
(
:dependencies
)
{
%w(rspec staging)
}
it
{
is_expected
.
to
contain_exactly
(
rspec_test
,
staging
)
}
end
context
'when needs are defined'
do
let
(
:needs
)
do
[
{
name:
'build'
,
artifacts:
true
},
{
name:
'rspec'
,
artifacts:
true
},
{
name:
'staging'
,
artifacts:
true
}
]
end
it
{
is_expected
.
to
contain_exactly
(
build
,
rspec_test
,
staging
)
}
context
'when ci_dag_support is disabled'
do
before
do
stub_feature_flags
(
ci_dag_support:
false
)
end
it
{
is_expected
.
to
contain_exactly
(
build
,
rspec_test
,
rubocop_test
,
staging
)
}
end
end
context
'when need artifacts are defined'
do
let
(
:needs
)
do
[
{
name:
'build'
,
artifacts:
true
},
{
name:
'rspec'
,
artifacts:
false
},
{
name:
'staging'
,
artifacts:
true
}
]
end
it
{
is_expected
.
to
contain_exactly
(
build
,
staging
)
}
end
context
'when needs and dependencies are defined'
do
let
(
:dependencies
)
{
%w(rspec staging)
}
let
(
:needs
)
do
[
{
name:
'build'
,
artifacts:
true
},
{
name:
'rspec'
,
artifacts:
true
},
{
name:
'staging'
,
artifacts:
true
}
]
end
it
{
is_expected
.
to
contain_exactly
(
rspec_test
,
staging
)
}
end
context
'when needs and dependencies contradict'
do
let
(
:dependencies
)
{
%w(rspec staging)
}
let
(
:needs
)
do
[
{
name:
'build'
,
artifacts:
true
},
{
name:
'rspec'
,
artifacts:
false
},
{
name:
'staging'
,
artifacts:
true
}
]
end
it
'returns only the intersection'
do
is_expected
.
to
contain_exactly
(
staging
)
end
end
context
'when nor dependencies or needs are defined'
do
it
'returns the jobs from previous stages'
do
is_expected
.
to
contain_exactly
(
build
,
rspec_test
,
rubocop_test
,
staging
)
end
end
end
end
describe
'#all'
do
let!
(
:job
)
do
create
(
:ci_build
,
pipeline:
pipeline
,
name:
'deploy'
,
stage_idx:
3
,
stage:
'deploy'
)
end
let
(
:dependencies
)
{
described_class
.
new
(
job
)
}
subject
{
dependencies
.
all
}
it
'returns the union of all local dependencies and any cross pipeline dependencies'
do
expect
(
dependencies
).
to
receive
(
:local
).
and_return
([
1
,
2
,
3
])
expect
(
dependencies
).
to
receive
(
:cross_pipeline
).
and_return
([
3
,
4
])
expect
(
subject
).
to
contain_exactly
(
1
,
2
,
3
,
4
)
end
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