diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-03-31 00:08:01 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-03-31 00:08:01 +0300 |
commit | 95ad46159e4cd93f2b31838199180d824e041994 (patch) | |
tree | d41880d3b6a0093463694978590e590efb08caef | |
parent | 2c72daf2f1744f2b8c8c6674c266907e9ef55558 (diff) |
Add latest changes from gitlab-org/gitlab@master
74 files changed, 793 insertions, 613 deletions
diff --git a/.rubocop.yml b/.rubocop.yml index df2e7c2cb0b..f0c6a909bd2 100644 --- a/.rubocop.yml +++ b/.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' diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index bd9803aa943..3553ab14f29 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -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. diff --git a/app/assets/javascripts/vue_shared/components/file_row.vue b/app/assets/javascripts/vue_shared/components/file_row.vue index 4d60cf5b1cc..e3a606571c0 100644 --- a/app/assets/javascripts/vue_shared/components/file_row.vue +++ b/app/assets/javascripts/vue_shared/components/file_row.vue @@ -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" diff --git a/app/assets/javascripts/vue_shared/components/file_row_header.vue b/app/assets/javascripts/vue_shared/components/file_row_header.vue index 301fd8116a9..2c3e2a3a433 100644 --- a/app/assets/javascripts/vue_shared/components/file_row_header.vue +++ b/app/assets/javascripts/vue_shared/components/file_row_header.vue @@ -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> diff --git a/app/finders/issuable_finder.rb b/app/finders/issuable_finder.rb index 6d5b1ca3bc5..5687b375cf0 100644 --- a/app/finders/issuable_finder.rb +++ b/app/finders/issuable_finder.rb @@ -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 + return items unless params.milestones? + + 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 - - items 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? - - 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 + return items unless params.labels? - items - 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 + 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 - - 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 by_my_reaction_emoji(items) + return items unless params[:my_reaction_emoji] && current_user - 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 diff --git a/app/finders/issuable_finder/params.rb b/app/finders/issuable_finder/params.rb new file mode 100644 index 00000000000..120ef364368 --- /dev/null +++ b/app/finders/issuable_finder/params.rb @@ -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 diff --git a/app/finders/issues_finder.rb b/app/finders/issues_finder.rb index 641b4422db9..72695a9d501 100644 --- a/app/finders/issues_finder.rb +++ b/app/finders/issues_finder.rb @@ -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 diff --git a/app/finders/issues_finder/params.rb b/app/finders/issues_finder/params.rb new file mode 100644 index 00000000000..aaeead7c709 --- /dev/null +++ b/app/finders/issues_finder/params.rb @@ -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') diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 2a6f498269c..7934b0f8f59 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -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) diff --git a/app/services/issuable/bulk_update_service.rb b/app/services/issuable/bulk_update_service.rb index bbb3c2ad050..2cd0e1e992d 100644 --- a/app/services/issuable/bulk_update_service.rb +++ b/app/services/issuable/bulk_update_service.rb @@ -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 diff --git a/app/services/issuable_base_service.rb b/app/services/issuable_base_service.rb index 830afbf4a43..506f4309a1e 100644 --- a/app/services/issuable_base_service.rb +++ b/app/services/issuable_base_service.rb @@ -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 = diff --git a/app/views/admin/services/index.html.haml b/app/views/admin/services/index.html.haml index 48f31bd0c6e..e0a1a3549a5 100644 --- a/app/views/admin/services/index.html.haml +++ b/app/views/admin/services/index.html.haml @@ -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 diff --git a/app/views/projects/services/_index.html.haml b/app/views/projects/services/_index.html.haml index a4041d09415..dca324ac846 100644 --- a/app/views/projects/services/_index.html.haml +++ b/app/views/projects/services/_index.html.haml @@ -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| diff --git a/app/views/projects/services/edit.html.haml b/app/views/projects/services/edit.html.haml index ef799d2c046..4195dce7780 100644 --- a/app/views/projects/services/edit.html.haml +++ b/app/views/projects/services/edit.html.haml @@ -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 diff --git a/changelogs/unreleased/208516-rename-project-services-in-frontend-and-documentation.yml b/changelogs/unreleased/208516-rename-project-services-in-frontend-and-documentation.yml new file mode 100644 index 00000000000..7d404fadd99 --- /dev/null +++ b/changelogs/unreleased/208516-rename-project-services-in-frontend-and-documentation.yml @@ -0,0 +1,5 @@ +--- +title: Rename "Project Services" to "Integrations" in frontend and docs +merge_request: 26244 +author: +type: changed diff --git a/changelogs/unreleased/andr3-fix-file-tree-tooltips.yml b/changelogs/unreleased/andr3-fix-file-tree-tooltips.yml new file mode 100644 index 00000000000..998fa7079b1 --- /dev/null +++ b/changelogs/unreleased/andr3-fix-file-tree-tooltips.yml @@ -0,0 +1,5 @@ +--- +title: Add tooltips with full path to file headers on file tree +merge_request: 27437 +author: +type: fixed diff --git a/doc/README.md b/doc/README.md index 95a8b09dd07..3a3e93244c4 100644 --- a/doc/README.md +++ b/doc/README.md @@ -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"> diff --git a/doc/administration/instance_limits.md b/doc/administration/instance_limits.md index c1ab7730903..e44fc8679ce 100644 --- a/doc/administration/instance_limits.md +++ b/doc/administration/instance_limits.md @@ -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 diff --git a/doc/administration/logs.md b/doc/administration/logs.md index 01774f8d320..5a6eb95de42 100644 --- a/doc/administration/logs.md +++ b/doc/administration/logs.md @@ -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 { diff --git a/doc/ci/enable_or_disable_ci.md b/doc/ci/enable_or_disable_ci.md index 732b4676c56..12ed41e81ee 100644 --- a/doc/ci/enable_or_disable_ci.md +++ b/doc/ci/enable_or_disable_ci.md @@ -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 diff --git a/doc/ci/variables/README.md b/doc/ci/variables/README.md index 831669b6f6b..1ec4c154039 100644 --- a/doc/ci/variables/README.md +++ b/doc/ci/variables/README.md @@ -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 diff --git a/doc/development/integrations/jenkins.md b/doc/development/integrations/jenkins.md index 44ee80b7b3f..31c479bc898 100644 --- a/doc/development/integrations/jenkins.md +++ b/doc/development/integrations/jenkins.md @@ -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 +``` diff --git a/doc/integration/README.md b/doc/integration/README.md index 5cda537ac39..bba38922b9d 100644 --- a/doc/integration/README.md +++ b/doc/integration/README.md @@ -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 diff --git a/doc/integration/external-issue-tracker.md b/doc/integration/external-issue-tracker.md index c3328e01081..8b4ebc337de 100644 --- a/doc/integration/external-issue-tracker.md +++ b/doc/integration/external-issue-tracker.md @@ -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) diff --git a/doc/integration/jenkins.md b/doc/integration/jenkins.md index fee30578be4..5514b756c00 100644 --- a/doc/integration/jenkins.md +++ b/doc/integration/jenkins.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 diff --git a/doc/integration/slash_commands.md b/doc/integration/slash_commands.md index f74a4f1a77f..11abf3ca203 100644 --- a/doc/integration/slash_commands.md +++ b/doc/integration/slash_commands.md @@ -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. diff --git a/doc/project_services/project_services.md b/doc/project_services/project_services.md index 2ae7a0ce3ce..2d58e0ca065 100644 --- a/doc/project_services/project_services.md +++ b/doc/project_services/project_services.md @@ -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). diff --git a/doc/user/index.md b/doc/user/index.md index fdcc87aca0b..b6defdc3f65 100644 --- a/doc/user/index.md +++ b/doc/user/index.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 diff --git a/doc/user/project/clusters/index.md b/doc/user/project/clusters/index.md index 4594d415fa0..1517e8ad64e 100644 --- a/doc/user/project/clusters/index.md +++ b/doc/user/project/clusters/index.md @@ -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 diff --git a/doc/user/project/deploy_boards.md b/doc/user/project/deploy_boards.md index daeca8aa614..d8d1db4fbcb 100644 --- a/doc/user/project/deploy_boards.md +++ b/doc/user/project/deploy_boards.md @@ -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" diff --git a/doc/user/project/integrations/bamboo.md b/doc/user/project/integrations/bamboo.md index a43082d9415..726b5f657ea 100644 --- a/doc/user/project/integrations/bamboo.md +++ b/doc/user/project/integrations/bamboo.md @@ -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. diff --git a/doc/user/project/integrations/bugzilla.md b/doc/user/project/integrations/bugzilla.md index 109080f463e..de43c504b05 100644 --- a/doc/user/project/integrations/bugzilla.md +++ b/doc/user/project/integrations/bugzilla.md @@ -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). diff --git a/doc/user/project/integrations/custom_issue_tracker.md b/doc/user/project/integrations/custom_issue_tracker.md index 99f80aea8d1..848e89c18cb 100644 --- a/doc/user/project/integrations/custom_issue_tracker.md +++ b/doc/user/project/integrations/custom_issue_tracker.md @@ -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. diff --git a/doc/user/project/integrations/discord_notifications.md b/doc/user/project/integrations/discord_notifications.md index e9fa01246f7..9252b7dd0f9 100644 --- a/doc/user/project/integrations/discord_notifications.md +++ b/doc/user/project/integrations/discord_notifications.md @@ -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. diff --git a/doc/user/project/integrations/emails_on_push.md b/doc/user/project/integrations/emails_on_push.md index 61359dcaa90..b0838690d3b 100644 --- a/doc/user/project/integrations/emails_on_push.md +++ b/doc/user/project/integrations/emails_on_push.md @@ -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. diff --git a/doc/user/project/integrations/github.md b/doc/user/project/integrations/github.md index f84f1bb06cd..2e3801f3a32 100644 --- a/doc/user/project/integrations/github.md +++ b/doc/user/project/integrations/github.md @@ -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 diff --git a/doc/user/project/integrations/hangouts_chat.md b/doc/user/project/integrations/hangouts_chat.md index 6e77708162d..bd32ef91e3c 100644 --- a/doc/user/project/integrations/hangouts_chat.md +++ b/doc/user/project/integrations/hangouts_chat.md @@ -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. diff --git a/doc/user/project/integrations/hipchat.md b/doc/user/project/integrations/hipchat.md index 347f7973c84..1e04e28143a 100644 --- a/doc/user/project/integrations/hipchat.md +++ b/doc/user/project/integrations/hipchat.md @@ -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. diff --git a/doc/user/project/integrations/index.md b/doc/user/project/integrations/index.md index 363e994f36d..21df15c90f4 100644 --- a/doc/user/project/integrations/index.md +++ b/doc/user/project/integrations/index.md @@ -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 diff --git a/doc/user/project/integrations/irker.md b/doc/user/project/integrations/irker.md index cadf01c382a..f7e129d1e7f 100644 --- a/doc/user/project/integrations/irker.md +++ b/doc/user/project/integrations/irker.md @@ -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`) diff --git a/doc/user/project/integrations/jira.md b/doc/user/project/integrations/jira.md index 76b1d187698..cef9300fc67 100644 --- a/doc/user/project/integrations/jira.md +++ b/doc/user/project/integrations/jira.md @@ -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 diff --git a/doc/user/project/integrations/mattermost.md b/doc/user/project/integrations/mattermost.md index c240b6cb6b4..67d60984c22 100644 --- a/doc/user/project/integrations/mattermost.md +++ b/doc/user/project/integrations/mattermost.md @@ -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: diff --git a/doc/user/project/integrations/mattermost_slash_commands.md b/doc/user/project/integrations/mattermost_slash_commands.md index 563cad717e2..35bcc907185 100644 --- a/doc/user/project/integrations/mattermost_slash_commands.md +++ b/doc/user/project/integrations/mattermost_slash_commands.md @@ -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. diff --git a/doc/user/project/integrations/microsoft_teams.md b/doc/user/project/integrations/microsoft_teams.md index f2a94de9906..6d37646d75b 100644 --- a/doc/user/project/integrations/microsoft_teams.md +++ b/doc/user/project/integrations/microsoft_teams.md @@ -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: diff --git a/doc/user/project/integrations/overview.md b/doc/user/project/integrations/overview.md new file mode 100644 index 00000000000..b973abbe210 --- /dev/null +++ b/doc/user/project/integrations/overview.md @@ -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 diff --git a/doc/user/project/integrations/project_services.md b/doc/user/project/integrations/project_services.md index 96221971908..2c681db1692 100644 --- a/doc/user/project/integrations/project_services.md +++ b/doc/user/project/integrations/project_services.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). diff --git a/doc/user/project/integrations/prometheus.md b/doc/user/project/integrations/prometheus.md index 230b4a379b1..04be63de5ea 100644 --- a/doc/user/project/integrations/prometheus.md +++ b/doc/user/project/integrations/prometheus.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**. diff --git a/doc/user/project/integrations/redmine.md b/doc/user/project/integrations/redmine.md index 56e219fade5..9e1cdf0490c 100644 --- a/doc/user/project/integrations/redmine.md +++ b/doc/user/project/integrations/redmine.md @@ -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. diff --git a/doc/user/project/integrations/slack.md b/doc/user/project/integrations/slack.md index c6a8941785a..6ceb398fa17 100644 --- a/doc/user/project/integrations/slack.md +++ b/doc/user/project/integrations/slack.md @@ -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. diff --git a/doc/user/project/integrations/slack_slash_commands.md b/doc/user/project/integrations/slack_slash_commands.md index 813066c51ac..d39d5cde46a 100644 --- a/doc/user/project/integrations/slack_slash_commands.md +++ b/doc/user/project/integrations/slack_slash_commands.md @@ -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. diff --git a/doc/user/project/integrations/unify_circuit.md b/doc/user/project/integrations/unify_circuit.md index e357afb9224..51f524f95c3 100644 --- a/doc/user/project/integrations/unify_circuit.md +++ b/doc/user/project/integrations/unify_circuit.md @@ -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. diff --git a/doc/user/project/integrations/youtrack.md b/doc/user/project/integrations/youtrack.md index 81c148e41fd..a72eaaa9ff1 100644 --- a/doc/user/project/integrations/youtrack.md +++ b/doc/user/project/integrations/youtrack.md @@ -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 | diff --git a/doc/user/project/merge_requests/merge_when_pipeline_succeeds.md b/doc/user/project/merge_requests/merge_when_pipeline_succeeds.md index cc3e00bc098..50412e0b319 100644 --- a/doc/user/project/merge_requests/merge_when_pipeline_succeeds.md +++ b/doc/user/project/merge_requests/merge_when_pipeline_succeeds.md @@ -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 diff --git a/doc/user/project/repository/web_editor.md b/doc/user/project/repository/web_editor.md index f1947066279..3a6fef0bc51 100644 --- a/doc/user/project/repository/web_editor.md +++ b/doc/user/project/repository/web_editor.md @@ -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. diff --git a/lib/api/helpers/custom_validators.rb b/lib/api/helpers/custom_validators.rb index b4523d7b436..76f5fe555b4 100644 --- a/lib/api/helpers/custom_validators.rb +++ b/lib/api/helpers/custom_validators.rb @@ -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'" diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb index 9adabd4e8fe..ed746163748 100644 --- a/lib/gitlab/git/repository.rb +++ b/lib/gitlab/git/repository.rb @@ -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 diff --git a/lib/gitlab/gitaly_client/praefect_info_service.rb b/lib/gitlab/gitaly_client/praefect_info_service.rb new file mode 100644 index 00000000000..127f8cfbdf6 --- /dev/null +++ b/lib/gitlab/gitaly_client/praefect_info_service.rb @@ -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 diff --git a/locale/gitlab.pot b/locale/gitlab.pot index fe50802b059..4f713893a9c 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -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 "" diff --git a/package.json b/package.json index b3c01541d0e..bc0c719943d 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/spec/features/issues/user_filters_issues_spec.rb b/spec/features/issues/user_filters_issues_spec.rb index 714bc972025..9ce47e68926 100644 --- a/spec/features/issues/user_filters_issues_spec.rb +++ b/spec/features/issues/user_filters_issues_spec.rb @@ -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' diff --git a/spec/features/merge_requests/user_lists_merge_requests_spec.rb b/spec/features/merge_requests/user_lists_merge_requests_spec.rb index f145bdd044b..ee0d7307e6c 100644 --- a/spec/features/merge_requests/user_lists_merge_requests_spec.rb +++ b/spec/features/merge_requests/user_lists_merge_requests_spec.rb @@ -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' diff --git a/spec/finders/issues_finder_spec.rb b/spec/finders/issues_finder_spec.rb index ff52e1b9d5f..b6bedab724a 100644 --- a/spec/finders/issues_finder_spec.rb +++ b/spec/finders/issues_finder_spec.rb @@ -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) diff --git a/spec/frontend/vue_shared/components/__snapshots__/file_row_header_spec.js.snap b/spec/frontend/vue_shared/components/__snapshots__/file_row_header_spec.js.snap index 26eae2d5e61..5ab159a5a84 100644 --- a/spec/frontend/vue_shared/components/__snapshots__/file_row_header_spec.js.snap +++ b/spec/frontend/vue_shared/components/__snapshots__/file_row_header_spec.js.snap @@ -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" diff --git a/spec/frontend/vue_shared/components/file_row_spec.js b/spec/frontend/vue_shared/components/file_row_spec.js index b3ced84ddb5..732491378fa 100644 --- a/spec/frontend/vue_shared/components/file_row_spec.js +++ b/spec/frontend/vue_shared/components/file_row_spec.js @@ -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({ diff --git a/spec/graphql/resolvers/issues_resolver_spec.rb b/spec/graphql/resolvers/issues_resolver_spec.rb index 4467c228e96..53e0a9e3724 100644 --- a/spec/graphql/resolvers/issues_resolver_spec.rb +++ b/spec/graphql/resolvers/issues_resolver_spec.rb @@ -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 diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb index b706cad612a..183e6e8d044 100644 --- a/spec/lib/gitlab/git/repository_spec.rb +++ b/spec/lib/gitlab/git/repository_spec.rb @@ -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) } diff --git a/spec/lib/gitlab/gitaly_client/praefect_info_service_spec.rb b/spec/lib/gitlab/gitaly_client/praefect_info_service_spec.rb new file mode 100644 index 00000000000..9b5c751e0ec --- /dev/null +++ b/spec/lib/gitlab/gitaly_client/praefect_info_service_spec.rb @@ -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 diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index f37e39a9ee9..137795dcbc3 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -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) diff --git a/spec/requests/api/issues/get_group_issues_spec.rb b/spec/requests/api/issues/get_group_issues_spec.rb index 0a95f9114a5..3ec5f380390 100644 --- a/spec/requests/api/issues/get_group_issues_spec.rb +++ b/spec/requests/api/issues/get_group_issues_spec.rb @@ -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 diff --git a/spec/requests/api/issues/get_project_issues_spec.rb b/spec/requests/api/issues/get_project_issues_spec.rb index 539841fe460..1e6a1d2ed20 100644 --- a/spec/requests/api/issues/get_project_issues_spec.rb +++ b/spec/requests/api/issues/get_project_issues_spec.rb @@ -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 diff --git a/spec/requests/api/issues/issues_spec.rb b/spec/requests/api/issues/issues_spec.rb index 6fea6201a65..d9496d6646f 100644 --- a/spec/requests/api/issues/issues_spec.rb +++ b/spec/requests/api/issues/issues_spec.rb @@ -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 diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb index a3fd365771b..ab7149a6bb3 100644 --- a/spec/requests/api/merge_requests_spec.rb +++ b/spec/requests/api/merge_requests_spec.rb @@ -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 diff --git a/spec/services/issuable/bulk_update_service_spec.rb b/spec/services/issuable/bulk_update_service_spec.rb index 2b0b486308a..f82a3cee1d9 100644 --- a/spec/services/issuable/bulk_update_service_spec.rb +++ b/spec/services/issuable/bulk_update_service_spec.rb @@ -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 diff --git a/yarn.lock b/yarn.lock index d78aee490e2..9610f68fd97 100644 --- a/yarn.lock +++ b/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/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/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.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" |