Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'lib/gitlab/ci/config/entry')
-rw-r--r--lib/gitlab/ci/config/entry/artifacts.rb2
-rw-r--r--lib/gitlab/ci/config/entry/bridge.rb2
-rw-r--r--lib/gitlab/ci/config/entry/job.rb54
-rw-r--r--lib/gitlab/ci/config/entry/processable.rb20
-rw-r--r--lib/gitlab/ci/config/entry/product/matrix.rb61
-rw-r--r--lib/gitlab/ci/config/entry/product/parallel.rb57
-rw-r--r--lib/gitlab/ci/config/entry/product/variables.rb36
7 files changed, 212 insertions, 20 deletions
diff --git a/lib/gitlab/ci/config/entry/artifacts.rb b/lib/gitlab/ci/config/entry/artifacts.rb
index a9a9636637f..206dbaea272 100644
--- a/lib/gitlab/ci/config/entry/artifacts.rb
+++ b/lib/gitlab/ci/config/entry/artifacts.rb
@@ -42,7 +42,7 @@ module Gitlab
inclusion: { in: %w[on_success on_failure always],
message: 'should be on_success, on_failure ' \
'or always' }
- validates :expire_in, duration: true
+ validates :expire_in, duration: { parser: ::Gitlab::Ci::Build::Artifacts::ExpireInParser }
end
end
diff --git a/lib/gitlab/ci/config/entry/bridge.rb b/lib/gitlab/ci/config/entry/bridge.rb
index f4362d3b0ce..a8b67a1db4f 100644
--- a/lib/gitlab/ci/config/entry/bridge.rb
+++ b/lib/gitlab/ci/config/entry/bridge.rb
@@ -11,7 +11,7 @@ module Gitlab
class Bridge < ::Gitlab::Config::Entry::Node
include ::Gitlab::Ci::Config::Entry::Processable
- ALLOWED_KEYS = %i[trigger allow_failure when needs].freeze
+ ALLOWED_KEYS = %i[trigger].freeze
validations do
validates :config, allowed_keys: ALLOWED_KEYS + PROCESSABLE_ALLOWED_KEYS
diff --git a/lib/gitlab/ci/config/entry/job.rb b/lib/gitlab/ci/config/entry/job.rb
index a615cab1a80..f960cec1f26 100644
--- a/lib/gitlab/ci/config/entry/job.rb
+++ b/lib/gitlab/ci/config/entry/job.rb
@@ -11,9 +11,8 @@ module Gitlab
include ::Gitlab::Ci::Config::Entry::Processable
ALLOWED_WHEN = %w[on_success on_failure always manual delayed].freeze
- ALLOWED_KEYS = %i[tags script type image services
- allow_failure type when start_in artifacts cache
- dependencies before_script needs after_script
+ ALLOWED_KEYS = %i[tags script type image services start_in artifacts
+ cache dependencies before_script after_script
environment coverage retry parallel interruptible timeout
resource_group release secrets].freeze
@@ -23,18 +22,9 @@ module Gitlab
validates :config, allowed_keys: ALLOWED_KEYS + PROCESSABLE_ALLOWED_KEYS
validates :config, required_keys: REQUIRED_BY_NEEDS, if: :has_needs?
validates :script, presence: true
- validates :config,
- disallowed_keys: {
- in: %i[release],
- message: 'release features are not enabled'
- },
- unless: -> { Gitlab::Ci::Features.release_generation_enabled? }
with_options allow_nil: true do
validates :allow_failure, boolean: true
- validates :parallel, numericality: { only_integer: true,
- greater_than_or_equal_to: 2,
- less_than_or_equal_to: 50 }
validates :when, inclusion: {
in: ALLOWED_WHEN,
message: "should be one of: #{ALLOWED_WHEN.join(', ')}"
@@ -124,13 +114,47 @@ module Gitlab
description: 'This job will produce a release.',
inherit: false
+ entry :parallel, Entry::Product::Parallel,
+ description: 'Parallel configuration for this job.',
+ inherit: false
+
attributes :script, :tags, :allow_failure, :when, :dependencies,
:needs, :retry, :parallel, :start_in,
:interruptible, :timeout, :resource_group, :release
+ Matcher = Struct.new(:name, :config) do
+ def applies?
+ job_is_not_hidden? &&
+ config_is_a_hash? &&
+ has_job_keys?
+ end
+
+ private
+
+ def job_is_not_hidden?
+ !name.to_s.start_with?('.')
+ end
+
+ def config_is_a_hash?
+ config.is_a?(Hash)
+ end
+
+ def has_job_keys?
+ if name == :default
+ config.key?(:script)
+ else
+ (ALLOWED_KEYS & config.keys).any?
+ end
+ end
+ end
+
def self.matching?(name, config)
- !name.to_s.start_with?('.') &&
- config.is_a?(Hash) && config.key?(:script)
+ if Gitlab::Ci::Features.job_entry_matches_all_keys?
+ Matcher.new(name, config).applies?
+ else
+ !name.to_s.start_with?('.') &&
+ config.is_a?(Hash) && config.key?(:script)
+ end
end
def self.visible?
@@ -174,7 +198,7 @@ module Gitlab
environment_name: environment_defined? ? environment_value[:name] : nil,
coverage: coverage_defined? ? coverage_value : nil,
retry: retry_defined? ? retry_value : nil,
- parallel: has_parallel? ? parallel.to_i : nil,
+ parallel: has_parallel? ? parallel_value : nil,
interruptible: interruptible_defined? ? interruptible_value : nil,
timeout: has_timeout? ? ChronicDuration.parse(timeout.to_s) : nil,
artifacts: artifacts_value,
diff --git a/lib/gitlab/ci/config/entry/processable.rb b/lib/gitlab/ci/config/entry/processable.rb
index b4539475d88..f10c509d0cc 100644
--- a/lib/gitlab/ci/config/entry/processable.rb
+++ b/lib/gitlab/ci/config/entry/processable.rb
@@ -14,7 +14,8 @@ module Gitlab
include ::Gitlab::Config::Entry::Attributable
include ::Gitlab::Config::Entry::Inheritable
- PROCESSABLE_ALLOWED_KEYS = %i[extends stage only except rules variables inherit].freeze
+ PROCESSABLE_ALLOWED_KEYS = %i[extends stage only except rules variables
+ inherit allow_failure when needs].freeze
included do
validations do
@@ -82,8 +83,8 @@ module Gitlab
@entries.delete(:except) unless except_defined? # rubocop:disable Gitlab/ModuleWithInstanceVariables
end
- if has_rules? && !has_workflow_rules && Gitlab::Ci::Features.raise_job_rules_without_workflow_rules_warning?
- add_warning('uses `rules` without defining `workflow:rules`')
+ unless has_workflow_rules
+ validate_against_warnings
end
# inherit root variables
@@ -93,6 +94,19 @@ module Gitlab
end
end
+ def validate_against_warnings
+ # If rules are valid format and workflow rules are not specified
+ return unless rules_value
+ return unless Gitlab::Ci::Features.raise_job_rules_without_workflow_rules_warning?
+
+ last_rule = rules_value.last
+
+ if last_rule&.keys == [:when] && last_rule[:when] != 'never'
+ docs_url = 'read more: https://docs.gitlab.com/ee/ci/troubleshooting.html#pipeline-warnings'
+ add_warning("may allow multiple pipelines to run for a single action due to `rules:when` clause with no `workflow:rules` - #{docs_url}")
+ end
+ end
+
def name
metadata[:name]
end
diff --git a/lib/gitlab/ci/config/entry/product/matrix.rb b/lib/gitlab/ci/config/entry/product/matrix.rb
new file mode 100644
index 00000000000..6af809d46c1
--- /dev/null
+++ b/lib/gitlab/ci/config/entry/product/matrix.rb
@@ -0,0 +1,61 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ class Config
+ module Entry
+ ##
+ # Entry that represents matrix style parallel builds.
+ #
+ module Product
+ class Matrix < ::Gitlab::Config::Entry::Node
+ include ::Gitlab::Utils::StrongMemoize
+ include ::Gitlab::Config::Entry::Validatable
+ include ::Gitlab::Config::Entry::Attributable
+
+ validations do
+ validates :config, array_of_hashes: true
+
+ validate on: :composed do
+ limit = Entry::Product::Parallel::PARALLEL_LIMIT
+
+ if number_of_generated_jobs > limit
+ errors.add(:config, "generates too many jobs (maximum is #{limit})")
+ end
+ end
+ end
+
+ def compose!(deps = nil)
+ super(deps) do
+ @config.each_with_index do |variables, index|
+ @entries[index] = ::Gitlab::Config::Entry::Factory.new(Entry::Product::Variables)
+ .value(variables)
+ .with(parent: self, description: 'matrix variables definition.') # rubocop:disable CodeReuse/ActiveRecord
+ .create!
+ end
+
+ @entries.each_value do |entry|
+ entry.compose!(deps)
+ end
+ end
+ end
+
+ def value
+ strong_memoize(:value) do
+ @entries.values.map(&:value)
+ end
+ end
+
+ # rubocop:disable CodeReuse/ActiveRecord
+ def number_of_generated_jobs
+ value.sum do |config|
+ config.values.reduce(1) { |acc, values| acc * values.size }
+ end
+ end
+ # rubocop:enable CodeReuse/ActiveRecord
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/config/entry/product/parallel.rb b/lib/gitlab/ci/config/entry/product/parallel.rb
new file mode 100644
index 00000000000..cd9eabbbc66
--- /dev/null
+++ b/lib/gitlab/ci/config/entry/product/parallel.rb
@@ -0,0 +1,57 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ class Config
+ module Entry
+ ##
+ # Entry that represents a parallel job config.
+ #
+ module Product
+ class Parallel < ::Gitlab::Config::Entry::Simplifiable
+ strategy :ParallelBuilds, if: -> (config) { config.is_a?(Numeric) }
+ strategy :MatrixBuilds, if: -> (config) { config.is_a?(Hash) }
+
+ PARALLEL_LIMIT = 50
+
+ class ParallelBuilds < ::Gitlab::Config::Entry::Node
+ include ::Gitlab::Config::Entry::Validatable
+
+ validations do
+ validates :config, numericality: { only_integer: true,
+ greater_than_or_equal_to: 2,
+ less_than_or_equal_to: Entry::Product::Parallel::PARALLEL_LIMIT },
+ allow_nil: true
+ end
+
+ def value
+ { number: super.to_i }
+ end
+ end
+
+ class MatrixBuilds < ::Gitlab::Config::Entry::Node
+ include ::Gitlab::Config::Entry::Attributable
+ include ::Gitlab::Config::Entry::Configurable
+
+ PERMITTED_KEYS = %i[matrix].freeze
+
+ validations do
+ validates :config, allowed_keys: PERMITTED_KEYS
+ validates :config, required_keys: PERMITTED_KEYS
+ end
+
+ entry :matrix, Entry::Product::Matrix,
+ description: 'Variables definition for matrix builds'
+ end
+
+ class UnknownStrategy < ::Gitlab::Config::Entry::Node
+ def errors
+ ["#{location} should be an integer or a hash"]
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/config/entry/product/variables.rb b/lib/gitlab/ci/config/entry/product/variables.rb
new file mode 100644
index 00000000000..ac4f70fb69e
--- /dev/null
+++ b/lib/gitlab/ci/config/entry/product/variables.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ class Config
+ module Entry
+ ##
+ # Entry that represents variables for parallel matrix builds.
+ #
+ module Product
+ class Variables < ::Gitlab::Config::Entry::Node
+ include ::Gitlab::Config::Entry::Validatable
+
+ validations do
+ validates :config, variables: { array_values: true }
+ validates :config, length: {
+ minimum: 2,
+ too_short: 'requires at least %{count} items'
+ }
+ end
+
+ def self.default(**)
+ {}
+ end
+
+ def value
+ @config
+ .map { |key, value| [key.to_s, Array(value).map(&:to_s)] }
+ .to_h
+ end
+ end
+ end
+ end
+ end
+ end
+end