From e8d2c2579383897a1dd7f9debd359abe8ae8373d Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Tue, 20 Jul 2021 09:55:51 +0000 Subject: Add latest changes from gitlab-org/gitlab@14-1-stable-ee --- lib/api/helpers/caching.rb | 107 +---- lib/api/helpers/groups_helpers.rb | 4 + lib/api/helpers/integrations_helpers.rb | 822 ++++++++++++++++++++++++++++++++ lib/api/helpers/projects_helpers.rb | 2 + lib/api/helpers/runner.rb | 4 + lib/api/helpers/services_helpers.rb | 822 -------------------------------- lib/api/helpers/snippets_helpers.rb | 18 +- 7 files changed, 859 insertions(+), 920 deletions(-) create mode 100644 lib/api/helpers/integrations_helpers.rb delete mode 100644 lib/api/helpers/services_helpers.rb (limited to 'lib/api/helpers') diff --git a/lib/api/helpers/caching.rb b/lib/api/helpers/caching.rb index f24ac7302c1..f567d85443f 100644 --- a/lib/api/helpers/caching.rb +++ b/lib/api/helpers/caching.rb @@ -8,18 +8,15 @@ module API module Helpers module Caching - # @return [ActiveSupport::Duration] - DEFAULT_EXPIRY = 1.day - + include Gitlab::Cache::Helpers # @return [Hash] DEFAULT_CACHE_OPTIONS = { - race_condition_ttl: 5.seconds + race_condition_ttl: 5.seconds, + version: 1 }.freeze - # @return [ActiveSupport::Cache::Store] - def cache - Rails.cache - end + # @return [Array] + PAGINATION_HEADERS = %w[X-Per-Page X-Page X-Next-Page X-Prev-Page Link X-Total X-Total-Pages].freeze # This is functionally equivalent to the standard `#present` used in # Grape endpoints, but the JSON for the object, or for each object of @@ -45,7 +42,7 @@ module API # @param expires_in [ActiveSupport::Duration, Integer] an expiry time for the cache entry # @param presenter_args [Hash] keyword arguments to be passed to the entity # @return [Gitlab::Json::PrecompiledJson] - def present_cached(obj_or_collection, with:, cache_context: -> (_) { current_user&.cache_key }, expires_in: DEFAULT_EXPIRY, **presenter_args) + def present_cached(obj_or_collection, with:, cache_context: -> (_) { current_user&.cache_key }, expires_in: Gitlab::Cache::Helpers::DEFAULT_EXPIRY, **presenter_args) json = if obj_or_collection.is_a?(Enumerable) cached_collection( @@ -79,15 +76,22 @@ module API # @param key [Object] any object that can be converted into a cache key # @param expires_in [ActiveSupport::Duration, Integer] an expiry time for the cache entry # @return [Gitlab::Json::PrecompiledJson] - def cache_action(key, **cache_opts) - json = cache.fetch(key, **apply_default_cache_options(cache_opts)) do + def cache_action(key, **custom_cache_opts) + cache_opts = apply_default_cache_options(custom_cache_opts) + + json, cached_headers = cache.fetch(key, **cache_opts) do response = yield - if response.is_a?(Gitlab::Json::PrecompiledJson) - response.to_s - else - Gitlab::Json.dump(response.as_json) - end + cached_body = response.is_a?(Gitlab::Json::PrecompiledJson) ? response.to_s : Gitlab::Json.dump(response.as_json) + cached_headers = header.slice(*PAGINATION_HEADERS) + + [cached_body, cached_headers] + end + + cached_headers.each do |key, value| + next if header.key?(key) + + header key, value end body Gitlab::Json::PrecompiledJson.new(json) @@ -120,77 +124,6 @@ module API def apply_default_cache_options(opts = {}) DEFAULT_CACHE_OPTIONS.merge(opts) end - - # Optionally uses a `Proc` to add context to a cache key - # - # @param object [Object] must respond to #cache_key - # @param context [Proc] a proc that will be called with the object as an argument, and which should return a - # string or array of strings to be combined into the cache key - # @return [String] - def contextual_cache_key(object, context) - return object.cache_key if context.nil? - - [object.cache_key, context.call(object)].flatten.join(":") - end - - # Used for fetching or rendering a single object - # - # @param object [Object] the object to render - # @param presenter [Grape::Entity] - # @param presenter_args [Hash] keyword arguments to be passed to the entity - # @param context [Proc] - # @param expires_in [ActiveSupport::Duration, Integer] an expiry time for the cache entry - # @return [String] - def cached_object(object, presenter:, presenter_args:, context:, expires_in:) - cache.fetch(contextual_cache_key(object, context), expires_in: expires_in) do - Gitlab::Json.dump(presenter.represent(object, **presenter_args).as_json) - end - end - - # Used for fetching or rendering multiple objects - # - # @param objects [Enumerable] the objects to render - # @param presenter [Grape::Entity] - # @param presenter_args [Hash] keyword arguments to be passed to the entity - # @param context [Proc] - # @param expires_in [ActiveSupport::Duration, Integer] an expiry time for the cache entry - # @return [Array] - def cached_collection(collection, presenter:, presenter_args:, context:, expires_in:) - json = fetch_multi(collection, context: context, expires_in: expires_in) do |obj| - Gitlab::Json.dump(presenter.represent(obj, **presenter_args).as_json) - end - - json.values - end - - # An adapted version of ActiveSupport::Cache::Store#fetch_multi. - # - # The original method only provides the missing key to the block, - # not the missing object, so we have to create a map of cache keys - # to the objects to allow us to pass the object to the missing value - # block. - # - # The result is that this is functionally identical to `#fetch`. - def fetch_multi(*objs, context:, **kwargs) - objs.flatten! - map = multi_key_map(objs, context: context) - - # TODO: `contextual_cache_key` should be constructed based on the guideline https://docs.gitlab.com/ee/development/redis.html#multi-key-commands. - Gitlab::Instrumentation::RedisClusterValidator.allow_cross_slot_commands do - cache.fetch_multi(*map.keys, **kwargs) do |key| - yield map[key] - end - end - end - - # @param objects [Enumerable] objects which _must_ respond to `#cache_key` - # @param context [Proc] a proc that can be called to help generate each cache key - # @return [Hash] - def multi_key_map(objects, context:) - objects.index_by do |object| - contextual_cache_key(object, context) - end - end end end end diff --git a/lib/api/helpers/groups_helpers.rb b/lib/api/helpers/groups_helpers.rb index 5c5109f3d21..e38213532ba 100644 --- a/lib/api/helpers/groups_helpers.rb +++ b/lib/api/helpers/groups_helpers.rb @@ -30,6 +30,10 @@ module API params :optional_params_ee do end + params :optional_update_params do + optional :prevent_sharing_groups_outside_hierarchy, type: Boolean, desc: 'Prevent sharing groups within this namespace with any groups outside the namespace. Only available on top-level groups.' + end + params :optional_update_params_ee do end diff --git a/lib/api/helpers/integrations_helpers.rb b/lib/api/helpers/integrations_helpers.rb new file mode 100644 index 00000000000..06539772568 --- /dev/null +++ b/lib/api/helpers/integrations_helpers.rb @@ -0,0 +1,822 @@ +# frozen_string_literal: true + +module API + module Helpers + # Helpers module for API::Services + # + # The data structures inside this model are returned using class methods, + # allowing EE to extend them where necessary. + module IntegrationsHelpers + def self.chat_notification_settings + [ + { + required: true, + name: :webhook, + type: String, + desc: 'The chat webhook' + }, + { + required: false, + name: :username, + type: String, + desc: 'The chat username' + }, + { + required: false, + name: :channel, + type: String, + desc: 'The default chat channel' + }, + { + required: false, + name: :branches_to_be_notified, + type: String, + desc: 'Branches for which notifications are to be sent' + } + ].freeze + end + + def self.chat_notification_flags + [ + { + required: false, + name: :notify_only_broken_pipelines, + type: Boolean, + desc: 'Send notifications for broken pipelines' + } + ].freeze + end + + def self.chat_notification_channels + [ + { + required: false, + name: :push_channel, + type: String, + desc: 'The name of the channel to receive push_events notifications' + }, + { + required: false, + name: :issue_channel, + type: String, + desc: 'The name of the channel to receive issues_events notifications' + }, + { + required: false, + name: :confidential_issue_channel, + type: String, + desc: 'The name of the channel to receive confidential_issues_events notifications' + }, + { + required: false, + name: :merge_request_channel, + type: String, + desc: 'The name of the channel to receive merge_requests_events notifications' + }, + { + required: false, + name: :note_channel, + type: String, + desc: 'The name of the channel to receive note_events notifications' + }, + { + required: false, + name: :tag_push_channel, + type: String, + desc: 'The name of the channel to receive tag_push_events notifications' + }, + { + required: false, + name: :pipeline_channel, + type: String, + desc: 'The name of the channel to receive pipeline_events notifications' + }, + { + required: false, + name: :wiki_page_channel, + type: String, + desc: 'The name of the channel to receive wiki_page_events notifications' + } + ].freeze + end + + def self.chat_notification_events + [ + { + required: false, + name: :push_events, + type: Boolean, + desc: 'Enable notifications for push_events' + }, + { + required: false, + name: :issues_events, + type: Boolean, + desc: 'Enable notifications for issues_events' + }, + { + required: false, + name: :confidential_issues_events, + type: Boolean, + desc: 'Enable notifications for confidential_issues_events' + }, + { + required: false, + name: :merge_requests_events, + type: Boolean, + desc: 'Enable notifications for merge_requests_events' + }, + { + required: false, + name: :note_events, + type: Boolean, + desc: 'Enable notifications for note_events' + }, + { + required: false, + name: :confidential_note_events, + type: Boolean, + desc: 'Enable notifications for confidential_note_events' + }, + { + required: false, + name: :tag_push_events, + type: Boolean, + desc: 'Enable notifications for tag_push_events' + }, + { + required: false, + name: :pipeline_events, + type: Boolean, + desc: 'Enable notifications for pipeline_events' + }, + { + required: false, + name: :wiki_page_events, + type: Boolean, + desc: 'Enable notifications for wiki_page_events' + } + ].freeze + end + + def self.integrations + { + 'asana' => [ + { + required: true, + name: :api_key, + type: String, + desc: 'User API token' + }, + { + required: false, + name: :restrict_to_branch, + type: String, + desc: 'Comma-separated list of branches which will be automatically inspected. Leave blank to include all branches' + } + ], + 'assembla' => [ + { + required: true, + name: :token, + type: String, + desc: 'The authentication token' + }, + { + required: false, + name: :subdomain, + type: String, + desc: 'Subdomain setting' + } + ], + 'bamboo' => [ + { + required: true, + name: :bamboo_url, + type: String, + desc: 'Bamboo root URL like https://bamboo.example.com' + }, + { + required: true, + name: :build_key, + type: String, + desc: 'Bamboo build plan key like' + }, + { + required: true, + name: :username, + type: String, + desc: 'A user with API access, if applicable' + }, + { + required: true, + name: :password, + type: String, + desc: 'Password of the user' + } + ], + 'bugzilla' => [ + { + required: true, + name: :new_issue_url, + type: String, + desc: 'New issue URL' + }, + { + required: true, + name: :issues_url, + type: String, + desc: 'Issues URL' + }, + { + required: true, + name: :project_url, + type: String, + desc: 'Project URL' + } + ], + 'buildkite' => [ + { + required: true, + name: :token, + type: String, + desc: 'Buildkite project GitLab token' + }, + { + required: true, + name: :project_url, + type: String, + desc: 'The Buildkite pipeline URL' + }, + { + required: false, + name: :enable_ssl_verification, + type: Boolean, + desc: 'DEPRECATED: This parameter has no effect since SSL verification will always be enabled' + } + ], + 'campfire' => [ + { + required: true, + name: :token, + type: String, + desc: 'Campfire token' + }, + { + required: false, + name: :subdomain, + type: String, + desc: 'Campfire subdomain' + }, + { + required: false, + name: :room, + type: String, + desc: 'Campfire room' + } + ], + 'confluence' => [ + { + required: true, + name: :confluence_url, + type: String, + desc: 'The URL of the Confluence Cloud Workspace hosted on atlassian.net' + } + ], + 'custom-issue-tracker' => [ + { + required: true, + name: :new_issue_url, + type: String, + desc: 'New issue URL' + }, + { + required: true, + name: :issues_url, + type: String, + desc: 'Issues URL' + }, + { + required: true, + name: :project_url, + type: String, + desc: 'Project URL' + } + ], + 'datadog' => [ + { + required: true, + name: :api_key, + type: String, + desc: 'API key used for authentication with Datadog' + }, + { + required: false, + name: :datadog_site, + type: String, + desc: 'Choose the Datadog site to send data to. Set to "datadoghq.eu" to send data to the EU site' + }, + { + required: false, + name: :api_url, + type: String, + desc: '(Advanced) Define the full URL for your Datadog site directly' + }, + { + required: false, + name: :datadog_service, + type: String, + desc: 'Name of this GitLab instance that all data will be tagged with' + }, + { + required: false, + name: :datadog_env, + type: String, + desc: 'The environment tag that traces will be tagged with' + } + ], + 'discord' => [ + { + required: true, + name: :webhook, + type: String, + desc: 'Discord webhook. e.g. https://discordapp.com/api/webhooks/…' + } + ], + 'drone-ci' => [ + { + required: true, + name: :token, + type: String, + desc: 'Drone CI token' + }, + { + required: true, + name: :drone_url, + type: String, + desc: 'Drone CI URL' + }, + { + required: false, + name: :enable_ssl_verification, + type: Boolean, + desc: 'Enable SSL verification for communication' + } + ], + 'emails-on-push' => [ + { + required: true, + name: :recipients, + type: String, + desc: 'Comma-separated list of recipient email addresses' + }, + { + required: false, + name: :disable_diffs, + type: Boolean, + desc: 'Disable code diffs' + }, + { + required: false, + name: :send_from_committer_email, + type: Boolean, + desc: 'Send from committer' + }, + { + required: false, + name: :branches_to_be_notified, + type: String, + desc: 'Branches for which notifications are to be sent' + } + ], + 'external-wiki' => [ + { + required: true, + name: :external_wiki_url, + type: String, + desc: 'The URL of the external wiki' + } + ], + 'flowdock' => [ + { + required: true, + name: :token, + type: String, + desc: 'Flowdock token' + } + ], + 'hangouts-chat' => [ + { + required: true, + name: :webhook, + type: String, + desc: 'The Hangouts Chat webhook. e.g. https://chat.googleapis.com/v1/spaces…' + }, + { + required: false, + name: :branches_to_be_notified, + type: String, + desc: 'Branches for which notifications are to be sent' + }, + chat_notification_events + ].flatten, + 'irker' => [ + { + required: true, + name: :recipients, + type: String, + desc: 'Recipients/channels separated by whitespaces' + }, + { + required: false, + name: :default_irc_uri, + type: String, + desc: 'Default: irc://irc.network.net:6697' + }, + { + required: false, + name: :server_host, + type: String, + desc: 'Server host. Default localhost' + }, + { + required: false, + name: :server_port, + type: Integer, + desc: 'Server port. Default 6659' + }, + { + required: false, + name: :colorize_messages, + type: Boolean, + desc: 'Colorize messages' + } + ], + 'jenkins' => [ + { + required: true, + name: :jenkins_url, + type: String, + desc: 'Jenkins root URL like https://jenkins.example.com' + }, + { + required: true, + name: :project_name, + type: String, + desc: 'The URL-friendly project name. Example: my_project_name' + }, + { + required: false, + name: :username, + type: String, + desc: 'A user with access to the Jenkins server, if applicable' + }, + { + required: false, + name: :password, + type: String, + desc: 'The password of the user' + } + ], + 'jira' => [ + { + required: true, + name: :url, + type: String, + desc: 'The base URL to the Jira instance web interface which is being linked to this GitLab project. E.g., https://jira.example.com' + }, + { + required: false, + name: :api_url, + type: String, + desc: 'The base URL to the Jira instance API. Web URL value will be used if not set. E.g., https://jira-api.example.com' + }, + { + required: true, + name: :username, + type: String, + desc: 'The username of the user created to be used with GitLab/Jira' + }, + { + required: true, + name: :password, + type: String, + desc: 'The password of the user created to be used with GitLab/Jira' + }, + { + required: false, + name: :jira_issue_transition_automatic, + type: Boolean, + desc: 'Enable automatic issue transitions' + }, + { + required: false, + name: :jira_issue_transition_id, + type: String, + desc: 'The ID of one or more transitions for custom issue transitions' + }, + { + required: false, + name: :comment_on_event_enabled, + type: Boolean, + desc: 'Enable comments inside Jira issues on each GitLab event (commit / merge request)' + } + ], + 'mattermost-slash-commands' => [ + { + required: true, + name: :token, + type: String, + desc: 'The Mattermost token' + } + ], + 'slack-slash-commands' => [ + { + required: true, + name: :token, + type: String, + desc: 'The Slack token' + } + ], + 'packagist' => [ + { + required: true, + name: :username, + type: String, + desc: 'The username' + }, + { + required: true, + name: :token, + type: String, + desc: 'The Packagist API token' + }, + { + required: false, + name: :server, + type: String, + desc: 'The server' + } + ], + 'pipelines-email' => [ + { + required: true, + name: :recipients, + type: String, + desc: 'Comma-separated list of recipient email addresses' + }, + { + required: false, + name: :notify_only_broken_pipelines, + type: Boolean, + desc: 'Notify only broken pipelines' + }, + { + required: false, + name: :branches_to_be_notified, + type: String, + desc: 'Branches for which notifications are to be sent' + } + ], + 'pivotaltracker' => [ + { + required: true, + name: :token, + type: String, + desc: 'The Pivotaltracker token' + }, + { + required: false, + name: :restrict_to_branch, + type: String, + desc: 'Comma-separated list of branches which will be automatically inspected. Leave blank to include all branches.' + } + ], + 'prometheus' => [ + { + required: true, + name: :api_url, + type: String, + desc: 'Prometheus API Base URL, like http://prometheus.example.com/' + }, + { + required: true, + name: :google_iap_audience_client_id, + type: String, + desc: 'Client ID of the IAP-secured resource (looks like IAP_CLIENT_ID.apps.googleusercontent.com)' + }, + { + required: true, + name: :google_iap_service_account_json, + type: String, + desc: 'Contents of the credentials.json file of your service account, like: { "type": "service_account", "project_id": ... }' + } + ], + 'pushover' => [ + { + required: true, + name: :api_key, + type: String, + desc: 'The application key' + }, + { + required: true, + name: :user_key, + type: String, + desc: 'The user key' + }, + { + required: true, + name: :priority, + type: String, + desc: 'The priority' + }, + { + required: true, + name: :device, + type: String, + desc: 'Leave blank for all active devices' + }, + { + required: true, + name: :sound, + type: String, + desc: 'The sound of the notification' + } + ], + 'redmine' => [ + { + required: true, + name: :new_issue_url, + type: String, + desc: 'The new issue URL' + }, + { + required: true, + name: :project_url, + type: String, + desc: 'The project URL' + }, + { + required: true, + name: :issues_url, + type: String, + desc: 'The issues URL' + } + ], + 'ewm' => [ + { + required: true, + name: :new_issue_url, + type: String, + desc: 'New Issue URL' + }, + { + required: true, + name: :project_url, + type: String, + desc: 'Project URL' + }, + { + required: true, + name: :issues_url, + type: String, + desc: 'Issues URL' + } + ], + 'youtrack' => [ + { + required: true, + name: :project_url, + type: String, + desc: 'The project URL' + }, + { + required: true, + name: :issues_url, + type: String, + desc: 'The issues URL' + } + ], + 'slack' => [ + chat_notification_settings, + chat_notification_flags, + chat_notification_channels, + chat_notification_events + ].flatten, + 'microsoft-teams' => [ + { + required: true, + name: :webhook, + type: String, + desc: 'The Microsoft Teams webhook. e.g. https://outlook.office.com/webhook/…' + }, + { + required: false, + name: :branches_to_be_notified, + type: String, + desc: 'Branches for which notifications are to be sent' + }, + chat_notification_flags + ].flatten, + 'mattermost' => [ + chat_notification_settings, + chat_notification_flags, + chat_notification_channels, + chat_notification_events + ].flatten, + 'teamcity' => [ + { + required: true, + name: :teamcity_url, + type: String, + desc: 'TeamCity root URL like https://teamcity.example.com' + }, + { + required: true, + name: :build_type, + type: String, + desc: 'Build configuration ID' + }, + { + required: true, + name: :username, + type: String, + desc: 'A user with permissions to trigger a manual build' + }, + { + required: true, + name: :password, + type: String, + desc: 'The password of the user' + } + ], + 'unify-circuit' => [ + { + required: true, + name: :webhook, + type: String, + desc: 'The Unify Circuit webhook. e.g. https://circuit.com/rest/v2/webhooks/incoming/…' + }, + chat_notification_events + ].flatten, + 'webex-teams' => [ + { + required: true, + name: :webhook, + type: String, + desc: 'The Webex Teams webhook. For example, https://api.ciscospark.com/v1/webhooks/incoming/...' + }, + chat_notification_events + ].flatten + } + end + + def self.integration_classes + [ + ::Integrations::Asana, + ::Integrations::Assembla, + ::Integrations::Bamboo, + ::Integrations::Bugzilla, + ::Integrations::Buildkite, + ::Integrations::Campfire, + ::Integrations::Confluence, + ::Integrations::CustomIssueTracker, + ::Integrations::Datadog, + ::Integrations::Discord, + ::Integrations::DroneCi, + ::Integrations::EmailsOnPush, + ::Integrations::Ewm, + ::Integrations::ExternalWiki, + ::Integrations::Flowdock, + ::Integrations::HangoutsChat, + ::Integrations::Irker, + ::Integrations::Jenkins, + ::Integrations::Jira, + ::Integrations::Mattermost, + ::Integrations::MattermostSlashCommands, + ::Integrations::MicrosoftTeams, + ::Integrations::Packagist, + ::Integrations::PipelinesEmail, + ::Integrations::Pivotaltracker, + ::Integrations::Prometheus, + ::Integrations::Pushover, + ::Integrations::Redmine, + ::Integrations::Slack, + ::Integrations::SlackSlashCommands, + ::Integrations::Teamcity, + ::Integrations::Youtrack + ] + end + + def self.development_integration_classes + [ + ::Integrations::MockCi, + ::Integrations::MockMonitoring + ] + end + end + end +end + +API::Helpers::IntegrationsHelpers.prepend_mod_with('API::Helpers::IntegrationsHelpers') diff --git a/lib/api/helpers/projects_helpers.rb b/lib/api/helpers/projects_helpers.rb index 69a83043617..272452bd8db 100644 --- a/lib/api/helpers/projects_helpers.rb +++ b/lib/api/helpers/projects_helpers.rb @@ -66,6 +66,7 @@ module API optional :autoclose_referenced_issues, type: Boolean, desc: 'Flag indication if referenced issues auto-closing is enabled' optional :repository_storage, type: String, desc: 'Which storage shard the repository is on. Available only to admins' optional :packages_enabled, type: Boolean, desc: 'Enable project packages feature' + optional :squash_option, type: String, values: %w(never always default_on default_off), desc: 'Squash default for project. One of `never`, `always`, `default_on`, or `default_off`.' end params :optional_project_params_ee do @@ -145,6 +146,7 @@ module API :request_access_enabled, :resolve_outdated_diff_discussions, :restrict_user_defined_variables, + :squash_option, :shared_runners_enabled, :snippets_access_level, :tag_list, diff --git a/lib/api/helpers/runner.rb b/lib/api/helpers/runner.rb index 9ec9b5e1e35..a022d1a56ac 100644 --- a/lib/api/helpers/runner.rb +++ b/lib/api/helpers/runner.rb @@ -14,6 +14,10 @@ module API ActiveSupport::SecurityUtils.secure_compare(params[:token], Gitlab::CurrentSettings.runners_registration_token) end + def runner_registrar_valid?(type) + Feature.disabled?(:runner_registration_control) || Gitlab::CurrentSettings.valid_runner_registrars.include?(type) + end + def authenticate_runner! forbidden! unless current_runner diff --git a/lib/api/helpers/services_helpers.rb b/lib/api/helpers/services_helpers.rb deleted file mode 100644 index ca13ea0789a..00000000000 --- a/lib/api/helpers/services_helpers.rb +++ /dev/null @@ -1,822 +0,0 @@ -# frozen_string_literal: true - -module API - module Helpers - # Helpers module for API::Services - # - # The data structures inside this model are returned using class methods, - # allowing EE to extend them where necessary. - module ServicesHelpers - def self.chat_notification_settings - [ - { - required: true, - name: :webhook, - type: String, - desc: 'The chat webhook' - }, - { - required: false, - name: :username, - type: String, - desc: 'The chat username' - }, - { - required: false, - name: :channel, - type: String, - desc: 'The default chat channel' - }, - { - required: false, - name: :branches_to_be_notified, - type: String, - desc: 'Branches for which notifications are to be sent' - } - ].freeze - end - - def self.chat_notification_flags - [ - { - required: false, - name: :notify_only_broken_pipelines, - type: Boolean, - desc: 'Send notifications for broken pipelines' - } - ].freeze - end - - def self.chat_notification_channels - [ - { - required: false, - name: :push_channel, - type: String, - desc: 'The name of the channel to receive push_events notifications' - }, - { - required: false, - name: :issue_channel, - type: String, - desc: 'The name of the channel to receive issues_events notifications' - }, - { - required: false, - name: :confidential_issue_channel, - type: String, - desc: 'The name of the channel to receive confidential_issues_events notifications' - }, - { - required: false, - name: :merge_request_channel, - type: String, - desc: 'The name of the channel to receive merge_requests_events notifications' - }, - { - required: false, - name: :note_channel, - type: String, - desc: 'The name of the channel to receive note_events notifications' - }, - { - required: false, - name: :tag_push_channel, - type: String, - desc: 'The name of the channel to receive tag_push_events notifications' - }, - { - required: false, - name: :pipeline_channel, - type: String, - desc: 'The name of the channel to receive pipeline_events notifications' - }, - { - required: false, - name: :wiki_page_channel, - type: String, - desc: 'The name of the channel to receive wiki_page_events notifications' - } - ].freeze - end - - def self.chat_notification_events - [ - { - required: false, - name: :push_events, - type: Boolean, - desc: 'Enable notifications for push_events' - }, - { - required: false, - name: :issues_events, - type: Boolean, - desc: 'Enable notifications for issues_events' - }, - { - required: false, - name: :confidential_issues_events, - type: Boolean, - desc: 'Enable notifications for confidential_issues_events' - }, - { - required: false, - name: :merge_requests_events, - type: Boolean, - desc: 'Enable notifications for merge_requests_events' - }, - { - required: false, - name: :note_events, - type: Boolean, - desc: 'Enable notifications for note_events' - }, - { - required: false, - name: :confidential_note_events, - type: Boolean, - desc: 'Enable notifications for confidential_note_events' - }, - { - required: false, - name: :tag_push_events, - type: Boolean, - desc: 'Enable notifications for tag_push_events' - }, - { - required: false, - name: :pipeline_events, - type: Boolean, - desc: 'Enable notifications for pipeline_events' - }, - { - required: false, - name: :wiki_page_events, - type: Boolean, - desc: 'Enable notifications for wiki_page_events' - } - ].freeze - end - - def self.services - { - 'asana' => [ - { - required: true, - name: :api_key, - type: String, - desc: 'User API token' - }, - { - required: false, - name: :restrict_to_branch, - type: String, - desc: 'Comma-separated list of branches which will be automatically inspected. Leave blank to include all branches' - } - ], - 'assembla' => [ - { - required: true, - name: :token, - type: String, - desc: 'The authentication token' - }, - { - required: false, - name: :subdomain, - type: String, - desc: 'Subdomain setting' - } - ], - 'bamboo' => [ - { - required: true, - name: :bamboo_url, - type: String, - desc: 'Bamboo root URL like https://bamboo.example.com' - }, - { - required: true, - name: :build_key, - type: String, - desc: 'Bamboo build plan key like' - }, - { - required: true, - name: :username, - type: String, - desc: 'A user with API access, if applicable' - }, - { - required: true, - name: :password, - type: String, - desc: 'Password of the user' - } - ], - 'bugzilla' => [ - { - required: true, - name: :new_issue_url, - type: String, - desc: 'New issue URL' - }, - { - required: true, - name: :issues_url, - type: String, - desc: 'Issues URL' - }, - { - required: true, - name: :project_url, - type: String, - desc: 'Project URL' - } - ], - 'buildkite' => [ - { - required: true, - name: :token, - type: String, - desc: 'Buildkite project GitLab token' - }, - { - required: true, - name: :project_url, - type: String, - desc: 'The Buildkite pipeline URL' - }, - { - required: false, - name: :enable_ssl_verification, - type: Boolean, - desc: 'DEPRECATED: This parameter has no effect since SSL verification will always be enabled' - } - ], - 'campfire' => [ - { - required: true, - name: :token, - type: String, - desc: 'Campfire token' - }, - { - required: false, - name: :subdomain, - type: String, - desc: 'Campfire subdomain' - }, - { - required: false, - name: :room, - type: String, - desc: 'Campfire room' - } - ], - 'confluence' => [ - { - required: true, - name: :confluence_url, - type: String, - desc: 'The URL of the Confluence Cloud Workspace hosted on atlassian.net' - } - ], - 'custom-issue-tracker' => [ - { - required: true, - name: :new_issue_url, - type: String, - desc: 'New issue URL' - }, - { - required: true, - name: :issues_url, - type: String, - desc: 'Issues URL' - }, - { - required: true, - name: :project_url, - type: String, - desc: 'Project URL' - } - ], - 'datadog' => [ - { - required: true, - name: :api_key, - type: String, - desc: 'API key used for authentication with Datadog' - }, - { - required: false, - name: :datadog_site, - type: String, - desc: 'Choose the Datadog site to send data to. Set to "datadoghq.eu" to send data to the EU site' - }, - { - required: false, - name: :api_url, - type: String, - desc: '(Advanced) Define the full URL for your Datadog site directly' - }, - { - required: false, - name: :datadog_service, - type: String, - desc: 'Name of this GitLab instance that all data will be tagged with' - }, - { - required: false, - name: :datadog_env, - type: String, - desc: 'The environment tag that traces will be tagged with' - } - ], - 'discord' => [ - { - required: true, - name: :webhook, - type: String, - desc: 'Discord webhook. e.g. https://discordapp.com/api/webhooks/…' - } - ], - 'drone-ci' => [ - { - required: true, - name: :token, - type: String, - desc: 'Drone CI token' - }, - { - required: true, - name: :drone_url, - type: String, - desc: 'Drone CI URL' - }, - { - required: false, - name: :enable_ssl_verification, - type: Boolean, - desc: 'Enable SSL verification for communication' - } - ], - 'emails-on-push' => [ - { - required: true, - name: :recipients, - type: String, - desc: 'Comma-separated list of recipient email addresses' - }, - { - required: false, - name: :disable_diffs, - type: Boolean, - desc: 'Disable code diffs' - }, - { - required: false, - name: :send_from_committer_email, - type: Boolean, - desc: 'Send from committer' - }, - { - required: false, - name: :branches_to_be_notified, - type: String, - desc: 'Branches for which notifications are to be sent' - } - ], - 'external-wiki' => [ - { - required: true, - name: :external_wiki_url, - type: String, - desc: 'The URL of the external wiki' - } - ], - 'flowdock' => [ - { - required: true, - name: :token, - type: String, - desc: 'Flowdock token' - } - ], - 'hangouts-chat' => [ - { - required: true, - name: :webhook, - type: String, - desc: 'The Hangouts Chat webhook. e.g. https://chat.googleapis.com/v1/spaces…' - }, - { - required: false, - name: :branches_to_be_notified, - type: String, - desc: 'Branches for which notifications are to be sent' - }, - chat_notification_events - ].flatten, - 'irker' => [ - { - required: true, - name: :recipients, - type: String, - desc: 'Recipients/channels separated by whitespaces' - }, - { - required: false, - name: :default_irc_uri, - type: String, - desc: 'Default: irc://irc.network.net:6697' - }, - { - required: false, - name: :server_host, - type: String, - desc: 'Server host. Default localhost' - }, - { - required: false, - name: :server_port, - type: Integer, - desc: 'Server port. Default 6659' - }, - { - required: false, - name: :colorize_messages, - type: Boolean, - desc: 'Colorize messages' - } - ], - 'jenkins' => [ - { - required: true, - name: :jenkins_url, - type: String, - desc: 'Jenkins root URL like https://jenkins.example.com' - }, - { - required: true, - name: :project_name, - type: String, - desc: 'The URL-friendly project name. Example: my_project_name' - }, - { - required: false, - name: :username, - type: String, - desc: 'A user with access to the Jenkins server, if applicable' - }, - { - required: false, - name: :password, - type: String, - desc: 'The password of the user' - } - ], - 'jira' => [ - { - required: true, - name: :url, - type: String, - desc: 'The base URL to the Jira instance web interface which is being linked to this GitLab project. E.g., https://jira.example.com' - }, - { - required: false, - name: :api_url, - type: String, - desc: 'The base URL to the Jira instance API. Web URL value will be used if not set. E.g., https://jira-api.example.com' - }, - { - required: true, - name: :username, - type: String, - desc: 'The username of the user created to be used with GitLab/Jira' - }, - { - required: true, - name: :password, - type: String, - desc: 'The password of the user created to be used with GitLab/Jira' - }, - { - required: false, - name: :jira_issue_transition_automatic, - type: Boolean, - desc: 'Enable automatic issue transitions' - }, - { - required: false, - name: :jira_issue_transition_id, - type: String, - desc: 'The ID of one or more transitions for custom issue transitions' - }, - { - required: false, - name: :comment_on_event_enabled, - type: Boolean, - desc: 'Enable comments inside Jira issues on each GitLab event (commit / merge request)' - } - ], - 'mattermost-slash-commands' => [ - { - required: true, - name: :token, - type: String, - desc: 'The Mattermost token' - } - ], - 'slack-slash-commands' => [ - { - required: true, - name: :token, - type: String, - desc: 'The Slack token' - } - ], - 'packagist' => [ - { - required: true, - name: :username, - type: String, - desc: 'The username' - }, - { - required: true, - name: :token, - type: String, - desc: 'The Packagist API token' - }, - { - required: false, - name: :server, - type: String, - desc: 'The server' - } - ], - 'pipelines-email' => [ - { - required: true, - name: :recipients, - type: String, - desc: 'Comma-separated list of recipient email addresses' - }, - { - required: false, - name: :notify_only_broken_pipelines, - type: Boolean, - desc: 'Notify only broken pipelines' - }, - { - required: false, - name: :branches_to_be_notified, - type: String, - desc: 'Branches for which notifications are to be sent' - } - ], - 'pivotaltracker' => [ - { - required: true, - name: :token, - type: String, - desc: 'The Pivotaltracker token' - }, - { - required: false, - name: :restrict_to_branch, - type: String, - desc: 'Comma-separated list of branches which will be automatically inspected. Leave blank to include all branches.' - } - ], - 'prometheus' => [ - { - required: true, - name: :api_url, - type: String, - desc: 'Prometheus API Base URL, like http://prometheus.example.com/' - }, - { - required: true, - name: :google_iap_audience_client_id, - type: String, - desc: 'Client ID of the IAP-secured resource (looks like IAP_CLIENT_ID.apps.googleusercontent.com)' - }, - { - required: true, - name: :google_iap_service_account_json, - type: String, - desc: 'Contents of the credentials.json file of your service account, like: { "type": "service_account", "project_id": ... }' - } - ], - 'pushover' => [ - { - required: true, - name: :api_key, - type: String, - desc: 'The application key' - }, - { - required: true, - name: :user_key, - type: String, - desc: 'The user key' - }, - { - required: true, - name: :priority, - type: String, - desc: 'The priority' - }, - { - required: true, - name: :device, - type: String, - desc: 'Leave blank for all active devices' - }, - { - required: true, - name: :sound, - type: String, - desc: 'The sound of the notification' - } - ], - 'redmine' => [ - { - required: true, - name: :new_issue_url, - type: String, - desc: 'The new issue URL' - }, - { - required: true, - name: :project_url, - type: String, - desc: 'The project URL' - }, - { - required: true, - name: :issues_url, - type: String, - desc: 'The issues URL' - } - ], - 'ewm' => [ - { - required: true, - name: :new_issue_url, - type: String, - desc: 'New Issue URL' - }, - { - required: true, - name: :project_url, - type: String, - desc: 'Project URL' - }, - { - required: true, - name: :issues_url, - type: String, - desc: 'Issues URL' - } - ], - 'youtrack' => [ - { - required: true, - name: :project_url, - type: String, - desc: 'The project URL' - }, - { - required: true, - name: :issues_url, - type: String, - desc: 'The issues URL' - } - ], - 'slack' => [ - chat_notification_settings, - chat_notification_flags, - chat_notification_channels, - chat_notification_events - ].flatten, - 'microsoft-teams' => [ - { - required: true, - name: :webhook, - type: String, - desc: 'The Microsoft Teams webhook. e.g. https://outlook.office.com/webhook/…' - }, - { - required: false, - name: :branches_to_be_notified, - type: String, - desc: 'Branches for which notifications are to be sent' - }, - chat_notification_flags - ].flatten, - 'mattermost' => [ - chat_notification_settings, - chat_notification_flags, - chat_notification_channels, - chat_notification_events - ].flatten, - 'teamcity' => [ - { - required: true, - name: :teamcity_url, - type: String, - desc: 'TeamCity root URL like https://teamcity.example.com' - }, - { - required: true, - name: :build_type, - type: String, - desc: 'Build configuration ID' - }, - { - required: true, - name: :username, - type: String, - desc: 'A user with permissions to trigger a manual build' - }, - { - required: true, - name: :password, - type: String, - desc: 'The password of the user' - } - ], - 'unify-circuit' => [ - { - required: true, - name: :webhook, - type: String, - desc: 'The Unify Circuit webhook. e.g. https://circuit.com/rest/v2/webhooks/incoming/…' - }, - chat_notification_events - ].flatten, - 'webex-teams' => [ - { - required: true, - name: :webhook, - type: String, - desc: 'The Webex Teams webhook. For example, https://api.ciscospark.com/v1/webhooks/incoming/...' - }, - chat_notification_events - ].flatten - } - end - - def self.service_classes - [ - ::Integrations::Asana, - ::Integrations::Assembla, - ::Integrations::Bamboo, - ::Integrations::Bugzilla, - ::Integrations::Buildkite, - ::Integrations::Campfire, - ::Integrations::Confluence, - ::Integrations::CustomIssueTracker, - ::Integrations::Datadog, - ::Integrations::Discord, - ::Integrations::DroneCi, - ::Integrations::EmailsOnPush, - ::Integrations::Ewm, - ::Integrations::ExternalWiki, - ::Integrations::Flowdock, - ::Integrations::HangoutsChat, - ::Integrations::Irker, - ::Integrations::Jenkins, - ::Integrations::Jira, - ::Integrations::Mattermost, - ::Integrations::MattermostSlashCommands, - ::Integrations::MicrosoftTeams, - ::Integrations::Packagist, - ::Integrations::PipelinesEmail, - ::Integrations::Pivotaltracker, - ::Integrations::Pushover, - ::Integrations::Redmine, - ::Integrations::Slack, - ::Integrations::SlackSlashCommands, - ::Integrations::Teamcity, - ::Integrations::Youtrack, - ::PrometheusService - ] - end - - def self.development_service_classes - [ - ::Integrations::MockCi, - ::MockMonitoringService - ] - end - end - end -end - -API::Helpers::ServicesHelpers.prepend_mod_with('API::Helpers::ServicesHelpers') diff --git a/lib/api/helpers/snippets_helpers.rb b/lib/api/helpers/snippets_helpers.rb index 42f56680ded..2d8c761101a 100644 --- a/lib/api/helpers/snippets_helpers.rb +++ b/lib/api/helpers/snippets_helpers.rb @@ -72,22 +72,18 @@ module API end def process_create_params(args) - with_api_params do |api_params| - args[:snippet_actions] = args.delete(:files)&.map do |file| - file[:action] = :create - file.symbolize_keys - end - - args.merge(api_params) + args[:snippet_actions] = args.delete(:files)&.map do |file| + file[:action] = :create + file.symbolize_keys end + + args end def process_update_params(args) - with_api_params do |api_params| - args[:snippet_actions] = args.delete(:files)&.map(&:symbolize_keys) + args[:snippet_actions] = args.delete(:files)&.map(&:symbolize_keys) - args.merge(api_params) - end + args end def validate_params_for_multiple_files(snippet) -- cgit v1.2.1