Skip to content
Snippets Groups Projects
Commit 46b10c0f authored by GitLab Bot's avatar GitLab Bot
Browse files

Add latest changes from gitlab-org/gitlab@master

parent 3358e1fd
No related branches found
No related tags found
No related merge requests found
# frozen_string_literal: true
# rubocop:disable Style/Documentation
module Gitlab
module BackgroundMigration
module UserMentions
module Models
class EpicUserMention < ActiveRecord::Base
self.table_name = 'epic_user_mentions'
def self.resource_foreign_key
:epic_id
end
end
end
end
end
end
# frozen_string_literal: true
module Gitlab
module BackgroundMigration
module UserMentions
module Models
# == IsolatedMentionable concern
#
# Shortcutted for isolation version of Mentionable to be used in mentions migrations
#
module IsolatedMentionable
extend ::ActiveSupport::Concern
class_methods do
# Indicate which attributes of the Mentionable to search for GFM references.
def attr_mentionable(attr, options = {})
attr = attr.to_s
mentionable_attrs << [attr, options]
end
end
included do
# Accessor for attributes marked mentionable.
cattr_accessor :mentionable_attrs, instance_accessor: false do
[]
end
if self < Participable
participant -> (user, ext) { all_references(user, extractor: ext) }
end
end
def all_references(current_user = nil, extractor: nil)
# Use custom extractor if it's passed in the function parameters.
if extractor
extractors[current_user] = extractor
else
extractor = extractors[current_user] ||= ::Gitlab::ReferenceExtractor.new(project, current_user)
extractor.reset_memoized_values
end
self.class.mentionable_attrs.each do |attr, options|
text = __send__(attr) # rubocop:disable GitlabSecurity/PublicSend
options = options.merge(
cache_key: [self, attr],
author: author,
skip_project_check: skip_project_check?
).merge(mentionable_params)
cached_html = self.try(:updated_cached_html_for, attr.to_sym)
options[:rendered] = cached_html if cached_html
extractor.analyze(text, options)
end
extractor
end
def extractors
@extractors ||= {}
end
def skip_project_check?
false
end
def build_mention_values
refs = all_references(author)
{
"#{self.user_mention_model.resource_foreign_key}": user_mention_resource_id,
note_id: user_mention_note_id,
mentioned_users_ids: array_to_sql(refs.mentioned_users.pluck(:id)),
mentioned_projects_ids: array_to_sql(refs.mentioned_projects.pluck(:id)),
mentioned_groups_ids: array_to_sql(refs.mentioned_groups.pluck(:id))
}
end
def array_to_sql(ids_array)
return unless ids_array.present?
'{' + ids_array.join(", ") + '}'
end
private
def mentionable_params
{}
end
end
end
end
end
end
# frozen_string_literal: true
# rubocop:disable Style/Documentation
module Gitlab
module BackgroundMigration
module UserMentions
module Models
class Note < ActiveRecord::Base
include IsolatedMentionable
include CacheMarkdownField
self.table_name = 'notes'
self.inheritance_column = :_type_disabled
attr_mentionable :note, pipeline: :note
cache_markdown_field :note, pipeline: :note, issuable_state_filter_enabled: true
belongs_to :author, class_name: "User"
belongs_to :noteable, polymorphic: true
belongs_to :project
def user_mention_model
"#{CreateResourceUserMention::ISOLATION_MODULE}::#{noteable.class}".constantize.user_mention_model
end
def for_personal_snippet?
noteable.class.name == 'PersonalSnippet'
end
def for_project_noteable?
!for_personal_snippet?
end
def skip_project_check?
!for_project_noteable?
end
def for_epic?
noteable.class.name == 'Epic'
end
def user_mention_resource_id
noteable_id || commit_id
end
def user_mention_note_id
id
end
private
def mentionable_params
return super unless for_epic?
super.merge(banzai_context_params)
end
def banzai_context_params
{ group: noteable.group, label_url_method: :group_epics_url }
end
end
end
end
end
end
Loading
Loading
@@ -130,6 +130,40 @@ describe Groups::MilestonesController do
end
end
end
context 'when subgroup milestones are present' do
let(:subgroup) { create(:group, :private, parent: group) }
let(:sub_project) { create(:project, :private, group: subgroup) }
let!(:group_milestone) { create(:milestone, group: group, title: 'Group milestone') }
let!(:sub_project_milestone) { create(:milestone, project: sub_project, title: 'Sub Project Milestone') }
let!(:subgroup_milestone) { create(:milestone, title: 'Subgroup Milestone', group: subgroup) }
it 'shows subgroup milestones that user has access to' do
get :index, params: { group_id: group.to_param }
expect(response).to have_gitlab_http_status(200)
expect(response.body).to include(group_milestone.title)
expect(response.body).to include(sub_project_milestone.title)
expect(response.body).to include(subgroup_milestone.title)
end
context 'when user has no access to subgroups' do
let(:non_member) { create(:user) }
before do
sign_in(non_member)
end
it 'does not show subgroup milestones' do
get :index, params: { group_id: group.to_param }
expect(response).to have_gitlab_http_status(200)
expect(response.body).to include(group_milestone.title)
expect(response.body).not_to include(sub_project_milestone.title)
expect(response.body).not_to include(subgroup_milestone.title)
end
end
end
end
 
context 'as JSON' do
Loading
Loading
@@ -149,6 +183,19 @@ describe Groups::MilestonesController do
expect(response.content_type).to eq 'application/json'
end
 
context 'with subgroup milestones' do
it 'lists descendants group milestones' do
subgroup = create(:group, :public, parent: group)
create(:milestone, group: subgroup, title: 'subgroup milestone')
get :index, params: { group_id: group.to_param }, format: :json
milestones = json_response
expect(milestones.count).to eq(3)
expect(milestones.second["title"]).to eq("subgroup milestone")
end
end
context 'for a subgroup' do
let(:subgroup) { create(:group, parent: group) }
 
Loading
Loading
Loading
Loading
@@ -31,10 +31,7 @@ describe('Dashboard', () => {
const findEnvironmentsDropdown = () => wrapper.find({ ref: 'monitorEnvironmentsDropdown' });
const findAllEnvironmentsDropdownItems = () => findEnvironmentsDropdown().findAll(GlDropdownItem);
const setSearchTerm = searchTerm => {
wrapper.vm.$store.commit(
`monitoringDashboard/${types.SET_ENVIRONMENTS_SEARCH_TERM}`,
searchTerm,
);
wrapper.vm.$store.commit(`monitoringDashboard/${types.SET_ENVIRONMENTS_FILTER}`, searchTerm);
};
 
const createShallowWrapper = (props = {}, options = {}) => {
Loading
Loading
@@ -313,6 +310,25 @@ describe('Dashboard', () => {
expect(wrapper.find({ ref: 'monitorEnvironmentsDropdownMsg' }).isVisible()).toBe(true);
});
});
it('shows loading element when environments fetch is still loading', () => {
wrapper.vm.$store.commit(`monitoringDashboard/${types.REQUEST_ENVIRONMENTS_DATA}`);
return wrapper.vm
.$nextTick()
.then(() => {
expect(wrapper.find({ ref: 'monitorEnvironmentsDropdownLoading' }).exists()).toBe(true);
})
.then(() => {
wrapper.vm.$store.commit(
`monitoringDashboard/${types.RECEIVE_ENVIRONMENTS_DATA_SUCCESS}`,
environmentData,
);
})
.then(() => {
expect(wrapper.find({ ref: 'monitorEnvironmentsDropdownLoading' }).exists()).toBe(false);
});
});
});
 
describe('drag and drop function', () => {
Loading
Loading
Loading
Loading
@@ -17,10 +17,12 @@ import {
fetchPrometheusMetrics,
fetchPrometheusMetric,
setEndpoints,
filterEnvironments,
setGettingStartedEmptyState,
duplicateSystemDashboard,
} from '~/monitoring/stores/actions';
import { gqClient, parseEnvironmentsResponse } from '~/monitoring/stores/utils';
import getEnvironments from '~/monitoring/queries/getEnvironments.query.graphql';
import storeState from '~/monitoring/stores/state';
import {
deploymentData,
Loading
Loading
@@ -105,12 +107,70 @@ describe('Monitoring store actions', () => {
.catch(done.fail);
});
});
describe('fetchEnvironmentsData', () => {
it('commits RECEIVE_ENVIRONMENTS_DATA_SUCCESS on error', () => {
const dispatch = jest.fn();
const { state } = store;
state.projectPath = '/gitlab-org/gitlab-test';
const dispatch = jest.fn();
const { state } = store;
state.projectPath = 'gitlab-org/gitlab-test';
 
afterEach(() => {
resetStore(store);
jest.restoreAllMocks();
});
it('setting SET_ENVIRONMENTS_FILTER should dispatch fetchEnvironmentsData', () => {
jest.spyOn(gqClient, 'mutate').mockReturnValue(
Promise.resolve({
data: {
project: {
data: {
environments: [],
},
},
},
}),
);
return testAction(
filterEnvironments,
{},
state,
[
{
type: 'SET_ENVIRONMENTS_FILTER',
payload: {},
},
],
[
{
type: 'fetchEnvironmentsData',
},
],
);
});
it('fetch environments data call takes in search param', () => {
const mockMutate = jest.spyOn(gqClient, 'mutate');
const searchTerm = 'Something';
const mutationVariables = {
mutation: getEnvironments,
variables: {
projectPath: state.projectPath,
search: searchTerm,
},
};
state.environmentsSearchTerm = searchTerm;
mockMutate.mockReturnValue(Promise.resolve());
return fetchEnvironmentsData({
state,
dispatch,
}).then(() => {
expect(mockMutate).toHaveBeenCalledWith(mutationVariables);
});
});
it('commits RECEIVE_ENVIRONMENTS_DATA_SUCCESS on success', () => {
jest.spyOn(gqClient, 'mutate').mockReturnValue(
Promise.resolve({
data: {
Loading
Loading
@@ -135,9 +195,6 @@ describe('Monitoring store actions', () => {
});
 
it('commits RECEIVE_ENVIRONMENTS_DATA_FAILURE on error', () => {
const dispatch = jest.fn();
const { state } = store;
state.projectPath = '/gitlab-org/gitlab-test';
jest.spyOn(gqClient, 'mutate').mockReturnValue(Promise.reject());
 
return fetchEnvironmentsData({
Loading
Loading
@@ -148,6 +205,7 @@ describe('Monitoring store actions', () => {
});
});
});
describe('Set endpoints', () => {
let mockedState;
beforeEach(() => {
Loading
Loading
Loading
Loading
@@ -5587,6 +5587,25 @@ describe Project do
end
end
 
describe 'with_issues_or_mrs_available_for_user' do
before do
Project.delete_all
end
it 'returns correct projects' do
user = create(:user)
project1 = create(:project, :public, :merge_requests_disabled, :issues_enabled)
project2 = create(:project, :public, :merge_requests_disabled, :issues_disabled)
project3 = create(:project, :public, :issues_enabled, :merge_requests_enabled)
project4 = create(:project, :private, :issues_private, :merge_requests_private)
[project1, project2, project3, project4].each { |project| project.add_developer(user) }
expect(described_class.with_issues_or_mrs_available_for_user(user))
.to contain_exactly(project1, project3, project4)
end
end
def rugged_config
rugged_repo(project.repository).config
end
Loading
Loading
Loading
Loading
@@ -229,16 +229,17 @@ RSpec.shared_examples 'mentions in description' do |mentionable_type|
 
context 'when mentionable description contains mentions' do
let(:user) { create(:user) }
let(:user2) { create(:user) }
let(:group) { create(:group) }
 
let(:mentionable_desc) { "#{user.to_reference} some description #{group.to_reference(full: true)} and @all" }
let(:mentionable_desc) { "#{user.to_reference} #{user2.to_reference} #{user.to_reference} some description #{group.to_reference(full: true)} and #{user2.to_reference} @all" }
let(:mentionable) { create(mentionable_type, description: mentionable_desc) }
 
it 'stores mentions' do
add_member(user)
 
expect(mentionable.user_mentions.count).to eq 1
expect(mentionable.referenced_users).to match_array([user])
expect(mentionable.referenced_users).to match_array([user, user2])
expect(mentionable.referenced_projects(user)).to match_array([mentionable.project].compact) # epic.project is nil, and we want empty []
expect(mentionable.referenced_groups(user)).to match_array([group])
end
Loading
Loading
@@ -249,8 +250,9 @@ end
RSpec.shared_examples 'mentions in notes' do |mentionable_type|
context 'when mentionable notes contain mentions' do
let(:user) { create(:user) }
let(:user2) { create(:user) }
let(:group) { create(:group) }
let(:note_desc) { "#{user.to_reference} and #{group.to_reference(full: true)} and @all" }
let(:note_desc) { "#{user.to_reference} #{user2.to_reference} #{user.to_reference} and #{group.to_reference(full: true)} and #{user2.to_reference} @all" }
let!(:mentionable) { note.noteable }
 
before do
Loading
Loading
@@ -261,7 +263,7 @@ RSpec.shared_examples 'mentions in notes' do |mentionable_type|
 
it 'returns all mentionable mentions' do
expect(mentionable.user_mentions.count).to eq 1
expect(mentionable.referenced_users).to eq [user]
expect(mentionable.referenced_users).to eq [user, user2]
expect(mentionable.referenced_projects(user)).to eq [mentionable.project].compact # epic.project is nil, and we want empty []
expect(mentionable.referenced_groups(user)).to eq [group]
end
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment