mirror of
https://gitlab.com/gitlab-org/gitlab-foss.git
synced 2025-07-23 00:47:51 +00:00
Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
@ -6,6 +6,7 @@ export default {
|
||||
i18n: {
|
||||
buttonLabel: __('Add request manually'),
|
||||
inputLabel: __('URL or request ID'),
|
||||
submitLabel: __('Add'),
|
||||
},
|
||||
components: {
|
||||
GlForm,
|
||||
@ -38,7 +39,7 @@ export default {
|
||||
</script>
|
||||
<template>
|
||||
<div id="peek-view-add-request" class="view gl-flex">
|
||||
<gl-form class="gl-flex gl-items-center" @submit.prevent>
|
||||
<gl-form class="gl-flex gl-items-center" @submit.prevent="addRequest">
|
||||
<gl-button
|
||||
v-gl-tooltip.viewport
|
||||
class="gl-mr-2"
|
||||
@ -50,16 +51,28 @@ export default {
|
||||
:aria-label="$options.i18n.buttonLabel"
|
||||
@click="toggleInput"
|
||||
/>
|
||||
<gl-form-input
|
||||
v-if="inputEnabled"
|
||||
v-model="urlOrRequestId"
|
||||
type="text"
|
||||
:placeholder="$options.i18n.inputLabel"
|
||||
:aria-label="$options.i18n.inputLabel"
|
||||
class="gl-ml-2 !gl-px-3 !gl-py-2"
|
||||
@keyup.enter="addRequest"
|
||||
@keyup.esc="clearForm"
|
||||
/>
|
||||
<template v-if="inputEnabled">
|
||||
<gl-form-input
|
||||
v-model="urlOrRequestId"
|
||||
type="text"
|
||||
:placeholder="$options.i18n.inputLabel"
|
||||
:aria-label="$options.i18n.inputLabel"
|
||||
class="gl-ml-2 !gl-px-3 !gl-py-2"
|
||||
@keyup.esc="clearForm"
|
||||
/>
|
||||
<gl-button
|
||||
v-gl-tooltip.viewport
|
||||
class="gl-ml-2"
|
||||
category="tertiary"
|
||||
type="submit"
|
||||
variant="link"
|
||||
icon="file-addition-solid"
|
||||
size="small"
|
||||
:aria-label="$options.i18n.submitLabel"
|
||||
>
|
||||
{{ $options.i18n.submitLabel }}
|
||||
</gl-button>
|
||||
</template>
|
||||
</gl-form>
|
||||
</div>
|
||||
</template>
|
||||
|
134
app/models/concerns/integrations/base/telegram.rb
Normal file
134
app/models/concerns/integrations/base/telegram.rb
Normal file
@ -0,0 +1,134 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Integrations
|
||||
module Base
|
||||
module Telegram
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
include HasAvatar
|
||||
include Base::ChatNotification
|
||||
|
||||
TELEGRAM_HOSTNAME = "%{hostname}/bot%{token}/sendMessage"
|
||||
|
||||
class_methods do
|
||||
def title
|
||||
'Telegram'
|
||||
end
|
||||
|
||||
def description
|
||||
s_("TelegramIntegration|Send notifications about project events to Telegram.")
|
||||
end
|
||||
|
||||
def to_param
|
||||
'telegram'
|
||||
end
|
||||
|
||||
def help
|
||||
build_help_page_url(
|
||||
'user/project/integrations/telegram.md',
|
||||
s_("TelegramIntegration|Send notifications about project events to Telegram.")
|
||||
)
|
||||
end
|
||||
|
||||
def supported_events
|
||||
super - ['deployment']
|
||||
end
|
||||
end
|
||||
|
||||
included do
|
||||
field :hostname,
|
||||
title: -> { _('Hostname') },
|
||||
section: Integrations::Base::Integration::SECTION_TYPE_CONNECTION,
|
||||
help: -> { _('Custom hostname of the Telegram API. The default value is `https://api.telegram.org`.') },
|
||||
placeholder: 'https://api.telegram.org',
|
||||
exposes_secrets: true,
|
||||
required: false
|
||||
|
||||
field :token,
|
||||
title: -> { _('Token') },
|
||||
section: Integrations::Base::Integration::SECTION_TYPE_CONNECTION,
|
||||
help: -> { s_('TelegramIntegration|Unique authentication token.') },
|
||||
non_empty_password_title: -> { s_('TelegramIntegration|New token') },
|
||||
non_empty_password_help: -> { s_('TelegramIntegration|Leave blank to use your current token.') },
|
||||
placeholder: '123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11',
|
||||
description: -> { _('The Telegram bot token (for example, `123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11`).') },
|
||||
exposes_secrets: true,
|
||||
is_secret: true,
|
||||
required: true
|
||||
|
||||
field :room,
|
||||
title: -> { _('Channel identifier') },
|
||||
section: Integrations::Base::Integration::SECTION_TYPE_CONFIGURATION,
|
||||
help: -> {
|
||||
_("Unique identifier for the target chat or the username of the target channel " \
|
||||
"(in the format `@channelusername`).")
|
||||
},
|
||||
placeholder: '@channelusername',
|
||||
required: true
|
||||
|
||||
field :thread,
|
||||
title: -> { _('Message thread ID') },
|
||||
section: Integrations::Base::Integration::SECTION_TYPE_CONFIGURATION,
|
||||
help: -> { _('Unique identifier for the target message thread (topic in a forum supergroup).') },
|
||||
placeholder: '123',
|
||||
required: false
|
||||
|
||||
field :notify_only_broken_pipelines,
|
||||
title: -> { _('Notify only broken pipelines') },
|
||||
type: :checkbox,
|
||||
section: Integrations::Base::Integration::SECTION_TYPE_CONFIGURATION,
|
||||
description: -> { _('Send notifications for broken pipelines.') },
|
||||
help: -> { _('If selected, successful pipelines do not trigger a notification event.') }
|
||||
|
||||
field :branches_to_be_notified,
|
||||
type: :select,
|
||||
section: Integrations::Base::Integration::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 }
|
||||
|
||||
with_options if: :activated? do
|
||||
validates :token, :room, presence: true
|
||||
validates :thread, numericality: { only_integer: true }, allow_blank: true
|
||||
end
|
||||
|
||||
before_validation :set_webhook
|
||||
|
||||
private
|
||||
|
||||
def set_webhook
|
||||
hostname = self.hostname.presence || 'https://api.telegram.org'
|
||||
self.webhook = format(TELEGRAM_HOSTNAME, hostname: hostname, token: token) if token.present?
|
||||
end
|
||||
|
||||
def notify(message, _opts)
|
||||
body = {
|
||||
text: message.summary,
|
||||
chat_id: room,
|
||||
message_thread_id: thread,
|
||||
parse_mode: 'markdown'
|
||||
}.compact_blank
|
||||
|
||||
header = { 'Content-Type' => 'application/json' }
|
||||
response = Gitlab::HTTP.post(webhook, headers: header, body: Gitlab::Json.dump(body))
|
||||
|
||||
# We're retrying the request with a different format to ensure accurate formatting and
|
||||
# avoid receiving a 400 response due to invalid markdown.
|
||||
if response.bad_request?
|
||||
body.except!(:parse_mode)
|
||||
response = Gitlab::HTTP.post(webhook, headers: header, body: Gitlab::Json.dump(body))
|
||||
end
|
||||
|
||||
response if response.success?
|
||||
end
|
||||
|
||||
def custom_data(data)
|
||||
super.merge(markdown: true)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -3,7 +3,7 @@
|
||||
module Integrations
|
||||
module Instance
|
||||
class Telegram < Integration
|
||||
# To be updated as part of https://gitlab.com/gitlab-org/gitlab/-/issues/474809
|
||||
include Integrations::Base::Telegram
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -2,125 +2,6 @@
|
||||
|
||||
module Integrations
|
||||
class Telegram < Integration
|
||||
include HasAvatar
|
||||
include Base::ChatNotification
|
||||
|
||||
TELEGRAM_HOSTNAME = "%{hostname}/bot%{token}/sendMessage"
|
||||
|
||||
field :hostname,
|
||||
title: -> { _('Hostname') },
|
||||
section: SECTION_TYPE_CONNECTION,
|
||||
help: -> { _('Custom hostname of the Telegram API. The default value is `https://api.telegram.org`.') },
|
||||
placeholder: 'https://api.telegram.org',
|
||||
exposes_secrets: true,
|
||||
required: false
|
||||
|
||||
field :token,
|
||||
title: -> { _('Token') },
|
||||
section: SECTION_TYPE_CONNECTION,
|
||||
help: -> { s_('TelegramIntegration|Unique authentication token.') },
|
||||
non_empty_password_title: -> { s_('TelegramIntegration|New token') },
|
||||
non_empty_password_help: -> { s_('TelegramIntegration|Leave blank to use your current token.') },
|
||||
placeholder: '123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11',
|
||||
description: -> { _('The Telegram bot token (for example, `123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11`).') },
|
||||
exposes_secrets: true,
|
||||
is_secret: true,
|
||||
required: true
|
||||
|
||||
field :room,
|
||||
title: -> { _('Channel identifier') },
|
||||
section: SECTION_TYPE_CONFIGURATION,
|
||||
help: -> {
|
||||
_("Unique identifier for the target chat or the username of the target channel " \
|
||||
"(in the format `@channelusername`).")
|
||||
},
|
||||
placeholder: '@channelusername',
|
||||
required: true
|
||||
|
||||
field :thread,
|
||||
title: -> { _('Message thread ID') },
|
||||
section: SECTION_TYPE_CONFIGURATION,
|
||||
help: -> { _('Unique identifier for the target message thread (topic in a forum supergroup).') },
|
||||
placeholder: '123',
|
||||
required: false
|
||||
|
||||
field :notify_only_broken_pipelines,
|
||||
title: -> { _('Notify only broken pipelines') },
|
||||
type: :checkbox,
|
||||
section: SECTION_TYPE_CONFIGURATION,
|
||||
description: -> { _('Send notifications for broken pipelines.') },
|
||||
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') },
|
||||
description: -> {
|
||||
_('Branches to send notifications for. Valid options are `all`, `default`, `protected`, ' \
|
||||
'and `default_and_protected`. The default value is `default`.')
|
||||
},
|
||||
choices: -> { branch_choices }
|
||||
|
||||
with_options if: :activated? do
|
||||
validates :token, :room, presence: true
|
||||
validates :thread, numericality: { only_integer: true }, allow_blank: true
|
||||
end
|
||||
|
||||
before_validation :set_webhook
|
||||
|
||||
def self.title
|
||||
'Telegram'
|
||||
end
|
||||
|
||||
def self.description
|
||||
s_("TelegramIntegration|Send notifications about project events to Telegram.")
|
||||
end
|
||||
|
||||
def self.to_param
|
||||
'telegram'
|
||||
end
|
||||
|
||||
def self.help
|
||||
build_help_page_url(
|
||||
'user/project/integrations/telegram.md',
|
||||
s_("TelegramIntegration|Send notifications about project events to Telegram.")
|
||||
)
|
||||
end
|
||||
|
||||
def self.supported_events
|
||||
super - ['deployment']
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_webhook
|
||||
hostname = self.hostname.presence || 'https://api.telegram.org'
|
||||
self.webhook = format(TELEGRAM_HOSTNAME, hostname: hostname, token: token) if token.present?
|
||||
end
|
||||
|
||||
def notify(message, _opts)
|
||||
body = {
|
||||
text: message.summary,
|
||||
chat_id: room,
|
||||
message_thread_id: thread,
|
||||
parse_mode: 'markdown'
|
||||
}.compact_blank
|
||||
|
||||
header = { 'Content-Type' => 'application/json' }
|
||||
response = Gitlab::HTTP.post(webhook, headers: header, body: Gitlab::Json.dump(body))
|
||||
|
||||
# We're retrying the request with a different format to ensure accurate formatting and
|
||||
# avoid receiving a 400 response due to invalid markdown.
|
||||
if response.bad_request?
|
||||
body.except!(:parse_mode)
|
||||
response = Gitlab::HTTP.post(webhook, headers: header, body: Gitlab::Json.dump(body))
|
||||
end
|
||||
|
||||
response if response.success?
|
||||
end
|
||||
|
||||
def custom_data(data)
|
||||
super(data).merge(markdown: true)
|
||||
end
|
||||
include Integrations::Base::Telegram
|
||||
end
|
||||
end
|
||||
|
@ -8,14 +8,6 @@ description: Keeps connection between merge request and project approval rule
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/8497
|
||||
milestone: '11.7'
|
||||
gitlab_schema: gitlab_main_cell
|
||||
desired_sharding_key:
|
||||
project_id:
|
||||
references: projects
|
||||
backfill_via:
|
||||
parent:
|
||||
foreign_key: approval_project_rule_id
|
||||
table: approval_project_rules
|
||||
sharding_key: project_id
|
||||
belongs_to: approval_project_rule
|
||||
desired_sharding_key_migration_job_name: BackfillApprovalMergeRequestRuleSourcesProjectId
|
||||
table_size: small
|
||||
sharding_key:
|
||||
project_id: projects
|
||||
|
@ -0,0 +1,13 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class ValidateApprovalMergeRequestRuleSourcesProjectIdNotNullConstraint < Gitlab::Database::Migration[2.2]
|
||||
milestone '17.10'
|
||||
|
||||
def up
|
||||
validate_not_null_constraint :approval_merge_request_rule_sources, :project_id
|
||||
end
|
||||
|
||||
def down
|
||||
# no-op
|
||||
end
|
||||
end
|
1
db/schema_migrations/20250210064812
Normal file
1
db/schema_migrations/20250210064812
Normal file
@ -0,0 +1 @@
|
||||
f46d1d2ae51d974cb2fd139b82f87b72a3ef4ca666f36630012ffef297f38f38
|
@ -8534,7 +8534,8 @@ CREATE TABLE approval_merge_request_rule_sources (
|
||||
id bigint NOT NULL,
|
||||
approval_merge_request_rule_id bigint NOT NULL,
|
||||
approval_project_rule_id bigint NOT NULL,
|
||||
project_id bigint
|
||||
project_id bigint,
|
||||
CONSTRAINT check_f82666a937 CHECK ((project_id IS NOT NULL))
|
||||
);
|
||||
|
||||
CREATE SEQUENCE approval_merge_request_rule_sources_id_seq
|
||||
@ -27257,9 +27258,6 @@ ALTER TABLE project_relation_exports
|
||||
ALTER TABLE merge_request_blocks
|
||||
ADD CONSTRAINT check_f8034ca45e CHECK ((project_id IS NOT NULL)) NOT VALID;
|
||||
|
||||
ALTER TABLE approval_merge_request_rule_sources
|
||||
ADD CONSTRAINT check_f82666a937 CHECK ((project_id IS NOT NULL)) NOT VALID;
|
||||
|
||||
ALTER TABLE projects
|
||||
ADD CONSTRAINT check_fa75869cb1 CHECK ((project_namespace_id IS NOT NULL)) NOT VALID;
|
||||
|
||||
|
@ -21,6 +21,12 @@ Sometimes, HAML page is enough to satisfy requirements. This statement is correc
|
||||
|
||||
To better explain this, let's imagine the page that has one toggle, and toggling it sends an API request. This case does not involve any state we want to maintain, we send the request and switch the toggle. However, if we add one more toggle that should always be the opposite to the first one, we need a _state_: one toggle should be "aware" about the state of another one. When written in plain JavaScript, this logic usually involves listening to DOM event and reacting with modifying DOM. Cases like this are much easier to handle with Vue.js so we should create a Vue application here.
|
||||
|
||||
## How to add a Vue application to a page
|
||||
|
||||
1. Create a new folder in `app/assets/javascripts` for your Vue application.
|
||||
1. Add [page-specific JavaScript](performance.md#page-specific-javascript) to load your application.
|
||||
1. You can use the [`initSimpleApp helper](#the-initsimpleapp-helper) to simplify [passing data from HAML to JS](#providing-data-from-haml-to-javascript).
|
||||
|
||||
### What are some flags signaling that you might need Vue application?
|
||||
|
||||
- when you need to define complex conditionals based on multiple factors and update them on user interaction;
|
||||
|
@ -8,6 +8,7 @@ describe('add request form', () => {
|
||||
|
||||
const findGlFormInput = () => wrapper.findComponent(GlFormInput);
|
||||
const findGlButton = () => wrapper.findComponent(GlButton);
|
||||
const findGlSubmit = () => wrapper.findComponent('[type=submit]');
|
||||
|
||||
beforeEach(() => {
|
||||
wrapper = mount(AddRequest);
|
||||
@ -15,6 +16,7 @@ describe('add request form', () => {
|
||||
|
||||
it('hides the input on load', () => {
|
||||
expect(findGlFormInput().exists()).toBe(false);
|
||||
expect(findGlSubmit().exists()).toBe(false);
|
||||
});
|
||||
|
||||
describe('when clicking the button', () => {
|
||||
@ -25,6 +27,7 @@ describe('add request form', () => {
|
||||
|
||||
it('shows the form', () => {
|
||||
expect(findGlFormInput().exists()).toBe(true);
|
||||
expect(findGlSubmit().exists()).toBe(true);
|
||||
});
|
||||
|
||||
describe('when pressing escape', () => {
|
||||
@ -35,6 +38,7 @@ describe('add request form', () => {
|
||||
|
||||
it('hides the input', () => {
|
||||
expect(findGlFormInput().exists()).toBe(false);
|
||||
expect(findGlSubmit().exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@ -42,7 +46,7 @@ describe('add request form', () => {
|
||||
beforeEach(async () => {
|
||||
findGlFormInput().setValue('http://gitlab.example.com/users/root/calendar.json');
|
||||
await nextTick();
|
||||
findGlFormInput().trigger('keyup.enter');
|
||||
findGlSubmit().trigger('submit');
|
||||
await nextTick();
|
||||
});
|
||||
|
||||
@ -55,6 +59,7 @@ describe('add request form', () => {
|
||||
|
||||
it('hides the input', () => {
|
||||
expect(findGlFormInput().exists()).toBe(false);
|
||||
expect(findGlSubmit().exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('clears the value for next time', async () => {
|
||||
|
7
spec/models/integrations/instance/telegram_spec.rb
Normal file
7
spec/models/integrations/instance/telegram_spec.rb
Normal file
@ -0,0 +1,7 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "spec_helper"
|
||||
|
||||
RSpec.describe Integrations::Instance::Telegram, feature_category: :integrations do
|
||||
it_behaves_like Integrations::Base::Telegram
|
||||
end
|
@ -3,99 +3,5 @@
|
||||
require "spec_helper"
|
||||
|
||||
RSpec.describe Integrations::Telegram, feature_category: :integrations do
|
||||
it_behaves_like Integrations::HasAvatar
|
||||
it_behaves_like "chat integration", "Telegram" do
|
||||
let(:payload) do
|
||||
{
|
||||
text: be_present
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
describe 'validations' do
|
||||
context 'when integration is active' do
|
||||
before do
|
||||
subject.activate!
|
||||
end
|
||||
|
||||
it { is_expected.to validate_presence_of(:token) }
|
||||
it { is_expected.to validate_presence_of(:room) }
|
||||
it { is_expected.to validate_numericality_of(:thread).only_integer }
|
||||
end
|
||||
|
||||
context 'when integration is inactive' do
|
||||
before do
|
||||
subject.deactivate!
|
||||
end
|
||||
|
||||
it { is_expected.not_to validate_presence_of(:token) }
|
||||
it { is_expected.not_to validate_presence_of(:room) }
|
||||
it { is_expected.not_to validate_numericality_of(:thread).only_integer }
|
||||
end
|
||||
end
|
||||
|
||||
describe 'before_validation :set_webhook' do
|
||||
context 'when token is not present' do
|
||||
let(:integration) { build(:telegram_integration, token: nil) }
|
||||
|
||||
it 'does not set webhook value' do
|
||||
expect(integration.webhook).to eq(nil)
|
||||
expect(integration).not_to be_valid
|
||||
end
|
||||
end
|
||||
|
||||
context 'when token is present' do
|
||||
let(:integration) { build_stubbed(:telegram_integration) }
|
||||
|
||||
it 'sets webhook value' do
|
||||
expect(integration).to be_valid
|
||||
expect(integration.webhook).to eq("https://api.telegram.org/bot123456:ABC-DEF1234/sendMessage")
|
||||
end
|
||||
|
||||
context 'with custom hostname' do
|
||||
before do
|
||||
integration.hostname = 'https://gitlab.example.com'
|
||||
end
|
||||
|
||||
it 'sets webhook value with custom hostname' do
|
||||
expect(integration).to be_valid
|
||||
expect(integration.webhook).to eq("https://gitlab.example.com/bot123456:ABC-DEF1234/sendMessage")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#notify' do
|
||||
let(:subject) { build(:telegram_integration) }
|
||||
let(:message) { instance_double(Integrations::ChatMessage::PushMessage, summary: '_Test message') }
|
||||
let(:header) { { 'Content-Type' => 'application/json' } }
|
||||
let(:response) { instance_double(HTTParty::Response, bad_request?: true, success?: true) }
|
||||
let(:body_1) do
|
||||
{
|
||||
text: '_Test message',
|
||||
chat_id: subject.room,
|
||||
message_thread_id: subject.thread,
|
||||
parse_mode: 'markdown'
|
||||
}.compact_blank
|
||||
end
|
||||
|
||||
let(:body_2) { body_1.without(:parse_mode) }
|
||||
|
||||
before do
|
||||
allow(Gitlab::HTTP).to receive(:post).and_return(response)
|
||||
end
|
||||
|
||||
it 'removes the parse mode if the first request fails with a bad request' do
|
||||
expect(Gitlab::HTTP).to receive(:post).with(subject.webhook, headers: header, body: Gitlab::Json.dump(body_1))
|
||||
expect(Gitlab::HTTP).to receive(:post).with(subject.webhook, headers: header, body: Gitlab::Json.dump(body_2))
|
||||
|
||||
subject.send(:notify, message, {})
|
||||
end
|
||||
|
||||
it 'makes a second request if the first one fails with a bad request' do
|
||||
expect(Gitlab::HTTP).to receive(:post).twice
|
||||
|
||||
subject.send(:notify, message, {})
|
||||
end
|
||||
end
|
||||
it_behaves_like Integrations::Base::Telegram
|
||||
end
|
||||
|
@ -0,0 +1,102 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
RSpec.shared_examples Integrations::Base::Telegram do
|
||||
it_behaves_like Integrations::HasAvatar
|
||||
it_behaves_like "chat integration", "Telegram" do
|
||||
let(:payload) do
|
||||
{
|
||||
text: be_present
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
describe 'validations' do
|
||||
subject(:integration) { build(:telegram_integration) }
|
||||
|
||||
context 'when integration is active' do
|
||||
before do
|
||||
integration.activate!
|
||||
end
|
||||
|
||||
it { is_expected.to validate_presence_of(:token) }
|
||||
it { is_expected.to validate_presence_of(:room) }
|
||||
it { is_expected.to validate_numericality_of(:thread).only_integer }
|
||||
end
|
||||
|
||||
context 'when integration is inactive' do
|
||||
before do
|
||||
integration.deactivate!
|
||||
end
|
||||
|
||||
it { is_expected.not_to validate_presence_of(:token) }
|
||||
it { is_expected.not_to validate_presence_of(:room) }
|
||||
it { is_expected.not_to validate_numericality_of(:thread).only_integer }
|
||||
end
|
||||
end
|
||||
|
||||
describe 'before_validation :set_webhook' do
|
||||
context 'when token is not present' do
|
||||
subject(:integration) { build(:telegram_integration, token: nil) }
|
||||
|
||||
it 'does not set webhook value' do
|
||||
expect(integration.webhook).to be_nil
|
||||
expect(integration).not_to be_valid
|
||||
end
|
||||
end
|
||||
|
||||
context 'when token is present' do
|
||||
subject(:integration) { build_stubbed(:telegram_integration) }
|
||||
|
||||
it 'sets webhook value' do
|
||||
expect(integration).to be_valid
|
||||
expect(integration.webhook).to eq("https://api.telegram.org/bot123456:ABC-DEF1234/sendMessage")
|
||||
end
|
||||
|
||||
context 'with custom hostname' do
|
||||
before do
|
||||
integration.hostname = 'https://gitlab.example.com'
|
||||
end
|
||||
|
||||
it 'sets webhook value with custom hostname' do
|
||||
expect(integration).to be_valid
|
||||
expect(integration.webhook).to eq("https://gitlab.example.com/bot123456:ABC-DEF1234/sendMessage")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#notify' do
|
||||
let(:message) { instance_double(Integrations::ChatMessage::PushMessage, summary: '_Test message') }
|
||||
let(:header) { { 'Content-Type' => 'application/json' } }
|
||||
let(:response) { instance_double(HTTParty::Response, bad_request?: true, success?: true) }
|
||||
let(:body_1) do
|
||||
{
|
||||
text: '_Test message',
|
||||
chat_id: integration.room,
|
||||
message_thread_id: integration.thread,
|
||||
parse_mode: 'markdown'
|
||||
}.compact_blank
|
||||
end
|
||||
|
||||
let(:body_2) { body_1.without(:parse_mode) }
|
||||
|
||||
subject(:integration) { build(:telegram_integration) }
|
||||
|
||||
before do
|
||||
allow(Gitlab::HTTP).to receive(:post).and_return(response)
|
||||
end
|
||||
|
||||
it 'removes the parse mode if the first request fails with a bad request' do
|
||||
expect(Gitlab::HTTP).to receive(:post).with(integration.webhook, headers: header, body: Gitlab::Json.dump(body_1))
|
||||
expect(Gitlab::HTTP).to receive(:post).with(integration.webhook, headers: header, body: Gitlab::Json.dump(body_2))
|
||||
|
||||
integration.send(:notify, message, {})
|
||||
end
|
||||
|
||||
it 'makes a second request if the first one fails with a bad request' do
|
||||
expect(Gitlab::HTTP).to receive(:post).twice
|
||||
|
||||
integration.send(:notify, message, {})
|
||||
end
|
||||
end
|
||||
end
|
Reference in New Issue
Block a user