diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-12-10 14:52:44 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-12-10 14:52:44 +0000 |
commit | 86a8eee1b8bd43a1fe962905eb97a1f478cc050b (patch) | |
tree | 439816bbaf4a0caf16d579223eb9465e0b0daebc | |
parent | 1b517a5a19c4aafc6fa6d738b0ee7c1e4a2cce36 (diff) | |
download | gitlab-ce-86a8eee1b8bd43a1fe962905eb97a1f478cc050b.tar.gz |
Add latest changes from gitlab-org/gitlab@13-6-stable-ee
29 files changed, 196 insertions, 44 deletions
diff --git a/app/assets/javascripts/registry/explorer/utils.js b/app/assets/javascripts/registry/explorer/utils.js index 2c89d508c31..a48da51caae 100644 --- a/app/assets/javascripts/registry/explorer/utils.js +++ b/app/assets/javascripts/registry/explorer/utils.js @@ -1,3 +1,5 @@ +import { joinPaths } from '~/lib/utils/url_utility'; + export const pathGenerator = (imageDetails, ending = '?format=json') => { // this method is a temporary workaround, to be removed with graphql implementation // https://gitlab.com/gitlab-org/gitlab/-/issues/276432 @@ -12,5 +14,12 @@ export const pathGenerator = (imageDetails, ending = '?format=json') => { return acc; }, []) .join('/'); - return `/${basePath}/registry/repository/${imageDetails.id}/tags${ending}`; + + return joinPaths( + window.gon.relative_url_root, + `/${basePath}`, + '/registry/repository/', + `${imageDetails.id}`, + `tags${ending}`, + ); }; diff --git a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue index 190d790f584..e7f0977778e 100644 --- a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue +++ b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue @@ -202,6 +202,9 @@ export default { shouldShowAccessibilityReport() { return this.mr.accessibilityReportPath; }, + formattedHumanAccess() { + return (this.mr.humanAccess || '').toLowerCase(); + }, }, watch: { state(newVal, oldVal) { @@ -439,7 +442,7 @@ export default { class="mr-widget-workflow" :pipeline-path="mr.mergeRequestAddCiConfigPath" :pipeline-svg-path="mr.pipelinesEmptySvgPath" - :human-access="mr.humanAccess.toLowerCase()" + :human-access="formattedHumanAccess" :user-callouts-path="mr.userCalloutsPath" :user-callout-feature-id="mr.suggestPipelineFeatureId" @dismiss="dismissSuggestPipelines" diff --git a/app/helpers/members_helper.rb b/app/helpers/members_helper.rb index d66f67fbb60..5dc636ad996 100644 --- a/app/helpers/members_helper.rb +++ b/app/helpers/members_helper.rb @@ -6,14 +6,14 @@ module MembersHelper text = 'Are you sure you want to' action = - if member.request? + if member.invite? + "revoke the invitation for #{member.invite_email} to join" + elsif member.request? if member.user == user 'withdraw your access request for' else "deny #{member.user.name}'s request to join" end - elsif member.invite? - "revoke the invitation for #{member.invite_email} to join" else if member.user "remove #{member.user.name} from" diff --git a/app/services/members/invite_service.rb b/app/services/members/invite_service.rb index cfab5c3ef9d..60ebbaface2 100644 --- a/app/services/members/invite_service.rb +++ b/app/services/members/invite_service.rb @@ -20,8 +20,8 @@ module Members emails.each do |email| next if existing_member?(source, email) - next if existing_invite?(source, email) + next if existing_request?(source, email) if existing_user?(email) add_existing_user_as_member(current_user, source, params, email) @@ -44,8 +44,7 @@ module Members access_level: params[:access_level], invite_email: email, created_by_id: current_user.id, - expires_at: params[:expires_at], - requested_at: Time.current.utc) + expires_at: params[:expires_at]) unless new_member.valid? && new_member.persisted? errors[params[:email]] = new_member.errors.full_messages.to_sentence @@ -92,6 +91,17 @@ module Members false end + def existing_request?(source, email) + existing_request = source.requesters.with_user_by_email(email).exists? + + if existing_request + errors[email] = "Member cannot be invited because they already requested to join #{source.name}" + return true + end + + false + end + def existing_user(email) User.find_by_email(email) end diff --git a/app/services/projects/create_service.rb b/app/services/projects/create_service.rb index 8f18a23aa0f..a01db4b498c 100644 --- a/app/services/projects/create_service.rb +++ b/app/services/projects/create_service.rb @@ -67,7 +67,7 @@ module Projects @project rescue ActiveRecord::RecordInvalid => e - message = "Unable to save #{e.record.type}: #{e.record.errors.full_messages.join(", ")} " + message = "Unable to save #{e.inspect}: #{e.record.errors.full_messages.join(", ")}" fail(error: message) rescue => e @project.errors.add(:base, e.message) if @project @@ -122,8 +122,9 @@ module Projects only_concrete_membership: true) if group_access_level > GroupMember::NO_ACCESS - current_user.project_authorizations.create!(project: @project, - access_level: group_access_level) + current_user.project_authorizations.safe_find_or_create_by!( + project: @project, + access_level: group_access_level) end if Feature.enabled?(:specialized_project_authorization_workers) diff --git a/changelogs/unreleased/285076-400-bad-request-during-authentication-due-to-password-format-lengt.yml b/changelogs/unreleased/285076-400-bad-request-during-authentication-due-to-password-format-lengt.yml new file mode 100644 index 00000000000..a2dfc320f49 --- /dev/null +++ b/changelogs/unreleased/285076-400-bad-request-during-authentication-due-to-password-format-lengt.yml @@ -0,0 +1,5 @@ +--- +title: Add different string encoding method in rack middleware +merge_request: 49044 +author: +type: fixed diff --git a/changelogs/unreleased/288752-registry-details-relative-url-fix.yml b/changelogs/unreleased/288752-registry-details-relative-url-fix.yml new file mode 100644 index 00000000000..2d315d396ea --- /dev/null +++ b/changelogs/unreleased/288752-registry-details-relative-url-fix.yml @@ -0,0 +1,5 @@ +--- +title: Fix container_registry url for relative urls +merge_request: 48661 +author: +type: fixed diff --git a/changelogs/unreleased/290006-error-500-on-members-page-after-invitation-sent-via-api.yml b/changelogs/unreleased/290006-error-500-on-members-page-after-invitation-sent-via-api.yml new file mode 100644 index 00000000000..8d393e47a61 --- /dev/null +++ b/changelogs/unreleased/290006-error-500-on-members-page-after-invitation-sent-via-api.yml @@ -0,0 +1,5 @@ +--- +title: Resolve Members page 500 error after Invitation sent via API +merge_request: 48937 +author: +type: fixed diff --git a/changelogs/unreleased/291160-merge-request-doesn-t-fully-render-when-user-is-a-tool-admin-if-no.yml b/changelogs/unreleased/291160-merge-request-doesn-t-fully-render-when-user-is-a-tool-admin-if-no.yml new file mode 100644 index 00000000000..654119b2342 --- /dev/null +++ b/changelogs/unreleased/291160-merge-request-doesn-t-fully-render-when-user-is-a-tool-admin-if-no.yml @@ -0,0 +1,5 @@ +--- +title: Fix MR rendering issue when user is tool admin and not project member +merge_request: 49258 +author: +type: fixed diff --git a/changelogs/unreleased/sh-fix-issue-233862.yml b/changelogs/unreleased/sh-fix-issue-233862.yml new file mode 100644 index 00000000000..081c3574ec4 --- /dev/null +++ b/changelogs/unreleased/sh-fix-issue-233862.yml @@ -0,0 +1,5 @@ +--- +title: Fix error 500s creating projects concurrently +merge_request: 48571 +author: +type: fixed diff --git a/changelogs/unreleased/sh-require-ruby-2-7.yml b/changelogs/unreleased/sh-require-ruby-2-7.yml new file mode 100644 index 00000000000..7f7465d5cac --- /dev/null +++ b/changelogs/unreleased/sh-require-ruby-2-7.yml @@ -0,0 +1,5 @@ +--- +title: Update Rake check and docs to require Ruby 2.7 +merge_request: 48552 +author: +type: changed diff --git a/config/object_store_settings.rb b/config/object_store_settings.rb index 767fcd7579c..ec433c4dda6 100644 --- a/config/object_store_settings.rb +++ b/config/object_store_settings.rb @@ -121,6 +121,7 @@ class ObjectStoreSettings if section['enabled'] && target_config['bucket'].blank? missing_bucket_for(store_type) + next end # Map bucket (external name) -> remote_directory (internal representation) diff --git a/doc/api/invitations.md b/doc/api/invitations.md index 6fd2b26d80f..00dc4252380 100644 --- a/doc/api/invitations.md +++ b/doc/api/invitations.md @@ -97,7 +97,7 @@ Example response: { "id": 1, "invite_email": "member@example.org", - "invited_at": "2020-10-22T14:13:35Z", + "created_at": "2020-10-22T14:13:35Z", "access_level": 30, "expires_at": "2020-11-22T14:13:35Z", "user_name": "Raymond Smith", diff --git a/doc/install/installation.md b/doc/install/installation.md index 87e3cd1ea06..a6d00ad140e 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -224,12 +224,6 @@ make sudo make install ``` -Then install the Bundler gem (a version below 2.x): - -```shell -sudo gem install bundler --no-document --version '< 2' -``` - ## 3. Go In GitLab 8.0 and later, GitLab has several daemons written in Go. To install diff --git a/doc/install/requirements.md b/doc/install/requirements.md index 4a61831ff86..3f02544a5ab 100644 --- a/doc/install/requirements.md +++ b/doc/install/requirements.md @@ -45,7 +45,13 @@ Please consider using a virtual machine to run GitLab. ### Ruby versions -GitLab requires Ruby (MRI) 2.6. Beginning in GitLab 12.2, we no longer support Ruby 2.5 and lower. +From GitLab 13.6: + +- Ruby 2.7 and later is required. + +From GitLab 12.2: + +- Ruby 2.6 and later is required. You must use the standard MRI implementation of Ruby. We love [JRuby](https://www.jruby.org/) and [Rubinius](https://github.com/rubinius/rubinius#the-rubinius-language-platform), but GitLab diff --git a/doc/update/README.md b/doc/update/README.md index 774d468cb76..0534d793613 100644 --- a/doc/update/README.md +++ b/doc/update/README.md @@ -312,6 +312,8 @@ installation-specific upgrade instructions, based on how you installed GitLab: ### 13.6.0 +Ruby 2.7.2 is required. GitLab will not start with Ruby 2.6.6 or older versions. + The required Git version is Git v2.29 or higher. ### 13.3.0 diff --git a/doc/update/upgrading_from_source.md b/doc/update/upgrading_from_source.md index d2a3466984e..4eedc9bb89f 100644 --- a/doc/update/upgrading_from_source.md +++ b/doc/update/upgrading_from_source.md @@ -61,8 +61,8 @@ sudo service gitlab stop ### 3. Update Ruby -NOTE: Beginning in GitLab 12.2, we only support Ruby 2.6 or higher, and dropped -support for Ruby 2.5. Be sure to upgrade if necessary. +NOTE: Beginning in GitLab 13.6, we only support Ruby 2.7 or higher, and dropped +support for Ruby 2.6. Be sure to upgrade if necessary. You can check which version you are running with `ruby -v`. @@ -70,21 +70,15 @@ Download Ruby and compile it: ```shell mkdir /tmp/ruby && cd /tmp/ruby -curl --remote-name --progress https://cache.ruby-lang.org/pub/ruby/2.6/ruby-2.6.6.tar.gz -echo '2d78048e293817f38d4ede4ebc7873013e97bb0b ruby-2.6.6.tar.gz' | shasum -c - && tar xzf ruby-2.6.6.tar.gz -cd ruby-2.6.6 +curl --remote-name --progress https://cache.ruby-lang.org/pub/ruby/2.7/ruby-2.7.2.tar.gz +echo 'cb9731a17487e0ad84037490a6baf8bfa31a09e8 ruby-2.7.2.tar.gz' | shasum -c - && tar xzf ruby-2.7.2.tar.gz +cd ruby-2.7.2 ./configure --disable-install-rdoc make sudo make install ``` -Install Bundler: - -```shell -sudo gem install bundler --no-document --version '< 2' -``` - ### 4. Update Node.js NOTE: To check the minimum required Node.js version, see [Node.js versions](../install/requirements.md#nodejs-versions). diff --git a/doc/user/profile/index.md b/doc/user/profile/index.md index 8ae92a42581..37623c94eda 100644 --- a/doc/user/profile/index.md +++ b/doc/user/profile/index.md @@ -188,15 +188,12 @@ To set your current status: 1. Set the desired emoji and/or status message. 1. Click **Set status**. Alternatively, you can click **Remove status** to remove your user status entirely. -![Busy status indicator](img/busy_status_indicator_v13_6.png) - or 1. Click your avatar. 1. Select **Profile**. 1. Click **Edit profile** (pencil icon). 1. Enter your status message in the **Your status** text field. - 1. Alternatively, select the **Busy** checkbox ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/259649) in GitLab 13.6}. 1. Click **Add status emoji** (smiley face), and select the desired emoji. 1. Click **Update profile settings**. @@ -204,6 +201,44 @@ You can also set your current status [using the API](../../api/users.md#user-sta If you previously selected the "Busy" checkbox, remember to deselect it when you become available again. +## Busy status indicator + +> - Introduced in GitLab 13.6. +> - It's [deployed behind a feature flag](../feature_flags.md), disabled by default. +> - It's disabled on GitLab.com. +> - It's not recommended for production use. +> - To use it in GitLab self-managed instances, ask a GitLab administrator to [enable it](#enable-busy-status-feature). + +To indicate to others that you are busy, you can set an indicator + +![Busy status indicator](img/busy_status_indicator_v13_6.png) + +To set the busy status indicator, either: + +- Set it directly: + + 1. Click your avatar. + 1. Click **Set status**, or **Edit status** if you have already set a status. + 1. Select the **Busy** checkbox + +- Set it on your profile: + + 1. Click your avatar. + 1. Select **Profile**. + 1. Click **Edit profile** (**{pencil}**). + 1. Select the **Busy** checkbox + +### Enable busy status feature + +The busy status feature is deployed behind a feature flag and is **disabled by default**. +[GitLab administrators with access to the GitLab Rails console](../../administration/feature_flags.md) can enable it for your instance from the [rails console](../../administration/feature_flags.md#start-the-gitlab-rails-console). + +To enable it: + +```ruby +Feature.enable(:set_user_availability_status) +``` + ## Commit email > [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/21598) in GitLab 11.4. diff --git a/lib/api/entities/invitation.rb b/lib/api/entities/invitation.rb index 342f4804cf3..517b89529d7 100644 --- a/lib/api/entities/invitation.rb +++ b/lib/api/entities/invitation.rb @@ -4,7 +4,7 @@ module API module Entities class Invitation < Grape::Entity expose :access_level - expose :requested_at + expose :created_at expose :expires_at expose :invite_email expose :invite_token diff --git a/lib/gitlab/middleware/handle_malformed_strings.rb b/lib/gitlab/middleware/handle_malformed_strings.rb index 84f7e2e1b14..b966395ee32 100644 --- a/lib/gitlab/middleware/handle_malformed_strings.rb +++ b/lib/gitlab/middleware/handle_malformed_strings.rb @@ -93,7 +93,8 @@ module Gitlab # We try to encode the string from ASCII-8BIT to UTF8. If we failed to do # so for certain characters in the string, those chars are probably incomplete # multibyte characters. - string.encode(Encoding::UTF_8).match?(NULL_BYTE_REGEX) + string.dup.force_encoding(Encoding::UTF_8).match?(NULL_BYTE_REGEX) + rescue ArgumentError, Encoding::UndefinedConversionError # If we're here, we caught a malformed string. Return true true diff --git a/lib/system_check/app/ruby_version_check.rb b/lib/system_check/app/ruby_version_check.rb index 53da62df176..135413c528d 100644 --- a/lib/system_check/app/ruby_version_check.rb +++ b/lib/system_check/app/ruby_version_check.rb @@ -7,7 +7,7 @@ module SystemCheck set_check_pass -> { "yes (#{self.current_version})" } def self.required_version - @required_version ||= Gitlab::VersionInfo.new(2, 5, 3) + @required_version ||= Gitlab::VersionInfo.new(2, 7, 2) end def self.current_version diff --git a/spec/config/object_store_settings_spec.rb b/spec/config/object_store_settings_spec.rb index 430ba1205cb..1777213f481 100644 --- a/spec/config/object_store_settings_spec.rb +++ b/spec/config/object_store_settings_spec.rb @@ -88,6 +88,7 @@ RSpec.describe ObjectStoreSettings do config['object_store']['objects']['pages'].delete('bucket') expect { subject }.not_to raise_error + expect(settings.pages['object_store']).to eq(nil) end context 'with legacy config' do diff --git a/spec/frontend/registry/explorer/utils_spec.js b/spec/frontend/registry/explorer/utils_spec.js index 0cd4a1cec29..7a5d6958a09 100644 --- a/spec/frontend/registry/explorer/utils_spec.js +++ b/spec/frontend/registry/explorer/utils_spec.js @@ -8,6 +8,10 @@ describe('Utils', () => { id: 1, }; + beforeEach(() => { + window.gon.relative_url_root = null; + }); + it('returns the fetch url when no ending is passed', () => { expect(pathGenerator(imageDetails)).toBe('/foo/bar/registry/repository/1/tags?format=json'); }); @@ -16,7 +20,7 @@ describe('Utils', () => { expect(pathGenerator(imageDetails, '/foo')).toBe('/foo/bar/registry/repository/1/tags/foo'); }); - it.each` + describe.each` path | name | result ${'foo/foo'} | ${''} | ${'/foo/foo/registry/repository/1/tags?format=json'} ${'foo/foo/foo'} | ${'foo'} | ${'/foo/foo/registry/repository/1/tags?format=json'} @@ -26,8 +30,15 @@ describe('Utils', () => { ${'foo/foo/baz/foo/bar'} | ${'foo/bar'} | ${'/foo/foo/baz/registry/repository/1/tags?format=json'} ${'baz/foo/foo'} | ${'foo'} | ${'/baz/foo/registry/repository/1/tags?format=json'} ${'baz/foo/bar'} | ${'foo'} | ${'/baz/foo/bar/registry/repository/1/tags?format=json'} - `('returns the correct path when path is $path and name is $name', ({ name, path, result }) => { - expect(pathGenerator({ id: 1, name, path })).toBe(result); + `('when path is $path and name is $name', ({ name, path, result }) => { + it('returns the correct value', () => { + expect(pathGenerator({ id: 1, name, path })).toBe(result); + }); + + it('produces a correct relative url', () => { + window.gon.relative_url_root = '/gitlab'; + expect(pathGenerator({ id: 1, name, path })).toBe(`/gitlab${result}`); + }); }); it('returns the url unchanged when imageDetails have no name', () => { diff --git a/spec/frontend/vue_mr_widget/mr_widget_options_spec.js b/spec/frontend/vue_mr_widget/mr_widget_options_spec.js index d6f85dcfcc7..cb0006548d4 100644 --- a/spec/frontend/vue_mr_widget/mr_widget_options_spec.js +++ b/spec/frontend/vue_mr_widget/mr_widget_options_spec.js @@ -260,6 +260,20 @@ describe('mrWidgetOptions', () => { }); }); }); + + describe('formattedHumanAccess', () => { + it('when user is a tool admin but not a member of project', () => { + vm.mr.humanAccess = null; + + expect(vm.formattedHumanAccess).toEqual(''); + }); + + it('when user a member of the project', () => { + vm.mr.humanAccess = 'Owner'; + + expect(vm.formattedHumanAccess).toEqual('owner'); + }); + }); }); describe('methods', () => { diff --git a/spec/helpers/members_helper_spec.rb b/spec/helpers/members_helper_spec.rb index 84b3f99b89a..c671379c4b4 100644 --- a/spec/helpers/members_helper_spec.rb +++ b/spec/helpers/members_helper_spec.rb @@ -33,6 +33,16 @@ RSpec.describe MembersHelper do expect(remove_member_message(group_member_invite)).to eq "Are you sure you want to remove this orphaned member from the #{group.name} group and any subresources?" end end + + context 'a pending member invitation with no user associated' do + before do + project_member_invite.update_columns(invite_email: "#{SecureRandom.hex}@example.com", invite_token: 'some-token', user_id: nil) + end + + it 'does not error when there is an invitation for the requestor' do + expect(remove_member_message(project_member_invite)).to eq "Are you sure you want to revoke the invitation for #{project_member_invite.invite_email} to join the #{project.full_name} project?" + end + end end describe '#remove_member_title' do diff --git a/spec/lib/gitlab/middleware/handle_malformed_strings_spec.rb b/spec/lib/gitlab/middleware/handle_malformed_strings_spec.rb index e806f6478b7..cf7b0dbb5fd 100644 --- a/spec/lib/gitlab/middleware/handle_malformed_strings_spec.rb +++ b/spec/lib/gitlab/middleware/handle_malformed_strings_spec.rb @@ -1,5 +1,4 @@ # frozen_string_literal: true - require 'spec_helper' require "rack/test" @@ -104,6 +103,12 @@ RSpec.describe Gitlab::Middleware::HandleMalformedStrings do expect(subject.call(env)).not_to eq error_400 end + + it 'does not reject correct encoded password with special characters' do + env = env_for.merge(auth_env("username", "RçKszEwéC5kFnû∆f243fycGu§Gh9ftDj!U", nil)) + + expect(subject.call(env)).not_to eq error_400 + end end context 'in params' do diff --git a/spec/requests/api/invitations_spec.rb b/spec/requests/api/invitations_spec.rb index 75586970abb..aeb8e3642ed 100644 --- a/spec/requests/api/invitations_spec.rb +++ b/spec/requests/api/invitations_spec.rb @@ -58,7 +58,7 @@ RSpec.describe API::Invitations do it 'does not transform the requester into a proper member' do expect do post api("/#{source_type.pluralize}/#{source.id}/invitations", maintainer), - params: { email: email, access_level: Member::MAINTAINER } + params: { email: access_requester.email, access_level: Member::MAINTAINER } expect(response).to have_gitlab_http_status(:created) end.not_to change { source.members.count } @@ -71,7 +71,7 @@ RSpec.describe API::Invitations do params: { email: email, access_level: Member::DEVELOPER } expect(response).to have_gitlab_http_status(:created) - end.to change { source.requesters.count }.by(1) + end.to change { source.members.invite.count }.by(1) end it 'invites a list of new email addresses' do @@ -82,7 +82,7 @@ RSpec.describe API::Invitations do params: { email: email_list, access_level: Member::DEVELOPER } expect(response).to have_gitlab_http_status(:created) - end.to change { source.requesters.count }.by(2) + end.to change { source.members.invite.count }.by(2) end end @@ -140,7 +140,7 @@ RSpec.describe API::Invitations do it 'invites a member' do expect do subject - end.to change { source.requesters.count }.by(1) + end.to change { source.members.invite.count }.by(1) expect(response).to have_gitlab_http_status(:created) end diff --git a/spec/requests/git_http_spec.rb b/spec/requests/git_http_spec.rb index dc735e3714d..32aeeed43b6 100644 --- a/spec/requests/git_http_spec.rb +++ b/spec/requests/git_http_spec.rb @@ -280,6 +280,20 @@ RSpec.describe 'Git HTTP requests' do project.add_developer(user) end + context 'when user is using credentials with special characters' do + context 'with password with special characters' do + before do + user.update!(password: 'RKszEwéC5kFnû∆f243fycGu§Gh9ftDj!U') + end + + it 'allows clones' do + download(path, user: user.username, password: user.password) do |response| + expect(response).to have_gitlab_http_status(:ok) + end + end + end + end + context 'but the repo is disabled' do let(:project) { create(:project, :wiki_repo, :private, :repository_disabled, :wiki_enabled) } diff --git a/spec/services/members/invite_service_spec.rb b/spec/services/members/invite_service_spec.rb index 12a1a54696b..08cdf0d3ae1 100644 --- a/spec/services/members/invite_service_spec.rb +++ b/spec/services/members/invite_service_spec.rb @@ -63,4 +63,15 @@ RSpec.describe Members::InviteService do expect(result[:status]).to eq(:error) expect(result[:message][invited_member.invite_email]).to eq("Member already invited to #{project.name}") end + + it 'does not add a member with an access_request' do + requested_member = create(:project_member, :access_request, project: project) + + params = { email: requested_member.user.email, + access_level: Gitlab::Access::GUEST } + result = described_class.new(user, params).execute(project) + + expect(result[:status]).to eq(:error) + expect(result[:message][requested_member.user.email]).to eq("Member cannot be invited because they already requested to join #{project.name}") + end end |