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
df17e87e
Commit
df17e87e
authored
Sep 01, 2020
by
GitLab Bot
Browse files
Options
Browse Files
Download
Plain Diff
Automatic merge of gitlab-org/gitlab master
parents
dd883716
ce721bd7
Changes
27
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
27 changed files
with
455 additions
and
356 deletions
+455
-356
.gitlab/ci/review.gitlab-ci.yml
.gitlab/ci/review.gitlab-ci.yml
+3
-3
.gitlab/ci/rules.gitlab-ci.yml
.gitlab/ci/rules.gitlab-ci.yml
+11
-0
app/assets/javascripts/diffs/components/app.vue
app/assets/javascripts/diffs/components/app.vue
+11
-46
app/assets/javascripts/diffs/components/merge_conflict_warning.vue
...s/javascripts/diffs/components/merge_conflict_warning.vue
+72
-0
doc/ci/yaml/README.md
doc/ci/yaml/README.md
+2
-0
ee/app/graphql/ee/types/project_type.rb
ee/app/graphql/ee/types/project_type.rb
+0
-2
ee/app/services/security/ci_configuration/sast_parser_service.rb
...services/security/ci_configuration/sast_parser_service.rb
+4
-1
ee/spec/controllers/projects/feature_flags_controller_spec.rb
...pec/controllers/projects/feature_flags_controller_spec.rb
+3
-3
ee/spec/graphql/types/project_type_spec.rb
ee/spec/graphql/types/project_type_spec.rb
+0
-9
ee/spec/lib/ee/gitlab/ci/templates/templates_spec.rb
ee/spec/lib/ee/gitlab/ci/templates/templates_spec.rb
+2
-2
ee/spec/lib/gitlab/ci/yaml_processor_spec.rb
ee/spec/lib/gitlab/ci/yaml_processor_spec.rb
+7
-9
lib/gitlab/ci/config.rb
lib/gitlab/ci/config.rb
+4
-0
lib/gitlab/ci/config/normalizer.rb
lib/gitlab/ci/config/normalizer.rb
+1
-0
lib/gitlab/ci/lint.rb
lib/gitlab/ci/lint.rb
+8
-7
lib/gitlab/ci/pipeline/chain/config/process.rb
lib/gitlab/ci/pipeline/chain/config/process.rb
+9
-6
lib/gitlab/ci/yaml_processor.rb
lib/gitlab/ci/yaml_processor.rb
+37
-155
lib/gitlab/ci/yaml_processor/result.rb
lib/gitlab/ci/yaml_processor/result.rb
+120
-0
spec/controllers/projects/ci/lints_controller_spec.rb
spec/controllers/projects/ci/lints_controller_spec.rb
+2
-2
spec/frontend/diffs/components/merge_conflict_warning_spec.js
.../frontend/diffs/components/merge_conflict_warning_spec.js
+77
-0
spec/lib/gitlab/ci/config/normalizer_spec.rb
spec/lib/gitlab/ci/config/normalizer_spec.rb
+6
-0
spec/lib/gitlab/ci/config_spec.rb
spec/lib/gitlab/ci/config_spec.rb
+2
-2
spec/lib/gitlab/ci/lint_spec.rb
spec/lib/gitlab/ci/lint_spec.rb
+1
-1
spec/lib/gitlab/ci/pipeline/chain/validate/external_spec.rb
spec/lib/gitlab/ci/pipeline/chain/validate/external_spec.rb
+3
-3
spec/lib/gitlab/ci/templates/templates_spec.rb
spec/lib/gitlab/ci/templates/templates_spec.rb
+2
-2
spec/lib/gitlab/ci/yaml_processor_spec.rb
spec/lib/gitlab/ci/yaml_processor_spec.rb
+68
-91
spec/lib/gitlab/import_export/fast_hash_serializer_spec.rb
spec/lib/gitlab/import_export/fast_hash_serializer_spec.rb
+0
-6
spec/lib/gitlab/import_export/project/tree_saver_spec.rb
spec/lib/gitlab/import_export/project/tree_saver_spec.rb
+0
-6
No files found.
.gitlab/ci/review.gitlab-ci.yml
View file @
df17e87e
...
...
@@ -45,7 +45,7 @@ review-build-cng:
DOMAIN
:
"
-${CI_ENVIRONMENT_SLUG}.${REVIEW_APPS_DOMAIN}"
GITLAB_HELM_CHART_REF
:
"
v4.3.0"
environment
:
name
:
review/${CI_COMMIT_REF_
NAME
}
name
:
review/${CI_COMMIT_REF_
SLUG}${FREQUENCY
}
url
:
https://gitlab-${CI_ENVIRONMENT_SLUG}.${REVIEW_APPS_DOMAIN}
on_stop
:
review-stop
auto_stop_in
:
48 hours
...
...
@@ -113,8 +113,8 @@ review-stop-failed-deployment:
review-stop
:
extends
:
-
.review-stop-base
-
.review:rules:
mr-only-manual
stage
:
review
-
.review:rules:
review-stop
stage
:
post-qa
script
:
-
delete_release
...
...
.gitlab/ci/rules.gitlab-ci.yml
View file @
df17e87e
...
...
@@ -753,6 +753,17 @@
-
<<
:
*if-dot-com-gitlab-org-schedule
allow_failure
:
true
.review:rules:review-stop:
rules
:
-
<<
:
*if-not-ee
when
:
never
-
<<
:
*if-dot-com-gitlab-org-merge-request
changes
:
*code-qa-patterns
when
:
manual
allow_failure
:
true
-
<<
:
*if-master-refs
allow_failure
:
true
.review:rules:danger:
rules
:
-
if
:
'
$DANGER_GITLAB_API_TOKEN
&&
$CI_MERGE_REQUEST_IID'
...
...
app/assets/javascripts/diffs/components/app.vue
View file @
df17e87e
<
script
>
import
{
mapState
,
mapGetters
,
mapActions
}
from
'
vuex
'
;
import
{
GlLoadingIcon
,
Gl
Button
,
GlAlert
,
Gl
Pagination
,
GlSprintf
}
from
'
@gitlab/ui
'
;
import
{
GlLoadingIcon
,
GlPagination
,
GlSprintf
}
from
'
@gitlab/ui
'
;
import
Mousetrap
from
'
mousetrap
'
;
import
{
__
}
from
'
~/locale
'
;
import
{
getParameterByName
,
parseBoolean
}
from
'
~/lib/utils/common_utils
'
;
...
...
@@ -13,9 +13,12 @@ import eventHub from '../../notes/event_hub';
import
CompareVersions
from
'
./compare_versions.vue
'
;
import
DiffFile
from
'
./diff_file.vue
'
;
import
NoChanges
from
'
./no_changes.vue
'
;
import
HiddenFilesWarning
from
'
./hidden_files_warning.vue
'
;
import
CommitWidget
from
'
./commit_widget.vue
'
;
import
TreeList
from
'
./tree_list.vue
'
;
import
HiddenFilesWarning
from
'
./hidden_files_warning.vue
'
;
import
MergeConflictWarning
from
'
./merge_conflict_warning.vue
'
;
import
{
TREE_LIST_WIDTH_STORAGE_KEY
,
INITIAL_TREE_WIDTH
,
...
...
@@ -33,13 +36,12 @@ export default {
DiffFile
,
NoChanges
,
HiddenFilesWarning
,
MergeConflictWarning
,
CommitWidget
,
TreeList
,
GlLoadingIcon
,
PanelResizer
,
GlPagination
,
GlButton
,
GlAlert
,
GlSprintf
,
},
mixins
:
[
glFeatureFlagsMixin
()],
...
...
@@ -422,49 +424,12 @@ export default {
:plain-diff-path=
"plainDiffPath"
:email-patch-path=
"emailPatchPath"
/>
<div
<merge-conflict-warning
v-if=
"isDiffHead && hasConflicts"
:class=
"
{
[CENTERED_LIMITED_CONTAINER_CLASSES]: isLimitedContainer,
}"
>
<gl-alert
:dismissible=
"false"
:title=
"__('There are merge conflicts')"
variant=
"warning"
class=
"w-100 mb-3"
>
<p
class=
"mb-1"
>
{{
__
(
'
The comparison view may be inaccurate due to merge conflicts.
'
)
}}
</p>
<p
class=
"mb-0"
>
{{
__
(
'
Resolve these conflicts or ask someone with write access to this repository to merge it locally.
'
,
)
}}
</p>
<template
#actions
>
<gl-button
v-if=
"conflictResolutionPath"
:href=
"conflictResolutionPath"
variant=
"info"
class=
"mr-3 gl-alert-action"
>
{{
__
(
'
Resolve conflicts
'
)
}}
</gl-button>
<gl-button
v-if=
"canMerge"
class=
"gl-alert-action"
data-toggle=
"modal"
data-target=
"#modal_merge_info"
>
{{
__
(
'
Merge locally
'
)
}}
</gl-button>
</
template
>
</gl-alert>
</div>
:limited=
"isLimitedContainer"
:resolution-path=
"conflictResolutionPath"
:mergeable=
"canMerge"
/>
<div
:data-can-create-note=
"getNoteableData.current_user.can_create_note"
...
...
app/assets/javascripts/diffs/components/merge_conflict_warning.vue
0 → 100644
View file @
df17e87e
<
script
>
import
{
GlButton
,
GlAlert
}
from
'
@gitlab/ui
'
;
import
{
CENTERED_LIMITED_CONTAINER_CLASSES
}
from
'
../constants
'
;
export
default
{
components
:
{
GlAlert
,
GlButton
,
},
props
:
{
limited
:
{
type
:
Boolean
,
required
:
true
,
},
mergeable
:
{
type
:
Boolean
,
required
:
true
,
},
resolutionPath
:
{
type
:
String
,
required
:
true
,
},
},
computed
:
{
containerClasses
()
{
return
{
[
CENTERED_LIMITED_CONTAINER_CLASSES
]:
this
.
limited
,
};
},
},
};
</
script
>
<
template
>
<div
:class=
"containerClasses"
>
<gl-alert
:dismissible=
"false"
:title=
"__('There are merge conflicts')"
variant=
"warning"
class=
"gl-mb-5"
>
<p
class=
"gl-mb-2"
>
{{
__
(
'
The comparison view may be inaccurate due to merge conflicts.
'
)
}}
</p>
<p
class=
"gl-mb-0"
>
{{
__
(
'
Resolve these conflicts or ask someone with write access to this repository to merge it locally.
'
,
)
}}
</p>
<template
#actions
>
<gl-button
v-if=
"resolutionPath"
:href=
"resolutionPath"
variant=
"info"
class=
"gl-mr-5 gl-alert-action"
>
{{
__
(
'
Resolve conflicts
'
)
}}
</gl-button>
<gl-button
v-if=
"mergeable"
class=
"gl-alert-action"
data-toggle=
"modal"
data-target=
"#modal_merge_info"
>
{{
__
(
'
Merge locally
'
)
}}
</gl-button>
</
template
>
</gl-alert>
</div>
</template>
doc/ci/yaml/README.md
View file @
df17e87e
...
...
@@ -1335,6 +1335,8 @@ expression string per rule, rather than an array of them. Any set of expressions
evaluated can be
[
conjoined into a single expression
](
../variables/README.md#conjunction--disjunction
)
by using
`&&`
or
`||`
, and use
the
[
variable matching syntax
](
../variables/README.md#syntax-of-environment-variable-expressions
)
.
Unlike variables in
[
`script`
](
../variables/README.md#syntax-of-environment-variables-in-job-scripts
)
sections, variables in rules expressions are always formatted as
`$VARIABLE`
.
`if:`
clauses are evaluated based on the values of
[
predefined environment variables
](
../variables/predefined_variables.md
)
or
[
custom environment variables
](
../variables/README.md#custom-environment-variables
)
.
...
...
ee/app/graphql/ee/types/project_type.rb
View file @
df17e87e
...
...
@@ -89,8 +89,6 @@ module EE
def
self
.
sast_ci_configuration
(
project
)
::
Security
::
CiConfiguration
::
SastParserService
.
new
(
project
).
configuration
rescue
::
Gitlab
::
Ci
::
YamlProcessor
::
ValidationError
=>
ex
raise
::
GraphQL
::
ExecutionError
,
ex
.
message
end
end
end
...
...
ee/app/services/security/ci_configuration/sast_parser_service.rb
View file @
df17e87e
...
...
@@ -66,7 +66,10 @@ module Security
def
build_sast_attributes
(
content
)
options
=
{
project:
@project
,
user:
current_user
,
sha:
@project
.
repository
.
commit
.
sha
}
sast_attributes
=
Gitlab
::
Ci
::
YamlProcessor
.
new
(
content
,
options
).
build_attributes
(
:sast
)
yaml_result
=
Gitlab
::
Ci
::
YamlProcessor
.
new
(
content
,
options
).
execute
return
{}
unless
yaml_result
.
valid?
sast_attributes
=
yaml_result
.
build_attributes
(
:sast
)
extract_required_attributes
(
sast_attributes
)
end
...
...
ee/spec/controllers/projects/feature_flags_controller_spec.rb
View file @
df17e87e
...
...
@@ -62,11 +62,11 @@ RSpec.describe Projects::FeatureFlagsController do
subject
{
get
(
:index
,
params:
view_params
,
format: :json
)
}
let!
(
:feature_flag_active
)
do
create
(
:operations_feature_flag
,
project:
project
,
active:
true
)
create
(
:operations_feature_flag
,
project:
project
,
active:
true
,
name:
'feature_flag_a'
)
end
let!
(
:feature_flag_inactive
)
do
create
(
:operations_feature_flag
,
project:
project
,
active:
false
)
create
(
:operations_feature_flag
,
project:
project
,
active:
false
,
name:
'feature_flag_b'
)
end
it
'returns all feature flags as json response'
do
...
...
@@ -219,7 +219,7 @@ RSpec.describe Projects::FeatureFlagsController do
context
'with version 1 and 2 feature flags'
do
let!
(
:new_version_feature_flag
)
do
create
(
:operations_feature_flag
,
:new_version_flag
,
project:
project
)
create
(
:operations_feature_flag
,
:new_version_flag
,
project:
project
,
name:
'feature_flag_c'
)
end
it
'returns all feature flags as json response'
do
...
...
ee/spec/graphql/types/project_type_spec.rb
View file @
df17e87e
...
...
@@ -25,7 +25,6 @@ RSpec.describe GitlabSchema.types['Project'] do
describe
'sast_ci_configuration'
do
include_context
'read ci configuration for sast enabled project'
let
(
:error_message
)
{
"This is an error for YamlProcessor."
}
let_it_be
(
:query
)
do
%(
...
...
@@ -110,14 +109,6 @@ RSpec.describe GitlabSchema.types['Project'] do
expect
(
analyzer
[
'label'
]).
to
eq
(
'Brakeman'
)
expect
(
analyzer
[
'enabled'
]).
to
eq
(
true
)
end
it
'returns an error if there is an exception in YamlProcessor'
do
allow_next_instance_of
(
::
Security
::
CiConfiguration
::
SastParserService
)
do
|
service
|
allow
(
service
).
to
receive
(
:configuration
).
and_raise
(
::
Gitlab
::
Ci
::
YamlProcessor
::
ValidationError
.
new
(
error_message
))
end
expect
(
subject
[
"errors"
].
first
[
"message"
]).
to
eql
(
error_message
)
end
end
describe
'security_scanners'
do
...
...
ee/spec/lib/ee/gitlab/ci/templates/templates_spec.rb
View file @
df17e87e
...
...
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec
.
describe
"CI YML Templates"
do
using
RSpec
::
Parameterized
::
TableSyntax
subject
{
Gitlab
::
Ci
::
YamlProcessor
.
new
(
content
)
}
subject
{
Gitlab
::
Ci
::
YamlProcessor
.
new
(
content
)
.
execute
}
where
(
:template_name
)
do
Gitlab
::
Template
::
GitlabCiYmlTemplate
.
all
.
map
(
&
:full_name
)
...
...
@@ -24,7 +24,7 @@ RSpec.describe "CI YML Templates" do
end
it
'is valid'
do
expect
{
subject
}.
not_to
raise_error
expect
(
subject
).
to
be_valid
end
it
'require default stages to be included'
do
...
...
ee/spec/lib/gitlab/ci/yaml_processor_spec.rb
View file @
df17e87e
...
...
@@ -11,7 +11,7 @@ RSpec.describe Gitlab::Ci::YamlProcessor do
}
end
subject
{
described_class
.
new
(
YAML
.
dump
(
config
))
}
subject
{
described_class
.
new
(
YAML
.
dump
(
config
))
.
execute
}
context
'needs upstream pipeline'
do
let
(
:needs
)
{
{
pipeline:
'some/project'
}
}
...
...
@@ -174,9 +174,8 @@ RSpec.describe Gitlab::Ci::YamlProcessor do
end
it
'returns errors'
do
expect
{
subject
}
.
to
raise_error
(
Gitlab
::
Ci
::
YamlProcessor
::
ValidationError
,
'jobs:bridge config should contain either a trigger or a needs:pipeline'
)
expect
(
subject
.
errors
).
to
include
(
'jobs:bridge config should contain either a trigger or a needs:pipeline'
)
end
end
...
...
@@ -198,9 +197,8 @@ RSpec.describe Gitlab::Ci::YamlProcessor do
end
it
'returns errors'
do
expect
{
subject
}
.
to
raise_error
(
Gitlab
::
Ci
::
YamlProcessor
::
ValidationError
,
'jobs:test:needs:need ref should be a string'
)
expect
(
subject
.
errors
).
to
contain_exactly
(
'jobs:test:needs:need ref should be a string'
)
end
end
end
...
...
@@ -216,10 +214,10 @@ RSpec.describe Gitlab::Ci::YamlProcessor do
let
(
:config
)
{
{
deploy_to_production:
{
stage:
'deploy'
,
script:
[
'echo'
],
secrets:
secrets
}
}
}
subject
(
:
processor
)
{
described_class
.
new
(
YAML
.
dump
(
config
))
}
subject
(
:
result
)
{
described_class
.
new
(
YAML
.
dump
(
config
)).
execute
}
it
"returns secrets info"
do
secrets
=
processor
.
stage_builds_attributes
(
'deploy'
).
first
.
fetch
(
:secrets
)
secrets
=
result
.
stage_builds_attributes
(
'deploy'
).
first
.
fetch
(
:secrets
)
expect
(
secrets
).
to
eq
({
DATABASE_PASSWORD
:
{
...
...
lib/gitlab/ci/config.rb
View file @
df17e87e
...
...
@@ -62,6 +62,10 @@ module Gitlab
root
.
jobs_value
end
def
normalized_jobs
@normalized_jobs
||=
Ci
::
Config
::
Normalizer
.
new
(
jobs
).
normalize_jobs
end
private
def
expand_config
(
config
)
...
...
lib/gitlab/ci/config/normalizer.rb
View file @
df17e87e
...
...
@@ -11,6 +11,7 @@ module Gitlab
end
def
normalize_jobs
return
{}
unless
@jobs_config
return
@jobs_config
if
parallelized_jobs
.
empty?
expand_parallelize_jobs
do
|
job_name
,
config
|
...
...
lib/gitlab/ci/lint.rb
View file @
df17e87e
...
...
@@ -45,14 +45,15 @@ module Gitlab
end
def
static_validation
(
content
)
result
=
Gitlab
::
Ci
::
YamlProcessor
.
new
_with_validation_errors
(
result
=
Gitlab
::
Ci
::
YamlProcessor
.
new
(
content
,
project:
@project
,
user:
@current_user
,
sha:
@project
.
repository
.
commit
.
sha
)
sha:
@project
.
repository
.
commit
.
sha
).
execute
Result
.
new
(
jobs:
static_validation_convert_to_jobs
(
result
.
config
&
.
stages
,
result
.
config
&
.
builds
),
jobs:
static_validation_convert_to_jobs
(
result
),
errors:
result
.
errors
,
warnings:
result
.
warnings
)
...
...
@@ -76,12 +77,12 @@ module Gitlab
end
end
def
static_validation_convert_to_jobs
(
stages
,
all_jobs
)
def
static_validation_convert_to_jobs
(
result
)
jobs
=
[]
return
jobs
unless
stages
||
all_jobs
return
jobs
unless
result
.
valid?
stages
.
each
do
|
stage_name
|
all_job
s
.
each
do
|
job
|
result
.
stages
.
each
do
|
stage_name
|
result
.
build
s
.
each
do
|
job
|
next
unless
job
[
:stage
]
==
stage_name
jobs
<<
{
...
...
lib/gitlab/ci/pipeline/chain/config/process.rb
View file @
df17e87e
...
...
@@ -11,20 +11,23 @@ module Gitlab
def
perform!
raise
ArgumentError
,
'missing config content'
unless
@command
.
config_content
@command
.
config_processor
=
::
Gitlab
::
Ci
::
YamlProcessor
.
new
(
result
=
::
Gitlab
::
Ci
::
YamlProcessor
.
new
(
@command
.
config_content
,
{
project:
project
,
sha:
@pipeline
.
sha
,
user:
current_user
,
parent_pipeline:
parent_pipeline
}
)
).
execute
add_warnings_to_pipeline
(
result
.
warnings
)
add_warnings_to_pipeline
(
@command
.
config_processor
.
warnings
)
rescue
Gitlab
::
Ci
::
YamlProcessor
::
ValidationError
=>
ex
add_warnings_to_pipeline
(
ex
.
warnings
)
if
result
.
valid?
@command
.
config_processor
=
result
else
error
(
result
.
errors
.
first
,
config_error:
true
)
end
error
(
ex
.
message
,
config_error:
true
)
rescue
=>
ex
Gitlab
::
ErrorTracking
.
track_exception
(
ex
,
project_id:
project
.
id
,
...
...
lib/gitlab/ci/yaml_processor.rb
View file @
df17e87e
# frozen_string_literal: true
# This is the CI Linter component that runs the syntax validations
# while parsing the YAML config into a data structure that is
# then presented to the caller as result object.
# After syntax validations (done by Ci::Config), this component also
# runs logical validation on the built data structure.
module
Gitlab
module
Ci
class
YamlProcessor
# ValidationError is treated like a result object in the form of an exception.
# We can return any warnings, raised during the config validation, along with
# the error object until we support multiple messages to be returned.
class
ValidationError
<
StandardError
attr_reader
:warnings
def
initialize
(
message
,
warnings:
[])
@warnings
=
warnings
super
(
message
)
end
end
include
Gitlab
::
Config
::
Entry
::
LegacyValidationHelpers
ValidationError
=
Class
.
new
(
StandardError
)
attr_reader
:stages
,
:jobs
def
self
.
validation_message
(
content
,
opts
=
{})
result
=
new
(
content
,
opts
).
execute
class
Resul
t
attr_reader
:config
,
:errors
,
:warnings
result
.
errors
.
firs
t
end
def
initialize
(
config:
nil
,
errors:
[],
warnings:
[])
@config
=
config
@errors
=
errors
@warnings
=
warnings
end
def
initialize
(
config_content
,
opts
=
{})
@config_content
=
config_content
@opts
=
opts
end
def
valid?
config
.
present?
&&
errors
.
empty?
def
execute
if
@config_content
.
blank?
return
Result
.
new
(
errors:
[
'Please provide content of .gitlab-ci.yml'
])
end
end
def
initialize
(
config
,
opts
=
{})
@ci_config
=
Gitlab
::
Ci
::
Config
.
new
(
config
,
**
opts
)
@config
=
@ci_config
.
to_hash
@ci_config
=
Gitlab
::
Ci
::
Config
.
new
(
@config_content
,
**
@opts
)
unless
@ci_config
.
valid?
error!
(
@ci_config
.
errors
.
first
)
return
Result
.
new
(
ci_config:
@ci_config
,
errors:
@ci_config
.
errors
,
warnings:
@ci_config
.
warnings
)
end
initial_parsing
rescue
Gitlab
::
Ci
::
Config
::
ConfigError
=>
e
error!
(
e
.
message
)
end
def
self
.
new_with_validation_errors
(
content
,
opts
=
{})
return
Result
.
new
(
errors:
[
'Please provide content of .gitlab-ci.yml'
])
if
content
.
blank?
run_logical_validations!
config
=
Gitlab
::
Ci
::
Config
.
new
(
content
,
**
opts
)
return
Result
.
new
(
errors:
config
.
errors
,
warnings:
config
.
warnings
)
unless
config
.
valid?
config
=
Gitlab
::
Ci
::
YamlProcessor
.
new
(
content
,
opts
)
Result
.
new
(
config:
config
,
warnings:
config
.
warnings
)
rescue
ValidationError
=>
e
Result
.
new
(
errors:
[
e
.
message
],
warnings:
e
.
warnings
)
Result
.
new
(
ci_config:
@ci_config
,
warnings:
@ci_config
&
.
warnings
)
rescue
Gitlab
::
Ci
::
Config
::
ConfigError
=>
e
Result
.
new
(
errors:
[
e
.
message
])
end
def
warnings
@ci_config
&
.
warnings
||
[]
end
def
builds
@jobs
.
map
do
|
name
,
_
|
build_attributes
(
name
)
end
end
def
build_attributes
(
name
)
job
=
@jobs
.
fetch
(
name
.
to_sym
,
{})
{
stage_idx:
@stages
.
index
(
job
[
:stage
]),
stage:
job
[
:stage
],
tag_list:
job
[
:tags
],
name:
job
[
:name
].
to_s
,
allow_failure:
job
[
:ignore
],
when:
job
[
:when
]
||
'on_success'
,
environment:
job
[
:environment_name
],
coverage_regex:
job
[
:coverage
],
yaml_variables:
transform_to_yaml_variables
(
job
[
:variables
]),
needs_attributes:
job
.
dig
(
:needs
,
:job
),
interruptible:
job
[
:interruptible
],
only:
job
[
:only
],
except:
job
[
:except
],
rules:
job
[
:rules
],
cache:
job
[
:cache
],
resource_group_key:
job
[
:resource_group
],
scheduling_type:
job
[
:scheduling_type
],
secrets:
job
[
:secrets
],
options:
{
image:
job
[
:image
],
services:
job
[
:services
],
artifacts:
job
[
:artifacts
],
dependencies:
job
[
:dependencies
],
cross_dependencies:
job
.
dig
(
:needs
,
:cross_dependency
),
job_timeout:
job
[
:timeout
],
before_script:
job
[
:before_script
],
script:
job
[
:script
],
after_script:
job
[
:after_script
],
environment:
job
[
:environment
],
retry:
job
[
:retry
],
parallel:
job
[
:parallel
],
instance:
job
[
:instance
],
start_in:
job
[
:start_in
],
trigger:
job
[
:trigger
],
bridge_needs:
job
.
dig
(
:needs
,
:bridge
)
&
.
first
,
release:
release
(
job
)
}.
compact
}.
compact
end
Result
.
new
(
ci_config:
@ci_config
,
errors:
[
e
.
message
],
warnings:
@ci_config
&
.
warnings
)
def
release
(
job
)
job
[
:release
]
end
def
stage_builds_attributes
(
stage
)
@jobs
.
values
.
select
{
|
job
|
job
[
:stage
]
==
stage
}
.
map
{
|
job
|
build_attributes
(
job
[
:name
])
}
end
def
stages_attributes
@stages
.
uniq
.
map
do
|
stage
|
seeds
=
stage_builds_attributes
(
stage
)
{
name:
stage
,
index:
@stages
.
index
(
stage
),
builds:
seeds
}
end
end
def
workflow_attributes
{
rules:
@config
.
dig
(
:workflow
,
:rules
),
yaml_variables:
transform_to_yaml_variables
(
@variables
)
}
end
def
self
.
validation_message
(
content
,
opts
=
{})
return
'Please provide content of .gitlab-ci.yml'
if
content
.
blank?
begin
Gitlab
::
Ci
::
YamlProcessor
.
new
(
content
,
opts
)
nil
rescue
ValidationError
=>
e
e
.
message
end
rescue
ValidationError
=>
e
Result
.
new
(
ci_config:
@ci_config
,
errors:
[
e
.
message
],
warnings:
@ci_config
&
.
warnings
)
end
private
def
initial_parsing
##
# Global config
#
@variables
=
@ci_config
.
variables
def
run_logical_validations!
@stages
=
@ci_config
.
stages
##
# Jobs
#
@jobs
=
Ci
::
Config
::
Normalizer
.
new
(
@ci_config
.
jobs
).
normalize_jobs
@jobs
=
@ci_config
.
normalized_jobs
@jobs
.
each
do
|
name
,
job
|
# logical validation for job
validate_job_stage!
(
name
,
job
)
validate_job_dependencies!
(
name
,
job
)
validate_job_needs!
(
name
,
job
)
validate_dynamic_child_pipeline_dependencies!
(
name
,
job
)
validate_job_environment!
(
name
,
job
)
validate_job!
(
name
,
job
)
end
end
def
transform_to_yaml_variables
(
variables
)
variables
.
to_h
.
map
do
|
key
,
value
|
{
key:
key
.
to_s
,
value:
value
,
public:
true
}
end
def
validate_job!
(
name
,
job
)
validate_job_stage!
(
name
,
job
)
validate_job_dependencies!
(
name
,
job
)
validate_job_needs!
(
name
,
job
)
validate_dynamic_child_pipeline_dependencies!
(
name
,
job
)
validate_job_environment!
(
name
,
job
)
end
def
validate_job_stage!
(
name
,
job
)
...
...
@@ -188,10 +70,6 @@ module Gitlab
end
end
def
error!
(
message
)
raise
ValidationError
.
new
(
message
,
warnings:
warnings
)
end
def
validate_job_dependencies!
(
name
,
job
)
return
unless
job
[
:dependencies
]
...
...
@@ -267,6 +145,10 @@ module Gitlab
error!
(
"
#{
name
}
job: on_stop job
#{
on_stop
}
needs to have action stop defined"
)
end
end
def
error!
(
message
)
raise
ValidationError
.
new
(
message
)
end
end
end
end
lib/gitlab/ci/yaml_processor/result.rb
0 → 100644
View file @
df17e87e
# frozen_string_literal: true
# A data object that wraps `Ci::Config` and any messages
# (errors, warnings) generated by the YamlProcessor.
module
Gitlab
module
Ci
class
YamlProcessor
class
Result
attr_reader
:errors
,
:warnings
def
initialize
(
ci_config:
nil
,
errors:
[],
warnings:
[])
@ci_config
=
ci_config
@errors
=
errors
||
[]
@warnings
=
warnings
||
[]
end
def
valid?
errors
.
empty?
end
def
stages_attributes
stages
.
uniq
.
map
do
|
stage
|
seeds
=
stage_builds_attributes
(
stage
)
{
name:
stage
,
index:
stages
.
index
(
stage
),
builds:
seeds
}
end
end
def
builds
jobs
.
map
do
|
name
,
_
|
build_attributes
(
name
)
end
end
def
stage_builds_attributes
(
stage
)
jobs
.
values
.
select
{
|
job
|
job
[
:stage
]
==
stage
}
.
map
{
|
job
|
build_attributes
(
job
[
:name
])
}
end
def
workflow_attributes
{
rules:
hash_config
.
dig
(
:workflow
,
:rules
),
yaml_variables:
transform_to_yaml_variables
(
variables
)
}
end
def
jobs
@jobs
||=
@ci_config
.
normalized_jobs
end
def
stages
@stages
||=
@ci_config
.
stages
end
def
build_attributes
(
name
)
job
=
jobs
.
fetch
(
name
.
to_sym
,
{})
{
stage_idx:
stages
.
index
(
job
[
:stage
]),
stage:
job
[
:stage
],
tag_list:
job
[
:tags
],
name:
job
[
:name
].
to_s
,
allow_failure:
job
[
:ignore
],
when:
job
[
:when
]
||
'on_success'
,
environment:
job
[
:environment_name
],
coverage_regex:
job
[
:coverage
],
yaml_variables:
transform_to_yaml_variables
(
job
[
:variables
]),
needs_attributes:
job
.
dig
(
:needs
,
:job
),
interruptible:
job
[
:interruptible
],
only:
job
[
:only
],
except:
job
[
:except
],
rules:
job
[
:rules
],
cache:
job
[
:cache
],
resource_group_key:
job
[
:resource_group
],
scheduling_type:
job
[
:scheduling_type
],
secrets:
job
[
:secrets
],
options:
{
image:
job
[
:image
],
services:
job
[
:services
],
artifacts:
job
[
:artifacts
],
dependencies:
job
[
:dependencies
],
cross_dependencies:
job
.
dig
(
:needs
,
:cross_dependency
),
job_timeout:
job
[
:timeout
],
before_script:
job
[
:before_script
],
script:
job
[
:script
],
after_script:
job
[
:after_script
],
environment:
job
[
:environment
],
retry:
job
[
:retry
],
parallel:
job
[
:parallel
],
instance:
job
[
:instance
],
start_in:
job
[
:start_in
],
trigger:
job
[
:trigger
],
bridge_needs:
job
.
dig
(
:needs
,
:bridge
)
&
.
first
,
release:
release
(
job
)
}.
compact
}.
compact
end
private
def
variables
@variables
||=
@ci_config
.
variables
end
def
hash_config
@hash_config
||=
@ci_config
.
to_hash
end
def
release
(
job
)
job
[
:release
]
end
def
transform_to_yaml_variables
(
variables
)
variables
.
to_h
.
map
do
|
key
,
value
|
{
key:
key
.
to_s
,
value:
value
,
public:
true
}
end
end
end
end
end
end
spec/controllers/projects/ci/lints_controller_spec.rb
View file @
df17e87e
...
...
@@ -98,7 +98,7 @@ RSpec.describe Projects::Ci::LintsController do
it_behaves_like
'returns a successful validation'
it
'runs validations through YamlProcessor'
do
expect
(
Gitlab
::
Ci
::
YamlProcessor
).
to
receive
(
:new
_with_validation_errors
).
and_call_original
expect
(
Gitlab
::
Ci
::
YamlProcessor
).
to
receive
(
:new
).
and_call_original
subject
end
...
...
@@ -126,7 +126,7 @@ RSpec.describe Projects::Ci::LintsController do
it_behaves_like
'returns a successful validation'
it
'runs validations through YamlProcessor'
do
expect
(
Gitlab
::
Ci
::
YamlProcessor
).
to
receive
(
:new
_with_validation_errors
).
and_call_original
expect
(
Gitlab
::
Ci
::
YamlProcessor
).
to
receive
(
:new
).
and_call_original
subject
end
...
...
spec/frontend/diffs/components/merge_conflict_warning_spec.js
0 → 100644
View file @
df17e87e
import
{
shallowMount
,
mount
}
from
'
@vue/test-utils
'
;
import
MergeConflictWarning
from
'
~/diffs/components/merge_conflict_warning.vue
'
;
import
{
CENTERED_LIMITED_CONTAINER_CLASSES
}
from
'
~/diffs/constants
'
;
const
propsData
=
{
limited
:
true
,
mergeable
:
true
,
resolutionPath
:
'
a-path
'
,
};
const
limitedClasses
=
CENTERED_LIMITED_CONTAINER_CLASSES
.
split
(
'
'
);
function
findResolveButton
(
wrapper
)
{
return
wrapper
.
find
(
'
.gl-alert-actions a.gl-button:first-child
'
);
}
function
findLocalMergeButton
(
wrapper
)
{
return
wrapper
.
find
(
'
.gl-alert-actions button.gl-button:last-child
'
);
}
describe
(
'
MergeConflictWarning
'
,
()
=>
{
let
wrapper
;
const
createComponent
=
(
props
=
{},
{
full
}
=
{
full
:
false
})
=>
{
const
mounter
=
full
?
mount
:
shallowMount
;
wrapper
=
mounter
(
MergeConflictWarning
,
{
propsData
:
{
...
propsData
,
...
props
},
});
};
afterEach
(()
=>
{
wrapper
.
destroy
();
});
it
.
each
`
limited | containerClasses
${
true
}
|
${
limitedClasses
}
${
false
}
|
${[]}
`
(
'
has the correct container classes when limited is $limited
'
,
({
limited
,
containerClasses
})
=>
{
createComponent
({
limited
});
expect
(
wrapper
.
classes
()).
toEqual
(
containerClasses
);
},
);
it
.
each
`
present | resolutionPath
${
false
}
|
${
''
}
${
true
}
|
${
'
some-path
'
}
`
(
'
toggles the resolve conflicts button based on the provided resolutionPath "$resolutionPath"
'
,
({
present
,
resolutionPath
})
=>
{
createComponent
({
resolutionPath
},
{
full
:
true
});
const
resolveButton
=
findResolveButton
(
wrapper
);
expect
(
resolveButton
.
exists
()).
toBe
(
present
);
if
(
present
)
{
expect
(
resolveButton
.
attributes
(
'
href
'
)).
toBe
(
resolutionPath
);
}
},
);
it
.
each
`
present | mergeable
${
false
}
|
${
false
}
${
true
}
|
${
true
}
`
(
'
toggles the local merge button based on the provided mergeable property "$mergable"
'
,
({
present
,
mergeable
})
=>
{
createComponent
({
mergeable
},
{
full
:
true
});
const
localMerge
=
findLocalMergeButton
(
wrapper
);
expect
(
localMerge
.
exists
()).
toBe
(
present
);
},
);
});
spec/lib/gitlab/ci/config/normalizer_spec.rb
View file @
df17e87e
...
...
@@ -264,5 +264,11 @@ RSpec.describe Gitlab::Ci::Config::Normalizer do
is_expected
.
to
match
(
config
)
end
end
context
'when jobs config is nil'
do
let
(
:config
)
{
nil
}
it
{
is_expected
.
to
eq
({})
}
end
end
end
spec/lib/gitlab/ci/config_spec.rb
View file @
df17e87e
...
...
@@ -312,7 +312,7 @@ RSpec.describe Gitlab::Ci::Config do
HEREDOC
end
it
'raises
error YamlProcessor validation
Error'
do
it
'raises
Config
Error'
do
expect
{
config
}.
to
raise_error
(
described_class
::
ConfigError
,
"Included file `invalid` does not have YAML extension!"
...
...
@@ -329,7 +329,7 @@ RSpec.describe Gitlab::Ci::Config do
HEREDOC
end
it
'raises
error YamlProcessor validation
Error'
do
it
'raises
Config
Error'
do
expect
{
config
}.
to
raise_error
(
described_class
::
ConfigError
,
'Include `{"remote":"http://url","local":"/local/file.yml"}` needs to match exactly one accessor!'
...
...
spec/lib/gitlab/ci/lint_spec.rb
View file @
df17e87e
...
...
@@ -157,7 +157,7 @@ RSpec.describe Gitlab::Ci::Lint do
it
'uses YamlProcessor'
do
expect
(
Gitlab
::
Ci
::
YamlProcessor
)
.
to
receive
(
:new
_with_validation_errors
)
.
to
receive
(
:new
)
.
and_call_original
subject
...
...
spec/lib/gitlab/ci/pipeline/chain/validate/external_spec.rb
View file @
df17e87e
...
...
@@ -31,20 +31,20 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Validate::External do
CI_YAML
end
let
(
:yaml_processor
)
do
let
(
:yaml_processor
_result
)
do
::
Gitlab
::
Ci
::
YamlProcessor
.
new
(
ci_yaml
,
{
project:
project
,
sha:
pipeline
.
sha
,
user:
user
}
)
)
.
execute
end
let
(
:save_incompleted
)
{
true
}
let
(
:command
)
do
Gitlab
::
Ci
::
Pipeline
::
Chain
::
Command
.
new
(
project:
project
,
current_user:
user
,
config_processor:
yaml_processor
,
save_incompleted:
save_incompleted
project:
project
,
current_user:
user
,
config_processor:
yaml_processor
_result
,
save_incompleted:
save_incompleted
)
end
...
...
spec/lib/gitlab/ci/templates/templates_spec.rb
View file @
df17e87e
...
...
@@ -3,7 +3,7 @@
require
'spec_helper'
RSpec
.
describe
'CI YML Templates'
do
subject
{
Gitlab
::
Ci
::
YamlProcessor
.
new
(
content
)
}
subject
{
Gitlab
::
Ci
::
YamlProcessor
.
new
(
content
)
.
execute
}
let
(
:all_templates
)
{
Gitlab
::
Template
::
GitlabCiYmlTemplate
.
all
.
map
(
&
:full_name
)
}
...
...
@@ -33,7 +33,7 @@ RSpec.describe 'CI YML Templates' do
end
it
'is valid'
do
expect
{
subject
}.
not_to
raise_error
expect
(
subject
).
to
be_valid
end
it
'require default stages to be included'
do
...
...
spec/lib/gitlab/ci/yaml_processor_spec.rb
View file @
df17e87e
This diff is collapsed.
Click to expand it.
spec/lib/gitlab/import_export/fast_hash_serializer_spec.rb
View file @
df17e87e
...
...
@@ -133,12 +133,6 @@ RSpec.describe Gitlab::ImportExport::FastHashSerializer do
expect
(
builds_count
).
to
eq
(
1
)
end
it
'has no when YML attributes but only the DB column'
do
expect_any_instance_of
(
Gitlab
::
Ci
::
YamlProcessor
).
not_to
receive
(
:build_attributes
)
subject
end
it
'has pipeline commits'
do
expect
(
subject
[
'ci_pipelines'
]).
not_to
be_empty
end
...
...
spec/lib/gitlab/import_export/project/tree_saver_spec.rb
View file @
df17e87e
...
...
@@ -381,12 +381,6 @@ RSpec.describe Gitlab::ImportExport::Project::TreeSaver do
expect
(
project_tree_saver
.
save
).
to
be
true
end
it
'has no when YML attributes but only the DB column'
do
expect_any_instance_of
(
Gitlab
::
Ci
::
YamlProcessor
).
not_to
receive
(
:build_attributes
)
project_tree_saver
.
save
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