f00db0c342
MergeRequests::PushOptionsHandlerService has been updated to allow adding and removing labels to a merge request using git push options. To create a new merge request and add 2 labels to it: git push -u origin -o merge_request.create \ -o merge_request.label="My label 1" \ -o merge_request.label="My label 2" To update an existing merge request and remove a label while adding a different label: git push -u origin -o merge_request.label="My added label" \ -o merge_request.unlabel="My removed label" Issue https://gitlab.com/gitlab-org/gitlab-ce/issues/64320
94 lines
2.1 KiB
Ruby
94 lines
2.1 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module Gitlab
|
|
class PushOptions
|
|
VALID_OPTIONS = HashWithIndifferentAccess.new({
|
|
merge_request: {
|
|
keys: [
|
|
:create,
|
|
:description,
|
|
:label,
|
|
:merge_when_pipeline_succeeds,
|
|
:remove_source_branch,
|
|
:target,
|
|
:title,
|
|
:unlabel
|
|
]
|
|
},
|
|
ci: {
|
|
keys: [:skip]
|
|
}
|
|
}).freeze
|
|
|
|
MULTI_VALUE_OPTIONS = [
|
|
%w[merge_request label],
|
|
%w[merge_request unlabel]
|
|
].freeze
|
|
|
|
NAMESPACE_ALIASES = HashWithIndifferentAccess.new({
|
|
mr: :merge_request
|
|
}).freeze
|
|
|
|
OPTION_MATCHER = /(?<namespace>[^\.]+)\.(?<key>[^=]+)=?(?<value>.*)/.freeze
|
|
|
|
attr_reader :options
|
|
|
|
def initialize(options = [])
|
|
@options = parse_options(options)
|
|
end
|
|
|
|
def get(*args)
|
|
options.dig(*args)
|
|
end
|
|
|
|
# Allow #to_json serialization
|
|
def as_json(*_args)
|
|
options
|
|
end
|
|
|
|
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
|
|
|
|
if option_multi_value?(namespace, key)
|
|
options[namespace][key] ||= HashWithIndifferentAccess.new(0)
|
|
options[namespace][key][value] += 1
|
|
else
|
|
options[namespace][key] = value
|
|
end
|
|
end
|
|
|
|
options
|
|
end
|
|
|
|
def option_multi_value?(namespace, key)
|
|
MULTI_VALUE_OPTIONS.any? { |arr| arr == [namespace, key] }
|
|
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
|