Commit 70aa14c3 authored by GitLab Bot's avatar GitLab Bot

Automatic merge of gitlab-org/gitlab master

parents da897284 8c7788fc
21e7c85471a8d7401fad69be300eaff1c0384577 82a7a8e90f5bf3f0cae18d158a28eb8a7a1693c6
...@@ -52,7 +52,8 @@ class Projects::CommitController < Projects::ApplicationController ...@@ -52,7 +52,8 @@ class Projects::CommitController < Projects::ApplicationController
# rubocop: disable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord
def pipelines def pipelines
@pipelines = @commit.pipelines.order(id: :desc) @pipelines = @commit.pipelines.order(id: :desc)
@pipelines = @pipelines.where(ref: params[:ref]).page(params[:page]).per(30) if params[:ref] @pipelines = @pipelines.where(ref: params[:ref]) if params[:ref]
@pipelines = @pipelines.page(params[:page])
respond_to do |format| respond_to do |format|
format.html format.html
......
...@@ -167,7 +167,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo ...@@ -167,7 +167,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
def pipelines def pipelines
set_pipeline_variables set_pipeline_variables
@pipelines = @pipelines.page(params[:page]).per(30) @pipelines = @pipelines.page(params[:page])
Gitlab::PollingInterval.set_header(response, interval: 10_000) Gitlab::PollingInterval.set_header(response, interval: 10_000)
......
...@@ -42,7 +42,6 @@ class Projects::PipelinesController < Projects::ApplicationController ...@@ -42,7 +42,6 @@ class Projects::PipelinesController < Projects::ApplicationController
.new(project, current_user, index_params) .new(project, current_user, index_params)
.execute .execute
.page(params[:page]) .page(params[:page])
.per(20)
@pipelines_count = limited_pipelines_count(project) @pipelines_count = limited_pipelines_count(project)
......
...@@ -29,6 +29,8 @@ module Ci ...@@ -29,6 +29,8 @@ module Ci
BridgeStatusError = Class.new(StandardError) BridgeStatusError = Class.new(StandardError)
paginates_per 15
sha_attribute :source_sha sha_attribute :source_sha
sha_attribute :target_sha sha_attribute :target_sha
......
...@@ -65,7 +65,7 @@ You can create a thread without replying to a standard comment. ...@@ -65,7 +65,7 @@ You can create a thread without replying to a standard comment.
Prerequisites: Prerequisites:
- You must have at least the [Guest role](../permissions.md#project-members-permissions). - You must have at least the [Guest role](../permissions.md#project-members-permissions).
- You must be in an issue, commit, snippet, or merge request. - You must be in an issue, merge request, commit, or snippet.
To create a thread: To create a thread:
...@@ -95,25 +95,30 @@ You can edit your own comment at any time. ...@@ -95,25 +95,30 @@ You can edit your own comment at any time.
Anyone with the [Maintainer role](../permissions.md) or Anyone with the [Maintainer role](../permissions.md) or
higher can also edit a comment made by someone else. higher can also edit a comment made by someone else.
## Resolvable comments and threads ## Resolve a thread
> - [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/5022) in GitLab 8.11. > - [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/5022) in GitLab 8.11.
> - Resolvable threads can be added only to merge request diffs. > - Resolvable threads can be added only to merge request diffs.
> - Resolving comments individually was [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/28750) in GitLab 13.6. > - Resolving comments individually was [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/28750) in GitLab 13.6.
Thread resolution helps keep track of progress during planning or code review. You can resolve a thread when you want to finish a conversation.
Every thread in merge requests, commits, commit diffs, and Prerequisites:
snippets is initially displayed as unresolved. They can then be individually resolved by anyone
with at least the Developer role to the project or by the author of the change being reviewed. - You must have at least the [Developer role](../permissions.md#project-members-permissions)
If the thread has been resolved and a non-member un-resolves their own response, or be the author of the change being reviewed.
this also unresolves the discussion thread. - You must be in an issue, merge request, commit, or snippet.
If the non-member then resolves this same response, this resolves the discussion thread.
To resolve a thread:
1. Go to the thread.
1. Below the last reply, in the **Reply** field, either:
- Select **Resolve thread**.
- Enter text, select the **Resolve thread** checkbox, and select **Add comment now**.
The need to resolve threads prevents you from forgetting to address feedback and lets you At the top of the page, the number of unresolved threads is updated.
hide threads that are no longer relevant.
!["A thread between two people on a piece of code"](img/thread_view.png) ![Count of unresolved threads](img/unresolved_threads_v14_1.png)
### Commit threads in the context of a merge request ### Commit threads in the context of a merge request
......
...@@ -136,7 +136,7 @@ merge requests, code snippets, and commits. ...@@ -136,7 +136,7 @@ merge requests, code snippets, and commits.
When performing inline reviews to implementations When performing inline reviews to implementations
to your codebase through merge requests you can to your codebase through merge requests you can
gather feedback through [resolvable threads](discussions/index.md#resolvable-comments-and-threads). gather feedback through [resolvable threads](discussions/index.md#resolve-a-thread).
### GitLab Flavored Markdown (GFM) ### GitLab Flavored Markdown (GFM)
......
...@@ -27,7 +27,7 @@ important parts of the merge request: ...@@ -27,7 +27,7 @@ important parts of the merge request:
![Merge request tab positions](img/merge_request_tab_position_v13_11.png) ![Merge request tab positions](img/merge_request_tab_position_v13_11.png)
- **Overview**: Contains the description, notifications from pipelines, and a - **Overview**: Contains the description, notifications from pipelines, and a
discussion area for [comment threads](../../discussions/index.md#resolvable-comments-and-threads) discussion area for [comment threads](../../discussions/index.md#resolve-a-thread))
and [code suggestions](reviews/suggestions.md). The right sidebar provides fields and [code suggestions](reviews/suggestions.md). The right sidebar provides fields
to add assignees, reviewers, labels, and a milestone to your work, and the to add assignees, reviewers, labels, and a milestone to your work, and the
[merge request widgets area](widgets.md) reports results from pipelines and tests. [merge request widgets area](widgets.md) reports results from pipelines and tests.
......
...@@ -100,7 +100,7 @@ When you submit your review, GitLab: ...@@ -100,7 +100,7 @@ When you submit your review, GitLab:
### Resolving/Unresolving threads ### Resolving/Unresolving threads
Review comments can also resolve or unresolve [resolvable threads](../../../discussions/index.md#resolvable-comments-and-threads). Review comments can also resolve or unresolve [resolvable threads](../../../discussions/index.md#resolve-a-thread)).
When replying to a comment, a checkbox is displayed to resolve or unresolve When replying to a comment, a checkbox is displayed to resolve or unresolve
the thread after publication. the thread after publication.
......
- page_title _('Audit Events') - page_title _('Audit Events')
%h3.page-title= _('Instance audit events')
%p.light
= _('Track important events in your GitLab instance.')
= link_to _('What are instance audit events?'), help_page_path('administration/audit_events.md', anchor: 'instance-events'), target: '_blank', rel: 'noopener noreferrer'
#js-audit-log-app{ data: { form_path: admin_audit_logs_path, #js-audit-log-app{ data: { form_path: admin_audit_logs_path,
events: @events.to_json, events: @events.to_json,
is_last_page: @is_last_page.to_json, is_last_page: @is_last_page.to_json,
......
- page_title _('Audit Events') - page_title _('Audit Events')
%h3.page-title= _('Group Audit Events') %h3.page-title= _('Group audit events')
%p.light= _('Group-level events in %{group_name} (no project-level events)') % { group_name: @group.name } %p.light
= _("Track important events in your group.")
= link_to _('What are group audit events?'), help_page_path('administration/audit_events.md', anchor: 'group-events'), target: '_blank', rel: 'noopener noreferrer'
#js-group-audit-events-app{ data: { form_path: group_audit_events_path(@group), #js-group-audit-events-app{ data: { form_path: group_audit_events_path(@group),
events: @events.to_json, events: @events.to_json,
......
...@@ -3,9 +3,10 @@ ...@@ -3,9 +3,10 @@
- if feature_available - if feature_available
%h3.page-title %h3.page-title
= _('Project Audit Events') = _('Project audit events')
%p.light %p.light
= _('Events in %{project_path}') % { project_path: @project.full_path } = _('Track important events in your project.')
= link_to _('What are project audit events?'), help_page_path('administration/audit_events.md', anchor: 'project-events'), target: '_blank', rel: 'noopener noreferrer'
#js-project-audit-events-app{ data: { form_path: project_audit_events_path(@project), #js-project-audit-events-app{ data: { form_path: project_audit_events_path(@project),
events: @events.to_json, events: @events.to_json,
......
...@@ -60,10 +60,10 @@ RSpec.describe 'Projects > Audit Events', :js do ...@@ -60,10 +60,10 @@ RSpec.describe 'Projects > Audit Events', :js do
expect(page).to have_link('Audit Events') expect(page).to have_link('Audit Events')
end end
it 'does not have Project Audit Events in the header' do it 'does not have Project audit events in the header' do
visit project_audit_events_path(project) visit project_audit_events_path(project)
expect(page).not_to have_content('Project Audit Events') expect(page).not_to have_content('Project audit events')
end end
end end
...@@ -73,10 +73,10 @@ RSpec.describe 'Projects > Audit Events', :js do ...@@ -73,10 +73,10 @@ RSpec.describe 'Projects > Audit Events', :js do
expect(page).to have_link('Audit Events') expect(page).to have_link('Audit Events')
end end
it 'has Project Audit Events in the header' do it 'has Project audit events in the header' do
visit project_audit_events_path(project) visit project_audit_events_path(project)
expect(page).to have_content('Project Audit Events') expect(page).to have_content('Project audit events')
end end
describe 'adding an SSH key' do describe 'adding an SSH key' do
......
...@@ -19,11 +19,10 @@ module Gitlab ...@@ -19,11 +19,10 @@ module Gitlab
private private
def paginate_with_limit_optimization(relation) def paginate_with_limit_optimization(relation)
# do not paginate relation if it is already paginated pagination_data = if needs_pagination?(relation)
pagination_data = if relation.respond_to?(:current_page) && relation.current_page == params[:page] && relation.limit_value == params[:per_page]
relation
else
relation.page(params[:page]).per(params[:per_page]) relation.page(params[:page]).per(params[:per_page])
else
relation
end end
return pagination_data unless pagination_data.is_a?(ActiveRecord::Relation) return pagination_data unless pagination_data.is_a?(ActiveRecord::Relation)
...@@ -39,6 +38,14 @@ module Gitlab ...@@ -39,6 +38,14 @@ module Gitlab
end end
end end
def needs_pagination?(relation)
return true unless relation.respond_to?(:current_page)
return true if params[:page].present? && relation.current_page != params[:page].to_i
return true if params[:per_page].present? && relation.limit_value != params[:per_page].to_i
false
end
def add_default_order(relation) def add_default_order(relation)
if relation.is_a?(ActiveRecord::Relation) && relation.order_values.empty? if relation.is_a?(ActiveRecord::Relation) && relation.order_values.empty?
relation = relation.order(:id) # rubocop: disable CodeReuse/ActiveRecord relation = relation.order(:id) # rubocop: disable CodeReuse/ActiveRecord
......
...@@ -12979,9 +12979,6 @@ msgstr "" ...@@ -12979,9 +12979,6 @@ msgstr ""
msgid "Events" msgid "Events"
msgstr "" msgstr ""
msgid "Events in %{project_path}"
msgstr ""
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again." msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr "" msgstr ""
...@@ -15256,9 +15253,6 @@ msgstr "" ...@@ -15256,9 +15253,6 @@ msgstr ""
msgid "Group %{group_name} was successfully created." msgid "Group %{group_name} was successfully created."
msgstr "" msgstr ""
msgid "Group Audit Events"
msgstr ""
msgid "Group Git LFS status:" msgid "Group Git LFS status:"
msgstr "" msgstr ""
...@@ -15289,6 +15283,9 @@ msgstr "" ...@@ -15289,6 +15283,9 @@ msgstr ""
msgid "Group applications" msgid "Group applications"
msgstr "" msgstr ""
msgid "Group audit events"
msgstr ""
msgid "Group avatar" msgid "Group avatar"
msgstr "" msgstr ""
...@@ -15397,9 +15394,6 @@ msgstr "" ...@@ -15397,9 +15394,6 @@ msgstr ""
msgid "Group was successfully updated." msgid "Group was successfully updated."
msgstr "" msgstr ""
msgid "Group-level events in %{group_name} (no project-level events)"
msgstr ""
msgid "Group: %{group_name}" msgid "Group: %{group_name}"
msgstr "" msgstr ""
...@@ -17380,6 +17374,9 @@ msgstr "" ...@@ -17380,6 +17374,9 @@ msgstr ""
msgid "Instance administrators group already exists" msgid "Instance administrators group already exists"
msgstr "" msgstr ""
msgid "Instance audit events"
msgstr ""
msgid "Instance overview" msgid "Instance overview"
msgstr "" msgstr ""
...@@ -25211,9 +25208,6 @@ msgstr "" ...@@ -25211,9 +25208,6 @@ msgstr ""
msgid "Project Access Tokens" msgid "Project Access Tokens"
msgstr "" msgstr ""
msgid "Project Audit Events"
msgstr ""
msgid "Project Badges" msgid "Project Badges"
msgstr "" msgstr ""
...@@ -25241,6 +25235,9 @@ msgstr "" ...@@ -25241,6 +25235,9 @@ msgstr ""
msgid "Project and wiki repositories" msgid "Project and wiki repositories"
msgstr "" msgstr ""
msgid "Project audit events"
msgstr ""
msgid "Project avatar" msgid "Project avatar"
msgstr "" msgstr ""
...@@ -34189,6 +34186,15 @@ msgstr "" ...@@ -34189,6 +34186,15 @@ msgstr ""
msgid "Track groups of issues that share a theme, across projects and milestones" msgid "Track groups of issues that share a theme, across projects and milestones"
msgstr "" msgstr ""
msgid "Track important events in your GitLab instance."
msgstr ""
msgid "Track important events in your group."
msgstr ""
msgid "Track important events in your project."
msgstr ""
msgid "Track time with quick actions" msgid "Track time with quick actions"
msgstr "" msgstr ""
...@@ -36550,6 +36556,15 @@ msgstr "" ...@@ -36550,6 +36556,15 @@ msgstr ""
msgid "Welcome, %{name}!" msgid "Welcome, %{name}!"
msgstr "" msgstr ""
msgid "What are group audit events?"
msgstr ""
msgid "What are instance audit events?"
msgstr ""
msgid "What are project audit events?"
msgstr ""
msgid "What are you searching for?" msgid "What are you searching for?"
msgstr "" msgstr ""
......
...@@ -483,7 +483,7 @@ RSpec.describe Projects::CommitController do ...@@ -483,7 +483,7 @@ RSpec.describe Projects::CommitController do
end end
context 'when rendering a JSON format' do context 'when rendering a JSON format' do
it 'responds with serialized pipelines' do it 'responds with serialized pipelines', :aggregate_failures do
get_pipelines(id: commit.id, format: :json) get_pipelines(id: commit.id, format: :json)
expect(response).to be_ok expect(response).to be_ok
...@@ -491,6 +491,26 @@ RSpec.describe Projects::CommitController do ...@@ -491,6 +491,26 @@ RSpec.describe Projects::CommitController do
expect(json_response['count']['all']).to eq 1 expect(json_response['count']['all']).to eq 1
expect(response).to include_pagination_headers expect(response).to include_pagination_headers
end end
context 'with pagination' do
let!(:extra_pipeline) { create(:ci_pipeline, project: project, ref: project.default_branch, sha: commit.sha, status: :running) }
it 'paginates the result when ref is blank' do
allow(Ci::Pipeline).to receive(:default_per_page).and_return(1)
get_pipelines(id: commit.id, format: :json)
expect(json_response['pipelines'].count).to eq(1)
end
it 'paginates the result when ref is present' do
allow(Ci::Pipeline).to receive(:default_per_page).and_return(1)
get_pipelines(id: commit.id, ref: project.default_branch, format: :json)
expect(json_response['pipelines'].count).to eq(1)
end
end
end end
end end
end end
......
...@@ -860,6 +860,20 @@ RSpec.describe Projects::MergeRequestsController do ...@@ -860,6 +860,20 @@ RSpec.describe Projects::MergeRequestsController do
end end
end end
end end
context 'with pagination' do
before do
create(:ci_pipeline, project: merge_request.source_project, ref: merge_request.source_branch, sha: merge_request.diff_head_sha)
end
it 'paginates the result' do
allow(Ci::Pipeline).to receive(:default_per_page).and_return(1)
get :pipelines, params: { namespace_id: project.namespace.to_param, project_id: project, id: merge_request.iid }, format: :json
expect(json_response['pipelines'].count).to eq(1)
end
end
end end
describe 'GET context commits' do describe 'GET context commits' do
......
...@@ -66,6 +66,14 @@ RSpec.describe Projects::PipelinesController do ...@@ -66,6 +66,14 @@ RSpec.describe Projects::PipelinesController do
expect(json_response['pipelines'][0]).not_to include('coverage') expect(json_response['pipelines'][0]).not_to include('coverage')
end end
it 'paginates the result' do
allow(Ci::Pipeline).to receive(:default_per_page).and_return(2)
get_pipelines_index_json
check_pipeline_response(returned: 2, all: 6)
end
context 'when performing gitaly calls', :request_store do context 'when performing gitaly calls', :request_store do
it 'limits the Gitaly requests' do it 'limits the Gitaly requests' do
# Isolate from test preparation (Repository#exists? is also cached in RequestStore) # Isolate from test preparation (Repository#exists? is also cached in RequestStore)
......
...@@ -130,6 +130,80 @@ RSpec.describe Gitlab::Pagination::OffsetPagination do ...@@ -130,6 +130,80 @@ RSpec.describe Gitlab::Pagination::OffsetPagination do
end end
end end
context 'when resource already paginated' do
let(:resource) { Project.all.page(1).per(1) }
context 'when per_page param is specified' do
let(:query) { base_query.merge(page: 1, per_page: 2) }
it 'returns appropriate amount of resources based on per_page param' do
expect(subject.paginate(resource).count).to eq 2
end
end
context 'when page and per page params are strings' do
let(:query) { base_query.merge(page: '1', per_page: '1') }
it 'returns appropriate amount of resources' do
expect(subject.paginate(resource).count).to eq 1
end
end
context 'when per_page param is blank' do
let(:query) { base_query.merge(page: 1) }
it 'returns appropriate amount of resources' do
expect(subject.paginate(resource).count).to eq 1
end
end
context 'when page param is blank' do
let(:query) { base_query }
it 'returns appropriate amount of resources based on resource per(N)' do
expect(subject.paginate(resource).count).to eq 1
end
end
end
context 'when resource does not respond to limit_value' do
let(:custom_collection) do
Class.new do
include Enumerable
def initialize(items)
@collection = items
end
def each
@collection.each { |item| yield item }
end
def page(number)
Kaminari.paginate_array(@collection).page(number)
end
end
end
let(:resource) { custom_collection.new(Project.all).page(query[:page]) }
context 'when page param is blank' do
let(:query) { base_query }
it 'returns appropriate amount of resources' do
expect(subject.paginate(resource).count).to eq 3
end
end
context 'when per_page param is blank' do
let(:query) { base_query.merge(page: 1) }
it 'returns appropriate amount of resources with default per page value' do
expect(subject.paginate(resource).count).to eq 3
end
end
end
context 'when resource is a paginatable array' do context 'when resource is a paginatable array' do
let(:resource) { Kaminari.paginate_array(Project.all.to_a) } let(:resource) { Kaminari.paginate_array(Project.all.to_a) }
......
...@@ -11,6 +11,10 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do ...@@ -11,6 +11,10 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
let_it_be(:namespace) { create_default(:namespace).freeze } let_it_be(:namespace) { create_default(:namespace).freeze }
let_it_be(:project) { create_default(:project, :repository).freeze } let_it_be(:project) { create_default(:project, :repository).freeze }
it 'paginates 15 pipeleines per page' do
expect(described_class.default_per_page).to eq(15)
end
it_behaves_like 'having unique enum values' it_behaves_like 'having unique enum values'
it { is_expected.to belong_to(:project) } it { is_expected.to belong_to(:project) }
......
...@@ -34,7 +34,7 @@ RSpec.describe Integrations::BaseChatNotification do ...@@ -34,7 +34,7 @@ RSpec.describe Integrations::BaseChatNotification do
end end
describe '#execute' do describe '#execute' do
subject(:chat_service) { described_class.new } subject(:chat_integration) { described_class.new }
let_it_be(:project) { create(:project, :repository) } let_it_be(:project) { create(:project, :repository) }
...@@ -43,7 +43,7 @@ RSpec.describe Integrations::BaseChatNotification do ...@@ -43,7 +43,7 @@ RSpec.describe Integrations::BaseChatNotification do
let(:data) { Gitlab::DataBuilder::Push.build_sample(subject.project, user) } let(:data) { Gitlab::DataBuilder::Push.build_sample(subject.project, user) }
before do before do
allow(chat_service).to receive_messages( allow(chat_integration).to receive_messages(
project: project, project: project,
project_id: project.id, project_id: project.id,
service_hook: true, service_hook: true,
...@@ -57,8 +57,8 @@ RSpec.describe Integrations::BaseChatNotification do ...@@ -57,8 +57,8 @@ RSpec.describe Integrations::BaseChatNotification do
context 'with a repository' do context 'with a repository' do
it 'returns true' do it 'returns true' do
expect(chat_service).to receive(:notify).and_return(true) expect(chat_integration).to receive(:notify).and_return(true)
expect(chat_service.execute(data)).to be true expect(chat_integration.execute(data)).to be true
end end
end end
...@@ -66,8 +66,8 @@ RSpec.describe Integrations::BaseChatNotification do ...@@ -66,8 +66,8 @@ RSpec.describe Integrations::BaseChatNotification do
it 'returns true' do it 'returns true' do
subject.project = create(:project, :empty_repo) subject.project = create(:project, :empty_repo)
expect(chat_service).to receive(:notify).and_return(true) expect(chat_integration).to receive(:notify).and_return(true)
expect(chat_service.execute(data)).to be true expect(chat_integration.execute(data)).to be true
end end
end end
...@@ -75,8 +75,8 @@ RSpec.describe Integrations::BaseChatNotification do ...@@ -75,8 +75,8 @@ RSpec.describe Integrations::BaseChatNotification do
it 'does not remove spaces' do it 'does not remove spaces' do
allow(project).to receive(:full_name).and_return('Project Name') allow(project).to receive(:full_name).and_return('Project Name')
expect(chat_service).to receive(:get_message).with(any_args, hash_including(project_name: 'Project Name')) expect(chat_integration).to receive(:get_message).with(any_args, hash_including(project_name: 'Project Name'))
chat_service.execute(data) chat_integration.execute(data)
end end
end end
...@@ -89,76 +89,76 @@ RSpec.describe Integrations::BaseChatNotification do ...@@ -89,76 +89,76 @@ RSpec.describe Integrations::BaseChatNotification do
let(:data) { Gitlab::DataBuilder::Note.build(note, user) } let(:data) { Gitlab::DataBuilder::Note.build(note, user) }
shared_examples 'notifies the chat service' do shared_examples 'notifies the chat integration' do
specify do specify do
expect(chat_service).to receive(:notify).with(any_args) expect(chat_integration).to receive(:notify).with(any_args)
chat_service.execute(data) chat_integration.execute(data)
end end
end end
shared_examples 'does not notify the chat service' do shared_examples 'does not notify the chat integration' do
specify do specify do
expect(chat_service).not_to receive(:notify).with(any_args) expect(chat_integration).not_to receive(:notify).with(any_args)
chat_service.execute(data) chat_integration.execute(data)
end end
end end
it_behaves_like 'notifies the chat service' it_behaves_like 'notifies the chat integration'
context 'with label filter' do context 'with label filter' do
subject(:chat_service) { described_class.new(labels_to_be_notified: '~Bug') } subject(:chat_integration) { described_class.new(labels_to_be_notified: '~Bug') }
it_behaves_like 'notifies the chat service' it_behaves_like 'notifies the chat integration'
context 'MergeRequest events' do context 'MergeRequest events' do
let(:data) { create(:merge_request, labels: [label]).to_hook_data(user) } let(:data) { create(:merge_request, labels: [label]).to_hook_data(user) }
it_behaves_like 'notifies the chat service' it_behaves_like 'notifies the chat integration'
end end
context 'Issue events' do context 'Issue events' do
let(:data) { issue.to_hook_data(user) } let(:data) { issue.to_hook_data(user) }
it_behaves_like 'notifies the chat service' it_behaves_like 'notifies the chat integration'
end end
end end
context 'when labels_to_be_notified_behavior is not defined' do context 'when labels_to_be_notified_behavior is not defined' do
subject(:chat_service) { described_class.new(labels_to_be_notified: label_filter) } subject(:chat_integration) { described_class.new(labels_to_be_notified: label_filter) }
context 'no matching labels' do context 'no matching labels' do
let(:label_filter) { '~some random label' } let(:label_filter) { '~some random label' }
it_behaves_like 'does not notify the chat service' it_behaves_like 'does not notify the chat integration'
end end
context 'only one label matches' do context 'only one label matches' do
let(:label_filter) { '~some random label, ~Bug' } let(:label_filter) { '~some random label, ~Bug' }
it_behaves_like 'notifies the chat service' it_behaves_like 'notifies the chat integration'
end end
end end
context 'when labels_to_be_notified_behavior is blank' do context 'when labels_to_be_notified_behavior is blank' do
subject(:chat_service) { described_class.new(labels_to_be_notified: label_filter, labels_to_be_notified_behavior: '') } subject(:chat_integration) { described_class.new(labels_to_be_notified: label_filter, labels_to_be_notified_behavior: '') }
context 'no matching labels' do context 'no matching labels' do
let(:label_filter) { '~some random label' } let(:label_filter) { '~some random label' }
it_behaves_like 'does not notify the chat service' it_behaves_like 'does not notify the chat integration'
end end
context 'only one label matches' do context 'only one label matches' do
let(:label_filter) { '~some random label, ~Bug' } let(:label_filter) { '~some random label, ~Bug' }
it_behaves_like 'notifies the chat service' it_behaves_like 'notifies the chat integration'
end end
end end
context 'when labels_to_be_notified_behavior is match_any' do context 'when labels_to_be_notified_behavior is match_any' do
subject(:chat_service) do subject(:chat_integration) do
described_class.new( described_class.new(
labels_to_be_notified: label_filter, labels_to_be_notified: label_filter,
labels_to_be_notified_behavior: 'match_any' labels_to_be_notified_behavior: 'match_any'
...@@ -168,24 +168,24 @@ RSpec.describe Integrations::BaseChatNotification do ...@@ -168,24 +168,24 @@ RSpec.describe Integrations::BaseChatNotification do
context 'no label filter' do context 'no label filter' do
let(:label_filter) { nil } let(:label_filter) { nil }
it_behaves_like 'notifies the chat service' it_behaves_like 'notifies the chat integration'
end end
context 'no matching labels' do context 'no matching labels' do
let(:label_filter) { '~some random label' } let(:label_filter) { '~some random label' }
it_behaves_like 'does not notify the chat service' it_behaves_like 'does not notify the chat integration'
end end
context 'only one label matches' do context 'only one label matches' do
let(:label_filter) { '~some random label, ~Bug' } let(:label_filter) { '~some random label, ~Bug' }
it_behaves_like 'notifies the chat service' it_behaves_like 'notifies the chat integration'
end end
end end
context 'when labels_to_be_notified_behavior is match_all' do context 'when labels_to_be_notified_behavior is match_all' do
subject(:chat_service) do subject(:chat_integration) do
described_class.new( described_class.new(
labels_to_be_notified: label_filter, labels_to_be_notified: label_filter,
labels_to_be_notified_behavior: 'match_all' labels_to_be_notified_behavior: 'match_all'
...@@ -195,31 +195,31 @@ RSpec.describe Integrations::BaseChatNotification do ...@@ -195,31 +195,31 @@ RSpec.describe Integrations::BaseChatNotification do
context 'no label filter' do context 'no label filter' do
let(:label_filter) { nil } let(:label_filter) { nil }
it_behaves_like 'notifies the chat service' it_behaves_like 'notifies the chat integration'
end end
context 'no matching labels' do context 'no matching labels' do
let(:label_filter) { '~some random label' } let(:label_filter) { '~some random label' }
it_behaves_like 'does not notify the chat service' it_behaves_like 'does not notify the chat integration'
end end
context 'only one label matches' do context 'only one label matches' do
let(:label_filter) { '~some random label, ~Bug' } let(:label_filter) { '~some random label, ~Bug' }
it_behaves_like 'does not notify the chat service' it_behaves_like 'does not notify the chat integration'
end end
context 'labels matches exactly' do context 'labels matches exactly' do
let(:label_filter) { '~Bug, ~Backend, ~Community contribution' } let(:label_filter) { '~Bug, ~Backend, ~Community contribution' }
it_behaves_like 'notifies the chat service' it_behaves_like 'notifies the chat integration'
end end
context 'labels matches but object has more' do context 'labels matches but object has more' do
let(:label_filter) { '~Bug, ~Backend' } let(:label_filter) { '~Bug, ~Backend' }
it_behaves_like 'notifies the chat service' it_behaves_like 'notifies the chat integration'
end end
context 'labels are distributed on multiple objects' do context 'labels are distributed on multiple objects' do
...@@ -241,22 +241,22 @@ RSpec.describe Integrations::BaseChatNotification do ...@@ -241,22 +241,22 @@ RSpec.describe Integrations::BaseChatNotification do
}) })
end end
it_behaves_like 'does not notify the chat service' it_behaves_like 'does not notify the chat integration'
end end
end end
end end
context 'with "channel" property' do context 'with "channel" property' do
before do before do
allow(chat_service).to receive(:channel).and_return(channel) allow(chat_integration).to receive(:channel).and_return(channel)
end end
context 'empty string' do context 'empty string' do
let(:channel) { '' } let(:channel) { '' }
it 'does not include the channel' do it 'does not include the channel' do
expect(chat_service).to receive(:notify).with(any_args, hash_excluding(:channel)).and_return(true) expect(chat_integration).to receive(:notify).with(any_args, hash_excluding(:channel)).and_return(true)
expect(chat_service.execute(data)).to be(true) expect(chat_integration.execute(data)).to be(true)
end end
end end
...@@ -264,20 +264,20 @@ RSpec.describe Integrations::BaseChatNotification do ...@@ -264,20 +264,20 @@ RSpec.describe Integrations::BaseChatNotification do
let(:channel) { ' ' } let(:channel) { ' ' }
it 'does not include the channel' do it 'does not include the channel' do
expect(chat_service).to receive(:notify).with(any_args, hash_excluding(:channel)).and_return(true) expect(chat_integration).to receive(:notify).with(any_args, hash_excluding(:channel)).and_return(true)
expect(chat_service.execute(data)).to be(true) expect(chat_integration.execute(data)).to be(true)
end end
end end
end end
shared_examples 'with channel specified' do |channel, expected_channels| shared_examples 'with channel specified' do |channel, expected_channels|
before do before do
allow(chat_service).to receive(:push_channel).and_return(channel) allow(chat_integration).to receive(:push_channel).and_return(channel)
end end
it 'notifies all channels' do it 'notifies all channels' do
expect(chat_service).to receive(:notify).with(any_args, hash_including(channel: expected_channels)).and_return(true) expect(chat_integration).to receive(:notify).with(any_args, hash_including(channel: expected_channels)).and_return(true)
expect(chat_service.execute(data)).to be(true) expect(chat_integration.execute(data)).to be(true)
end end
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment