diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-08-11 09:10:03 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-08-11 09:10:03 +0300 |
commit | 281f1b6ba36531122463afd6869ca5dcdd0b0e35 (patch) | |
tree | 1f4c771d0b58b7fdd88643b4690b847e1e968c08 | |
parent | bdca0979165cb662173d959c358fce0c539c7544 (diff) |
Add latest changes from gitlab-org/gitlab@master
35 files changed, 393 insertions, 142 deletions
diff --git a/app/assets/stylesheets/pages/users.scss b/app/assets/stylesheets/pages/users.scss index 3b018c1e087..0863b573f75 100644 --- a/app/assets/stylesheets/pages/users.scss +++ b/app/assets/stylesheets/pages/users.scss @@ -25,8 +25,12 @@ } .form-control { - width: 100%; padding-right: 35px; + } + + .search-control-wrap, + .form-control { + width: 100%; @include media-breakpoint-up(sm) { width: 250px; diff --git a/app/views/groups/group_members/index.html.haml b/app/views/groups/group_members/index.html.haml index b9ea8316bbc..c8e58a50b18 100644 --- a/app/views/groups/group_members/index.html.haml +++ b/app/views/groups/group_members/index.html.haml @@ -1,84 +1,99 @@ -- page_title _("Group members") +- page_title _('Group members') - can_manage_members = can?(current_user, :admin_group_member, @group) - show_invited_members = can_manage_members && @invited_members.exists? -- pending_active = params[:search_invited].present? -- total_count = @members.count + @group.shared_with_group_links.count +- show_access_requests = can_manage_members && @requesters.exists? +- invited_active = params[:search_invited].present? || params[:invited_members_page].present? + +- form_item_label_css_class = 'label-bold gl-mr-2 gl-mb-0 gl-py-2 align-self-md-center' .js-remove-member-modal .project-members-page.gl-mt-3 %h4 - = _("Group members") + = _('Group members') %hr - if can_manage_members %ul.nav-links.nav.nav-tabs.gitlab-tabs{ role: 'tablist' } %li.nav-tab{ role: 'presentation' } - %a.nav-link.active{ href: '#invite-member-pane', id: 'invite-member-tab', data: { toggle: 'tab' }, role: 'tab' }= _("Invite member") + %a.nav-link.active{ href: '#invite-member-pane', id: 'invite-member-tab', data: { toggle: 'tab' }, role: 'tab' }= _('Invite member') %li.nav-tab{ role: 'presentation' } - %a.nav-link{ href: '#invite-group-pane', id: 'invite-group-tab', data: { toggle: 'tab', qa_selector: 'invite_group_tab' }, role: 'tab' }= _("Invite group") + %a.nav-link{ href: '#invite-group-pane', id: 'invite-group-tab', data: { toggle: 'tab', qa_selector: 'invite_group_tab' }, role: 'tab' }= _('Invite group') .tab-content.gitlab-tab-content .tab-pane.active{ id: 'invite-member-pane', role: 'tabpanel' } = render_invite_member_for_group(@group, @group_member.access_level) .tab-pane{ id: 'invite-group-pane', role: 'tabpanel' } = render 'shared/members/invite_group', submit_url: group_group_links_path(@group), access_levels: GroupMember.access_level_roles, default_access_level: @group_member.access_level, group_link_field: 'shared_with_group_id', group_access_field: 'shared_group_access' - = render 'shared/members/requests', membership_source: @group, requesters: @requesters - = render_if_exists 'groups/group_members/ldap_sync' - %ul.nav-links.mobile-separator.nav.nav-tabs.clearfix + %ul.nav-links.mobile-separator.nav.nav-tabs %li.nav-item - = link_to "#existing_shares", class: ["nav-link", ("active" unless pending_active)] , 'data-toggle' => 'tab' do + = link_to '#tab-members', class: ['nav-link', ('active' unless invited_active)], data: { toggle: 'tab' } do %span - = _("Existing shares") - %span.badge.badge-pill= total_count + = _('Members') + %span.badge.badge-pill= @members.total_count + - if @group.shared_with_group_links.any? + %li.nav-item + = link_to '#tab-groups', class: ['nav-link'] , data: { toggle: 'tab', qa_selector: 'groups_list_tab' } do + %span + = _('Groups') + %span.badge.badge-pill= @group.shared_with_group_links.count - if show_invited_members %li.nav-item - = link_to "#invited_members", class: ["nav-link", ("active" if pending_active)], 'data-toggle' => 'tab' do + = link_to '#tab-invited-members', class: ['nav-link', ('active' if invited_active)], data: { toggle: 'tab' } do %span - = _("Pending") + = _('Invited') %span.badge.badge-pill= @invited_members.total_count - + - if show_access_requests + %li.nav-item + = link_to '#tab-access-requests', class: 'nav-link', data: { toggle: 'tab' } do + %span + = _('Access requests') + %span.badge.badge-pill= @requesters.count .tab-content - #existing_shares.tab-pane{ :class => ("active" unless pending_active) } - - if @group.shared_with_group_links.any? - .card.card-without-border - .d-flex.flex-column.flex-md-row.row-content-block.second-block - %span.flex-grow-1.align-self-md-center.col-form-label - = _("Groups with access to %{strong_start}%{group_name}%{strong_end}").html_safe % { group_name: @group.name, strong_start: '<strong>'.html_safe, strong_end: '</strong>'.html_safe } - %ul.content-list.members-list{ data: { qa_selector: "groups_list" } } - - can_admin_member = can?(current_user, :admin_group_member, @group) - - @group.shared_with_group_links.each do |group_link| - = render 'shared/members/group', group_link: group_link, can_admin_member: can_admin_member, group_link_path: group_group_link_path(@group, group_link) + #tab-members.tab-pane{ class: ('active' unless invited_active) } .card.card-without-border - .d-flex.flex-column.flex-md-row.row-content-block.second-block - %span.flex-grow-1.align-self-md-center.col-form-label - = _("Members with access to %{strong_start}%{group_name}%{strong_end}").html_safe % { group_name: @group.name, strong_start: '<strong>'.html_safe, strong_end: '</strong>'.html_safe } - = form_tag group_group_members_path(@group), method: :get, class: 'form-inline user-search-form' do - .form-group.flex-grow - .position-relative.mr-md-2 - = search_field_tag :search, params[:search], { placeholder: _('Search'), class: 'form-control', spellcheck: false } - %button.user-search-btn.border-left{ type: "submit", "aria-label" => _("Submit search") } - = icon("search") - - if can_manage_members - = label_tag '2fa', '2FA', class: 'col-form-label label-bold pr-md-2' + = render 'groups/group_members/tab_pane/header' do + = render 'groups/group_members/tab_pane/title' do + = html_escape(_('Members with access to %{strong_start}%{group_name}%{strong_end}')) % { group_name: @group.name, strong_start: '<strong>'.html_safe, strong_end: '</strong>'.html_safe } + = form_tag group_group_members_path(@group), method: :get, class: 'user-search-form gl-display-flex gl-md-align-items-center gl-flex-wrap gl-flex-direction-column gl-md-flex-direction-row gl-mx-n3 gl-my-n3', data: { testid: 'user-search-form' } do + .gl-px-3.gl-py-2 + .search-control-wrap.gl-relative + = render 'shared/members/search_field' + - if can_manage_members + = render 'groups/group_members/tab_pane/form_item' do + = label_tag '2fa', _('2FA'), class: form_item_label_css_class = render 'shared/members/filter_2fa_dropdown' + = render 'groups/group_members/tab_pane/form_item' do + = label_tag :sort_by, _('Sort by'), class: form_item_label_css_class = render 'shared/members/sort_dropdown' - %ul.content-list.members-list{ data: { qa_selector: "members_list" } } + %ul.content-list.members-list{ data: { qa_selector: 'members_list' } } = render partial: 'shared/members/member', collection: @members, as: :member - = paginate @members, theme: 'gitlab' - + = paginate @members, theme: 'gitlab', params: { invited_members_page: nil, search_invited: nil } + - if @group.shared_with_group_links.any? + #tab-groups.tab-pane + .card.card-without-border + = render 'groups/group_members/tab_pane/header' do + = render 'groups/group_members/tab_pane/title' do + = html_escape(_('Groups with access to %{strong_start}%{group_name}%{strong_end}')) % { group_name: @group.name, strong_start: '<strong>'.html_safe, strong_end: '</strong>'.html_safe } + %ul.content-list.members-list{ data: { qa_selector: 'groups_list' } } + - @group.shared_with_group_links.each do |group_link| + = render 'shared/members/group', group_link: group_link, can_admin_member: can_manage_members, group_link_path: group_group_link_path(@group, group_link) - if show_invited_members - #invited_members.tab-pane{ :class => ("active" if pending_active) } + #tab-invited-members.tab-pane{ class: ('active' if invited_active) } .card.card-without-border - .d-flex.flex-column.flex-md-row.row-content-block.second-block - %span.flex-grow-1 - = _("Members with pending access to %{strong_start}%{group_name}%{strong_end}").html_safe % { group_name: @group.name, strong_start: '<strong>'.html_safe, strong_end: '</strong>'.html_safe } - = form_tag group_group_members_path(@group), method: :get, class: 'form-inline user-search-form' do - .form-group - .position-relative.mr-md-2 - = search_field_tag :search_invited, params[:search_invited], { placeholder: _('Search'), class: 'form-control', spellcheck: false } - %button.user-search-btn.border-left{ type: "submit", "aria-label" => _("Submit search") } - = icon("search") + = render 'groups/group_members/tab_pane/header' do + = render 'groups/group_members/tab_pane/title' do + = html_escape(_('Members invited to %{strong_start}%{group_name}%{strong_end}')) % { group_name: @group.name, strong_start: '<strong>'.html_safe, strong_end: '</strong>'.html_safe } + = form_tag group_group_members_path(@group), method: :get, class: 'user-search-form', data: { testid: 'user-search-form' } do + = render 'shared/members/search_field', name: 'search_invited' %ul.content-list.members-list = render partial: 'shared/members/member', collection: @invited_members, as: :member - = paginate @invited_members, param_name: 'invited_members_page', theme: 'gitlab' + = paginate @invited_members, param_name: 'invited_members_page', theme: 'gitlab', params: { page: nil } + - if show_access_requests + #tab-access-requests.tab-pane + .card.card-without-border + = render 'groups/group_members/tab_pane/header' do + = render 'groups/group_members/tab_pane/title' do + = html_escape(_('Users requesting access to %{strong_start}%{group_name}%{strong_end}')) % { group_name: @group.name, strong_start: '<strong>'.html_safe, strong_end: '</strong>'.html_safe } + %ul.content-list.members-list + = render partial: 'shared/members/member', collection: @requesters, as: :member diff --git a/app/views/groups/group_members/tab_pane/_form_item.html.haml b/app/views/groups/group_members/tab_pane/_form_item.html.haml new file mode 100644 index 00000000000..9e57d3329d7 --- /dev/null +++ b/app/views/groups/group_members/tab_pane/_form_item.html.haml @@ -0,0 +1,2 @@ +.gl-px-3.gl-py-3.gl-display-flex.gl-flex-direction-column.gl-md-flex-direction-row + = yield diff --git a/app/views/groups/group_members/tab_pane/_header.html.haml b/app/views/groups/group_members/tab_pane/_header.html.haml new file mode 100644 index 00000000000..a02bf90eddf --- /dev/null +++ b/app/views/groups/group_members/tab_pane/_header.html.haml @@ -0,0 +1,2 @@ +.gl-display-flex.gl-md-align-items-center.gl-flex-direction-column.gl-md-flex-direction-row.row-content-block.second-block + = yield diff --git a/app/views/groups/group_members/tab_pane/_title.html.haml b/app/views/groups/group_members/tab_pane/_title.html.haml new file mode 100644 index 00000000000..c1418a5f7c8 --- /dev/null +++ b/app/views/groups/group_members/tab_pane/_title.html.haml @@ -0,0 +1,2 @@ +%span.gl-flex-grow-1.gl-py-3.gl-pr-3 + = yield diff --git a/app/views/projects/project_members/_team.html.haml b/app/views/projects/project_members/_team.html.haml index 655984397e3..4b3fdf8d0b1 100644 --- a/app/views/projects/project_members/_team.html.haml +++ b/app/views/projects/project_members/_team.html.haml @@ -12,6 +12,7 @@ = search_field_tag :search, params[:search], { placeholder: _('Find existing members by name'), class: 'form-control', spellcheck: false } %button.user-search-btn{ type: "submit", "aria-label" => _("Submit search") } = icon("search") + = label_tag :sort_by, _('Sort by'), class: 'col-form-label label-bold px-2' = render 'shared/members/sort_dropdown' %ul.content-list.members-list{ data: { qa_selector: 'members_list' } } = render partial: 'shared/members/member', collection: members, as: :member diff --git a/app/views/shared/members/_filter_2fa_dropdown.html.haml b/app/views/shared/members/_filter_2fa_dropdown.html.haml index 44ea844028e..a2bc5e9ecdf 100644 --- a/app/views/shared/members/_filter_2fa_dropdown.html.haml +++ b/app/views/shared/members/_filter_2fa_dropdown.html.haml @@ -1,6 +1,6 @@ - filter = params[:two_factor] || 'everyone' - filter_options = { 'everyone' => _('Everyone'), 'enabled' => _('Enabled'), 'disabled' => _('Disabled') } -.dropdown.inline.member-filter-2fa-dropdown.pr-md-2 +.dropdown.inline.member-filter-2fa-dropdown = dropdown_toggle(filter_options[filter], { toggle: 'dropdown' }) %ul.dropdown-menu.dropdown-menu-align-right.dropdown-menu-selectable %li.dropdown-header diff --git a/app/views/shared/members/_search_field.html.haml b/app/views/shared/members/_search_field.html.haml new file mode 100644 index 00000000000..e70cb063324 --- /dev/null +++ b/app/views/shared/members/_search_field.html.haml @@ -0,0 +1,6 @@ +- name = local_assigns.fetch(:name, :search) + +.search-control-wrap.gl-relative + = search_field_tag name, params[name], { placeholder: _('Search'), class: 'form-control', spellcheck: false } + %button.user-search-btn.border-left.gl-display-flex.gl-align-items-center.gl-justify-content-center{ type: 'submit', 'aria': { label: _('Submit search') } } + = sprite_icon('search') diff --git a/app/views/shared/members/_sort_dropdown.html.haml b/app/views/shared/members/_sort_dropdown.html.haml index 50a55565c3c..606d3bcdfa8 100644 --- a/app/views/shared/members/_sort_dropdown.html.haml +++ b/app/views/shared/members/_sort_dropdown.html.haml @@ -1,4 +1,3 @@ -= label_tag :sort_by, 'Sort by', class: 'col-form-label label-bold px-2' .dropdown.inline.qa-user-sort-dropdown = dropdown_toggle(member_sort_options_hash[@sort], { toggle: 'dropdown' }) %ul.dropdown-menu.dropdown-menu-right.dropdown-menu-selectable diff --git a/changelogs/unreleased/229830-move-groups-members-pending-in-to-tabs.yml b/changelogs/unreleased/229830-move-groups-members-pending-in-to-tabs.yml new file mode 100644 index 00000000000..cb1101b0e6a --- /dev/null +++ b/changelogs/unreleased/229830-move-groups-members-pending-in-to-tabs.yml @@ -0,0 +1,5 @@ +--- +title: Reorganize group member management into tabs +merge_request: 38344 +author: +type: changed diff --git a/changelogs/unreleased/update-auto-build-image-to-v0-4-0.yml b/changelogs/unreleased/update-auto-build-image-to-v0-4-0.yml new file mode 100644 index 00000000000..e5d4453622c --- /dev/null +++ b/changelogs/unreleased/update-auto-build-image-to-v0-4-0.yml @@ -0,0 +1,6 @@ +--- +title: Update auto-build-image to v0.4.0 for an updated version of the pack CLI (v0.12.0) for + Cloud Native Buildpack builds +merge_request: 39159 +author: +type: changed diff --git a/doc/ci/variables/predefined_variables.md b/doc/ci/variables/predefined_variables.md index 88cb560dd8f..f13f1f1f36e 100644 --- a/doc/ci/variables/predefined_variables.md +++ b/doc/ci/variables/predefined_variables.md @@ -72,8 +72,8 @@ Kubernetes-specific environment variables are detailed in the | `CI_JOB_URL` | 11.1 | 0.5 | Job details URL | | `CI_KUBERNETES_ACTIVE` | 13.0 | all | Included with the value `true` only if the pipeline has a Kubernetes cluster available for deployments. Not included if no cluster is available. Can be used as an alternative to [`only:kubernetes`/`except:kubernetes`](../yaml/README.md#onlykubernetesexceptkubernetes) with [`rules:if`](../yaml/README.md#rulesif) | | `CI_MERGE_REQUEST_ASSIGNEES` | 11.9 | all | Comma-separated list of username(s) of assignee(s) for the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md). Available only if `only: [merge_requests]` or [`rules`](../yaml/README.md#rules) syntax is used and the merge request is created. | -| `CI_MERGE_REQUEST_ID` | 11.6 | all | The project-level ID of the merge request. Only available if [the pipelines are for merge requests](../merge_request_pipelines/index.md) and the merge request is created. | -| `CI_MERGE_REQUEST_IID` | 11.6 | all | The instance-level IID of the merge request. Only available If [the pipelines are for merge requests](../merge_request_pipelines/index.md) and the merge request is created. | +| `CI_MERGE_REQUEST_ID` | 11.6 | all | The instance-level ID of the merge request. Only available if [the pipelines are for merge requests](../merge_request_pipelines/index.md) and the merge request is created. | +| `CI_MERGE_REQUEST_IID` | 11.6 | all | The project-level IID of the merge request. Only available If [the pipelines are for merge requests](../merge_request_pipelines/index.md) and the merge request is created. | | `CI_MERGE_REQUEST_LABELS` | 11.9 | all | Comma-separated label names of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md). Available only if `only: [merge_requests]` or [`rules`](../yaml/README.md#rules) syntax is used and the merge request is created. | | `CI_MERGE_REQUEST_MILESTONE` | 11.9 | all | The milestone title of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md). Available only if `only: [merge_requests]` or [`rules`](../yaml/README.md#rules) syntax is used and the merge request is created. | | `CI_MERGE_REQUEST_PROJECT_ID` | 11.6 | all | The ID of the project of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md). Available only if `only: [merge_requests]` or [`rules`](../yaml/README.md#rules) syntax is used and the merge request is created. | diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md index 5f0909ca749..790052128cc 100644 --- a/doc/ci/yaml/README.md +++ b/doc/ci/yaml/README.md @@ -3184,7 +3184,7 @@ stored on GitLab. If the expiry time is not defined, it defaults to the [instance wide setting](../../user/admin_area/settings/continuous_integration.md#default-artifacts-expiration-core-only) (30 days by default). -To override the expiration time and keep artifacts forever: +To override the expiration date and protect artifacts from being automatically deleted: - Use the **Keep** button on the job page. - Set the value of `expire_in` to `never`. [Available](https://gitlab.com/gitlab-org/gitlab/-/issues/22761) diff --git a/doc/install/azure/index.md b/doc/install/azure/index.md index 9ab37abc61f..548c7d8c92e 100644 --- a/doc/install/azure/index.md +++ b/doc/install/azure/index.md @@ -41,8 +41,7 @@ create SQL Databases, author websites, and perform lots of other cloud tasks. The [Azure Marketplace](https://azuremarketplace.microsoft.com/en-us/marketplace/) is an online store for pre-configured applications and services which have been optimized for the cloud by software vendors like GitLab, available on the Azure Marketplace as pre-configured solutions. In this tutorial -we will install GitLab Community Edition, but for GitLab Enterprise Edition you -can follow the same process. +we will install GitLab Community Edition. To begin creating a new GitLab VM, click on the **+ New** icon, type "GitLab" into the search box, and then click the **"GitLab Community Edition"** search result: diff --git a/doc/topics/git/lfs/migrate_to_git_lfs.md b/doc/topics/git/lfs/migrate_to_git_lfs.md index 3e287c0816d..944f4d8f78d 100644 --- a/doc/topics/git/lfs/migrate_to_git_lfs.md +++ b/doc/topics/git/lfs/migrate_to_git_lfs.md @@ -96,9 +96,10 @@ Consider an example upstream project, `git@gitlab.com:gitlab-tests/test-git-lfs- 1. Clean up the repository: ```shell - # cd path/to/mirror/repo: + # Change into the mirror repo directory: cd test-git-lfs-repo-migration.git - # clean up the repo: + + # Clean up the repo: git reflog expire --expire=now --all && git gc --prune=now --aggressive ``` @@ -128,12 +129,23 @@ Consider an example upstream project, `git@gitlab.com:gitlab-tests/test-git-lfs- 1. Track the files you want with LFS: ```shell - # cd path/to/upstream/repo: + # Change into the /tmp directory + cd /tmp + + # Clone the repo + git clone git@gitlab.com:gitlab-tests/test-git-lfs-repo-migration.git + + # Change into the upstream repo directory: cd test-git-lfs-repo-migration + # You may need to reset your local copy with upstream's `master` after force-pushing from the mirror: git reset --hard origin/master + # Track the files with LFS: git lfs track "*.gif" "*.png" "*.jpg" "*.psd" "*.mp4" "img/" + + # Push up changes to .gitattributes + git add .gitattributes && git commit -m 'Track .gif,.png,.jpg,.psd,.mp4 and img/' && git push ``` Now all existing the files you converted, as well as the new diff --git a/doc/user/group/img/add_new_members.png b/doc/user/group/img/add_new_members.png Binary files differindex 6d43e309e84..8bd9e2374bc 100644 --- a/doc/user/group/img/add_new_members.png +++ b/doc/user/group/img/add_new_members.png diff --git a/lib/gitlab/ci/templates/Jobs/Build.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Build.gitlab-ci.yml index dbe870953ae..0c3598a61a7 100644 --- a/lib/gitlab/ci/templates/Jobs/Build.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Jobs/Build.gitlab-ci.yml @@ -1,6 +1,6 @@ build: stage: build - image: "registry.gitlab.com/gitlab-org/cluster-integration/auto-build-image:v0.3.1" + image: "registry.gitlab.com/gitlab-org/cluster-integration/auto-build-image:v0.4.0" variables: DOCKER_TLS_CERTDIR: "" services: diff --git a/lib/gitlab/danger/helper.rb b/lib/gitlab/danger/helper.rb index de6bcde213d..077c71f1233 100644 --- a/lib/gitlab/danger/helper.rb +++ b/lib/gitlab/danger/helper.rb @@ -172,9 +172,13 @@ module Gitlab %r{\Atooling/} => :engineering_productivity, %r{(CODEOWNERS)} => :engineering_productivity, + %r{\A(ee/)?spec/features/} => :test, + %r{\A(ee/)?spec/support/shared_examples/features/} => :test, + %r{\A(ee/)?spec/support/shared_contexts/features/} => :test, + %r{\A(ee/)?spec/support/helpers/features/} => :test, + %r{\A(ee/)?app/(?!assets|views)[^/]+} => :backend, %r{\A(ee/)?(bin|config|generator_templates|lib|rubocop)/} => :backend, - %r{\A(ee/)?spec/features/} => :test, %r{\A(ee/)?spec/} => :backend, %r{\A(ee/)?vendor/} => :backend, %r{\A(Gemfile|Gemfile.lock|Rakefile)\z} => :backend, diff --git a/locale/gitlab.pot b/locale/gitlab.pot index d4c32f65007..73c4ba5002d 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -1237,6 +1237,9 @@ msgstr "" msgid "Access forbidden. Check your access level." msgstr "" +msgid "Access requests" +msgstr "" + msgid "Access to '%{classification_label}' not allowed" msgstr "" @@ -9926,9 +9929,6 @@ msgstr "" msgid "Existing projects will be able to use expiration policies. Avoid enabling this if an external Container Registry is being used, as there is a performance risk if many images exist on one project." msgstr "" -msgid "Existing shares" -msgstr "" - msgid "Existing sign in methods may be removed" msgstr "" @@ -13264,6 +13264,9 @@ msgstr "" msgid "Invite teammates (optional)" msgstr "" +msgid "Invited" +msgstr "" + msgid "Invited users will be added with developer level permissions. You can always change this later." msgstr "" @@ -14864,6 +14867,9 @@ msgstr "" msgid "Members can be added by project %{i_open}Maintainers%{i_close} or %{i_open}Owners%{i_close}" msgstr "" +msgid "Members invited to %{strong_start}%{group_name}%{strong_end}" +msgstr "" + msgid "Members of %{strong_open}%{project_name}%{strong_close}" msgstr "" @@ -14873,9 +14879,6 @@ msgstr "" msgid "Members with access to %{strong_start}%{group_name}%{strong_end}" msgstr "" -msgid "Members with pending access to %{strong_start}%{group_name}%{strong_end}" -msgstr "" - msgid "Memory Usage" msgstr "" @@ -26700,6 +26703,9 @@ msgstr "" msgid "Users requesting access to" msgstr "" +msgid "Users requesting access to %{strong_start}%{group_name}%{strong_end}" +msgstr "" + msgid "Users were successfully added." msgstr "" diff --git a/qa/qa/page/group/members.rb b/qa/qa/page/group/members.rb index 20caa7e839f..dce18ee5c55 100644 --- a/qa/qa/page/group/members.rb +++ b/qa/qa/page/group/members.rb @@ -25,6 +25,7 @@ module QA view 'app/views/groups/group_members/index.html.haml' do element :invite_group_tab + element :groups_list_tab element :groups_list end @@ -71,6 +72,8 @@ module QA end def has_existing_group_share?(group_name) + click_element :groups_list_tab + within_element(:groups_list) do has_element?(:group_row, text: group_name) end diff --git a/spec/features/groups/members/manage_groups_spec.rb b/spec/features/groups/members/manage_groups_spec.rb index f1cf04417c0..faf455e4ed9 100644 --- a/spec/features/groups/members/manage_groups_spec.rb +++ b/spec/features/groups/members/manage_groups_spec.rb @@ -20,26 +20,28 @@ RSpec.describe 'Groups > Members > Manage groups', :js do add_group(shared_with_group.id, 'Reporter') + click_groups_tab + page.within(first_row) do expect(page).to have_content(shared_with_group.name) expect(page).to have_content('Reporter') end end - it 'remove user from group' do + it 'remove group from group' do create(:group_group_link, shared_group: shared_group, shared_with_group: shared_with_group, group_access: ::Gitlab::Access::DEVELOPER) visit group_group_members_path(shared_group) + click_groups_tab + expect(page).to have_content(shared_with_group.name) accept_confirm do - find(:css, '#existing_shares li', text: shared_with_group.name).find(:css, 'a.btn-remove').click + find(:css, '#tab-groups li', text: shared_with_group.name).find(:css, 'a.btn-remove').click end - wait_for_requests - expect(page).not_to have_content(shared_with_group.name) end @@ -49,6 +51,8 @@ RSpec.describe 'Groups > Members > Manage groups', :js do visit group_group_members_path(shared_group) + click_groups_tab + page.within(first_row) do click_button('Developer') click_link('Maintainer') @@ -67,4 +71,8 @@ RSpec.describe 'Groups > Members > Manage groups', :js do click_button "Invite" end end + + def click_groups_tab + click_link "Groups" + end end diff --git a/spec/features/groups/members/manage_members_spec.rb b/spec/features/groups/members/manage_members_spec.rb index 99846ecee27..1ea2e36ce28 100644 --- a/spec/features/groups/members/manage_members_spec.rb +++ b/spec/features/groups/members/manage_members_spec.rb @@ -101,7 +101,7 @@ RSpec.describe 'Groups > Members > Manage members' do add_user('test@example.com', 'Reporter') - click_link('Pending') + click_link('Invited') page.within('.content-list.members-list') do expect(page).to have_content('test@example.com') diff --git a/spec/features/groups/members/master_manages_access_requests_spec.rb b/spec/features/groups/members/master_manages_access_requests_spec.rb index 2a17e7d2a5c..71c9b280ebe 100644 --- a/spec/features/groups/members/master_manages_access_requests_spec.rb +++ b/spec/features/groups/members/master_manages_access_requests_spec.rb @@ -4,6 +4,7 @@ require 'spec_helper' RSpec.describe 'Groups > Members > Maintainer manages access requests' do it_behaves_like 'Maintainer manages access requests' do + let(:has_tabs) { true } let(:entity) { create(:group, :public) } let(:members_page_path) { group_group_members_path(entity) } end diff --git a/spec/features/groups/members/search_members_spec.rb b/spec/features/groups/members/search_members_spec.rb index 4c34ccf87c3..ad4f5c0b579 100644 --- a/spec/features/groups/members/search_members_spec.rb +++ b/spec/features/groups/members/search_members_spec.rb @@ -19,7 +19,7 @@ RSpec.describe 'Search group member' do end it 'renders member users' do - page.within '.user-search-form' do + page.within '[data-testid="user-search-form"]' do fill_in 'search', with: member.name find('.user-search-btn').click end diff --git a/spec/features/groups/members/tabs_spec.rb b/spec/features/groups/members/tabs_spec.rb new file mode 100644 index 00000000000..fa77d1a2ff8 --- /dev/null +++ b/spec/features/groups/members/tabs_spec.rb @@ -0,0 +1,112 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'Groups > Members > Tabs' do + using RSpec::Parameterized::TableSyntax + + shared_examples 'active "Members" tab' do + it 'displays "Members" tab' do + expect(page).to have_selector('.nav-link.active', text: 'Members') + end + end + + shared_examples 'active "Invited" tab' do + it 'displays "Invited" tab' do + expect(page).to have_selector('.nav-link.active', text: 'Invited') + end + end + + let(:owner) { create(:user) } + let(:group) { create(:group) } + + before do + stub_const('Groups::GroupMembersController::MEMBER_PER_PAGE_LIMIT', 1) + allow_any_instance_of(Member).to receive(:send_request).and_return(true) + + group.add_owner(owner) + sign_in(owner) + + create_list(:group_member, 2, group: group) + create_list(:group_member, 2, :invited, group: group) + create_list(:group_group_link, 2, shared_group: group) + create_list(:group_member, 2, :access_request, group: group) + end + + where(:tab, :count) do + 'Members' | 3 + 'Invited' | 2 + 'Groups' | 2 + 'Access requests' | 2 + end + + with_them do + it "renders #{params[:tab]} tab" do + visit group_group_members_path(group) + + expect(page).to have_selector('.nav-link', text: "#{tab} #{count}") + end + end + + context 'displays "Members" tab by default' do + before do + visit group_group_members_path(group) + end + + it_behaves_like 'active "Members" tab' + end + + context 'when searching "Invited"', :js do + before do + visit group_group_members_path(group) + + click_link 'Invited' + + page.within '[data-testid="user-search-form"]' do + fill_in 'search_invited', with: 'email' + find('button[type="submit"]').click + end + end + + it_behaves_like 'active "Invited" tab' + + context 'and then searching "Members"' do + before do + click_link 'Members' + + page.within '[data-testid="user-search-form"]' do + fill_in 'search', with: 'test' + find('button[type="submit"]').click + end + end + + it_behaves_like 'active "Members" tab' + end + end + + context 'when using "Invited" pagination', :js do + before do + visit group_group_members_path(group) + + click_link 'Invited' + + page.within '.pagination' do + click_link '2' + end + end + + it_behaves_like 'active "Invited" tab' + + context 'and then using "Members" pagination' do + before do + click_link 'Members' + + page.within '.pagination' do + click_link '2' + end + end + + it_behaves_like 'active "Members" tab' + end + end +end diff --git a/spec/features/projects/members/master_manages_access_requests_spec.rb b/spec/features/projects/members/master_manages_access_requests_spec.rb index 4c3eaa93352..2fdc75dca91 100644 --- a/spec/features/projects/members/master_manages_access_requests_spec.rb +++ b/spec/features/projects/members/master_manages_access_requests_spec.rb @@ -4,6 +4,7 @@ require 'spec_helper' RSpec.describe 'Projects > Members > Maintainer manages access requests' do it_behaves_like 'Maintainer manages access requests' do + let(:has_tabs) { false } let(:entity) { create(:project, :public) } let(:members_page_path) { project_project_members_path(entity) } end diff --git a/spec/frontend/registry/explorer/pages/details_spec.js b/spec/frontend/registry/explorer/pages/details_spec.js index 9bc0bae5c23..66e8a4aea0d 100644 --- a/spec/frontend/registry/explorer/pages/details_spec.js +++ b/spec/frontend/registry/explorer/pages/details_spec.js @@ -13,7 +13,7 @@ import { SET_TAGS_LIST_SUCCESS, SET_TAGS_PAGINATION, SET_INITIAL_STATE, -} from '~/registry/explorer/stores/mutation_types/'; +} from '~/registry/explorer/stores/mutation_types'; import { tagsListResponse } from '../mock_data'; import { DeleteModal } from '../stubs'; diff --git a/spec/frontend/registry/explorer/pages/list_spec.js b/spec/frontend/registry/explorer/pages/list_spec.js index 2ece7593b41..0685da78924 100644 --- a/spec/frontend/registry/explorer/pages/list_spec.js +++ b/spec/frontend/registry/explorer/pages/list_spec.js @@ -14,7 +14,7 @@ import { SET_IMAGES_LIST_SUCCESS, SET_PAGINATION, SET_INITIAL_STATE, -} from '~/registry/explorer/stores/mutation_types/'; +} from '~/registry/explorer/stores/mutation_types'; import { DELETE_IMAGE_SUCCESS_MESSAGE, DELETE_IMAGE_ERROR_MESSAGE, diff --git a/spec/frontend/vue_shared/components/identicon_spec.js b/spec/frontend/vue_shared/components/identicon_spec.js index 53a55dcd6bd..24fc3713e2b 100644 --- a/spec/frontend/vue_shared/components/identicon_spec.js +++ b/spec/frontend/vue_shared/components/identicon_spec.js @@ -25,7 +25,7 @@ describe('Identicon', () => { }); describe('entity id is a number', () => { - beforeEach(createComponent); + beforeEach(() => createComponent()); it('matches snapshot', () => { expect(wrapper.element).toMatchSnapshot(); diff --git a/spec/lib/gitlab/danger/helper_spec.rb b/spec/lib/gitlab/danger/helper_spec.rb index 3739e1d424d..37bc14c44f2 100644 --- a/spec/lib/gitlab/danger/helper_spec.rb +++ b/spec/lib/gitlab/danger/helper_spec.rb @@ -225,6 +225,15 @@ RSpec.describe Gitlab::Danger::Helper do 'ee/spec/foo' | [:backend] 'ee/spec/foo/bar' | [:backend] + 'spec/features/foo' | [:test] + 'ee/spec/features/foo' | [:test] + 'spec/support/shared_examples/features/foo' | [:test] + 'ee/spec/support/shared_examples/features/foo' | [:test] + 'spec/support/shared_contexts/features/foo' | [:test] + 'ee/spec/support/shared_contexts/features/foo' | [:test] + 'spec/support/helpers/features/foo' | [:test] + 'ee/spec/support/helpers/features/foo' | [:test] + 'generator_templates/foo' | [:backend] 'vendor/languages.yml' | [:backend] 'vendor/licenses.csv' | [:backend] diff --git a/spec/requests/api/composer_packages_spec.rb b/spec/requests/api/composer_packages_spec.rb index 29372d15a32..d5e23a91da0 100644 --- a/spec/requests/api/composer_packages_spec.rb +++ b/spec/requests/api/composer_packages_spec.rb @@ -11,6 +11,8 @@ RSpec.describe API::ComposerPackages do let_it_be(:project, reload: true) { create(:project, :custom_repo, files: { 'composer.json' => { name: package_name }.to_json }, group: group) } let(:headers) { {} } + using RSpec::Parameterized::TableSyntax + describe 'GET /api/v4/group/:id/-/packages/composer/packages' do let(:url) { "/group/#{group.id}/-/packages/composer/packages.json" } @@ -19,32 +21,73 @@ RSpec.describe API::ComposerPackages do context 'with valid project' do let!(:package) { create(:composer_package, :with_metadatum, project: project) } - using RSpec::Parameterized::TableSyntax + context 'with a public group' do + before do + group.update!(visibility_level: Gitlab::VisibilityLevel::PUBLIC) + end - where(:project_visibility_level, :user_role, :member, :user_token, :shared_examples_name, :expected_status) do - 'PUBLIC' | :developer | true | true | 'Composer package index' | :success - 'PUBLIC' | :guest | true | true | 'Composer package index' | :success - 'PUBLIC' | :developer | true | false | 'Composer package index' | :success - 'PUBLIC' | :guest | true | false | 'Composer package index' | :success - 'PUBLIC' | :developer | false | true | 'Composer package index' | :success - 'PUBLIC' | :guest | false | true | 'Composer package index' | :success - 'PUBLIC' | :developer | false | false | 'Composer package index' | :success - 'PUBLIC' | :guest | false | false | 'Composer package index' | :success - 'PUBLIC' | :anonymous | false | true | 'Composer package index' | :success - 'PRIVATE' | :developer | true | true | 'Composer package index' | :success - 'PRIVATE' | :guest | true | true | 'Composer package index' | :success - 'PRIVATE' | :developer | true | false | 'process Composer api request' | :not_found - 'PRIVATE' | :guest | true | false | 'process Composer api request' | :not_found - 'PRIVATE' | :developer | false | true | 'process Composer api request' | :not_found - 'PRIVATE' | :guest | false | true | 'process Composer api request' | :not_found - 'PRIVATE' | :developer | false | false | 'process Composer api request' | :not_found - 'PRIVATE' | :guest | false | false | 'process Composer api request' | :not_found - 'PRIVATE' | :anonymous | false | true | 'process Composer api request' | :not_found + where(:project_visibility_level, :user_role, :member, :user_token, :include_package) do + 'PUBLIC' | :developer | true | true | :include_package + 'PUBLIC' | :developer | true | false | :include_package + 'PUBLIC' | :developer | false | false | :include_package + 'PUBLIC' | :developer | false | true | :include_package + 'PUBLIC' | :guest | true | true | :include_package + 'PUBLIC' | :guest | true | false | :include_package + 'PUBLIC' | :guest | false | true | :include_package + 'PUBLIC' | :guest | false | false | :include_package + 'PUBLIC' | :anonymous | false | true | :include_package + 'PRIVATE' | :developer | true | true | :include_package + 'PRIVATE' | :developer | true | false | :does_not_include_package + 'PRIVATE' | :developer | false | true | :does_not_include_package + 'PRIVATE' | :developer | false | false | :does_not_include_package + 'PRIVATE' | :guest | true | true | :does_not_include_package + 'PRIVATE' | :guest | true | false | :does_not_include_package + 'PRIVATE' | :guest | false | true | :does_not_include_package + 'PRIVATE' | :guest | false | false | :does_not_include_package + 'PRIVATE' | :anonymous | false | true | :does_not_include_package + end + + with_them do + include_context 'Composer api project access', params[:project_visibility_level], params[:user_role], params[:user_token] do + it_behaves_like 'Composer package index', params[:user_role], :success, params[:member], params[:include_package] + end + end end - with_them do - include_context 'Composer api group access', params[:project_visibility_level], params[:user_role], params[:user_token] do - it_behaves_like params[:shared_examples_name], params[:user_role], params[:expected_status], params[:member] + context 'with a private group' do + before do + group.update!(visibility_level: Gitlab::VisibilityLevel::PRIVATE) + end + + context 'with access to the api' do + where(:project_visibility_level, :user_role, :member, :user_token, :include_package) do + 'PRIVATE' | :developer | true | true | :include_package + 'PRIVATE' | :guest | true | true | :does_not_include_package + end + + with_them do + include_context 'Composer api project access', params[:project_visibility_level], params[:user_role], params[:user_token] do + it_behaves_like 'Composer package index', params[:user_role], :success, params[:member], params[:include_package] + end + end + end + + context 'without access to the api' do + where(:project_visibility_level, :user_role, :member, :user_token) do + 'PRIVATE' | :developer | true | false + 'PRIVATE' | :developer | false | true + 'PRIVATE' | :developer | false | false + 'PRIVATE' | :guest | true | false + 'PRIVATE' | :guest | false | true + 'PRIVATE' | :guest | false | false + 'PRIVATE' | :anonymous | false | true + end + + with_them do + include_context 'Composer api project access', params[:project_visibility_level], params[:user_role], params[:user_token] do + it_behaves_like 'process Composer api request', params[:user_role], :not_found, params[:member] + end + end end end end @@ -60,25 +103,23 @@ RSpec.describe API::ComposerPackages do subject { get api(url), headers: headers } context 'with valid project' do - using RSpec::Parameterized::TableSyntax - where(:project_visibility_level, :user_role, :member, :user_token, :shared_examples_name, :expected_status) do 'PUBLIC' | :developer | true | true | 'Composer provider index' | :success - 'PUBLIC' | :guest | true | true | 'Composer provider index' | :success 'PUBLIC' | :developer | true | false | 'Composer provider index' | :success - 'PUBLIC' | :guest | true | false | 'Composer provider index' | :success 'PUBLIC' | :developer | false | true | 'Composer provider index' | :success - 'PUBLIC' | :guest | false | true | 'Composer provider index' | :success 'PUBLIC' | :developer | false | false | 'Composer provider index' | :success + 'PUBLIC' | :guest | true | true | 'Composer provider index' | :success + 'PUBLIC' | :guest | true | false | 'Composer provider index' | :success + 'PUBLIC' | :guest | false | true | 'Composer provider index' | :success 'PUBLIC' | :guest | false | false | 'Composer provider index' | :success 'PUBLIC' | :anonymous | false | true | 'Composer provider index' | :success 'PRIVATE' | :developer | true | true | 'Composer provider index' | :success - 'PRIVATE' | :guest | true | true | 'Composer empty provider index' | :success 'PRIVATE' | :developer | true | false | 'process Composer api request' | :not_found - 'PRIVATE' | :guest | true | false | 'process Composer api request' | :not_found 'PRIVATE' | :developer | false | true | 'process Composer api request' | :not_found - 'PRIVATE' | :guest | false | true | 'process Composer api request' | :not_found 'PRIVATE' | :developer | false | false | 'process Composer api request' | :not_found + 'PRIVATE' | :guest | true | true | 'Composer empty provider index' | :success + 'PRIVATE' | :guest | true | false | 'process Composer api request' | :not_found + 'PRIVATE' | :guest | false | true | 'process Composer api request' | :not_found 'PRIVATE' | :guest | false | false | 'process Composer api request' | :not_found 'PRIVATE' | :anonymous | false | true | 'process Composer api request' | :not_found end @@ -106,27 +147,25 @@ RSpec.describe API::ComposerPackages do end context 'with valid project' do - using RSpec::Parameterized::TableSyntax - let!(:package) { create(:composer_package, :with_metadatum, name: package_name, project: project) } where(:project_visibility_level, :user_role, :member, :user_token, :shared_examples_name, :expected_status) do 'PUBLIC' | :developer | true | true | 'Composer package api request' | :success - 'PUBLIC' | :guest | true | true | 'Composer package api request' | :success 'PUBLIC' | :developer | true | false | 'Composer package api request' | :success - 'PUBLIC' | :guest | true | false | 'Composer package api request' | :success 'PUBLIC' | :developer | false | true | 'Composer package api request' | :success - 'PUBLIC' | :guest | false | true | 'Composer package api request' | :success 'PUBLIC' | :developer | false | false | 'Composer package api request' | :success + 'PUBLIC' | :guest | true | true | 'Composer package api request' | :success + 'PUBLIC' | :guest | true | false | 'Composer package api request' | :success + 'PUBLIC' | :guest | false | true | 'Composer package api request' | :success 'PUBLIC' | :guest | false | false | 'Composer package api request' | :success 'PUBLIC' | :anonymous | false | true | 'Composer package api request' | :success 'PRIVATE' | :developer | true | true | 'Composer package api request' | :success - 'PRIVATE' | :guest | true | true | 'process Composer api request' | :not_found 'PRIVATE' | :developer | true | false | 'process Composer api request' | :not_found - 'PRIVATE' | :guest | true | false | 'process Composer api request' | :not_found 'PRIVATE' | :developer | false | true | 'process Composer api request' | :not_found - 'PRIVATE' | :guest | false | true | 'process Composer api request' | :not_found 'PRIVATE' | :developer | false | false | 'process Composer api request' | :not_found + 'PRIVATE' | :guest | true | true | 'process Composer api request' | :not_found + 'PRIVATE' | :guest | true | false | 'process Composer api request' | :not_found + 'PRIVATE' | :guest | false | true | 'process Composer api request' | :not_found 'PRIVATE' | :guest | false | false | 'process Composer api request' | :not_found 'PRIVATE' | :anonymous | false | true | 'process Composer api request' | :not_found end @@ -153,25 +192,23 @@ RSpec.describe API::ComposerPackages do shared_examples 'composer package publish' do context 'with valid project' do - using RSpec::Parameterized::TableSyntax - where(:project_visibility_level, :user_role, :member, :user_token, :shared_examples_name, :expected_status) do 'PUBLIC' | :developer | true | true | 'Composer package creation' | :created - 'PUBLIC' | :guest | true | true | 'process Composer api request' | :forbidden 'PUBLIC' | :developer | true | false | 'process Composer api request' | :unauthorized - 'PUBLIC' | :guest | true | false | 'process Composer api request' | :unauthorized 'PUBLIC' | :developer | false | true | 'process Composer api request' | :forbidden - 'PUBLIC' | :guest | false | true | 'process Composer api request' | :forbidden 'PUBLIC' | :developer | false | false | 'process Composer api request' | :unauthorized + 'PUBLIC' | :guest | true | true | 'process Composer api request' | :forbidden + 'PUBLIC' | :guest | true | false | 'process Composer api request' | :unauthorized + 'PUBLIC' | :guest | false | true | 'process Composer api request' | :forbidden 'PUBLIC' | :guest | false | false | 'process Composer api request' | :unauthorized 'PUBLIC' | :anonymous | false | true | 'process Composer api request' | :unauthorized 'PRIVATE' | :developer | true | true | 'Composer package creation' | :created - 'PRIVATE' | :guest | true | true | 'process Composer api request' | :forbidden 'PRIVATE' | :developer | true | false | 'process Composer api request' | :unauthorized - 'PRIVATE' | :guest | true | false | 'process Composer api request' | :unauthorized 'PRIVATE' | :developer | false | true | 'process Composer api request' | :not_found - 'PRIVATE' | :guest | false | true | 'process Composer api request' | :not_found 'PRIVATE' | :developer | false | false | 'process Composer api request' | :unauthorized + 'PRIVATE' | :guest | true | true | 'process Composer api request' | :forbidden + 'PRIVATE' | :guest | true | false | 'process Composer api request' | :unauthorized + 'PRIVATE' | :guest | false | true | 'process Composer api request' | :not_found 'PRIVATE' | :guest | false | false | 'process Composer api request' | :unauthorized 'PRIVATE' | :anonymous | false | true | 'process Composer api request' | :unauthorized end @@ -251,25 +288,23 @@ RSpec.describe API::ComposerPackages do let(:branch) { project.repository.find_branch('master') } let(:sha) { branch.target } - using RSpec::Parameterized::TableSyntax - where(:project_visibility_level, :user_role, :member, :user_token, :expected_status) do 'PUBLIC' | :developer | true | true | :success - 'PUBLIC' | :guest | true | true | :success 'PUBLIC' | :developer | true | false | :success - 'PUBLIC' | :guest | true | false | :success 'PUBLIC' | :developer | false | true | :success - 'PUBLIC' | :guest | false | true | :success 'PUBLIC' | :developer | false | false | :success + 'PUBLIC' | :guest | true | true | :success + 'PUBLIC' | :guest | true | false | :success + 'PUBLIC' | :guest | false | true | :success 'PUBLIC' | :guest | false | false | :success 'PUBLIC' | :anonymous | false | true | :success 'PRIVATE' | :developer | true | true | :success - 'PRIVATE' | :guest | true | true | :success 'PRIVATE' | :developer | true | false | :success - 'PRIVATE' | :guest | true | false | :success 'PRIVATE' | :developer | false | true | :success - 'PRIVATE' | :guest | false | true | :success 'PRIVATE' | :developer | false | false | :success + 'PRIVATE' | :guest | true | true | :success + 'PRIVATE' | :guest | true | false | :success + 'PRIVATE' | :guest | false | true | :success 'PRIVATE' | :guest | false | false | :success 'PRIVATE' | :anonymous | false | true | :success end diff --git a/spec/support/csv_response.rb b/spec/support/csv_response.rb new file mode 100644 index 00000000000..9ed76dcdd4a --- /dev/null +++ b/spec/support/csv_response.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +RSpec.configure do |config| + config.include_context 'CSV response', type: :controller +end diff --git a/spec/support/shared_contexts/csv_response_shared_context.rb b/spec/support/shared_contexts/csv_response_shared_context.rb new file mode 100644 index 00000000000..af79e393a91 --- /dev/null +++ b/spec/support/shared_contexts/csv_response_shared_context.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +RSpec.shared_context 'CSV response' do + let(:csv_response) { CSV.parse(response.body) } +end diff --git a/spec/support/shared_examples/features/master_manages_access_requests_shared_example.rb b/spec/support/shared_examples/features/master_manages_access_requests_shared_example.rb index 00ce690d2e3..ffe4fb83283 100644 --- a/spec/support/shared_examples/features/master_manages_access_requests_shared_example.rb +++ b/spec/support/shared_examples/features/master_manages_access_requests_shared_example.rb @@ -8,17 +8,18 @@ RSpec.shared_examples 'Maintainer manages access requests' do entity.request_access(user) entity.respond_to?(:add_owner) ? entity.add_owner(maintainer) : entity.add_maintainer(maintainer) sign_in(maintainer) - end - - it 'maintainer can see access requests' do visit members_page_path + if has_tabs + click_on 'Access requests' + end + end + + it 'maintainer can see access requests', :js do expect_visible_access_request(entity, user) end it 'maintainer can grant access', :js do - visit members_page_path - expect_visible_access_request(entity, user) click_on 'Grant access' @@ -31,8 +32,6 @@ RSpec.shared_examples 'Maintainer manages access requests' do end it 'maintainer can deny access', :js do - visit members_page_path - expect_visible_access_request(entity, user) # Open modal @@ -47,7 +46,13 @@ RSpec.shared_examples 'Maintainer manages access requests' do end def expect_visible_access_request(entity, user) - expect(page).to have_content "Users requesting access to #{entity.name} 1" + if has_tabs + expect(page).to have_content "Access requests 1" + expect(page).to have_content "Users requesting access to #{entity.name}" + else + expect(page).to have_content "Users requesting access to #{entity.name} 1" + end + expect(page).to have_content user.name end diff --git a/spec/support/shared_examples/requests/api/composer_packages_shared_examples.rb b/spec/support/shared_examples/requests/api/composer_packages_shared_examples.rb index 5257980d7df..5ebf4e350e3 100644 --- a/spec/support/shared_examples/requests/api/composer_packages_shared_examples.rb +++ b/spec/support/shared_examples/requests/api/composer_packages_shared_examples.rb @@ -7,13 +7,17 @@ RSpec.shared_context 'Composer user type' do |user_type, add_member| end end -RSpec.shared_examples 'Composer package index' do |user_type, status, add_member = true| +RSpec.shared_examples 'Composer package index' do |user_type, status, add_member, include_package| include_context 'Composer user type', user_type, add_member do + let(:expected_packages) { include_package == :include_package ? [package] : [] } + let(:presenter) { ::Packages::Composer::PackagesPresenter.new(group, expected_packages ) } + it 'returns the package index' do subject expect(response).to have_gitlab_http_status(status) expect(response).to match_response_schema('public_api/v4/packages/composer/index') + expect(json_response).to eq presenter.root end end end |