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/yaml')
-rw-r--r--lib/gitlab/ci/config/yaml/tags.rb13
-rw-r--r--lib/gitlab/ci/config/yaml/tags/base.rb72
-rw-r--r--lib/gitlab/ci/config/yaml/tags/reference.rb46
-rw-r--r--lib/gitlab/ci/config/yaml/tags/resolver.rb46
4 files changed, 177 insertions, 0 deletions
diff --git a/lib/gitlab/ci/config/yaml/tags.rb b/lib/gitlab/ci/config/yaml/tags.rb
new file mode 100644
index 00000000000..1575edad3b0
--- /dev/null
+++ b/lib/gitlab/ci/config/yaml/tags.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ class Config
+ module Yaml
+ module Tags
+ TagError = Class.new(StandardError)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/config/yaml/tags/base.rb b/lib/gitlab/ci/config/yaml/tags/base.rb
new file mode 100644
index 00000000000..13416a4afb6
--- /dev/null
+++ b/lib/gitlab/ci/config/yaml/tags/base.rb
@@ -0,0 +1,72 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ class Config
+ module Yaml
+ module Tags
+ class Base
+ CircularReferenceError = Class.new(Tags::TagError)
+ NotValidError = Class.new(Tags::TagError)
+
+ extend ::Gitlab::Utils::Override
+
+ attr_accessor :resolved_status, :resolved_value, :data
+
+ def self.tag
+ raise NotImplementedError
+ end
+
+ # Only one of the `seq`, `scalar`, `map` fields is available.
+ def init_with(coder)
+ @data = {
+ tag: coder.tag, # This is the custom YAML tag, like !reference or !flatten
+ style: coder.style,
+ seq: coder.seq, # This holds Array data
+ scalar: coder.scalar, # This holds data of basic types, like String.
+ map: coder.map # This holds Hash data.
+ }
+ end
+
+ def valid?
+ raise NotImplementedError
+ end
+
+ def resolve(resolver)
+ raise NotValidError, validation_error_message unless valid?
+ raise CircularReferenceError, circular_error_message if resolving?
+ return resolved_value if resolved?
+
+ self.resolved_status = :in_progress
+ self.resolved_value = _resolve(resolver)
+ self.resolved_status = :done
+ resolved_value
+ end
+
+ private
+
+ def _resolve(resolver)
+ raise NotImplementedError
+ end
+
+ def resolved?
+ resolved_status == :done
+ end
+
+ def resolving?
+ resolved_status == :in_progress
+ end
+
+ def circular_error_message
+ "#{data[:tag]} #{data[:seq].inspect} is part of a circular chain"
+ end
+
+ def validation_error_message
+ "#{data[:tag]} #{(data[:scalar].presence || data[:map].presence || data[:seq]).inspect} is not valid"
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/config/yaml/tags/reference.rb b/lib/gitlab/ci/config/yaml/tags/reference.rb
new file mode 100644
index 00000000000..22822614b67
--- /dev/null
+++ b/lib/gitlab/ci/config/yaml/tags/reference.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ class Config
+ module Yaml
+ module Tags
+ class Reference < Base
+ MissingReferenceError = Class.new(Tags::TagError)
+
+ def self.tag
+ '!reference'
+ end
+
+ override :valid?
+ def valid?
+ data[:seq].is_a?(Array) &&
+ !data[:seq].empty? &&
+ data[:seq].all? { |identifier| identifier.is_a?(String) }
+ end
+
+ private
+
+ def location
+ data[:seq].to_a.map(&:to_sym)
+ end
+
+ override :_resolve
+ def _resolve(resolver)
+ object = resolver.config.dig(*location)
+ value = resolver.deep_resolve(object)
+
+ raise MissingReferenceError, missing_ref_error_message unless value
+
+ value
+ end
+
+ def missing_ref_error_message
+ "#{data[:tag]} #{data[:seq].inspect} could not be found"
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/config/yaml/tags/resolver.rb b/lib/gitlab/ci/config/yaml/tags/resolver.rb
new file mode 100644
index 00000000000..e207ec296b6
--- /dev/null
+++ b/lib/gitlab/ci/config/yaml/tags/resolver.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ class Config
+ module Yaml
+ module Tags
+ # This class is the entry point for transforming custom YAML tags back
+ # into primitive objects.
+ # Usage: `Resolver.new(a_hash_including_custom_tag_objects).to_hash`
+ #
+ class Resolver
+ attr_reader :config
+
+ def initialize(config)
+ @config = config.deep_dup
+ end
+
+ def to_hash
+ deep_resolve(config)
+ end
+
+ def deep_resolve(object)
+ case object
+ when Array
+ object.map(&method(:resolve_wrapper))
+ when Hash
+ object.deep_transform_values(&method(:resolve_wrapper))
+ else
+ resolve_wrapper(object)
+ end
+ end
+
+ def resolve_wrapper(object)
+ if object.respond_to?(:resolve)
+ object.resolve(self)
+ else
+ object
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+end