1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
|
# frozen_string_literal: true
require "discordrb/webhooks"
module Integrations
class Discord < BaseChatNotification
ATTACHMENT_REGEX = Gitlab::UntrustedRegexp.new(': (?<entry>[^\n]*)\n - (?<name>[^\n]*)\n*')
field :webhook,
section: SECTION_TYPE_CONNECTION,
description: -> { _('Discord webhook (for example, `https://discord.com/api/webhooks/…`).') },
help: 'e.g. https://discord.com/api/webhooks/…',
required: true
field :notify_only_broken_pipelines,
type: :checkbox,
section: SECTION_TYPE_CONFIGURATION,
description: -> { _('Send notifications for broken pipelines.') }
field :branches_to_be_notified,
type: :select,
section: SECTION_TYPE_CONFIGURATION,
title: -> { s_('Integrations|Branches for which notifications are to be sent') },
description: -> { _('Branches to send notifications for. Valid options are `all`, `default`, `protected`, and `default_and_protected`. The default value is `default`.') },
choices: -> { branch_choices }
def self.title
s_("DiscordService|Discord Notifications")
end
def self.description
s_("DiscordService|Send notifications about project events to a Discord channel.")
end
def self.help
build_help_page_url(
'user/project/integrations/discord_notifications.md',
s_("DiscordService|Send notifications about project events to a Discord channel."),
_('How do I set up this integration?')
)
end
def self.to_param
"discord"
end
def default_channel_placeholder
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 deployment]
end
def configurable_channels?
true
end
def channel_limit_per_event
1
end
def mask_configurable_channels?
true
end
private
def notify(message, opts)
webhook_url = opts[:channel]&.first || webhook
client = Discordrb::Webhooks::Client.new(url: webhook_url)
client.execute do |builder|
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"))
if ATTACHMENT_REGEX.match?(embed.description)
embed.description = ATTACHMENT_REGEX.replace_gsub(embed.description) do |match|
" #{match[:entry]} - #{match[:name]}\n"
end
end
embed.colour = embed_color(message)
embed.timestamp = Time.now.utc
end
end
rescue RestClient::Exception => e
log_error(e.message)
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
end
end
|