Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
eb1755b2d9
commit
8d9c82762d
|
@ -35,7 +35,7 @@ module BoardsResponses
|
||||||
end
|
end
|
||||||
|
|
||||||
def authorize_read_list
|
def authorize_read_list
|
||||||
authorize_action_for!(board, :read_list)
|
authorize_action_for!(board, :read_issue_board_list)
|
||||||
end
|
end
|
||||||
|
|
||||||
def authorize_read_issue
|
def authorize_read_issue
|
||||||
|
@ -54,7 +54,7 @@ module BoardsResponses
|
||||||
end
|
end
|
||||||
|
|
||||||
def authorize_admin_list
|
def authorize_admin_list
|
||||||
authorize_action_for!(board, :admin_list)
|
authorize_action_for!(board, :admin_issue_board_list)
|
||||||
end
|
end
|
||||||
|
|
||||||
def authorize_action_for!(resource, ability)
|
def authorize_action_for!(resource, ability)
|
||||||
|
|
|
@ -80,7 +80,7 @@ module MultipleBoardsActions
|
||||||
end
|
end
|
||||||
|
|
||||||
def authorize_admin_board!
|
def authorize_admin_board!
|
||||||
return render_404 unless can?(current_user, :admin_board, parent)
|
return render_404 unless can?(current_user, :admin_issue_board, parent)
|
||||||
end
|
end
|
||||||
|
|
||||||
def serializer
|
def serializer
|
||||||
|
|
|
@ -44,6 +44,6 @@ class Groups::BoardsController < Groups::ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def authorize_read_board!
|
def authorize_read_board!
|
||||||
access_denied! unless can?(current_user, :read_board, group)
|
access_denied! unless can?(current_user, :read_issue_board, group)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -45,6 +45,6 @@ class Projects::BoardsController < Projects::ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def authorize_read_board!
|
def authorize_read_board!
|
||||||
access_denied! unless can?(current_user, :read_board, project)
|
access_denied! unless can?(current_user, :read_issue_board, project)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -14,7 +14,7 @@ module Mutations
|
||||||
null: true,
|
null: true,
|
||||||
description: 'The board after mutation.'
|
description: 'The board after mutation.'
|
||||||
|
|
||||||
authorize :admin_board
|
authorize :admin_issue_board
|
||||||
|
|
||||||
def resolve(args)
|
def resolve(args)
|
||||||
board_parent = authorized_resource_parent_find!(args)
|
board_parent = authorized_resource_parent_find!(args)
|
||||||
|
|
|
@ -14,7 +14,7 @@ module Mutations
|
||||||
required: true,
|
required: true,
|
||||||
description: 'The global ID of the board to destroy.'
|
description: 'The global ID of the board to destroy.'
|
||||||
|
|
||||||
authorize :admin_board
|
authorize :admin_issue_board
|
||||||
|
|
||||||
def resolve(id:)
|
def resolve(id:)
|
||||||
board = authorized_find!(id: id)
|
board = authorized_find!(id: id)
|
||||||
|
|
|
@ -83,7 +83,7 @@ module Mutations
|
||||||
end
|
end
|
||||||
|
|
||||||
def authorize_board!(board)
|
def authorize_board!(board)
|
||||||
return if Ability.allowed?(current_user, :read_board, board.resource_parent)
|
return if Ability.allowed?(current_user, :read_issue_board, board.resource_parent)
|
||||||
|
|
||||||
raise_resource_not_available_error!
|
raise_resource_not_available_error!
|
||||||
end
|
end
|
||||||
|
|
|
@ -15,7 +15,7 @@ module Mutations
|
||||||
null: true,
|
null: true,
|
||||||
description: 'Issue list in the issue board.'
|
description: 'Issue list in the issue board.'
|
||||||
|
|
||||||
authorize :admin_list
|
authorize :admin_issue_board_list
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ module Mutations
|
||||||
def can_admin_list?(list)
|
def can_admin_list?(list)
|
||||||
return false unless list.present?
|
return false unless list.present?
|
||||||
|
|
||||||
Ability.allowed?(current_user, :admin_list, list.board)
|
Ability.allowed?(current_user, :admin_issue_board_list, list.board)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -44,7 +44,7 @@ module Mutations
|
||||||
def can_read_list?(list)
|
def can_read_list?(list)
|
||||||
return false unless list.present?
|
return false unless list.present?
|
||||||
|
|
||||||
Ability.allowed?(current_user, :read_list, list.board)
|
Ability.allowed?(current_user, :read_issue_board_list, list.board)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -17,7 +17,7 @@ module Mutations
|
||||||
null: true,
|
null: true,
|
||||||
description: 'The board after mutation.'
|
description: 'The board after mutation.'
|
||||||
|
|
||||||
authorize :admin_board
|
authorize :admin_issue_board
|
||||||
|
|
||||||
def resolve(id:, **args)
|
def resolve(id:, **args)
|
||||||
board = authorized_find!(id: id)
|
board = authorized_find!(id: id)
|
||||||
|
|
|
@ -9,7 +9,7 @@ module Resolvers
|
||||||
type Types::BoardListType, null: true
|
type Types::BoardListType, null: true
|
||||||
extras [:lookahead]
|
extras [:lookahead]
|
||||||
|
|
||||||
authorize :read_list
|
authorize :read_issue_board_list
|
||||||
|
|
||||||
argument :id, Types::GlobalIDType[List],
|
argument :id, Types::GlobalIDType[List],
|
||||||
required: false,
|
required: false,
|
||||||
|
|
|
@ -5,11 +5,12 @@ module Types
|
||||||
graphql_name 'AccessLevelEnum'
|
graphql_name 'AccessLevelEnum'
|
||||||
description 'Access level to a resource'
|
description 'Access level to a resource'
|
||||||
|
|
||||||
value 'NO_ACCESS', value: Gitlab::Access::NO_ACCESS
|
value 'NO_ACCESS', value: Gitlab::Access::NO_ACCESS, description: 'No access'
|
||||||
value 'GUEST', value: Gitlab::Access::GUEST
|
value 'MINIMAL_ACCESS', value: Gitlab::Access::MINIMAL_ACCESS, description: 'Minimal access'
|
||||||
value 'REPORTER', value: Gitlab::Access::REPORTER
|
value 'GUEST', value: Gitlab::Access::GUEST, description: 'Guest access'
|
||||||
value 'DEVELOPER', value: Gitlab::Access::DEVELOPER
|
value 'REPORTER', value: Gitlab::Access::REPORTER, description: 'Reporter access'
|
||||||
value 'MAINTAINER', value: Gitlab::Access::MAINTAINER
|
value 'DEVELOPER', value: Gitlab::Access::DEVELOPER, description: 'Developer access'
|
||||||
value 'OWNER', value: Gitlab::Access::OWNER
|
value 'MAINTAINER', value: Gitlab::Access::MAINTAINER, description: 'Maintainer access'
|
||||||
|
value 'OWNER', value: Gitlab::Access::OWNER, description: 'Owner access'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,7 +5,7 @@ module Types
|
||||||
graphql_name 'Board'
|
graphql_name 'Board'
|
||||||
description 'Represents a project or group issue board'
|
description 'Represents a project or group issue board'
|
||||||
accepts ::Board
|
accepts ::Board
|
||||||
authorize :read_board
|
authorize :read_issue_board
|
||||||
|
|
||||||
present_using BoardPresenter
|
present_using BoardPresenter
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,14 @@ module Emails
|
||||||
mail_answer_thread(@merge_request, merge_request_thread_options(updated_by_user_id, recipient_id, reason))
|
mail_answer_thread(@merge_request, merge_request_thread_options(updated_by_user_id, recipient_id, reason))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def change_in_merge_request_draft_status_email(recipient_id, merge_request_id, updated_by_user_id, reason = nil)
|
||||||
|
setup_merge_request_mail(merge_request_id, recipient_id)
|
||||||
|
|
||||||
|
@updated_by_user = User.find(updated_by_user_id)
|
||||||
|
|
||||||
|
mail_answer_thread(@merge_request, merge_request_thread_options(updated_by_user_id, recipient_id, reason))
|
||||||
|
end
|
||||||
|
|
||||||
# rubocop: disable CodeReuse/ActiveRecord
|
# rubocop: disable CodeReuse/ActiveRecord
|
||||||
def reassigned_merge_request_email(recipient_id, merge_request_id, previous_assignee_ids, updated_by_user_id, reason = nil)
|
def reassigned_merge_request_email(recipient_id, merge_request_id, previous_assignee_ids, updated_by_user_id, reason = nil)
|
||||||
setup_merge_request_mail(merge_request_id, recipient_id)
|
setup_merge_request_mail(merge_request_id, recipient_id)
|
||||||
|
|
|
@ -253,9 +253,10 @@ module Ci
|
||||||
end
|
end
|
||||||
|
|
||||||
def can_pick?(build)
|
def can_pick?(build)
|
||||||
return false if self.ref_protected? && !build.protected?
|
# Run `matches_build?` checks before, since they are cheaper than
|
||||||
|
# `assignable_for?`.
|
||||||
assignable_for?(build.project_id) && accepting_tags?(build)
|
#
|
||||||
|
matches_build?(build) && assignable_for?(build.project_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def only_for?(project)
|
def only_for?(project)
|
||||||
|
@ -266,6 +267,16 @@ module Ci
|
||||||
token[0...8] if token
|
token[0...8] if token
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def tag_list
|
||||||
|
return super unless Feature.enabled?(:ci_preload_runner_tags, default_enabled: :yaml)
|
||||||
|
|
||||||
|
if tags.loaded?
|
||||||
|
tags.map(&:name)
|
||||||
|
else
|
||||||
|
super
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def has_tags?
|
def has_tags?
|
||||||
tag_list.any?
|
tag_list.any?
|
||||||
end
|
end
|
||||||
|
@ -305,8 +316,10 @@ module Ci
|
||||||
end
|
end
|
||||||
|
|
||||||
def pick_build!(build)
|
def pick_build!(build)
|
||||||
if can_pick?(build)
|
if Feature.enabled?(:ci_reduce_queries_when_ticking_runner_queue, self, default_enabled: :yaml)
|
||||||
tick_runner_queue
|
tick_runner_queue if matches_build?(build)
|
||||||
|
else
|
||||||
|
tick_runner_queue if can_pick?(build)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -370,6 +383,13 @@ module Ci
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# TODO: choose a better name and consider splitting this method into two
|
||||||
|
def matches_build?(build)
|
||||||
|
return false if self.ref_protected? && !build.protected?
|
||||||
|
|
||||||
|
accepting_tags?(build)
|
||||||
|
end
|
||||||
|
|
||||||
def accepting_tags?(build)
|
def accepting_tags?(build)
|
||||||
(run_untagged? || build.has_tags?) && (build.tag_list - tag_list).empty?
|
(run_untagged? || build.has_tags?) && (build.tag_list - tag_list).empty?
|
||||||
end
|
end
|
||||||
|
|
|
@ -17,7 +17,7 @@ module ReadonlyAbilities
|
||||||
|
|
||||||
READONLY_FEATURES = %i[
|
READONLY_FEATURES = %i[
|
||||||
issue
|
issue
|
||||||
list
|
issue_board_list
|
||||||
merge_request
|
merge_request
|
||||||
label
|
label
|
||||||
milestone
|
milestone
|
||||||
|
|
|
@ -97,9 +97,9 @@ class GroupPolicy < BasePolicy
|
||||||
|
|
||||||
rule { can?(:read_group) }.policy do
|
rule { can?(:read_group) }.policy do
|
||||||
enable :read_milestone
|
enable :read_milestone
|
||||||
enable :read_list
|
enable :read_issue_board_list
|
||||||
enable :read_label
|
enable :read_label
|
||||||
enable :read_board
|
enable :read_issue_board
|
||||||
enable :read_group_member
|
enable :read_group_member
|
||||||
enable :read_custom_emoji
|
enable :read_custom_emoji
|
||||||
end
|
end
|
||||||
|
@ -122,9 +122,9 @@ class GroupPolicy < BasePolicy
|
||||||
rule { reporter }.policy do
|
rule { reporter }.policy do
|
||||||
enable :reporter_access
|
enable :reporter_access
|
||||||
enable :read_container_image
|
enable :read_container_image
|
||||||
enable :admin_board
|
enable :admin_issue_board
|
||||||
enable :admin_label
|
enable :admin_label
|
||||||
enable :admin_list
|
enable :admin_issue_board_list
|
||||||
enable :admin_issue
|
enable :admin_issue
|
||||||
enable :read_metrics_dashboard_annotation
|
enable :read_metrics_dashboard_annotation
|
||||||
enable :read_prometheus
|
enable :read_prometheus
|
||||||
|
|
|
@ -204,8 +204,8 @@ class ProjectPolicy < BasePolicy
|
||||||
rule { can?(:guest_access) }.policy do
|
rule { can?(:guest_access) }.policy do
|
||||||
enable :read_project
|
enable :read_project
|
||||||
enable :create_merge_request_in
|
enable :create_merge_request_in
|
||||||
enable :read_board
|
enable :read_issue_board
|
||||||
enable :read_list
|
enable :read_issue_board_list
|
||||||
enable :read_wiki
|
enable :read_wiki
|
||||||
enable :read_issue
|
enable :read_issue
|
||||||
enable :read_label
|
enable :read_label
|
||||||
|
@ -231,7 +231,7 @@ class ProjectPolicy < BasePolicy
|
||||||
rule { guest & can?(:read_container_image) }.enable :build_read_container_image
|
rule { guest & can?(:read_container_image) }.enable :build_read_container_image
|
||||||
|
|
||||||
rule { can?(:reporter_access) }.policy do
|
rule { can?(:reporter_access) }.policy do
|
||||||
enable :admin_board
|
enable :admin_issue_board
|
||||||
enable :download_code
|
enable :download_code
|
||||||
enable :read_statistics
|
enable :read_statistics
|
||||||
enable :download_wiki_code
|
enable :download_wiki_code
|
||||||
|
@ -240,7 +240,7 @@ class ProjectPolicy < BasePolicy
|
||||||
enable :reopen_issue
|
enable :reopen_issue
|
||||||
enable :admin_issue
|
enable :admin_issue
|
||||||
enable :admin_label
|
enable :admin_label
|
||||||
enable :admin_list
|
enable :admin_issue_board_list
|
||||||
enable :admin_issue_link
|
enable :admin_issue_link
|
||||||
enable :read_commit_status
|
enable :read_commit_status
|
||||||
enable :read_build
|
enable :read_build
|
||||||
|
@ -319,7 +319,7 @@ class ProjectPolicy < BasePolicy
|
||||||
|
|
||||||
rule { can?(:developer_access) }.policy do
|
rule { can?(:developer_access) }.policy do
|
||||||
enable :create_package
|
enable :create_package
|
||||||
enable :admin_board
|
enable :admin_issue_board
|
||||||
enable :admin_merge_request
|
enable :admin_merge_request
|
||||||
enable :admin_milestone
|
enable :admin_milestone
|
||||||
enable :update_merge_request
|
enable :update_merge_request
|
||||||
|
@ -369,7 +369,7 @@ class ProjectPolicy < BasePolicy
|
||||||
|
|
||||||
rule { can?(:maintainer_access) }.policy do
|
rule { can?(:maintainer_access) }.policy do
|
||||||
enable :destroy_package
|
enable :destroy_package
|
||||||
enable :admin_board
|
enable :admin_issue_board
|
||||||
enable :push_to_delete_protected_branch
|
enable :push_to_delete_protected_branch
|
||||||
enable :update_snippet
|
enable :update_snippet
|
||||||
enable :admin_snippet
|
enable :admin_snippet
|
||||||
|
@ -429,8 +429,8 @@ class ProjectPolicy < BasePolicy
|
||||||
|
|
||||||
rule { issues_disabled }.policy do
|
rule { issues_disabled }.policy do
|
||||||
prevent(*create_read_update_admin_destroy(:issue))
|
prevent(*create_read_update_admin_destroy(:issue))
|
||||||
prevent(*create_read_update_admin_destroy(:board))
|
prevent(*create_read_update_admin_destroy(:issue_board))
|
||||||
prevent(*create_read_update_admin_destroy(:list))
|
prevent(*create_read_update_admin_destroy(:issue_board_list))
|
||||||
end
|
end
|
||||||
|
|
||||||
rule { merge_requests_disabled | repository_disabled }.policy do
|
rule { merge_requests_disabled | repository_disabled }.policy do
|
||||||
|
@ -507,8 +507,8 @@ class ProjectPolicy < BasePolicy
|
||||||
rule { can?(:public_access) }.policy do
|
rule { can?(:public_access) }.policy do
|
||||||
enable :read_package
|
enable :read_package
|
||||||
enable :read_project
|
enable :read_project
|
||||||
enable :read_board
|
enable :read_issue_board
|
||||||
enable :read_list
|
enable :read_issue_board_list
|
||||||
enable :read_wiki
|
enable :read_wiki
|
||||||
enable :read_label
|
enable :read_label
|
||||||
enable :read_milestone
|
enable :read_milestone
|
||||||
|
|
|
@ -47,11 +47,11 @@ module Boards
|
||||||
end
|
end
|
||||||
|
|
||||||
def can_read?(list)
|
def can_read?(list)
|
||||||
Ability.allowed?(current_user, :read_list, parent)
|
Ability.allowed?(current_user, :read_issue_board_list, parent)
|
||||||
end
|
end
|
||||||
|
|
||||||
def can_admin?(list)
|
def can_admin?(list)
|
||||||
Ability.allowed?(current_user, :admin_list, parent)
|
Ability.allowed?(current_user, :admin_issue_board_list, parent)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -10,6 +10,8 @@ module Ci
|
||||||
|
|
||||||
def tick_for(build, runners, metrics)
|
def tick_for(build, runners, metrics)
|
||||||
runners = runners.with_recent_runner_queue
|
runners = runners.with_recent_runner_queue
|
||||||
|
runners = runners.with_tags if Feature.enabled?(:ci_preload_runner_tags, default_enabled: :yaml)
|
||||||
|
|
||||||
metrics.observe_active_runners(-> { runners.to_a.size })
|
metrics.observe_active_runners(-> { runners.to_a.size })
|
||||||
|
|
||||||
runners.each do |runner|
|
runners.each do |runner|
|
||||||
|
|
|
@ -154,11 +154,20 @@ module MergeRequests
|
||||||
elsif old_title_wip && !new_title_wip
|
elsif old_title_wip && !new_title_wip
|
||||||
# Unmarked as Draft/WIP
|
# Unmarked as Draft/WIP
|
||||||
#
|
#
|
||||||
|
notify_draft_status_changed(merge_request)
|
||||||
|
|
||||||
merge_request_activity_counter
|
merge_request_activity_counter
|
||||||
.track_unmarked_as_draft_action(user: current_user)
|
.track_unmarked_as_draft_action(user: current_user)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def notify_draft_status_changed(merge_request)
|
||||||
|
notification_service.async.change_in_merge_request_draft_status(
|
||||||
|
merge_request,
|
||||||
|
current_user
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
def handle_milestone_change(merge_request)
|
def handle_milestone_change(merge_request)
|
||||||
return if skip_milestone_email
|
return if skip_milestone_email
|
||||||
|
|
||||||
|
|
|
@ -189,6 +189,20 @@ class NotificationService
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def change_in_merge_request_draft_status(merge_request, current_user)
|
||||||
|
recipients = NotificationRecipients::BuildService.build_recipients(merge_request, current_user, action: "draft_status_change")
|
||||||
|
|
||||||
|
recipients.each do |recipient|
|
||||||
|
mailer.send(
|
||||||
|
:change_in_merge_request_draft_status_email,
|
||||||
|
recipient.user.id,
|
||||||
|
merge_request.id,
|
||||||
|
current_user.id,
|
||||||
|
recipient.reason
|
||||||
|
).deliver_later
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# When a merge request is found to be unmergeable, we should send an email to:
|
# When a merge request is found to be unmergeable, we should send an email to:
|
||||||
#
|
#
|
||||||
# * mr author
|
# * mr author
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
- group = local_assigns.fetch(:group, false)
|
- group = local_assigns.fetch(:group, false)
|
||||||
-# TODO: Move group_id and can_admin_list to the board store
|
-# TODO: Move group_id and can_admin_list to the board store
|
||||||
See: https://gitlab.com/gitlab-org/gitlab/-/issues/213082
|
See: https://gitlab.com/gitlab-org/gitlab/-/issues/213082
|
||||||
- can_admin_list = can?(current_user, :admin_list, current_board_parent) == true
|
- can_admin_list = can?(current_user, :admin_issue_board_list, current_board_parent) == true
|
||||||
- @no_breadcrumb_container = true
|
- @no_breadcrumb_container = true
|
||||||
- @no_container = true
|
- @no_container = true
|
||||||
- @content_class = "issue-boards-content js-focus-mode-board"
|
- @content_class = "issue-boards-content js-focus-mode-board"
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
milestone_path: milestones_filter_path(milestone_filter_opts),
|
milestone_path: milestones_filter_path(milestone_filter_opts),
|
||||||
board_base_url: board_base_url,
|
board_base_url: board_base_url,
|
||||||
has_missing_boards: (!multiple_boards_available? && current_board_parent.boards.size > 1).to_s,
|
has_missing_boards: (!multiple_boards_available? && current_board_parent.boards.size > 1).to_s,
|
||||||
can_admin_board: can?(current_user, :admin_board, parent).to_s,
|
can_admin_board: can?(current_user, :admin_issue_board, parent).to_s,
|
||||||
multiple_issue_boards_available: parent.multiple_issue_boards_available?.to_s,
|
multiple_issue_boards_available: parent.multiple_issue_boards_available?.to_s,
|
||||||
labels_path: labels_filter_path_with_defaults(only_group_labels: true, include_descendant_groups: true),
|
labels_path: labels_filter_path_with_defaults(only_group_labels: true, include_descendant_groups: true),
|
||||||
labels_web_url: parent.is_a?(Project) ? project_labels_path(@project) : group_labels_path(@group),
|
labels_web_url: parent.is_a?(Project) ? project_labels_path(@project) : group_labels_path(@group),
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
- placeholder = local_assigns[:placeholder] || _('Search or filter results...')
|
- placeholder = local_assigns[:placeholder] || _('Search or filter results...')
|
||||||
- is_not_boards_modal_or_productivity_analytics = type != :boards_modal && type != :productivity_analytics
|
- is_not_boards_modal_or_productivity_analytics = type != :boards_modal && type != :productivity_analytics
|
||||||
- block_css_class = is_not_boards_modal_or_productivity_analytics ? 'row-content-block second-block' : ''
|
- block_css_class = is_not_boards_modal_or_productivity_analytics ? 'row-content-block second-block' : ''
|
||||||
- user_can_admin_list = board && can?(current_user, :admin_list, board.resource_parent)
|
- user_can_admin_list = board && can?(current_user, :admin_issue_board_list, board.resource_parent)
|
||||||
|
|
||||||
.issues-filters{ class: ("w-100" if type == :boards_modal) }
|
.issues-filters{ class: ("w-100" if type == :boards_modal) }
|
||||||
.issues-details-filters.filtered-search-block.d-flex.flex-column.flex-lg-row{ class: block_css_class, "v-pre" => type == :boards_modal }
|
.issues-details-filters.filtered-search-block.d-flex.flex-column.flex-lg-row{ class: block_css_class, "v-pre" => type == :boards_modal }
|
||||||
|
@ -202,7 +202,7 @@
|
||||||
- else
|
- else
|
||||||
= render 'shared/issuable/board_create_list_dropdown', board: board
|
= render 'shared/issuable/board_create_list_dropdown', board: board
|
||||||
- if @project
|
- if @project
|
||||||
#js-add-issues-btn{ data: { can_admin_list: can?(current_user, :admin_list, @project) } }
|
#js-add-issues-btn{ data: { can_admin_list: can?(current_user, :admin_issue_board_list, @project) } }
|
||||||
#js-toggle-focus-btn
|
#js-toggle-focus-btn
|
||||||
- elsif is_not_boards_modal_or_productivity_analytics && show_sorting_dropdown
|
- elsif is_not_boards_modal_or_productivity_analytics && show_sorting_dropdown
|
||||||
= render 'shared/issuable/sort_dropdown'
|
= render 'shared/issuable/sort_dropdown'
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
title: Send notifications to subscribers when merge request draft status removed
|
||||||
|
merge_request: 55444
|
||||||
|
author:
|
||||||
|
type: changed
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
title: Reduce queries when ticking runner queue
|
||||||
|
merge_request: 55496
|
||||||
|
author:
|
||||||
|
type: performance
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
title: Preload runner tags for `UpdateBuildQueueService`
|
||||||
|
merge_request: 55543
|
||||||
|
author:
|
||||||
|
type: performance
|
|
@ -0,0 +1,8 @@
|
||||||
|
---
|
||||||
|
name: ci_preload_runner_tags
|
||||||
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/55543
|
||||||
|
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/323243
|
||||||
|
milestone: '13.10'
|
||||||
|
type: development
|
||||||
|
group: group::memory
|
||||||
|
default_enabled: false
|
|
@ -0,0 +1,8 @@
|
||||||
|
---
|
||||||
|
name: ci_reduce_queries_when_ticking_runner_queue
|
||||||
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/55496
|
||||||
|
rollout_issue_url:
|
||||||
|
milestone: '13.10'
|
||||||
|
type: development
|
||||||
|
group: group::continuous integration
|
||||||
|
default_enabled: false
|
|
@ -118,7 +118,7 @@ We use PostgreSQL's own replication functionality to replicate data from the **p
|
||||||
We use Redis both as a cache store and to hold persistent data for our background jobs system. Because both
|
We use Redis both as a cache store and to hold persistent data for our background jobs system. Because both
|
||||||
use-cases has data that are exclusive to the same Geo node, we don't replicate it between nodes.
|
use-cases has data that are exclusive to the same Geo node, we don't replicate it between nodes.
|
||||||
|
|
||||||
Elasticsearch is an optional database, that can enable advanced searching capabilities, like improved Global Search
|
Elasticsearch is an optional database, that can enable advanced searching capabilities, like improved Advanced Search
|
||||||
in both source-code level and user generated content in Issues / Merge-Requests and discussions. Currently it's not
|
in both source-code level and user generated content in Issues / Merge-Requests and discussions. Currently it's not
|
||||||
supported in Geo.
|
supported in Geo.
|
||||||
|
|
||||||
|
|
|
@ -526,7 +526,7 @@ amount of memory during indexing.
|
||||||
|
|
||||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/201826) in GitLab 12.8.
|
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/201826) in GitLab 12.8.
|
||||||
|
|
||||||
You can set a limit on the content of text fields indexed for Global Search.
|
You can set a limit on the content of text fields indexed for Advanced Search.
|
||||||
Setting a maximum helps to reduce the load of the indexing processes. If any
|
Setting a maximum helps to reduce the load of the indexing processes. If any
|
||||||
text field exceeds this limit then the text will be truncated to this number of
|
text field exceeds this limit then the text will be truncated to this number of
|
||||||
characters and the rest will not be indexed and hence will not be searchable.
|
characters and the rest will not be indexed and hence will not be searchable.
|
||||||
|
|
|
@ -87,7 +87,7 @@ In addition, the log contains the originating IP address,
|
||||||
(`remote_ip`), the user's ID (`user_id`), and username (`username`).
|
(`remote_ip`), the user's ID (`user_id`), and username (`username`).
|
||||||
|
|
||||||
Some endpoints such as `/search` may make requests to Elasticsearch if using
|
Some endpoints such as `/search` may make requests to Elasticsearch if using
|
||||||
[Advanced Search](../user/search/advanced_global_search.md). These
|
[Advanced Search](../user/search/advanced_search.md). These
|
||||||
additionally log `elasticsearch_calls` and `elasticsearch_call_duration_s`,
|
additionally log `elasticsearch_calls` and `elasticsearch_call_duration_s`,
|
||||||
which correspond to:
|
which correspond to:
|
||||||
|
|
||||||
|
|
|
@ -4964,12 +4964,13 @@ Access level to a resource.
|
||||||
|
|
||||||
| Value | Description |
|
| Value | Description |
|
||||||
| ----- | ----------- |
|
| ----- | ----------- |
|
||||||
| `DEVELOPER` | |
|
| `DEVELOPER` | Developer access |
|
||||||
| `GUEST` | |
|
| `GUEST` | Guest access |
|
||||||
| `MAINTAINER` | |
|
| `MAINTAINER` | Maintainer access |
|
||||||
| `NO_ACCESS` | |
|
| `MINIMAL_ACCESS` | Minimal access |
|
||||||
| `OWNER` | |
|
| `NO_ACCESS` | No access |
|
||||||
| `REPORTER` | |
|
| `OWNER` | Owner access |
|
||||||
|
| `REPORTER` | Reporter access |
|
||||||
|
|
||||||
### AlertManagementAlertSort
|
### AlertManagementAlertSort
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ type: reference, api
|
||||||
|
|
||||||
Every API call to search must be authenticated.
|
Every API call to search must be authenticated.
|
||||||
|
|
||||||
## Global Search API
|
## Advanced Search API
|
||||||
|
|
||||||
Search globally across the GitLab instance.
|
Search globally across the GitLab instance.
|
||||||
|
|
||||||
|
|
|
@ -184,7 +184,7 @@ If the current version is `v12p1`, and we need to create a new version for `v12p
|
||||||
1. Change the namespace for files under `v12p1` folder from `Latest` to `V12p1`
|
1. Change the namespace for files under `v12p1` folder from `Latest` to `V12p1`
|
||||||
1. Make changes to files under the `latest` folder as needed
|
1. Make changes to files under the `latest` folder as needed
|
||||||
|
|
||||||
## Creating a new Global Search migration
|
## Creating a new Advanced Search migration
|
||||||
|
|
||||||
> This functionality was introduced by [#234046](https://gitlab.com/gitlab-org/gitlab/-/issues/234046).
|
> This functionality was introduced by [#234046](https://gitlab.com/gitlab-org/gitlab/-/issues/234046).
|
||||||
|
|
||||||
|
|
|
@ -59,8 +59,7 @@ GitLab can be integrated with the following enhancements:
|
||||||
or [Kroki](../administration/integration/kroki.md) to use diagrams in AsciiDoc and Markdown documents.
|
or [Kroki](../administration/integration/kroki.md) to use diagrams in AsciiDoc and Markdown documents.
|
||||||
- Attach merge requests to [Trello](trello_power_up.md) cards.
|
- Attach merge requests to [Trello](trello_power_up.md) cards.
|
||||||
- Enable integrated code intelligence powered by [Sourcegraph](sourcegraph.md).
|
- Enable integrated code intelligence powered by [Sourcegraph](sourcegraph.md).
|
||||||
- Add [Elasticsearch](elasticsearch.md) for [Advanced Search](../user/search/advanced_global_search.md),
|
- Add [Elasticsearch](elasticsearch.md) for [Advanced Search](../user/search/advanced_search.md).
|
||||||
[Advanced System Search](../user/search/advanced_search_syntax.md), and faster searching.
|
|
||||||
|
|
||||||
## Integrations
|
## Integrations
|
||||||
|
|
||||||
|
|
|
@ -11,10 +11,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
||||||
|
|
||||||
This document describes how to enable Advanced Search. After
|
This document describes how to enable Advanced Search. After
|
||||||
Advanced Search is enabled, you'll have the benefit of fast search response times
|
Advanced Search is enabled, you'll have the benefit of fast search response times
|
||||||
and the advantage of the following special searches:
|
and the advantage of the [special searches](../user/search/advanced_search.md).
|
||||||
|
|
||||||
- [Advanced Search](../user/search/advanced_global_search.md)
|
|
||||||
- [Advanced Search Syntax](../user/search/advanced_search_syntax.md)
|
|
||||||
|
|
||||||
## Version requirements
|
## Version requirements
|
||||||
|
|
||||||
|
|
|
@ -107,8 +107,7 @@ the tiers are no longer mentioned in GitLab documentation:
|
||||||
- Search:
|
- Search:
|
||||||
- [Filtering merge requests by approvers](../user/search/index.md#filtering-merge-requests-by-approvers)
|
- [Filtering merge requests by approvers](../user/search/index.md#filtering-merge-requests-by-approvers)
|
||||||
- [Filtering merge requests by "approved by"](../user/search/index.md#filtering-merge-requests-by-approved-by)
|
- [Filtering merge requests by "approved by"](../user/search/index.md#filtering-merge-requests-by-approved-by)
|
||||||
- [Advanced Global Search (Elasticsearch)](../user/search/advanced_global_search.md)
|
- [Advanced Search (Elasticsearch)](../user/search/advanced_search.md)
|
||||||
- [Advanced Search Syntax](../user/search/advanced_search_syntax.md)
|
|
||||||
- [Service Desk](../user/project/service_desk.md)
|
- [Service Desk](../user/project/service_desk.md)
|
||||||
- [Storage usage statistics](../user/usage_quotas.md#storage-usage-statistics)
|
- [Storage usage statistics](../user/usage_quotas.md#storage-usage-statistics)
|
||||||
|
|
||||||
|
@ -130,7 +129,7 @@ Bronze-level subscribers:
|
||||||
- [Group iterations API](../api/group_iterations.md)
|
- [Group iterations API](../api/group_iterations.md)
|
||||||
- Project milestones API: [Get all burndown chart events for a single milestone](../api/milestones.md#get-all-burndown-chart-events-for-a-single-milestone)
|
- Project milestones API: [Get all burndown chart events for a single milestone](../api/milestones.md#get-all-burndown-chart-events-for-a-single-milestone)
|
||||||
- [Project iterations API](../api/iterations.md)
|
- [Project iterations API](../api/iterations.md)
|
||||||
- Fields in the [Search API](../api/search.md) available only to [Advanced Global Search (Elasticsearch)](../integration/elasticsearch.md) users
|
- Fields in the [Search API](../api/search.md) available only to [Advanced Search (Elasticsearch)](../integration/elasticsearch.md) users
|
||||||
- Fields in the [Merge requests API](../api/merge_requests.md) for [merge request approvals](../user/project/merge_requests/merge_request_approvals.md)
|
- Fields in the [Merge requests API](../api/merge_requests.md) for [merge request approvals](../user/project/merge_requests/merge_request_approvals.md)
|
||||||
- Fields in the [Protected branches API](../api/protected_branches.md) that specify users or groups allowed to merge
|
- Fields in the [Protected branches API](../api/protected_branches.md) that specify users or groups allowed to merge
|
||||||
- [Merge request approvals API](../api/merge_request_approvals.md)
|
- [Merge request approvals API](../api/merge_request_approvals.md)
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
---
|
||||||
|
stage: Create
|
||||||
|
group: Source Code
|
||||||
|
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
|
||||||
|
comments: false
|
||||||
|
---
|
||||||
|
|
||||||
|
# Cherry Pick
|
||||||
|
|
||||||
|
Given an existing commit on one branch, apply the change to another branch.
|
||||||
|
|
||||||
|
This can be useful for backporting bug fixes to previous release branches. Make
|
||||||
|
the commit on the default branch, and then cherry pick it into the release branch.
|
||||||
|
|
||||||
|
## Sample workflow
|
||||||
|
|
||||||
|
1. Check out a new `stable` branch from the default branch:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
git checkout master
|
||||||
|
git checkout -b stable
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Change back to the default branch:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
git checkout master
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Make any required changes, then commit the changes:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
git add changed_file.rb
|
||||||
|
git commit -m 'Fix bugs in changed_file.rb'
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Review the commit log and copy the SHA of the latest commit:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
git log
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Check out the `stable` branch:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
git checkout stable
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Cherry pick the commit by using the SHA copied previously:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
git cherry-pick <commit SHA>
|
||||||
|
```
|
|
@ -1,36 +1,8 @@
|
||||||
---
|
---
|
||||||
stage: none
|
redirect_to: '../../../topics/git/cherry_picking.md'
|
||||||
group: unassigned
|
|
||||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
|
|
||||||
comments: false
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# Cherry Pick
|
This document was moved to [another location](../../../topics/git/cherry_picking.md).
|
||||||
|
|
||||||
- Given an existing commit on one branch, apply the change to another branch
|
<!-- This redirect file can be deleted after <2021-06-01>. -->
|
||||||
- Useful for backporting bug fixes to previous release branches
|
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page -->
|
||||||
- Make the commit on the master branch and pick in to stable
|
|
||||||
|
|
||||||
## Cherry Pick sample workflow
|
|
||||||
|
|
||||||
1. Check out a new 'stable' branch from 'master'
|
|
||||||
1. Change back to 'master'
|
|
||||||
1. Edit '`cherry_pick.rb`' and commit the changes.
|
|
||||||
1. Check commit log to get the commit SHA
|
|
||||||
1. Check out the 'stable' branch
|
|
||||||
1. Cherry pick the commit using the SHA obtained earlier
|
|
||||||
|
|
||||||
```shell
|
|
||||||
git checkout master
|
|
||||||
git checkout -b stable
|
|
||||||
git checkout master
|
|
||||||
|
|
||||||
# Edit `cherry_pick.rb`
|
|
||||||
git add cherry_pick.rb
|
|
||||||
git commit -m 'Fix bugs in cherry_pick.rb'
|
|
||||||
git log
|
|
||||||
# Copy commit SHA
|
|
||||||
git checkout stable
|
|
||||||
|
|
||||||
git cherry-pick <commit SHA>
|
|
||||||
```
|
|
||||||
|
|
|
@ -4,5 +4,5 @@ redirect_to: '../../../topics/git/tags.md'
|
||||||
|
|
||||||
This document was moved to [another location](../../../topics/git/tags.md).
|
This document was moved to [another location](../../../topics/git/tags.md).
|
||||||
|
|
||||||
<!-- This redirect file can be deleted after <YYYY-MM-DD>. -->
|
<!-- This redirect file can be deleted after <2021-06-01>. -->
|
||||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page -->
|
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page -->
|
||||||
|
|
|
@ -1469,7 +1469,7 @@ Kubernetes API, giving you access to more advanced querying capabilities. Log
|
||||||
data is deleted after 30 days, using [Curator](https://www.elastic.co/guide/en/elasticsearch/client/curator/5.5/about.html).
|
data is deleted after 30 days, using [Curator](https://www.elastic.co/guide/en/elasticsearch/client/curator/5.5/about.html).
|
||||||
|
|
||||||
The Elastic Stack cluster application is intended as a log aggregation solution
|
The Elastic Stack cluster application is intended as a log aggregation solution
|
||||||
and is not related to our [Advanced Search](../search/advanced_global_search.md)
|
and is not related to our [Advanced Search](../search/advanced_search.md)
|
||||||
functionality, which uses a separate Elasticsearch cluster.
|
functionality, which uses a separate Elasticsearch cluster.
|
||||||
|
|
||||||
To enable log shipping:
|
To enable log shipping:
|
||||||
|
|
|
@ -61,7 +61,7 @@ With GitLab Enterprise Edition, you can also:
|
||||||
- [Multiple Issue Boards](project/issue_board.md#multiple-issue-boards).
|
- [Multiple Issue Boards](project/issue_board.md#multiple-issue-boards).
|
||||||
- Create formal relationships between issues with [Related Issues](project/issues/related_issues.md).
|
- Create formal relationships between issues with [Related Issues](project/issues/related_issues.md).
|
||||||
- Use [Burndown Charts](project/milestones/burndown_and_burnup_charts.md) to track progress during a sprint or while working on a new version of their software.
|
- Use [Burndown Charts](project/milestones/burndown_and_burnup_charts.md) to track progress during a sprint or while working on a new version of their software.
|
||||||
- Leverage [Elasticsearch](../integration/elasticsearch.md) with [Advanced Search](search/advanced_global_search.md) and [Advanced Search Syntax](search/advanced_search_syntax.md) for faster, more advanced code search across your entire GitLab instance.
|
- Leverage [Elasticsearch](../integration/elasticsearch.md) with [Advanced Search](search/advanced_search.md) for faster, more advanced code search across your entire GitLab instance.
|
||||||
- [Authenticate users with Kerberos](../integration/kerberos.md).
|
- [Authenticate users with Kerberos](../integration/kerberos.md).
|
||||||
- [Mirror a repository](project/repository/repository_mirroring.md) from elsewhere on your local server.
|
- [Mirror a repository](project/repository/repository_mirroring.md) from elsewhere on your local server.
|
||||||
- View your entire CI/CD pipeline involving more than one project with [Multiple-Project Pipelines](../ci/multi_project_pipelines.md).
|
- View your entire CI/CD pipeline involving more than one project with [Multiple-Project Pipelines](../ci/multi_project_pipelines.md).
|
||||||
|
|
|
@ -79,7 +79,8 @@ An individual user can be added as an approver for a project if they are a membe
|
||||||
- The project's immediate parent group.
|
- The project's immediate parent group.
|
||||||
- A group that has access to the project via a [share](../members/share_project_with_groups.md).
|
- A group that has access to the project via a [share](../members/share_project_with_groups.md).
|
||||||
|
|
||||||
A group of users can also be added as approvers. In the future, group approvers may be
|
A group of users can also be added as approvers, though they will only count as approvers if
|
||||||
|
they have direct membership to the group. In the future, group approvers may be
|
||||||
[restricted to only groups with share access to the project](https://gitlab.com/gitlab-org/gitlab/-/issues/2048).
|
[restricted to only groups with share access to the project](https://gitlab.com/gitlab-org/gitlab/-/issues/2048).
|
||||||
|
|
||||||
If a user is added as an individual approver and is also part of a group approver,
|
If a user is added as an individual approver and is also part of a group approver,
|
||||||
|
|
|
@ -1,70 +1,8 @@
|
||||||
---
|
---
|
||||||
stage: Enablement
|
redirect_to: advanced_search.md
|
||||||
group: Global Search
|
|
||||||
info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments"
|
|
||||||
type: reference
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# Advanced Search **(PREMIUM)**
|
This document was moved to [another location](advanced_search.md).
|
||||||
|
|
||||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/109) in GitLab 8.4.
|
<!-- This redirect file can be deleted after <2021-02-12>. -->
|
||||||
> - [Moved](../../subscriptions/bronze_starter.md) to GitLab Premium in 13.9.
|
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page -->
|
||||||
|
|
||||||
NOTE:
|
|
||||||
Advanced Search (powered by Elasticsearch) is enabled for Bronze and above on GitLab.com since 2020-07-10.
|
|
||||||
|
|
||||||
Leverage Elasticsearch for faster, more advanced code search across your entire
|
|
||||||
GitLab instance.
|
|
||||||
|
|
||||||
This is the user documentation. To install and configure Elasticsearch,
|
|
||||||
visit the [administrator documentation](../../integration/elasticsearch.md).
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
The Advanced Search in GitLab is a powerful search service that saves
|
|
||||||
you time. Instead of creating duplicate code and wasting time, you can
|
|
||||||
now search for code within other projects that can help your own project.
|
|
||||||
|
|
||||||
GitLab leverages the search capabilities of [Elasticsearch](https://www.elastic.co/elasticsearch/) and enables it when
|
|
||||||
searching in:
|
|
||||||
|
|
||||||
- Projects
|
|
||||||
- Issues
|
|
||||||
- Merge requests
|
|
||||||
- Milestones
|
|
||||||
- Comments
|
|
||||||
- Code
|
|
||||||
- Commits
|
|
||||||
- Wiki
|
|
||||||
- Users
|
|
||||||
|
|
||||||
## Use cases
|
|
||||||
|
|
||||||
The Advanced Search can be useful in various scenarios.
|
|
||||||
|
|
||||||
### Faster searches
|
|
||||||
|
|
||||||
Advanced Search is based on Elasticsearch, which is a purpose built full text search engine that can be horizontally scaled so that it can provide search results in 1-2 seconds in most cases.
|
|
||||||
|
|
||||||
### Promote innersourcing
|
|
||||||
|
|
||||||
Your company may consist of many different developer teams each of which has
|
|
||||||
their own group where the various projects are hosted. Some of your applications
|
|
||||||
may be connected to each other, so your developers need to instantly search
|
|
||||||
throughout the GitLab instance and find the code they search for.
|
|
||||||
|
|
||||||
## Searching globally
|
|
||||||
|
|
||||||
Just use the search as before and GitLab will show you matching code from each
|
|
||||||
project you have access to.
|
|
||||||
|
|
||||||
![Advanced Search](img/advanced_global_search.png)
|
|
||||||
|
|
||||||
You can also use the [Advanced Search Syntax](advanced_search_syntax.md) which
|
|
||||||
provides some useful queries.
|
|
||||||
|
|
||||||
NOTE:
|
|
||||||
Elasticsearch has only data for the default branch. That means that if you go
|
|
||||||
to the repository tree and switch the branch from the default to something else,
|
|
||||||
then the "Code" tab in the search result page will be served by the basic
|
|
||||||
search even if Elasticsearch is enabled.
|
|
||||||
|
|
|
@ -0,0 +1,115 @@
|
||||||
|
---
|
||||||
|
stage: Enablement
|
||||||
|
group: Global Search
|
||||||
|
info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments"
|
||||||
|
type: reference
|
||||||
|
---
|
||||||
|
|
||||||
|
# GitLab Advanced Search **(PREMIUM)**
|
||||||
|
|
||||||
|
> - Moved to GitLab Premium in 13.9.
|
||||||
|
|
||||||
|
NOTE:
|
||||||
|
This is the user documentation. To configure the Advanced Search,
|
||||||
|
visit the [administrator documentation](../../integration/elasticsearch.md).
|
||||||
|
|
||||||
|
GitLab Advanced Search expands on the Basic Search with an additional set of
|
||||||
|
features for faster, more advanced searches across the entire GitLab instance
|
||||||
|
when searching in:
|
||||||
|
|
||||||
|
- Projects
|
||||||
|
- Issues
|
||||||
|
- Merge requests
|
||||||
|
- Milestones
|
||||||
|
- Epics
|
||||||
|
- Comments
|
||||||
|
- Code
|
||||||
|
- Commits
|
||||||
|
- Wiki
|
||||||
|
- Users
|
||||||
|
|
||||||
|
The Advanced Search can be useful in various scenarios:
|
||||||
|
|
||||||
|
- **Faster searches:**
|
||||||
|
Advanced Search is based on Elasticsearch, which is a purpose-built full
|
||||||
|
text search engine that can be horizontally scaled so that it can provide
|
||||||
|
search results in 1-2 seconds in most cases.
|
||||||
|
- **Promote innersourcing:**
|
||||||
|
Your company may consist of many different developer teams each of which has
|
||||||
|
their own group where the various projects are hosted. Some of your applications
|
||||||
|
may be connected to each other, so your developers need to instantly search
|
||||||
|
throughout the GitLab instance and find the code they search for.
|
||||||
|
|
||||||
|
## Use the Advanced Search syntax
|
||||||
|
|
||||||
|
Elasticsearch has only data for the default branch. That means that if you go
|
||||||
|
to the repository tree and switch the branch from the default to something else,
|
||||||
|
then the "Code" tab in the search result page will be served by the basic
|
||||||
|
search even if Elasticsearch is enabled.
|
||||||
|
|
||||||
|
The Advanced Search syntax supports fuzzy or exact search queries with prefixes,
|
||||||
|
boolean operators, and much more. Use the search as before and GitLab will show
|
||||||
|
you matching code from each project you have access to.
|
||||||
|
|
||||||
|
![Advanced Search](img/advanced_search_v13.10.png)
|
||||||
|
|
||||||
|
Full details can be found in the [Elasticsearch documentation](https://www.elastic.co/guide/en/elasticsearch/reference/5.3/query-dsl-simple-query-string-query.html#_simple_query_string_syntax), but
|
||||||
|
here's a quick guide:
|
||||||
|
|
||||||
|
- Searches look for all the words in a query, in any order - e.g.: searching
|
||||||
|
issues for [`display bug`](https://gitlab.com/search?utf8=%E2%9C%93&snippets=&scope=issues&repository_ref=&search=display+bug&group_id=9970&project_id=278964) and [`bug display`](https://gitlab.com/search?utf8=%E2%9C%93&snippets=&scope=issues&repository_ref=&search=bug+Display&group_id=9970&project_id=278964) will return the same results.
|
||||||
|
- To find the exact phrase (stemming still applies), use double quotes: [`"display bug"`](https://gitlab.com/search?utf8=%E2%9C%93&snippets=&scope=issues&repository_ref=&search=%22display+bug%22&group_id=9970&project_id=278964)
|
||||||
|
- To find bugs not mentioning display, use `-`: [`bug -display`](https://gitlab.com/search?utf8=%E2%9C%93&snippets=&scope=issues&repository_ref=&search=bug+-display&group_id=9970&project_id=278964)
|
||||||
|
- To find a bug in display or banner, use `|`: [`bug display | banner`](https://gitlab.com/search?utf8=%E2%9C%93&snippets=&scope=issues&repository_ref=&search=bug+display+%7C+banner&group_id=9970&project_id=278964)
|
||||||
|
- To group terms together, use parentheses: [`bug | (display +banner)`](https://gitlab.com/search?utf8=%E2%9C%93&snippets=&scope=issues&repository_ref=&search=bug+%7C+%28display+%2Bbanner%29&group_id=9970&project_id=278964)
|
||||||
|
- To match a partial word, use `*`. In this example, I want to find bugs with any 500 errors. : [`bug error 50*`](https://gitlab.com/search?utf8=%E2%9C%93&snippets=&scope=issues&repository_ref=&search=bug+error+50*&group_id=9970&project_id=278964)
|
||||||
|
- To use one of symbols above literally, escape the symbol with a preceding `\`: [`argument \-last`](https://gitlab.com/search?utf8=%E2%9C%93&snippets=&scope=blobs&repository_ref=&search=argument+%5C-last&group_id=9970&project_id=278964)
|
||||||
|
|
||||||
|
## Syntax search filters
|
||||||
|
|
||||||
|
Advanced Search also supports the use of filters. The available filters are:
|
||||||
|
|
||||||
|
- `filename`: Filters by filename. You can use the glob (`*`) operator for fuzzy matching.
|
||||||
|
- `path`: Filters by path. You can use the glob (`*`) operator for fuzzy matching.
|
||||||
|
- `extension`: Filters by extension in the filename. Please write the extension without a leading dot. Exact match only.
|
||||||
|
- `blob`: Filters by Git `object ID`. Exact match only.
|
||||||
|
|
||||||
|
To use them, add them to your keyword in the format `<filter_name>:<value>` without
|
||||||
|
any spaces between the colon (`:`) and the value. When no keyword is provided, an asterisk (`*`) will be used as the keyword.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
- Finding a file with any content named `search_results.rb`: [`* filename:search_results.rb`](https://gitlab.com/search?utf8=%E2%9C%93&snippets=&scope=blobs&repository_ref=&search=*+filename%3Asearch_results.rb&group_id=9970&project_id=278964)
|
||||||
|
- The leading asterisk (`*`) can be ignored in the case above: [`filename:search_results.rb`](https://gitlab.com/search?group_id=9970&project_id=278964&scope=blobs&search=filename%3Asearch_results.rb)
|
||||||
|
- Finding a file named `found_blob_spec.rb` with the text `CHANGELOG` inside of it: [`CHANGELOG filename:found_blob_spec.rb`](https://gitlab.com/search?utf8=%E2%9C%93&snippets=&scope=blobs&repository_ref=&search=CHANGELOG+filename%3Afound_blob_spec.rb&group_id=9970&project_id=278964)
|
||||||
|
- Finding the text `EpicLinks` inside files with the `.rb` extension: [`EpicLinks extension:rb`](https://gitlab.com/search?utf8=%E2%9C%93&snippets=&scope=blobs&repository_ref=&search=EpicLinks+extension%3Arb&group_id=9970&project_id=278964)
|
||||||
|
- Finding any file with the `.yaml` extension: [`extension:yaml`](https://gitlab.com/search?utf8=%E2%9C%93&snippets=&scope=blobs&repository_ref=&search=extension%3Ayaml&group_id=9970&project_id=278964)
|
||||||
|
- Finding the text `Sidekiq` in a file, when that file is in a path that includes `elastic`: [`Sidekiq path:elastic`](https://gitlab.com/search?utf8=%E2%9C%93&snippets=&scope=blobs&repository_ref=&search=Sidekiq+path%3Aelastic&group_id=9970&project_id=278964)
|
||||||
|
- Finding any file in a path that includes `elasticsearch`: [`path:elasticsearch`](https://gitlab.com/search?utf8=%E2%9C%93&snippets=&scope=blobs&repository_ref=&search=path%3Aelasticsearch&group_id=9970&project_id=278964)
|
||||||
|
- Finding the files represented by the Git object ID `998707b421c89bd9a3063333f9f728ef3e43d101`: [`* blob:998707b421c89bd9a3063333f9f728ef3e43d101`](https://gitlab.com/search?utf8=%E2%9C%93&snippets=false&scope=blobs&repository_ref=&search=*+blob%3A998707b421c89bd9a3063333f9f728ef3e43d101&group_id=9970)
|
||||||
|
- Syntax filters can be combined for complex filtering. Finding any file starting with `search` containing `eventHub` and with the `.js` extension: [`eventHub filename:search* extension:js`](https://gitlab.com/search?utf8=%E2%9C%93&snippets=&scope=blobs&repository_ref=&search=eventHub+filename%3Asearch*+extension%3Ajs&group_id=9970&project_id=278964)
|
||||||
|
|
||||||
|
### Excluding filters
|
||||||
|
|
||||||
|
[Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/31684) in GitLab Starter 13.3.
|
||||||
|
|
||||||
|
Filters can be inverted to **filter out** results from the result set, by prefixing the filter name with a `-` (hyphen) character, such as:
|
||||||
|
|
||||||
|
- `-filename`
|
||||||
|
- `-path`
|
||||||
|
- `-extension`
|
||||||
|
- `-blob`
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
- Finding `rails` in all files but `Gemfile.lock`: [`rails -filename:Gemfile.lock`](https://gitlab.com/search?utf8=%E2%9C%93&snippets=&scope=blobs&repository_ref=&search=rails+-filename%3AGemfile.lock&group_id=9970&project_id=278964)
|
||||||
|
- Finding `success` in all files excluding `.po|pot` files: [`success -filename:*.po*`](https://gitlab.com/search?utf8=%E2%9C%93&snippets=&scope=blobs&repository_ref=&search=success+-filename%3A*.po*&group_id=9970&project_id=278964)
|
||||||
|
- Finding `import` excluding minified JavaScript (`.min.js`) files: [`import -extension:min.js`](https://gitlab.com/search?utf8=%E2%9C%93&snippets=&scope=blobs&repository_ref=&search=import+-extension%3Amin.js&group_id=9970&project_id=278964)
|
||||||
|
- Finding `docs` for all files outside the `docs/` folder: [`docs -path:docs/`](https://gitlab.com/search?utf8=%E2%9C%93&snippets=&scope=blobs&repository_ref=&search=docs+-path%3Adocs%2F&group_id=9970&project_id=278964)
|
||||||
|
|
||||||
|
## Search by issue or merge request ID
|
||||||
|
|
||||||
|
You can search a specific issue or merge request by its ID with a special prefix.
|
||||||
|
|
||||||
|
- To search by issue ID, use prefix `#` followed by issue ID. For example, [#23456](https://gitlab.com/search?utf8=%E2%9C%93&snippets=&scope=issues&repository_ref=&search=%2323456&group_id=9970&project_id=278964)
|
||||||
|
- To search by merge request ID, use prefix `!` followed by merge request ID. For example [!23456](https://gitlab.com/search?utf8=%E2%9C%93&snippets=&scope=merge_requests&repository_ref=&search=%2123456&group_id=9970&project_id=278964)
|
|
@ -1,90 +1,8 @@
|
||||||
---
|
---
|
||||||
stage: Enablement
|
redirect_to: advanced_search.md
|
||||||
group: Global Search
|
|
||||||
info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments"
|
|
||||||
type: reference
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# Advanced Search Syntax **(PREMIUM)**
|
This document was moved to [another location](advanced_search.md).
|
||||||
|
|
||||||
> - Introduced in [GitLab](https://about.gitlab.com/pricing/) 9.2.
|
<!-- This redirect file can be deleted after <2021-02-12>. -->
|
||||||
> - [Moved](../../subscriptions/bronze_starter.md) to GitLab Premium in 13.9.
|
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page -->
|
||||||
|
|
||||||
Use advanced queries for more targeted search results.
|
|
||||||
|
|
||||||
This is the user documentation. To install and configure Elasticsearch,
|
|
||||||
visit the [administrator documentation](../../integration/elasticsearch.md).
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
The Advanced Search Syntax is a subset of the
|
|
||||||
[Advanced Search](advanced_global_search.md), which you can use if you
|
|
||||||
want to have more specific search results.
|
|
||||||
|
|
||||||
Advanced Search only supports searching the [default branch](../project/repository/branches/index.md#default-branch).
|
|
||||||
|
|
||||||
## Using the Advanced Search Syntax
|
|
||||||
|
|
||||||
The Advanced Search Syntax supports fuzzy or exact search queries with prefixes,
|
|
||||||
boolean operators, and much more.
|
|
||||||
|
|
||||||
Full details can be found in the [Elasticsearch documentation](https://www.elastic.co/guide/en/elasticsearch/reference/5.3/query-dsl-simple-query-string-query.html#_simple_query_string_syntax), but
|
|
||||||
here's a quick guide:
|
|
||||||
|
|
||||||
- Searches look for all the words in a query, in any order - e.g.: searching
|
|
||||||
issues for [`display bug`](https://gitlab.com/search?utf8=%E2%9C%93&snippets=&scope=issues&repository_ref=&search=display+bug&group_id=9970&project_id=278964) and [`bug display`](https://gitlab.com/search?utf8=%E2%9C%93&snippets=&scope=issues&repository_ref=&search=bug+Display&group_id=9970&project_id=278964) will return the same results.
|
|
||||||
- To find the exact phrase (stemming still applies), use double quotes: [`"display bug"`](https://gitlab.com/search?utf8=%E2%9C%93&snippets=&scope=issues&repository_ref=&search=%22display+bug%22&group_id=9970&project_id=278964)
|
|
||||||
- To find bugs not mentioning display, use `-`: [`bug -display`](https://gitlab.com/search?utf8=%E2%9C%93&snippets=&scope=issues&repository_ref=&search=bug+-display&group_id=9970&project_id=278964)
|
|
||||||
- To find a bug in display or banner, use `|`: [`bug display | banner`](https://gitlab.com/search?utf8=%E2%9C%93&snippets=&scope=issues&repository_ref=&search=bug+display+%7C+banner&group_id=9970&project_id=278964)
|
|
||||||
- To group terms together, use parentheses: [`bug | (display +banner)`](https://gitlab.com/search?utf8=%E2%9C%93&snippets=&scope=issues&repository_ref=&search=bug+%7C+%28display+%2Bbanner%29&group_id=9970&project_id=278964)
|
|
||||||
- To match a partial word, use `*`. In this example, I want to find bugs with any 500 errors. : [`bug error 50*`](https://gitlab.com/search?utf8=%E2%9C%93&snippets=&scope=issues&repository_ref=&search=bug+error+50*&group_id=9970&project_id=278964)
|
|
||||||
- To use one of symbols above literally, escape the symbol with a preceding `\`: [`argument \-last`](https://gitlab.com/search?utf8=%E2%9C%93&snippets=&scope=blobs&repository_ref=&search=argument+%5C-last&group_id=9970&project_id=278964)
|
|
||||||
|
|
||||||
### Syntax search filters
|
|
||||||
|
|
||||||
The Advanced Search Syntax also supports the use of filters. The available filters are:
|
|
||||||
|
|
||||||
- filename: Filters by filename. You can use the glob (`*`) operator for fuzzy matching.
|
|
||||||
- path: Filters by path. You can use the glob (`*`) operator for fuzzy matching.
|
|
||||||
- extension: Filters by extension in the filename. Please write the extension without a leading dot. Exact match only.
|
|
||||||
- blob: Filters by Git `object ID`. Exact match only.
|
|
||||||
|
|
||||||
To use them, add them to your keyword in the format `<filter_name>:<value>` without
|
|
||||||
any spaces between the colon (`:`) and the value. When no keyword is provided, an asterisk (`*`) will be used as the keyword.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
|
|
||||||
- Finding a file with any content named `search_results.rb`: [`* filename:search_results.rb`](https://gitlab.com/search?utf8=%E2%9C%93&snippets=&scope=blobs&repository_ref=&search=*+filename%3Asearch_results.rb&group_id=9970&project_id=278964)
|
|
||||||
- The leading asterisk (`*`) can be ignored in the case above: [`filename:search_results.rb`](https://gitlab.com/search?group_id=9970&project_id=278964&scope=blobs&search=filename%3Asearch_results.rb)
|
|
||||||
- Finding a file named `found_blob_spec.rb` with the text `CHANGELOG` inside of it: [`CHANGELOG filename:found_blob_spec.rb`](https://gitlab.com/search?utf8=%E2%9C%93&snippets=&scope=blobs&repository_ref=&search=CHANGELOG+filename%3Afound_blob_spec.rb&group_id=9970&project_id=278964)
|
|
||||||
- Finding the text `EpicLinks` inside files with the `.rb` extension: [`EpicLinks extension:rb`](https://gitlab.com/search?utf8=%E2%9C%93&snippets=&scope=blobs&repository_ref=&search=EpicLinks+extension%3Arb&group_id=9970&project_id=278964)
|
|
||||||
- Finding any file with the `.yaml` extension: [`extension:yaml`](https://gitlab.com/search?utf8=%E2%9C%93&snippets=&scope=blobs&repository_ref=&search=extension%3Ayaml&group_id=9970&project_id=278964)
|
|
||||||
- Finding the text `Sidekiq` in a file, when that file is in a path that includes `elastic`: [`Sidekiq path:elastic`](https://gitlab.com/search?utf8=%E2%9C%93&snippets=&scope=blobs&repository_ref=&search=Sidekiq+path%3Aelastic&group_id=9970&project_id=278964)
|
|
||||||
- Finding any file in a path that includes `elasticsearch`: [`path:elasticsearch`](https://gitlab.com/search?utf8=%E2%9C%93&snippets=&scope=blobs&repository_ref=&search=path%3Aelasticsearch&group_id=9970&project_id=278964)
|
|
||||||
- Finding the files represented by the Git object ID `998707b421c89bd9a3063333f9f728ef3e43d101`: [`* blob:998707b421c89bd9a3063333f9f728ef3e43d101`](https://gitlab.com/search?utf8=%E2%9C%93&snippets=false&scope=blobs&repository_ref=&search=*+blob%3A998707b421c89bd9a3063333f9f728ef3e43d101&group_id=9970)
|
|
||||||
- Syntax filters can be combined for complex filtering. Finding any file starting with `search` containing `eventHub` and with the `.js` extension: [`eventHub filename:search* extension:js`](https://gitlab.com/search?utf8=%E2%9C%93&snippets=&scope=blobs&repository_ref=&search=eventHub+filename%3Asearch*+extension%3Ajs&group_id=9970&project_id=278964)
|
|
||||||
|
|
||||||
#### Excluding filters
|
|
||||||
|
|
||||||
[Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/31684) in GitLab Starter 13.3.
|
|
||||||
|
|
||||||
Filters can be inverted to **filter out** results from the result set, by prefixing the filter name with a `-` (hyphen) character, such as:
|
|
||||||
|
|
||||||
- `-filename`
|
|
||||||
- `-path`
|
|
||||||
- `-extension`
|
|
||||||
- `-blob`
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
|
|
||||||
- Finding `rails` in all files but `Gemfile.lock`: [`rails -filename:Gemfile.lock`](https://gitlab.com/search?utf8=%E2%9C%93&snippets=&scope=blobs&repository_ref=&search=rails+-filename%3AGemfile.lock&group_id=9970&project_id=278964)
|
|
||||||
- Finding `success` in all files excluding `.po|pot` files: [`success -filename:*.po*`](https://gitlab.com/search?utf8=%E2%9C%93&snippets=&scope=blobs&repository_ref=&search=success+-filename%3A*.po*&group_id=9970&project_id=278964)
|
|
||||||
- Finding `import` excluding minified JavaScript (`.min.js`) files: [`import -extension:min.js`](https://gitlab.com/search?utf8=%E2%9C%93&snippets=&scope=blobs&repository_ref=&search=import+-extension%3Amin.js&group_id=9970&project_id=278964)
|
|
||||||
- Finding `docs` for all files outside the `docs/` folder: [`docs -path:docs/`](https://gitlab.com/search?utf8=%E2%9C%93&snippets=&scope=blobs&repository_ref=&search=docs+-path%3Adocs%2F&group_id=9970&project_id=278964)
|
|
||||||
|
|
||||||
### Search by issue or merge request ID
|
|
||||||
|
|
||||||
You can search a specific issue or merge request by its ID with a special prefix.
|
|
||||||
|
|
||||||
- To search by issue ID, use prefix `#` followed by issue ID. For example, [#23456](https://gitlab.com/search?utf8=%E2%9C%93&snippets=&scope=issues&repository_ref=&search=%2323456&group_id=9970&project_id=278964)
|
|
||||||
- To search by merge request ID, use prefix `!` followed by merge request ID. For example [!23456](https://gitlab.com/search?utf8=%E2%9C%93&snippets=&scope=merge_requests&repository_ref=&search=%2123456&group_id=9970&project_id=278964)
|
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 15 KiB |
Binary file not shown.
After Width: | Height: | Size: 46 KiB |
|
@ -298,13 +298,7 @@ redirected to the commit result and given the option to return to the search res
|
||||||
Leverage Elasticsearch for faster, more advanced code search across your entire
|
Leverage Elasticsearch for faster, more advanced code search across your entire
|
||||||
GitLab instance.
|
GitLab instance.
|
||||||
|
|
||||||
[Learn how to use the Advanced Search.](advanced_global_search.md)
|
[Learn how to use the Advanced Search.](advanced_search.md)
|
||||||
|
|
||||||
## Advanced Search Syntax **(PREMIUM)**
|
|
||||||
|
|
||||||
Use advanced queries for more targeted search results.
|
|
||||||
|
|
||||||
[Learn how to use the Advanced Search Syntax.](advanced_search_syntax.md)
|
|
||||||
|
|
||||||
## Search settings
|
## Search settings
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ module API
|
||||||
use :pagination
|
use :pagination
|
||||||
end
|
end
|
||||||
get '/' do
|
get '/' do
|
||||||
authorize!(:read_board, user_project)
|
authorize!(:read_issue_board, user_project)
|
||||||
present paginate(board_parent.boards.with_associations), with: Entities::Board
|
present paginate(board_parent.boards.with_associations), with: Entities::Board
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ module API
|
||||||
success Entities::Board
|
success Entities::Board
|
||||||
end
|
end
|
||||||
get '/:board_id' do
|
get '/:board_id' do
|
||||||
authorize!(:read_board, user_project)
|
authorize!(:read_issue_board, user_project)
|
||||||
present board, with: Entities::Board
|
present board, with: Entities::Board
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ module API
|
||||||
requires :name, type: String, desc: 'The board name'
|
requires :name, type: String, desc: 'The board name'
|
||||||
end
|
end
|
||||||
post '/' do
|
post '/' do
|
||||||
authorize!(:admin_board, board_parent)
|
authorize!(:admin_issue_board, board_parent)
|
||||||
|
|
||||||
create_board
|
create_board
|
||||||
end
|
end
|
||||||
|
@ -64,7 +64,7 @@ module API
|
||||||
use :update_params
|
use :update_params
|
||||||
end
|
end
|
||||||
put '/:board_id' do
|
put '/:board_id' do
|
||||||
authorize!(:admin_board, board_parent)
|
authorize!(:admin_issue_board, board_parent)
|
||||||
|
|
||||||
update_board
|
update_board
|
||||||
end
|
end
|
||||||
|
@ -75,7 +75,7 @@ module API
|
||||||
end
|
end
|
||||||
|
|
||||||
delete '/:board_id' do
|
delete '/:board_id' do
|
||||||
authorize!(:admin_board, board_parent)
|
authorize!(:admin_issue_board, board_parent)
|
||||||
|
|
||||||
delete_board
|
delete_board
|
||||||
end
|
end
|
||||||
|
@ -93,7 +93,7 @@ module API
|
||||||
use :pagination
|
use :pagination
|
||||||
end
|
end
|
||||||
get '/lists' do
|
get '/lists' do
|
||||||
authorize!(:read_board, user_project)
|
authorize!(:read_issue_board, user_project)
|
||||||
present paginate(board_lists), with: Entities::List
|
present paginate(board_lists), with: Entities::List
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -105,7 +105,7 @@ module API
|
||||||
requires :list_id, type: Integer, desc: 'The ID of a list'
|
requires :list_id, type: Integer, desc: 'The ID of a list'
|
||||||
end
|
end
|
||||||
get '/lists/:list_id' do
|
get '/lists/:list_id' do
|
||||||
authorize!(:read_board, user_project)
|
authorize!(:read_issue_board, user_project)
|
||||||
present board_lists.find(params[:list_id]), with: Entities::List
|
present board_lists.find(params[:list_id]), with: Entities::List
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -117,7 +117,7 @@ module API
|
||||||
use :list_creation_params
|
use :list_creation_params
|
||||||
end
|
end
|
||||||
post '/lists' do
|
post '/lists' do
|
||||||
authorize!(:admin_list, user_project)
|
authorize!(:admin_issue_board_list, user_project)
|
||||||
|
|
||||||
create_list
|
create_list
|
||||||
end
|
end
|
||||||
|
@ -133,7 +133,7 @@ module API
|
||||||
put '/lists/:list_id' do
|
put '/lists/:list_id' do
|
||||||
list = board_lists.find(params[:list_id])
|
list = board_lists.find(params[:list_id])
|
||||||
|
|
||||||
authorize!(:admin_list, user_project)
|
authorize!(:admin_issue_board_list, user_project)
|
||||||
|
|
||||||
move_list(list)
|
move_list(list)
|
||||||
end
|
end
|
||||||
|
@ -146,7 +146,7 @@ module API
|
||||||
requires :list_id, type: Integer, desc: 'The ID of a board list'
|
requires :list_id, type: Integer, desc: 'The ID of a board list'
|
||||||
end
|
end
|
||||||
delete "/lists/:list_id" do
|
delete "/lists/:list_id" do
|
||||||
authorize!(:admin_list, user_project)
|
authorize!(:admin_issue_board_list, user_project)
|
||||||
list = board_lists.find(params[:list_id])
|
list = board_lists.find(params[:list_id])
|
||||||
|
|
||||||
destroy_list(list)
|
destroy_list(list)
|
||||||
|
|
|
@ -30,7 +30,7 @@ module API
|
||||||
use :pagination
|
use :pagination
|
||||||
end
|
end
|
||||||
get '/' do
|
get '/' do
|
||||||
authorize!(:read_board, user_group)
|
authorize!(:read_issue_board, user_group)
|
||||||
present paginate(board_parent.boards.with_associations), with: Entities::Board
|
present paginate(board_parent.boards.with_associations), with: Entities::Board
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ module API
|
||||||
success Entities::Board
|
success Entities::Board
|
||||||
end
|
end
|
||||||
get '/:board_id' do
|
get '/:board_id' do
|
||||||
authorize!(:read_board, user_group)
|
authorize!(:read_issue_board, user_group)
|
||||||
present board, with: Entities::Board
|
present board, with: Entities::Board
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ module API
|
||||||
use :update_params
|
use :update_params
|
||||||
end
|
end
|
||||||
put '/:board_id' do
|
put '/:board_id' do
|
||||||
authorize!(:admin_board, board_parent)
|
authorize!(:admin_issue_board, board_parent)
|
||||||
|
|
||||||
update_board
|
update_board
|
||||||
end
|
end
|
||||||
|
@ -69,7 +69,7 @@ module API
|
||||||
use :pagination
|
use :pagination
|
||||||
end
|
end
|
||||||
get '/lists' do
|
get '/lists' do
|
||||||
authorize!(:read_board, user_group)
|
authorize!(:read_issue_board, user_group)
|
||||||
present paginate(board_lists), with: Entities::List
|
present paginate(board_lists), with: Entities::List
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ module API
|
||||||
requires :list_id, type: Integer, desc: 'The ID of a list'
|
requires :list_id, type: Integer, desc: 'The ID of a list'
|
||||||
end
|
end
|
||||||
get '/lists/:list_id' do
|
get '/lists/:list_id' do
|
||||||
authorize!(:read_board, user_group)
|
authorize!(:read_issue_board, user_group)
|
||||||
present board_lists.find(params[:list_id]), with: Entities::List
|
present board_lists.find(params[:list_id]), with: Entities::List
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -93,7 +93,7 @@ module API
|
||||||
use :list_creation_params
|
use :list_creation_params
|
||||||
end
|
end
|
||||||
post '/lists' do
|
post '/lists' do
|
||||||
authorize!(:admin_list, user_group)
|
authorize!(:admin_issue_board_list, user_group)
|
||||||
|
|
||||||
create_list
|
create_list
|
||||||
end
|
end
|
||||||
|
@ -109,7 +109,7 @@ module API
|
||||||
put '/lists/:list_id' do
|
put '/lists/:list_id' do
|
||||||
list = board_lists.find(params[:list_id])
|
list = board_lists.find(params[:list_id])
|
||||||
|
|
||||||
authorize!(:admin_list, user_group)
|
authorize!(:admin_issue_board_list, user_group)
|
||||||
|
|
||||||
move_list(list)
|
move_list(list)
|
||||||
end
|
end
|
||||||
|
@ -122,7 +122,7 @@ module API
|
||||||
requires :list_id, type: Integer, desc: 'The ID of a board list'
|
requires :list_id, type: Integer, desc: 'The ID of a board list'
|
||||||
end
|
end
|
||||||
delete "/lists/:list_id" do
|
delete "/lists/:list_id" do
|
||||||
authorize!(:admin_list, user_group)
|
authorize!(:admin_issue_board_list, user_group)
|
||||||
list = board_lists.find(params[:list_id])
|
list = board_lists.find(params[:list_id])
|
||||||
|
|
||||||
destroy_list(list)
|
destroy_list(list)
|
||||||
|
|
|
@ -29,7 +29,7 @@ RSpec.describe Groups::BoardsController do
|
||||||
expect(Ability).to receive(:allowed?).with(user, :log_in, :global).and_call_original
|
expect(Ability).to receive(:allowed?).with(user, :log_in, :global).and_call_original
|
||||||
allow(Ability).to receive(:allowed?).with(user, :read_cross_project, :global).and_return(true)
|
allow(Ability).to receive(:allowed?).with(user, :read_cross_project, :global).and_return(true)
|
||||||
allow(Ability).to receive(:allowed?).with(user, :read_group, group).and_return(true)
|
allow(Ability).to receive(:allowed?).with(user, :read_group, group).and_return(true)
|
||||||
allow(Ability).to receive(:allowed?).with(user, :read_board, group).and_return(false)
|
allow(Ability).to receive(:allowed?).with(user, :read_issue_board, group).and_return(false)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns a not found 404 response' do
|
it 'returns a not found 404 response' do
|
||||||
|
@ -74,7 +74,7 @@ RSpec.describe Groups::BoardsController do
|
||||||
expect(Ability).to receive(:allowed?).with(user, :log_in, :global).and_call_original
|
expect(Ability).to receive(:allowed?).with(user, :log_in, :global).and_call_original
|
||||||
allow(Ability).to receive(:allowed?).with(user, :read_cross_project, :global).and_return(true)
|
allow(Ability).to receive(:allowed?).with(user, :read_cross_project, :global).and_return(true)
|
||||||
allow(Ability).to receive(:allowed?).with(user, :read_group, group).and_return(true)
|
allow(Ability).to receive(:allowed?).with(user, :read_group, group).and_return(true)
|
||||||
allow(Ability).to receive(:allowed?).with(user, :read_board, group).and_return(false)
|
allow(Ability).to receive(:allowed?).with(user, :read_issue_board, group).and_return(false)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns a not found 404 response' do
|
it 'returns a not found 404 response' do
|
||||||
|
@ -111,7 +111,7 @@ RSpec.describe Groups::BoardsController do
|
||||||
expect(Ability).to receive(:allowed?).with(user, :log_in, :global).and_call_original
|
expect(Ability).to receive(:allowed?).with(user, :log_in, :global).and_call_original
|
||||||
allow(Ability).to receive(:allowed?).with(user, :read_cross_project, :global).and_return(true)
|
allow(Ability).to receive(:allowed?).with(user, :read_cross_project, :global).and_return(true)
|
||||||
allow(Ability).to receive(:allowed?).with(user, :read_group, group).and_return(true)
|
allow(Ability).to receive(:allowed?).with(user, :read_group, group).and_return(true)
|
||||||
allow(Ability).to receive(:allowed?).with(user, :read_board, group).and_return(false)
|
allow(Ability).to receive(:allowed?).with(user, :read_issue_board, group).and_return(false)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns a not found 404 response' do
|
it 'returns a not found 404 response' do
|
||||||
|
|
|
@ -34,7 +34,7 @@ RSpec.describe Projects::BoardsController do
|
||||||
before do
|
before do
|
||||||
expect(Ability).to receive(:allowed?).with(user, :log_in, :global).and_call_original
|
expect(Ability).to receive(:allowed?).with(user, :log_in, :global).and_call_original
|
||||||
allow(Ability).to receive(:allowed?).with(user, :read_project, project).and_return(true)
|
allow(Ability).to receive(:allowed?).with(user, :read_project, project).and_return(true)
|
||||||
allow(Ability).to receive(:allowed?).with(user, :read_board, project).and_return(false)
|
allow(Ability).to receive(:allowed?).with(user, :read_issue_board, project).and_return(false)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns a not found 404 response' do
|
it 'returns a not found 404 response' do
|
||||||
|
@ -78,7 +78,7 @@ RSpec.describe Projects::BoardsController do
|
||||||
before do
|
before do
|
||||||
expect(Ability).to receive(:allowed?).with(user, :log_in, :global).and_call_original
|
expect(Ability).to receive(:allowed?).with(user, :log_in, :global).and_call_original
|
||||||
allow(Ability).to receive(:allowed?).with(user, :read_project, project).and_return(true)
|
allow(Ability).to receive(:allowed?).with(user, :read_project, project).and_return(true)
|
||||||
allow(Ability).to receive(:allowed?).with(user, :read_board, project).and_return(false)
|
allow(Ability).to receive(:allowed?).with(user, :read_issue_board, project).and_return(false)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns a not found 404 response' do
|
it 'returns a not found 404 response' do
|
||||||
|
@ -134,7 +134,7 @@ RSpec.describe Projects::BoardsController do
|
||||||
before do
|
before do
|
||||||
expect(Ability).to receive(:allowed?).with(user, :log_in, :global).and_call_original
|
expect(Ability).to receive(:allowed?).with(user, :log_in, :global).and_call_original
|
||||||
allow(Ability).to receive(:allowed?).with(user, :read_project, project).and_return(true)
|
allow(Ability).to receive(:allowed?).with(user, :read_project, project).and_return(true)
|
||||||
allow(Ability).to receive(:allowed?).with(user, :read_board, project).and_return(false)
|
allow(Ability).to receive(:allowed?).with(user, :read_issue_board, project).and_return(false)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns a not found 404 response' do
|
it 'returns a not found 404 response' do
|
||||||
|
@ -172,7 +172,7 @@ RSpec.describe Projects::BoardsController do
|
||||||
before do
|
before do
|
||||||
expect(Ability).to receive(:allowed?).with(user, :log_in, :global).and_call_original
|
expect(Ability).to receive(:allowed?).with(user, :log_in, :global).and_call_original
|
||||||
allow(Ability).to receive(:allowed?).with(user, :read_project, project).and_return(true)
|
allow(Ability).to receive(:allowed?).with(user, :read_project, project).and_return(true)
|
||||||
allow(Ability).to receive(:allowed?).with(user, :read_board, project).and_return(false)
|
allow(Ability).to receive(:allowed?).with(user, :read_issue_board, project).and_return(false)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns a not found 404 response' do
|
it 'returns a not found 404 response' do
|
||||||
|
|
|
@ -20,7 +20,7 @@ RSpec.describe Mutations::Boards::Update do
|
||||||
|
|
||||||
subject { mutation.resolve(**mutation_params) }
|
subject { mutation.resolve(**mutation_params) }
|
||||||
|
|
||||||
specify { expect(described_class).to require_graphql_authorizations(:admin_board) }
|
specify { expect(described_class).to require_graphql_authorizations(:admin_issue_board) }
|
||||||
|
|
||||||
describe '#resolve' do
|
describe '#resolve' do
|
||||||
context 'when the user cannot admin the board' do
|
context 'when the user cannot admin the board' do
|
||||||
|
|
|
@ -6,6 +6,6 @@ RSpec.describe GitlabSchema.types['AccessLevelEnum'] do
|
||||||
specify { expect(described_class.graphql_name).to eq('AccessLevelEnum') }
|
specify { expect(described_class.graphql_name).to eq('AccessLevelEnum') }
|
||||||
|
|
||||||
it 'exposes all the existing access levels' do
|
it 'exposes all the existing access levels' do
|
||||||
expect(described_class.values.keys).to match_array(%w[NO_ACCESS GUEST REPORTER DEVELOPER MAINTAINER OWNER])
|
expect(described_class.values.keys).to match_array(%w[NO_ACCESS MINIMAL_ACCESS GUEST REPORTER DEVELOPER MAINTAINER OWNER])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,7 +5,7 @@ require 'spec_helper'
|
||||||
RSpec.describe GitlabSchema.types['Board'] do
|
RSpec.describe GitlabSchema.types['Board'] do
|
||||||
specify { expect(described_class.graphql_name).to eq('Board') }
|
specify { expect(described_class.graphql_name).to eq('Board') }
|
||||||
|
|
||||||
specify { expect(described_class).to require_graphql_authorizations(:read_board) }
|
specify { expect(described_class).to require_graphql_authorizations(:read_issue_board) }
|
||||||
|
|
||||||
it 'has specific fields' do
|
it 'has specific fields' do
|
||||||
expected_fields = %w[id name web_url web_path]
|
expected_fields = %w[id name web_url web_path]
|
||||||
|
|
|
@ -842,27 +842,50 @@ RSpec.describe Ci::Runner do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#pick_build!' do
|
describe '#pick_build!' do
|
||||||
|
let(:build) { create(:ci_build) }
|
||||||
|
let(:runner) { create(:ci_runner) }
|
||||||
|
|
||||||
context 'runner can pick the build' do
|
context 'runner can pick the build' do
|
||||||
it 'calls #tick_runner_queue' do
|
it 'calls #tick_runner_queue' do
|
||||||
ci_build = build(:ci_build)
|
|
||||||
runner = build(:ci_runner)
|
|
||||||
allow(runner).to receive(:can_pick?).with(ci_build).and_return(true)
|
|
||||||
|
|
||||||
expect(runner).to receive(:tick_runner_queue)
|
expect(runner).to receive(:tick_runner_queue)
|
||||||
|
|
||||||
runner.pick_build!(ci_build)
|
runner.pick_build!(build)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'runner cannot pick the build' do
|
context 'runner cannot pick the build' do
|
||||||
it 'does not call #tick_runner_queue' do
|
before do
|
||||||
ci_build = build(:ci_build)
|
build.tag_list = [:docker]
|
||||||
runner = build(:ci_runner)
|
end
|
||||||
allow(runner).to receive(:can_pick?).with(ci_build).and_return(false)
|
|
||||||
|
|
||||||
|
it 'does not call #tick_runner_queue' do
|
||||||
expect(runner).not_to receive(:tick_runner_queue)
|
expect(runner).not_to receive(:tick_runner_queue)
|
||||||
|
|
||||||
runner.pick_build!(ci_build)
|
runner.pick_build!(build)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'build picking improvement enabled' do
|
||||||
|
before do
|
||||||
|
stub_feature_flags(ci_reduce_queries_when_ticking_runner_queue: true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not check if the build is assignable to a runner' do
|
||||||
|
expect(runner).not_to receive(:can_pick?)
|
||||||
|
|
||||||
|
runner.pick_build!(build)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'build picking improvement disabled' do
|
||||||
|
before do
|
||||||
|
stub_feature_flags(ci_reduce_queries_when_ticking_runner_queue: false)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'checks if the build is assignable to a runner' do
|
||||||
|
expect(runner).to receive(:can_pick?).and_call_original
|
||||||
|
|
||||||
|
runner.pick_build!(build)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1834,7 +1834,7 @@ RSpec.describe User do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '.instance_access_request_approvers_to_be_notified' do
|
describe '.instance_access_request_approvers_to_be_notified' do
|
||||||
let_it_be(:admin_list) { create_list(:user, 12, :admin, :with_sign_ins) }
|
let_it_be(:admin_issue_board_list) { create_list(:user, 12, :admin, :with_sign_ins) }
|
||||||
|
|
||||||
it 'returns up to the ten most recently active instance admins' do
|
it 'returns up to the ten most recently active instance admins' do
|
||||||
active_admins_in_recent_sign_in_desc_order = User.admins.active.order_recent_sign_in.limit(10)
|
active_admins_in_recent_sign_in_desc_order = User.admins.active.order_recent_sign_in.limit(10)
|
||||||
|
|
|
@ -64,8 +64,8 @@ RSpec.describe ProjectPolicy do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'disables boards and lists permissions' do
|
it 'disables boards and lists permissions' do
|
||||||
expect_disallowed :read_board, :create_board, :update_board
|
expect_disallowed :read_issue_board, :create_board, :update_board
|
||||||
expect_disallowed :read_list, :create_list, :update_list, :admin_list
|
expect_disallowed :read_issue_board_list, :create_list, :update_list, :admin_issue_board_list
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when external tracker configured' do
|
context 'when external tracker configured' do
|
||||||
|
|
|
@ -26,6 +26,24 @@ RSpec.describe Ci::UpdateBuildQueueService do
|
||||||
end
|
end
|
||||||
|
|
||||||
it_behaves_like 'refreshes runner'
|
it_behaves_like 'refreshes runner'
|
||||||
|
|
||||||
|
it 'avoids running redundant queries' do
|
||||||
|
expect(Ci::Runner).not_to receive(:owned_or_instance_wide)
|
||||||
|
|
||||||
|
subject.execute(build)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when feature flag ci_reduce_queries_when_ticking_runner_queue is disabled' do
|
||||||
|
before do
|
||||||
|
stub_feature_flags(ci_reduce_queries_when_ticking_runner_queue: false)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'runs redundant queries using `owned_or_instance_wide` scope' do
|
||||||
|
expect(Ci::Runner).to receive(:owned_or_instance_wide).and_call_original
|
||||||
|
|
||||||
|
subject.execute(build)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -97,4 +115,43 @@ RSpec.describe Ci::UpdateBuildQueueService do
|
||||||
it_behaves_like 'does not refresh runner'
|
it_behaves_like 'does not refresh runner'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'avoids N+1 queries', :request_store do
|
||||||
|
let!(:build) { create(:ci_build, pipeline: pipeline, tag_list: %w[a b]) }
|
||||||
|
let!(:project_runner) { create(:ci_runner, :project, :online, projects: [project], tag_list: %w[a b c]) }
|
||||||
|
|
||||||
|
context 'when ci_preload_runner_tags and ci_reduce_queries_when_ticking_runner_queue are enabled' do
|
||||||
|
before do
|
||||||
|
stub_feature_flags(
|
||||||
|
ci_reduce_queries_when_ticking_runner_queue: true,
|
||||||
|
ci_preload_runner_tags: true
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does execute the same amount of queries regardless of number of runners' do
|
||||||
|
control_count = ActiveRecord::QueryRecorder.new { subject.execute(build) }.count
|
||||||
|
|
||||||
|
create_list(:ci_runner, 10, :project, :online, projects: [project], tag_list: %w[b c d])
|
||||||
|
|
||||||
|
expect { subject.execute(build) }.not_to exceed_all_query_limit(control_count)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when ci_preload_runner_tags and ci_reduce_queries_when_ticking_runner_queue are disabled' do
|
||||||
|
before do
|
||||||
|
stub_feature_flags(
|
||||||
|
ci_reduce_queries_when_ticking_runner_queue: false,
|
||||||
|
ci_preload_runner_tags: false
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does execute more queries for more runners' do
|
||||||
|
control_count = ActiveRecord::QueryRecorder.new { subject.execute(build) }.count
|
||||||
|
|
||||||
|
create_list(:ci_runner, 10, :project, :online, projects: [project], tag_list: %w[b c d])
|
||||||
|
|
||||||
|
expect { subject.execute(build) }.to exceed_all_query_limit(control_count)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -656,6 +656,48 @@ RSpec.describe MergeRequests::UpdateService, :mailer do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when the draft status is changed' do
|
||||||
|
let!(:non_subscriber) { create(:user) }
|
||||||
|
let!(:subscriber) do
|
||||||
|
create(:user) { |u| merge_request.toggle_subscription(u, project) }
|
||||||
|
end
|
||||||
|
|
||||||
|
before do
|
||||||
|
project.add_developer(non_subscriber)
|
||||||
|
project.add_developer(subscriber)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'removing draft status' do
|
||||||
|
before do
|
||||||
|
merge_request.update_attribute(:title, 'Draft: New Title')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'sends notifications for subscribers', :sidekiq_might_not_need_inline do
|
||||||
|
opts = { title: 'New title' }
|
||||||
|
|
||||||
|
perform_enqueued_jobs do
|
||||||
|
@merge_request = described_class.new(project, user, opts).execute(merge_request)
|
||||||
|
end
|
||||||
|
|
||||||
|
should_email(subscriber)
|
||||||
|
should_not_email(non_subscriber)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'adding draft status' do
|
||||||
|
it 'does not send notifications', :sidekiq_might_not_need_inline do
|
||||||
|
opts = { title: 'Draft: New title' }
|
||||||
|
|
||||||
|
perform_enqueued_jobs do
|
||||||
|
@merge_request = described_class.new(project, user, opts).execute(merge_request)
|
||||||
|
end
|
||||||
|
|
||||||
|
should_not_email(subscriber)
|
||||||
|
should_not_email(non_subscriber)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context 'when the merge request is relabeled' do
|
context 'when the merge request is relabeled' do
|
||||||
let!(:non_subscriber) { create(:user) }
|
let!(:non_subscriber) { create(:user) }
|
||||||
let!(:subscriber) { create(:user) { |u| label.toggle_subscription(u, project) } }
|
let!(:subscriber) { create(:user) { |u| label.toggle_subscription(u, project) } }
|
||||||
|
|
|
@ -1868,6 +1868,42 @@ RSpec.describe NotificationService, :mailer do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#change_in_merge_request_draft_status' do
|
||||||
|
let(:merge_request) { create(:merge_request, author: author, source_project: project) }
|
||||||
|
|
||||||
|
let_it_be(:current_user) { create(:user) }
|
||||||
|
|
||||||
|
it 'sends emails to relevant users only', :aggregate_failures do
|
||||||
|
notification.change_in_merge_request_draft_status(merge_request, current_user)
|
||||||
|
|
||||||
|
merge_request.reviewers.each { |reviewer| should_email(reviewer) }
|
||||||
|
merge_request.assignees.each { |assignee| should_email(assignee) }
|
||||||
|
should_email(merge_request.author)
|
||||||
|
should_email(@u_watcher)
|
||||||
|
should_email(@subscriber)
|
||||||
|
should_email(@watcher_and_subscriber)
|
||||||
|
should_email(@u_guest_watcher)
|
||||||
|
should_not_email(@u_participant_mentioned)
|
||||||
|
should_not_email(@u_guest_custom)
|
||||||
|
should_not_email(@u_custom_global)
|
||||||
|
should_not_email(@unsubscriber)
|
||||||
|
should_not_email(@u_participating)
|
||||||
|
should_not_email(@u_disabled)
|
||||||
|
should_not_email(@u_lazy_participant)
|
||||||
|
end
|
||||||
|
|
||||||
|
it_behaves_like 'participating notifications' do
|
||||||
|
let(:participant) { create(:user, username: 'user-participant') }
|
||||||
|
let(:issuable) { merge_request }
|
||||||
|
let(:notification_trigger) { notification.change_in_merge_request_draft_status(merge_request, @u_disabled) }
|
||||||
|
end
|
||||||
|
|
||||||
|
it_behaves_like 'project emails are disabled' do
|
||||||
|
let(:notification_target) { merge_request }
|
||||||
|
let(:notification_trigger) { notification.change_in_merge_request_draft_status(merge_request, @u_disabled) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe '#push_to_merge_request' do
|
describe '#push_to_merge_request' do
|
||||||
before do
|
before do
|
||||||
update_custom_notification(:push_to_merge_request, @u_guest_custom, resource: project)
|
update_custom_notification(:push_to_merge_request, @u_guest_custom, resource: project)
|
||||||
|
|
|
@ -18,12 +18,12 @@ RSpec.shared_context 'GroupPolicy context' do
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
let(:read_group_permissions) { %i[read_label read_list read_milestone read_board] }
|
let(:read_group_permissions) { %i[read_label read_issue_board_list read_milestone read_issue_board] }
|
||||||
|
|
||||||
let(:reporter_permissions) do
|
let(:reporter_permissions) do
|
||||||
%i[
|
%i[
|
||||||
admin_label
|
admin_label
|
||||||
admin_board
|
admin_issue_board
|
||||||
read_container_image
|
read_container_image
|
||||||
read_metrics_dashboard_annotation
|
read_metrics_dashboard_annotation
|
||||||
read_prometheus
|
read_prometheus
|
||||||
|
|
|
@ -16,8 +16,8 @@ RSpec.shared_context 'ProjectPolicy context' do
|
||||||
let(:base_guest_permissions) do
|
let(:base_guest_permissions) do
|
||||||
%i[
|
%i[
|
||||||
award_emoji create_issue create_merge_request_in create_note
|
award_emoji create_issue create_merge_request_in create_note
|
||||||
create_project read_board read_issue read_issue_iid read_issue_link
|
create_project read_issue_board read_issue read_issue_iid read_issue_link
|
||||||
read_label read_list read_milestone read_note read_project
|
read_label read_issue_board_list read_milestone read_note read_project
|
||||||
read_project_for_iids read_project_member read_release read_snippet
|
read_project_for_iids read_project_member read_release read_snippet
|
||||||
read_wiki upload_file
|
read_wiki upload_file
|
||||||
]
|
]
|
||||||
|
@ -25,7 +25,7 @@ RSpec.shared_context 'ProjectPolicy context' do
|
||||||
|
|
||||||
let(:base_reporter_permissions) do
|
let(:base_reporter_permissions) do
|
||||||
%i[
|
%i[
|
||||||
admin_issue admin_issue_link admin_label admin_list create_snippet
|
admin_issue admin_issue_link admin_label admin_issue_board_list create_snippet
|
||||||
download_code download_wiki_code fork_project metrics_dashboard
|
download_code download_wiki_code fork_project metrics_dashboard
|
||||||
read_build read_commit_status read_confidential_issues
|
read_build read_commit_status read_confidential_issues
|
||||||
read_container_image read_deployment read_environment read_merge_request
|
read_container_image read_deployment read_environment read_merge_request
|
||||||
|
|
|
@ -25,7 +25,7 @@ RSpec.shared_examples 'group and project boards query' do
|
||||||
board = create(:board, resource_parent: board_parent, name: 'A')
|
board = create(:board, resource_parent: board_parent, name: 'A')
|
||||||
|
|
||||||
allow(Ability).to receive(:allowed?).and_call_original
|
allow(Ability).to receive(:allowed?).and_call_original
|
||||||
allow(Ability).to receive(:allowed?).with(user, :read_board, board).and_return(false)
|
allow(Ability).to receive(:allowed?).with(user, :read_issue_board, board).and_return(false)
|
||||||
|
|
||||||
post_graphql(query, current_user: current_user)
|
post_graphql(query, current_user: current_user)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue