push_options.rb 1.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
# frozen_string_literal: true

module Gitlab
  class PushOptions
    VALID_OPTIONS = HashWithIndifferentAccess.new({
      merge_request: {
        keys: [:create, :target]
      },
      ci: {
        keys: [:skip]
      }
    }).freeze

    NAMESPACE_ALIASES = HashWithIndifferentAccess.new({
      mr: :merge_request
    }).freeze

    OPTION_MATCHER = /(?<namespace>[^\.]+)\.(?<key>[^=]+)=?(?<value>.*)/

    attr_reader :options

    def initialize(options = [])
      @options = parse_options(options)
    end

    def get(*args)
      options.dig(*args)
    end

30 31 32 33 34
    # Allow #to_json serialization
    def as_json(*_args)
      options
    end

35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
    private

    def parse_options(raw_options)
      options = HashWithIndifferentAccess.new

      Array.wrap(raw_options).each do |option|
        namespace, key, value = parse_option(option)

        next if [namespace, key].any?(&:nil?)

        options[namespace] ||= HashWithIndifferentAccess.new
        options[namespace][key] = value
      end

      options
    end

    def parse_option(option)
      parts = OPTION_MATCHER.match(option)
      return unless parts

      namespace, key, value = parts.values_at(:namespace, :key, :value).map(&:strip)
      namespace = NAMESPACE_ALIASES[namespace] if NAMESPACE_ALIASES[namespace]
      value = value.presence || true

      return unless valid_option?(namespace, key)

      [namespace, key, value]
    end

    def valid_option?(namespace, key)
      keys = VALID_OPTIONS.dig(namespace, :keys)
      keys && keys.include?(key.to_sym)
    end
  end
end