Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2021-01-05 00:10:20 +00:00
parent 9248363e3e
commit b28aa8bd7d
32 changed files with 225 additions and 125 deletions

View file

@ -11,7 +11,17 @@ function broadcastCount(newCount) {
}
function updateUserMergeRequestCounts(newCount) {
const mergeRequestsCountEl = document.querySelector('.merge-requests-count');
const mergeRequestsCountEl = document.querySelector('.js-assigned-mr-count');
mergeRequestsCountEl.textContent = newCount.toLocaleString();
}
function updateReviewerMergeRequestCounts(newCount) {
const mergeRequestsCountEl = document.querySelector('.js-reviewer-mr-count');
mergeRequestsCountEl.textContent = newCount.toLocaleString();
}
function updateMergeRequestCounts(newCount) {
const mergeRequestsCountEl = document.querySelector('.js-merge-requests-count');
mergeRequestsCountEl.textContent = newCount.toLocaleString();
mergeRequestsCountEl.classList.toggle('hidden', Number(newCount) === 0);
}
@ -22,10 +32,14 @@ function updateUserMergeRequestCounts(newCount) {
export function refreshUserMergeRequestCounts() {
return Api.userCounts()
.then(({ data }) => {
const count = data.merge_requests;
const assignedMergeRequests = data.assigned_merge_requests;
const reviewerMergeRequests = data.review_requested_merge_requests;
const fullCount = assignedMergeRequests + reviewerMergeRequests;
updateUserMergeRequestCounts(count);
broadcastCount(count);
updateUserMergeRequestCounts(assignedMergeRequests);
updateReviewerMergeRequestCounts(reviewerMergeRequests);
updateMergeRequestCounts(fullCount);
broadcastCount(fullCount);
})
.catch((ex) => {
console.error(ex); // eslint-disable-line no-console
@ -60,7 +74,7 @@ export function openUserCountsBroadcast() {
if (currentUserId) {
channel = new BroadcastChannel(`mr_count_channel_${currentUserId}`);
channel.onmessage = (ev) => {
updateUserMergeRequestCounts(ev.data);
updateMergeRequestCounts(ev.data);
};
}
}

View file

@ -2,6 +2,7 @@
// NOTE! For the first iteration, we are simply copying the implementation of Assignees
// It will soon be overhauled in Issue https://gitlab.com/gitlab-org/gitlab/-/issues/233736
import { deprecatedCreateFlash as Flash } from '~/flash';
import { refreshUserMergeRequestCounts } from '~/commons/nav/user_merge_requests';
import eventHub from '~/sidebar/event_hub';
import Store from '~/sidebar/stores/sidebar_store';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
@ -80,8 +81,7 @@ export default {
.saveReviewers(this.field)
.then(() => {
this.loading = false;
// Uncomment once this issue has been addressed > https://gitlab.com/gitlab-org/gitlab/-/issues/237922
// refreshUserMergeRequestCounts();
refreshUserMergeRequestCounts();
})
.catch(() => {
this.loading = false;

View file

@ -796,6 +796,14 @@
.navbar-gitlab {
li.dropdown {
position: static;
&.user-counter {
margin-left: 8px !important;
> a {
padding: 0 4px !important;
}
}
}
}

View file

@ -172,7 +172,7 @@
}
li {
.badge.badge-pill {
.badge.badge-pill:not(.merge-request-badge) {
box-shadow: none;
font-weight: $gl-font-weight-bold;
}
@ -438,7 +438,7 @@
.title-container,
.navbar-nav {
.badge.badge-pill {
.badge.badge-pill:not(.merge-request-badge) {
position: inherit;
font-weight: $gl-font-weight-normal;
margin-left: -6px;

View file

@ -11,6 +11,10 @@ module DashboardHelper
merge_requests_dashboard_path(assignee_username: current_user.username)
end
def reviewer_mrs_dashboard_path
merge_requests_dashboard_path(reviewer_username: current_user.username)
end
def dashboard_nav_links
@dashboard_nav_links ||= get_dashboard_nav_links
end

View file

@ -159,6 +159,32 @@ module MergeRequestsHelper
issuable_path(issuable, { merge_request: { wip_event: wip_event } })
end
def user_merge_requests_counts
@user_merge_requests_counts ||= begin
assigned_count = assigned_issuables_count(:merge_requests)
review_requested_count = review_requested_merge_requests_count
total_count = assigned_count + review_requested_count
{
assigned: assigned_count,
review_requested: review_requested_count,
total: total_count
}
end
end
def merge_request_reviewers_enabled?
Feature.enabled?(:merge_request_reviewers, default_enabled: :yaml)
end
private
def review_requested_merge_requests_count
return 0 unless merge_request_reviewers_enabled?
current_user.review_requested_open_merge_requests_count
end
end
MergeRequestsHelper.prepend_if_ee('EE::MergeRequestsHelper')

View file

@ -1564,6 +1564,12 @@ class User < ApplicationRecord
end
end
def review_requested_open_merge_requests_count(force: false)
Rails.cache.fetch(['users', id, 'review_requested_open_merge_requests_count'], force: force, expires_in: 20.minutes) do
MergeRequestsFinder.new(self, reviewer_id: id, state: 'opened', non_archived: true).execute.count
end
end
def assigned_open_issues_count(force: false)
Rails.cache.fetch(['users', id, 'assigned_open_issues_count'], force: force, expires_in: 20.minutes) do
IssuesFinder.new(self, assignee_id: self.id, state: 'opened', non_archived: true).execute.count
@ -1607,6 +1613,7 @@ class User < ApplicationRecord
def invalidate_merge_request_cache_counts
Rails.cache.delete(['users', id, 'assigned_open_merge_requests_count'])
Rails.cache.delete(['users', id, 'review_requested_open_merge_requests_count'])
end
def invalidate_todos_done_count

View file

@ -135,10 +135,6 @@ class ProjectPolicy < BasePolicy
::Feature.enabled?(:build_service_proxy, @subject)
end
condition(:project_bot_is_member) do
user.project_bot? & team_member?
end
with_scope :subject
condition(:packages_disabled) { !@subject.packages_enabled }
@ -619,8 +615,6 @@ class ProjectPolicy < BasePolicy
enable :admin_resource_access_tokens
end
rule { project_bot_is_member & ~blocked }.enable :bot_log_in
private
def user_is_user?

View file

@ -112,9 +112,11 @@ module MergeRequests
end
def handle_reviewers_change(merge_request, old_reviewers)
affected_reviewers = (old_reviewers + merge_request.reviewers) - (old_reviewers & merge_request.reviewers)
create_reviewer_note(merge_request, old_reviewers)
notification_service.async.changed_reviewer_of_merge_request(merge_request, current_user, old_reviewers)
todo_service.reassigned_reviewable(merge_request, current_user, old_reviewers)
invalidate_cache_counts(merge_request, users: affected_reviewers.compact)
end
def create_branch_change_note(issuable, branch_type, old_branch, new_branch)

View file

@ -47,17 +47,36 @@
%span.badge.badge-pill.issues-count.green-badge{ class: ('hidden' if issues_count == 0) }
= number_with_delimiter(issues_count)
- if header_link?(:merge_requests)
= nav_link(path: 'dashboard#merge_requests', html_options: { class: "user-counter" }) do
= link_to assigned_mrs_dashboard_path, title: _('Merge requests'), class: 'dashboard-shortcuts-merge_requests', aria: { label: _('Merge requests') },
data: { qa_selector: 'merge_requests_shortcut_button', toggle: 'tooltip', placement: 'bottom',
- reviewers_enabled = merge_request_reviewers_enabled?
= nav_link(path: 'dashboard#merge_requests', html_options: { class: "user-counter #{reviewers_enabled ? 'dropdown' : ''}" }) do
= link_to assigned_mrs_dashboard_path, class: 'dashboard-shortcuts-merge_requests', title: _('Merge requests'), aria: { label: _('Merge requests') },
data: { qa_selector: 'merge_requests_shortcut_button',
toggle: reviewers_enabled ? "dropdown" : "tooltip",
placement: 'bottom',
track_label: 'main_navigation',
track_event: 'click_merge_link',
track_property: 'navigation',
container: 'body' } do
= sprite_icon('git-merge')
- merge_requests_count = assigned_issuables_count(:merge_requests)
%span.badge.badge-pill.merge-requests-count{ class: ('hidden' if merge_requests_count == 0) }
= number_with_delimiter(merge_requests_count)
%span.badge.badge-pill.merge-requests-count.js-merge-requests-count{ class: ('hidden' if user_merge_requests_counts[:total] == 0) }
= number_with_delimiter(user_merge_requests_counts[:total])
- if reviewers_enabled
= sprite_icon('chevron-down', css_class: 'caret-down gl-mx-0!')
- if reviewers_enabled
.dropdown-menu.dropdown-menu-right
%ul
%li.dropdown-header
= _('Merge requests')
%li
= link_to assigned_mrs_dashboard_path, class: 'gl-display-flex! gl-align-items-center' do
= _('Assigned to you')
%span.badge.gl-badge.badge-pill.badge-muted.merge-request-badge.gl-ml-auto.js-assigned-mr-count{ class: "" }
= user_merge_requests_counts[:assigned]
%li
= link_to reviewer_mrs_dashboard_path, class: 'gl-display-flex! gl-align-items-center' do
= _('Review requests for you')
%span.badge.gl-badge.badge-pill.badge-muted.merge-request-badge.gl-ml-auto.js-reviewer-mr-count{ class: "" }
= user_merge_requests_counts[:review_requested]
- if header_link?(:todos)
= nav_link(controller: 'dashboard/todos', html_options: { class: "user-counter" }) do
= link_to dashboard_todos_path, title: _('To-Do List'), aria: { label: _('To-Do List') }, class: 'shortcuts-todos',

View file

@ -0,0 +1,5 @@
---
title: Fix project access token regression
merge_request: 50800
author:
type: fixed

View file

@ -1,5 +0,0 @@
---
title: Fix empty pipeline analytics charts when time_zone is non-UTC
merge_request: 50760
author:
type: fixed

View file

@ -459,11 +459,11 @@ Cluster.
| `alert` | Hash | yes | Alerts detail. Currently same format as [3rd party alert](../operations/incident_management/alert_integrations.md#customize-the-alert-payload-outside-of-gitlab). |
```plaintext
POST internal/kubernetes/modules/cilium/network_alert
POST internal/kubernetes/modules/cilium_alert
```
Example Request:
```shell
curl --request POST --header "Gitlab-Kas-Api-Request: <JWT token>" --header "Authorization: Bearer <agent token>" --header "Content-Type: application/json" --data '"{\"alert\":{\"title\":\"minimal\",\"message\":\"network problem\",\"evalMatches\":[{\"value\":1,\"metric\":\"Count\",\"tags\":{}}]}}"' "http://localhost:3000/api/v4/internal/kubernetes/modules/cilium/network_alert"
curl --request POST --header "Gitlab-Kas-Api-Request: <JWT token>" --header "Authorization: Bearer <agent token>" --header "Content-Type: application/json" --data '"{\"alert\":{\"title\":\"minimal\",\"message\":\"network problem\",\"evalMatches\":[{\"value\":1,\"metric\":\"Count\",\"tags\":{}}]}}"' "http://localhost:3000/api/v4/internal/kubernetes/modules/cilium_alert"
```

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

View file

@ -42,18 +42,21 @@ Otherwise, you can:
1. Navigate to the **License** tab, and click **Upload New License**.
![License Admin Area](img/license_admin_area.png)
- *If you've received a `.gitlab-license` file:*
1. Download the license file to your local machine.
1. Select **Upload `.gitlab-license` file**.
1. Select **Choose File** and select the license file.
In this example the license file is named `GitLab.gitlab-license`.
1. Check the **Subscription Agreement** checkbox.
1. Select **Upload License**.
- *If you've received a `.gitlab-license` file,* you should have already downloaded
it in your local machine. You can then upload it directly by choosing the
license file and clicking the **Upload license** button. In the image below,
the selected license file is named `GitLab.gitlab-license`.
![Upload license](img/license_upload_v13_8.png)
![Upload license](img/license_upload.png)
- *If you've received your license as plain text,* select the
**Enter license key** option, copy the license, paste it into the **License key**
field, and click **Upload license**.
- *If you've received your license as plain text:*
1. Select **Enter license key**.
1. Copy the license and paste it into the **License key** field.
1. Check the **Subscription Agreement** checkbox.
1. Select **Upload License**.
## Add your license at install time

View file

@ -47,6 +47,9 @@ To enforce confirmation of the email address used for new sign ups:
1. Go to **Admin Area > Settings > General** and expand **Sign-up restrictions**.
1. Select the **Enable email restrictions for sign ups** checkbox, then select **Save changes**.
In [GitLab 13.7 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/273258), if an administrator disables this setting, the users in pending approval state are
automatically approved in a background job.
## User cap **(CORE ONLY)**
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/4315) in GitLab 13.6.

View file

@ -102,7 +102,7 @@ To authenticate to the Package Registry, you must use one of the following:
- It's not recommended, but you can use [OAuth tokens](../../../api/oauth2.md#resource-owner-password-credentials-flow).
Standard OAuth tokens cannot authenticate to the GitLab NPM Registry. You must use a personal access token with OAuth headers.
- A [CI job token](#authenticate-with-a-ci-job-token).
- Your NPM package name must be in the format of [@scope:package-name](#package-naming-convention). It must match exactly, including the case.
- Your NPM package name must be in the format of [@scope/package-name](#package-naming-convention). It must match exactly, including the case.
### Authenticate with a personal access token or deploy token
@ -201,7 +201,7 @@ Then, you can run `npm publish` either locally or by using GitLab CI/CD.
## Package naming convention
Your NPM package name must be in the format of `@scope:package-name`.
Your NPM package name must be in the format of `@scope/package-name`.
- The `@scope` is the root namespace of the GitLab project. It must match exactly, including the case.
- The `package-name` can be whatever you want.
@ -241,7 +241,7 @@ Prerequisites:
- [Authenticate](#authenticate-to-the-package-registry) to the Package Registry.
- Set a [project-level NPM endpoint](#use-the-gitlab-endpoint-for-npm-packages).
- Your NPM package name must be in the format of [@scope:package-name](#package-naming-convention). It must match exactly, including the case.
- Your NPM package name must be in the format of [@scope/package-name](#package-naming-convention). It must match exactly, including the case.
To upload an NPM package to your project, run this command:
@ -461,7 +461,7 @@ If you get this error, ensure that:
### `npm publish` returns `npm ERR! 400 Bad Request`
If you get this error, your package name may not meet the
[@scope:package-name package naming convention](#package-naming-convention).
[@scope/package-name package naming convention](#package-naming-convention).
Ensure the name meets the convention exactly, including the case.
Then try to publish again.

View file

@ -235,9 +235,12 @@ password = ${env.CI_JOB_TOKEN}
When publishing packages, note that:
- The maximum allowed size is 50 MB.
- You must [authenticate with the Package Registry](#authenticate-with-the-package-registry).
- Your [version string must be valid](#ensure-your-version-string-is-valid).
- The maximum allowed package size is 5 GB.
- You can't upload the same version of a package multiple times. If you try,
you receive the error `Validation failed: File name has already been taken`.
- You cannot publish PyPI packages to a group, only to a project.
### Ensure your version string is valid

View file

@ -12,7 +12,9 @@ module API
unauthorized! unless current_user
{
merge_requests: current_user.assigned_open_merge_requests_count
merge_requests: current_user.assigned_open_merge_requests_count, # @deprecated
assigned_merge_requests: current_user.assigned_open_merge_requests_count,
review_requested_merge_requests: current_user.review_requested_open_merge_requests_count
}
end
end

View file

@ -198,7 +198,9 @@ module Gitlab
return unless valid_scoped_token?(token, all_available_scopes)
if token.user.can?(:log_in) || token.user.can?(:bot_log_in, project)
return if project && token.user.project_bot? && !project.bots.include?(token.user)
if token.user.can?(:log_in) || token.user.project_bot?
Gitlab::Auth::Result.new(token.user, nil, :personal_access_token, abilities_for_scopes(token.scopes))
end
end
@ -283,7 +285,7 @@ module Gitlab
return unless build.project.builds_enabled?
if build.user
return unless build.user.can?(:log_in) || build.user.can?(:bot_log_in, build.project)
return unless build.user.can?(:log_in) || (build.user.project_bot? && build.project.bots&.include?(build.user))
# If user is assigned to build, use restricted credentials of user
Gitlab::Auth::Result.new(build.user, build.project, :build, build_authentication_abilities)

View file

@ -31,10 +31,9 @@ module Gitlab
current = @from
while current <= @to
label = current.strftime(@format)
@labels << label
@total << (totals_count[label] || 0)
@success << (success_count[label] || 0)
@labels << current.strftime(@format)
@total << (totals_count[current] || 0)
@success << (success_count[current] || 0)
current += interval_step
end
@ -46,7 +45,6 @@ module Gitlab
query
.group("date_trunc('#{interval}', #{::Ci::Pipeline.table_name}.created_at)")
.count(:created_at)
.transform_keys { |date| date.strftime(@format) }
end
# rubocop: enable CodeReuse/ActiveRecord

View file

@ -3943,6 +3943,9 @@ msgstr ""
msgid "Assigned to me"
msgstr ""
msgid "Assigned to you"
msgstr ""
msgid "Assignee"
msgid_plural "%d Assignees"
msgstr[0] ""
@ -24032,6 +24035,9 @@ msgstr ""
msgid "Review requested from %{name}"
msgstr ""
msgid "Review requests for you"
msgstr ""
msgid "Review the changes locally"
msgstr ""

View file

@ -110,6 +110,12 @@ RSpec.describe 'Dashboard Merge Requests' do
visit merge_requests_dashboard_path(assignee_username: current_user.username)
end
it 'includes assigned and reviewers in badge' do
expect(find('.merge-requests-count')).to have_content('3')
expect(find('.js-assigned-mr-count')).to have_content('2')
expect(find('.js-reviewer-mr-count')).to have_content('1')
end
it 'shows assigned merge requests' do
expect(page).to have_content(assigned_merge_request.title)
expect(page).to have_content(assigned_merge_request_from_fork.title)

View file

@ -8,7 +8,7 @@ import Api from '~/api';
jest.mock('~/api');
const TEST_COUNT = 1000;
const MR_COUNT_CLASS = 'merge-requests-count';
const MR_COUNT_CLASS = 'js-merge-requests-count';
describe('User Merge Requests', () => {
let channelMock;
@ -24,7 +24,9 @@ describe('User Merge Requests', () => {
newBroadcastChannelMock = jest.fn().mockImplementation(() => channelMock);
global.BroadcastChannel = newBroadcastChannelMock;
setFixtures(`<div class="${MR_COUNT_CLASS}">0</div>`);
setFixtures(
`<div><div class="${MR_COUNT_CLASS}">0</div><div class="js-assigned-mr-count"></div><div class="js-reviewer-mr-count"></div></div>`,
);
});
const findMRCountText = () => document.body.querySelector(`.${MR_COUNT_CLASS}`).textContent;
@ -33,7 +35,10 @@ describe('User Merge Requests', () => {
beforeEach(() => {
Api.userCounts.mockReturnValue(
Promise.resolve({
data: { merge_requests: TEST_COUNT },
data: {
assigned_merge_requests: TEST_COUNT,
review_requested_merge_requests: TEST_COUNT,
},
}),
);
});
@ -46,7 +51,7 @@ describe('User Merge Requests', () => {
});
it('updates the top count of merge requests', () => {
expect(findMRCountText()).toEqual(TEST_COUNT.toLocaleString());
expect(findMRCountText()).toEqual(Number(TEST_COUNT + TEST_COUNT).toLocaleString());
});
it('calls the API', () => {
@ -54,7 +59,7 @@ describe('User Merge Requests', () => {
});
it('posts count to BroadcastChannel', () => {
expect(channelMock.postMessage).toHaveBeenCalledWith(TEST_COUNT);
expect(channelMock.postMessage).toHaveBeenCalledWith(TEST_COUNT + TEST_COUNT);
});
});

View file

@ -89,4 +89,10 @@ RSpec.describe DashboardHelper do
it { is_expected.to eq(false) }
end
describe '#reviewer_mrs_dashboard_path' do
subject { helper.reviewer_mrs_dashboard_path }
it { is_expected.to eq(merge_requests_dashboard_path(reviewer_username: user.username)) }
end
end

View file

@ -67,4 +67,37 @@ RSpec.describe MergeRequestsHelper do
end
end
end
describe '#user_merge_requests_counts' do
let(:user) do
double(
assigned_open_merge_requests_count: 1,
review_requested_open_merge_requests_count: 2
)
end
subject { helper.user_merge_requests_counts }
before do
allow(helper).to receive(:current_user).and_return(user)
end
it "returns assigned, review requested and total merge request counts" do
expect(subject).to eq(
assigned: user.assigned_open_merge_requests_count,
review_requested: user.review_requested_open_merge_requests_count,
total: user.assigned_open_merge_requests_count + user.review_requested_open_merge_requests_count
)
end
context 'when merge_request_reviewers is disabled' do
before do
stub_feature_flags(merge_request_reviewers: false)
end
it 'returns review_requested as 0' do
expect(subject[:review_requested]).to eq(0)
end
end
end
end

View file

@ -47,10 +47,6 @@ RSpec.describe Gitlab::Ci::Charts do
subject { chart.to }
before do
create(:ci_empty_pipeline, project: project, duration: 120)
end
it 'includes the whole current day' do
is_expected.to eq(Date.today.end_of_day)
end
@ -62,37 +58,6 @@ RSpec.describe Gitlab::Ci::Charts do
it 'uses %d %B as labels format' do
expect(chart.labels).to include(chart.from.strftime('%d %B'))
end
it 'returns count of pipelines run each day in the current week' do
expect(chart.total).to contain_exactly(0, 0, 0, 0, 0, 0, 0, 1)
end
end
context 'weekchart_non_utc' do
today = Date.today
end_of_today = Time.use_zone(Time.find_zone('Asia/Dubai')) { today.end_of_day }
let(:project) { create(:project) }
let(:chart) do
allow(Date).to receive(:today).and_return(today)
allow(today).to receive(:end_of_day).and_return(end_of_today)
Gitlab::Ci::Charts::WeekChart.new(project)
end
subject { chart.total }
before do
create(:ci_empty_pipeline, project: project, duration: 120)
end
it 'uses a non-utc time zone for range times' do
expect(chart.to.zone).to eq(end_of_today.zone)
expect(chart.from.zone).to eq(end_of_today.zone)
end
it 'returns count of pipelines run each day in the current week' do
is_expected.to contain_exactly(0, 0, 0, 0, 0, 0, 0, 1)
end
end
context 'pipeline_times' do

View file

@ -4084,6 +4084,7 @@ RSpec.describe User do
cache_mock = double
expect(cache_mock).to receive(:delete).with(['users', user.id, 'assigned_open_merge_requests_count'])
expect(cache_mock).to receive(:delete).with(['users', user.id, 'review_requested_open_merge_requests_count'])
allow(Rails).to receive(:cache).and_return(cache_mock)
@ -4163,6 +4164,20 @@ RSpec.describe User do
end
end
describe '#review_requested_open_merge_requests_count' do
it 'returns number of open merge requests from non-archived projects' do
user = create(:user)
project = create(:project, :public)
archived_project = create(:project, :public, :archived)
create(:merge_request, source_project: project, author: user, reviewers: [user])
create(:merge_request, :closed, source_project: project, author: user, reviewers: [user])
create(:merge_request, source_project: archived_project, author: user, reviewers: [user])
expect(user.review_requested_open_merge_requests_count(force: true)).to eq 1
end
end
describe '#assigned_open_issues_count' do
it 'returns number of open issues from non-archived projects' do
user = create(:user)

View file

@ -401,40 +401,6 @@ RSpec.describe ProjectPolicy do
end
end
describe 'bot_log_in' do
let(:bot_user) { create(:user, :project_bot) }
let(:project) { private_project }
context 'when bot is in project and is not blocked' do
before do
project.add_maintainer(bot_user)
end
it 'is a valid project bot' do
expect(bot_user.can?(:bot_log_in, project)).to be_truthy
end
end
context 'when project bot is invalid' do
context 'when bot is not in project' do
it 'is not a valid project bot' do
expect(bot_user.can?(:bot_log_in, project)).to be_falsy
end
end
context 'when bot user is blocked' do
before do
project.add_maintainer(bot_user)
bot_user.block!
end
it 'is not a valid project bot' do
expect(bot_user.can?(:bot_log_in, project)).to be_falsy
end
end
end
end
context 'support bot' do
let(:current_user) { User.support_bot }

View file

@ -521,6 +521,19 @@ RSpec.describe MergeRequests::UpdateService, :mailer do
should_email(user2)
should_email(user3)
end
it 'updates open merge request counter for reviewers', :use_clean_rails_memory_store_caching do
merge_request.reviewers = [user3]
# Cache them to ensure the cache gets invalidated on update
expect(user2.review_requested_open_merge_requests_count).to eq(0)
expect(user3.review_requested_open_merge_requests_count).to eq(1)
update_merge_request(reviewer_ids: [user2.id])
expect(user2.review_requested_open_merge_requests_count).to eq(1)
expect(user3.review_requested_open_merge_requests_count).to eq(0)
end
end
context 'when the milestone is removed' do