diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-04-03 21:09:56 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-04-03 21:09:56 +0000 |
commit | c1a50b8195f4e36fda9b233acbde57a449bcf6c3 (patch) | |
tree | b24a10a7951e9a799397753d1badf6894fe03089 | |
parent | b6847c621ff246e6abceb90545d5a608318762d6 (diff) | |
download | gitlab-ce-c1a50b8195f4e36fda9b233acbde57a449bcf6c3.tar.gz |
Add latest changes from gitlab-org/gitlab@master
-rw-r--r-- | app/assets/javascripts/ide/components/repo_editor.vue | 7 | ||||
-rw-r--r-- | app/assets/javascripts/notes/components/sort_discussion.vue | 3 | ||||
-rw-r--r-- | app/controllers/projects/import/jira_controller.rb | 8 | ||||
-rw-r--r-- | app/models/user.rb | 8 | ||||
-rw-r--r-- | app/serializers/note_user_entity.rb | 2 | ||||
-rw-r--r-- | app/views/profiles/show.html.haml | 2 | ||||
-rw-r--r-- | app/views/projects/import/jira/show.html.haml | 2 | ||||
-rw-r--r-- | changelogs/unreleased/199081-remove-open-in-file-view-in-web-ide.yml | 5 | ||||
-rw-r--r-- | changelogs/unreleased/25426_subgroups_runners_in_api.yml | 6 | ||||
-rw-r--r-- | locale/gitlab.pot | 6 | ||||
-rw-r--r-- | spec/controllers/projects/import/jira_controller_spec.rb | 22 | ||||
-rw-r--r-- | spec/frontend/notes/components/sort_discussion_spec.js | 8 | ||||
-rw-r--r-- | spec/models/user_spec.rb | 265 | ||||
-rw-r--r-- | spec/requests/api/runners_spec.rb | 68 | ||||
-rw-r--r-- | spec/views/profiles/show.html.haml_spec.rb | 44 |
15 files changed, 373 insertions, 83 deletions
diff --git a/app/assets/javascripts/ide/components/repo_editor.vue b/app/assets/javascripts/ide/components/repo_editor.vue index c93a95e490a..08850679152 100644 --- a/app/assets/javascripts/ide/components/repo_editor.vue +++ b/app/assets/javascripts/ide/components/repo_editor.vue @@ -11,7 +11,6 @@ import { FILE_VIEW_MODE_PREVIEW, } from '../constants'; import Editor from '../lib/editor'; -import ExternalLink from './external_link.vue'; import FileTemplatesBar from './file_templates/bar.vue'; import { __ } from '~/locale'; @@ -19,7 +18,6 @@ export default { components: { ContentViewer, DiffViewer, - ExternalLink, FileTemplatesBar, }, props: { @@ -275,8 +273,8 @@ export default { <template> <div id="ide" class="blob-viewer-container blob-editor-container"> - <div class="ide-mode-tabs clearfix"> - <ul v-if="!shouldHideEditor && isEditModeActive" class="nav-links float-left border-bottom-0"> + <div v-if="!shouldHideEditor && isEditModeActive" class="ide-mode-tabs clearfix"> + <ul class="nav-links float-left border-bottom-0"> <li :class="editTabCSS"> <a href="javascript:void(0);" @@ -296,7 +294,6 @@ export default { > </li> </ul> - <external-link :file="file" /> </div> <file-templates-bar v-if="showFileTemplatesBar(file.name)" /> <div diff --git a/app/assets/javascripts/notes/components/sort_discussion.vue b/app/assets/javascripts/notes/components/sort_discussion.vue index 16eded52763..3f82ddde3ef 100644 --- a/app/assets/javascripts/notes/components/sort_discussion.vue +++ b/app/assets/javascripts/notes/components/sort_discussion.vue @@ -2,6 +2,7 @@ import { GlIcon } from '@gitlab/ui'; import { mapActions, mapGetters } from 'vuex'; import { __ } from '~/locale'; +import Tracking from '~/tracking'; import { ASC, DESC } from '../constants'; const SORT_OPTIONS = [ @@ -14,6 +15,7 @@ export default { components: { GlIcon, }, + mixins: [Tracking.mixin()], computed: { ...mapGetters(['sortDirection']), selectedOption() { @@ -31,6 +33,7 @@ export default { } this.setDiscussionSortDirection(direction); + this.track('change_discussion_sort_direction', { property: direction }); }, isDropdownItemActive(sortDir) { return sortDir === this.sortDirection; diff --git a/app/controllers/projects/import/jira_controller.rb b/app/controllers/projects/import/jira_controller.rb index e88d28e9db4..03ae17e18be 100644 --- a/app/controllers/projects/import/jira_controller.rb +++ b/app/controllers/projects/import/jira_controller.rb @@ -9,7 +9,13 @@ module Projects def show unless @project.import_state&.in_progress? jira_client = @project.jira_service.client - @jira_projects = jira_client.Project.all.map { |p| ["#{p.name} (#{p.key})", p.key] } + jira_projects = jira_client.Project.all + + if jira_projects.present? + @jira_projects = jira_projects.map { |p| ["#{p.name} (#{p.key})", p.key] } + else + flash[:alert] = 'No projects have been returned from Jira. Please check your Jira configuration.' + end end flash[:notice] = _("Import %{status}") % { status: @project.import_state.status } if @project.import_state.present? && !@project.import_state.none? diff --git a/app/models/user.rb b/app/models/user.rb index 343edfae799..62624f8eec1 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1405,7 +1405,7 @@ class User < ApplicationRecord .select('ci_runners.*') group_runners = Ci::RunnerNamespace - .where(namespace_id: owned_groups.select(:id)) + .where(namespace_id: Gitlab::ObjectHierarchy.new(owned_groups).base_and_descendants.select(:id)) .joins(:runner) .select('ci_runners.*') @@ -1696,7 +1696,7 @@ class User < ApplicationRecord def gitlab_employee? strong_memoize(:gitlab_employee) do - if Gitlab.com? + if Feature.enabled?(:gitlab_employee_badge) && Gitlab.com? Mail::Address.new(email).domain == "gitlab.com" && confirmed? else false @@ -1713,6 +1713,10 @@ class User < ApplicationRecord !confirmed? && !confirmation_period_valid? end + def organization + gitlab_employee? ? 'GitLab' : super + end + protected # override, from Devise::Validatable diff --git a/app/serializers/note_user_entity.rb b/app/serializers/note_user_entity.rb index ffaf7664dae..8d30bbff5e4 100644 --- a/app/serializers/note_user_entity.rb +++ b/app/serializers/note_user_entity.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class NoteUserEntity < UserEntity - expose :gitlab_employee?, as: :is_gitlab_employee, if: ->(user, options) { ::Feature.enabled?(:gitlab_employee_badge) && user.gitlab_employee? } + expose :gitlab_employee?, as: :is_gitlab_employee, if: ->(user, options) { user.gitlab_employee? } unexpose :web_url end diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml index 86e157ee042..da2b8c40191 100644 --- a/app/views/profiles/show.html.haml +++ b/app/views/profiles/show.html.haml @@ -101,7 +101,7 @@ - else = f.text_field :location, label: s_('Profiles|Location'), class: 'input-lg', placeholder: s_("Profiles|City, country") = f.text_field :job_title, class: 'input-md' - = f.text_field :organization, label: s_('Profiles|Organization'), class: 'input-md', help: s_("Profiles|Who you represent or work for") + = f.text_field :organization, readonly: @user.gitlab_employee?, label: s_('Profiles|Organization'), class: 'input-md', help: s_("Profiles|Who you represent or work for") = f.text_area :bio, label: s_('Profiles|Bio'), rows: 4, maxlength: 250, help: s_("Profiles|Tell us about yourself in fewer than 250 characters") %hr %h5= s_("Private profile") diff --git a/app/views/projects/import/jira/show.html.haml b/app/views/projects/import/jira/show.html.haml index f295a241113..c734297d7f3 100644 --- a/app/views/projects/import/jira/show.html.haml +++ b/app/views/projects/import/jira/show.html.haml @@ -9,7 +9,7 @@ %h3.page-title.d-flex.align-items-center = sprite_icon('issues', size: 16, css_class: 'mr-1') = _('Import in progress') -- else +- elsif @jira_projects.present? %h3.page-title.d-flex.align-items-center = sprite_icon('issues', size: 16, css_class: 'mr-1') = _('Import issues from Jira') diff --git a/changelogs/unreleased/199081-remove-open-in-file-view-in-web-ide.yml b/changelogs/unreleased/199081-remove-open-in-file-view-in-web-ide.yml new file mode 100644 index 00000000000..610833e69ba --- /dev/null +++ b/changelogs/unreleased/199081-remove-open-in-file-view-in-web-ide.yml @@ -0,0 +1,5 @@ +--- +title: Remove open in file view link from Web IDE +merge_request: 28705 +author: +type: removed diff --git a/changelogs/unreleased/25426_subgroups_runners_in_api.yml b/changelogs/unreleased/25426_subgroups_runners_in_api.yml new file mode 100644 index 00000000000..cd04c739678 --- /dev/null +++ b/changelogs/unreleased/25426_subgroups_runners_in_api.yml @@ -0,0 +1,6 @@ +--- +title: 'Fix for issue 26426: Details of runners of nested groups of an owned group + are now available for users with enough permissions' +merge_request: 24169 +author: nachootal@gmail.com +type: changed diff --git a/locale/gitlab.pot b/locale/gitlab.pot index a56d4cc2e6e..c385e1e1a91 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -6567,6 +6567,9 @@ msgstr "" msgid "Dependencies|All" msgstr "" +msgid "Dependencies|Based on the %{linkStart}latest successful%{linkEnd} scan" +msgstr "" + msgid "Dependencies|Component" msgstr "" @@ -7124,9 +7127,6 @@ msgstr "" msgid "Display source" msgstr "" -msgid "Displays dependencies and known vulnerabilities, based on the %{linkStart}latest successful%{linkEnd} scan" -msgstr "" - msgid "Do not display offers from third parties within GitLab" msgstr "" diff --git a/spec/controllers/projects/import/jira_controller_spec.rb b/spec/controllers/projects/import/jira_controller_spec.rb index 3a29c3d4093..33b51320391 100644 --- a/spec/controllers/projects/import/jira_controller_spec.rb +++ b/spec/controllers/projects/import/jira_controller_spec.rb @@ -66,13 +66,29 @@ describe Projects::Import::JiraController do context 'when running jira import first time' do context 'get show' do - it 'renders show template' do - allow(JIRA::Resource::Project).to receive(:all).and_return([]) + before do + allow(JIRA::Resource::Project).to receive(:all).and_return(jira_projects) + expect(project.import_state).to be_nil get :show, params: { namespace_id: project.namespace.to_param, project_id: project } + end + + context 'when no projects have been retrieved from Jira' do + let(:jira_projects) { [] } + + it 'render an error message' do + expect(flash[:alert]).to eq('No projects have been returned from Jira. Please check your Jira configuration.') + expect(response).to render_template(:show) + end + end + + context 'when everything is ok' do + let(:jira_projects) { [double(name: 'FOO project', key: 'FOO')] } - expect(response).to render_template :show + it 'renders show template' do + expect(response).to render_template(:show) + end end end diff --git a/spec/frontend/notes/components/sort_discussion_spec.js b/spec/frontend/notes/components/sort_discussion_spec.js index 785e8c75233..724c77eee3d 100644 --- a/spec/frontend/notes/components/sort_discussion_spec.js +++ b/spec/frontend/notes/components/sort_discussion_spec.js @@ -3,6 +3,7 @@ import Vuex from 'vuex'; import SortDiscussion from '~/notes/components/sort_discussion.vue'; import createStore from '~/notes/stores'; import { ASC, DESC } from '~/notes/constants'; +import Tracking from '~/tracking'; const localVue = createLocalVue(); localVue.use(Vuex); @@ -22,6 +23,7 @@ describe('Sort Discussion component', () => { beforeEach(() => { store = createStore(); + jest.spyOn(Tracking, 'event'); }); afterEach(() => { @@ -37,6 +39,9 @@ describe('Sort Discussion component', () => { wrapper.find('.js-newest-first').trigger('click'); expect(store.dispatch).toHaveBeenCalledWith('setDiscussionSortDirection', DESC); + expect(Tracking.event).toHaveBeenCalledWith(undefined, 'change_discussion_sort_direction', { + property: DESC, + }); }); }); @@ -58,6 +63,9 @@ describe('Sort Discussion component', () => { wrapper.find('.js-oldest-first').trigger('click'); expect(store.dispatch).toHaveBeenCalledWith('setDiscussionSortDirection', ASC); + expect(Tracking.event).toHaveBeenCalledWith(undefined, 'change_discussion_sort_direction', { + property: ASC, + }); }); it('applies the active class to the correct button in the dropdown', () => { diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 12f83e6d8c6..e69d4e18c1e 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -2835,61 +2835,88 @@ describe User, :do_not_mock_admin_mode do describe '#ci_owned_runners' do let(:user) { create(:user) } - let!(:project) { create(:project) } - let(:runner) { create(:ci_runner, :project, projects: [project]) } - context 'without any projects nor groups' do - it 'does not load' do - expect(user.ci_owned_runners).to be_empty + shared_examples :nested_groups_owner do + context 'when the user is the owner of a multi-level group' do + before do + set_permissions_for_users + end + + it 'loads all the runners in the tree of groups' do + expect(user.ci_owned_runners).to contain_exactly(runner, group_runner) + end end end - context 'with personal projects runners' do - let(:namespace) { create(:namespace, owner: user) } - let!(:project) { create(:project, namespace: namespace) } + shared_examples :group_owner do + context 'when the user is the owner of a one level group' do + before do + group.add_owner(user) + end - it 'loads' do - expect(user.ci_owned_runners).to contain_exactly(runner) + it 'loads the runners in the group' do + expect(user.ci_owned_runners).to contain_exactly(group_runner) + end end end - context 'with personal group runner' do - let!(:project) { create(:project) } - let(:group_runner) { create(:ci_runner, :group, groups: [group]) } - let!(:group) do - create(:group).tap do |group| - group.add_owner(user) + shared_examples :project_owner do + context 'when the user is the owner of a project' do + it 'loads the runner belonging to the project' do + expect(user.ci_owned_runners).to contain_exactly(runner) + end + end + end + + shared_examples :project_member do + context 'when the user is a maintainer' do + before do + add_user(:maintainer) + end + + it 'loads the runners of the project' do + expect(user.ci_owned_runners).to contain_exactly(project_runner) end end - it 'loads' do - expect(user.ci_owned_runners).to contain_exactly(group_runner) + context 'when the user is a developer' do + before do + add_user(:developer) + end + + it 'does not load any runner' do + expect(user.ci_owned_runners).to be_empty + end end - end - context 'with personal project and group runner' do - let(:namespace) { create(:namespace, owner: user) } - let!(:project) { create(:project, namespace: namespace) } - let!(:group_runner) { create(:ci_runner, :group, groups: [group]) } + context 'when the user is a reporter' do + before do + add_user(:reporter) + end - let!(:group) do - create(:group).tap do |group| - group.add_owner(user) + it 'does not load any runner' do + expect(user.ci_owned_runners).to be_empty end end - it 'loads' do - expect(user.ci_owned_runners).to contain_exactly(runner, group_runner) + context 'when the user is a guest' do + before do + add_user(:guest) + end + + it 'does not load any runner' do + expect(user.ci_owned_runners).to be_empty + end end end - shared_examples :member do + shared_examples :group_member do context 'when the user is a maintainer' do before do add_user(:maintainer) end - it 'does not load' do + it 'does not load the runners of the group' do expect(user.ci_owned_runners).to be_empty end end @@ -2899,29 +2926,49 @@ describe User, :do_not_mock_admin_mode do add_user(:developer) end - it 'does not load' do + it 'does not load any runner' do expect(user.ci_owned_runners).to be_empty end end - end - shared_examples :group_member do - context 'when the user is owner' do + context 'when the user is a reporter' do before do - add_user(:owner) + add_user(:reporter) end - it 'loads' do - expect(user.ci_owned_runners).to contain_exactly(runner) + it 'does not load any runner' do + expect(user.ci_owned_runners).to be_empty end end - it_behaves_like :member + context 'when the user is a guest' do + before do + add_user(:guest) + end + + it 'does not load any runner' do + expect(user.ci_owned_runners).to be_empty + end + end end - context 'with groups projects runners' do - let(:group) { create(:group) } - let!(:project) { create(:project, group: group) } + context 'without any projects nor groups' do + it 'does not load any runner' do + expect(user.ci_owned_runners).to be_empty + end + end + + context 'with runner in a personal project' do + let!(:namespace) { create(:namespace, owner: user) } + let!(:project) { create(:project, namespace: namespace) } + let!(:runner) { create(:ci_runner, :project, projects: [project]) } + + it_behaves_like :project_owner + end + + context 'with group runner in a non owned group' do + let!(:group) { create(:group) } + let!(:runner) { create(:ci_runner, :group, groups: [group]) } def add_user(access) group.add_user(user, access) @@ -2930,37 +2977,114 @@ describe User, :do_not_mock_admin_mode do it_behaves_like :group_member end - context 'with groups runners' do + context 'with group runner in an owned group' do + let!(:group) { create(:group) } + let!(:group_runner) { create(:ci_runner, :group, groups: [group]) } + + it_behaves_like :group_owner + end + + context 'with group runner in an owned group and group runner in a different owner subgroup' do + let!(:group) { create(:group) } let!(:runner) { create(:ci_runner, :group, groups: [group]) } + let!(:subgroup) { create(:group, parent: group) } + let!(:group_runner) { create(:ci_runner, :group, groups: [subgroup]) } + let!(:another_user) { create(:user) } + + def set_permissions_for_users + group.add_owner(user) + subgroup.add_owner(another_user) + end + + it_behaves_like :nested_groups_owner + end + + context 'with personal project runner in an an owned group and a group runner in that same group' do let!(:group) { create(:group) } + let!(:group_runner) { create(:ci_runner, :group, groups: [group]) } + let!(:project) { create(:project, group: group) } + let!(:runner) { create(:ci_runner, :project, projects: [project]) } - def add_user(access) - group.add_user(user, access) + def set_permissions_for_users + group.add_owner(user) end - it_behaves_like :group_member + it_behaves_like :nested_groups_owner end - context 'with other projects runners' do - let!(:project) { create(:project) } + context 'with personal project runner in an owned group and a group runner in a subgroup' do + let!(:group) { create(:group) } + let!(:subgroup) { create(:group, parent: group) } + let!(:group_runner) { create(:ci_runner, :group, groups: [subgroup]) } + let!(:project) { create(:project, group: group) } + let!(:runner) { create(:ci_runner, :project, projects: [project]) } + + def set_permissions_for_users + group.add_owner(user) + end + + it_behaves_like :nested_groups_owner + end + + context 'with personal project runner in an owned group in an owned namespace and a group runner in that group' do + let!(:namespace) { create(:namespace, owner: user) } + let!(:group) { create(:group) } + let!(:group_runner) { create(:ci_runner, :group, groups: [group]) } + let!(:project) { create(:project, namespace: namespace, group: group) } + let!(:runner) { create(:ci_runner, :project, projects: [project]) } + + def set_permissions_for_users + group.add_owner(user) + end + + it_behaves_like :nested_groups_owner + end + + context 'with personal project runner in an owned namespace, an owned group, a subgroup and a group runner in that subgroup' do + let!(:namespace) { create(:namespace, owner: user) } + let!(:group) { create(:group) } + let!(:subgroup) { create(:group, parent: group) } + let!(:group_runner) { create(:ci_runner, :group, groups: [subgroup]) } + let!(:project) { create(:project, namespace: namespace, group: group) } + let!(:runner) { create(:ci_runner, :project, projects: [project]) } + + def set_permissions_for_users + group.add_owner(user) + end + + it_behaves_like :nested_groups_owner + end + + context 'with a project runner that belong to projects that belong to a not owned group' do + let!(:group) { create(:group) } + let!(:project) { create(:project, group: group) } + let!(:project_runner) { create(:ci_runner, :project, projects: [project]) } def add_user(access) project.add_user(user, access) end - it_behaves_like :member + it_behaves_like :project_member end - context 'with subgroup with different owner for project runner' do - let(:group) { create(:group) } - let(:another_user) { create(:user) } - let(:subgroup) { create(:group, parent: group) } - let!(:project) { create(:project, group: subgroup) } + context 'with project runners that belong to projects that do not belong to any group' do + let!(:project) { create(:project) } + let!(:runner) { create(:ci_runner, :project, projects: [project]) } + + it 'does not load any runner' do + expect(user.ci_owned_runners).to be_empty + end + end + + context 'with a group runner that belongs to a subgroup of a group owned by another user' do + let!(:group) { create(:group) } + let!(:subgroup) { create(:group, parent: group) } + let!(:runner) { create(:ci_runner, :group, groups: [subgroup]) } + let!(:another_user) { create(:user) } def add_user(access) - group.add_user(user, access) + subgroup.add_user(user, access) group.add_user(another_user, :owner) - subgroup.add_user(another_user, :owner) end it_behaves_like :group_member @@ -4406,6 +4530,16 @@ describe User, :do_not_mock_admin_mode do it { is_expected.to be false } end + + context 'when `:gitlab_employee_badge` feature flag is disabled' do + let(:user) { build(:user, email: 'test@gitlab.com') } + + before do + stub_feature_flags(gitlab_employee_badge: false) + end + + it { is_expected.to be false } + end end describe '#current_highest_access_level' do @@ -4428,6 +4562,27 @@ describe User, :do_not_mock_admin_mode do end end + describe '#organization' do + using RSpec::Parameterized::TableSyntax + + let(:user) { build(:user, organization: 'ACME') } + + subject { user.organization } + + where(:gitlab_employee?, :expected_result) do + true | 'GitLab' + false | 'ACME' + end + + with_them do + before do + allow(user).to receive(:gitlab_employee?).and_return(gitlab_employee?) + end + + it { is_expected.to eql(expected_result) } + end + end + context 'when after_commit :update_highest_role' do describe 'create user' do it 'initializes a new Members::UpdateHighestRoleService object' do diff --git a/spec/requests/api/runners_spec.rb b/spec/requests/api/runners_spec.rb index f6b257e6288..164be8f0da6 100644 --- a/spec/requests/api/runners_spec.rb +++ b/spec/requests/api/runners_spec.rb @@ -6,20 +6,28 @@ describe API::Runners do let(:admin) { create(:user, :admin) } let(:user) { create(:user) } let(:user2) { create(:user) } + let(:group_guest) { create(:user) } + let(:group_reporter) { create(:user) } + let(:group_developer) { create(:user) } let(:group_maintainer) { create(:user) } let(:project) { create(:project, creator_id: user.id) } let(:project2) { create(:project, creator_id: user.id) } let(:group) { create(:group).tap { |group| group.add_owner(user) } } + let(:subgroup) { create(:group, parent: group) } let!(:shared_runner) { create(:ci_runner, :instance, description: 'Shared runner') } let!(:project_runner) { create(:ci_runner, :project, description: 'Project runner', projects: [project]) } let!(:two_projects_runner) { create(:ci_runner, :project, description: 'Two projects runner', projects: [project, project2]) } - let!(:group_runner) { create(:ci_runner, :group, description: 'Group runner', groups: [group]) } + let!(:group_runner_a) { create(:ci_runner, :group, description: 'Group runner A', groups: [group]) } + let!(:group_runner_b) { create(:ci_runner, :group, description: 'Group runner B', groups: [subgroup]) } before do # Set project access for users + create(:group_member, :guest, user: group_guest, group: group) + create(:group_member, :reporter, user: group_reporter, group: group) + create(:group_member, :developer, user: group_developer, group: group) create(:group_member, :maintainer, user: group_maintainer, group: group) create(:project_member, :maintainer, user: user, project: project) create(:project_member, :maintainer, user: user, project: project2) @@ -41,7 +49,8 @@ describe API::Runners do expect(json_response).to match_array [ a_hash_including('description' => 'Project runner'), a_hash_including('description' => 'Two projects runner'), - a_hash_including('description' => 'Group runner') + a_hash_including('description' => 'Group runner A'), + a_hash_including('description' => 'Group runner B') ] end @@ -131,7 +140,8 @@ describe API::Runners do expect(json_response).to match_array [ a_hash_including('description' => 'Project runner'), a_hash_including('description' => 'Two projects runner'), - a_hash_including('description' => 'Group runner'), + a_hash_including('description' => 'Group runner A'), + a_hash_including('description' => 'Group runner B'), a_hash_including('description' => 'Shared runner') ] end @@ -156,7 +166,8 @@ describe API::Runners do expect(json_response).to match_array [ a_hash_including('description' => 'Project runner'), a_hash_including('description' => 'Two projects runner'), - a_hash_including('description' => 'Group runner') + a_hash_including('description' => 'Group runner A'), + a_hash_including('description' => 'Group runner B') ] end @@ -165,7 +176,7 @@ describe API::Runners do expect(response).to have_gitlab_http_status(:bad_request) end - it 'filters runners by type' do + it 'filters runners by project type' do get api('/runners/all?type=project_type', admin) expect(json_response).to match_array [ @@ -174,6 +185,15 @@ describe API::Runners do ] end + it 'filters runners by group type' do + get api('/runners/all?type=group_type', admin) + + expect(json_response).to match_array [ + a_hash_including('description' => 'Group runner A'), + a_hash_including('description' => 'Group runner B') + ] + end + it 'does not filter by invalid type' do get api('/runners/all?type=bogus', admin) @@ -526,15 +546,41 @@ describe API::Runners do end.to change { Ci::Runner.project_type.count }.by(-1) end + it 'does not delete group runner with guest access' do + delete api("/runners/#{group_runner_a.id}", group_guest) + + expect(response).to have_gitlab_http_status(:forbidden) + end + + it 'does not delete group runner with reporter access' do + delete api("/runners/#{group_runner_a.id}", group_reporter) + + expect(response).to have_gitlab_http_status(:forbidden) + end + + it 'does not delete group runner with developer access' do + delete api("/runners/#{group_runner_a.id}", group_developer) + + expect(response).to have_gitlab_http_status(:forbidden) + end + it 'does not delete group runner with maintainer access' do - delete api("/runners/#{group_runner.id}", group_maintainer) + delete api("/runners/#{group_runner_a.id}", group_maintainer) expect(response).to have_gitlab_http_status(:forbidden) end - it 'deletes group runner with owner access' do + it 'deletes owned group runner with owner access' do + expect do + delete api("/runners/#{group_runner_a.id}", user) + + expect(response).to have_gitlab_http_status(:no_content) + end.to change { Ci::Runner.group_type.count }.by(-1) + end + + it 'deletes inherited group runner with owner access' do expect do - delete api("/runners/#{group_runner.id}", user) + delete api("/runners/#{group_runner_b.id}", user) expect(response).to have_gitlab_http_status(:no_content) end.to change { Ci::Runner.group_type.count }.by(-1) @@ -842,7 +888,7 @@ describe API::Runners do get api("/groups/#{group.id}/runners", user) expect(json_response).to match_array([ - a_hash_including('description' => 'Group runner') + a_hash_including('description' => 'Group runner A') ]) end @@ -851,7 +897,7 @@ describe API::Runners do get api("/groups/#{group.id}/runners?type=group_type", user) expect(json_response).to match_array([ - a_hash_including('description' => 'Group runner') + a_hash_including('description' => 'Group runner A') ]) end @@ -939,7 +985,7 @@ describe API::Runners do end it 'does not enable group runner' do - post api("/projects/#{project.id}/runners", user), params: { runner_id: group_runner.id } + post api("/projects/#{project.id}/runners", user), params: { runner_id: group_runner_a.id } expect(response).to have_gitlab_http_status(:forbidden) end diff --git a/spec/views/profiles/show.html.haml_spec.rb b/spec/views/profiles/show.html.haml_spec.rb index 14e6feed3ab..e1c21f87780 100644 --- a/spec/views/profiles/show.html.haml_spec.rb +++ b/spec/views/profiles/show.html.haml_spec.rb @@ -19,4 +19,48 @@ describe 'profiles/show' do expect(rendered).to have_field('user_id', with: user.id) end end + + context 'gitlab.com organization field' do + before do + allow(Gitlab).to receive(:com?).and_return(true) + end + + context 'when `:gitlab_employee_badge` feature flag is enabled' do + context 'and when user has an `@gitlab.com` email address' do + let(:user) { create(:user, email: 'test@gitlab.com') } + + it 'displays the organization field as `readonly` with a `value` of `GitLab`' do + render + + expect(rendered).to have_selector('#user_organization[readonly][value="GitLab"]') + end + end + + context 'and when a user does not have an `@gitlab.com` email' do + let(:user) { create(:user, email: 'test@example.com') } + + it 'displays an editable organization field' do + render + + expect(rendered).to have_selector('#user_organization:not([readonly]):not([value="GitLab"])') + end + end + end + + context 'when `:gitlab_employee_badge` feature flag is disabled' do + before do + stub_feature_flags(gitlab_employee_badge: false) + end + + context 'and when a user has an `@gitlab.com` email' do + let(:user) { create(:user, email: 'test@gitlab.com') } + + it 'displays an editable organization field' do + render + + expect(rendered).to have_selector('#user_organization:not([readonly]):not([value="GitLab"])') + end + end + end + end end |