diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-04-11 06:13:40 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-04-11 06:13:40 +0300 |
commit | 3e5f51c3717e31b741bca08639932cf6d63533c8 (patch) | |
tree | 4017a1b7a7494816a052f1ac3ebf509ddb04f915 | |
parent | 2546306238465366ac0f0c8038ac4443dc82189e (diff) |
Add latest changes from gitlab-org/gitlab@master
-rw-r--r-- | GITALY_SERVER_VERSION | 2 | ||||
-rw-r--r-- | app/models/member.rb | 3 | ||||
-rw-r--r-- | app/models/members/group_member.rb | 7 | ||||
-rw-r--r-- | app/models/members/project_member.rb | 7 | ||||
-rw-r--r-- | app/services/notification_service.rb | 36 | ||||
-rw-r--r-- | locale/gitlab.pot | 6 | ||||
-rw-r--r-- | spec/frontend/notes/components/note_form_spec.js | 114 | ||||
-rw-r--r-- | spec/services/notification_service_spec.rb | 30 | ||||
-rw-r--r-- | spec/support/shared_examples/models/members_notifications_shared_example.rb | 2 | ||||
-rw-r--r-- | workhorse/go.mod | 2 | ||||
-rw-r--r-- | workhorse/go.sum | 4 |
11 files changed, 78 insertions, 135 deletions
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION index 27d83a4a895..5f84ef38652 100644 --- a/GITALY_SERVER_VERSION +++ b/GITALY_SERVER_VERSION @@ -1 +1 @@ -6583e7d21b0533866bcb1d812fa397f6f34cd3df +13f08896b308c617c4a4ca585212069808422367 diff --git a/app/models/member.rb b/app/models/member.rb index 9b3f1742dec..529666a069c 100644 --- a/app/models/member.rb +++ b/app/models/member.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true class Member < ApplicationRecord + extend ::Gitlab::Utils::Override include EachBatch include AfterCommitQueue include Sortable @@ -576,7 +577,7 @@ class Member < ApplicationRecord end def after_decline_invite - # override in subclass + notification_service.decline_invite(self) end def after_accept_request diff --git a/app/models/members/group_member.rb b/app/models/members/group_member.rb index 3bbb7749ce4..aabc902fe03 100644 --- a/app/models/members/group_member.rb +++ b/app/models/members/group_member.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true class GroupMember < Member - extend ::Gitlab::Utils::Override include FromUnion include CreatedAtFilterable @@ -108,12 +107,6 @@ class GroupMember < Member super end - def after_decline_invite - notification_service.decline_group_invite(self) - - super - end - def send_welcome_email? true end diff --git a/app/models/members/project_member.rb b/app/models/members/project_member.rb index ea47435f229..e0fecf702de 100644 --- a/app/models/members/project_member.rb +++ b/app/models/members/project_member.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true class ProjectMember < Member - extend ::Gitlab::Utils::Override SOURCE_TYPE = 'Project' SOURCE_TYPE_FORMAT = /\AProject\z/.freeze @@ -146,12 +145,6 @@ class ProjectMember < Member super end - def after_decline_invite - notification_service.decline_project_invite(self) - - super - end - # rubocop: disable CodeReuse/ServiceClass def event_service EventCreateService.new diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb index c9b8e052bf6..b93b44ce797 100644 --- a/app/services/notification_service.rb +++ b/app/services/notification_service.rb @@ -492,6 +492,18 @@ class NotificationService mailer.member_access_denied_email(member.real_source_type, member.source_id, member.user_id).deliver_later end + def decline_invite(member) + # Must always send, regardless of project/namespace configuration since it's a + # response to the user's action. + + mailer.member_invite_declined_email( + member.real_source_type, + member.source.id, + member.invite_email, + member.created_by_id + ).deliver_later + end + # Project invite def invite_project_member(project_member, token) return true unless project_member.notifiable?(:subscription) @@ -505,18 +517,6 @@ class NotificationService mailer.member_invite_accepted_email(project_member.real_source_type, project_member.id).deliver_later end - def decline_project_invite(project_member) - # Must always send, regardless of project/namespace configuration since it's a - # response to the user's action. - - mailer.member_invite_declined_email( - project_member.real_source_type, - project_member.project.id, - project_member.invite_email, - project_member.created_by_id - ).deliver_later - end - def new_project_member(project_member) return true unless project_member.notifiable?(:mention, skip_read_ability: true) @@ -542,18 +542,6 @@ class NotificationService mailer.member_invite_accepted_email(group_member.real_source_type, group_member.id).deliver_later end - def decline_group_invite(group_member) - # Must always send, regardless of project/namespace configuration since it's a - # response to the user's action. - - mailer.member_invite_declined_email( - group_member.real_source_type, - group_member.group.id, - group_member.invite_email, - group_member.created_by_id - ).deliver_later - end - def new_group_member(group_member) return true unless group_member.notifiable?(:mention) diff --git a/locale/gitlab.pot b/locale/gitlab.pot index fd265e61876..aa59278aa39 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -47060,13 +47060,13 @@ msgstr "" msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again." msgstr "" -msgid "UsageQuotas|Namespace transfer data used" +msgid "UsageQuotas|Container Registry storage statistics are not used to calculate the total project storage. After namespace container deduplication, the total of all unique containers is added to the namespace storage total." msgstr "" -msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication." +msgid "UsageQuotas|Namespace transfer data used" msgstr "" -msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage." +msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication." msgstr "" msgid "UsageQuota|%{linkStart}Shared runners%{linkEnd} are disabled, so there are no limits set on pipeline usage" diff --git a/spec/frontend/notes/components/note_form_spec.js b/spec/frontend/notes/components/note_form_spec.js index 12c3b154fc7..00f75b14e6b 100644 --- a/spec/frontend/notes/components/note_form_spec.js +++ b/spec/frontend/notes/components/note_form_spec.js @@ -1,11 +1,12 @@ import { GlLink } from '@gitlab/ui'; -import { mount } from '@vue/test-utils'; import { nextTick } from 'vue'; import batchComments from '~/batch_comments/stores/modules/batch_comments'; import NoteForm from '~/notes/components/note_form.vue'; import createStore from '~/notes/stores'; import MarkdownField from '~/vue_shared/components/markdown/field.vue'; import { AT_WHO_ACTIVE_CLASS } from '~/gfm_auto_complete'; +import eventHub from '~/environments/event_hub'; +import { mountExtended } from 'helpers/vue_test_utils_helper'; import { noteableDataMock, notesDataMock, discussionMock, note } from '../mock_data'; jest.mock('~/lib/utils/autosave'); @@ -14,23 +15,25 @@ describe('issue_note_form component', () => { let store; let wrapper; let props; - let features; - const createComponentWrapper = () => { - return mount(NoteForm, { + const createComponentWrapper = (propsData = {}, provide = {}) => { + wrapper = mountExtended(NoteForm, { store, - propsData: props, + propsData: { + ...props, + ...propsData, + }, provide: { - glFeatures: features || {}, + glFeatures: provide, }, }); }; - const findCancelButton = () => wrapper.find('[data-testid="cancel"]'); + const findCancelButton = () => wrapper.findByTestId('cancel'); + const findCancelCommentButton = () => wrapper.findByTestId('cancelBatchCommentsEnabled'); + const findMarkdownField = () => wrapper.findComponent(MarkdownField); beforeEach(() => { - features = {}; - store = createStore(); store.dispatch('setNoteableData', noteableDataMock); store.dispatch('setNotesData', notesDataMock); @@ -44,7 +47,7 @@ describe('issue_note_form component', () => { describe('noteHash', () => { beforeEach(() => { - wrapper = createComponentWrapper(); + createComponentWrapper(); }); it('returns note hash string based on `noteId`', () => { @@ -52,33 +55,29 @@ describe('issue_note_form component', () => { }); it('return note hash as `#` when `noteId` is empty', async () => { - wrapper.setProps({ - ...props, + createComponentWrapper({ noteId: '', }); - await nextTick(); expect(wrapper.vm.noteHash).toBe('#'); }); }); it('hides content editor switcher if feature flag content_editor_on_issues is off', () => { - features = { contentEditorOnIssues: false }; - wrapper = createComponentWrapper(); + createComponentWrapper({}, { contentEditorOnIssues: false }); expect(wrapper.text()).not.toContain('Rich text'); }); it('shows content editor switcher if feature flag content_editor_on_issues is on', () => { - features = { contentEditorOnIssues: true }; - wrapper = createComponentWrapper(); + createComponentWrapper({}, { contentEditorOnIssues: true }); expect(wrapper.text()).toContain('Rich text'); }); describe('conflicts editing', () => { beforeEach(() => { - wrapper = createComponentWrapper(); + createComponentWrapper(); }); it('should show conflict message if note changes outside the component', async () => { @@ -102,15 +101,13 @@ describe('issue_note_form component', () => { describe('form', () => { beforeEach(() => { - wrapper = createComponentWrapper(); + createComponentWrapper(); }); it('should render text area with placeholder', () => { const textarea = wrapper.find('textarea'); - expect(textarea.attributes('placeholder')).toEqual( - 'Write a comment or drag your files here…', - ); + expect(textarea.attributes('placeholder')).toBe('Write a comment or drag your files here…'); }); it('should set data-supports-quick-actions to enable autocomplete', () => { @@ -130,7 +127,7 @@ describe('issue_note_form component', () => { ...note, internal, }; - wrapper = createComponentWrapper(); + createComponentWrapper(); await nextTick(); @@ -139,11 +136,7 @@ describe('issue_note_form component', () => { ); it('should link to markdown docs', () => { - const { markdownDocsPath } = notesDataMock; - const markdownField = wrapper.findComponent(MarkdownField); - const markdownFieldProps = markdownField.props(); - - expect(markdownFieldProps.markdownDocsPath).toBe(markdownDocsPath); + expect(findMarkdownField().props('markdownDocsPath')).toBe(notesDataMock.markdownDocsPath); }); describe('keyboard events', () => { @@ -156,12 +149,11 @@ describe('issue_note_form component', () => { describe('up', () => { it('should ender edit mode', () => { - // TODO: do not spy on vm - jest.spyOn(wrapper.vm, 'editMyLastNote'); + const eventHubSpy = jest.spyOn(eventHub, '$emit'); textarea.trigger('keydown.up'); - expect(wrapper.vm.editMyLastNote).toHaveBeenCalled(); + expect(eventHubSpy).not.toHaveBeenCalled(); }); }); @@ -169,17 +161,13 @@ describe('issue_note_form component', () => { it('should save note when cmd+enter is pressed', () => { textarea.trigger('keydown.enter', { metaKey: true }); - const { handleFormUpdate } = wrapper.emitted(); - - expect(handleFormUpdate.length).toBe(1); + expect(wrapper.emitted('handleFormUpdate')).toHaveLength(1); }); it('should save note when ctrl+enter is pressed', () => { textarea.trigger('keydown.enter', { ctrlKey: true }); - const { handleFormUpdate } = wrapper.emitted(); - - expect(handleFormUpdate.length).toBe(1); + expect(wrapper.emitted('handleFormUpdate')).toHaveLength(1); }); it('should disable textarea when ctrl+enter is pressed', async () => { @@ -195,24 +183,16 @@ describe('issue_note_form component', () => { }); describe('actions', () => { - it('should be possible to cancel', async () => { - wrapper.setProps({ - ...props, - }); - await nextTick(); + it('should be possible to cancel', () => { + createComponentWrapper(); - const cancelButton = findCancelButton(); - cancelButton.vm.$emit('click'); - await nextTick(); + findCancelButton().vm.$emit('click'); - expect(wrapper.emitted().cancelForm).toHaveLength(1); + expect(wrapper.emitted('cancelForm')).toHaveLength(1); }); it('will not cancel form if there is an active at-who-active class', async () => { - wrapper.setProps({ - ...props, - }); - await nextTick(); + createComponentWrapper(); const textareaEl = wrapper.vm.$refs.markdownEditor.$el.querySelector('textarea'); const cancelButton = findCancelButton(); @@ -220,21 +200,18 @@ describe('issue_note_form component', () => { cancelButton.vm.$emit('click'); await nextTick(); - expect(wrapper.emitted().cancelForm).toBeUndefined(); + expect(wrapper.emitted('cancelForm')).toBeUndefined(); }); it('should be possible to update the note', async () => { - wrapper.setProps({ - ...props, - }); - await nextTick(); + createComponentWrapper(); const textarea = wrapper.find('textarea'); textarea.setValue('Foo'); const saveButton = wrapper.find('.js-vue-issue-save'); saveButton.vm.$emit('click'); - expect(wrapper.vm.isSubmitting).toBe(true); + expect(wrapper.emitted('handleFormUpdate')).toHaveLength(1); }); }); }); @@ -243,9 +220,7 @@ describe('issue_note_form component', () => { beforeEach(() => { store.registerModule('batchComments', batchComments()); - wrapper = createComponentWrapper(); - wrapper.setProps({ - ...props, + createComponentWrapper({ isDraft: true, noteId: '', discussion: { ...discussionMock, for_commit: false }, @@ -253,13 +228,9 @@ describe('issue_note_form component', () => { }); it('should be possible to cancel', async () => { - jest.spyOn(wrapper.vm, 'cancelHandler'); - - await nextTick(); - const cancelButton = wrapper.find('[data-testid="cancelBatchCommentsEnabled"]'); - cancelButton.vm.$emit('click'); + findCancelCommentButton().vm.$emit('click'); - expect(wrapper.vm.cancelHandler).toHaveBeenCalledWith(true); + expect(wrapper.emitted('cancelForm')).toEqual([[true, false]]); }); it('shows resolve checkbox', () => { @@ -267,7 +238,7 @@ describe('issue_note_form component', () => { }); it('hides resolve checkbox', async () => { - wrapper.setProps({ + createComponentWrapper({ isDraft: false, discussion: { ...discussionMock, @@ -282,15 +253,11 @@ describe('issue_note_form component', () => { }, }); - await nextTick(); - expect(wrapper.find('.js-resolve-checkbox').exists()).toBe(false); }); it('hides actions for commits', async () => { - wrapper.setProps({ discussion: { for_commit: true } }); - - await nextTick(); + createComponentWrapper({ discussion: { for_commit: true } }); expect(wrapper.find('.note-form-actions').text()).not.toContain('Start a review'); }); @@ -299,13 +266,12 @@ describe('issue_note_form component', () => { it('should start review or add to review when cmd+enter is pressed', async () => { const textarea = wrapper.find('textarea'); - jest.spyOn(wrapper.vm, 'handleAddToReview'); - textarea.setValue('Foo'); textarea.trigger('keydown.enter', { metaKey: true }); await nextTick(); - expect(wrapper.vm.handleAddToReview).toHaveBeenCalled(); + + expect(wrapper.emitted('handleFormUpdateAddToReview')).toEqual([['Foo', false]]); }); }); }); diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb index 15e430ddc74..f63f982708d 100644 --- a/spec/services/notification_service_spec.rb +++ b/spec/services/notification_service_spec.rb @@ -253,6 +253,16 @@ RSpec.describe NotificationService, :mailer, feature_category: :team_planning do it_behaves_like 'participating by assignee notification', check_delivery_jobs_queue: check_delivery_jobs_queue end + shared_examples 'declines the invite' do + specify do + member = source.members.last + + expect do + notification.decline_invite(member) + end.to change { ActionMailer::Base.deliveries.size }.by(1) + end + end + describe '.permitted_actions' do it 'includes public methods' do expect(described_class.permitted_actions).to include(:access_token_created) @@ -3029,7 +3039,7 @@ RSpec.describe NotificationService, :mailer, feature_category: :team_planning do end end - describe '#decline_group_invite' do + describe '#decline_invite' do let(:creator) { create(:user) } let(:group) { create(:group) } let(:member) { create(:user) } @@ -3039,12 +3049,8 @@ RSpec.describe NotificationService, :mailer, feature_category: :team_planning do group.add_developer(member, creator) end - it do - group_member = group.members.last - - expect do - notification.decline_group_invite(group_member) - end.to change { ActionMailer::Base.deliveries.size }.by(1) + it_behaves_like 'declines the invite' do + let(:source) { group } end end @@ -3201,19 +3207,15 @@ RSpec.describe NotificationService, :mailer, feature_category: :team_planning do end end - describe '#decline_project_invite' do + describe '#decline_invite' do let(:member) { create(:user) } before do project.add_developer(member, current_user: project.first_owner) end - it do - project_member = project.members.last - - expect do - notification.decline_project_invite(project_member) - end.to change { ActionMailer::Base.deliveries.size }.by(1) + it_behaves_like 'declines the invite' do + let(:source) { project } end end diff --git a/spec/support/shared_examples/models/members_notifications_shared_example.rb b/spec/support/shared_examples/models/members_notifications_shared_example.rb index e28220334ac..329cb812a08 100644 --- a/spec/support/shared_examples/models/members_notifications_shared_example.rb +++ b/spec/support/shared_examples/models/members_notifications_shared_example.rb @@ -69,7 +69,7 @@ RSpec.shared_examples 'members notifications' do |entity_type| let(:member) { create(:"#{entity_type}_member", :invited) } it "calls NotificationService.decline_#{entity_type}_invite" do - expect(notification_service).to receive(:"decline_#{entity_type}_invite").with(member) + expect(notification_service).to receive(:decline_invite).with(member) member.decline_invite! end diff --git a/workhorse/go.mod b/workhorse/go.mod index 6a989942523..a9d5e533653 100644 --- a/workhorse/go.mod +++ b/workhorse/go.mod @@ -26,7 +26,7 @@ require ( github.com/sirupsen/logrus v1.9.0 github.com/smartystreets/goconvey v1.7.2 github.com/stretchr/testify v1.8.2 - gitlab.com/gitlab-org/gitaly/v15 v15.10.0 + gitlab.com/gitlab-org/gitaly/v15 v15.10.1 gitlab.com/gitlab-org/golang-archive-zip v0.1.1 gitlab.com/gitlab-org/labkit v1.18.0 gocloud.dev v0.29.0 diff --git a/workhorse/go.sum b/workhorse/go.sum index 3868d8edf66..45447c67e2c 100644 --- a/workhorse/go.sum +++ b/workhorse/go.sum @@ -1918,8 +1918,8 @@ github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= -gitlab.com/gitlab-org/gitaly/v15 v15.10.0 h1:l6K7AuaK3LPB9FaVk0tLtpPEX7eXEvVgPzRQGRq1FJc= -gitlab.com/gitlab-org/gitaly/v15 v15.10.0/go.mod h1:ZsyTd8zGxT4WuSZJ0G8ydJb60mauzEP0XJtZJEy/7bc= +gitlab.com/gitlab-org/gitaly/v15 v15.10.1 h1:43RZwVktIZLOq2GsRvQVUWZ4YiKPEueoWnmzz3T/UWk= +gitlab.com/gitlab-org/gitaly/v15 v15.10.1/go.mod h1:ZsyTd8zGxT4WuSZJ0G8ydJb60mauzEP0XJtZJEy/7bc= gitlab.com/gitlab-org/golang-archive-zip v0.1.1 h1:35k9giivbxwF03+8A05Cm8YoxoakU8FBCj5gysjCTCE= gitlab.com/gitlab-org/golang-archive-zip v0.1.1/go.mod h1:ZDtqpWPGPB9qBuZnZDrKQjIdJtkN7ZAoVwhT6H2o2kE= gitlab.com/gitlab-org/labkit v1.18.0 h1:uYCIqDt/5V1hLIecTR4UNc1sD2+xiYplyKeyfpNN26A= |