Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
2c72daf2f1
commit
95ad46159e
36
.rubocop.yml
36
.rubocop.yml
|
@ -382,3 +382,39 @@ Cop/BanCatchThrow:
|
|||
|
||||
Performance/ReadlinesEach:
|
||||
Enabled: true
|
||||
|
||||
# https://gitlab.com/gitlab-org/gitlab/-/issues/212541
|
||||
RSpec/RepeatedExample:
|
||||
Exclude:
|
||||
- 'spec/features/issues/filtered_search/filter_issues_spec.rb'
|
||||
- 'spec/features/merge_request/user_posts_diff_notes_spec.rb'
|
||||
- 'spec/features/projects/files/template_type_dropdown_spec.rb'
|
||||
- 'spec/finders/environments_finder_spec.rb'
|
||||
- 'spec/frontend/fixtures/merge_requests.rb'
|
||||
- 'spec/graphql/gitlab_schema_spec.rb'
|
||||
- 'spec/helpers/users_helper_spec.rb'
|
||||
- 'spec/lib/banzai/filter/autolink_filter_spec.rb'
|
||||
- 'spec/lib/banzai/filter/issuable_state_filter_spec.rb'
|
||||
- 'spec/lib/gitlab/closing_issue_extractor_spec.rb'
|
||||
- 'spec/lib/gitlab/danger/changelog_spec.rb'
|
||||
- 'spec/lib/gitlab/git/blob_spec.rb'
|
||||
- 'spec/lib/gitlab/import_export/project/relation_factory_spec.rb'
|
||||
- 'spec/models/ability_spec.rb'
|
||||
- 'spec/models/ci/build_spec.rb'
|
||||
- 'spec/models/concerns/issuable_spec.rb'
|
||||
- 'spec/models/concerns/prometheus_adapter_spec.rb'
|
||||
- 'spec/models/member_spec.rb'
|
||||
- 'spec/models/project_services/chat_message/pipeline_message_spec.rb'
|
||||
- 'spec/models/user_spec.rb'
|
||||
- 'spec/models/wiki_page_spec.rb'
|
||||
- 'spec/requests/api/merge_requests_spec.rb'
|
||||
- 'spec/routing/admin_routing_spec.rb'
|
||||
- 'spec/rubocop/cop/migration/update_large_table_spec.rb'
|
||||
- 'spec/services/notification_service_spec.rb'
|
||||
- 'spec/services/web_hook_service_spec.rb'
|
||||
- 'ee/spec/models/group_spec.rb'
|
||||
- 'ee/spec/models/user_spec.rb'
|
||||
- 'ee/spec/requests/api/merge_request_approvals_spec.rb'
|
||||
- 'ee/spec/services/boards/lists/update_service_spec.rb'
|
||||
- 'ee/spec/services/geo/repository_verification_primary_service_spec.rb'
|
||||
- 'ee/spec/workers/geo/file_download_dispatch_worker_spec.rb'
|
||||
|
|
|
@ -251,10 +251,6 @@ RSpec/LetBeforeExamples:
|
|||
RSpec/PredicateMatcher:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 69
|
||||
RSpec/RepeatedExample:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 584
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyle.
|
||||
|
|
|
@ -39,6 +39,10 @@ export default {
|
|||
'is-open': this.file.opened,
|
||||
};
|
||||
},
|
||||
textForTitle() {
|
||||
// don't output a title if we don't have the expanded path
|
||||
return this.file?.tree?.length ? this.file.tree[0].parentPath : false;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
'file.active': function fileActiveWatch(active) {
|
||||
|
@ -106,7 +110,7 @@ export default {
|
|||
<div
|
||||
v-else
|
||||
:class="fileClass"
|
||||
:title="file.name"
|
||||
:title="textForTitle"
|
||||
class="file-row"
|
||||
role="button"
|
||||
@click="clickFile"
|
||||
|
|
|
@ -19,7 +19,7 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div class="file-row-header bg-white sticky-top p-2 js-file-row-header">
|
||||
<div class="file-row-header bg-white sticky-top p-2 js-file-row-header" :title="path">
|
||||
<span class="bold">{{ truncatedPath }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -38,19 +38,14 @@ class IssuableFinder
|
|||
include CreatedAtFilter
|
||||
include Gitlab::Utils::StrongMemoize
|
||||
|
||||
requires_cross_project_access unless: -> { project? }
|
||||
|
||||
# This is used as a common filter for None / Any
|
||||
FILTER_NONE = 'none'
|
||||
FILTER_ANY = 'any'
|
||||
|
||||
# This is used in unassigning users
|
||||
NONE = '0'
|
||||
requires_cross_project_access unless: -> { params.project? }
|
||||
|
||||
NEGATABLE_PARAMS_HELPER_KEYS = %i[include_subgroups in].freeze
|
||||
|
||||
attr_accessor :current_user, :params
|
||||
|
||||
delegate(*%i[assignee milestones], to: :params)
|
||||
|
||||
class << self
|
||||
def scalar_params
|
||||
@scalar_params ||= %i[
|
||||
|
@ -91,9 +86,13 @@ class IssuableFinder
|
|||
end
|
||||
end
|
||||
|
||||
def params_class
|
||||
IssuableFinder::Params
|
||||
end
|
||||
|
||||
def initialize(current_user, params = {})
|
||||
@current_user = current_user
|
||||
@params = params
|
||||
@params = params_class.new(params, current_user, klass)
|
||||
end
|
||||
|
||||
def execute
|
||||
|
@ -161,7 +160,7 @@ class IssuableFinder
|
|||
# of a CTE. The CTE will not be used if the sort doesn't support it,
|
||||
# but will always be used for the counts here as we ignore sorting
|
||||
# anyway.
|
||||
labels_count = label_names.any? ? label_names.count : 1
|
||||
labels_count = params.label_names.any? ? params.label_names.count : 1
|
||||
labels_count = 1 if use_cte_for_search?
|
||||
|
||||
finder.execute.reorder(nil).group(:state_id).count.each do |key, value|
|
||||
|
@ -174,192 +173,10 @@ class IssuableFinder
|
|||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
||||
def group
|
||||
return @group if defined?(@group)
|
||||
|
||||
@group =
|
||||
if params[:group_id].present?
|
||||
Group.find(params[:group_id])
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
def related_groups
|
||||
if project? && project && project.group && Ability.allowed?(current_user, :read_group, project.group)
|
||||
project.group.self_and_ancestors
|
||||
elsif group
|
||||
[group]
|
||||
elsif current_user
|
||||
Gitlab::ObjectHierarchy.new(current_user.authorized_groups, current_user.groups).all_objects
|
||||
else
|
||||
[]
|
||||
end
|
||||
end
|
||||
|
||||
def project?
|
||||
params[:project_id].present?
|
||||
end
|
||||
|
||||
def project
|
||||
return @project if defined?(@project)
|
||||
|
||||
project = Project.find(params[:project_id])
|
||||
project = nil unless Ability.allowed?(current_user, :"read_#{klass.to_ability_name}", project)
|
||||
|
||||
@project = project
|
||||
end
|
||||
|
||||
def projects
|
||||
return @projects if defined?(@projects)
|
||||
|
||||
return @projects = [project] if project?
|
||||
|
||||
projects =
|
||||
if current_user && params[:authorized_only].presence && !current_user_related?
|
||||
current_user.authorized_projects(min_access_level)
|
||||
else
|
||||
projects_public_or_visible_to_user
|
||||
end
|
||||
|
||||
@projects = projects.with_feature_available_for_user(klass, current_user).reorder(nil) # rubocop: disable CodeReuse/ActiveRecord
|
||||
end
|
||||
|
||||
def projects_public_or_visible_to_user
|
||||
projects =
|
||||
if group
|
||||
if params[:projects]
|
||||
find_group_projects.id_in(params[:projects])
|
||||
else
|
||||
find_group_projects
|
||||
end
|
||||
elsif params[:projects]
|
||||
Project.id_in(params[:projects])
|
||||
else
|
||||
Project
|
||||
end
|
||||
|
||||
projects.public_or_visible_to_user(current_user, min_access_level)
|
||||
end
|
||||
|
||||
def find_group_projects
|
||||
return Project.none unless group
|
||||
|
||||
if params[:include_subgroups]
|
||||
Project.where(namespace_id: group.self_and_descendants) # rubocop: disable CodeReuse/ActiveRecord
|
||||
else
|
||||
group.projects
|
||||
end
|
||||
end
|
||||
|
||||
def search
|
||||
params[:search].presence
|
||||
end
|
||||
|
||||
def milestones?
|
||||
params[:milestone_title].present?
|
||||
end
|
||||
|
||||
def milestones
|
||||
return @milestones if defined?(@milestones)
|
||||
|
||||
@milestones =
|
||||
if milestones?
|
||||
if project?
|
||||
group_id = project.group&.id
|
||||
project_id = project.id
|
||||
end
|
||||
|
||||
group_id = group.id if group
|
||||
|
||||
search_params =
|
||||
{ title: params[:milestone_title], project_ids: project_id, group_ids: group_id }
|
||||
|
||||
MilestonesFinder.new(search_params).execute # rubocop: disable CodeReuse/Finder
|
||||
else
|
||||
Milestone.none
|
||||
end
|
||||
end
|
||||
|
||||
def labels?
|
||||
params[:label_name].present?
|
||||
end
|
||||
|
||||
def filter_by_no_label?
|
||||
downcased = label_names.map(&:downcase)
|
||||
|
||||
downcased.include?(FILTER_NONE)
|
||||
end
|
||||
|
||||
def filter_by_any_label?
|
||||
label_names.map(&:downcase).include?(FILTER_ANY)
|
||||
end
|
||||
|
||||
def labels
|
||||
return @labels if defined?(@labels)
|
||||
|
||||
@labels =
|
||||
if labels? && !filter_by_no_label?
|
||||
LabelsFinder.new(current_user, project_ids: projects, title: label_names).execute(skip_authorization: true) # rubocop: disable CodeReuse/Finder
|
||||
else
|
||||
Label.none
|
||||
end
|
||||
end
|
||||
|
||||
def assignee_id?
|
||||
params[:assignee_id].present?
|
||||
end
|
||||
|
||||
def assignee_username?
|
||||
params[:assignee_username].present?
|
||||
end
|
||||
|
||||
def assignee
|
||||
assignees.first
|
||||
end
|
||||
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
def assignees
|
||||
strong_memoize(:assignees) do
|
||||
if assignee_id?
|
||||
User.where(id: params[:assignee_id])
|
||||
elsif assignee_username?
|
||||
User.where(username: params[:assignee_username])
|
||||
else
|
||||
User.none
|
||||
end
|
||||
end
|
||||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
||||
def author_id?
|
||||
params[:author_id].present? && params[:author_id] != NONE
|
||||
end
|
||||
|
||||
def author_username?
|
||||
params[:author_username].present? && params[:author_username] != NONE
|
||||
end
|
||||
|
||||
def no_author?
|
||||
# author_id takes precedence over author_username
|
||||
params[:author_id] == NONE || params[:author_username] == NONE
|
||||
end
|
||||
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
def author
|
||||
return @author if defined?(@author)
|
||||
|
||||
@author =
|
||||
if author_id?
|
||||
User.find_by(id: params[:author_id])
|
||||
elsif author_username?
|
||||
User.find_by_username(params[:author_username])
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
||||
def use_cte_for_search?
|
||||
strong_memoize(:use_cte_for_search) do
|
||||
next false unless search
|
||||
|
@ -370,10 +187,6 @@ class IssuableFinder
|
|||
end
|
||||
end
|
||||
|
||||
def releases?
|
||||
params[:release_tag].present?
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def force_cte?
|
||||
|
@ -431,7 +244,7 @@ class IssuableFinder
|
|||
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
def by_scope(items)
|
||||
return items.none if current_user_related? && !current_user
|
||||
return items.none if params.current_user_related? && !current_user
|
||||
|
||||
case params[:scope]
|
||||
when 'created_by_me', 'authored'
|
||||
|
@ -480,16 +293,13 @@ class IssuableFinder
|
|||
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
def by_project(items)
|
||||
items =
|
||||
if project?
|
||||
items.of_projects(projects).references_project
|
||||
elsif projects
|
||||
items.merge(projects.reorder(nil)).join_project
|
||||
else
|
||||
items.none
|
||||
end
|
||||
|
||||
items
|
||||
if params.project?
|
||||
items.of_projects(params.projects).references_project
|
||||
elsif params.projects
|
||||
items.merge(params.projects.reorder(nil)).join_project
|
||||
else
|
||||
items.none
|
||||
end
|
||||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
||||
|
@ -519,42 +329,34 @@ class IssuableFinder
|
|||
def sort(items)
|
||||
# Ensure we always have an explicit sort order (instead of inheriting
|
||||
# multiple orders when combining ActiveRecord::Relation objects).
|
||||
params[:sort] ? items.sort_by_attribute(params[:sort], excluded_labels: label_names) : items.reorder(id: :desc)
|
||||
params[:sort] ? items.sort_by_attribute(params[:sort], excluded_labels: params.label_names) : items.reorder(id: :desc)
|
||||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
||||
def filter_by_no_assignee?
|
||||
params[:assignee_id].to_s.downcase == FILTER_NONE
|
||||
end
|
||||
|
||||
def filter_by_any_assignee?
|
||||
params[:assignee_id].to_s.downcase == FILTER_ANY
|
||||
end
|
||||
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
def by_author(items)
|
||||
if author
|
||||
items = items.where(author_id: author.id)
|
||||
elsif no_author?
|
||||
items = items.where(author_id: nil)
|
||||
elsif author_id? || author_username? # author not found
|
||||
items = items.none
|
||||
if params.author
|
||||
items.where(author_id: params.author.id)
|
||||
elsif params.no_author?
|
||||
items.where(author_id: nil)
|
||||
elsif params.author_id? || params.author_username? # author not found
|
||||
items.none
|
||||
else
|
||||
items
|
||||
end
|
||||
|
||||
items
|
||||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
||||
def by_assignee(items)
|
||||
return items.assigned_to(assignees) if not_query? && assignees.any?
|
||||
return items.assigned_to(params.assignees) if not_query? && params.assignees.any?
|
||||
|
||||
if filter_by_no_assignee?
|
||||
if params.filter_by_no_assignee?
|
||||
items.unassigned
|
||||
elsif filter_by_any_assignee?
|
||||
elsif params.filter_by_any_assignee?
|
||||
items.assigned
|
||||
elsif assignee
|
||||
items.assigned_to(assignee)
|
||||
elsif assignee_id? || assignee_username? # assignee not found
|
||||
elsif params.assignee
|
||||
items.assigned_to(params.assignee)
|
||||
elsif params.assignee_id? || params.assignee_username? # assignee not found
|
||||
items.none
|
||||
else
|
||||
items
|
||||
|
@ -563,106 +365,56 @@ class IssuableFinder
|
|||
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
def by_milestone(items)
|
||||
if milestones?
|
||||
if filter_by_no_milestone?
|
||||
items = items.left_joins_milestones.where(milestone_id: [-1, nil])
|
||||
elsif filter_by_any_milestone?
|
||||
items = items.any_milestone
|
||||
elsif filter_by_upcoming_milestone?
|
||||
upcoming_ids = Milestone.upcoming_ids(projects, related_groups)
|
||||
items = items.left_joins_milestones.where(milestone_id: upcoming_ids)
|
||||
elsif filter_by_started_milestone?
|
||||
items = items.left_joins_milestones.merge(Milestone.started)
|
||||
else
|
||||
items = items.with_milestone(params[:milestone_title])
|
||||
end
|
||||
end
|
||||
return items unless params.milestones?
|
||||
|
||||
items
|
||||
if params.filter_by_no_milestone?
|
||||
items.left_joins_milestones.where(milestone_id: [-1, nil])
|
||||
elsif params.filter_by_any_milestone?
|
||||
items.any_milestone
|
||||
elsif params.filter_by_upcoming_milestone?
|
||||
upcoming_ids = Milestone.upcoming_ids(params.projects, params.related_groups)
|
||||
items.left_joins_milestones.where(milestone_id: upcoming_ids)
|
||||
elsif params.filter_by_started_milestone?
|
||||
items.left_joins_milestones.merge(Milestone.started)
|
||||
else
|
||||
items.with_milestone(params[:milestone_title])
|
||||
end
|
||||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
||||
def by_release(items)
|
||||
return items unless releases?
|
||||
return items unless params.releases?
|
||||
|
||||
if filter_by_no_release?
|
||||
if params.filter_by_no_release?
|
||||
items.without_release
|
||||
elsif filter_by_any_release?
|
||||
elsif params.filter_by_any_release?
|
||||
items.any_release
|
||||
else
|
||||
items.with_release(params[:release_tag], params[:project_id])
|
||||
end
|
||||
end
|
||||
|
||||
def filter_by_no_milestone?
|
||||
# Accepts `No Milestone` for compatibility
|
||||
params[:milestone_title].to_s.downcase == FILTER_NONE || params[:milestone_title] == Milestone::None.title
|
||||
end
|
||||
|
||||
def filter_by_any_milestone?
|
||||
# Accepts `Any Milestone` for compatibility
|
||||
params[:milestone_title].to_s.downcase == FILTER_ANY || params[:milestone_title] == Milestone::Any.title
|
||||
end
|
||||
|
||||
def filter_by_upcoming_milestone?
|
||||
params[:milestone_title] == Milestone::Upcoming.name
|
||||
end
|
||||
|
||||
def filter_by_started_milestone?
|
||||
params[:milestone_title] == Milestone::Started.name
|
||||
end
|
||||
|
||||
def filter_by_no_release?
|
||||
params[:release_tag].to_s.downcase == FILTER_NONE
|
||||
end
|
||||
|
||||
def filter_by_any_release?
|
||||
params[:release_tag].to_s.downcase == FILTER_ANY
|
||||
end
|
||||
|
||||
def by_label(items)
|
||||
return items unless labels?
|
||||
return items unless params.labels?
|
||||
|
||||
items =
|
||||
if filter_by_no_label?
|
||||
items.without_label
|
||||
elsif filter_by_any_label?
|
||||
items.any_label
|
||||
else
|
||||
items.with_label(label_names, params[:sort], not_query: not_query?)
|
||||
end
|
||||
|
||||
items
|
||||
if params.filter_by_no_label?
|
||||
items.without_label
|
||||
elsif params.filter_by_any_label?
|
||||
items.any_label
|
||||
else
|
||||
items.with_label(params.label_names, params[:sort], not_query: not_query?)
|
||||
end
|
||||
end
|
||||
|
||||
def by_my_reaction_emoji(items)
|
||||
if params[:my_reaction_emoji].present? && current_user
|
||||
items =
|
||||
if filter_by_no_reaction?
|
||||
items.not_awarded(current_user)
|
||||
elsif filter_by_any_reaction?
|
||||
items.awarded(current_user)
|
||||
else
|
||||
items.awarded(current_user, params[:my_reaction_emoji])
|
||||
end
|
||||
end
|
||||
return items unless params[:my_reaction_emoji] && current_user
|
||||
|
||||
items
|
||||
end
|
||||
|
||||
def filter_by_no_reaction?
|
||||
params[:my_reaction_emoji].to_s.downcase == FILTER_NONE
|
||||
end
|
||||
|
||||
def filter_by_any_reaction?
|
||||
params[:my_reaction_emoji].to_s.downcase == FILTER_ANY
|
||||
end
|
||||
|
||||
def label_names
|
||||
if labels?
|
||||
params[:label_name].is_a?(String) ? params[:label_name].split(',') : params[:label_name]
|
||||
if params.filter_by_no_reaction?
|
||||
items.not_awarded(current_user)
|
||||
elsif params.filter_by_any_reaction?
|
||||
items.awarded(current_user)
|
||||
else
|
||||
[]
|
||||
items.awarded(current_user, params[:my_reaction_emoji])
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -670,15 +422,6 @@ class IssuableFinder
|
|||
params[:non_archived].present? ? items.non_archived : items
|
||||
end
|
||||
|
||||
def current_user_related?
|
||||
scope = params[:scope]
|
||||
scope == 'created_by_me' || scope == 'authored' || scope == 'assigned_to_me'
|
||||
end
|
||||
|
||||
def min_access_level
|
||||
ProjectFeature.required_minimum_access_level(klass)
|
||||
end
|
||||
|
||||
def not_query?
|
||||
!!params[:not_query]
|
||||
end
|
||||
|
|
|
@ -0,0 +1,287 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class IssuableFinder
|
||||
class Params < SimpleDelegator
|
||||
include Gitlab::Utils::StrongMemoize
|
||||
|
||||
# This is used as a common filter for None / Any
|
||||
FILTER_NONE = 'none'
|
||||
FILTER_ANY = 'any'
|
||||
|
||||
# This is used in unassigning users
|
||||
NONE = '0'
|
||||
|
||||
alias_method :params, :__getobj__
|
||||
|
||||
attr_accessor :current_user, :klass
|
||||
|
||||
def initialize(params, current_user, klass)
|
||||
@current_user = current_user
|
||||
@klass = klass
|
||||
# We turn the params into a HashWithIndifferentAccess. We must use #to_h first because sometimes
|
||||
# we get ActionController::Params and IssuableFinder::Params objects here.
|
||||
super(params.to_h.with_indifferent_access)
|
||||
end
|
||||
|
||||
def present?
|
||||
params.present?
|
||||
end
|
||||
|
||||
def author_id?
|
||||
params[:author_id].present? && params[:author_id] != NONE
|
||||
end
|
||||
|
||||
def author_username?
|
||||
params[:author_username].present? && params[:author_username] != NONE
|
||||
end
|
||||
|
||||
def no_author?
|
||||
# author_id takes precedence over author_username
|
||||
params[:author_id] == NONE || params[:author_username] == NONE
|
||||
end
|
||||
|
||||
def filter_by_no_assignee?
|
||||
params[:assignee_id].to_s.downcase == FILTER_NONE
|
||||
end
|
||||
|
||||
def filter_by_any_assignee?
|
||||
params[:assignee_id].to_s.downcase == FILTER_ANY
|
||||
end
|
||||
|
||||
def filter_by_no_label?
|
||||
downcased = label_names.map(&:downcase)
|
||||
|
||||
downcased.include?(FILTER_NONE)
|
||||
end
|
||||
|
||||
def filter_by_any_label?
|
||||
label_names.map(&:downcase).include?(FILTER_ANY)
|
||||
end
|
||||
|
||||
def labels?
|
||||
params[:label_name].present?
|
||||
end
|
||||
|
||||
def milestones?
|
||||
params[:milestone_title].present?
|
||||
end
|
||||
|
||||
def filter_by_no_milestone?
|
||||
# Accepts `No Milestone` for compatibility
|
||||
params[:milestone_title].to_s.downcase == FILTER_NONE || params[:milestone_title] == Milestone::None.title
|
||||
end
|
||||
|
||||
def filter_by_any_milestone?
|
||||
# Accepts `Any Milestone` for compatibility
|
||||
params[:milestone_title].to_s.downcase == FILTER_ANY || params[:milestone_title] == Milestone::Any.title
|
||||
end
|
||||
|
||||
def filter_by_upcoming_milestone?
|
||||
params[:milestone_title] == Milestone::Upcoming.name
|
||||
end
|
||||
|
||||
def filter_by_started_milestone?
|
||||
params[:milestone_title] == Milestone::Started.name
|
||||
end
|
||||
|
||||
def filter_by_no_release?
|
||||
params[:release_tag].to_s.downcase == FILTER_NONE
|
||||
end
|
||||
|
||||
def filter_by_any_release?
|
||||
params[:release_tag].to_s.downcase == FILTER_ANY
|
||||
end
|
||||
|
||||
def filter_by_no_reaction?
|
||||
params[:my_reaction_emoji].to_s.downcase == FILTER_NONE
|
||||
end
|
||||
|
||||
def filter_by_any_reaction?
|
||||
params[:my_reaction_emoji].to_s.downcase == FILTER_ANY
|
||||
end
|
||||
|
||||
def releases?
|
||||
params[:release_tag].present?
|
||||
end
|
||||
|
||||
def project?
|
||||
params[:project_id].present?
|
||||
end
|
||||
|
||||
def group
|
||||
strong_memoize(:group) do
|
||||
if params[:group_id].present?
|
||||
Group.find(params[:group_id])
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def related_groups
|
||||
if project? && project&.group && Ability.allowed?(current_user, :read_group, project.group)
|
||||
project.group.self_and_ancestors
|
||||
elsif group
|
||||
[group]
|
||||
elsif current_user
|
||||
Gitlab::ObjectHierarchy.new(current_user.authorized_groups, current_user.groups).all_objects
|
||||
else
|
||||
[]
|
||||
end
|
||||
end
|
||||
|
||||
def project
|
||||
strong_memoize(:project) do
|
||||
project = Project.find(params[:project_id])
|
||||
project = nil unless Ability.allowed?(current_user, :"read_#{klass.to_ability_name}", project)
|
||||
|
||||
project
|
||||
end
|
||||
end
|
||||
|
||||
def projects
|
||||
strong_memoize(:projects) do
|
||||
next [project] if project?
|
||||
|
||||
projects =
|
||||
if current_user && params[:authorized_only].presence && !current_user_related?
|
||||
current_user.authorized_projects(min_access_level)
|
||||
else
|
||||
projects_public_or_visible_to_user
|
||||
end
|
||||
|
||||
projects.with_feature_available_for_user(klass, current_user).reorder(nil) # rubocop: disable CodeReuse/ActiveRecord
|
||||
end
|
||||
end
|
||||
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
def author
|
||||
strong_memoize(:author) do
|
||||
if author_id?
|
||||
User.find_by(id: params[:author_id])
|
||||
elsif author_username?
|
||||
User.find_by_username(params[:author_username])
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
def assignees
|
||||
strong_memoize(:assignees) do
|
||||
if assignee_id?
|
||||
User.where(id: params[:assignee_id])
|
||||
elsif assignee_username?
|
||||
User.where(username: params[:assignee_username])
|
||||
else
|
||||
User.none
|
||||
end
|
||||
end
|
||||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
||||
def assignee
|
||||
assignees.first
|
||||
end
|
||||
|
||||
def label_names
|
||||
if labels?
|
||||
params[:label_name].is_a?(String) ? params[:label_name].split(',') : params[:label_name]
|
||||
else
|
||||
[]
|
||||
end
|
||||
end
|
||||
|
||||
def labels
|
||||
strong_memoize(:labels) do
|
||||
if labels? && !filter_by_no_label?
|
||||
LabelsFinder.new(current_user, project_ids: projects, title: label_names).execute(skip_authorization: true) # rubocop: disable CodeReuse/Finder
|
||||
else
|
||||
Label.none
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def milestones
|
||||
strong_memoize(:milestones) do
|
||||
if milestones?
|
||||
if project?
|
||||
group_id = project.group&.id
|
||||
project_id = project.id
|
||||
end
|
||||
|
||||
group_id = group.id if group
|
||||
|
||||
search_params =
|
||||
{ title: params[:milestone_title], project_ids: project_id, group_ids: group_id }
|
||||
|
||||
MilestonesFinder.new(search_params).execute # rubocop: disable CodeReuse/Finder
|
||||
else
|
||||
Milestone.none
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def current_user_related?
|
||||
scope = params[:scope]
|
||||
scope == 'created_by_me' || scope == 'authored' || scope == 'assigned_to_me'
|
||||
end
|
||||
|
||||
def find_group_projects
|
||||
return Project.none unless group
|
||||
|
||||
if params[:include_subgroups]
|
||||
Project.where(namespace_id: group.self_and_descendants) # rubocop: disable CodeReuse/ActiveRecord
|
||||
else
|
||||
group.projects
|
||||
end
|
||||
end
|
||||
|
||||
# We use Hash#merge in a few places, so let's support it
|
||||
def merge(other)
|
||||
self.class.new(params.merge(other), current_user, klass)
|
||||
end
|
||||
|
||||
# Just for symmetry, and in case someone tries to use it
|
||||
def merge!(other)
|
||||
params.merge!(other)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def projects_public_or_visible_to_user
|
||||
projects =
|
||||
if group
|
||||
if params[:projects]
|
||||
find_group_projects.id_in(params[:projects])
|
||||
else
|
||||
find_group_projects
|
||||
end
|
||||
elsif params[:projects]
|
||||
Project.id_in(params[:projects])
|
||||
else
|
||||
Project
|
||||
end
|
||||
|
||||
projects.public_or_visible_to_user(current_user, min_access_level)
|
||||
end
|
||||
|
||||
def min_access_level
|
||||
ProjectFeature.required_minimum_access_level(klass)
|
||||
end
|
||||
|
||||
def method_missing(method_name, *args, &block)
|
||||
if method_name[-1] == '?'
|
||||
params[method_name[0..-2].to_sym].present?
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
def respond_to_missing?(method_name, include_private = false)
|
||||
method_name[-1] == '?'
|
||||
end
|
||||
end
|
||||
end
|
|
@ -38,10 +38,14 @@ class IssuesFinder < IssuableFinder
|
|||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
||||
def params_class
|
||||
IssuesFinder::Params
|
||||
end
|
||||
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
def with_confidentiality_access_check
|
||||
return Issue.all if user_can_see_all_confidential_issues?
|
||||
return Issue.where('issues.confidential IS NOT TRUE') if user_cannot_see_confidential_issues?
|
||||
return Issue.all if params.user_can_see_all_confidential_issues?
|
||||
return Issue.where('issues.confidential IS NOT TRUE') if params.user_cannot_see_confidential_issues?
|
||||
|
||||
Issue.where('
|
||||
issues.confidential IS NOT TRUE
|
||||
|
@ -57,17 +61,13 @@ class IssuesFinder < IssuableFinder
|
|||
private
|
||||
|
||||
def init_collection
|
||||
if public_only?
|
||||
if params.public_only?
|
||||
Issue.public_only
|
||||
else
|
||||
with_confidentiality_access_check
|
||||
end
|
||||
end
|
||||
|
||||
def public_only?
|
||||
params.fetch(:public_only, false)
|
||||
end
|
||||
|
||||
def filter_items(items)
|
||||
issues = super
|
||||
issues = by_due_date(issues)
|
||||
|
@ -82,67 +82,19 @@ class IssuesFinder < IssuableFinder
|
|||
end
|
||||
|
||||
def by_due_date(items)
|
||||
if due_date?
|
||||
if filter_by_no_due_date?
|
||||
items = items.without_due_date
|
||||
elsif filter_by_overdue?
|
||||
items = items.due_before(Date.today)
|
||||
elsif filter_by_due_this_week?
|
||||
items = items.due_between(Date.today.beginning_of_week, Date.today.end_of_week)
|
||||
elsif filter_by_due_this_month?
|
||||
items = items.due_between(Date.today.beginning_of_month, Date.today.end_of_month)
|
||||
elsif filter_by_due_next_month_and_previous_two_weeks?
|
||||
items = items.due_between(Date.today - 2.weeks, (Date.today + 1.month).end_of_month)
|
||||
end
|
||||
return items unless params.due_date?
|
||||
|
||||
if params.filter_by_no_due_date?
|
||||
items.without_due_date
|
||||
elsif params.filter_by_overdue?
|
||||
items.due_before(Date.today)
|
||||
elsif params.filter_by_due_this_week?
|
||||
items.due_between(Date.today.beginning_of_week, Date.today.end_of_week)
|
||||
elsif params.filter_by_due_this_month?
|
||||
items.due_between(Date.today.beginning_of_month, Date.today.end_of_month)
|
||||
elsif params.filter_by_due_next_month_and_previous_two_weeks?
|
||||
items.due_between(Date.today - 2.weeks, (Date.today + 1.month).end_of_month)
|
||||
end
|
||||
|
||||
items
|
||||
end
|
||||
|
||||
def filter_by_no_due_date?
|
||||
due_date? && params[:due_date] == Issue::NoDueDate.name
|
||||
end
|
||||
|
||||
def filter_by_overdue?
|
||||
due_date? && params[:due_date] == Issue::Overdue.name
|
||||
end
|
||||
|
||||
def filter_by_due_this_week?
|
||||
due_date? && params[:due_date] == Issue::DueThisWeek.name
|
||||
end
|
||||
|
||||
def filter_by_due_this_month?
|
||||
due_date? && params[:due_date] == Issue::DueThisMonth.name
|
||||
end
|
||||
|
||||
def filter_by_due_next_month_and_previous_two_weeks?
|
||||
due_date? && params[:due_date] == Issue::DueNextMonthAndPreviousTwoWeeks.name
|
||||
end
|
||||
|
||||
def due_date?
|
||||
params[:due_date].present?
|
||||
end
|
||||
|
||||
def user_can_see_all_confidential_issues?
|
||||
return @user_can_see_all_confidential_issues if defined?(@user_can_see_all_confidential_issues)
|
||||
|
||||
return @user_can_see_all_confidential_issues = false if current_user.blank?
|
||||
return @user_can_see_all_confidential_issues = true if current_user.can_read_all_resources?
|
||||
|
||||
@user_can_see_all_confidential_issues =
|
||||
if project? && project
|
||||
project.team.max_member_access(current_user.id) >= CONFIDENTIAL_ACCESS_LEVEL
|
||||
elsif group
|
||||
group.max_member_access_for_user(current_user) >= CONFIDENTIAL_ACCESS_LEVEL
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def user_cannot_see_confidential_issues?
|
||||
return false if user_can_see_all_confidential_issues?
|
||||
|
||||
current_user.blank?
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class IssuesFinder
|
||||
class Params < IssuableFinder::Params
|
||||
def public_only?
|
||||
params.fetch(:public_only, false)
|
||||
end
|
||||
|
||||
def filter_by_no_due_date?
|
||||
due_date? && params[:due_date] == Issue::NoDueDate.name
|
||||
end
|
||||
|
||||
def filter_by_overdue?
|
||||
due_date? && params[:due_date] == Issue::Overdue.name
|
||||
end
|
||||
|
||||
def filter_by_due_this_week?
|
||||
due_date? && params[:due_date] == Issue::DueThisWeek.name
|
||||
end
|
||||
|
||||
def filter_by_due_this_month?
|
||||
due_date? && params[:due_date] == Issue::DueThisMonth.name
|
||||
end
|
||||
|
||||
def filter_by_due_next_month_and_previous_two_weeks?
|
||||
due_date? && params[:due_date] == Issue::DueNextMonthAndPreviousTwoWeeks.name
|
||||
end
|
||||
|
||||
def user_can_see_all_confidential_issues?
|
||||
return @user_can_see_all_confidential_issues if defined?(@user_can_see_all_confidential_issues)
|
||||
|
||||
return @user_can_see_all_confidential_issues = false if current_user.blank?
|
||||
return @user_can_see_all_confidential_issues = true if current_user.can_read_all_resources?
|
||||
|
||||
@user_can_see_all_confidential_issues =
|
||||
if project? && project
|
||||
project.team.max_member_access(current_user.id) >= CONFIDENTIAL_ACCESS_LEVEL
|
||||
elsif group
|
||||
group.max_member_access_for_user(current_user) >= CONFIDENTIAL_ACCESS_LEVEL
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def user_cannot_see_confidential_issues?
|
||||
return false if user_can_see_all_confidential_issues?
|
||||
|
||||
current_user.blank?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
IssuableFinder::Params.prepend_if_ee('EE::IssuesFinder::Params')
|
|
@ -189,7 +189,7 @@ class MergeRequest < ApplicationRecord
|
|||
end
|
||||
|
||||
# rubocop: disable CodeReuse/ServiceClass
|
||||
after_transition [:unchecked, :checking] => :cannot_be_merged do |merge_request, transition|
|
||||
after_transition unchecked: :cannot_be_merged do |merge_request, transition|
|
||||
if merge_request.notify_conflict?
|
||||
NotificationService.new.merge_request_unmergeable(merge_request)
|
||||
TodoService.new.merge_request_became_unmergeable(merge_request)
|
||||
|
|
|
@ -21,7 +21,7 @@ module Issuable
|
|||
params.delete(key) unless params[key].present?
|
||||
end
|
||||
|
||||
if params[:assignee_ids] == [IssuableFinder::NONE.to_s]
|
||||
if params[:assignee_ids] == [IssuableFinder::Params::NONE.to_s]
|
||||
params[:assignee_ids] = []
|
||||
end
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ class IssuableBaseService < BaseService
|
|||
|
||||
assignee_ids = params[:assignee_ids].select { |assignee_id| assignee_can_read?(issuable, assignee_id) }
|
||||
|
||||
if params[:assignee_ids].map(&:to_s) == [IssuableFinder::NONE]
|
||||
if params[:assignee_ids].map(&:to_s) == [IssuableFinder::Params::NONE]
|
||||
params[:assignee_ids] = []
|
||||
elsif assignee_ids.any?
|
||||
params[:assignee_ids] = assignee_ids
|
||||
|
@ -70,7 +70,7 @@ class IssuableBaseService < BaseService
|
|||
milestone_id = params[:milestone_id]
|
||||
return unless milestone_id
|
||||
|
||||
params[:milestone_id] = '' if milestone_id == IssuableFinder::NONE
|
||||
params[:milestone_id] = '' if milestone_id == IssuableFinder::Params::NONE
|
||||
groups = project.group&.self_and_ancestors&.select(:id)
|
||||
|
||||
milestone =
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
- page_title "Service Templates"
|
||||
%h3.page-title Service templates
|
||||
%p.light Service template allows you to set default values for project services
|
||||
%p.light= s_('AdminSettings|Service template allows you to set default values for integrations')
|
||||
|
||||
.table-holder
|
||||
%table.table
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
%thead
|
||||
%tr
|
||||
%th
|
||||
%th= s_("ProjectService|Service")
|
||||
%th= _('Integration')
|
||||
%th.d-none.d-sm-block= _("Description")
|
||||
%th= s_("ProjectService|Last edit")
|
||||
- @services.sort_by(&:title).each do |service|
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
- breadcrumb_title @service.title
|
||||
- add_to_breadcrumbs _('Integration Settings'), project_settings_integrations_path(@project)
|
||||
- page_title @service.title, s_("ProjectService|Services")
|
||||
- page_title @service.title, _('Integrations')
|
||||
|
||||
= render 'deprecated_message' if @service.deprecation_message
|
||||
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Rename "Project Services" to "Integrations" in frontend and docs
|
||||
merge_request: 26244
|
||||
author:
|
||||
type: changed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add tooltips with full path to file headers on file tree
|
||||
merge_request: 27437
|
||||
author:
|
||||
type: fixed
|
|
@ -211,7 +211,7 @@ The following documentation relates to the DevOps **Create** stage:
|
|||
| [GitLab Integration](integration/README.md) | Integrate with multiple third-party services with GitLab to allow external issue trackers and external authentication. |
|
||||
| [GitLab Webhooks](user/project/integrations/webhooks.md) | Let GitLab notify you when new code has been pushed to your project. |
|
||||
| [Jira Development Panel](integration/jira_development_panel.md) **(PREMIUM)** | See GitLab information in the Jira Development Panel. |
|
||||
| [Project Services](user/project/integrations/project_services.md) | Integrate a project with external services, such as CI and chat. |
|
||||
| [Integrations](user/project/integrations/overview.md) | Integrate a project with external services, such as CI and chat. |
|
||||
| [Trello Power-Up](integration/trello_power_up.md) | Integrate with GitLab's Trello Power-Up. |
|
||||
|
||||
<div align="right">
|
||||
|
|
|
@ -196,7 +196,7 @@ than the specified limit, hooks won't be executed.
|
|||
More information can be found in these docs:
|
||||
|
||||
- [Webhooks push events](../user/project/integrations/webhooks.md#push-events)
|
||||
- [Project services push hooks limit](../user/project/integrations/project_services.md#push-hooks-limit)
|
||||
- [Project services push hooks limit](../user/project/integrations/overview.md#push-hooks-limit)
|
||||
|
||||
### Activities
|
||||
|
||||
|
|
|
@ -228,7 +228,7 @@ This file lives in `/var/log/gitlab/gitlab-rails/integrations_json.log` for
|
|||
Omnibus GitLab packages or in `/home/git/gitlab/log/integrations_json.log` for
|
||||
installations from source.
|
||||
|
||||
It contains information about [integrations](../user/project/integrations/project_services.md) activities such as Jira, Asana, and Irker services. It uses JSON format like the example below:
|
||||
It contains information about [integrations](../user/project/integrations/overview.md) activities such as Jira, Asana, and Irker services. It uses JSON format like the example below:
|
||||
|
||||
```json
|
||||
{
|
||||
|
|
|
@ -30,7 +30,7 @@ either:
|
|||
|
||||
NOTE: **Note:**
|
||||
This only applies to pipelines run as part of GitLab CI/CD. This will not enable or disable
|
||||
pipelines that are run from an [external integration](../user/project/integrations/project_services.md#services).
|
||||
pipelines that are run from an [external integration](../user/project/integrations/overview.md#integrations-listing).
|
||||
|
||||
## Per-project user setting
|
||||
|
||||
|
|
|
@ -435,13 +435,13 @@ To learn more about about scoping environments, see [Scoping environments with s
|
|||
|
||||
> Introduced in GitLab 8.15.
|
||||
|
||||
[Project services](../../user/project/integrations/project_services.md) that are
|
||||
[Integrations](../../user/project/integrations/overview.md) that are
|
||||
responsible for deployment configuration may define their own variables that
|
||||
are set in the build environment. These variables are only defined for
|
||||
[deployment jobs](../environments.md). Please consult the documentation of
|
||||
the project services that you are using to learn which variables they define.
|
||||
the integrations that you are using to learn which variables they define.
|
||||
|
||||
An example project service that defines deployment variables is the
|
||||
An example integration that defines deployment variables is the
|
||||
[Kubernetes integration](../../user/project/clusters/index.md#deployment-variables).
|
||||
|
||||
### Auto DevOps environment variables
|
||||
|
|
|
@ -90,3 +90,22 @@ To activate the Jenkins service you must have a Starter subscription or higher.
|
|||
## Test your setup
|
||||
|
||||
Make a change in your repository and open an MR. In your Jenkins project it should have triggered a new build and on your MR, there should be a widget saying "Pipeline #NUMBER passed". It will also include a link to your Jenkins build.
|
||||
|
||||
### Run QA test
|
||||
|
||||
The [jenkins_build_status_spec](https://gitlab.com/gitlab-org/gitlab/-/blob/v12.9.0-ee/qa/qa/specs/features/ee/browser_ui/3_create/jenkins/jenkins_build_status_spec.rb) performs an end-to-end test of the Jenkins setup using [GitLab QA](https://gitlab.com/gitlab-org/gitlab-qa).
|
||||
|
||||
To run the test against your GDK, follow the [run QA tests against your GDK setup](https://gitlab.com/gitlab-org/gitlab-qa/-/blob/master/docs/run_qa_against_gdk.md#run-qa-tests-against-your-gdk-setup) instructions.
|
||||
|
||||
The following environment variables are required to run the test:
|
||||
|
||||
- `GITLAB_USERNAME`
|
||||
- `GITLAB_PASSWORD`
|
||||
- `GITLAB_ADMIN_USERNAME`
|
||||
- `GITLAB_ADMIN_PASSWORD`
|
||||
|
||||
Run the test in the **qa** directory using:
|
||||
|
||||
```shell
|
||||
bundle exec bin/qa Test::Instance::All http://<your_network_ip_address>:3000 -- qa/specs/features/ee/browser_ui/3_create/jenkins/jenkins_build_status_spec.rb --tag quarantine
|
||||
```
|
||||
|
|
|
@ -57,9 +57,9 @@ GitLab can be integrated with the following enhancements:
|
|||
- Attach merge requests to [Trello](trello_power_up.md) cards.
|
||||
- Enable integrated code intelligence powered by [Sourcegraph](sourcegraph.md).
|
||||
|
||||
## Project services
|
||||
## Integrations
|
||||
|
||||
Integration with services such as Campfire, Flowdock, HipChat, Pivotal Tracker, and Slack are available as [Project Services](../user/project/integrations/project_services.md).
|
||||
Integration with services such as Campfire, Flowdock, HipChat, Pivotal Tracker, and Slack are available as [Integrations](../user/project/integrations/overview.md).
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
|
|
|
@ -15,11 +15,11 @@ GitLab menu always opens the internal issue tracker. When disabled, the link is
|
|||
|
||||
## Configuration
|
||||
|
||||
The configuration is done via a project's **Services**.
|
||||
The configuration is done via a project's **Integrations**.
|
||||
|
||||
### Project Service
|
||||
### Integration
|
||||
|
||||
To enable an external issue tracker you must configure the appropriate **Service**.
|
||||
To enable an external issue tracker you must configure the appropriate **Integration**.
|
||||
Visit the links below for details:
|
||||
|
||||
- [Redmine](../user/project/integrations/redmine.md)
|
||||
|
|
|
@ -6,8 +6,8 @@ In GitLab 8.3, Jenkins integration using the
|
|||
was deprecated in favor of the
|
||||
[GitLab Plugin](https://wiki.jenkins.io/display/JENKINS/GitLab+Plugin).
|
||||
The deprecated integration has been renamed to [Jenkins CI (Deprecated)](jenkins_deprecated.md) in the
|
||||
project service settings. We may remove this in a future release and recommend
|
||||
using the new 'Jenkins CI' project service instead which is described in this
|
||||
integration settings. We may remove this in a future release and recommend
|
||||
using the new 'Jenkins CI' integration instead which is described in this
|
||||
document.
|
||||
|
||||
## Overview
|
||||
|
@ -138,7 +138,7 @@ configured or there was an error reporting the status via the API.
|
|||
|
||||
### Merge Request event does not trigger a Jenkins Pipeline
|
||||
|
||||
Check [service hook logs](../user/project/integrations/project_services.md#troubleshooting-project-services) for request failures or check the `/var/log/gitlab/gitlab-rails/production.log` file for messages like:
|
||||
Check [service hook logs](../user/project/integrations/overview.md#troubleshooting-integrations) for request failures or check the `/var/log/gitlab/gitlab-rails/production.log` file for messages like:
|
||||
|
||||
```plaintext
|
||||
WebHook Error => Net::ReadTimeout
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
> The `run` command was [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/4466) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 10.6. [Moved](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/24780) to [GitLab Core](https://about.gitlab.com/pricing/) in 11.9.
|
||||
|
||||
Slash commands in Mattermost and Slack allow you to control GitLab and view GitLab content right inside your chat client, without having to leave it. For Slack, this requires a [project service configuration](../user/project/integrations/slack_slash_commands.md). Simply type the command as a message in your chat client to activate it.
|
||||
Slash commands in Mattermost and Slack allow you to control GitLab and view GitLab content right inside your chat client, without having to leave it. For Slack, this requires an [integration configuration](../user/project/integrations/slack_slash_commands.md). Simply type the command as a message in your chat client to activate it.
|
||||
|
||||
Commands are scoped to a project, with a trigger term that is specified during configuration.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
redirect_to: '../user/project/integrations/project_services.md'
|
||||
redirect_to: '../user/project/integrations/overview.md'
|
||||
---
|
||||
|
||||
This document was moved to [another location](../user/project/integrations/project_services.md).
|
||||
This document was moved to [another location](../user/project/integrations/overview.md).
|
||||
|
|
|
@ -66,7 +66,7 @@ With GitLab Enterprise Edition, you can also:
|
|||
- Leverage continuous delivery method with [Canary Deployments](project/canary_deployments.md).
|
||||
- Scan your code for vulnerabilities and [display them in merge requests](application_security/sast/index.md).
|
||||
|
||||
You can also [integrate](project/integrations/project_services.md) GitLab with numerous third-party applications, such as Mattermost, Microsoft Teams, HipChat, Trello, Slack, Bamboo CI, Jira, and a lot more.
|
||||
You can also [integrate](project/integrations/overview.md) GitLab with numerous third-party applications, such as Mattermost, Microsoft Teams, HipChat, Trello, Slack, Bamboo CI, Jira, and a lot more.
|
||||
|
||||
## Projects
|
||||
|
||||
|
|
|
@ -78,7 +78,7 @@ Kubernetes clusters can be used without Auto DevOps.
|
|||
|
||||
> Introduced in GitLab 8.15.
|
||||
|
||||
When enabled, the Kubernetes service adds [web terminal](../../../ci/environments.md#web-terminals)
|
||||
When enabled, the Kubernetes integration adds [web terminal](../../../ci/environments.md#web-terminals)
|
||||
support to your [environments](../../../ci/environments.md). This is based on the `exec` functionality found in
|
||||
Docker and Kubernetes, so you get a new shell session within your existing
|
||||
containers. To use this integration, you should deploy to Kubernetes using
|
||||
|
|
|
@ -72,7 +72,7 @@ To display the Deploy Boards for a specific [environment] you should:
|
|||
|
||||
1. [Configure GitLab Runner][runners] with the [Docker][docker-exec] or
|
||||
[Kubernetes][kube-exec] executor.
|
||||
1. Configure the [Kubernetes service][kube-service] in your project for the
|
||||
1. Configure the [Kubernetes integration][kube-integration] in your project for the
|
||||
cluster. The Kubernetes namespace is of particular note as you will need it
|
||||
for your deployment scripts (exposed by the `KUBE_NAMESPACE` env variable).
|
||||
1. Ensure Kubernetes annotations of `app.gitlab.com/env: $CI_ENVIRONMENT_SLUG`
|
||||
|
@ -151,7 +151,7 @@ version of your application.
|
|||
[environment]: ../../ci/environments.md "Environments and deployments documentation"
|
||||
[docker-exec]: https://docs.gitlab.com/runner/executors/docker.html "GitLab Runner Docker executor"
|
||||
[kube-exec]: https://docs.gitlab.com/runner/executors/kubernetes.html "GitLab Runner Kubernetes executor"
|
||||
[kube-service]: integrations/kubernetes.md "Kubernetes project service"
|
||||
[kube-integration]: clusters/index.md "Kubernetes integration"
|
||||
[review apps]: ../../ci/review_apps/index.md "Review Apps documentation"
|
||||
[variables]: ../../ci/variables/README.md "GitLab CI/CD variables"
|
||||
[autodeploy]: ../../topics/autodevops/index.md#auto-deploy "GitLab Autodeploy"
|
||||
|
|
|
@ -37,7 +37,7 @@ service in GitLab.
|
|||
### Complete these steps in GitLab
|
||||
|
||||
1. Navigate to the project you want to configure to trigger builds.
|
||||
1. Navigate to the [Integrations page](project_services.md#accessing-the-project-services)
|
||||
1. Navigate to the [Integrations page](overview.md#accessing-integrations)
|
||||
1. Click 'Atlassian Bamboo CI'
|
||||
1. Select the 'Active' checkbox.
|
||||
1. Enter the base URL of your Bamboo server. `https://bamboo.example.com`
|
||||
|
@ -55,7 +55,7 @@ service in GitLab.
|
|||
## Troubleshooting
|
||||
|
||||
If builds are not triggered, ensure you entered the right GitLab IP address in
|
||||
Bamboo under 'Trigger IP addresses'. Also check [service hook logs](project_services.md#troubleshooting-project-services) for request failures.
|
||||
Bamboo under 'Trigger IP addresses'. Also check [service hook logs](overview.md#troubleshooting-integrations) for request failures.
|
||||
|
||||
NOTE: **Note:**
|
||||
Starting with GitLab 8.14.0, builds are triggered on push events.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Bugzilla Service
|
||||
|
||||
Navigate to the [Integrations page](project_services.md#accessing-the-project-services),
|
||||
Navigate to the [Integrations page](overview.md#accessing-integrations),
|
||||
select the **Bugzilla** service and fill in the required details as described
|
||||
in the table below.
|
||||
|
||||
|
@ -29,4 +29,4 @@ address specified in `issues_url`.
|
|||
|
||||
## Troubleshooting
|
||||
|
||||
To see recent service hook deliveries, check [service hook logs](project_services.md#troubleshooting-project-services).
|
||||
To see recent service hook deliveries, check [service hook logs](overview.md#troubleshooting-integrations).
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# Custom Issue Tracker Service
|
||||
|
||||
To enable the Custom Issue Tracker integration in a project, navigate to the
|
||||
[Integrations page](project_services.md#accessing-the-project-services), click
|
||||
[Integrations page](overview.md#accessing-integrations), click
|
||||
the **Customer Issue Tracker** service, and fill in the required details on the page as described
|
||||
in the table below. You will be able to edit the title and description later as well.
|
||||
|
||||
|
|
|
@ -19,8 +19,8 @@ To send GitLab event notifications to a Discord channel, create a webhook in Dis
|
|||
|
||||
With the webhook URL created in the Discord channel, you can set up the Discord Notifications service in GitLab.
|
||||
|
||||
1. Navigate to the [Integrations page](project_services.md#accessing-the-project-services) in your project's settings. That is, **Project > Settings > Integrations**.
|
||||
1. Select the **Discord Notifications** project service to configure it.
|
||||
1. Navigate to the [Integrations page](overview.md#accessing-integrations) in your project's settings. That is, **Project > Settings > Integrations**.
|
||||
1. Select the **Discord Notifications** integration to configure it.
|
||||
1. Check the **Active** checkbox to turn on the service.
|
||||
1. Check the checkboxes corresponding to the GitLab events for which you want to send notifications to Discord.
|
||||
1. Paste the webhook URL that you copied from the create Discord webhook step.
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
By enabling this service, you will receive email notifications for every change
|
||||
that is pushed to your project.
|
||||
|
||||
From the [Integrations page](project_services.md#accessing-the-project-services)
|
||||
From the [Integrations page](overview.md#accessing-integrations)
|
||||
select **Emails on push** service to activate and configure it.
|
||||
|
||||
In the _Recipients_ area, provide a list of emails separated by spaces or newlines.
|
||||
|
|
|
@ -25,7 +25,7 @@ with `repo:status` access granted:
|
|||
### Complete these steps on GitLab
|
||||
|
||||
1. Navigate to the project you want to configure.
|
||||
1. Navigate to the [Integrations page](project_services.md#accessing-the-project-services)
|
||||
1. Navigate to the [Integrations page](overview.md#accessing-integrations)
|
||||
1. Click "GitHub".
|
||||
1. Select the "Active" checkbox.
|
||||
1. Paste the token you've generated on GitHub
|
||||
|
|
|
@ -17,8 +17,8 @@ See also [the Hangouts Chat documentation for configuring incoming webhooks](htt
|
|||
|
||||
When you have the **Webhook URL** for your Hangouts Chat room webhook, you can set up the GitLab service.
|
||||
|
||||
1. Navigate to the [Integrations page](project_services.md#accessing-the-project-services) in your project's settings, i.e. **Project > Settings > Integrations**.
|
||||
1. Select the **Hangouts Chat** project service to configure it.
|
||||
1. Navigate to the [Integrations page](overview.md#accessing-integrations) in your project's settings, i.e. **Project > Settings > Integrations**.
|
||||
1. Select the **Hangouts Chat** integration to configure it.
|
||||
1. Check the **Active** checkbox to turn on the service.
|
||||
1. Check the checkboxes corresponding to the GitLab events you want to receive.
|
||||
1. Paste the **Webhook URL** that you copied from the Hangouts Chat configuration step.
|
||||
|
|
|
@ -35,7 +35,7 @@ service in GitLab.
|
|||
### Complete these steps in GitLab
|
||||
|
||||
1. Navigate to the project you want to configure for notifications.
|
||||
1. Navigate to the [Integrations page](project_services.md#accessing-the-project-services)
|
||||
1. Navigate to the [Integrations page](overview.md#accessing-integrations)
|
||||
1. Click "HipChat".
|
||||
1. Select the "Active" checkbox.
|
||||
1. Insert the `token` field from the URL into the `Token` field on the Web page.
|
||||
|
|
|
@ -4,13 +4,13 @@ You can find the available integrations under your project's
|
|||
**Settings ➔ Integrations** page. You need to have at least
|
||||
[maintainer permission][permissions] on the project.
|
||||
|
||||
## Project services
|
||||
## Integrations
|
||||
|
||||
Project services allow you to integrate GitLab with other applications.
|
||||
Integrations allow you to integrate GitLab with other applications.
|
||||
They are a bit like plugins in that they allow a lot of freedom in
|
||||
adding functionality to GitLab.
|
||||
|
||||
[Learn more about project services.](project_services.md)
|
||||
[Learn more about integrations.](overview.md)
|
||||
|
||||
## Project webhooks
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ need to follow the firsts steps of the next section.
|
|||
## Complete these steps in GitLab
|
||||
|
||||
1. Navigate to the project you want to configure for notifications.
|
||||
1. Navigate to the [Integrations page](project_services.md#accessing-the-project-services)
|
||||
1. Navigate to the [Integrations page](overview.md#accessing-integrations)
|
||||
1. Click "Irker".
|
||||
1. Select the "Active" checkbox.
|
||||
1. Enter the server host address where `irkerd` runs (defaults to `localhost`)
|
||||
|
|
|
@ -65,7 +65,7 @@ In order to enable the Jira service in GitLab, you need to first configure the p
|
|||
> a value of `fromDialog`.
|
||||
|
||||
To enable the Jira integration in a project, navigate to the
|
||||
[Integrations page](project_services.md#accessing-the-project-services), click
|
||||
[Integrations page](overview.md#accessing-integrations), click
|
||||
the **Jira** service, and fill in the required details on the page as described
|
||||
in the table below.
|
||||
|
||||
|
@ -101,7 +101,7 @@ When you reference a Jira issue, it will always link back to the source commit/M
|
|||
|
||||
To disable the automated commenting on Jira issues:
|
||||
|
||||
1. Open the [Integrations page](project_services.md#accessing-the-project-services) and select **Jira**.
|
||||
1. Open the [Integrations page](overview.md#accessing-integrations) and select **Jira**.
|
||||
1. In the **Event Action** section, uncheck **Comment**.
|
||||
|
||||
## Jira issues
|
||||
|
|
|
@ -27,7 +27,7 @@ Display name override is not enabled by default, you need to ask your admin to e
|
|||
|
||||
After you set up Mattermost, it's time to set up GitLab.
|
||||
|
||||
Navigate to the [Integrations page](project_services.md#accessing-the-project-services)
|
||||
Navigate to the [Integrations page](overview.md#accessing-integrations)
|
||||
and select the **Mattermost notifications** service to configure it.
|
||||
There, you will see a checkbox with the following events that can be triggered:
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ the administrator console.
|
|||
### Step 2. Open the Mattermost slash commands service in GitLab
|
||||
|
||||
1. Open a new tab for GitLab, go to your project's
|
||||
[Integrations page](project_services.md#accessing-the-project-services)
|
||||
[Integrations page](overview.md#accessing-integrations)
|
||||
and select the **Mattermost command** service to configure it.
|
||||
A screen will appear with all the values you need to copy in Mattermost as
|
||||
described in the next step. Leave the window open.
|
||||
|
|
|
@ -9,7 +9,7 @@ Teams by following the steps described in [Sending messages to Connectors and We
|
|||
|
||||
After you set up Microsoft Teams, it's time to set up GitLab.
|
||||
|
||||
Navigate to the [Integrations page](project_services.md#accessing-the-project-services)
|
||||
Navigate to the [Integrations page](overview.md#accessing-integrations)
|
||||
and select the **Microsoft Teams Notification** service to configure it.
|
||||
There, you will see a checkbox with the following events that can be triggered:
|
||||
|
||||
|
|
|
@ -0,0 +1,108 @@
|
|||
# Integrations
|
||||
|
||||
Integrations allow you to integrate GitLab with other applications. They
|
||||
are a bit like plugins in that they allow a lot of freedom in adding
|
||||
functionality to GitLab.
|
||||
|
||||
## Accessing integrations
|
||||
|
||||
You can find the available integrations under your project's
|
||||
**Settings ➔ Integrations** page.
|
||||
|
||||
There are more than 20 integrations to integrate with. Click on the one that you
|
||||
want to configure.
|
||||
|
||||
![Integrations list](img/project_services.png)
|
||||
|
||||
Below, you will find a list of the currently supported ones accompanied with comprehensive documentation.
|
||||
|
||||
## Integrations listing
|
||||
|
||||
Click on the service links to see further configuration instructions and details.
|
||||
|
||||
| Service | Description | Service Hooks |
|
||||
| ------- | ----------- | ------------- |
|
||||
| Asana | Asana - Teamwork without email | No |
|
||||
| Assembla | Project Management Software (Source Commits Endpoint) | No |
|
||||
| [Atlassian Bamboo CI](bamboo.md) | A continuous integration and build server | Yes |
|
||||
| Buildkite | Continuous integration and deployments | Yes |
|
||||
| [Bugzilla](bugzilla.md) | Bugzilla issue tracker | No |
|
||||
| Campfire | Simple web-based real-time group chat | No |
|
||||
| Custom Issue Tracker | Custom issue tracker | No |
|
||||
| [Discord Notifications](discord_notifications.md) | Receive event notifications in Discord | No |
|
||||
| Drone CI | Continuous Integration platform built on Docker, written in Go | Yes |
|
||||
| [Emails on push](emails_on_push.md) | Email the commits and diff of each push to a list of recipients | No |
|
||||
| External Wiki | Replaces the link to the internal wiki with a link to an external wiki | No |
|
||||
| Flowdock | Flowdock is a collaboration web app for technical teams | No |
|
||||
| [Generic alerts](generic_alerts.md) **(ULTIMATE)** | Receive alerts on GitLab from any source | No |
|
||||
| [GitHub](github.md) **(PREMIUM)** | Sends pipeline notifications to GitHub | No |
|
||||
| [Hangouts Chat](hangouts_chat.md) | Receive events notifications in Google Hangouts Chat | No |
|
||||
| [HipChat](hipchat.md) | Private group chat and IM | No |
|
||||
| [Irker (IRC gateway)](irker.md) | Send IRC messages, on update, to a list of recipients through an Irker gateway | No |
|
||||
| [Jira](jira.md) | Jira issue tracker | No |
|
||||
| [Jenkins](../../../integration/jenkins.md) **(STARTER)** | An extendable open source continuous integration server | Yes |
|
||||
| JetBrains TeamCity CI | A continuous integration and build server | Yes |
|
||||
| [Mattermost slash commands](mattermost_slash_commands.md) | Mattermost chat and ChatOps slash commands | No |
|
||||
| [Mattermost Notifications](mattermost.md) | Receive event notifications in Mattermost | No |
|
||||
| [Microsoft teams](microsoft_teams.md) | Receive notifications for actions that happen on GitLab into a room on Microsoft Teams using Office 365 Connectors | No |
|
||||
| Packagist | Update your project on Packagist, the main Composer repository | Yes |
|
||||
| Pipelines emails | Email the pipeline status to a list of recipients | No |
|
||||
| [Slack Notifications](slack.md) | Send GitLab events (e.g. issue created) to Slack as notifications | No |
|
||||
| [Slack slash commands](slack_slash_commands.md) **(CORE ONLY)** | Use slash commands in Slack to control GitLab | No |
|
||||
| [GitLab Slack application](gitlab_slack_application.md) **(FREE ONLY)** | Use Slack's official application | No |
|
||||
| PivotalTracker | Project Management Software (Source Commits Endpoint) | No |
|
||||
| [Prometheus](prometheus.md) | Monitor the performance of your deployed apps | No |
|
||||
| Pushover | Pushover makes it easy to get real-time notifications on your Android device, iPhone, iPad, and Desktop | No |
|
||||
| [Redmine](redmine.md) | Redmine issue tracker | No |
|
||||
| [Unify Circuit](unify_circuit.md) | Receive events notifications in Unify Circuit | No |
|
||||
| [YouTrack](youtrack.md) | YouTrack issue tracker | No |
|
||||
|
||||
## Push hooks limit
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/17874) in GitLab 12.4.
|
||||
|
||||
If a single push includes changes to more than three branches or tags, services
|
||||
supported by `push_hooks` and `tag_push_hooks` events won't be executed.
|
||||
|
||||
The number of branches or tags supported can be changed via
|
||||
[`push_event_hooks_limit` application setting](../../../api/settings.md#list-of-settings-that-can-be-accessed-via-api-calls).
|
||||
|
||||
## Services templates
|
||||
|
||||
Services templates is a way to set some predefined values in the Service of
|
||||
your liking which will then be pre-filled on each project's Service.
|
||||
|
||||
Read more about [Services templates in this document](services_templates.md).
|
||||
|
||||
## Troubleshooting integrations
|
||||
|
||||
Some integrations use service hooks for integration with external applications. To confirm which ones use service hooks, see the [integrations listing](#integrations-listing). GitLab stores details of service hook requests made within the last 2 days. To view details of the requests, go to the service's configuration page.
|
||||
|
||||
The **Recent Deliveries** section lists the details of each request made within the last 2 days:
|
||||
|
||||
- HTTP status code (green for 200-299 codes, red for the others, `internal error` for failed deliveries)
|
||||
- Triggered event
|
||||
- URL to which the request was sent
|
||||
- Elapsed time of the request
|
||||
- Relative time in which the request was made
|
||||
|
||||
To view more information about the request's execution, click the respective **View details** link.
|
||||
On the details page, you can see the data sent by GitLab (request headers and body) and the data received by GitLab (response headers and body).
|
||||
|
||||
From this page, you can repeat delivery with the same data by clicking **Resend Request**.
|
||||
|
||||
![Recent deliveries](img/webhook_logs.png)
|
||||
|
||||
## Contributing to integrations
|
||||
|
||||
Because GitLab is open source we can ship with the code and tests for all
|
||||
plugins. This allows the community to keep the plugins up to date so that they
|
||||
always work in newer GitLab versions.
|
||||
|
||||
For an overview of what integrations are available, please see the
|
||||
[project_services source directory][projects-code].
|
||||
|
||||
Contributions are welcome!
|
||||
|
||||
[projects-code]: https://gitlab.com/gitlab-org/gitlab-foss/tree/master/app/models/project_services
|
||||
[permissions]: ../../permissions.md
|
|
@ -1,108 +1 @@
|
|||
# Project services
|
||||
|
||||
Project services allow you to integrate GitLab with other applications. They
|
||||
are a bit like plugins in that they allow a lot of freedom in adding
|
||||
functionality to GitLab.
|
||||
|
||||
## Accessing the project services
|
||||
|
||||
You can find the available services under your project's
|
||||
**Settings ➔ Integrations** page.
|
||||
|
||||
There are more than 20 services to integrate with. Click on the one that you
|
||||
want to configure.
|
||||
|
||||
![Project services list](img/project_services.png)
|
||||
|
||||
Below, you will find a list of the currently supported ones accompanied with comprehensive documentation.
|
||||
|
||||
## Services
|
||||
|
||||
Click on the service links to see further configuration instructions and details.
|
||||
|
||||
| Service | Description | Service Hooks |
|
||||
| ------- | ----------- | ------------- |
|
||||
| Asana | Asana - Teamwork without email | No |
|
||||
| Assembla | Project Management Software (Source Commits Endpoint) | No |
|
||||
| [Atlassian Bamboo CI](bamboo.md) | A continuous integration and build server | Yes |
|
||||
| Buildkite | Continuous integration and deployments | Yes |
|
||||
| [Bugzilla](bugzilla.md) | Bugzilla issue tracker | No |
|
||||
| Campfire | Simple web-based real-time group chat | No |
|
||||
| Custom Issue Tracker | Custom issue tracker | No |
|
||||
| [Discord Notifications](discord_notifications.md) | Receive event notifications in Discord | No |
|
||||
| Drone CI | Continuous Integration platform built on Docker, written in Go | Yes |
|
||||
| [Emails on push](emails_on_push.md) | Email the commits and diff of each push to a list of recipients | No |
|
||||
| External Wiki | Replaces the link to the internal wiki with a link to an external wiki | No |
|
||||
| Flowdock | Flowdock is a collaboration web app for technical teams | No |
|
||||
| [Generic alerts](generic_alerts.md) **(ULTIMATE)** | Receive alerts on GitLab from any source | No |
|
||||
| [GitHub](github.md) **(PREMIUM)** | Sends pipeline notifications to GitHub | No |
|
||||
| [Hangouts Chat](hangouts_chat.md) | Receive events notifications in Google Hangouts Chat | No |
|
||||
| [HipChat](hipchat.md) | Private group chat and IM | No |
|
||||
| [Irker (IRC gateway)](irker.md) | Send IRC messages, on update, to a list of recipients through an Irker gateway | No |
|
||||
| [Jira](jira.md) | Jira issue tracker | No |
|
||||
| [Jenkins](../../../integration/jenkins.md) **(STARTER)** | An extendable open source continuous integration server | Yes |
|
||||
| JetBrains TeamCity CI | A continuous integration and build server | Yes |
|
||||
| [Mattermost slash commands](mattermost_slash_commands.md) | Mattermost chat and ChatOps slash commands | No |
|
||||
| [Mattermost Notifications](mattermost.md) | Receive event notifications in Mattermost | No |
|
||||
| [Microsoft teams](microsoft_teams.md) | Receive notifications for actions that happen on GitLab into a room on Microsoft Teams using Office 365 Connectors | No |
|
||||
| Packagist | Update your project on Packagist, the main Composer repository | Yes |
|
||||
| Pipelines emails | Email the pipeline status to a list of recipients | No |
|
||||
| [Slack Notifications](slack.md) | Send GitLab events (e.g. issue created) to Slack as notifications | No |
|
||||
| [Slack slash commands](slack_slash_commands.md) **(CORE ONLY)** | Use slash commands in Slack to control GitLab | No |
|
||||
| [GitLab Slack application](gitlab_slack_application.md) **(FREE ONLY)** | Use Slack's official application | No |
|
||||
| PivotalTracker | Project Management Software (Source Commits Endpoint) | No |
|
||||
| [Prometheus](prometheus.md) | Monitor the performance of your deployed apps | No |
|
||||
| Pushover | Pushover makes it easy to get real-time notifications on your Android device, iPhone, iPad, and Desktop | No |
|
||||
| [Redmine](redmine.md) | Redmine issue tracker | No |
|
||||
| [Unify Circuit](unify_circuit.md) | Receive events notifications in Unify Circuit | No |
|
||||
| [YouTrack](youtrack.md) | YouTrack issue tracker | No |
|
||||
|
||||
## Push hooks limit
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/17874) in GitLab 12.4.
|
||||
|
||||
If a single push includes changes to more than three branches or tags, services
|
||||
supported by `push_hooks` and `tag_push_hooks` events won't be executed.
|
||||
|
||||
The number of branches or tags supported can be changed via
|
||||
[`push_event_hooks_limit` application setting](../../../api/settings.md#list-of-settings-that-can-be-accessed-via-api-calls).
|
||||
|
||||
## Services templates
|
||||
|
||||
Services templates is a way to set some predefined values in the Service of
|
||||
your liking which will then be pre-filled on each project's Service.
|
||||
|
||||
Read more about [Services templates in this document](services_templates.md).
|
||||
|
||||
## Troubleshooting project services
|
||||
|
||||
Some project services use service hooks for integration with external applications. To confirm which ones use service hooks, see the [services table](#services). GitLab stores details of service hook requests made within the last 2 days. To view details of the requests, go to the service's configuration page.
|
||||
|
||||
The **Recent Deliveries** section lists the details of each request made within the last 2 days:
|
||||
|
||||
- HTTP status code (green for 200-299 codes, red for the others, `internal error` for failed deliveries)
|
||||
- Triggered event
|
||||
- URL to which the request was sent
|
||||
- Elapsed time of the request
|
||||
- Relative time in which the request was made
|
||||
|
||||
To view more information about the request's execution, click the respective **View details** link.
|
||||
On the details page, you can see the data sent by GitLab (request headers and body) and the data received by GitLab (response headers and body).
|
||||
|
||||
From this page, you can repeat delivery with the same data by clicking **Resend Request**.
|
||||
|
||||
![Recent deliveries](img/webhook_logs.png)
|
||||
|
||||
## Contributing to project services
|
||||
|
||||
Because GitLab is open source we can ship with the code and tests for all
|
||||
plugins. This allows the community to keep the plugins up to date so that they
|
||||
always work in newer GitLab versions.
|
||||
|
||||
For an overview of what projects services are available, please see the
|
||||
[project_services source directory][projects-code].
|
||||
|
||||
Contributions are welcome!
|
||||
|
||||
[projects-code]: https://gitlab.com/gitlab-org/gitlab-foss/tree/master/app/models/project_services
|
||||
[permissions]: ../../permissions.md
|
||||
This document was moved to [Integrations](overview.md).
|
||||
|
|
|
@ -105,7 +105,7 @@ The actual configuration of Prometheus integration within GitLab is very simple.
|
|||
All you will need is the domain name or IP address of the Prometheus server you'd like
|
||||
to integrate with.
|
||||
|
||||
1. Navigate to the [Integrations page](project_services.md#accessing-the-project-services).
|
||||
1. Navigate to the [Integrations page](overview.md#accessing-integrations).
|
||||
1. Click the **Prometheus** service.
|
||||
1. Provide the domain name or IP address of your server, for example `http://prometheus.example.com/` or `http://192.0.2.1/`.
|
||||
1. Click **Save changes**.
|
||||
|
@ -118,7 +118,7 @@ You can configure [Thanos](https://thanos.io/) as a drop-in replacement for Prom
|
|||
with GitLab. You will need the domain name or IP address of the Thanos server you'd like
|
||||
to integrate with.
|
||||
|
||||
1. Navigate to the [Integrations page](project_services.md#accessing-the-project-services).
|
||||
1. Navigate to the [Integrations page](overview.md#accessing-integrations).
|
||||
1. Click the **Prometheus** service.
|
||||
1. Provide the domain name or IP address of your server, for example `http://thanos.example.com/` or `http://192.0.2.1/`.
|
||||
1. Click **Save changes**.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# Redmine Service
|
||||
|
||||
1. To enable the Redmine integration in a project, navigate to the
|
||||
[Integrations page](project_services.md#accessing-the-project-services), click
|
||||
[Integrations page](overview.md#accessing-integrations), click
|
||||
the **Redmine** service, and fill in the required details on the page as described
|
||||
in the table below.
|
||||
|
||||
|
|
|
@ -12,8 +12,8 @@ The Slack Notifications Service allows your GitLab project to send events (e.g.
|
|||
|
||||
## GitLab Configuration
|
||||
|
||||
1. Navigate to the [Integrations page](project_services.md#accessing-the-project-services) in your project's settings, i.e. **Project > Settings > Integrations**.
|
||||
1. Select the **Slack notifications** project service to configure it.
|
||||
1. Navigate to the [Integrations page](overview.md#accessing-integrations) in your project's settings, i.e. **Project > Settings > Integrations**.
|
||||
1. Select the **Slack notifications** integration to configure it.
|
||||
1. Check the **Active** checkbox to turn on the service.
|
||||
1. Check the checkboxes corresponding to the GitLab events you want to send to Slack as a notification.
|
||||
1. For each event, optionally enter the Slack channel names where you want to send the event, separated by a comma. If left empty, the event will be sent to the default channel that you configured in the Slack Configuration step. **Note:** Usernames and private channels are not supported. To send direct messages, use the Member ID found under user's Slack profile.
|
||||
|
|
|
@ -13,8 +13,8 @@ For GitLab.com, use the [Slack app](gitlab_slack_application.md) instead.
|
|||
|
||||
## Configuration
|
||||
|
||||
1. Slack slash commands are scoped to a project. Navigate to the [Integrations page](project_services.md#accessing-the-project-services) in your project's settings, i.e. **Project > Settings > Integrations**.
|
||||
1. Select the **Slack slash commands** project service to configure it. This page contains required information to complete the configuration in Slack. Leave this browser tab open.
|
||||
1. Slack slash commands are scoped to a project. Navigate to the [Integrations page](overview.md#accessing-integrations) in your project's settings, i.e. **Project > Settings > Integrations**.
|
||||
1. Select the **Slack slash commands** integration to configure it. This page contains required information to complete the configuration in Slack. Leave this browser tab open.
|
||||
1. Open a new browser tab and sign in to your Slack team. [Start a new Slash Commands integration](https://my.slack.com/services/new/slash-commands).
|
||||
1. Enter a trigger term. We suggest you use the project name. Click **Add Slash Command Integration**.
|
||||
1. Complete the rest of the fields in the Slack configuration page using information from the GitLab browser tab. In particular, the URL needs to be copied and pasted. Click **Save Integration** to complete the configuration in Slack.
|
||||
|
|
|
@ -15,8 +15,8 @@ For more information, see the [Unify Circuit documentation for configuring incom
|
|||
|
||||
When you have the **Webhook URL** for your Unify Circuit conversation webhook, you can set up the GitLab service.
|
||||
|
||||
1. Navigate to the [Integrations page](project_services.md#accessing-the-project-services) in your project's settings, i.e. **Project > Settings > Integrations**.
|
||||
1. Select the **Unify Circuit** project service to configure it.
|
||||
1. Navigate to the [Integrations page](overview.md#accessing-integrations) in your project's settings, i.e. **Project > Settings > Integrations**.
|
||||
1. Select the **Unify Circuit** integration to configure it.
|
||||
1. Check the **Active** checkbox to turn on the service.
|
||||
1. Check the checkboxes corresponding to the GitLab events you want to receive in Unify Circuit.
|
||||
1. Paste the **Webhook URL** that you copied from the Unify Circuit configuration step.
|
||||
|
|
|
@ -8,7 +8,7 @@ You can configure YouTrack as an [External Issue Tracker](../../../integration/e
|
|||
|
||||
To enable YouTrack integration in a project:
|
||||
|
||||
1. Navigate to the project's **Settings > [Integrations](project_services.md#accessing-the-project-services)** page.
|
||||
1. Navigate to the project's **Settings > [Integrations](overview.md#accessing-integrations)** page.
|
||||
1. Click the **YouTrack** service, ensure it's active, and enter the required details on the page as described in the table below.
|
||||
|
||||
| Field | Description |
|
||||
|
|
|
@ -39,7 +39,7 @@ You can prevent merge requests from being merged if their pipeline did not succe
|
|||
or if there are threads to be resolved. This works for both:
|
||||
|
||||
- GitLab CI/CD pipelines
|
||||
- Pipelines run from an [external CI integration](../integrations/project_services.md#services)
|
||||
- Pipelines run from an [external CI integration](../integrations/overview.md#integrations-listing)
|
||||
|
||||
As a result, [disabling GitLab CI/CD pipelines](../../../ci/enable_or_disable_ci.md)
|
||||
will not disable this feature, as it will still be possible to use pipelines from external
|
||||
|
|
|
@ -124,7 +124,7 @@ When you click the **Create branch** button in an empty
|
|||
repository project, GitLab automatically creates a `master` branch, commits
|
||||
a blank `README.md` file to it, and creates and redirects you to a new branch
|
||||
based on the issue title.
|
||||
If your [project is already configured with a deployment service](../integrations/project_services.md),
|
||||
If your [project is already configured with a deployment service](../integrations/overview.md),
|
||||
such as Kubernetes, GitLab takes one step further and prompts you to set up
|
||||
[auto deploy](../../../topics/autodevops/index.md#auto-deploy)
|
||||
by helping you create a `.gitlab-ci.yml` file.
|
||||
|
|
|
@ -38,7 +38,7 @@ module API
|
|||
value = params[attr_name]
|
||||
|
||||
return if value.is_a?(Integer) ||
|
||||
[IssuableFinder::FILTER_NONE, IssuableFinder::FILTER_ANY].include?(value.to_s.downcase)
|
||||
[IssuableFinder::Params::FILTER_NONE, IssuableFinder::Params::FILTER_ANY].include?(value.to_s.downcase)
|
||||
|
||||
raise Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)],
|
||||
message: "should be an integer, 'None' or 'Any'"
|
||||
|
@ -50,7 +50,7 @@ module API
|
|||
value = params[attr_name]
|
||||
|
||||
return if value.is_a?(Array) ||
|
||||
[IssuableFinder::FILTER_NONE, IssuableFinder::FILTER_ANY].include?(value.to_s.downcase)
|
||||
[IssuableFinder::Params::FILTER_NONE, IssuableFinder::Params::FILTER_ANY].include?(value.to_s.downcase)
|
||||
|
||||
raise Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)],
|
||||
message: "should be an array, 'None' or 'Any'"
|
||||
|
|
|
@ -944,6 +944,10 @@ module Gitlab
|
|||
Gitlab::GitalyClient::ConflictsService.new(self, our_commit_oid, their_commit_oid)
|
||||
end
|
||||
|
||||
def praefect_info_client
|
||||
@praefect_info_client ||= Gitlab::GitalyClient::PraefectInfoService.new(self)
|
||||
end
|
||||
|
||||
def clean_stale_repository_files
|
||||
wrapped_gitaly_errors do
|
||||
gitaly_repository_client.cleanup if exists?
|
||||
|
@ -1019,6 +1023,12 @@ module Gitlab
|
|||
raise NoRepository # Guard against data races.
|
||||
end
|
||||
|
||||
def replicas
|
||||
wrapped_gitaly_errors do
|
||||
praefect_info_client.replicas
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def empty_diff_stats
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Gitlab
|
||||
module GitalyClient
|
||||
class PraefectInfoService
|
||||
def initialize(repository)
|
||||
@repository = repository
|
||||
@gitaly_repo = repository.gitaly_repository
|
||||
@storage = repository.storage
|
||||
end
|
||||
|
||||
def replicas
|
||||
request = Gitaly::RepositoryReplicasRequest.new(repository: @gitaly_repo)
|
||||
|
||||
GitalyClient.call(@storage, :praefect_info_service, :repository_replicas, request, timeout: GitalyClient.fast_timeout)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1384,6 +1384,9 @@ msgstr ""
|
|||
msgid "AdminSettings|Select a template"
|
||||
msgstr ""
|
||||
|
||||
msgid "AdminSettings|Service template allows you to set default values for integrations"
|
||||
msgstr ""
|
||||
|
||||
msgid "AdminSettings|Set an instance-wide auto included %{link_start}pipeline configuration%{link_end}. This pipeline configuration will be run after the project's own configuration."
|
||||
msgstr ""
|
||||
|
||||
|
@ -15537,12 +15540,6 @@ msgstr ""
|
|||
msgid "ProjectService|Perform common operations on GitLab project: %{project_name}"
|
||||
msgstr ""
|
||||
|
||||
msgid "ProjectService|Service"
|
||||
msgstr ""
|
||||
|
||||
msgid "ProjectService|Services"
|
||||
msgstr ""
|
||||
|
||||
msgid "ProjectService|To set up this service:"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -39,8 +39,8 @@
|
|||
"@babel/plugin-syntax-import-meta": "^7.8.3",
|
||||
"@babel/preset-env": "^7.8.4",
|
||||
"@gitlab/at.js": "^1.5.5",
|
||||
"@gitlab/svgs": "^1.115.0",
|
||||
"@gitlab/ui": "^10.0.1",
|
||||
"@gitlab/svgs": "^1.116.0",
|
||||
"@gitlab/ui": "^10.1.2",
|
||||
"@gitlab/visual-review-tools": "1.5.1",
|
||||
"@sentry/browser": "^5.10.2",
|
||||
"@sourcegraph/code-host-integration": "0.0.34",
|
||||
|
|
|
@ -24,7 +24,7 @@ describe 'User filters issues' do
|
|||
let(:issue) { @issue }
|
||||
|
||||
it 'allows filtering by issues with no specified assignee' do
|
||||
visit project_issues_path(project, assignee_id: IssuableFinder::FILTER_NONE)
|
||||
visit project_issues_path(project, assignee_id: IssuableFinder::Params::FILTER_NONE)
|
||||
|
||||
expect(page).to have_content 'foobar'
|
||||
expect(page).not_to have_content 'barbaz'
|
||||
|
|
|
@ -35,7 +35,7 @@ describe 'Merge requests > User lists merge requests' do
|
|||
end
|
||||
|
||||
it 'filters on no assignee' do
|
||||
visit_merge_requests(project, assignee_id: IssuableFinder::FILTER_NONE)
|
||||
visit_merge_requests(project, assignee_id: IssuableFinder::Params::FILTER_NONE)
|
||||
|
||||
expect(current_path).to eq(project_merge_requests_path(project))
|
||||
expect(page).to have_content 'merge-test'
|
||||
|
|
|
@ -429,7 +429,7 @@ describe IssuesFinder do
|
|||
end
|
||||
|
||||
context 'filtering by no label' do
|
||||
let(:params) { { label_name: described_class::FILTER_NONE } }
|
||||
let(:params) { { label_name: described_class::Params::FILTER_NONE } }
|
||||
|
||||
it 'returns issues with no labels' do
|
||||
expect(issues).to contain_exactly(issue1, issue4)
|
||||
|
@ -437,7 +437,7 @@ describe IssuesFinder do
|
|||
end
|
||||
|
||||
context 'filtering by any label' do
|
||||
let(:params) { { label_name: described_class::FILTER_ANY } }
|
||||
let(:params) { { label_name: described_class::Params::FILTER_ANY } }
|
||||
|
||||
it 'returns issues that have one or more label' do
|
||||
create_list(:label_link, 2, label: create(:label, project: project2), target: issue3)
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
exports[`File row header component adds multiple ellipsises after 40 characters 1`] = `
|
||||
<div
|
||||
class="file-row-header bg-white sticky-top p-2 js-file-row-header"
|
||||
title="app/assets/javascripts/merge_requests/widget/diffs/notes"
|
||||
>
|
||||
<span
|
||||
class="bold"
|
||||
|
@ -15,6 +16,7 @@ exports[`File row header component adds multiple ellipsises after 40 characters
|
|||
exports[`File row header component renders file path 1`] = `
|
||||
<div
|
||||
class="file-row-header bg-white sticky-top p-2 js-file-row-header"
|
||||
title="app/assets"
|
||||
>
|
||||
<span
|
||||
class="bold"
|
||||
|
@ -27,6 +29,7 @@ exports[`File row header component renders file path 1`] = `
|
|||
exports[`File row header component trucates path after 40 characters 1`] = `
|
||||
<div
|
||||
class="file-row-header bg-white sticky-top p-2 js-file-row-header"
|
||||
title="app/assets/javascripts/merge_requests"
|
||||
>
|
||||
<span
|
||||
class="bold"
|
||||
|
|
|
@ -33,6 +33,35 @@ describe('File row component', () => {
|
|||
expect(name.text().trim()).toEqual(fileName);
|
||||
});
|
||||
|
||||
it('renders the full path as title', () => {
|
||||
const filePath = 'path/to/file/with a very long folder name/';
|
||||
const fileName = 'foo.txt';
|
||||
|
||||
createComponent({
|
||||
file: {
|
||||
name: fileName,
|
||||
isHeader: false,
|
||||
tree: [
|
||||
{
|
||||
parentPath: filePath,
|
||||
},
|
||||
],
|
||||
},
|
||||
level: 1,
|
||||
});
|
||||
|
||||
expect(wrapper.element.title.trim()).toEqual('path/to/file/with a very long folder name/');
|
||||
});
|
||||
|
||||
it('does not render a title attribute if no tree present', () => {
|
||||
createComponent({
|
||||
file: file('f1.txt'),
|
||||
level: 0,
|
||||
});
|
||||
|
||||
expect(wrapper.element.title.trim()).toEqual('');
|
||||
});
|
||||
|
||||
it('emits toggleTreeOpen on click', () => {
|
||||
const fileName = 't3';
|
||||
createComponent({
|
||||
|
|
|
@ -51,11 +51,11 @@ describe Resolvers::IssuesResolver do
|
|||
end
|
||||
|
||||
it 'filters by any assignee' do
|
||||
expect(resolve_issues(assignee_id: IssuableFinder::FILTER_ANY)).to contain_exactly(issue2)
|
||||
expect(resolve_issues(assignee_id: IssuableFinder::Params::FILTER_ANY)).to contain_exactly(issue2)
|
||||
end
|
||||
|
||||
it 'filters by no assignee' do
|
||||
expect(resolve_issues(assignee_id: IssuableFinder::FILTER_NONE)).to contain_exactly(issue1)
|
||||
expect(resolve_issues(assignee_id: IssuableFinder::Params::FILTER_NONE)).to contain_exactly(issue1)
|
||||
end
|
||||
|
||||
it 'filters by labels' do
|
||||
|
|
|
@ -1919,6 +1919,15 @@ describe Gitlab::Git::Repository, :seed_helper do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#replicas', :praefect do
|
||||
it 'gets the replica checksum through praefect' do
|
||||
resp = repository.replicas
|
||||
|
||||
expect(resp.replicas).to be_empty
|
||||
expect(resp.primary.checksum).to eq(repository.checksum)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#clean_stale_repository_files' do
|
||||
let(:worktree_id) { 'rebase-1' }
|
||||
let(:gitlab_worktree_path) { File.join(repository_path, 'gitlab-worktree', worktree_id) }
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::GitalyClient::PraefectInfoService do
|
||||
let(:project) { create(:project, :repository) }
|
||||
let(:repository) { project.repository }
|
||||
let(:gitaly_repository) { repository.gitaly_repository }
|
||||
let(:client) { described_class.new(repository) }
|
||||
|
||||
describe '#repository_replicas', :praefect do
|
||||
it 'sends an RPC request' do
|
||||
request = Gitaly::RepositoryReplicasRequest.new(repository: gitaly_repository)
|
||||
|
||||
expect_any_instance_of(Gitaly::PraefectInfoService::Stub).to receive(:repository_replicas).with(request, kind_of(Hash))
|
||||
|
||||
client.replicas
|
||||
end
|
||||
end
|
||||
end
|
|
@ -3223,14 +3223,6 @@ describe MergeRequest do
|
|||
subject.mark_as_unmergeable
|
||||
end
|
||||
|
||||
it 'notifies conflict, with enabled async mergability check' do
|
||||
expect(notification_service).to receive(:merge_request_unmergeable).with(subject).once
|
||||
expect(todo_service).to receive(:merge_request_became_unmergeable).with(subject).once
|
||||
|
||||
subject.mark_as_checking
|
||||
subject.mark_as_unmergeable
|
||||
end
|
||||
|
||||
it 'does not notify whenever merge request is newly unmergeable due to other reasons' do
|
||||
allow(subject.project.repository).to receive(:can_be_merged?).and_return(true)
|
||||
|
||||
|
|
|
@ -475,27 +475,27 @@ describe API::Issues do
|
|||
end
|
||||
|
||||
it 'returns an array of group issues with any label' do
|
||||
get api(base_url, user), params: { labels: IssuesFinder::FILTER_ANY }
|
||||
get api(base_url, user), params: { labels: IssuableFinder::Params::FILTER_ANY }
|
||||
|
||||
expect_paginated_array_response(group_issue.id)
|
||||
expect(json_response.first['id']).to eq(group_issue.id)
|
||||
end
|
||||
|
||||
it 'returns an array of group issues with any label with labels param as array' do
|
||||
get api(base_url, user), params: { labels: [IssuesFinder::FILTER_ANY] }
|
||||
get api(base_url, user), params: { labels: [IssuableFinder::Params::FILTER_ANY] }
|
||||
|
||||
expect_paginated_array_response(group_issue.id)
|
||||
expect(json_response.first['id']).to eq(group_issue.id)
|
||||
end
|
||||
|
||||
it 'returns an array of group issues with no label' do
|
||||
get api(base_url, user), params: { labels: IssuesFinder::FILTER_NONE }
|
||||
get api(base_url, user), params: { labels: IssuableFinder::Params::FILTER_NONE }
|
||||
|
||||
expect_paginated_array_response([group_closed_issue.id, group_confidential_issue.id])
|
||||
end
|
||||
|
||||
it 'returns an array of group issues with no label with labels param as array' do
|
||||
get api(base_url, user), params: { labels: [IssuesFinder::FILTER_NONE] }
|
||||
get api(base_url, user), params: { labels: [IssuableFinder::Params::FILTER_NONE] }
|
||||
|
||||
expect_paginated_array_response([group_closed_issue.id, group_confidential_issue.id])
|
||||
end
|
||||
|
|
|
@ -350,25 +350,25 @@ describe API::Issues do
|
|||
end
|
||||
|
||||
it 'returns an array of project issues with any label' do
|
||||
get api("#{base_url}/issues", user), params: { labels: IssuesFinder::FILTER_ANY }
|
||||
get api("#{base_url}/issues", user), params: { labels: IssuableFinder::Params::FILTER_ANY }
|
||||
|
||||
expect_paginated_array_response(issue.id)
|
||||
end
|
||||
|
||||
it 'returns an array of project issues with any label with labels param as array' do
|
||||
get api("#{base_url}/issues", user), params: { labels: [IssuesFinder::FILTER_ANY] }
|
||||
get api("#{base_url}/issues", user), params: { labels: [IssuableFinder::Params::FILTER_ANY] }
|
||||
|
||||
expect_paginated_array_response(issue.id)
|
||||
end
|
||||
|
||||
it 'returns an array of project issues with no label' do
|
||||
get api("#{base_url}/issues", user), params: { labels: IssuesFinder::FILTER_NONE }
|
||||
get api("#{base_url}/issues", user), params: { labels: IssuableFinder::Params::FILTER_NONE }
|
||||
|
||||
expect_paginated_array_response([confidential_issue.id, closed_issue.id])
|
||||
end
|
||||
|
||||
it 'returns an array of project issues with no label with labels param as array' do
|
||||
get api("#{base_url}/issues", user), params: { labels: [IssuesFinder::FILTER_NONE] }
|
||||
get api("#{base_url}/issues", user), params: { labels: [IssuableFinder::Params::FILTER_NONE] }
|
||||
|
||||
expect_paginated_array_response([confidential_issue.id, closed_issue.id])
|
||||
end
|
||||
|
|
|
@ -476,25 +476,25 @@ describe API::Issues do
|
|||
end
|
||||
|
||||
it 'returns an array of issues with any label' do
|
||||
get api('/issues', user), params: { labels: IssuesFinder::FILTER_ANY }
|
||||
get api('/issues', user), params: { labels: IssuableFinder::Params::FILTER_ANY }
|
||||
|
||||
expect_paginated_array_response(issue.id)
|
||||
end
|
||||
|
||||
it 'returns an array of issues with any label with labels param as array' do
|
||||
get api('/issues', user), params: { labels: [IssuesFinder::FILTER_ANY] }
|
||||
get api('/issues', user), params: { labels: [IssuableFinder::Params::FILTER_ANY] }
|
||||
|
||||
expect_paginated_array_response(issue.id)
|
||||
end
|
||||
|
||||
it 'returns an array of issues with no label' do
|
||||
get api('/issues', user), params: { labels: IssuesFinder::FILTER_NONE }
|
||||
get api('/issues', user), params: { labels: IssuableFinder::Params::FILTER_NONE }
|
||||
|
||||
expect_paginated_array_response(closed_issue.id)
|
||||
end
|
||||
|
||||
it 'returns an array of issues with no label with labels param as array' do
|
||||
get api('/issues', user), params: { labels: [IssuesFinder::FILTER_NONE] }
|
||||
get api('/issues', user), params: { labels: [IssuableFinder::Params::FILTER_NONE] }
|
||||
|
||||
expect_paginated_array_response(closed_issue.id)
|
||||
end
|
||||
|
|
|
@ -281,14 +281,14 @@ describe API::MergeRequests do
|
|||
end
|
||||
|
||||
it 'returns an array of merge requests with any label when filtering by any label' do
|
||||
get api(endpoint_path, user), params: { labels: IssuesFinder::FILTER_ANY }
|
||||
get api(endpoint_path, user), params: { labels: IssuableFinder::Params::FILTER_ANY }
|
||||
|
||||
expect_paginated_array_response([merge_request.id])
|
||||
expect(json_response.first['id']).to eq(merge_request.id)
|
||||
end
|
||||
|
||||
it 'returns an array of merge requests without a label when filtering by no label' do
|
||||
get api(endpoint_path, user), params: { labels: IssuesFinder::FILTER_NONE }
|
||||
get api(endpoint_path, user), params: { labels: IssuableFinder::Params::FILTER_NONE }
|
||||
|
||||
expect_response_contain_exactly(
|
||||
merge_request_merged.id, merge_request_locked.id, merge_request_closed.id
|
||||
|
|
|
@ -245,9 +245,9 @@ describe Issuable::BulkUpdateService do
|
|||
end
|
||||
end
|
||||
|
||||
context "when the new assignee ID is #{IssuableFinder::NONE}" do
|
||||
context "when the new assignee ID is #{IssuableFinder::Params::NONE}" do
|
||||
it 'unassigns the issues' do
|
||||
expect { bulk_update(merge_request, assignee_ids: [IssuableFinder::NONE]) }
|
||||
expect { bulk_update(merge_request, assignee_ids: [IssuableFinder::Params::NONE]) }
|
||||
.to change { merge_request.reload.assignee_ids }.to([])
|
||||
end
|
||||
end
|
||||
|
@ -282,9 +282,9 @@ describe Issuable::BulkUpdateService do
|
|||
end
|
||||
end
|
||||
|
||||
context "when the new assignee ID is #{IssuableFinder::NONE}" do
|
||||
context "when the new assignee ID is #{IssuableFinder::Params::NONE}" do
|
||||
it "unassigns the issues" do
|
||||
expect { bulk_update(issue, assignee_ids: [IssuableFinder::NONE.to_s]) }
|
||||
expect { bulk_update(issue, assignee_ids: [IssuableFinder::Params::NONE.to_s]) }
|
||||
.to change { issue.reload.assignees.count }.from(1).to(0)
|
||||
end
|
||||
end
|
||||
|
|
16
yarn.lock
16
yarn.lock
|
@ -781,15 +781,15 @@
|
|||
eslint-plugin-vue "^6.2.1"
|
||||
vue-eslint-parser "^7.0.0"
|
||||
|
||||
"@gitlab/svgs@^1.115.0":
|
||||
version "1.115.0"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.115.0.tgz#2762ad045d5a2bd728f74fcb4c00caa9bd6dbc22"
|
||||
integrity sha512-jlmNGqCTpSiPFrNbLaW6GGXNbvIShLdrpeYTtSEz/yFJMClQfPjHc8Zm9bl/PqAM5d/yGQqk8e+rBc4LeAhEfg==
|
||||
"@gitlab/svgs@^1.116.0":
|
||||
version "1.116.0"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.116.0.tgz#a3c89f950bb256c2e109444c9a85fecdd261292c"
|
||||
integrity sha512-sZLn3acu0IyrSnZRU1rE3UjxF6FlwvBNfjKQgn0qclxdbe8Ya6cGNVq4aGdCEkHwvb9rFpKbfHBujVgVKNkxSA==
|
||||
|
||||
"@gitlab/ui@^10.0.1":
|
||||
version "10.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-10.0.1.tgz#65deee8ded3b8d003dfd74cd93c7eb0549e11b37"
|
||||
integrity sha512-RMOJjpZjmWJnu0ebfGJsPOn6/ko+HlfHYbBXBImpTIk6Xsr5AaRjT4yCYEoefZ55jK/SJ2nxHytqrMe26wjfDA==
|
||||
"@gitlab/ui@^10.1.2":
|
||||
version "10.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-10.1.2.tgz#027f86f69ef08fb90cab5c69545adf37e20c6ceb"
|
||||
integrity sha512-xTvLIHrBqvvvHLVPMGdktBv3hNL7FPGPSFbAC3IURrVa/9FIJbzkIYFGlUIbLu/QX1i0CJN+MLmyHhLtzhKgtA==
|
||||
dependencies:
|
||||
"@babel/standalone" "^7.0.0"
|
||||
"@gitlab/vue-toasted" "^1.3.0"
|
||||
|
|
Loading…
Reference in New Issue