diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-07-20 18:40:28 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-07-20 18:40:28 +0300 |
commit | b595cb0c1dec83de5bdee18284abe86614bed33b (patch) | |
tree | 8c3d4540f193c5ff98019352f554e921b3a41a72 /app/models/integrations | |
parent | 2f9104a328fc8a4bddeaa4627b595166d24671d0 (diff) |
Add latest changes from gitlab-org/gitlab@15-2-stable-eev15.2.0-rc42
Diffstat (limited to 'app/models/integrations')
33 files changed, 464 insertions, 569 deletions
diff --git a/app/models/integrations/asana.rb b/app/models/integrations/asana.rb index d25bf8b1b1e..2cfd71c9eb2 100644 --- a/app/models/integrations/asana.rb +++ b/app/models/integrations/asana.rb @@ -4,9 +4,22 @@ require 'asana' module Integrations class Asana < Integration - prop_accessor :api_key, :restrict_to_branch validates :api_key, presence: true, if: :activated? + field :api_key, + type: 'password', + title: 'API key', + help: -> { s_('AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user.') }, + non_empty_password_title: -> { s_('ProjectService|Enter new API key') }, + non_empty_password_help: -> { s_('ProjectService|Leave blank to use your current API key.') }, + # Example Personal Access Token from Asana docs + placeholder: '0/68a9e79b868c6789e79a124c30b0', + required: true + + field :restrict_to_branch, + title: -> { s_('Integrations|Restrict to branch (optional)') }, + help: -> { s_('AsanaService|Comma-separated list of branches to be automatically inspected. Leave blank to include all branches.') } + def title 'Asana' end @@ -24,28 +37,6 @@ module Integrations 'asana' end - def fields - [ - { - type: 'password', - name: 'api_key', - title: 'API key', - help: s_('AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user.'), - non_empty_password_title: s_('ProjectService|Enter new API key'), - non_empty_password_help: s_('ProjectService|Leave blank to use your current API key.'), - # Example Personal Access Token from Asana docs - placeholder: '0/68a9e79b868c6789e79a124c30b0', - required: true - }, - { - type: 'text', - name: 'restrict_to_branch', - title: 'Restrict to branch (optional)', - help: s_('AsanaService|Comma-separated list of branches to be automatically inspected. Leave blank to include all branches.') - } - ] - end - def self.supported_events %w(push) end diff --git a/app/models/integrations/assembla.rb b/app/models/integrations/assembla.rb index ccd24c1fb2c..88dbf2915ef 100644 --- a/app/models/integrations/assembla.rb +++ b/app/models/integrations/assembla.rb @@ -2,9 +2,18 @@ module Integrations class Assembla < Integration - prop_accessor :token, :subdomain validates :token, presence: true, if: :activated? + field :token, + type: 'password', + non_empty_password_title: -> { s_('ProjectService|Enter new token') }, + non_empty_password_help: -> { s_('ProjectService|Leave blank to use your current token.') }, + placeholder: '', + required: true + + field :subdomain, + placeholder: '' + def title 'Assembla' end @@ -17,24 +26,6 @@ module Integrations 'assembla' end - def fields - [ - { - type: 'password', - name: 'token', - non_empty_password_title: s_('ProjectService|Enter new token'), - non_empty_password_help: s_('ProjectService|Leave blank to use your current token.'), - placeholder: '', - required: true - }, - { - type: 'text', - name: 'subdomain', - placeholder: '' - } - ] - end - def self.supported_events %w(push) end diff --git a/app/models/integrations/bamboo.rb b/app/models/integrations/bamboo.rb index 4e30c1ccc69..230dc6bb336 100644 --- a/app/models/integrations/bamboo.rb +++ b/app/models/integrations/bamboo.rb @@ -155,7 +155,6 @@ module Integrations query_params[:os_authType] = 'basic' params[:basic_auth] = basic_auth - params[:use_read_total_timeout] = true params end diff --git a/app/models/integrations/base_chat_notification.rb b/app/models/integrations/base_chat_notification.rb index 33d4eecbf49..c7992e4083c 100644 --- a/app/models/integrations/base_chat_notification.rb +++ b/app/models/integrations/base_chat_notification.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -# Base class for Chat notifications services +# Base class for Chat notifications integrations # This class is not meant to be used directly, but only to inherit from. module Integrations @@ -46,7 +46,7 @@ module Integrations # `notify_only_default_branch`. Now we have a string property named # `branches_to_be_notified`. Instead of doing a background migration, we # opted to set a value for the new property based on the old one, if - # users haven't specified one already. When users edit the service and + # users haven't specified one already. When users edit the integration and # select a value for this new property, it will override everything. self.branches_to_be_notified ||= notify_only_default_branch? ? "default" : "all" @@ -78,7 +78,7 @@ module Integrations type: 'select', name: 'branches_to_be_notified', title: s_('Integrations|Branches for which notifications are to be sent'), - choices: branch_choices + choices: self.class.branch_choices }.freeze, { type: 'text', @@ -118,7 +118,7 @@ module Integrations event_type = data[:event_type] || object_kind - channel_names = get_channel_field(event_type).presence || channel.presence + channel_names = event_channel_value(event_type).presence || channel.presence channels = channel_names&.split(',')&.map(&:strip) opts = {} @@ -134,15 +134,13 @@ module Integrations end def event_channel_names - supported_events.map { |event| event_channel_name(event) } - end + return [] unless configurable_channels? - def event_field(event) - fields.find { |field| field[:name] == event_channel_name(event) } + supported_events.map { |event| event_channel_name(event) } end - def global_fields - fields.reject { |field| field[:name].end_with?('channel') } + def form_fields + super.reject { |field| field[:name].end_with?('channel') } end def default_channel_placeholder @@ -153,6 +151,21 @@ module Integrations raise NotImplementedError end + # With some integrations the webhook is already tied to a specific channel, + # for others the channels are configurable for each event. + def configurable_channels? + false + end + + def event_channel_name(event) + EVENT_CHANNEL[event] + end + + def event_channel_value(event) + field_name = event_channel_name(event) + self.public_send(field_name) # rubocop:disable GitlabSecurity/PublicSend + end + private def log_usage(_, _) @@ -213,21 +226,12 @@ module Integrations end end - def get_channel_field(event) - field_name = event_channel_name(event) - self.public_send(field_name) # rubocop:disable GitlabSecurity/PublicSend - end - def build_event_channels - supported_events.reduce([]) do |channels, event| - channels << { type: 'text', name: event_channel_name(event), placeholder: default_channel_placeholder } + event_channel_names.map do |channel_field| + { type: 'text', name: channel_field, placeholder: default_channel_placeholder } end end - def event_channel_name(event) - EVENT_CHANNEL[event] - end - def project_name project.full_name end diff --git a/app/models/integrations/base_issue_tracker.rb b/app/models/integrations/base_issue_tracker.rb index bffe87c21ee..fe4a2f43b13 100644 --- a/app/models/integrations/base_issue_tracker.rb +++ b/app/models/integrations/base_issue_tracker.rb @@ -94,7 +94,7 @@ module Integrations result = false begin - response = Gitlab::HTTP.head(self.project_url, verify: true, use_read_total_timeout: true) + response = Gitlab::HTTP.head(self.project_url, verify: true) if response message = "#{self.type} received response #{response.code} when attempting to connect to #{self.project_url}" diff --git a/app/models/integrations/campfire.rb b/app/models/integrations/campfire.rb index 7889cd8f9a9..bf1358ac0f6 100644 --- a/app/models/integrations/campfire.rb +++ b/app/models/integrations/campfire.rb @@ -2,9 +2,34 @@ module Integrations class Campfire < Integration - prop_accessor :token, :subdomain, :room validates :token, presence: true, if: :activated? + field :token, + type: 'password', + title: -> { _('Campfire token') }, + help: -> { s_('CampfireService|API authentication token from Campfire.') }, + non_empty_password_title: -> { s_('ProjectService|Enter new token') }, + non_empty_password_help: -> { s_('ProjectService|Leave blank to use your current token.') }, + placeholder: '', + required: true + + field :subdomain, + title: -> { _('Campfire subdomain (optional)') }, + placeholder: '', + help: -> do + ERB::Util.html_escape( + s_('CampfireService|The %{code_open}.campfirenow.com%{code_close} subdomain.') + ) % { + code_open: '<code>'.html_safe, + code_close: '</code>'.html_safe + } + end + + field :room, + title: -> { _('Campfire room ID (optional)') }, + placeholder: '123456', + help: -> { s_('CampfireService|From the end of the room URL.') } + def title 'Campfire' end @@ -15,42 +40,18 @@ module Integrations def help docs_link = ActionController::Base.helpers.link_to _('Learn more.'), Rails.application.routes.url_helpers.help_page_url('api/services', anchor: 'campfire'), target: '_blank', rel: 'noopener noreferrer' - s_('CampfireService|Send notifications about push events to Campfire chat rooms. %{docs_link}').html_safe % { docs_link: docs_link.html_safe } + + ERB::Util.html_escape( + s_('CampfireService|Send notifications about push events to Campfire chat rooms. %{docs_link}') + ) % { + docs_link: docs_link.html_safe + } end def self.to_param 'campfire' end - def fields - [ - { - type: 'password', - name: 'token', - title: _('Campfire token'), - help: s_('CampfireService|API authentication token from Campfire.'), - non_empty_password_title: s_('ProjectService|Enter new token'), - non_empty_password_help: s_('ProjectService|Leave blank to use your current token.'), - placeholder: '', - required: true - }, - { - type: 'text', - name: 'subdomain', - title: _('Campfire subdomain (optional)'), - placeholder: '', - help: s_('CampfireService|The %{code_open}.campfirenow.com%{code_close} subdomain.') % { code_open: '<code>'.html_safe, code_close: '</code>'.html_safe } - }, - { - type: 'text', - name: 'room', - title: _('Campfire room ID (optional)'), - placeholder: '123456', - help: s_('CampfireService|From the end of the room URL.') - } - ] - end - def self.supported_events %w(push) end diff --git a/app/models/integrations/confluence.rb b/app/models/integrations/confluence.rb index 4e1d1993d02..c1c43af99bf 100644 --- a/app/models/integrations/confluence.rb +++ b/app/models/integrations/confluence.rb @@ -6,11 +6,14 @@ module Integrations VALID_HOST_MATCH = %r{\A.+\.atlassian\.net\Z}.freeze VALID_PATH_MATCH = %r{\A/wiki(/|\Z)}.freeze - prop_accessor :confluence_url - validates :confluence_url, presence: true, if: :activated? validate :validate_confluence_url_is_cloud, if: :activated? + field :confluence_url, + title: -> { s_('Confluence Cloud Workspace URL') }, + placeholder: 'https://example.atlassian.net/wiki', + required: true + def self.to_param 'confluence' end @@ -38,18 +41,6 @@ module Integrations end end - def fields - [ - { - type: 'text', - name: 'confluence_url', - title: s_('Confluence Cloud Workspace URL'), - placeholder: 'https://example.atlassian.net/wiki', - required: true - } - ] - end - def testable? false end diff --git a/app/models/integrations/datadog.rb b/app/models/integrations/datadog.rb index bb0fb6b9079..97e586c0662 100644 --- a/app/models/integrations/datadog.rb +++ b/app/models/integrations/datadog.rb @@ -15,7 +15,75 @@ module Integrations TAG_KEY_VALUE_RE = %r{\A [\w-]+ : .*\S.* \z}x.freeze - prop_accessor :datadog_site, :api_url, :api_key, :datadog_service, :datadog_env, :datadog_tags + field :datadog_site, + placeholder: DEFAULT_DOMAIN, + help: -> do + ERB::Util.html_escape( + s_('DatadogIntegration|The Datadog site to send data to. To send data to the EU site, use %{codeOpen}datadoghq.eu%{codeClose}.') + ) % { + codeOpen: '<code>'.html_safe, + codeClose: '</code>'.html_safe + } + end + + field :api_url, + title: -> { s_('DatadogIntegration|API URL') }, + help: -> { s_('DatadogIntegration|(Advanced) The full URL for your Datadog site.') } + + field :api_key, + type: 'password', + title: -> { _('API key') }, + non_empty_password_title: -> { s_('ProjectService|Enter new API key') }, + non_empty_password_help: -> { s_('ProjectService|Leave blank to use your current API key') }, + help: -> do + ERB::Util.html_escape( + s_('DatadogIntegration|%{linkOpen}API key%{linkClose} used for authentication with Datadog.') + ) % { + linkOpen: %Q{<a href="#{URL_API_KEYS_DOCS}" target="_blank" rel="noopener noreferrer">}.html_safe, + linkClose: '</a>'.html_safe + } + end, + required: true + + field :archive_trace_events, + type: 'checkbox', + title: -> { s_('Logs') }, + checkbox_label: -> { s_('Enable logs collection') }, + help: -> { s_('When enabled, job logs are collected by Datadog and displayed along with pipeline execution traces.') } + + field :datadog_service, + title: -> { s_('DatadogIntegration|Service') }, + placeholder: 'gitlab-ci', + help: -> { s_('DatadogIntegration|Tag all data from this GitLab instance in Datadog. Useful when managing several self-managed deployments.') } + + field :datadog_env, + title: -> { s_('DatadogIntegration|Environment') }, + placeholder: 'ci', + help: -> do + ERB::Util.html_escape( + s_('DatadogIntegration|For self-managed deployments, set the %{codeOpen}env%{codeClose} tag for all the data sent to Datadog. %{linkOpen}How do I use tags?%{linkClose}') + ) % { + codeOpen: '<code>'.html_safe, + codeClose: '</code>'.html_safe, + linkOpen: '<a href="https://docs.datadoghq.com/getting_started/tagging/#using-tags" target="_blank" rel="noopener noreferrer">'.html_safe, + linkClose: '</a>'.html_safe + } + end + + field :datadog_tags, + type: 'textarea', + title: -> { s_('DatadogIntegration|Tags') }, + placeholder: "tag:value\nanother_tag:value", + help: -> do + ERB::Util.html_escape( + s_('DatadogIntegration|Custom tags in Datadog. Enter one tag per line in the %{codeOpen}key:value%{codeClose} format. %{linkOpen}How do I use tags?%{linkClose}') + ) % { + codeOpen: '<code>'.html_safe, + codeClose: '</code>'.html_safe, + linkOpen: '<a href="https://docs.datadoghq.com/getting_started/tagging/#using-tags" target="_blank" rel="noopener noreferrer">'.html_safe, + linkClose: '</a>'.html_safe + } + end before_validation :strip_properties @@ -77,92 +145,11 @@ module Integrations end def fields - f = [ - { - type: 'text', - name: 'datadog_site', - placeholder: DEFAULT_DOMAIN, - help: ERB::Util.html_escape( - s_('DatadogIntegration|The Datadog site to send data to. To send data to the EU site, use %{codeOpen}datadoghq.eu%{codeClose}.') - ) % { - codeOpen: '<code>'.html_safe, - codeClose: '</code>'.html_safe - }, - required: false - }, - { - type: 'text', - name: 'api_url', - title: s_('DatadogIntegration|API URL'), - help: s_('DatadogIntegration|(Advanced) The full URL for your Datadog site.'), - required: false - }, - { - type: 'password', - name: 'api_key', - title: _('API key'), - non_empty_password_title: s_('ProjectService|Enter new API key'), - non_empty_password_help: s_('ProjectService|Leave blank to use your current API key'), - help: ERB::Util.html_escape( - s_('DatadogIntegration|%{linkOpen}API key%{linkClose} used for authentication with Datadog.') - ) % { - linkOpen: %Q{<a href="#{URL_API_KEYS_DOCS}" target="_blank" rel="noopener noreferrer">}.html_safe, - linkClose: '</a>'.html_safe - }, - required: true - } - ] - if Feature.enabled?(:datadog_integration_logs_collection, parent) - f.append({ - type: 'checkbox', - name: 'archive_trace_events', - title: s_('Logs'), - checkbox_label: s_('Enable logs collection'), - help: s_('When enabled, job logs are collected by Datadog and displayed along with pipeline execution traces.'), - required: false - }) + super + else + super.reject { _1.name == 'archive_trace_events' } end - - f += [ - { - type: 'text', - name: 'datadog_service', - title: s_('DatadogIntegration|Service'), - placeholder: 'gitlab-ci', - help: s_('DatadogIntegration|Tag all data from this GitLab instance in Datadog. Useful when managing several self-managed deployments.') - }, - { - type: 'text', - name: 'datadog_env', - title: s_('DatadogIntegration|Environment'), - placeholder: 'ci', - help: ERB::Util.html_escape( - s_('DatadogIntegration|For self-managed deployments, set the %{codeOpen}env%{codeClose} tag for all the data sent to Datadog. %{linkOpen}How do I use tags?%{linkClose}') - ) % { - codeOpen: '<code>'.html_safe, - codeClose: '</code>'.html_safe, - linkOpen: '<a href="https://docs.datadoghq.com/getting_started/tagging/#using-tags" target="_blank" rel="noopener noreferrer">'.html_safe, - linkClose: '</a>'.html_safe - } - }, - { - type: 'textarea', - name: 'datadog_tags', - title: s_('DatadogIntegration|Tags'), - placeholder: "tag:value\nanother_tag:value", - help: ERB::Util.html_escape( - s_('DatadogIntegration|Custom tags in Datadog. Enter one tag per line in the %{codeOpen}key:value%{codeClose} format. %{linkOpen}How do I use tags?%{linkClose}') - ) % { - codeOpen: '<code>'.html_safe, - codeClose: '</code>'.html_safe, - linkOpen: '<a href="https://docs.datadoghq.com/getting_started/tagging/#using-tags" target="_blank" rel="noopener noreferrer">'.html_safe, - linkClose: '</a>'.html_safe - } - } - ] - - f end override :hook_url diff --git a/app/models/integrations/discord.rb b/app/models/integrations/discord.rb index 790e41e5a2a..ecabf23c90b 100644 --- a/app/models/integrations/discord.rb +++ b/app/models/integrations/discord.rb @@ -23,10 +23,6 @@ module Integrations s_('Send notifications about project events to a Discord channel. %{docs_link}').html_safe % { docs_link: docs_link.html_safe } end - def event_field(event) - # No-op. - end - def default_channel_placeholder # No-op. end @@ -43,7 +39,7 @@ module Integrations type: 'select', name: 'branches_to_be_notified', title: s_('Integrations|Branches for which notifications are to be sent'), - choices: branch_choices + choices: self.class.branch_choices } ] end diff --git a/app/models/integrations/drone_ci.rb b/app/models/integrations/drone_ci.rb index 35524503dea..b1f72b7144e 100644 --- a/app/models/integrations/drone_ci.rb +++ b/app/models/integrations/drone_ci.rb @@ -60,8 +60,7 @@ module Integrations response = Gitlab::HTTP.try_get( commit_status_path(sha, ref), verify: enable_ssl_verification, - extra_log_info: { project_id: project_id }, - use_read_total_timeout: true + extra_log_info: { project_id: project_id } ) status = diff --git a/app/models/integrations/emails_on_push.rb b/app/models/integrations/emails_on_push.rb index ab458bb2c27..ed12a3a8d63 100644 --- a/app/models/integrations/emails_on_push.rb +++ b/app/models/integrations/emails_on_push.rb @@ -6,12 +6,35 @@ module Integrations RECIPIENTS_LIMIT = 750 - boolean_accessor :send_from_committer_email - boolean_accessor :disable_diffs - prop_accessor :recipients, :branches_to_be_notified validates :recipients, presence: true, if: :validate_recipients? validate :number_of_recipients_within_limit, if: :validate_recipients? + field :send_from_committer_email, + type: 'checkbox', + title: -> { s_("EmailsOnPushService|Send from committer") }, + help: -> do + @help ||= begin + domains = Notify.allowed_email_domains.map { |domain| "user@#{domain}" }.join(", ") + + s_("EmailsOnPushService|Send notifications from the committer's email address if the domain matches the domain used by your GitLab instance (such as %{domains}).") % { domains: domains } + end + end + + field :disable_diffs, + type: 'checkbox', + title: -> { s_("EmailsOnPushService|Disable code diffs") }, + help: -> { s_("EmailsOnPushService|Don't include possibly sensitive code diffs in notification body.") } + + field :branches_to_be_notified, + type: 'select', + title: -> { s_('Integrations|Branches for which notifications are to be sent') }, + choices: branch_choices + + field :recipients, + type: 'textarea', + placeholder: -> { s_('EmailsOnPushService|tanuki@example.com gitlab@example.com') }, + help: -> { s_('EmailsOnPushService|Emails separated by whitespace.') } + def self.valid_recipients(recipients) recipients.split.grep(Devise.email_regexp).uniq(&:downcase) end @@ -67,28 +90,6 @@ module Integrations Gitlab::Utils.to_boolean(self.disable_diffs) end - def fields - domains = Notify.allowed_email_domains.map { |domain| "user@#{domain}" }.join(", ") - [ - { type: 'checkbox', name: 'send_from_committer_email', title: s_("EmailsOnPushService|Send from committer"), - help: s_("EmailsOnPushService|Send notifications from the committer's email address if the domain matches the domain used by your GitLab instance (such as %{domains}).") % { domains: domains } }, - { type: 'checkbox', name: 'disable_diffs', title: s_("EmailsOnPushService|Disable code diffs"), - help: s_("EmailsOnPushService|Don't include possibly sensitive code diffs in notification body.") }, - { - type: 'select', - name: 'branches_to_be_notified', - title: s_('Integrations|Branches for which notifications are to be sent'), - choices: branch_choices - }, - { - type: 'textarea', - name: 'recipients', - placeholder: s_('EmailsOnPushService|tanuki@example.com gitlab@example.com'), - help: s_('EmailsOnPushService|Emails separated by whitespace.') - } - ] - end - private def number_of_recipients_within_limit diff --git a/app/models/integrations/external_wiki.rb b/app/models/integrations/external_wiki.rb index 18c48411e30..bc2ea193a84 100644 --- a/app/models/integrations/external_wiki.rb +++ b/app/models/integrations/external_wiki.rb @@ -2,9 +2,14 @@ module Integrations class ExternalWiki < Integration - prop_accessor :external_wiki_url validates :external_wiki_url, presence: true, public_url: true, if: :activated? + field :external_wiki_url, + title: -> { s_('ExternalWikiService|External wiki URL') }, + placeholder: -> { s_('ExternalWikiService|https://example.com/xxx/wiki/...') }, + help: -> { s_('ExternalWikiService|Enter the URL to the external wiki.') }, + required: true + def title s_('ExternalWikiService|External wiki') end @@ -17,19 +22,6 @@ module Integrations 'external_wiki' end - def fields - [ - { - type: 'text', - name: 'external_wiki_url', - title: s_('ExternalWikiService|External wiki URL'), - placeholder: s_('ExternalWikiService|https://example.com/xxx/wiki/...'), - help: 'Enter the URL to the external wiki.', - required: true - } - ] - end - def help docs_link = ActionController::Base.helpers.link_to _('Learn more.'), Rails.application.routes.url_helpers.help_page_url('user/project/wiki/index', anchor: 'link-an-external-wiki'), target: '_blank', rel: 'noopener noreferrer' @@ -37,7 +29,7 @@ module Integrations end def execute(_data) - response = Gitlab::HTTP.get(properties['external_wiki_url'], verify: true, use_read_total_timeout: true) + response = Gitlab::HTTP.get(properties['external_wiki_url'], verify: true) response.body if response.code == 200 rescue StandardError nil diff --git a/app/models/integrations/field.rb b/app/models/integrations/field.rb index cbda418755b..53c8f5f623e 100644 --- a/app/models/integrations/field.rb +++ b/app/models/integrations/field.rb @@ -4,14 +4,16 @@ module Integrations class Field SECRET_NAME = %r/token|key|password|passphrase|secret/.freeze + BOOLEAN_ATTRIBUTES = %i[required api_only exposes_secrets].freeze + ATTRIBUTES = %i[ - section type placeholder required choices value checkbox_label + section type placeholder choices value checkbox_label title help non_empty_password_help non_empty_password_title - api_only - exposes_secrets - ].freeze + ].concat(BOOLEAN_ATTRIBUTES).freeze + + TYPES = %w[text textarea password checkbox select].freeze attr_reader :name, :integration_class @@ -22,6 +24,13 @@ module Integrations attributes[:type] = SECRET_NAME.match?(@name) ? 'password' : type attributes[:api_only] = api_only @attributes = attributes.freeze + + invalid_attributes = attributes.keys - ATTRIBUTES + if invalid_attributes.present? + raise ArgumentError, "Invalid attributes #{invalid_attributes.inspect}" + elsif !TYPES.include?(self[:type]) + raise ArgumentError, "Invalid type #{self[:type].inspect}" + end end def [](key) @@ -34,11 +43,19 @@ module Integrations end def secret? - @attributes[:type] == 'password' + self[:type] == 'password' end ATTRIBUTES.each do |name| define_method(name) { self[name] } end + + BOOLEAN_ATTRIBUTES.each do |name| + define_method("#{name}?") { !!self[name] } + end + + TYPES.each do |type| + define_method("#{type}?") { self[:type] == type } + end end end diff --git a/app/models/integrations/flowdock.rb b/app/models/integrations/flowdock.rb index 703d8013bab..52efb29f2c1 100644 --- a/app/models/integrations/flowdock.rb +++ b/app/models/integrations/flowdock.rb @@ -2,9 +2,16 @@ module Integrations class Flowdock < Integration - prop_accessor :token validates :token, presence: true, if: :activated? + field :token, + type: 'password', + help: -> { s_('FlowdockService|Enter your Flowdock token.') }, + non_empty_password_title: -> { s_('ProjectService|Enter new token') }, + non_empty_password_help: -> { s_('ProjectService|Leave blank to use your current token.') }, + placeholder: '1b609b52537...', + required: true + def title 'Flowdock' end @@ -22,20 +29,6 @@ module Integrations 'flowdock' end - def fields - [ - { - type: 'password', - name: 'token', - help: s_('FlowdockService|Enter your Flowdock token.'), - non_empty_password_title: s_('ProjectService|Enter new token'), - non_empty_password_help: s_('ProjectService|Leave blank to use your current token.'), - placeholder: '1b609b52537...', - required: true - } - ] - end - def self.supported_events %w(push) end diff --git a/app/models/integrations/hangouts_chat.rb b/app/models/integrations/hangouts_chat.rb index 8c68c9ff95a..df112ad6ca8 100644 --- a/app/models/integrations/hangouts_chat.rb +++ b/app/models/integrations/hangouts_chat.rb @@ -19,9 +19,6 @@ module Integrations s_('Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}').html_safe % { docs_link: docs_link.html_safe } end - def event_field(event) - end - def default_channel_placeholder end @@ -42,7 +39,7 @@ module Integrations type: 'select', name: 'branches_to_be_notified', title: s_('Integrations|Branches for which notifications are to be sent'), - choices: branch_choices + choices: self.class.branch_choices } ] end diff --git a/app/models/integrations/harbor.rb b/app/models/integrations/harbor.rb index 44813795fc0..82981493822 100644 --- a/app/models/integrations/harbor.rb +++ b/app/models/integrations/harbor.rb @@ -4,7 +4,7 @@ module Integrations class Harbor < Integration prop_accessor :url, :project_name, :username, :password - validates :url, public_url: true, presence: true, if: :activated? + validates :url, public_url: true, presence: true, addressable_url: { allow_localhost: false, allow_local_network: false }, if: :activated? validates :project_name, presence: true, if: :activated? validates :username, presence: true, if: :activated? validates :password, format: { with: ::Ci::Maskable::REGEX }, if: :activated? diff --git a/app/models/integrations/irker.rb b/app/models/integrations/irker.rb index 780f4bef0c9..3f3e321f45e 100644 --- a/app/models/integrations/irker.rb +++ b/app/models/integrations/irker.rb @@ -4,13 +4,55 @@ require 'uri' module Integrations class Irker < Integration - prop_accessor :server_host, :server_port, :default_irc_uri - prop_accessor :recipients, :channels - boolean_accessor :colorize_messages validates :recipients, presence: true, if: :validate_recipients? - before_validation :get_channels + field :server_host, + placeholder: 'localhost', + title: -> { s_('IrkerService|Server host (optional)') }, + help: -> { s_('IrkerService|irker daemon hostname (defaults to localhost).') } + + field :server_port, + placeholder: 6659, + title: -> { s_('IrkerService|Server port (optional)') }, + help: -> { s_('IrkerService|irker daemon port (defaults to 6659).') } + + field :default_irc_uri, + title: -> { s_('IrkerService|Default IRC URI (optional)') }, + help: -> { s_('IrkerService|URI to add before each recipient.') }, + placeholder: 'irc://irc.network.net:6697/' + + field :recipients, + type: 'textarea', + title: -> { s_('IrkerService|Recipients') }, + placeholder: 'irc[s]://irc.network.net[:port]/#channel', + required: true, + help: -> do + recipients_docs_link = ActionController::Base.helpers.link_to( + s_('IrkerService|How to enter channels or users?'), + Rails.application.routes.url_helpers.help_page_url( + 'user/project/integrations/irker', + anchor: 'enter-irker-recipients' + ), + target: '_blank', rel: 'noopener noreferrer' + ) + + ERB::Util.html_escape( + s_('IrkerService|Channels and users separated by whitespaces. %{recipients_docs_link}') + ) % { + recipients_docs_link: recipients_docs_link.html_safe + } + end + + field :colorize_messages, + type: 'checkbox', + title: -> { _('Colorize messages') } + + # NOTE: This field is only used internally to store the parsed + # channels from the `recipients` field, it should not be exposed + # in the UI or API. + prop_accessor :channels + def title s_('IrkerService|irker (IRC gateway)') end @@ -30,17 +72,10 @@ module Integrations def execute(data) return unless supported_events.include?(data[:object_kind]) - if Feature.enabled?(:rename_integrations_workers) - Integrations::IrkerWorker.perform_async( - project_id, channels, - colorize_messages, data, settings - ) - else - ::IrkerWorker.perform_async( - project_id, channels, - colorize_messages, data, settings - ) - end + Integrations::IrkerWorker.perform_async( + project_id, channels, + colorize_messages, data, settings + ) end def settings @@ -50,34 +85,6 @@ module Integrations } end - def fields - recipients_docs_link = ActionController::Base.helpers.link_to( - s_('IrkerService|How to enter channels or users?'), - Rails.application.routes.url_helpers.help_page_url( - 'user/project/integrations/irker', - anchor: 'enter-irker-recipients' - ), - target: '_blank', rel: 'noopener noreferrer' - ) - - [ - { type: 'text', name: 'server_host', placeholder: 'localhost', title: s_('IrkerService|Server host (optional)'), - help: s_('IrkerService|irker daemon hostname (defaults to localhost).') }, - { type: 'text', name: 'server_port', placeholder: 6659, title: s_('IrkerService|Server port (optional)'), - help: s_('IrkerService|irker daemon port (defaults to 6659).') }, - { type: 'text', name: 'default_irc_uri', title: s_('IrkerService|Default IRC URI (optional)'), - help: s_('IrkerService|URI to add before each recipient.'), - placeholder: 'irc://irc.network.net:6697/' }, - { type: 'textarea', name: 'recipients', title: s_('IrkerService|Recipients'), - placeholder: 'irc[s]://irc.network.net[:port]/#channel', required: true, - help: format( - s_('IrkerService|Channels and users separated by whitespaces. %{recipients_docs_link}').html_safe, - recipients_docs_link: recipients_docs_link.html_safe - ) }, - { type: 'checkbox', name: 'colorize_messages', title: _('Colorize messages') } - ] - end - def help docs_link = ActionController::Base.helpers.link_to( _('Learn more.'), diff --git a/app/models/integrations/jira.rb b/app/models/integrations/jira.rb index 125f52104d4..c9c9b9d59d6 100644 --- a/app/models/integrations/jira.rb +++ b/app/models/integrations/jira.rb @@ -71,11 +71,12 @@ module Integrations non_empty_password_help: -> { s_('JiraService|Leave blank to use your current password or API token.') }, help: -> { s_('JiraService|Use a password for server version and an API token for cloud version.') } + field :jira_issue_transition_id, api_only: true + # TODO: we can probably just delegate as part of # https://gitlab.com/gitlab-org/gitlab/issues/29404 # These fields are API only, so no field definition is required. data_field :jira_issue_transition_automatic - data_field :jira_issue_transition_id data_field :project_key data_field :issues_enabled data_field :vulnerabilities_enabled diff --git a/app/models/integrations/mattermost.rb b/app/models/integrations/mattermost.rb index d9ccbb7ea34..dae11b99bc5 100644 --- a/app/models/integrations/mattermost.rb +++ b/app/models/integrations/mattermost.rb @@ -3,6 +3,7 @@ module Integrations class Mattermost < BaseChatNotification include SlackMattermostNotifier + extend ::Gitlab::Utils::Override def title s_('Mattermost notifications') @@ -28,5 +29,10 @@ module Integrations def webhook_placeholder 'http://mattermost.example.com/hooks/' end + + override :configurable_channels? + def configurable_channels? + true + end end end diff --git a/app/models/integrations/microsoft_teams.rb b/app/models/integrations/microsoft_teams.rb index 625ee0bc522..69863f164cd 100644 --- a/app/models/integrations/microsoft_teams.rb +++ b/app/models/integrations/microsoft_teams.rb @@ -22,9 +22,6 @@ module Integrations 'https://outlook.office.com/webhook/…' end - def event_field(event) - end - def default_channel_placeholder end @@ -47,7 +44,7 @@ module Integrations section: SECTION_TYPE_CONFIGURATION, name: 'branches_to_be_notified', title: s_('Integrations|Branches for which notifications are to be sent'), - choices: branch_choices + choices: self.class.branch_choices } ] end diff --git a/app/models/integrations/mock_ci.rb b/app/models/integrations/mock_ci.rb index 0b3a9bc5405..2d8e26d409f 100644 --- a/app/models/integrations/mock_ci.rb +++ b/app/models/integrations/mock_ci.rb @@ -49,7 +49,7 @@ module Integrations # # => 'running' # def commit_status(sha, ref) - response = Gitlab::HTTP.get(commit_status_path(sha), verify: enable_ssl_verification, use_read_total_timeout: true) + response = Gitlab::HTTP.get(commit_status_path(sha), verify: enable_ssl_verification) read_commit_status(response) rescue Errno::ECONNREFUSED :error diff --git a/app/models/integrations/packagist.rb b/app/models/integrations/packagist.rb index 758c9e4761b..05ee919892d 100644 --- a/app/models/integrations/packagist.rb +++ b/app/models/integrations/packagist.rb @@ -5,7 +5,25 @@ module Integrations include HasWebHook extend Gitlab::Utils::Override - prop_accessor :username, :token, :server + field :username, + title: -> { _('Username') }, + help: -> { s_('Enter your Packagist username.') }, + placeholder: '', + required: true + + field :token, + type: 'password', + title: -> { _('Token') }, + help: -> { s_('Enter your Packagist token.') }, + non_empty_password_title: -> { s_('ProjectService|Enter new token') }, + non_empty_password_help: -> { s_('ProjectService|Leave blank to use your current token.') }, + placeholder: '', + required: true + + field :server, + title: -> { _('Server (optional)') }, + help: -> { s_('Enter your Packagist server. Defaults to https://packagist.org.') }, + placeholder: 'https://packagist.org' validates :username, presence: true, if: :activated? validates :token, presence: true, if: :activated? @@ -22,37 +40,6 @@ module Integrations 'packagist' end - def fields - [ - { - type: 'text', - name: 'username', - title: _('Username'), - help: s_('Enter your Packagist username.'), - placeholder: '', - required: true - }, - { - type: 'password', - name: 'token', - title: _('Token'), - help: s_('Enter your Packagist token.'), - non_empty_password_title: s_('ProjectService|Enter new token'), - non_empty_password_help: s_('ProjectService|Leave blank to use your current token.'), - placeholder: '', - required: true - }, - { - type: 'text', - name: 'server', - title: _('Server (optional)'), - help: s_('Enter your Packagist server. Defaults to https://packagist.org.'), - placeholder: 'https://packagist.org', - required: false - } - ] - end - def self.supported_events %w(push merge_request tag_push) end diff --git a/app/models/integrations/pipelines_email.rb b/app/models/integrations/pipelines_email.rb index f15482dc2e1..77cbba25f2c 100644 --- a/app/models/integrations/pipelines_email.rb +++ b/app/models/integrations/pipelines_email.rb @@ -6,11 +6,26 @@ module Integrations RECIPIENTS_LIMIT = 30 - prop_accessor :recipients, :branches_to_be_notified - boolean_accessor :notify_only_broken_pipelines, :notify_only_default_branch validates :recipients, presence: true, if: :validate_recipients? validate :number_of_recipients_within_limit, if: :validate_recipients? + field :recipients, + type: 'textarea', + help: -> { _('Comma-separated list of email addresses.') }, + required: true + + field :notify_only_broken_pipelines, + type: 'checkbox' + + field :notify_only_default_branch, + type: 'checkbox', + api_only: true + + field :branches_to_be_notified, + type: 'select', + title: -> { s_('Integrations|Branches for which notifications are to be sent') }, + choices: branch_choices + def initialize_properties super @@ -65,21 +80,6 @@ module Integrations project&.ci_pipelines&.any? end - def fields - [ - { type: 'textarea', - name: 'recipients', - help: _('Comma-separated list of email addresses.'), - required: true }, - { type: 'checkbox', - name: 'notify_only_broken_pipelines' }, - { type: 'select', - name: 'branches_to_be_notified', - title: s_('Integrations|Branches for which notifications are to be sent'), - choices: branch_choices } - ] - end - def test(data) result = execute(data, force: true) diff --git a/app/models/integrations/pivotaltracker.rb b/app/models/integrations/pivotaltracker.rb index 931ccf46655..d32fb974339 100644 --- a/app/models/integrations/pivotaltracker.rb +++ b/app/models/integrations/pivotaltracker.rb @@ -4,9 +4,22 @@ module Integrations class Pivotaltracker < Integration API_ENDPOINT = 'https://www.pivotaltracker.com/services/v5/source_commits' - prop_accessor :token, :restrict_to_branch validates :token, presence: true, if: :activated? + field :token, + type: 'password', + help: -> { s_('PivotalTrackerService|Pivotal Tracker API token. User must have access to the story. All comments are attributed to this user.') }, + non_empty_password_title: -> { s_('ProjectService|Enter new token') }, + non_empty_password_help: -> { s_('ProjectService|Leave blank to use your current token.') }, + required: true + + field :restrict_to_branch, + title: -> { s_('Integrations|Restrict to branch (optional)') }, + help: -> do + s_('PivotalTrackerService|Comma-separated list of branches to ' \ + 'automatically inspect. Leave blank to include all branches.') + end + def title 'Pivotal Tracker' end @@ -24,26 +37,6 @@ module Integrations 'pivotaltracker' end - def fields - [ - { - type: 'password', - name: 'token', - help: s_('PivotalTrackerService|Pivotal Tracker API token. User must have access to the story. All comments are attributed to this user.'), - non_empty_password_title: s_('ProjectService|Enter new token'), - non_empty_password_help: s_('ProjectService|Leave blank to use your current token.'), - required: true - }, - { - type: 'text', - name: 'restrict_to_branch', - title: 'Restrict to branch (optional)', - help: s_('PivotalTrackerService|Comma-separated list of branches to ' \ - 'automatically inspect. Leave blank to include all branches.') - } - ] - end - def self.supported_events %w(push) end diff --git a/app/models/integrations/prometheus.rb b/app/models/integrations/prometheus.rb index 36060565317..e672a985810 100644 --- a/app/models/integrations/prometheus.rb +++ b/app/models/integrations/prometheus.rb @@ -4,11 +4,30 @@ module Integrations class Prometheus < BaseMonitoring include PrometheusAdapter - # Access to prometheus is directly through the API - prop_accessor :api_url - prop_accessor :google_iap_service_account_json - prop_accessor :google_iap_audience_client_id - boolean_accessor :manual_configuration + field :manual_configuration, + type: 'checkbox', + title: -> { s_('PrometheusService|Active') }, + help: -> { s_('PrometheusService|Select this checkbox to override the auto configuration settings with your own settings.') }, + required: true + + field :api_url, + title: 'API URL', + placeholder: -> { s_('PrometheusService|https://prometheus.example.com/') }, + help: -> { s_('PrometheusService|The Prometheus API base URL.') }, + required: true + + field :google_iap_audience_client_id, + title: 'Google IAP Audience Client ID', + placeholder: -> { s_('PrometheusService|IAP_CLIENT_ID.apps.googleusercontent.com') }, + help: -> { s_('PrometheusService|The ID of the IAP-secured resource.') }, + required: false + + field :google_iap_service_account_json, + type: 'textarea', + title: 'Google IAP Service Account JSON', + placeholder: -> { s_('PrometheusService|{ "type": "service_account", "project_id": ... }') }, + help: -> { s_('PrometheusService|The contents of the credentials.json file of your service account.') }, + required: false # We need to allow the self-monitoring project to connect to the internal # Prometheus instance. @@ -45,43 +64,6 @@ module Integrations 'prometheus' end - def fields - [ - { - type: 'checkbox', - name: 'manual_configuration', - title: s_('PrometheusService|Active'), - help: s_('PrometheusService|Select this checkbox to override the auto configuration settings with your own settings.'), - required: true - }, - { - type: 'text', - name: 'api_url', - title: 'API URL', - placeholder: s_('PrometheusService|https://prometheus.example.com/'), - help: s_('PrometheusService|The Prometheus API base URL.'), - required: true - }, - { - type: 'text', - name: 'google_iap_audience_client_id', - title: 'Google IAP Audience Client ID', - placeholder: s_('PrometheusService|IAP_CLIENT_ID.apps.googleusercontent.com'), - help: s_('PrometheusService|The ID of the IAP-secured resource.'), - autocomplete: 'off', - required: false - }, - { - type: 'textarea', - name: 'google_iap_service_account_json', - title: 'Google IAP Service Account JSON', - placeholder: s_('PrometheusService|{ "type": "service_account", "project_id": ... }'), - help: s_('PrometheusService|The contents of the credentials.json file of your service account.'), - required: false - } - ] - end - # Check we can connect to the Prometheus API def test(*args) return { success: false, result: 'Prometheus configuration error' } unless prometheus_client diff --git a/app/models/integrations/pushover.rb b/app/models/integrations/pushover.rb index 7fd5efa8765..791e27c5db7 100644 --- a/app/models/integrations/pushover.rb +++ b/app/models/integrations/pushover.rb @@ -4,9 +4,73 @@ module Integrations class Pushover < Integration BASE_URI = 'https://api.pushover.net/1' - prop_accessor :api_key, :user_key, :device, :priority, :sound validates :api_key, :user_key, :priority, presence: true, if: :activated? + field :api_key, + type: 'password', + title: -> { _('API key') }, + help: -> { s_('PushoverService|Enter your application key.') }, + non_empty_password_title: -> { s_('ProjectService|Enter new API key') }, + non_empty_password_help: -> { s_('ProjectService|Leave blank to use your current API key.') }, + placeholder: '', + required: true + + field :user_key, + type: 'password', + title: -> { _('User key') }, + help: -> { s_('PushoverService|Enter your user key.') }, + non_empty_password_title: -> { s_('PushoverService|Enter new user key') }, + non_empty_password_help: -> { s_('PushoverService|Leave blank to use your current user key.') }, + placeholder: '', + required: true + + field :device, + title: -> { _('Devices (optional)') }, + help: -> { s_('PushoverService|Leave blank for all active devices.') }, + placeholder: '' + + field :priority, + type: 'select', + required: true, + choices: -> do + [ + [s_('PushoverService|Lowest priority'), -2], + [s_('PushoverService|Low priority'), -1], + [s_('PushoverService|Normal priority'), 0], + [s_('PushoverService|High priority'), 1] + ] + end + + field :sound, + type: 'select', + choices: -> do + [ + ['Device default sound', nil], + ['Pushover (default)', 'pushover'], + %w(Bike bike), + %w(Bugle bugle), + ['Cash Register', 'cashregister'], + %w(Classical classical), + %w(Cosmic cosmic), + %w(Falling falling), + %w(Gamelan gamelan), + %w(Incoming incoming), + %w(Intermission intermission), + %w(Magic magic), + %w(Mechanical mechanical), + ['Piano Bar', 'pianobar'], + %w(Siren siren), + ['Space Alarm', 'spacealarm'], + ['Tug Boat', 'tugboat'], + ['Alien Alarm (long)', 'alien'], + ['Climb (long)', 'climb'], + ['Persistent (long)', 'persistent'], + ['Pushover Echo (long)', 'echo'], + ['Up Down (long)', 'updown'], + ['None (silent)', 'none'] + ] + end + def title 'Pushover' end @@ -19,81 +83,6 @@ module Integrations 'pushover' end - def fields - [ - { - type: 'password', - name: 'api_key', - title: _('API key'), - help: s_('PushoverService|Enter your application key.'), - non_empty_password_title: s_('ProjectService|Enter new API key'), - non_empty_password_help: s_('ProjectService|Leave blank to use your current API key.'), - placeholder: '', - required: true - }, - { - type: 'password', - name: 'user_key', - title: _('User key'), - help: s_('PushoverService|Enter your user key.'), - non_empty_password_title: s_('PushoverService|Enter new user key'), - non_empty_password_help: s_('PushoverService|Leave blank to use your current user key.'), - placeholder: '', - required: true - }, - { - type: 'text', - name: 'device', - title: _('Devices (optional)'), - help: s_('PushoverService|Leave blank for all active devices.'), - placeholder: '' - }, - { - type: 'select', - name: 'priority', - required: true, - choices: - [ - [s_('PushoverService|Lowest priority'), -2], - [s_('PushoverService|Low priority'), -1], - [s_('PushoverService|Normal priority'), 0], - [s_('PushoverService|High priority'), 1] - ], - default_choice: 0 - }, - { - type: 'select', - name: 'sound', - choices: - [ - ['Device default sound', nil], - ['Pushover (default)', 'pushover'], - %w(Bike bike), - %w(Bugle bugle), - ['Cash Register', 'cashregister'], - %w(Classical classical), - %w(Cosmic cosmic), - %w(Falling falling), - %w(Gamelan gamelan), - %w(Incoming incoming), - %w(Intermission intermission), - %w(Magic magic), - %w(Mechanical mechanical), - ['Piano Bar', 'pianobar'], - %w(Siren siren), - ['Space Alarm', 'spacealarm'], - ['Tug Boat', 'tugboat'], - ['Alien Alarm (long)', 'alien'], - ['Climb (long)', 'climb'], - ['Persistent (long)', 'persistent'], - ['Pushover Echo (long)', 'echo'], - ['Up Down (long)', 'updown'], - ['None (silent)', 'none'] - ] - } - ] - end - def self.supported_events %w(push) end diff --git a/app/models/integrations/shimo.rb b/app/models/integrations/shimo.rb index dd25a0bc558..8bc296e0320 100644 --- a/app/models/integrations/shimo.rb +++ b/app/models/integrations/shimo.rb @@ -2,9 +2,12 @@ module Integrations class Shimo < BaseThirdPartyWiki - prop_accessor :external_wiki_url validates :external_wiki_url, presence: true, public_url: true, if: :activated? + field :external_wiki_url, + title: -> { s_('Shimo|Shimo Workspace URL') }, + required: true + def render? return false unless Feature.enabled?(:shimo_integration, project) @@ -25,21 +28,10 @@ module Integrations # support for `test` method def execute(_data) - response = Gitlab::HTTP.get(properties['external_wiki_url'], verify: true, use_read_total_timeout: true) + response = Gitlab::HTTP.get(properties['external_wiki_url'], verify: true) response.body if response.code == 200 rescue StandardError nil end - - def fields - [ - { - type: 'text', - name: 'external_wiki_url', - title: s_('Shimo|Shimo Workspace URL'), - required: true - } - ] - end end end diff --git a/app/models/integrations/slack.rb b/app/models/integrations/slack.rb index 0381db3a67e..93263229109 100644 --- a/app/models/integrations/slack.rb +++ b/app/models/integrations/slack.rb @@ -55,5 +55,10 @@ module Integrations Gitlab::UsageDataCounters::HLLRedisCounter.track_event(key, values: user_id) end + + override :configurable_channels? + def configurable_channels? + true + end end end diff --git a/app/models/integrations/teamcity.rb b/app/models/integrations/teamcity.rb index a23aa5f783d..e0299c9ac5f 100644 --- a/app/models/integrations/teamcity.rb +++ b/app/models/integrations/teamcity.rb @@ -156,7 +156,7 @@ module Integrations end def get_path(path) - Gitlab::HTTP.try_get(build_url(path), verify: enable_ssl_verification, basic_auth: basic_auth, extra_log_info: { project_id: project_id }, use_read_total_timeout: true) + Gitlab::HTTP.try_get(build_url(path), verify: enable_ssl_verification, basic_auth: basic_auth, extra_log_info: { project_id: project_id }) end def post_to_build_queue(data, branch) @@ -167,8 +167,7 @@ module Integrations '</build>', headers: { 'Content-type' => 'application/xml' }, verify: enable_ssl_verification, - basic_auth: basic_auth, - use_read_total_timeout: true + basic_auth: basic_auth ) end diff --git a/app/models/integrations/unify_circuit.rb b/app/models/integrations/unify_circuit.rb index f085423d229..f10a75fac5d 100644 --- a/app/models/integrations/unify_circuit.rb +++ b/app/models/integrations/unify_circuit.rb @@ -19,9 +19,6 @@ module Integrations s_('Integrations|Send notifications about project events to a Unify Circuit conversation. %{docs_link}').html_safe % { docs_link: docs_link.html_safe } end - def event_field(event) - end - def default_channel_placeholder end @@ -38,7 +35,7 @@ module Integrations type: 'select', name: 'branches_to_be_notified', title: s_('Integrations|Branches for which notifications are to be sent'), - choices: branch_choices + choices: self.class.branch_choices } ] end @@ -49,8 +46,7 @@ module Integrations response = Gitlab::HTTP.post(webhook, body: { subject: message.project_name, text: message.summary, - markdown: true, - use_read_total_timeout: true + markdown: true }.to_json) response if response.success? diff --git a/app/models/integrations/webex_teams.rb b/app/models/integrations/webex_teams.rb index 345dd98cbc1..75be457dcf5 100644 --- a/app/models/integrations/webex_teams.rb +++ b/app/models/integrations/webex_teams.rb @@ -19,9 +19,6 @@ module Integrations s_("WebexTeamsService|Send notifications about project events to a Webex Teams conversation. %{docs_link}") % { docs_link: docs_link.html_safe } end - def event_field(event) - end - def default_channel_placeholder end @@ -38,7 +35,7 @@ module Integrations type: 'select', name: 'branches_to_be_notified', title: s_('Integrations|Branches for which notifications are to be sent'), - choices: branch_choices + choices: self.class.branch_choices } ] end @@ -47,7 +44,7 @@ module Integrations def notify(message, opts) header = { 'Content-Type' => 'application/json' } - response = Gitlab::HTTP.post(webhook, headers: header, body: { markdown: message.summary }.to_json, use_read_total_timeout: true) + response = Gitlab::HTTP.post(webhook, headers: header, body: { markdown: message.summary }.to_json) response if response.success? end diff --git a/app/models/integrations/youtrack.rb b/app/models/integrations/youtrack.rb index ab6e1da27f8..fa719f925ed 100644 --- a/app/models/integrations/youtrack.rb +++ b/app/models/integrations/youtrack.rb @@ -33,10 +33,7 @@ module Integrations end def fields - [ - { type: 'text', name: 'project_url', title: _('Project URL'), help: s_('IssueTracker|The URL to the project in YouTrack.'), required: true }, - { type: 'text', name: 'issues_url', title: s_('ProjectService|Issue URL'), help: s_('IssueTracker|The URL to view an issue in the YouTrack project. Must contain %{colon_id}.') % { colon_id: '<code>:id</code>'.html_safe }, required: true } - ] + super.select { _1.name.in?(%w[project_url issues_url]) } end end end diff --git a/app/models/integrations/zentao.rb b/app/models/integrations/zentao.rb index c33df465fde..11db469f7ee 100644 --- a/app/models/integrations/zentao.rb +++ b/app/models/integrations/zentao.rb @@ -4,7 +4,28 @@ module Integrations class Zentao < Integration include Gitlab::Routing - data_field :url, :api_url, :api_token, :zentao_product_xid + self.field_storage = :data_fields + + field :url, + title: -> { s_('ZentaoIntegration|ZenTao Web URL') }, + placeholder: 'https://www.zentao.net', + help: -> { s_('ZentaoIntegration|Base URL of the ZenTao instance.') }, + required: true + + field :api_url, + title: -> { s_('ZentaoIntegration|ZenTao API URL (optional)') }, + help: -> { s_('ZentaoIntegration|If different from Web URL.') } + + field :api_token, + type: 'password', + title: -> { s_('ZentaoIntegration|ZenTao API token') }, + non_empty_password_title: -> { s_('ZentaoIntegration|Enter new ZenTao API token') }, + non_empty_password_help: -> { s_('ProjectService|Leave blank to use your current token.') }, + required: true + + field :zentao_product_xid, + title: -> { s_('ZentaoIntegration|ZenTao Product ID') }, + required: true validates :url, public_url: true, presence: true, if: :activated? validates :api_url, public_url: true, allow_blank: true @@ -47,39 +68,6 @@ module Integrations %w() end - def fields - [ - { - type: 'text', - name: 'url', - title: s_('ZentaoIntegration|ZenTao Web URL'), - placeholder: 'https://www.zentao.net', - help: s_('ZentaoIntegration|Base URL of the ZenTao instance.'), - required: true - }, - { - type: 'text', - name: 'api_url', - title: s_('ZentaoIntegration|ZenTao API URL (optional)'), - help: s_('ZentaoIntegration|If different from Web URL.') - }, - { - type: 'password', - name: 'api_token', - title: s_('ZentaoIntegration|ZenTao API token'), - non_empty_password_title: s_('ZentaoIntegration|Enter new ZenTao API token'), - non_empty_password_help: s_('ProjectService|Leave blank to use your current token.'), - required: true - }, - { - type: 'text', - name: 'zentao_product_xid', - title: s_('ZentaoIntegration|ZenTao Product ID'), - required: true - } - ] - end - private def client |