diff options
Diffstat (limited to 'app/models/integrations')
-rw-r--r-- | app/models/integrations/asana.rb | 18 | ||||
-rw-r--r-- | app/models/integrations/bamboo.rb | 37 | ||||
-rw-r--r-- | app/models/integrations/base_chat_notification.rb | 20 | ||||
-rw-r--r-- | app/models/integrations/base_slack_notification.rb | 3 | ||||
-rw-r--r-- | app/models/integrations/chat_message/alert_message.rb | 4 | ||||
-rw-r--r-- | app/models/integrations/chat_message/deployment_message.rb | 24 | ||||
-rw-r--r-- | app/models/integrations/chat_message/issue_message.rb | 6 | ||||
-rw-r--r-- | app/models/integrations/chat_message/pipeline_message.rb | 18 | ||||
-rw-r--r-- | app/models/integrations/chat_message/push_message.rb | 8 | ||||
-rw-r--r-- | app/models/integrations/discord.rb | 38 | ||||
-rw-r--r-- | app/models/integrations/hangouts_chat.rb | 23 | ||||
-rw-r--r-- | app/models/integrations/integration_list.rb | 29 | ||||
-rw-r--r-- | app/models/integrations/jira.rb | 92 | ||||
-rw-r--r-- | app/models/integrations/pipelines_email.rb | 4 | ||||
-rw-r--r-- | app/models/integrations/pivotaltracker.rb | 4 | ||||
-rw-r--r-- | app/models/integrations/prometheus.rb | 2 | ||||
-rw-r--r-- | app/models/integrations/pushover.rb | 4 | ||||
-rw-r--r-- | app/models/integrations/telegram.rb | 10 |
18 files changed, 239 insertions, 105 deletions
diff --git a/app/models/integrations/asana.rb b/app/models/integrations/asana.rb index 859522670ef..77555996cd9 100644 --- a/app/models/integrations/asana.rb +++ b/app/models/integrations/asana.rb @@ -1,9 +1,10 @@ # frozen_string_literal: true -require 'asana' - module Integrations class Asana < Integration + TASK_URL_TEMPLATE = 'https://app.asana.com/api/1.0/tasks/%{task_gid}' + STORY_URL_TEMPLATE = 'https://app.asana.com/api/1.0/tasks/%{task_gid}/stories' + validates :api_key, presence: true, if: :activated? field :api_key, @@ -40,12 +41,6 @@ module Integrations %w[push] end - def client - @_client ||= ::Asana::Client.new do |c| - c.authentication :access_token, api_key - end - end - def execute(data) return unless supported_events.include?(data[:object_kind]) @@ -78,11 +73,12 @@ module Integrations taskid = tuple[2] || tuple[1] begin - task = ::Asana::Resources::Task.find_by_id(client, taskid) - task.add_comment(text: "#{push_msg} #{message}") + story_on_task_url = format(STORY_URL_TEMPLATE, task_gid: taskid) + Gitlab::HTTP.post(story_on_task_url, headers: { "Authorization" => "Bearer #{api_key}" }, body: { text: "#{push_msg} #{message}" }) if tuple[0] - task.update(completed: true) + task_url = format(TASK_URL_TEMPLATE, task_gid: taskid) + Gitlab::HTTP.put(task_url, headers: { "Authorization" => "Bearer #{api_key}" }, body: { completed: true }) end rescue StandardError => e log_error(e.message) diff --git a/app/models/integrations/bamboo.rb b/app/models/integrations/bamboo.rb index 0b8432136dd..9f15532a0b0 100644 --- a/app/models/integrations/bamboo.rb +++ b/app/models/integrations/bamboo.rb @@ -28,14 +28,13 @@ module Integrations non_empty_password_title: -> { s_('ProjectService|Enter new password') }, non_empty_password_help: -> { s_('ProjectService|Leave blank to use your current password') } - validates :bamboo_url, presence: true, public_url: true, if: :activated? - validates :build_key, presence: true, if: :activated? - validates :username, - presence: true, - if: ->(service) { service.activated? && service.password } - validates :password, - presence: true, - if: ->(service) { service.activated? && service.username } + with_options if: :activated? do + validates :bamboo_url, presence: true, public_url: true + validates :build_key, presence: true + end + + validates :username, presence: true, if: ->(integration) { integration.activated? && integration.password } + validates :password, presence: true, if: ->(integration) { integration.activated? && integration.username } attr_accessor :response @@ -48,8 +47,16 @@ module Integrations end def help - docs_link = ActionController::Base.helpers.link_to _('Learn more.'), Rails.application.routes.url_helpers.help_page_url('user/project/integrations/bamboo'), target: '_blank', rel: 'noopener noreferrer' - s_('BambooService|Run CI/CD pipelines with Atlassian Bamboo. You must set up automatic revision labeling and a repository trigger in Bamboo. %{docs_link}').html_safe % { docs_link: docs_link.html_safe } + docs_link = ActionController::Base.helpers.link_to( + _('Learn more.'), + Rails.application.routes.url_helpers.help_page_url('user/project/integrations/bamboo'), + target: '_blank', + rel: 'noopener noreferrer' + ) + format( + s_('BambooService|Run CI/CD pipelines with Atlassian Bamboo. You must set up automatic revision labeling and ' \ + 'a repository trigger in Bamboo. %{docs_link}').html_safe, + docs_link: docs_link.html_safe) end def self.to_param @@ -70,12 +77,18 @@ module Integrations get_path("updateAndBuild.action", { buildKey: build_key }) end - def calculate_reactive_cache(sha, ref) + def calculate_reactive_cache(sha, _ref) response = try_get_path("rest/api/latest/result/byChangeset/#{sha}") { build_page: read_build_page(response), commit_status: read_commit_status(response) } end + def avatar_url + ActionController::Base.helpers.image_path( + 'illustrations/third-party-logos/integrations-logos/atlassian-bamboo.svg' + ) + end + private def get_build_result(response) @@ -112,7 +125,7 @@ module Integrations if result.blank? 'Pending' else - result.dig('buildState') + result['buildState'] end return :error unless status.present? diff --git a/app/models/integrations/base_chat_notification.rb b/app/models/integrations/base_chat_notification.rb index 2c929dc2cb3..b75801335bd 100644 --- a/app/models/integrations/base_chat_notification.rb +++ b/app/models/integrations/base_chat_notification.rb @@ -13,6 +13,8 @@ module Integrations tag_push pipeline wiki_page deployment incident ].freeze + GROUP_ONLY_SUPPORTED_EVENTS = %w[group_mention group_confidential_mention].freeze + SUPPORTED_EVENTS_FOR_LABEL_FILTER = %w[issue confidential_issue merge_request note confidential_note].freeze EVENT_CHANNEL = proc { |event| "#{event}_channel" } @@ -26,12 +28,12 @@ module Integrations attribute :category, default: 'chat' - prop_accessor :webhook, :username, :channel, :branches_to_be_notified, :labels_to_be_notified, :labels_to_be_notified_behavior + prop_accessor :webhook, :username, :channel, :branches_to_be_notified, :labels_to_be_notified, + :labels_to_be_notified_behavior, :notify_only_default_branch # Custom serialized properties initialization prop_accessor(*SUPPORTED_EVENTS.map { |event| EVENT_CHANNEL[event] }) - - boolean_accessor :notify_only_default_branch + prop_accessor(*GROUP_ONLY_SUPPORTED_EVENTS.map { |event| EVENT_CHANNEL[event] }) validates :webhook, presence: true, @@ -44,10 +46,10 @@ module Integrations super if properties.empty? - self.notify_only_broken_pipelines = true if self.respond_to?(:notify_only_broken_pipelines) + self.notify_only_broken_pipelines = true if respond_to?(:notify_only_broken_pipelines) self.branches_to_be_notified = "default" self.labels_to_be_notified_behavior = MATCH_ANY_LABEL - elsif !self.notify_only_default_branch.nil? + elsif !notify_only_default_branch.nil? # In older versions, there was only a boolean property named # `notify_only_default_branch`. Now we have a string property named # `branches_to_be_notified`. Instead of doing a background migration, we @@ -55,7 +57,7 @@ module Integrations # 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" + self.branches_to_be_notified ||= notify_only_default_branch == 'true' ? "default" : "all" end end @@ -237,7 +239,7 @@ module Integrations case object_kind when "push", "tag_push" Integrations::ChatMessage::PushMessage.new(data) if notify_for_ref?(data) - when "issue" + when "issue", "incident" Integrations::ChatMessage::IssueMessage.new(data) unless update?(data) when "merge_request" Integrations::ChatMessage::MergeMessage.new(data) unless update?(data) @@ -249,8 +251,8 @@ module Integrations Integrations::ChatMessage::WikiPageMessage.new(data) when "deployment" Integrations::ChatMessage::DeploymentMessage.new(data) if notify_for_ref?(data) - when "incident" - Integrations::ChatMessage::IssueMessage.new(data) unless update?(data) + when "group_mention" + Integrations::ChatMessage::GroupMentionMessage.new(data) end end # rubocop:enable Metrics/CyclomaticComplexity diff --git a/app/models/integrations/base_slack_notification.rb b/app/models/integrations/base_slack_notification.rb index 65aec8b278f..09a0c9ba361 100644 --- a/app/models/integrations/base_slack_notification.rb +++ b/app/models/integrations/base_slack_notification.rb @@ -7,8 +7,6 @@ module Integrations ].freeze prop_accessor EVENT_CHANNEL['alert'] - prop_accessor EVENT_CHANNEL['group_mention'] - prop_accessor EVENT_CHANNEL['group_confidential_mention'] override :default_channel_placeholder def default_channel_placeholder @@ -18,7 +16,6 @@ module Integrations override :get_message def get_message(object_kind, data) return Integrations::ChatMessage::AlertMessage.new(data) if object_kind == 'alert' - return Integrations::ChatMessage::GroupMentionMessage.new(data) if object_kind == 'group_mention' super end diff --git a/app/models/integrations/chat_message/alert_message.rb b/app/models/integrations/chat_message/alert_message.rb index e2c689f9435..6c7ea9aed7c 100644 --- a/app/models/integrations/chat_message/alert_message.rb +++ b/app/models/integrations/chat_message/alert_message.rb @@ -34,12 +34,12 @@ module Integrations "Alert firing in #{strip_markup(project_name)}" end - private - def attachment_color "#C95823" end + private + def attachment_fields [ { diff --git a/app/models/integrations/chat_message/deployment_message.rb b/app/models/integrations/chat_message/deployment_message.rb index 0367459dfcb..4d3e962d885 100644 --- a/app/models/integrations/chat_message/deployment_message.rb +++ b/app/models/integrations/chat_message/deployment_message.rb @@ -30,7 +30,7 @@ module Integrations [{ text: format(description_message), - color: color + color: attachment_color }] end @@ -38,17 +38,7 @@ module Integrations {} end - private - - def message - if running? - "Starting deploy to #{strip_markup(environment)}" - else - "Deploy to #{strip_markup(environment)} #{humanized_status}" - end - end - - def color + def attachment_color case status when 'success' 'good' @@ -61,6 +51,16 @@ module Integrations end end + private + + def message + if running? + "Starting deploy to #{strip_markup(environment)}" + else + "Deploy to #{strip_markup(environment)} #{humanized_status}" + end + end + def project_link link(project_name, project_url) end diff --git a/app/models/integrations/chat_message/issue_message.rb b/app/models/integrations/chat_message/issue_message.rb index dd516362491..4c144bc2f68 100644 --- a/app/models/integrations/chat_message/issue_message.rb +++ b/app/models/integrations/chat_message/issue_message.rb @@ -41,6 +41,10 @@ module Integrations } end + def attachment_color + '#C95823' + end + private def message @@ -56,7 +60,7 @@ module Integrations title: issue_title, title_link: issue_url, text: format(SlackMarkdownSanitizer.sanitize_slack_link(description)), - color: '#C95823' + color: attachment_color }] end diff --git a/app/models/integrations/chat_message/pipeline_message.rb b/app/models/integrations/chat_message/pipeline_message.rb index f8a634be336..2abe4a6e9c7 100644 --- a/app/models/integrations/chat_message/pipeline_message.rb +++ b/app/models/integrations/chat_message/pipeline_message.rb @@ -89,6 +89,15 @@ module Integrations } end + def attachment_color + case status + when 'success' + detailed_status == 'passed with warnings' ? 'warning' : 'good' + else + 'danger' + end + end + private def actually_failed_jobs(builds) @@ -180,15 +189,6 @@ module Integrations end end - def attachment_color - case status - when 'success' - detailed_status == 'passed with warnings' ? 'warning' : 'good' - else - 'danger' - end - end - def ref_url if ref_type == 'tag' "#{project_url}/-/tags/#{ref}" diff --git a/app/models/integrations/chat_message/push_message.rb b/app/models/integrations/chat_message/push_message.rb index b17e28bb6c6..ee44fc98791 100644 --- a/app/models/integrations/chat_message/push_message.rb +++ b/app/models/integrations/chat_message/push_message.rb @@ -35,6 +35,10 @@ module Integrations } end + def attachment_color + '#345' + end + private def humanized_action(short: false) @@ -111,10 +115,6 @@ module Integrations ['pushed to', ref_link, "of #{project_link} (#{compare_link})"] end end - - def attachment_color - '#345' - end end end end diff --git a/app/models/integrations/discord.rb b/app/models/integrations/discord.rb index 815e3669d78..33b2b52fa62 100644 --- a/app/models/integrations/discord.rb +++ b/app/models/integrations/discord.rb @@ -42,8 +42,15 @@ module Integrations s_('DiscordService|Override the default webhook (e.g. https://discord.com/api/webhooks/…)') end + override :supported_events + def supported_events + additional = group_level? ? %w[group_mention group_confidential_mention] : [] + + (self.class.supported_events + additional).freeze + end + def self.supported_events - %w[push issue confidential_issue merge_request note confidential_note tag_push pipeline wiki_page] + %w[push issue confidential_issue merge_request note confidential_note tag_push pipeline wiki_page deployment] end def configurable_channels? @@ -68,7 +75,7 @@ module Integrations builder.add_embed do |embed| embed.author = Discordrb::Webhooks::EmbedAuthor.new(name: message.user_name, icon_url: message.user_avatar) embed.description = (message.pretext + "\n" + Array.wrap(message.attachments).join("\n")).gsub(ATTACHMENT_REGEX, " \\k<entry> - \\k<name>\n") - embed.colour = 16543014 # The hex "fc6d26" as an Integer + embed.colour = embed_color(message) embed.timestamp = Time.now.utc end end @@ -77,6 +84,33 @@ module Integrations false end + COLOR_OVERRIDES = { + 'good' => '#0d532a', + 'warning' => '#703800', + 'danger' => '#8d1300' + }.freeze + + def embed_color(message) + return 'fc6d26'.hex unless message.respond_to?(:attachment_color) + + color = message.attachment_color + + color = COLOR_OVERRIDES[color] if COLOR_OVERRIDES.key?(color) + + color = color.delete_prefix('#') + + normalize_color(color).hex + end + + # Expands the short notation to the full colorcode notation + # 123456 -> 123456 + # 123 -> 112233 + def normalize_color(color) + return (color[0, 1] * 2) + (color[1, 1] * 2) + (color[2, 1] * 2) if color.length == 3 + + color + end + def custom_data(data) super(data).merge(markdown: true) end diff --git a/app/models/integrations/hangouts_chat.rb b/app/models/integrations/hangouts_chat.rb index 680752c3d56..6e4753470a3 100644 --- a/app/models/integrations/hangouts_chat.rb +++ b/app/models/integrations/hangouts_chat.rb @@ -30,12 +30,15 @@ module Integrations end def help - docs_link = ActionController::Base.helpers.link_to _('How do I set up a Google Chat webhook?'), Rails.application.routes.url_helpers.help_page_url('user/project/integrations/hangouts_chat'), target: '_blank', rel: 'noopener noreferrer' - 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 } + docs_link = ActionController::Base.helpers.link_to(_('How do I set up a Google Chat webhook?'), + Rails.application.routes.url_helpers.help_page_url('user/project/integrations/hangouts_chat'), + target: '_blank', rel: 'noopener noreferrer') + format( + 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 default_channel_placeholder - end + def default_channel_placeholder; end def self.supported_events %w[push issue confidential_issue merge_request note confidential_note tag_push pipeline wiki_page] @@ -43,14 +46,20 @@ module Integrations private - def notify(message, opts) + def notify(message, _opts) url = webhook.dup key = parse_thread_key(message) url = Gitlab::Utils.add_url_parameters(url, { threadKey: key }) if key - simple_text = parse_simple_text_message(message) - ::HangoutsChat::Sender.new(url).simple(simple_text) + payload = { text: parse_simple_text_message(message) } + + Gitlab::HTTP.post( + url, + body: payload.to_json, + headers: { 'Content-Type' => 'application/json' }, + parse: nil + ).response end # Returns an appropriate key for threading messages in google chat diff --git a/app/models/integrations/integration_list.rb b/app/models/integrations/integration_list.rb new file mode 100644 index 00000000000..ab03e5c0e0a --- /dev/null +++ b/app/models/integrations/integration_list.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +module Integrations + class IntegrationList + def initialize(batch, integration_hash, association) + @batch = batch + @integration_hash = integration_hash + @association = association + end + + def to_array + [Integration, columns, values] + end + + private + + attr_reader :batch, :integration_hash, :association + + def columns + integration_hash.keys << "#{association}_id" + end + + def values + batch.select(:id).map do |record| + integration_hash.values << record.id + end + end + end +end diff --git a/app/models/integrations/jira.rb b/app/models/integrations/jira.rb index d8d1f860e9a..f6e99454cb1 100644 --- a/app/models/integrations/jira.rb +++ b/app/models/integrations/jira.rb @@ -11,8 +11,12 @@ module Integrations PROJECTS_PER_PAGE = 50 JIRA_CLOUD_HOST = '.atlassian.net' - ATLASSIAN_REFERRER_GITLAB_COM = { atlOrigin: 'eyJpIjoiY2QyZTJiZDRkNGZhNGZlMWI3NzRkNTBmZmVlNzNiZTkiLCJwIjoianN3LWdpdGxhYi1pbnQifQ' }.freeze - ATLASSIAN_REFERRER_SELF_MANAGED = { atlOrigin: 'eyJpIjoiYjM0MTA4MzUyYTYxNDVkY2IwMzVjOGQ3ZWQ3NzMwM2QiLCJwIjoianN3LWdpdGxhYlNNLWludCJ9' }.freeze + ATLASSIAN_REFERRER_GITLAB_COM = { + atlOrigin: 'eyJpIjoiY2QyZTJiZDRkNGZhNGZlMWI3NzRkNTBmZmVlNzNiZTkiLCJwIjoianN3LWdpdGxhYi1pbnQifQ' + }.freeze + ATLASSIAN_REFERRER_SELF_MANAGED = { + atlOrigin: 'eyJpIjoiYjM0MTA4MzUyYTYxNDVkY2IwMzVjOGQ3ZWQ3NzMwM2QiLCJwIjoianN3LWdpdGxhYlNNLWludCJ9' + }.freeze API_ENDPOINTS = { find_issue: "/rest/api/2/issue/%s", @@ -28,11 +32,13 @@ module Integrations AUTH_TYPE_BASIC = 0 AUTH_TYPE_PAT = 1 - SNOWPLOW_EVENT_CATEGORY = self.name + SNOWPLOW_EVENT_CATEGORY = name validates :url, public_url: true, presence: true, if: :activated? validates :api_url, public_url: true, allow_blank: true - validates :username, presence: true, if: ->(object) { object.activated? && !object.personal_access_token_authorization? } + validates :username, presence: true, if: ->(object) { + object.activated? && !object.personal_access_token_authorization? + } validates :password, presence: true, if: :activated? validates :jira_auth_type, presence: true, inclusion: { in: [AUTH_TYPE_BASIC, AUTH_TYPE_PAT] }, if: :activated? validates :jira_issue_prefix, untrusted_regexp: true, length: { maximum: 255 }, if: :activated? @@ -130,7 +136,7 @@ module Integrations end # {PROJECT-KEY}-{NUMBER} Examples: JIRA-1, PROJECT-1 - def reference_pattern(only_long: true) + def reference_pattern(*) @reference_pattern ||= jira_issue_match_regex end @@ -144,7 +150,7 @@ module Integrations end def data_fields - jira_tracker_data || self.build_jira_tracker_data + jira_tracker_data || build_jira_tracker_data end def set_default_data @@ -186,8 +192,13 @@ module Integrations end def help - jira_doc_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_page_path('integration/jira/index') } - s_("JiraService|You must configure Jira before enabling this integration. %{jira_doc_link_start}Learn more.%{link_end}") % { jira_doc_link_start: jira_doc_link_start, link_end: '</a>'.html_safe } + jira_doc_link_start = format('<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe, + url: help_page_path('integration/jira/index')) + format( + s_("JiraService|You must configure Jira before enabling this integration. " \ + "%{jira_doc_link_start}Learn more.%{link_end}"), + jira_doc_link_start: jira_doc_link_start, + link_end: '</a>'.html_safe) end def title @@ -212,7 +223,8 @@ module Integrations { type: SECTION_TYPE_JIRA_TRIGGER, title: _('Trigger'), - description: s_('JiraService|When a Jira issue is mentioned in a commit or merge request, a remote link and comment (if enabled) will be created.') + description: s_('JiraService|When a Jira issue is mentioned in a commit or merge request, a remote link ' \ + 'and comment (if enabled) will be created.') }, { type: SECTION_TYPE_CONFIGURATION, @@ -313,7 +325,8 @@ module Integrations override :create_cross_reference_note def create_cross_reference_note(external_issue, mentioned_in, author) unless can_cross_reference?(mentioned_in) - return s_("JiraService|Events for %{noteable_model_name} are disabled.") % { noteable_model_name: mentioned_in.model_name.plural.humanize(capitalize: false) } + return format(s_("JiraService|Events for %{noteable_model_name} are disabled."), + noteable_model_name: mentioned_in.model_name.plural.humanize(capitalize: false)) end jira_issue = find_issue(external_issue.id) @@ -381,6 +394,10 @@ module Integrations jira_auth_type == AUTH_TYPE_PAT end + def avatar_url + ActionController::Base.helpers.image_path('illustrations/third-party-logos/integrations-logos/jira.svg') + end + private def jira_issue_match_regex @@ -398,10 +415,9 @@ module Integrations end def server_info - strong_memoize(:server_info) do - client_url.present? ? jira_request(API_ENDPOINTS[:server_info]) { client.ServerInfo.all.attrs } : nil - end + client_url.present? ? jira_request(API_ENDPOINTS[:server_info]) { client.ServerInfo.all.attrs } : nil end + strong_memoize_attr :server_info def can_cross_reference?(mentioned_in) case mentioned_in @@ -430,7 +446,8 @@ module Integrations true rescue StandardError => e path = API_ENDPOINTS[:transition_issue] % issue.id - log_exception(e, message: 'Issue transition failed', client_url: client_url, client_path: path, client_status: '400') + log_exception(e, message: 'Issue transition failed', client_url: client_url, client_path: path, + client_status: '400') false end @@ -488,9 +505,9 @@ module Integrations link_title = "#{entity_name.capitalize} - #{entity_title}" link_props = build_remote_link_props(url: entity_url, title: link_title) - unless comment_exists?(issue, message) - send_message(issue, message, link_props) - end + return if comment_exists?(issue, message) + + send_message(issue, message, link_props) end def comment_message(data) @@ -503,21 +520,22 @@ module Integrations project_link = build_jira_link(project.full_name, Gitlab::Routing.url_helpers.project_url(project)) branch = if entity[:branch].present? - s_('JiraService| on branch %{branch_link}') % { - branch_link: build_jira_link(entity[:branch], project_tree_url(project, entity[:branch])) - } + format(s_('JiraService| on branch %{branch_link}'), + branch_link: build_jira_link(entity[:branch], project_tree_url(project, entity[:branch]))) end entity_message = entity[:description].presence if all_details? entity_message ||= entity[:title].chomp - s_('JiraService|%{user_link} mentioned this issue in %{entity_link} of %{project_link}%{branch}:{quote}%{entity_message}{quote}') % { + format( + s_('JiraService|%{user_link} mentioned this issue in %{entity_link} of ' \ + '%{project_link}%{branch}:{quote}%{entity_message}{quote}'), user_link: user_link, entity_link: entity_link, project_link: project_link, branch: branch, entity_message: entity_message - } + ) end def build_jira_link(title, url) @@ -586,13 +604,13 @@ module Integrations end def resource_url(resource) - "#{Settings.gitlab.base_url.chomp("/")}#{resource}" + "#{Settings.gitlab.base_url.chomp('/')}#{resource}" end def build_entity_url(entity_type, entity_id) polymorphic_url( [ - self.project, + project, entity_type.to_sym ], id: entity_id, @@ -631,7 +649,8 @@ module Integrations yield rescue StandardError => e @error = e - log_exception(e, message: 'Error sending message', client_url: client_url, client_path: path, client_status: e.try(:code)) + log_exception(e, message: 'Error sending message', client_url: client_url, client_path: path, + client_status: e.try(:code)) nil end @@ -648,7 +667,8 @@ module Integrations results = server_info unless results.present? - Gitlab::AppLogger.warn(message: "Jira API returned no ServerInfo, setting deployment_type from URL", server_info: results, url: client_url) + Gitlab::AppLogger.warn(message: "Jira API returned no ServerInfo, setting deployment_type from URL", + server_info: results, url: client_url) return set_deployment_type_from_url end @@ -681,13 +701,25 @@ module Integrations end def jira_issues_section_description - jira_issues_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_page_path('integration/jira/issues') } - description = s_('JiraService|Work on Jira issues without leaving GitLab. Add a Jira menu to access a read-only list of your Jira issues. %{jira_issues_link_start}Learn more.%{link_end}') % { jira_issues_link_start: jira_issues_link_start, link_end: '</a>'.html_safe } + jira_issues_link_start = format('<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe, + url: help_page_path('integration/jira/issues')) + description = format( + s_('JiraService|Work on Jira issues without leaving GitLab. Add a Jira menu to access a read-only list of ' \ + 'your Jira issues. %{jira_issues_link_start}Learn more.%{link_end}'), + jira_issues_link_start: jira_issues_link_start, + link_end: '</a>'.html_safe + ) if project&.issues_enabled? - gitlab_issues_link_start = '<a href="%{url}">'.html_safe % { url: edit_project_path(project, anchor: 'js-shared-permissions') } + gitlab_issues_link_start = format('<a href="%{url}">'.html_safe, url: edit_project_path(project, + anchor: 'js-shared-permissions')) description += '<br><br>'.html_safe - description += s_("JiraService|Displaying Jira issues while leaving GitLab issues also enabled might be confusing. Consider %{gitlab_issues_link_start}disabling GitLab issues%{link_end} if they won't otherwise be used.") % { gitlab_issues_link_start: gitlab_issues_link_start, link_end: '</a>'.html_safe } + description += format( + s_("JiraService|Displaying Jira issues while leaving GitLab issues also enabled might be confusing. " \ + "Consider %{gitlab_issues_link_start}disabling GitLab issues%{link_end} if they won't otherwise be used."), + gitlab_issues_link_start: gitlab_issues_link_start, + link_end: '</a>'.html_safe + ) end description diff --git a/app/models/integrations/pipelines_email.rb b/app/models/integrations/pipelines_email.rb index fa22bd1a73c..01efbc3e4a4 100644 --- a/app/models/integrations/pipelines_email.rb +++ b/app/models/integrations/pipelines_email.rb @@ -37,8 +37,8 @@ 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 hasn't specified one already. When users edit the service and - # selects a value for this new property, it will override everything. + # 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" end diff --git a/app/models/integrations/pivotaltracker.rb b/app/models/integrations/pivotaltracker.rb index f42a872c49e..b3cbc988dd6 100644 --- a/app/models/integrations/pivotaltracker.rb +++ b/app/models/integrations/pivotaltracker.rb @@ -65,6 +65,10 @@ module Integrations end end + def avatar_url + ActionController::Base.helpers.image_path('illustrations/third-party-logos/integrations-logos/pivotal-tracker.svg') + end + private def allowed_branch?(ref) diff --git a/app/models/integrations/prometheus.rb b/app/models/integrations/prometheus.rb index 8474a5b7adf..ff8d07a1b4c 100644 --- a/app/models/integrations/prometheus.rb +++ b/app/models/integrations/prometheus.rb @@ -185,7 +185,7 @@ module Integrations # Remove in next required stop after %16.4 # https://gitlab.com/gitlab-org/gitlab/-/issues/338838 def sync_http_integration! - return unless manual_configuration_changed? + return unless manual_configuration_changed? && !manual_configuration_was.nil? project.alert_management_http_integrations .for_endpoint_identifier('legacy-prometheus') diff --git a/app/models/integrations/pushover.rb b/app/models/integrations/pushover.rb index e97c7e5e738..2feae29f627 100644 --- a/app/models/integrations/pushover.rb +++ b/app/models/integrations/pushover.rb @@ -125,5 +125,9 @@ module Integrations Gitlab::HTTP.post('/messages.json', base_uri: BASE_URI, body: pushover_data) end + + def avatar_url + ActionController::Base.helpers.image_path('illustrations/third-party-logos/integrations-logos/pushover.svg') + end end end diff --git a/app/models/integrations/telegram.rb b/app/models/integrations/telegram.rb index 7c196720386..71fe6f8d6ef 100644 --- a/app/models/integrations/telegram.rb +++ b/app/models/integrations/telegram.rb @@ -26,6 +26,12 @@ module Integrations section: SECTION_TYPE_CONFIGURATION, help: 'If selected, successful pipelines do not trigger a notification event.' + field :branches_to_be_notified, + type: :select, + section: SECTION_TYPE_CONFIGURATION, + title: -> { s_('Integrations|Branches for which notifications are to be sent') }, + choices: -> { branch_choices } + with_options if: :activated? do validates :token, :room, presence: true end @@ -60,6 +66,10 @@ module Integrations super - ['deployment'] end + def avatar_url + ActionController::Base.helpers.image_path('illustrations/third-party-logos/integrations-logos/telegram.svg') + end + private def set_webhook |