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
path: root/lib
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-07-21 15:08:33 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-07-21 15:08:33 +0300
commit6c44b676312eb6cdffadef45f9ca3e29a8cc92ab (patch)
tree06666cd369ac9ad0533cec689f2c2b4fb826f797 /lib
parentc1cea595b6a9b4d85424e9afd2cb765101ee04bf (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'lib')
-rw-r--r--lib/gitlab/ci/config/yaml/interpolator.rb6
-rw-r--r--lib/gitlab/ci/interpolation/inputs.rb70
-rw-r--r--lib/gitlab/ci/interpolation/inputs/base_input.rb92
-rw-r--r--lib/gitlab/ci/interpolation/inputs/string_input.rb31
4 files changed, 198 insertions, 1 deletions
diff --git a/lib/gitlab/ci/config/yaml/interpolator.rb b/lib/gitlab/ci/config/yaml/interpolator.rb
index d8c81bf8b98..bb6c3215661 100644
--- a/lib/gitlab/ci/config/yaml/interpolator.rb
+++ b/lib/gitlab/ci/config/yaml/interpolator.rb
@@ -73,7 +73,11 @@ module Gitlab
end
def inputs
- @inputs ||= Ci::Input::Inputs.new(spec, args)
+ @inputs ||= if Feature.enabled?(:ci_interpolation_inputs_refactor)
+ Ci::Interpolation::Inputs.new(spec, args)
+ else
+ Ci::Input::Inputs.new(spec, args)
+ end
end
def context
diff --git a/lib/gitlab/ci/interpolation/inputs.rb b/lib/gitlab/ci/interpolation/inputs.rb
new file mode 100644
index 00000000000..910606e6ab2
--- /dev/null
+++ b/lib/gitlab/ci/interpolation/inputs.rb
@@ -0,0 +1,70 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ module Interpolation
+ # Interpolation inputs provided by the user.
+ class Inputs
+ UnknownInputTypeError = Class.new(StandardError)
+
+ TYPES = [
+ StringInput
+ ].freeze
+
+ def initialize(specs, args)
+ @specs = specs.to_h
+ @args = args.to_h
+ @inputs = []
+ @errors = []
+
+ validate!
+ fabricate!
+ end
+
+ def errors
+ @errors + @inputs.flat_map(&:errors)
+ end
+
+ def valid?
+ errors.none?
+ end
+
+ def to_hash
+ @inputs.inject({}) do |hash, input|
+ hash.merge(input.to_hash)
+ end
+ end
+
+ private
+
+ def validate!
+ unknown_inputs = @args.keys - @specs.keys
+ return if unknown_inputs.empty?
+
+ @errors.push("unknown input arguments: #{unknown_inputs.join(', ')}")
+ end
+
+ def fabricate!
+ @specs.each do |input_name, spec|
+ input_type = TYPES.find { |klass| klass.matches?(spec) }
+
+ unless input_type
+ @errors.push(
+ "unknown input specification for `#{input_name}` (valid types: #{valid_type_names.join(', ')})")
+ next
+ end
+
+ @inputs.push(input_type.new(
+ name: input_name,
+ spec: spec,
+ value: @args[input_name]))
+ end
+ end
+
+ def valid_type_names
+ TYPES.map(&:type_name)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/interpolation/inputs/base_input.rb b/lib/gitlab/ci/interpolation/inputs/base_input.rb
new file mode 100644
index 00000000000..20b9bfacb17
--- /dev/null
+++ b/lib/gitlab/ci/interpolation/inputs/base_input.rb
@@ -0,0 +1,92 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ module Interpolation
+ class Inputs
+ ##
+ # This is a common abstraction for all input types
+ class BaseInput
+ ArgumentNotValidError = Class.new(StandardError)
+
+ # Checks whether the class matches the type in the specification
+ def self.matches?(spec)
+ raise NotImplementedError
+ end
+
+ # Human readable type used in error messages
+ def self.type_name
+ raise NotImplementedError
+ end
+
+ # Checks whether the provided value is of the given type
+ def valid_value?(value)
+ raise NotImplementedError
+ end
+
+ attr_reader :errors, :name, :spec, :value
+
+ def initialize(name:, spec:, value:)
+ @name = name
+ @errors = []
+
+ # Treat minimal spec definition (nil) as a valid hash:
+ # spec:
+ # inputs:
+ # website:
+ @spec = spec || {} # specification from input definition
+ @value = value # actual value provided by the user
+
+ validate!
+ end
+
+ def to_hash
+ raise ArgumentNotValidError unless valid?
+
+ { name => actual_value }
+ end
+
+ def valid?
+ @errors.none?
+ end
+
+ private
+
+ def validate!
+ return error('required value has not been provided') if required_input? && value.nil?
+
+ # validate default value
+ return error("default value is not a #{self.class.type_name}") if !required_input? && !valid_value?(default)
+
+ # validate provided value
+ error("provided value is not a #{self.class.type_name}") unless valid_value?(value)
+ end
+
+ def error(message)
+ @errors.push("`#{name}` input: #{message}")
+ end
+
+ def actual_value
+ # nil check is to support boolean values.
+ value.nil? ? default : value
+ end
+
+ # An input specification without a default value is required.
+ # For example:
+ # ```yaml
+ # spec:
+ # inputs:
+ # website:
+ # ```
+ def required_input?
+ !spec.key?(:default)
+ end
+
+ def default
+ spec[:default]
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/interpolation/inputs/string_input.rb b/lib/gitlab/ci/interpolation/inputs/string_input.rb
new file mode 100644
index 00000000000..7a042964cbb
--- /dev/null
+++ b/lib/gitlab/ci/interpolation/inputs/string_input.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ module Interpolation
+ class Inputs
+ class StringInput < BaseInput
+ def self.matches?(spec)
+ # The input spec can be `nil` when using a minimal specification
+ # and also when `type` is not specified.
+ #
+ # ```yaml
+ # spec:
+ # inputs:
+ # foo:
+ # ```
+ spec.nil? || (spec.is_a?(Hash) && [nil, type_name].include?(spec[:type]))
+ end
+
+ def self.type_name
+ 'string'
+ end
+
+ def valid_value?(value)
+ value.nil? || value.is_a?(String)
+ end
+ end
+ end
+ end
+ end
+end