summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-03-07 03:07:43 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2023-03-07 03:07:43 +0000
commitd0db90848503511d758f29c16a93a1e2b1c3da47 (patch)
tree58240f1bc91479c60d78114ecccaa97516e9245a
parentdefeeba1a8d6fa8784db1c50ca4ff9e8b56f539c (diff)
downloadgitlab-ce-d0db90848503511d758f29c16a93a1e2b1c3da47.tar.gz
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.rubocop_todo/layout/argument_alignment.yml1
-rw-r--r--.rubocop_todo/lint/unused_method_argument.yml1
-rw-r--r--.rubocop_todo/style/mutable_constant.yml1
-rw-r--r--app/assets/javascripts/syntax_highlight.js4
-rw-r--r--app/graphql/mutations/members/bulk_update_base.rb88
-rw-r--r--app/graphql/mutations/members/groups/bulk_update.rb77
-rw-r--r--app/graphql/mutations/members/projects/bulk_update.rb26
-rw-r--r--app/graphql/types/mutation_type.rb1
-rw-r--r--app/helpers/diff_helper.rb6
-rw-r--r--app/views/projects/compare/index.html.haml4
-rw-r--r--app/views/projects/compare/show.html.haml2
-rw-r--r--app/views/projects/graphs/show.html.haml2
-rw-r--r--config/feature_flags/development/large_ipynb_diffs.yml8
-rw-r--r--doc/api/graphql/reference/index.md24
-rw-r--r--doc/architecture/blueprints/code_search_with_zoekt/index.md (renamed from doc/architecture/blueprints/search/code_search_with_zoekt.md)0
-rw-r--r--doc/user/project/file_lock.md2
-rw-r--r--doc/user/project/repository/branches/index.md2
-rw-r--r--doc/user/project/repository/index.md4
-rw-r--r--lib/gitlab/git/diff_collection.rb2
-rw-r--r--lib/sidebars/projects/menus/repository_menu.rb4
-rw-r--r--locale/gitlab.pot11
-rw-r--r--qa/qa/page/project/sub_menus/repository.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/web_ide/server_hooks_custom_error_message_spec.rb14
-rw-r--r--spec/features/merge_request/user_sees_real_time_reviewers_spec.rb24
-rw-r--r--spec/frontend/access_tokens/components/new_access_token_app_spec.js4
-rw-r--r--spec/frontend/contributors/store/actions_spec.js6
-rw-r--r--spec/frontend/deploy_freeze/store/actions_spec.js4
-rw-r--r--spec/frontend/filtered_search/filtered_search_manager_spec.js4
-rw-r--r--spec/frontend/filtered_search/visual_token_value_spec.js4
-rw-r--r--spec/frontend/groups/components/app_spec.js10
-rw-r--r--spec/frontend/groups/components/group_name_and_path_spec.js4
-rw-r--r--spec/frontend/header_search/store/actions_spec.js2
-rw-r--r--spec/frontend/issuable/related_issues/components/related_issues_root_spec.js4
-rw-r--r--spec/frontend/merge_request_spec.js4
-rw-r--r--spec/frontend/pipelines/components/jobs/failed_jobs_app_spec.js4
-rw-r--r--spec/frontend/pipelines/components/jobs/failed_jobs_table_spec.js4
-rw-r--r--spec/frontend/pipelines/components/jobs/jobs_app_spec.js4
-rw-r--r--spec/frontend/pipelines/pipelines_actions_spec.js4
-rw-r--r--spec/frontend/pipelines/pipelines_spec.js4
-rw-r--r--spec/frontend/pipelines/test_reports/stores/actions_spec.js6
-rw-r--r--spec/frontend/pipelines/test_reports/stores/mutations_spec.js6
-rw-r--r--spec/frontend/search/store/actions_spec.js18
-rw-r--r--spec/frontend/vue_merge_request_widget/components/approvals/approvals_spec.js6
-rw-r--r--spec/frontend/vue_merge_request_widget/components/states/work_in_progress_spec.js4
-rw-r--r--spec/graphql/mutations/members/bulk_update_base_spec.rb16
-rw-r--r--spec/helpers/diff_helper_spec.rb59
-rw-r--r--spec/lib/gitlab/git/diff_collection_spec.rb20
-rw-r--r--spec/lib/sidebars/projects/menus/repository_menu_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/members/groups/bulk_update_spec.rb128
-rw-r--r--spec/requests/api/graphql/mutations/members/projects/bulk_update_spec.rb18
-rw-r--r--spec/support/shared_contexts/navbar_structure_context.rb6
-rw-r--r--spec/support/shared_examples/graphql/mutations/members/bulk_update_shared_examples.rb123
-rw-r--r--spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb8
53 files changed, 500 insertions, 296 deletions
diff --git a/.rubocop_todo/layout/argument_alignment.yml b/.rubocop_todo/layout/argument_alignment.yml
index 63c0b722055..e442a2a8856 100644
--- a/.rubocop_todo/layout/argument_alignment.yml
+++ b/.rubocop_todo/layout/argument_alignment.yml
@@ -108,7 +108,6 @@ Layout/ArgumentAlignment:
- 'app/graphql/mutations/jira_import/import_users.rb'
- 'app/graphql/mutations/jira_import/start.rb'
- 'app/graphql/mutations/labels/create.rb'
- - 'app/graphql/mutations/members/groups/bulk_update.rb'
- 'app/graphql/mutations/merge_requests/accept.rb'
- 'app/graphql/mutations/merge_requests/base.rb'
- 'app/graphql/mutations/merge_requests/create.rb'
diff --git a/.rubocop_todo/lint/unused_method_argument.yml b/.rubocop_todo/lint/unused_method_argument.yml
index 8c23a6ae84b..a4e48b35248 100644
--- a/.rubocop_todo/lint/unused_method_argument.yml
+++ b/.rubocop_todo/lint/unused_method_argument.yml
@@ -19,7 +19,6 @@ Lint/UnusedMethodArgument:
- 'app/graphql/mutations/base_mutation.rb'
- 'app/graphql/mutations/ci/runner/delete.rb'
- 'app/graphql/mutations/concerns/mutations/assignable.rb'
- - 'app/graphql/mutations/members/groups/bulk_update.rb'
- 'app/graphql/mutations/notes/create/base.rb'
- 'app/graphql/mutations/notes/create/diff_note.rb'
- 'app/graphql/mutations/notes/create/image_diff_note.rb'
diff --git a/.rubocop_todo/style/mutable_constant.yml b/.rubocop_todo/style/mutable_constant.yml
index 2409d4f3521..8e6a0a2335b 100644
--- a/.rubocop_todo/style/mutable_constant.yml
+++ b/.rubocop_todo/style/mutable_constant.yml
@@ -5,7 +5,6 @@ Style/MutableConstant:
Exclude:
- 'app/finders/group_members_finder.rb'
- 'app/graphql/mutations/container_repositories/destroy_tags.rb'
- - 'app/graphql/mutations/members/groups/bulk_update.rb'
- 'app/graphql/mutations/packages/bulk_destroy.rb'
- 'app/helpers/blame_helper.rb'
- 'app/models/ci/build_trace_chunks/redis_base.rb'
diff --git a/app/assets/javascripts/syntax_highlight.js b/app/assets/javascripts/syntax_highlight.js
index cb2bf24abc7..065e1080897 100644
--- a/app/assets/javascripts/syntax_highlight.js
+++ b/app/assets/javascripts/syntax_highlight.js
@@ -15,6 +15,10 @@ export default function syntaxHighlight($els = null) {
const els = $els.get ? $els.get() : $els;
const handler = (el) => {
+ if (el.classList === undefined) {
+ return el;
+ }
+
if (el.classList.contains('js-syntax-highlight')) {
// Given the element itself, apply highlighting
return el.classList.add(gon.user_color_scheme);
diff --git a/app/graphql/mutations/members/bulk_update_base.rb b/app/graphql/mutations/members/bulk_update_base.rb
new file mode 100644
index 00000000000..1e0208e864d
--- /dev/null
+++ b/app/graphql/mutations/members/bulk_update_base.rb
@@ -0,0 +1,88 @@
+# frozen_string_literal: true
+
+module Mutations
+ module Members
+ class BulkUpdateBase < BaseMutation
+ include ::API::Helpers::MembersHelpers
+
+ argument :user_ids,
+ [::Types::GlobalIDType[::User]],
+ required: true,
+ description: 'Global IDs of the members.'
+
+ argument :access_level,
+ ::Types::MemberAccessLevelEnum,
+ required: true,
+ description: 'Access level to update the members to.'
+
+ argument :expires_at,
+ Types::TimeType,
+ required: false,
+ description: 'Date and time the membership expires.'
+
+ MAX_MEMBERS_UPDATE_LIMIT = 50
+ MAX_MEMBERS_UPDATE_ERROR = "Count of members to be updated should be less than #{MAX_MEMBERS_UPDATE_LIMIT}."
+ .freeze
+ INVALID_MEMBERS_ERROR = 'Only access level of direct members can be updated.'
+
+ def resolve(**args)
+ result = ::Members::UpdateService
+ .new(current_user, args.except(:user_ids, source_id_param_name))
+ .execute(@updatable_members)
+
+ {
+ source_members_key => result[:members],
+ errors: Array.wrap(result[:message])
+ }
+ rescue Gitlab::Access::AccessDeniedError
+ {
+ errors: ["Unable to update members, please check user permissions."]
+ }
+ end
+
+ private
+
+ def ready?(**args)
+ source = authorized_find!(source_id: args[source_id_param_name])
+ user_ids = args.fetch(:user_ids, {}).map(&:model_id)
+ @updatable_members = only_direct_members(source, user_ids)
+
+ if @updatable_members.size > MAX_MEMBERS_UPDATE_LIMIT
+ raise Gitlab::Graphql::Errors::InvalidMemberCountError, MAX_MEMBERS_UPDATE_ERROR
+ end
+
+ if @updatable_members.size != user_ids.size
+ raise Gitlab::Graphql::Errors::InvalidMembersError, INVALID_MEMBERS_ERROR
+ end
+
+ super
+ end
+
+ def find_object(source_id:)
+ GitlabSchema.object_from_id(source_id, expected_type: source_type)
+ end
+
+ def only_direct_members(source, user_ids)
+ source_members(source)
+ .with_user(user_ids)
+ .to_a
+ end
+
+ def source_id_param_name
+ "#{source_name}_id".to_sym
+ end
+
+ def source_members_key
+ "#{source_name}_members".to_sym
+ end
+
+ def source_name
+ source_type.name.downcase
+ end
+
+ def source_type
+ raise NotImplementedError
+ end
+ end
+ end
+end
diff --git a/app/graphql/mutations/members/groups/bulk_update.rb b/app/graphql/mutations/members/groups/bulk_update.rb
index d0b19bd9634..fe3c7521c20 100644
--- a/app/graphql/mutations/members/groups/bulk_update.rb
+++ b/app/graphql/mutations/members/groups/bulk_update.rb
@@ -3,81 +3,22 @@
module Mutations
module Members
module Groups
- class BulkUpdate < ::Mutations::BaseMutation
+ class BulkUpdate < BulkUpdateBase
graphql_name 'GroupMemberBulkUpdate'
-
- include Gitlab::Utils::StrongMemoize
-
authorize :admin_group_member
field :group_members,
- [Types::GroupMemberType],
- null: true,
- description: 'Group members after mutation.'
+ [Types::GroupMemberType],
+ null: true,
+ description: 'Group members after mutation.'
argument :group_id,
- ::Types::GlobalIDType[::Group],
- required: true,
- description: 'Global ID of the group.'
-
- argument :user_ids,
- [::Types::GlobalIDType[::User]],
- required: true,
- description: 'Global IDs of the group members.'
-
- argument :access_level,
- ::Types::MemberAccessLevelEnum,
- required: true,
- description: 'Access level to update the members to.'
-
- argument :expires_at,
- Types::TimeType,
- required: false,
- description: 'Date and time the membership expires.'
-
- MAX_MEMBERS_UPDATE_LIMIT = 50
- MAX_MEMBERS_UPDATE_ERROR = "Count of members to be updated should be less than #{MAX_MEMBERS_UPDATE_LIMIT}."
- INVALID_MEMBERS_ERROR = 'Only access level of direct members can be updated.'
-
- def resolve(group_id:, **args)
- result = ::Members::UpdateService.new(current_user, args.except(:user_ids)).execute(@updatable_group_members)
-
- {
- group_members: result[:members],
- errors: Array.wrap(result[:message])
- }
- rescue Gitlab::Access::AccessDeniedError
- {
- errors: ["Unable to update members, please check user permissions."]
- }
- end
-
- private
-
- def ready?(**args)
- group = authorized_find!(group_id: args[:group_id])
- user_ids = args.fetch(:user_ids, {}).map(&:model_id)
- @updatable_group_members = only_direct_group_members(group, user_ids)
-
- if @updatable_group_members.size > MAX_MEMBERS_UPDATE_LIMIT
- raise Gitlab::Graphql::Errors::InvalidMemberCountError, MAX_MEMBERS_UPDATE_ERROR
- end
-
- if @updatable_group_members.size != user_ids.size
- raise Gitlab::Graphql::Errors::InvalidMembersError, INVALID_MEMBERS_ERROR
- end
-
- super
- end
-
- def find_object(group_id:)
- GitlabSchema.object_from_id(group_id, expected_type: ::Group)
- end
+ ::Types::GlobalIDType[::Group],
+ required: true,
+ description: 'Global ID of the group.'
- def only_direct_group_members(group, user_ids)
- group
- .members
- .with_user(user_ids).to_a
+ def source_type
+ ::Group
end
end
end
diff --git a/app/graphql/mutations/members/projects/bulk_update.rb b/app/graphql/mutations/members/projects/bulk_update.rb
new file mode 100644
index 00000000000..cfb88e60c44
--- /dev/null
+++ b/app/graphql/mutations/members/projects/bulk_update.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+module Mutations
+ module Members
+ module Projects
+ class BulkUpdate < BulkUpdateBase
+ graphql_name 'ProjectMemberBulkUpdate'
+ authorize :admin_project_member
+
+ field :project_members,
+ [Types::ProjectMemberType],
+ null: true,
+ description: 'Project members after mutation.'
+
+ argument :project_id,
+ ::Types::GlobalIDType[::Project],
+ required: true,
+ description: 'Global ID of the project.'
+
+ def source_type
+ ::Project
+ end
+ end
+ end
+ end
+end
diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb
index 08ac6d7f658..108c55f1292 100644
--- a/app/graphql/types/mutation_type.rb
+++ b/app/graphql/types/mutation_type.rb
@@ -70,6 +70,7 @@ module Types
mount_mutation Mutations::Issues::BulkUpdate, alpha: { milestone: '15.9' }
mount_mutation Mutations::Labels::Create
mount_mutation Mutations::Members::Groups::BulkUpdate
+ mount_mutation Mutations::Members::Projects::BulkUpdate
mount_mutation Mutations::MergeRequests::Accept
mount_mutation Mutations::MergeRequests::Create
mount_mutation Mutations::MergeRequests::Update
diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb
index e0a1697cfa9..c5df53ec606 100644
--- a/app/helpers/diff_helper.rb
+++ b/app/helpers/diff_helper.rb
@@ -34,6 +34,12 @@ module DiffHelper
options[:expanded] = true
options[:paths] = params.values_at(:old_path, :new_path)
options[:use_extra_viewer_as_main] = false
+
+ if Feature.enabled?(:large_ipynb_diffs, @project) && params[:file_identifier]&.include?('.ipynb')
+ options[:max_patch_bytes_for_file_extension] = {
+ '.ipynb' => 1.megabyte
+ }
+ end
end
options
diff --git a/app/views/projects/compare/index.html.haml b/app/views/projects/compare/index.html.haml
index b3590eea631..58da76a3231 100644
--- a/app/views/projects/compare/index.html.haml
+++ b/app/views/projects/compare/index.html.haml
@@ -1,5 +1,5 @@
-- breadcrumb_title _("Compare Revisions")
-- page_title _("Compare")
+- breadcrumb_title _("Compare revisions")
+- page_title _("Compare revisions")
%h1.page-title.gl-font-size-h-display
= _("Compare Git revisions")
diff --git a/app/views/projects/compare/show.html.haml b/app/views/projects/compare/show.html.haml
index 1bdf3d1e6e3..bc378182057 100644
--- a/app/views/projects/compare/show.html.haml
+++ b/app/views/projects/compare/show.html.haml
@@ -1,4 +1,4 @@
-- add_to_breadcrumbs _("Compare Revisions"), project_compare_index_path(@project)
+- add_to_breadcrumbs _("Compare revisions"), project_compare_index_path(@project)
- page_title "#{params[:from]}...#{params[:to]}"
.sub-header-block.gl-border-b-0.gl-mb-0
diff --git a/app/views/projects/graphs/show.html.haml b/app/views/projects/graphs/show.html.haml
index 754de2db8f3..9d6f67bd190 100644
--- a/app/views/projects/graphs/show.html.haml
+++ b/app/views/projects/graphs/show.html.haml
@@ -1,4 +1,4 @@
-- page_title _('Contributors')
+- page_title _('Contributor statistics')
- graph_path = project_graph_path(@project, current_ref, ref_type: @ref_type, format: :json)
- commits_path = project_commits_path(@project, current_ref, ref_type: @ref_type)
diff --git a/config/feature_flags/development/large_ipynb_diffs.yml b/config/feature_flags/development/large_ipynb_diffs.yml
new file mode 100644
index 00000000000..fd1f8f487e6
--- /dev/null
+++ b/config/feature_flags/development/large_ipynb_diffs.yml
@@ -0,0 +1,8 @@
+---
+name: large_ipynb_diffs
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/113370
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/393886
+milestone: '15.10'
+type: development
+group: group::incubation
+default_enabled: false
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 701070b11d7..5ab6c40960f 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -3185,7 +3185,7 @@ Input type: `GroupMemberBulkUpdateInput`
| <a id="mutationgroupmemberbulkupdateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationgroupmemberbulkupdateexpiresat"></a>`expiresAt` | [`Time`](#time) | Date and time the membership expires. |
| <a id="mutationgroupmemberbulkupdategroupid"></a>`groupId` | [`GroupID!`](#groupid) | Global ID of the group. |
-| <a id="mutationgroupmemberbulkupdateuserids"></a>`userIds` | [`[UserID!]!`](#userid) | Global IDs of the group members. |
+| <a id="mutationgroupmemberbulkupdateuserids"></a>`userIds` | [`[UserID!]!`](#userid) | Global IDs of the members. |
#### Fields
@@ -4715,6 +4715,28 @@ Input type: `ProjectInitializeProductAnalyticsInput`
| <a id="mutationprojectinitializeproductanalyticserrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
| <a id="mutationprojectinitializeproductanalyticsproject"></a>`project` | [`Project`](#project) | Project on which the initialization took place. |
+### `Mutation.projectMemberBulkUpdate`
+
+Input type: `ProjectMemberBulkUpdateInput`
+
+#### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationprojectmemberbulkupdateaccesslevel"></a>`accessLevel` | [`MemberAccessLevel!`](#memberaccesslevel) | Access level to update the members to. |
+| <a id="mutationprojectmemberbulkupdateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationprojectmemberbulkupdateexpiresat"></a>`expiresAt` | [`Time`](#time) | Date and time the membership expires. |
+| <a id="mutationprojectmemberbulkupdateprojectid"></a>`projectId` | [`ProjectID!`](#projectid) | Global ID of the project. |
+| <a id="mutationprojectmemberbulkupdateuserids"></a>`userIds` | [`[UserID!]!`](#userid) | Global IDs of the members. |
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationprojectmemberbulkupdateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationprojectmemberbulkupdateerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
+| <a id="mutationprojectmemberbulkupdateprojectmembers"></a>`projectMembers` | [`[ProjectMember!]`](#projectmember) | Project members after mutation. |
+
### `Mutation.projectSetComplianceFramework`
Assign (or unset) a compliance framework to a project.
diff --git a/doc/architecture/blueprints/search/code_search_with_zoekt.md b/doc/architecture/blueprints/code_search_with_zoekt/index.md
index ca74460b98a..ca74460b98a 100644
--- a/doc/architecture/blueprints/search/code_search_with_zoekt.md
+++ b/doc/architecture/blueprints/code_search_with_zoekt/index.md
diff --git a/doc/user/project/file_lock.md b/doc/user/project/file_lock.md
index d6351483b60..b83feda0c96 100644
--- a/doc/user/project/file_lock.md
+++ b/doc/user/project/file_lock.md
@@ -221,7 +221,7 @@ To view the user who locked the file (if it was not you), hover over the button.
To view and remove file locks:
1. On the top bar, select **Main menu > Projects** and find your project.
-1. On the left sidebar, select **Repository > Locked Files**.
+1. On the left sidebar, select **Repository > Locked files**.
This list shows all the files locked either through LFS or GitLab UI.
diff --git a/doc/user/project/repository/branches/index.md b/doc/user/project/repository/branches/index.md
index 8169956c02e..13ee6fcdc91 100644
--- a/doc/user/project/repository/branches/index.md
+++ b/doc/user/project/repository/branches/index.md
@@ -62,7 +62,7 @@ issue number. GitLab uses the issue number to import data into the merge request
To compare branches in a repository:
1. On the top bar, select **Main menu > Projects** and find your project.
-1. On the left sidebar, select **Repository > Compare**.
+1. On the left sidebar, select **Repository > Compare revisions**.
1. Select the **Source** branch to search for your desired branch. Exact matches are
shown first. You can refine your search with operators:
- `^` matches the beginning of the branch name: `^feat` matches `feat/user-authentication`.
diff --git a/doc/user/project/repository/index.md b/doc/user/project/repository/index.md
index 5b4e1b14489..1d32dd3973d 100644
--- a/doc/user/project/repository/index.md
+++ b/doc/user/project/repository/index.md
@@ -235,9 +235,9 @@ The size can differ slightly from one instance to another due to compression, ho
Administrators can set a [repository size limit](../../admin_area/settings/account_and_limit_settings.md).
[GitLab sets the size limits for GitLab.com](../../gitlab_com/index.md#account-and-limit-settings).
-## Repository contributor graph
+## Repository contributor statistics
-All code contributors are displayed under your project's **Repository > Contributors**.
+All code contributors are displayed under your project's **Repository > Contributor statistics**.
The graph shows the contributor with the most commits to the fewest.
diff --git a/lib/gitlab/git/diff_collection.rb b/lib/gitlab/git/diff_collection.rb
index 0ffe8bee953..b4dd880ceb7 100644
--- a/lib/gitlab/git/diff_collection.rb
+++ b/lib/gitlab/git/diff_collection.rb
@@ -24,6 +24,8 @@ module Gitlab
limits[:safe_max_lines] = [limits[:max_lines], defaults[:max_lines]].min
limits[:safe_max_bytes] = limits[:safe_max_files] * 5.kilobytes # Average 5 KB per file
limits[:max_patch_bytes] = Gitlab::Git::Diff.patch_hard_limit_bytes
+ limits[:max_patch_bytes_for_file_extension] = options.fetch(:max_patch_bytes_for_file_extension, {})
+
limits
end
diff --git a/lib/sidebars/projects/menus/repository_menu.rb b/lib/sidebars/projects/menus/repository_menu.rb
index ec91ae741fe..5bfc9e727ff 100644
--- a/lib/sidebars/projects/menus/repository_menu.rb
+++ b/lib/sidebars/projects/menus/repository_menu.rb
@@ -92,7 +92,7 @@ module Sidebars
link = project_graph_path(context.project, context.current_ref, ref_type: ref_type_from_context(context))
::Sidebars::MenuItem.new(
- title: _('Contributors'),
+ title: _('Contributor statistics'),
link: link,
active_routes: { path: 'graphs#show' },
item_id: :contributors
@@ -112,7 +112,7 @@ module Sidebars
def compare_menu_item
::Sidebars::MenuItem.new(
- title: _('Compare'),
+ title: _('Compare revisions'),
link: project_compare_index_path(context.project, from: context.project.repository.root_ref, to: context.current_ref),
active_routes: { controller: :compare },
item_id: :compare
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 29eb4f9dd47..f58b7d5124a 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -10390,9 +10390,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10405,6 +10402,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -11401,7 +11401,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -25756,9 +25756,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
diff --git a/qa/qa/page/project/sub_menus/repository.rb b/qa/qa/page/project/sub_menus/repository.rb
index f9d55c0009c..b8ebaa10a49 100644
--- a/qa/qa/page/project/sub_menus/repository.rb
+++ b/qa/qa/page/project/sub_menus/repository.rb
@@ -40,7 +40,7 @@ module QA
def go_to_repository_contributors
hover_repository do
within_submenu do
- click_element(:sidebar_menu_item_link, menu_item: 'Contributors')
+ click_element(:sidebar_menu_item_link, menu_item: 'Contributor statistics')
end
end
end
diff --git a/qa/qa/specs/features/browser_ui/3_create/web_ide/server_hooks_custom_error_message_spec.rb b/qa/qa/specs/features/browser_ui/3_create/web_ide/server_hooks_custom_error_message_spec.rb
index 080832990c9..8082c54a6ee 100644
--- a/qa/qa/specs/features/browser_ui/3_create/web_ide/server_hooks_custom_error_message_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/web_ide/server_hooks_custom_error_message_spec.rb
@@ -1,13 +1,8 @@
# frozen_string_literal: true
+# TODO: remove this test when 'vscode_web_ide' feature flag is default enabled
module QA
- RSpec.describe 'Create', :skip_live_env, except: { job: 'review-qa-*' },
- feature_flag: { name: 'vscode_web_ide', scope: :global },
- product_group: :editor,
- quarantine: {
- issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/387928',
- type: :stale
- } do
+ RSpec.describe 'Create', :skip_live_env, except: { job: 'review-qa-*' }, product_group: :editor do
describe 'Git Server Hooks' do
let(:file_path) { File.join(Runtime::Path.fixtures_path, 'web_ide', 'README.md') }
@@ -20,15 +15,10 @@ module QA
end
before do
- Runtime::Feature.disable(:vscode_web_ide)
Flow::Login.sign_in
project.visit!
end
- after do
- Runtime::Feature.enable(:vscode_web_ide)
- end
-
context 'with custom error messages' do
it 'renders preconfigured error message when user hook failed on commit in WebIDE',
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/364751' do
diff --git a/spec/features/merge_request/user_sees_real_time_reviewers_spec.rb b/spec/features/merge_request/user_sees_real_time_reviewers_spec.rb
new file mode 100644
index 00000000000..e967787d2c7
--- /dev/null
+++ b/spec/features/merge_request/user_sees_real_time_reviewers_spec.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Merge request > Real-time reviewers', feature_category: :code_review_workflow do
+ let_it_be(:project) { create(:project, :public, :repository) }
+ let(:user) { project.creator }
+ let(:merge_request) { create(:merge_request, :simple, source_project: project, author: user) }
+
+ before do
+ sign_in(user)
+ visit project_merge_request_path(project, merge_request)
+ end
+
+ it 'updates in real-time', :js do
+ wait_for_requests
+
+ # Simulate a real-time update of reviewers
+ merge_request.update!(reviewer_ids: [user.id])
+ GraphqlTriggers.merge_request_reviewers_updated(merge_request)
+
+ expect(find('.reviewer')).to have_content(user.name)
+ end
+end
diff --git a/spec/frontend/access_tokens/components/new_access_token_app_spec.js b/spec/frontend/access_tokens/components/new_access_token_app_spec.js
index e4313bdfa26..753e693cc85 100644
--- a/spec/frontend/access_tokens/components/new_access_token_app_spec.js
+++ b/spec/frontend/access_tokens/components/new_access_token_app_spec.js
@@ -4,12 +4,12 @@ import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
import { mountExtended } from 'helpers/vue_test_utils_helper';
import NewAccessTokenApp from '~/access_tokens/components/new_access_token_app.vue';
import { EVENT_ERROR, EVENT_SUCCESS, FORM_SELECTOR } from '~/access_tokens/components/constants';
-import { createAlert, VARIANT_INFO } from '~/flash';
+import { createAlert, VARIANT_INFO } from '~/alert';
import { __, sprintf } from '~/locale';
import DomElementListener from '~/vue_shared/components/dom_element_listener.vue';
import InputCopyToggleVisibility from '~/vue_shared/components/form/input_copy_toggle_visibility.vue';
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('~/access_tokens/components/new_access_token_app', () => {
let wrapper;
diff --git a/spec/frontend/contributors/store/actions_spec.js b/spec/frontend/contributors/store/actions_spec.js
index 72b22548aa2..a15b9ad2978 100644
--- a/spec/frontend/contributors/store/actions_spec.js
+++ b/spec/frontend/contributors/store/actions_spec.js
@@ -2,11 +2,11 @@ import MockAdapter from 'axios-mock-adapter';
import testAction from 'helpers/vuex_action_helper';
import * as actions from '~/contributors/stores/actions';
import * as types from '~/contributors/stores/mutation_types';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { HTTP_STATUS_BAD_REQUEST, HTTP_STATUS_OK } from '~/lib/utils/http_status';
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('Contributors store actions', () => {
describe('fetchChartData', () => {
@@ -38,7 +38,7 @@ describe('Contributors store actions', () => {
);
});
- it('should show flash on API error', async () => {
+ it('should show alert on API error', async () => {
mock.onGet().reply(HTTP_STATUS_BAD_REQUEST, 'Not Found');
await testAction(
diff --git a/spec/frontend/deploy_freeze/store/actions_spec.js b/spec/frontend/deploy_freeze/store/actions_spec.js
index cd823e1fc28..d39577baa59 100644
--- a/spec/frontend/deploy_freeze/store/actions_spec.js
+++ b/spec/frontend/deploy_freeze/store/actions_spec.js
@@ -4,14 +4,14 @@ import Api from '~/api';
import * as actions from '~/deploy_freeze/store/actions';
import * as types from '~/deploy_freeze/store/mutation_types';
import getInitialState from '~/deploy_freeze/store/state';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import * as logger from '~/lib/logger';
import axios from '~/lib/utils/axios_utils';
import { freezePeriodsFixture } from '../helpers';
import { timezoneDataFixture } from '../../vue_shared/components/timezone_dropdown/helpers';
jest.mock('~/api.js');
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('deploy freeze store actions', () => {
const freezePeriodFixture = freezePeriodsFixture[0];
diff --git a/spec/frontend/filtered_search/filtered_search_manager_spec.js b/spec/frontend/filtered_search/filtered_search_manager_spec.js
index 26af7af701b..8c16ff100eb 100644
--- a/spec/frontend/filtered_search/filtered_search_manager_spec.js
+++ b/spec/frontend/filtered_search/filtered_search_manager_spec.js
@@ -8,11 +8,11 @@ import IssuableFilteredSearchTokenKeys from '~/filtered_search/issuable_filtered
import RecentSearchesRoot from '~/filtered_search/recent_searches_root';
import RecentSearchesService from '~/filtered_search/services/recent_searches_service';
import RecentSearchesServiceError from '~/filtered_search/services/recent_searches_service_error';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { BACKSPACE_KEY_CODE, DELETE_KEY_CODE } from '~/lib/utils/keycodes';
import { visitUrl, getParameterByName } from '~/lib/utils/url_utility';
-jest.mock('~/flash');
+jest.mock('~/alert');
jest.mock('~/lib/utils/url_utility', () => ({
...jest.requireActual('~/lib/utils/url_utility'),
getParameterByName: jest.fn(),
diff --git a/spec/frontend/filtered_search/visual_token_value_spec.js b/spec/frontend/filtered_search/visual_token_value_spec.js
index d3fa8fae9ab..138a4e183a9 100644
--- a/spec/frontend/filtered_search/visual_token_value_spec.js
+++ b/spec/frontend/filtered_search/visual_token_value_spec.js
@@ -5,11 +5,11 @@ import FilteredSearchSpecHelper from 'helpers/filtered_search_spec_helper';
import { TEST_HOST } from 'helpers/test_constants';
import DropdownUtils from '~/filtered_search/dropdown_utils';
import VisualTokenValue from '~/filtered_search/visual_token_value';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import AjaxCache from '~/lib/utils/ajax_cache';
import UsersCache from '~/lib/utils/users_cache';
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('Filtered Search Visual Tokens', () => {
const findElements = (tokenElement) => {
diff --git a/spec/frontend/groups/components/app_spec.js b/spec/frontend/groups/components/app_spec.js
index 4e6ddd89a55..ec397cc44f9 100644
--- a/spec/frontend/groups/components/app_spec.js
+++ b/spec/frontend/groups/components/app_spec.js
@@ -3,7 +3,7 @@ import AxiosMockAdapter from 'axios-mock-adapter';
import Vue, { nextTick } from 'vue';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import appComponent from '~/groups/components/app.vue';
import groupFolderComponent from '~/groups/components/group_folder.vue';
import groupItemComponent from '~/groups/components/group_item.vue';
@@ -34,7 +34,7 @@ import {
const $toast = {
show: jest.fn(),
};
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('AppComponent', () => {
let wrapper;
@@ -117,7 +117,7 @@ describe('AppComponent', () => {
});
});
- it('should show flash error when request fails', () => {
+ it('should show alert error when request fails', () => {
mock.onGet('/dashboard/groups.json').reply(HTTP_STATUS_BAD_REQUEST);
jest.spyOn(window, 'scrollTo').mockImplementation(() => {});
@@ -325,7 +325,7 @@ describe('AppComponent', () => {
});
});
- it('should show error flash message if request failed to leave group', () => {
+ it('should show error alert message if request failed to leave group', () => {
const message = 'An error occurred. Please try again.';
jest
.spyOn(vm.service, 'leaveGroup')
@@ -342,7 +342,7 @@ describe('AppComponent', () => {
});
});
- it('should show appropriate error flash message if request forbids to leave group', () => {
+ it('should show appropriate error alert message if request forbids to leave group', () => {
const message = 'Failed to leave the group. Please make sure you are not the only owner.';
jest.spyOn(vm.service, 'leaveGroup').mockRejectedValue({ status: HTTP_STATUS_FORBIDDEN });
jest.spyOn(vm.store, 'removeGroup');
diff --git a/spec/frontend/groups/components/group_name_and_path_spec.js b/spec/frontend/groups/components/group_name_and_path_spec.js
index 9965b608f27..0a18e657c94 100644
--- a/spec/frontend/groups/components/group_name_and_path_spec.js
+++ b/spec/frontend/groups/components/group_name_and_path_spec.js
@@ -7,11 +7,11 @@ import waitForPromises from 'helpers/wait_for_promises';
import createMockApollo from 'helpers/mock_apollo_helper';
import GroupNameAndPath from '~/groups/components/group_name_and_path.vue';
import { getGroupPathAvailability } from '~/rest_api';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { helpPagePath } from '~/helpers/help_page_helper';
import searchGroupsWhereUserCanCreateSubgroups from '~/groups/queries/search_groups_where_user_can_create_subgroups.query.graphql';
-jest.mock('~/flash');
+jest.mock('~/alert');
jest.mock('~/rest_api', () => ({
getGroupPathAvailability: jest.fn(),
}));
diff --git a/spec/frontend/header_search/store/actions_spec.js b/spec/frontend/header_search/store/actions_spec.js
index bd93b0edadf..95a619ebeca 100644
--- a/spec/frontend/header_search/store/actions_spec.js
+++ b/spec/frontend/header_search/store/actions_spec.js
@@ -16,7 +16,7 @@ import {
MOCK_ISSUE_PATH,
} from '../mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('Header Search Store Actions', () => {
let state;
diff --git a/spec/frontend/issuable/related_issues/components/related_issues_root_spec.js b/spec/frontend/issuable/related_issues/components/related_issues_root_spec.js
index 96c0b87e2cb..337a7c9a175 100644
--- a/spec/frontend/issuable/related_issues/components/related_issues_root_spec.js
+++ b/spec/frontend/issuable/related_issues/components/related_issues_root_spec.js
@@ -7,7 +7,7 @@ import {
issuable1,
issuable2,
} from 'jest/issuable/components/related_issuable_mock_data';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import {
HTTP_STATUS_CONFLICT,
@@ -19,7 +19,7 @@ import RelatedIssuesBlock from '~/related_issues/components/related_issues_block
import RelatedIssuesRoot from '~/related_issues/components/related_issues_root.vue';
import relatedIssuesService from '~/related_issues/services/related_issues_service';
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('RelatedIssuesRoot', () => {
let wrapper;
diff --git a/spec/frontend/merge_request_spec.js b/spec/frontend/merge_request_spec.js
index 579cee8c022..be16b5ebfd2 100644
--- a/spec/frontend/merge_request_spec.js
+++ b/spec/frontend/merge_request_spec.js
@@ -3,12 +3,12 @@ import $ from 'jquery';
import { loadHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
import { TEST_HOST } from 'spec/test_constants';
import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { HTTP_STATUS_CONFLICT, HTTP_STATUS_OK } from '~/lib/utils/http_status';
import MergeRequest from '~/merge_request';
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('MergeRequest', () => {
const test = {};
diff --git a/spec/frontend/pipelines/components/jobs/failed_jobs_app_spec.js b/spec/frontend/pipelines/components/jobs/failed_jobs_app_spec.js
index d1da7cb3acf..24732e71d5d 100644
--- a/spec/frontend/pipelines/components/jobs/failed_jobs_app_spec.js
+++ b/spec/frontend/pipelines/components/jobs/failed_jobs_app_spec.js
@@ -4,7 +4,7 @@ import Vue from 'vue';
import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import FailedJobsApp from '~/pipelines/components/jobs/failed_jobs_app.vue';
import FailedJobsTable from '~/pipelines/components/jobs/failed_jobs_table.vue';
import GetFailedJobsQuery from '~/pipelines/graphql/queries/get_failed_jobs.query.graphql';
@@ -12,7 +12,7 @@ import { mockFailedJobsQueryResponse, mockFailedJobsSummaryData } from '../../mo
Vue.use(VueApollo);
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('Failed Jobs App', () => {
let wrapper;
diff --git a/spec/frontend/pipelines/components/jobs/failed_jobs_table_spec.js b/spec/frontend/pipelines/components/jobs/failed_jobs_table_spec.js
index 0df15afd70d..e2bb8906128 100644
--- a/spec/frontend/pipelines/components/jobs/failed_jobs_table_spec.js
+++ b/spec/frontend/pipelines/components/jobs/failed_jobs_table_spec.js
@@ -4,7 +4,7 @@ import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import { mountExtended } from 'helpers/vue_test_utils_helper';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { redirectTo } from '~/lib/utils/url_utility';
import FailedJobsTable from '~/pipelines/components/jobs/failed_jobs_table.vue';
import RetryFailedJobMutation from '~/pipelines/graphql/mutations/retry_failed_job.mutation.graphql';
@@ -15,7 +15,7 @@ import {
mockPreparedFailedJobsDataNoPermission,
} from '../../mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
jest.mock('~/lib/utils/url_utility');
Vue.use(VueApollo);
diff --git a/spec/frontend/pipelines/components/jobs/jobs_app_spec.js b/spec/frontend/pipelines/components/jobs/jobs_app_spec.js
index 9bc14266593..26dee132690 100644
--- a/spec/frontend/pipelines/components/jobs/jobs_app_spec.js
+++ b/spec/frontend/pipelines/components/jobs/jobs_app_spec.js
@@ -4,7 +4,7 @@ import Vue from 'vue';
import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import JobsApp from '~/pipelines/components/jobs/jobs_app.vue';
import JobsTable from '~/jobs/components/table/jobs_table.vue';
import getPipelineJobsQuery from '~/pipelines/graphql/queries/get_pipeline_jobs.query.graphql';
@@ -12,7 +12,7 @@ import { mockPipelineJobsQueryResponse } from '../../mock_data';
Vue.use(VueApollo);
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('Jobs app', () => {
let wrapper;
diff --git a/spec/frontend/pipelines/pipelines_actions_spec.js b/spec/frontend/pipelines/pipelines_actions_spec.js
index e034d52a33c..3b2a7c0a76d 100644
--- a/spec/frontend/pipelines/pipelines_actions_spec.js
+++ b/spec/frontend/pipelines/pipelines_actions_spec.js
@@ -5,7 +5,7 @@ import { nextTick } from 'vue';
import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
import waitForPromises from 'helpers/wait_for_promises';
import { TEST_HOST } from 'spec/test_constants';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { HTTP_STATUS_INTERNAL_SERVER_ERROR, HTTP_STATUS_OK } from '~/lib/utils/http_status';
import { confirmAction } from '~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal';
@@ -13,7 +13,7 @@ import PipelinesManualActions from '~/pipelines/components/pipelines_list/pipeli
import GlCountdown from '~/vue_shared/components/gl_countdown.vue';
import { TRACKING_CATEGORIES } from '~/pipelines/constants';
-jest.mock('~/flash');
+jest.mock('~/alert');
jest.mock('~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal');
describe('Pipelines Actions dropdown', () => {
diff --git a/spec/frontend/pipelines/pipelines_spec.js b/spec/frontend/pipelines/pipelines_spec.js
index 2523b901506..67478f9307f 100644
--- a/spec/frontend/pipelines/pipelines_spec.js
+++ b/spec/frontend/pipelines/pipelines_spec.js
@@ -11,7 +11,7 @@ import { mockTracking } from 'helpers/tracking_helper';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
import Api from '~/api';
-import { createAlert, VARIANT_WARNING } from '~/flash';
+import { createAlert, VARIANT_WARNING } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { HTTP_STATUS_INTERNAL_SERVER_ERROR, HTTP_STATUS_OK } from '~/lib/utils/http_status';
import NavigationControls from '~/pipelines/components/pipelines_list/nav_controls.vue';
@@ -25,7 +25,7 @@ import TablePagination from '~/vue_shared/components/pagination/table_pagination
import { stageReply, users, mockSearch, branches } from './mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
const mockProjectPath = 'twitter/flight';
const mockProjectId = '21';
diff --git a/spec/frontend/pipelines/test_reports/stores/actions_spec.js b/spec/frontend/pipelines/test_reports/stores/actions_spec.js
index e813a63a53f..e05d2151f0a 100644
--- a/spec/frontend/pipelines/test_reports/stores/actions_spec.js
+++ b/spec/frontend/pipelines/test_reports/stores/actions_spec.js
@@ -2,13 +2,13 @@ import MockAdapter from 'axios-mock-adapter';
import testReports from 'test_fixtures/pipelines/test_report.json';
import { TEST_HOST } from 'helpers/test_constants';
import testAction from 'helpers/vuex_action_helper';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
import * as actions from '~/pipelines/stores/test_reports/actions';
import * as types from '~/pipelines/stores/test_reports/mutation_types';
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('Actions TestReports Store', () => {
let mock;
@@ -49,7 +49,7 @@ describe('Actions TestReports Store', () => {
);
});
- it('should create flash on API error', async () => {
+ it('should create alert on API error', async () => {
await testAction(
actions.fetchSummary,
null,
diff --git a/spec/frontend/pipelines/test_reports/stores/mutations_spec.js b/spec/frontend/pipelines/test_reports/stores/mutations_spec.js
index 82c70c6db58..9c374ea817a 100644
--- a/spec/frontend/pipelines/test_reports/stores/mutations_spec.js
+++ b/spec/frontend/pipelines/test_reports/stores/mutations_spec.js
@@ -1,9 +1,9 @@
import testReports from 'test_fixtures/pipelines/test_report.json';
import * as types from '~/pipelines/stores/test_reports/mutation_types';
import mutations from '~/pipelines/stores/test_reports/mutations';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('Mutations TestReports Store', () => {
let mockState;
@@ -58,7 +58,7 @@ describe('Mutations TestReports Store', () => {
expect(mockState.errorMessage).toBe(message);
});
- it('should show a flash message otherwise', () => {
+ it('should show an alert message otherwise', () => {
mutations[types.SET_SUITE_ERROR](mockState, {});
expect(createAlert).toHaveBeenCalled();
diff --git a/spec/frontend/search/store/actions_spec.js b/spec/frontend/search/store/actions_spec.js
index 0f270ff2491..cf0d4492305 100644
--- a/spec/frontend/search/store/actions_spec.js
+++ b/spec/frontend/search/store/actions_spec.js
@@ -1,7 +1,7 @@
import MockAdapter from 'axios-mock-adapter';
import testAction from 'helpers/vuex_action_helper';
import Api from '~/api';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import * as logger from '~/lib/logger';
import axios from '~/lib/utils/axios_utils';
import { HTTP_STATUS_INTERNAL_SERVER_ERROR, HTTP_STATUS_OK } from '~/lib/utils/http_status';
@@ -33,7 +33,7 @@ import {
MOCK_AGGREGATIONS,
} from '../mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
jest.mock('~/lib/utils/url_utility', () => ({
setUrlParams: jest.fn(),
joinPaths: jest.fn().mockReturnValue(''),
@@ -47,7 +47,7 @@ describe('Global Search Store Actions', () => {
let mock;
let state;
- const flashCallback = (callCount) => {
+ const alertCallback = (callCount) => {
expect(createAlert).toHaveBeenCalledTimes(callCount);
createAlert.mockClear();
};
@@ -63,12 +63,12 @@ describe('Global Search Store Actions', () => {
});
describe.each`
- action | axiosMock | type | expectedMutations | flashCallCount
+ action | axiosMock | type | expectedMutations | alertCallCount
${actions.fetchGroups} | ${{ method: 'onGet', code: HTTP_STATUS_OK, res: MOCK_GROUPS }} | ${'success'} | ${[{ type: types.REQUEST_GROUPS }, { type: types.RECEIVE_GROUPS_SUCCESS, payload: MOCK_GROUPS }]} | ${0}
${actions.fetchGroups} | ${{ method: 'onGet', code: HTTP_STATUS_INTERNAL_SERVER_ERROR, res: null }} | ${'error'} | ${[{ type: types.REQUEST_GROUPS }, { type: types.RECEIVE_GROUPS_ERROR }]} | ${1}
${actions.fetchProjects} | ${{ method: 'onGet', code: HTTP_STATUS_OK, res: MOCK_PROJECTS }} | ${'success'} | ${[{ type: types.REQUEST_PROJECTS }, { type: types.RECEIVE_PROJECTS_SUCCESS, payload: MOCK_PROJECTS }]} | ${0}
${actions.fetchProjects} | ${{ method: 'onGet', code: HTTP_STATUS_INTERNAL_SERVER_ERROR, res: null }} | ${'error'} | ${[{ type: types.REQUEST_PROJECTS }, { type: types.RECEIVE_PROJECTS_ERROR }]} | ${1}
- `(`axios calls`, ({ action, axiosMock, type, expectedMutations, flashCallCount }) => {
+ `(`axios calls`, ({ action, axiosMock, type, expectedMutations, alertCallCount }) => {
describe(action.name, () => {
describe(`on ${type}`, () => {
beforeEach(() => {
@@ -76,7 +76,7 @@ describe('Global Search Store Actions', () => {
});
it(`should dispatch the correct mutations`, () => {
return testAction({ action, state, expectedMutations }).then(() =>
- flashCallback(flashCallCount),
+ alertCallback(alertCallCount),
);
});
});
@@ -84,12 +84,12 @@ describe('Global Search Store Actions', () => {
});
describe.each`
- action | axiosMock | type | expectedMutations | flashCallCount
+ action | axiosMock | type | expectedMutations | alertCallCount
${actions.loadFrequentGroups} | ${{ method: 'onGet', code: HTTP_STATUS_OK }} | ${'success'} | ${[PROMISE_ALL_EXPECTED_MUTATIONS.resGroups]} | ${0}
${actions.loadFrequentGroups} | ${{ method: 'onGet', code: HTTP_STATUS_INTERNAL_SERVER_ERROR }} | ${'error'} | ${[]} | ${1}
${actions.loadFrequentProjects} | ${{ method: 'onGet', code: HTTP_STATUS_OK }} | ${'success'} | ${[PROMISE_ALL_EXPECTED_MUTATIONS.resProjects]} | ${0}
${actions.loadFrequentProjects} | ${{ method: 'onGet', code: HTTP_STATUS_INTERNAL_SERVER_ERROR }} | ${'error'} | ${[]} | ${1}
- `('Promise.all calls', ({ action, axiosMock, type, expectedMutations, flashCallCount }) => {
+ `('Promise.all calls', ({ action, axiosMock, type, expectedMutations, alertCallCount }) => {
describe(action.name, () => {
describe(`on ${type}`, () => {
beforeEach(() => {
@@ -103,7 +103,7 @@ describe('Global Search Store Actions', () => {
it(`should dispatch the correct mutations`, () => {
return testAction({ action, state, expectedMutations }).then(() => {
- flashCallback(flashCallCount);
+ alertCallback(alertCallCount);
});
});
});
diff --git a/spec/frontend/vue_merge_request_widget/components/approvals/approvals_spec.js b/spec/frontend/vue_merge_request_widget/components/approvals/approvals_spec.js
index 80a7565cbee..e78e1be7882 100644
--- a/spec/frontend/vue_merge_request_widget/components/approvals/approvals_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/approvals/approvals_spec.js
@@ -6,7 +6,7 @@ import approvedByCurrentUser from 'test_fixtures/graphql/merge_requests/approval
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import Approvals from '~/vue_merge_request_widget/components/approvals/approvals.vue';
import ApprovalsSummary from '~/vue_merge_request_widget/components/approvals/approvals_summary.vue';
import ApprovalsSummaryOptional from '~/vue_merge_request_widget/components/approvals/approvals_summary_optional.vue';
@@ -21,7 +21,7 @@ import { createCanApproveResponse } from 'jest/approvals/mock_data';
Vue.use(VueApollo);
const mockAlertDismiss = jest.fn();
-jest.mock('~/flash', () => ({
+jest.mock('~/alert', () => ({
createAlert: jest.fn().mockImplementation(() => ({
dismiss: mockAlertDismiss,
})),
@@ -295,7 +295,7 @@ describe('MRWidget approvals', () => {
return nextTick();
});
- it('flashes error message', () => {
+ it('alerts error message', () => {
expect(createAlert).toHaveBeenCalledWith({ message: UNAPPROVE_ERROR });
});
});
diff --git a/spec/frontend/vue_merge_request_widget/components/states/work_in_progress_spec.js b/spec/frontend/vue_merge_request_widget/components/states/work_in_progress_spec.js
index e610ceb2122..43ce1769ff3 100644
--- a/spec/frontend/vue_merge_request_widget/components/states/work_in_progress_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/states/work_in_progress_spec.js
@@ -1,7 +1,7 @@
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import getStateQueryResponse from 'test_fixtures/graphql/merge_requests/get_state.query.graphql.json';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import WorkInProgress, {
MSG_SOMETHING_WENT_WRONG,
MSG_MARK_READY,
@@ -22,7 +22,7 @@ const TEST_MR_IID = '23';
const TEST_MR_TITLE = 'Test MR Title';
const TEST_PROJECT_PATH = 'lorem/ipsum';
-jest.mock('~/flash');
+jest.mock('~/alert');
jest.mock('~/merge_request');
describe('~/vue_merge_request_widget/components/states/work_in_progress.vue', () => {
diff --git a/spec/graphql/mutations/members/bulk_update_base_spec.rb b/spec/graphql/mutations/members/bulk_update_base_spec.rb
new file mode 100644
index 00000000000..61a27984824
--- /dev/null
+++ b/spec/graphql/mutations/members/bulk_update_base_spec.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Mutations::Members::BulkUpdateBase, feature_category: :subgroups do
+ include GraphqlHelpers
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:group) { create(:group).tap { |group| group.add_owner(user) } }
+
+ it 'raises a NotImplementedError error if the source_type method is called on the base class' do
+ mutation = described_class.new(context: { current_user: user }, object: nil, field: nil)
+
+ expect { mutation.resolve(group_id: group.to_gid.to_s) }.to raise_error(NotImplementedError)
+ end
+end
diff --git a/spec/helpers/diff_helper_spec.rb b/spec/helpers/diff_helper_spec.rb
index a46f8c13f00..2318bbf861a 100644
--- a/spec/helpers/diff_helper_spec.rb
+++ b/spec/helpers/diff_helper_spec.rb
@@ -47,6 +47,12 @@ RSpec.describe DiffHelper do
end
describe 'diff_options' do
+ let(:large_notebooks_enabled) { false }
+
+ before do
+ stub_feature_flags(large_ipynb_diffs: large_notebooks_enabled)
+ end
+
it 'returns no collapse false' do
expect(diff_options).to include(expanded: false)
end
@@ -56,21 +62,48 @@ RSpec.describe DiffHelper do
expect(diff_options).to include(expanded: true)
end
- it 'returns no collapse true if action name diff_for_path' do
- allow(controller).to receive(:action_name) { 'diff_for_path' }
- expect(diff_options).to include(expanded: true)
- end
+ context 'when action name is diff_for_path' do
+ before do
+ allow(controller).to receive(:action_name) { 'diff_for_path' }
+ end
- it 'returns paths if action name diff_for_path and param old path' do
- allow(controller).to receive(:params) { { old_path: 'lib/wadus.rb' } }
- allow(controller).to receive(:action_name) { 'diff_for_path' }
- expect(diff_options[:paths]).to include('lib/wadus.rb')
- end
+ it 'returns expanded true' do
+ expect(diff_options).to include(expanded: true)
+ end
- it 'returns paths if action name diff_for_path and param new path' do
- allow(controller).to receive(:params) { { new_path: 'lib/wadus.rb' } }
- allow(controller).to receive(:action_name) { 'diff_for_path' }
- expect(diff_options[:paths]).to include('lib/wadus.rb')
+ it 'returns paths if param old path' do
+ allow(controller).to receive(:params) { { old_path: 'lib/wadus.rb' } }
+ expect(diff_options[:paths]).to include('lib/wadus.rb')
+ end
+
+ it 'returns paths if param new path' do
+ allow(controller).to receive(:params) { { new_path: 'lib/wadus.rb' } }
+ expect(diff_options[:paths]).to include('lib/wadus.rb')
+ end
+
+ it 'does not set max_patch_bytes_for_file_extension' do
+ expect(diff_options[:max_patch_bytes_for_file_extension]).to be_nil
+ end
+
+ context 'when file_identifier include .ipynb' do
+ before do
+ allow(controller).to receive(:params) { { file_identifier: 'something.ipynb' } }
+ end
+
+ context 'when large_ipynb_diffs is disabled' do
+ it 'does not set max_patch_bytes_for_file_extension' do
+ expect(diff_options[:max_patch_bytes_for_file_extension]).to be_nil
+ end
+ end
+
+ context 'when large_ipynb_diffs is enabled' do
+ let(:large_notebooks_enabled) { true }
+
+ it 'sets max_patch_bytes_for_file_extension' do
+ expect(diff_options[:max_patch_bytes_for_file_extension]).to eq({ '.ipynb' => 1.megabyte })
+ end
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/git/diff_collection_spec.rb b/spec/lib/gitlab/git/diff_collection_spec.rb
index 7fa5bd8a92b..5fa0447091c 100644
--- a/spec/lib/gitlab/git/diff_collection_spec.rb
+++ b/spec/lib/gitlab/git/diff_collection_spec.rb
@@ -777,6 +777,26 @@ RSpec.describe Gitlab::Git::DiffCollection do
end
end
+ describe '.limits' do
+ let(:options) { {} }
+
+ subject { described_class.limits(options) }
+
+ context 'when options do not include max_patch_bytes_for_file_extension' do
+ it 'sets max_patch_bytes_for_file_extension as empty' do
+ expect(subject[:max_patch_bytes_for_file_extension]).to eq({})
+ end
+ end
+
+ context 'when options include max_patch_bytes_for_file_extension' do
+ let(:options) { { max_patch_bytes_for_file_extension: { '.file' => 1 } } }
+
+ it 'sets value for max_patch_bytes_for_file_extension' do
+ expect(subject[:max_patch_bytes_for_file_extension]).to eq({ '.file' => 1 })
+ end
+ end
+ end
+
def fake_diff(line_length, line_count)
{ 'diff' => "#{'a' * line_length}\n" * line_count }
end
diff --git a/spec/lib/sidebars/projects/menus/repository_menu_spec.rb b/spec/lib/sidebars/projects/menus/repository_menu_spec.rb
index 40ca2107698..b0631aacdb9 100644
--- a/spec/lib/sidebars/projects/menus/repository_menu_spec.rb
+++ b/spec/lib/sidebars/projects/menus/repository_menu_spec.rb
@@ -85,7 +85,7 @@ RSpec.describe Sidebars::Projects::Menus::RepositoryMenu, feature_category: :sou
end
end
- describe 'Contributors' do
+ describe 'Contributor statistics' do
let_it_be(:item_id) { :contributors }
context 'when analytics is disabled' do
diff --git a/spec/requests/api/graphql/mutations/members/groups/bulk_update_spec.rb b/spec/requests/api/graphql/mutations/members/groups/bulk_update_spec.rb
index ad70129a7bc..f15b52f53a3 100644
--- a/spec/requests/api/graphql/mutations/members/groups/bulk_update_spec.rb
+++ b/spec/requests/api/graphql/mutations/members/groups/bulk_update_spec.rb
@@ -5,126 +5,14 @@ require 'spec_helper'
RSpec.describe 'GroupMemberBulkUpdate', feature_category: :subgroups do
include GraphqlHelpers
- let_it_be(:current_user) { create(:user) }
- let_it_be(:user1) { create(:user) }
- let_it_be(:user2) { create(:user) }
- let_it_be(:group) { create(:group) }
- let_it_be(:group_member1) { create(:group_member, group: group, user: user1) }
- let_it_be(:group_member2) { create(:group_member, group: group, user: user2) }
+ let_it_be(:parent_group) { create(:group) }
+ let_it_be(:parent_group_member) { create(:group_member, group: parent_group) }
+ let_it_be(:group) { create(:group, parent: parent_group) }
+ let_it_be(:source) { group }
+ let_it_be(:member_type) { :group_member }
let_it_be(:mutation_name) { :group_member_bulk_update }
+ let_it_be(:source_id_key) { 'group_id' }
+ let_it_be(:response_member_field) { 'groupMembers' }
- let(:input) do
- {
- 'group_id' => group.to_global_id.to_s,
- 'user_ids' => [user1.to_global_id.to_s, user2.to_global_id.to_s],
- 'access_level' => 'GUEST'
- }
- end
-
- let(:extra_params) { { expires_at: 10.days.from_now } }
- let(:input_params) { input.merge(extra_params) }
- let(:mutation) { graphql_mutation(mutation_name, input_params) }
- let(:mutation_response) { graphql_mutation_response(mutation_name) }
-
- context 'when user is not logged-in' do
- it_behaves_like 'a mutation that returns a top-level access error'
- end
-
- context 'when user is not an owner' do
- before do
- group.add_maintainer(current_user)
- end
-
- it_behaves_like 'a mutation that returns a top-level access error'
- end
-
- context 'when user is an owner' do
- before do
- group.add_owner(current_user)
- end
-
- shared_examples 'updates the user access role' do
- specify do
- post_graphql_mutation(mutation, current_user: current_user)
-
- new_access_levels = mutation_response['groupMembers'].map { |member| member['accessLevel']['integerValue'] }
- expect(response).to have_gitlab_http_status(:success)
- expect(mutation_response['errors']).to be_empty
- expect(new_access_levels).to all(be Gitlab::Access::GUEST)
- end
- end
-
- it_behaves_like 'updates the user access role'
-
- context 'when inherited members are passed' do
- let_it_be(:subgroup) { create(:group, parent: group) }
- let_it_be(:subgroup_member) { create(:group_member, group: subgroup) }
-
- let(:input) do
- {
- 'group_id' => group.to_global_id.to_s,
- 'user_ids' => [user1.to_global_id.to_s, user2.to_global_id.to_s, subgroup_member.user.to_global_id.to_s],
- 'access_level' => 'GUEST'
- }
- end
-
- it 'does not update the members' do
- post_graphql_mutation(mutation, current_user: current_user)
-
- error = Mutations::Members::Groups::BulkUpdate::INVALID_MEMBERS_ERROR
- expect(json_response['errors'].first['message']).to include(error)
- end
- end
-
- context 'when members count is more than the allowed limit' do
- let(:max_members_update_limit) { 1 }
-
- before do
- stub_const('Mutations::Members::Groups::BulkUpdate::MAX_MEMBERS_UPDATE_LIMIT', max_members_update_limit)
- end
-
- it 'does not update the members' do
- post_graphql_mutation(mutation, current_user: current_user)
-
- error = Mutations::Members::Groups::BulkUpdate::MAX_MEMBERS_UPDATE_ERROR
- expect(json_response['errors'].first['message']).to include(error)
- end
- end
-
- context 'when the update service raises access denied error' do
- before do
- allow_next_instance_of(Members::UpdateService) do |instance|
- allow(instance).to receive(:execute).and_raise(Gitlab::Access::AccessDeniedError)
- end
- end
-
- it 'does not update the members' do
- post_graphql_mutation(mutation, current_user: current_user)
-
- expect(mutation_response['groupMembers']).to be_nil
- expect(mutation_response['errors'])
- .to contain_exactly("Unable to update members, please check user permissions.")
- end
- end
-
- context 'when the update service returns an error message' do
- before do
- allow_next_instance_of(Members::UpdateService) do |instance|
- error_result = {
- message: 'Expires at cannot be a date in the past',
- status: :error,
- members: [group_member1]
- }
- allow(instance).to receive(:execute).and_return(error_result)
- end
- end
-
- it 'will pass through the error' do
- post_graphql_mutation(mutation, current_user: current_user)
-
- expect(mutation_response['groupMembers'].first['id']).to eq(group_member1.to_global_id.to_s)
- expect(mutation_response['errors']).to contain_exactly('Expires at cannot be a date in the past')
- end
- end
- end
+ it_behaves_like 'members bulk update mutation'
end
diff --git a/spec/requests/api/graphql/mutations/members/projects/bulk_update_spec.rb b/spec/requests/api/graphql/mutations/members/projects/bulk_update_spec.rb
new file mode 100644
index 00000000000..cbef9715cbe
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/members/projects/bulk_update_spec.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'ProjectMemberBulkUpdate', feature_category: :projects do
+ include GraphqlHelpers
+
+ let_it_be(:parent_group) { create(:group) }
+ let_it_be(:parent_group_member) { create(:group_member, group: parent_group) }
+ let_it_be(:project) { create(:project, group: parent_group) }
+ let_it_be(:source) { project }
+ let_it_be(:member_type) { :project_member }
+ let_it_be(:mutation_name) { :project_member_bulk_update }
+ let_it_be(:source_id_key) { 'project_id' }
+ let_it_be(:response_member_field) { 'projectMembers' }
+
+ it_behaves_like 'members bulk update mutation'
+end
diff --git a/spec/support/shared_contexts/navbar_structure_context.rb b/spec/support/shared_contexts/navbar_structure_context.rb
index e1ac0e3fd0a..3af0b30bca0 100644
--- a/spec/support/shared_contexts/navbar_structure_context.rb
+++ b/spec/support/shared_contexts/navbar_structure_context.rb
@@ -34,10 +34,10 @@ RSpec.shared_context 'project navbar structure' do
_('Commits'),
_('Branches'),
_('Tags'),
- _('Contributors'),
+ _('Contributor statistics'),
_('Graph'),
- _('Compare'),
- (_('Locked Files') if Gitlab.ee?)
+ _('Compare revisions'),
+ (_('Locked files') if Gitlab.ee?)
]
},
{
diff --git a/spec/support/shared_examples/graphql/mutations/members/bulk_update_shared_examples.rb b/spec/support/shared_examples/graphql/mutations/members/bulk_update_shared_examples.rb
new file mode 100644
index 00000000000..e885b5d283e
--- /dev/null
+++ b/spec/support/shared_examples/graphql/mutations/members/bulk_update_shared_examples.rb
@@ -0,0 +1,123 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'members bulk update mutation' do
+ let_it_be(:current_user) { create(:user) }
+ let_it_be(:user1) { create(:user) }
+ let_it_be(:user2) { create(:user) }
+ let_it_be(:member1) { create(member_type, source: source, user: user1) }
+ let_it_be(:member2) { create(member_type, source: source, user: user2) }
+
+ let(:extra_params) { { expires_at: 10.days.from_now } }
+ let(:input_params) { input.merge(extra_params) }
+ let(:mutation) { graphql_mutation(mutation_name, input_params) }
+ let(:mutation_response) { graphql_mutation_response(mutation_name) }
+
+ let(:input) do
+ {
+ source_id_key => source.to_global_id.to_s,
+ 'user_ids' => [user1.to_global_id.to_s, user2.to_global_id.to_s],
+ 'access_level' => 'GUEST'
+ }
+ end
+
+ context 'when user is not logged-in' do
+ it_behaves_like 'a mutation that returns a top-level access error'
+ end
+
+ context 'when user is not an owner' do
+ before do
+ source.add_developer(current_user)
+ end
+
+ it_behaves_like 'a mutation that returns a top-level access error'
+ end
+
+ context 'when user is an owner' do
+ before do
+ source.add_owner(current_user)
+ end
+
+ shared_examples 'updates the user access role' do
+ specify do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ new_access_levels = mutation_response[response_member_field].map do |member|
+ member['accessLevel']['integerValue']
+ end
+ expect(response).to have_gitlab_http_status(:success)
+ expect(mutation_response['errors']).to be_empty
+ expect(new_access_levels).to all(be Gitlab::Access::GUEST)
+ end
+ end
+
+ it_behaves_like 'updates the user access role'
+
+ context 'when inherited members are passed' do
+ let(:input) do
+ {
+ source_id_key => source.to_global_id.to_s,
+ 'user_ids' => [user1.to_global_id.to_s, user2.to_global_id.to_s, parent_group_member.user.to_global_id.to_s],
+ 'access_level' => 'GUEST'
+ }
+ end
+
+ it 'does not update the members' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ error = Mutations::Members::BulkUpdateBase::INVALID_MEMBERS_ERROR
+ expect(json_response['errors'].first['message']).to include(error)
+ end
+ end
+
+ context 'when members count is more than the allowed limit' do
+ let(:max_members_update_limit) { 1 }
+
+ before do
+ stub_const('Mutations::Members::BulkUpdateBase::MAX_MEMBERS_UPDATE_LIMIT', max_members_update_limit)
+ end
+
+ it 'does not update the members' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ error = Mutations::Members::BulkUpdateBase::MAX_MEMBERS_UPDATE_ERROR
+ expect(json_response['errors'].first['message']).to include(error)
+ end
+ end
+
+ context 'when the update service raises access denied error' do
+ before do
+ allow_next_instance_of(Members::UpdateService) do |instance|
+ allow(instance).to receive(:execute).and_raise(Gitlab::Access::AccessDeniedError)
+ end
+ end
+
+ it 'does not update the members' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(mutation_response[response_member_field]).to be_nil
+ expect(mutation_response['errors'])
+ .to contain_exactly("Unable to update members, please check user permissions.")
+ end
+ end
+
+ context 'when the update service returns an error message' do
+ before do
+ allow_next_instance_of(Members::UpdateService) do |instance|
+ error_result = {
+ message: 'Expires at cannot be a date in the past',
+ status: :error,
+ members: [member1]
+ }
+ allow(instance).to receive(:execute).and_return(error_result)
+ end
+ end
+
+ it 'will pass through the error' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(mutation_response[response_member_field].first['id']).to eq(member1.to_global_id.to_s)
+ expect(mutation_response['errors']).to contain_exactly('Expires at cannot be a date in the past')
+ end
+ end
+ end
+end
diff --git a/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb b/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb
index dc9575dc767..0df490f9b41 100644
--- a/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb
+++ b/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb
@@ -106,11 +106,11 @@ RSpec.describe 'layouts/nav/sidebar/_project', feature_category: :navigation do
end
end
- describe 'Contributors' do
+ describe 'Contributor statistics' do
it 'has a link to the project contributors path' do
render
- expect(rendered).to have_link('Contributors', href: project_graph_path(project, current_ref, ref_type: 'heads'))
+ expect(rendered).to have_link('Contributor statistics', href: project_graph_path(project, current_ref, ref_type: 'heads'))
end
end
@@ -122,11 +122,11 @@ RSpec.describe 'layouts/nav/sidebar/_project', feature_category: :navigation do
end
end
- describe 'Compare' do
+ describe 'Compare revisions' do
it 'has a link to the project compare path' do
render
- expect(rendered).to have_link('Compare', href: project_compare_index_path(project, from: project.repository.root_ref, to: current_ref))
+ expect(rendered).to have_link('Compare revisions', href: project_compare_index_path(project, from: project.repository.root_ref, to: current_ref))
end
end
end