Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
3902d464d6
commit
2e2cd0ea3e
|
|
@ -1 +1 @@
|
|||
d08b7024a0a2882dc55d8a480d891fc0ded5bb9b
|
||||
13.1.0-rc2
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ export const getProjectSlug = () => {
|
|||
};
|
||||
|
||||
export const getGroupSlug = () => {
|
||||
if (isInGroupsPage()) {
|
||||
if (isInProjectPage() || isInGroupsPage()) {
|
||||
return $('body').data('group');
|
||||
}
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ import initSearchAutocomplete from './search_autocomplete';
|
|||
import GlFieldErrors from './gl_field_errors';
|
||||
import initUserPopovers from './user_popovers';
|
||||
import initBroadcastNotifications from './broadcast_notification';
|
||||
import PersistentUserCallout from './persistent_user_callout';
|
||||
import initPersistentUserCallouts from './persistent_user_callouts';
|
||||
import { initUserTracking } from './tracking';
|
||||
import { __ } from './locale';
|
||||
|
||||
|
|
@ -108,12 +108,7 @@ function deferredInitialisation() {
|
|||
initUserPopovers();
|
||||
initBroadcastNotifications();
|
||||
initFrequentItemDropdowns();
|
||||
|
||||
const recoverySettingsCallout = document.querySelector('.js-recovery-settings-callout');
|
||||
PersistentUserCallout.factory(recoverySettingsCallout);
|
||||
|
||||
const usersOverLicenseCallout = document.querySelector('.js-users-over-license-callout');
|
||||
PersistentUserCallout.factory(usersOverLicenseCallout);
|
||||
initPersistentUserCallouts();
|
||||
|
||||
if (document.querySelector('.search')) initSearchAutocomplete();
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
import PersistentUserCallout from './persistent_user_callout';
|
||||
|
||||
const PERSISTENT_USER_CALLOUTS = [
|
||||
'.js-recovery-settings-callout',
|
||||
'.js-users-over-license-callout',
|
||||
'.js-admin-licensed-user-count-threshold',
|
||||
];
|
||||
|
||||
const initCallouts = () => {
|
||||
PERSISTENT_USER_CALLOUTS.forEach(calloutContainer =>
|
||||
PersistentUserCallout.factory(document.querySelector(calloutContainer)),
|
||||
);
|
||||
};
|
||||
|
||||
export default initCallouts;
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import $ from 'jquery';
|
||||
import { escape, throttle } from 'lodash';
|
||||
import { s__, __ } from '~/locale';
|
||||
import { s__, __, sprintf } from '~/locale';
|
||||
import { getIdenticonBackgroundClass, getIdenticonTitle } from '~/helpers/avatar_helper';
|
||||
import axios from './lib/utils/axios_utils';
|
||||
import {
|
||||
|
|
@ -170,33 +170,24 @@ export class SearchAutocomplete {
|
|||
},
|
||||
})
|
||||
.then(response => {
|
||||
// Hide dropdown menu if no suggestions returns
|
||||
if (!response.data.length) {
|
||||
this.disableAutocomplete();
|
||||
return;
|
||||
}
|
||||
const options = this.scopedSearchOptions(term);
|
||||
|
||||
const data = [];
|
||||
// List results
|
||||
let firstCategory = true;
|
||||
let lastCategory;
|
||||
let lastCategory = null;
|
||||
for (let i = 0, len = response.data.length; i < len; i += 1) {
|
||||
const suggestion = response.data[i];
|
||||
// Add group header before list each group
|
||||
if (lastCategory !== suggestion.category) {
|
||||
if (!firstCategory) {
|
||||
data.push({ type: 'separator' });
|
||||
}
|
||||
if (firstCategory) {
|
||||
firstCategory = false;
|
||||
}
|
||||
data.push({
|
||||
options.push({ type: 'separator' });
|
||||
options.push({
|
||||
type: 'header',
|
||||
content: suggestion.category,
|
||||
});
|
||||
lastCategory = suggestion.category;
|
||||
}
|
||||
data.push({
|
||||
|
||||
// Add the suggestion
|
||||
options.push({
|
||||
id: `${suggestion.category.toLowerCase()}-${suggestion.id}`,
|
||||
icon: this.getAvatar(suggestion),
|
||||
category: suggestion.category,
|
||||
|
|
@ -204,39 +195,8 @@ export class SearchAutocomplete {
|
|||
url: suggestion.url,
|
||||
});
|
||||
}
|
||||
// Add option to proceed with the search
|
||||
if (data.length) {
|
||||
const icon = spriteIcon('search', 's16 inline-search-icon');
|
||||
let template;
|
||||
|
||||
if (this.projectInputEl.val()) {
|
||||
template = s__('SearchAutocomplete|in this project');
|
||||
}
|
||||
if (this.groupInputEl.val()) {
|
||||
template = s__('SearchAutocomplete|in this group');
|
||||
}
|
||||
|
||||
data.unshift({ type: 'separator' });
|
||||
data.unshift({
|
||||
icon,
|
||||
text: term,
|
||||
template: s__('SearchAutocomplete|in all GitLab'),
|
||||
url: `${gon.relative_url_root}/search?search=${term}`,
|
||||
});
|
||||
|
||||
if (template) {
|
||||
data.unshift({
|
||||
icon,
|
||||
text: term,
|
||||
template,
|
||||
url: `${
|
||||
gon.relative_url_root
|
||||
}/search?search=${term}&project_id=${this.projectInputEl.val()}&group_id=${this.groupInputEl.val()}`,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
callback(data);
|
||||
callback(options);
|
||||
|
||||
this.loadingSuggestions = false;
|
||||
this.highlightFirstRow();
|
||||
|
|
@ -253,10 +213,10 @@ export class SearchAutocomplete {
|
|||
|
||||
// Get options
|
||||
let options;
|
||||
if (isInGroupsPage() && groupOptions) {
|
||||
options = groupOptions[getGroupSlug()];
|
||||
} else if (isInProjectPage() && projectOptions) {
|
||||
if (isInProjectPage() && projectOptions) {
|
||||
options = projectOptions[getProjectSlug()];
|
||||
} else if (isInGroupsPage() && groupOptions) {
|
||||
options = groupOptions[getGroupSlug()];
|
||||
} else if (dashboardOptions) {
|
||||
options = dashboardOptions;
|
||||
}
|
||||
|
|
@ -301,6 +261,64 @@ export class SearchAutocomplete {
|
|||
return items;
|
||||
}
|
||||
|
||||
// Add option to proceed with the search for each
|
||||
// scope that is currently available, namely:
|
||||
//
|
||||
// - Search in this project
|
||||
// - Search in this group (or project's group)
|
||||
// - Search in all GitLab
|
||||
scopedSearchOptions(term) {
|
||||
const icon = spriteIcon('search', 's16 inline-search-icon');
|
||||
const projectId = this.projectInputEl.val();
|
||||
const groupId = this.groupInputEl.val();
|
||||
const options = [];
|
||||
|
||||
if (projectId) {
|
||||
const projectOptions = gl.projectOptions[getProjectSlug()];
|
||||
const url = groupId
|
||||
? `${gon.relative_url_root}/search?search=${term}&project_id=${projectId}&group_id=${groupId}`
|
||||
: `${gon.relative_url_root}/search?search=${term}&project_id=${projectId}`;
|
||||
|
||||
options.push({
|
||||
icon,
|
||||
text: term,
|
||||
template: sprintf(
|
||||
s__(`SearchAutocomplete|in project %{projectName}`),
|
||||
{
|
||||
projectName: `<i>${projectOptions.name}</i>`,
|
||||
},
|
||||
false,
|
||||
),
|
||||
url,
|
||||
});
|
||||
}
|
||||
|
||||
if (groupId) {
|
||||
const groupOptions = gl.groupOptions[getGroupSlug()];
|
||||
options.push({
|
||||
icon,
|
||||
text: term,
|
||||
template: sprintf(
|
||||
s__(`SearchAutocomplete|in group %{groupName}`),
|
||||
{
|
||||
groupName: `<i>${groupOptions.name}</i>`,
|
||||
},
|
||||
false,
|
||||
),
|
||||
url: `${gon.relative_url_root}/search?search=${term}&group_id=${groupId}`,
|
||||
});
|
||||
}
|
||||
|
||||
options.push({
|
||||
icon,
|
||||
text: term,
|
||||
template: s__('SearchAutocomplete|in all GitLab'),
|
||||
url: `${gon.relative_url_root}/search?search=${term}`,
|
||||
});
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
serializeState() {
|
||||
return {
|
||||
// Search Criteria
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ class ApplicationController < ActionController::Base
|
|||
include WorkhorseHelper
|
||||
include EnforcesTwoFactorAuthentication
|
||||
include WithPerformanceBar
|
||||
include Gitlab::SearchContext::ControllerConcern
|
||||
include SessionlessAuthentication
|
||||
include SessionsHelper
|
||||
include ConfirmEmailWarning
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ module ApplicationHelper
|
|||
page: body_data_page,
|
||||
page_type_id: controller.params[:id],
|
||||
find_file: find_file_path,
|
||||
group: "#{@group&.path}"
|
||||
group: @group&.path
|
||||
}.merge(project_data)
|
||||
end
|
||||
|
||||
|
|
@ -113,6 +113,7 @@ module ApplicationHelper
|
|||
{
|
||||
project_id: @project.id,
|
||||
project: @project.path,
|
||||
group: @project.group&.path,
|
||||
namespace_id: @project.namespace&.id
|
||||
}
|
||||
end
|
||||
|
|
|
|||
|
|
@ -104,6 +104,16 @@ module PageLayoutHelper
|
|||
end
|
||||
end
|
||||
|
||||
# This helper ensures there is always a default `Gitlab::SearchContext` available
|
||||
# to all controller that use the application layout.
|
||||
def search_context
|
||||
strong_memoize(:search_context) do
|
||||
next super if defined?(super)
|
||||
|
||||
Gitlab::SearchContext::Builder.new(controller.view_context).build!
|
||||
end
|
||||
end
|
||||
|
||||
def fluid_layout
|
||||
current_user && current_user.layout == "fluid"
|
||||
end
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ module ChatMessage
|
|||
end
|
||||
|
||||
def merge_request_message
|
||||
"#{user_combined_name} #{state_or_action_text} #{merge_request_link} in #{project_link}"
|
||||
"#{user_combined_name} #{state_or_action_text} merge request #{merge_request_link} in #{project_link}"
|
||||
end
|
||||
|
||||
def merge_request_link
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
= render_if_exists 'layouts/header/users_over_license_banner'
|
||||
- if Feature.enabled?(:subscribable_banner_license, default_enabled: true)
|
||||
= render_if_exists "layouts/header/ee_subscribable_banner"
|
||||
= render_if_exists "layouts/header/licensed_user_count_threshold"
|
||||
= render "layouts/broadcast"
|
||||
= render "layouts/header/read_only_banner"
|
||||
= render "layouts/nav/classification_level_banner"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,3 @@
|
|||
- if @group && @group.persisted? && @group.path
|
||||
- group_data_attrs = { group_path: j(@group.path), name: j(@group.name), issues_path: issues_group_path(@group), mr_path: merge_requests_group_path(@group) }
|
||||
- if @project && @project.persisted?
|
||||
- project_data_attrs = { project_path: j(@project.path), name: j(@project.name), issues_path: project_issues_path(@project), mr_path: project_merge_requests_path(@project), issues_disabled: !@project.issues_enabled? }
|
||||
.search.search-form{ data: { track_label: "navbar_search", track_event: "activate_form_input", track_value: "" } }
|
||||
= form_tag search_path, method: :get, class: 'form-inline' do |f|
|
||||
.search-input-container
|
||||
|
|
@ -27,27 +23,20 @@
|
|||
= sprite_icon('search', size: 16, css_class: 'search-icon')
|
||||
= sprite_icon('close', size: 16, css_class: 'clear-icon js-clear-input')
|
||||
|
||||
= hidden_field_tag :group_id, @group.try(:id), class: 'js-search-group-options', data: group_data_attrs
|
||||
= hidden_field_tag :group_id, search_context.for_group? ? search_context.group.id : '', class: 'js-search-group-options', data: search_context.group_metadata
|
||||
= hidden_field_tag :project_id, search_context.for_project? ? search_context.project.id : '', id: 'search_project_id', class: 'js-search-project-options', data: search_context.project_metadata
|
||||
|
||||
= hidden_field_tag :project_id, @project && @project.persisted? ? @project.id : '', id: 'search_project_id', class: 'js-search-project-options', data: project_data_attrs
|
||||
- if search_context.for_project?
|
||||
= hidden_field_tag :scope, search_context.scope
|
||||
= hidden_field_tag :search_code, search_context.code_search?
|
||||
|
||||
- if @project && @project.persisted?
|
||||
- if current_controller?(:issues)
|
||||
= hidden_field_tag :scope, 'issues'
|
||||
- elsif current_controller?(:merge_requests)
|
||||
= hidden_field_tag :scope, 'merge_requests'
|
||||
- elsif current_controller?(:wikis)
|
||||
= hidden_field_tag :scope, 'wiki_blobs'
|
||||
- elsif current_controller?(:commits)
|
||||
= hidden_field_tag :scope, 'commits'
|
||||
- else
|
||||
= hidden_field_tag :search_code, true
|
||||
|
||||
- if @snippet || @snippets
|
||||
= hidden_field_tag :snippets, true
|
||||
= hidden_field_tag :repository_ref, @ref
|
||||
= hidden_field_tag :snippets, search_context.for_snippets?
|
||||
= hidden_field_tag :repository_ref, search_context.ref
|
||||
= hidden_field_tag :nav_source, 'navbar'
|
||||
|
||||
-# workaround for non-JS feature specs, see spec/support/helpers/search_helpers.rb
|
||||
- if ENV['RAILS_ENV'] == 'test'
|
||||
%noscript= button_tag 'Search'
|
||||
.search-autocomplete-opts.hide{ :'data-autocomplete-path' => search_autocomplete_path, :'data-autocomplete-project-id' => @project.try(:id), :'data-autocomplete-project-ref' => @ref }
|
||||
.search-autocomplete-opts.hide{ :'data-autocomplete-path' => search_autocomplete_path,
|
||||
:'data-autocomplete-project-id' => search_context.project.try(:id),
|
||||
:'data-autocomplete-project-ref' => search_context.ref }
|
||||
|
|
|
|||
|
|
@ -1,9 +1,3 @@
|
|||
- if project
|
||||
- search_path_url = search_path(project_id: project.id)
|
||||
- elsif group
|
||||
- search_path_url = search_path(group_id: group.id)
|
||||
- else
|
||||
- search_path_url = search_path
|
||||
- has_impersonation_link = header_link?(:admin_impersonation)
|
||||
|
||||
%header.navbar.navbar-gitlab.navbar-expand-sm.js-navbar{ data: { qa_selector: 'navbar' } }
|
||||
|
|
@ -36,7 +30,7 @@
|
|||
%li.nav-item.d-none.d-lg-block.m-auto
|
||||
= render 'layouts/search' unless current_controller?(:search)
|
||||
%li.nav-item.d-inline-block.d-lg-none
|
||||
= link_to search_path_url, title: _('Search'), aria: { label: _('Search') }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
|
||||
= link_to search_context.search_url, title: _('Search'), aria: { label: _('Search') }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
|
||||
= sprite_icon('search', size: 16)
|
||||
- if header_link?(:issues)
|
||||
= nav_link(path: 'dashboard#issues', html_options: { class: "user-counter" }) do
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add explicit mention of Merge request in Slack message
|
||||
merge_request: 33152
|
||||
author:
|
||||
type: changed
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Enable the `in this group` action in the Search dropdown
|
||||
merge_request: 31939
|
||||
author:
|
||||
type: changed
|
||||
|
|
@ -142,7 +142,8 @@ third party ports for other languages like JavaScript, Python, Ruby, and so on.
|
|||
|
||||
The `terraform` report obtains a Terraform `tfplan.json` file. [JQ processing required to remove creds](../../user/infrastructure/index.md#output-terraform-plan-information-into-a-merge-request). The collected Terraform
|
||||
plan report will be uploaded to GitLab as an artifact and will be automatically shown
|
||||
in merge requests.
|
||||
in merge requests. For more information, see
|
||||
[Output `terraform plan` information into a merge request](../../user/infrastructure/index.md#output-terraform-plan-information-into-a-merge-request).
|
||||
|
||||
#### `artifacts:reports:codequality` **(STARTER)**
|
||||
|
||||
|
|
|
|||
|
|
@ -317,43 +317,43 @@ On GitLab.com, we have DangerBot setup to monitor Telemetry related files and Da
|
|||
| `license_trial` | | | |
|
||||
| `assignee_lists` | `counts` | | |
|
||||
| `boards` | `counts` | | |
|
||||
| `ci_builds` | `counts` | | |
|
||||
| `ci_internal_pipelines` | `counts` | | |
|
||||
| `ci_external_pipelines` | `counts` | | |
|
||||
| `ci_pipeline_config_auto_devops` | `counts` | | |
|
||||
| `ci_pipeline_config_repository` | `counts` | | |
|
||||
| `ci_runners` | `counts` | | |
|
||||
| `ci_triggers` | `counts` | | |
|
||||
| `ci_pipeline_schedules` | `counts` | | |
|
||||
| `auto_devops_enabled` | `counts` | | |
|
||||
| `auto_devops_disabled` | `counts` | | |
|
||||
| `ci_builds` | `counts` | `verify` | Unique builds in project |
|
||||
| `ci_internal_pipelines` | `counts` | `verify` | Total pipelines in GitLab repositories |
|
||||
| `ci_external_pipelines` | `counts` | `verify` | Total pipelines in external repositories |
|
||||
| `ci_pipeline_config_auto_devops` | `counts` | `verify` | Total pipelines from an Auto DevOps template |
|
||||
| `ci_pipeline_config_repository` | `counts` | `verify` | Total Pipelines from templates in repository |
|
||||
| `ci_runners` | `counts` | `verify` | Total configured Runners in project |
|
||||
| `ci_triggers` | `counts` | `verify` | Total configured Triggers in project |
|
||||
| `ci_pipeline_schedules` | `counts` | `verify` | Pipeline schedules in GitLab |
|
||||
| `auto_devops_enabled` | `counts` |`configure` | Projects with Auto DevOps template enabled |
|
||||
| `auto_devops_disabled` | `counts` |`configure` | Projects with Auto DevOps template disabled |
|
||||
| `deploy_keys` | `counts` | | |
|
||||
| `deployments` | `counts` | | |
|
||||
| `deployments` | `counts` |`release` | Total deployments |
|
||||
| `dast_jobs` | `counts` | | |
|
||||
| `successful_deployments` | `counts` | | |
|
||||
| `failed_deployments` | `counts` | | |
|
||||
| `environments` | `counts` | | |
|
||||
| `clusters` | `counts` | | |
|
||||
| `clusters_enabled` | `counts` | | |
|
||||
| `project_clusters_enabled` | `counts` | | |
|
||||
| `group_clusters_enabled` | `counts` | | |
|
||||
| `instance_clusters_enabled` | `counts` | | |
|
||||
| `clusters_disabled` | `counts` | | |
|
||||
| `project_clusters_disabled` | `counts` | | |
|
||||
| `group_clusters_disabled` | `counts` | | |
|
||||
| `instance_clusters_disabled` | `counts` | | |
|
||||
| `clusters_platforms_eks` | `counts` | | |
|
||||
| `clusters_platforms_gke` | `counts` | | |
|
||||
| `clusters_platforms_user` | `counts` | | |
|
||||
| `clusters_applications_helm` | `counts` | | |
|
||||
| `clusters_applications_ingress` | `counts` | | |
|
||||
| `clusters_applications_cert_managers` | `counts` | | |
|
||||
| `clusters_applications_crossplane` | `counts` | | |
|
||||
| `clusters_applications_prometheus` | `counts` | | |
|
||||
| `clusters_applications_runner` | `counts` | | |
|
||||
| `clusters_applications_knative` | `counts` | | |
|
||||
| `clusters_applications_elastic_stack` | `counts` | | |
|
||||
| `clusters_management_project` | `counts` | | |
|
||||
| `successful_deployments` | `counts` |`release` | Total successful deployments |
|
||||
| `failed_deployments` | `counts` |`release` | Total failed deployments |
|
||||
| `environments` | `counts` |`release` | Total available and stopped environments |
|
||||
| `clusters` | `counts` |`configure` | Total GitLab Managed clusters both enabled and disabled |
|
||||
| `clusters_enabled` | `counts` |`configure` | Total GitLab Managed clusters currently enabled |
|
||||
| `project_clusters_enabled` | `counts` |`configure` | Total GitLab Managed clusters attached to projects|
|
||||
| `group_clusters_enabled` | `counts` |`configure` | Total GitLab Managed clusters attached to groups |
|
||||
| `instance_clusters_enabled` | `counts` |`configure` | Total GitLab Managed clusters attached to the instance |
|
||||
| `clusters_disabled` | `counts` |`configure` | Total GitLab Managed disabled clusters |
|
||||
| `project_clusters_disabled` | `counts` |`configure` | Total GitLab Managed disabled clusters previously attached to projects |
|
||||
| `group_clusters_disabled` | `counts` |`configure` | Total GitLab Managed disabled clusters previously attached to groups |
|
||||
| `instance_clusters_disabled` | `counts` |`configure` | Total GitLab Managed disabled clusters previously attached to the instance |
|
||||
| `clusters_platforms_eks` | `counts` |`configure` | Total GitLab Managed clusters provisioned with GitLab on AWS EKS |
|
||||
| `clusters_platforms_gke` | `counts` |`configure` | Total GitLab Managed clusters provisioned with GitLab on GCE GKE |
|
||||
| `clusters_platforms_user` | `counts` |`configure` | Total GitLab Managed clusters that are user provisioned |
|
||||
| `clusters_applications_helm` | `counts` |`configure` | Total GitLab Managed clusters with Helm enabled |
|
||||
| `clusters_applications_ingress` | `counts` |`configure` | Total GitLab Managed clusters with Ingress enabled |
|
||||
| `clusters_applications_cert_managers` | `counts` |`configure` | Total GitLab Managed clusters with Cert Manager enabled |
|
||||
| `clusters_applications_crossplane` | `counts` |`configure` | Total GitLab Managed clusters with Crossplane enabled |
|
||||
| `clusters_applications_prometheus` | `counts` |`configure` | Total GitLab Managed clusters with Prometheus enabled |
|
||||
| `clusters_applications_runner` | `counts` |`configure` | Total GitLab Managed clusters with Runner enabled |
|
||||
| `clusters_applications_knative` | `counts` |`configure` | Total GitLab Managed clusters with Knative enabled |
|
||||
| `clusters_applications_elastic_stack` | `counts` |`configure` | Total GitLab Managed clusters with Elastic Stack enabled |
|
||||
| `clusters_management_project` | `counts` |`configure` | Total GitLab Managed clusters with defined cluster management project |
|
||||
| `in_review_folder` | `counts` | | |
|
||||
| `grafana_integrated_projects` | `counts` | | |
|
||||
| `groups` | `counts` | | |
|
||||
|
|
@ -368,14 +368,14 @@ On GitLab.com, we have DangerBot setup to monitor Telemetry related files and Da
|
|||
| `lfs_objects` | `counts` | | |
|
||||
| `milestone_lists` | `counts` | | |
|
||||
| `milestones` | `counts` | | |
|
||||
| `pages_domains` | `counts` | | |
|
||||
| `pages_domains` | `counts` |`release` | Total GitLab Pages domains |
|
||||
| `pool_repositories` | `counts` | | |
|
||||
| `projects` | `counts` | | |
|
||||
| `projects_imported_from_github` | `counts` | | |
|
||||
| `projects_with_repositories_enabled` | `counts` | | |
|
||||
| `projects_with_error_tracking_enabled` | `counts` | | |
|
||||
| `protected_branches` | `counts` | | |
|
||||
| `releases` | `counts` | | |
|
||||
| `releases` | `counts` |`release` | Unique release tags |
|
||||
| `remote_mirrors` | `counts` | | |
|
||||
| `requirements_created` | `counts` | | |
|
||||
| `snippets` | `counts` | | |
|
||||
|
|
@ -466,22 +466,22 @@ On GitLab.com, we have DangerBot setup to monitor Telemetry related files and Da
|
|||
| `ldap_users` | `counts` | | |
|
||||
| `pod_logs_usages_total` | `counts` | | |
|
||||
| `projects_enforcing_code_owner_approval` | `counts` | | |
|
||||
| `projects_mirrored_with_pipelines_enabled` | `counts` | | |
|
||||
| `projects_reporting_ci_cd_back_to_github` | `counts` | | |
|
||||
| `projects_with_packages` | `counts` | | |
|
||||
| `projects_with_prometheus_alerts` | `counts` | | |
|
||||
| `projects_with_tracing_enabled` | `counts` | | |
|
||||
| `projects_with_alerts_service_enabled` | `counts` | | |
|
||||
| `projects_mirrored_with_pipelines_enabled` | `counts` |`release` | Projects with repository mirroring enabled |
|
||||
| `projects_reporting_ci_cd_back_to_github` | `counts` |`verify` | Projects with a GitHub service pipeline enabled |
|
||||
| `projects_with_packages` | `counts` |`package` | Projects with package registry configured |
|
||||
| `projects_with_prometheus_alerts` | `counts` |`monitor` | Projects with Promethus alerting enabled |
|
||||
| `projects_with_tracing_enabled` | `counts` |`monitor` | Projects with tracing enabled |
|
||||
| `projects_with_alerts_service_enabled` | `counts` |`monitor` | Projects with alerting service enabled |
|
||||
| `template_repositories` | `counts` | | |
|
||||
| `container_scanning_jobs` | `counts` | | |
|
||||
| `dependency_scanning_jobs` | `counts` | | |
|
||||
| `license_management_jobs` | `counts` | | |
|
||||
| `sast_jobs` | `counts` | | |
|
||||
| `status_page_projects` | `counts` | `monitor` | |
|
||||
| `status_page_issues` | `counts` | `monitor` | |
|
||||
| `status_page_projects` | `counts` | `monitor` | Projects with status page enabled |
|
||||
| `status_page_issues` | `counts` | `monitor` | Issues published to a Status Page |
|
||||
| `epics_deepest_relationship_level` | `counts` | | |
|
||||
| `operations_dashboard_default_dashboard` | `counts` | | |
|
||||
| `operations_dashboard_users_with_projects_added` | `counts` | | |
|
||||
| `operations_dashboard_default_dashboard` | `counts` | `monitor` | Active users with enabled operations dashboard |
|
||||
| `operations_dashboard_users_with_projects_added` | `counts` | `monitor` | Active users with projects on operations dashboard|
|
||||
| `container_registry_enabled` | | | |
|
||||
| `dependency_proxy_enabled` | | | |
|
||||
| `gitlab_shared_runners_enabled` | | | |
|
||||
|
|
@ -507,47 +507,47 @@ On GitLab.com, we have DangerBot setup to monitor Telemetry related files and Da
|
|||
| `sd` | `avg_cycle_analytics - production` | | |
|
||||
| `missing` | `avg_cycle_analytics - production` | | |
|
||||
| `total` | `avg_cycle_analytics` | | |
|
||||
| `clusters_applications_cert_managers` | `usage_activity_by_stage` | `configure` | |
|
||||
| `clusters_applications_helm` | `usage_activity_by_stage` | `configure` | |
|
||||
| `clusters_applications_ingress` | `usage_activity_by_stage` | `configure` | |
|
||||
| `clusters_applications_knative` | `usage_activity_by_stage` | `configure` | |
|
||||
| `clusters_management_project` | `usage_activity_by_stage` | `configure` | |
|
||||
| `clusters_disabled` | `usage_activity_by_stage` | `configure` | |
|
||||
| `clusters_enabled` | `usage_activity_by_stage` | `configure` | |
|
||||
| `clusters_platforms_gke` | `usage_activity_by_stage` | `configure` | |
|
||||
| `clusters_platforms_eks` | `usage_activity_by_stage` | `configure` | |
|
||||
| `clusters_platforms_user` | `usage_activity_by_stage` | `configure` | |
|
||||
| `instance_clusters_disabled` | `usage_activity_by_stage` | `configure` | |
|
||||
| `instance_clusters_enabled` | `usage_activity_by_stage` | `configure` | |
|
||||
| `group_clusters_disabled` | `usage_activity_by_stage` | `configure` | |
|
||||
| `group_clusters_enabled` | `usage_activity_by_stage` | `configure` | |
|
||||
| `project_clusters_disabled` | `usage_activity_by_stage` | `configure` | |
|
||||
| `project_clusters_enabled` | `usage_activity_by_stage` | `configure` | |
|
||||
| `projects_slack_notifications_active` | `usage_activity_by_stage` | `configure` | |
|
||||
| `projects_slack_slash_active` | `usage_activity_by_stage` | `configure` | |
|
||||
| `projects_with_prometheus_alerts: 0` | `usage_activity_by_stage` | `configure` | |
|
||||
| `clusters_applications_cert_managers` | `usage_activity_by_stage` | `configure` | Unique clusters with certificate managers enabled |
|
||||
| `clusters_applications_helm` | `usage_activity_by_stage` | `configure` | Unique clusters with Helm enabled |
|
||||
| `clusters_applications_ingress` | `usage_activity_by_stage` | `configure` | Unique clusters with Ingress enabled |
|
||||
| `clusters_applications_knative` | `usage_activity_by_stage` | `configure` | Unique clusters with Knative enabled |
|
||||
| `clusters_management_project` | `usage_activity_by_stage` | `configure` | Unique clusters with project management enabled |
|
||||
| `clusters_disabled` | `usage_activity_by_stage` | `configure` | Total non-"GitLab Managed clusters" |
|
||||
| `clusters_enabled` | `usage_activity_by_stage` | `configure` | Total GitLab Managed clusters |
|
||||
| `clusters_platforms_gke` | `usage_activity_by_stage` | `configure` | Unique clusters with Google Cloud installed |
|
||||
| `clusters_platforms_eks` | `usage_activity_by_stage` | `configure` | Unique clusters with AWS installed |
|
||||
| `clusters_platforms_user` | `usage_activity_by_stage` | `configure` | Unique clusters that are user provided |
|
||||
| `instance_clusters_disabled` | `usage_activity_by_stage` | `configure` | Unique clusters disabled on instance |
|
||||
| `instance_clusters_enabled` | `usage_activity_by_stage` | `configure` | Unique clusters enabled on instance |
|
||||
| `group_clusters_disabled` | `usage_activity_by_stage` | `configure` | Unique clusters disabled on group |
|
||||
| `group_clusters_enabled` | `usage_activity_by_stage` | `configure` | Unique clusters enabled on group |
|
||||
| `project_clusters_disabled` | `usage_activity_by_stage` | `configure` | Unique clusters disabled on project |
|
||||
| `project_clusters_enabled` | `usage_activity_by_stage` | `configure` | Unique clusters enabled on project |
|
||||
| `projects_slack_notifications_active` | `usage_activity_by_stage` | `configure` | Unique projects with Slack service enabled |
|
||||
| `projects_slack_slash_active` | `usage_activity_by_stage` | `configure` | Unique projects with Slack '/' commands enabled |
|
||||
| `projects_with_prometheus_alerts: 0` | `usage_activity_by_stage` | `monitor` | Projects with Promethus enabled and no alerts |
|
||||
| `deploy_keys` | `usage_activity_by_stage` | `create` | |
|
||||
| `keys` | `usage_activity_by_stage` | `create` | |
|
||||
| `projects_jira_dvcs_server_active` | `usage_activity_by_stage` | `plan` | |
|
||||
| `service_desk_enabled_projects` | `usage_activity_by_stage` | `plan` | |
|
||||
| `service_desk_issues` | `usage_activity_by_stage` | `plan` | |
|
||||
| `todos: 0` | `usage_activity_by_stage` | `plan` | |
|
||||
| `deployments` | `usage_activity_by_stage` | `release` | |
|
||||
| `failed_deployments` | `usage_activity_by_stage` | `release` | |
|
||||
| `projects_mirrored_with_pipelines_enabled` | `usage_activity_by_stage` | `release` | |
|
||||
| `releases` | `usage_activity_by_stage` | `release` | |
|
||||
| `successful_deployments: 0` | `usage_activity_by_stage` | `release` | |
|
||||
| `deployments` | `usage_activity_by_stage` | `release` | Total deployments |
|
||||
| `failed_deployments` | `usage_activity_by_stage` | `release` | Total failed deployments |
|
||||
| `projects_mirrored_with_pipelines_enabled` | `usage_activity_by_stage` | `release` | Projects with repository mirroring enabled |
|
||||
| `releases` | `usage_activity_by_stage` | `release` | Unique release tags in project |
|
||||
| `successful_deployments: 0` | `usage_activity_by_stage` | `release` | Total successful deployments |
|
||||
| `user_preferences_group_overview_security_dashboard: 0` | `usage_activity_by_stage` | `secure` | |
|
||||
| `ci_builds` | `usage_activity_by_stage` | `verify` | |
|
||||
| `ci_external_pipelines` | `usage_activity_by_stage` | `verify` | |
|
||||
| `ci_internal_pipelines` | `usage_activity_by_stage` | `verify` | |
|
||||
| `ci_pipeline_config_auto_devops` | `usage_activity_by_stage` | `verify` | |
|
||||
| `ci_pipeline_config_repository` | `usage_activity_by_stage` | `verify` | |
|
||||
| `ci_pipeline_schedules` | `usage_activity_by_stage` | `verify` | |
|
||||
| `ci_pipelines` | `usage_activity_by_stage` | `verify` | |
|
||||
| `ci_triggers` | `usage_activity_by_stage` | `verify` | |
|
||||
| `clusters_applications_runner` | `usage_activity_by_stage` | `verify` | |
|
||||
| `projects_reporting_ci_cd_back_to_github: 0` | `usage_activity_by_stage` | `verify` | |
|
||||
| `ci_builds` | `usage_activity_by_stage` | `verify` | Unique builds in project |
|
||||
| `ci_external_pipelines` | `usage_activity_by_stage` | `verify` | Total pipelines in external repositories |
|
||||
| `ci_internal_pipelines` | `usage_activity_by_stage` | `verify` | Total pipelines in GitLab repositories |
|
||||
| `ci_pipeline_config_auto_devops` | `usage_activity_by_stage` | `verify` | Total pipelines from an Auto DevOps template |
|
||||
| `ci_pipeline_config_repository` | `usage_activity_by_stage` | `verify` | Pipelines from templates in repository |
|
||||
| `ci_pipeline_schedules` | `usage_activity_by_stage` | `verify` | Pipeline schedules in GitLab |
|
||||
| `ci_pipelines` | `usage_activity_by_stage` | `verify` | Total pipelines |
|
||||
| `ci_triggers` | `usage_activity_by_stage` | `verify` | Triggers enabled |
|
||||
| `clusters_applications_runner` | `usage_activity_by_stage` | `verify` | Unique clusters with Runner enabled |
|
||||
| `projects_reporting_ci_cd_back_to_github: 0` | `usage_activity_by_stage` | `verify` | Unique projects with a GitHub pipeline enabled |
|
||||
|
||||
## Example Usage Ping payload
|
||||
|
||||
|
|
|
|||
|
|
@ -134,7 +134,7 @@ Make sure you have the right version of Git installed:
|
|||
# Install Git
|
||||
sudo apt-get install -y git-core
|
||||
|
||||
# Make sure Git is version 2.26.2 or higher (minimal supported version is 2.22.0)
|
||||
# Make sure Git is version 2.26.2 or higher (minimal supported version is 2.24.0)
|
||||
git --version
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -50,11 +50,11 @@ needs several Gems that have native extensions.
|
|||
|
||||
### Go versions
|
||||
|
||||
The minimum required Go version is 1.12.
|
||||
The minimum required Go version is 1.13.
|
||||
|
||||
### Git versions
|
||||
|
||||
GitLab 11.11 and higher only supports Git 2.21.x and newer, and
|
||||
GitLab 11.11 and higher only supports Git 2.24.x and newer, and
|
||||
[dropped support for older versions](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/54255).
|
||||
|
||||
### Node.js versions
|
||||
|
|
|
|||
|
|
@ -192,6 +192,16 @@ possible.
|
|||
|
||||
## Version specific upgrading instructions
|
||||
|
||||
### 13.1.0
|
||||
|
||||
In 13.1.0, you must upgrade to either:
|
||||
|
||||
- At least Git v2.24 (previously, the minimum required version was Git v2.22).
|
||||
- The recommended Git v2.26.
|
||||
|
||||
Failure to do so will result in internal errors in the Gitaly service in some RPCs due
|
||||
to the use of the new `--end-of-options` Git flag.
|
||||
|
||||
### 12.2.0
|
||||
|
||||
In 12.2.0, we enabled Rails' authenticated cookie encryption. Old sessions are
|
||||
|
|
|
|||
|
|
@ -122,12 +122,17 @@ rm go1.13.5.linux-amd64.tar.gz
|
|||
|
||||
### 6. Update Git
|
||||
|
||||
NOTE: To check the minimum required Git version, see [Git versions](../install/requirements.md#git-versions).
|
||||
CAUTION: **Caution:**
|
||||
From GitLab 13.1, you must use at least Git v2.24 (previous minimum version was v2.22).
|
||||
Git v2.26 is recommended.
|
||||
|
||||
To check you are running the minimum required Git version, see
|
||||
[Git versions](../install/requirements.md#git-versions).
|
||||
|
||||
In Debian or Ubuntu:
|
||||
|
||||
```shell
|
||||
# Make sure Git is version 2.21.0 or higher
|
||||
# Make sure Git is version 2.24.0 or higher
|
||||
git --version
|
||||
|
||||
# Remove packaged Git
|
||||
|
|
@ -147,9 +152,9 @@ make install
|
|||
|
||||
# Download and compile from source
|
||||
cd /tmp
|
||||
curl --remote-name --location --progress https://www.kernel.org/pub/software/scm/git/git-2.21.0.tar.gz
|
||||
echo '85eca51c7404da75e353eba587f87fea9481ba41e162206a6f70ad8118147bee git-2.21.0.tar.gz' | shasum -a256 -c - && tar -xzf git-2.21.0.tar.gz
|
||||
cd git-2.21.0/
|
||||
curl --remote-name --location --progress https://www.kernel.org/pub/software/scm/git/git-2.26.0.tar.gz
|
||||
echo 'aa168c2318e7187cd295a645f7370cc6d71a324aafc932f80f00c780b6a26bed git-2.26.0.tar.gz' | shasum -a256 -c - && tar -xzf git-2.26.0.tar.gz
|
||||
cd git-2.26.0/
|
||||
./configure --with-libpcre
|
||||
make prefix=/usr/local all
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,162 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Gitlab
|
||||
# Holds the contextual data used by navbar search component to
|
||||
# determine the search scope, whether to search for code, or if
|
||||
# a search should target snippets.
|
||||
#
|
||||
# Use the SearchContext::Builder to create an instance of this class
|
||||
class SearchContext
|
||||
attr_accessor :project, :project_metadata, :ref,
|
||||
:group, :group_metadata,
|
||||
:snippets,
|
||||
:scope, :search_url
|
||||
|
||||
def initialize
|
||||
@ref = nil
|
||||
@project = nil
|
||||
@project_metadata = {}
|
||||
@group = nil
|
||||
@group_metadata = {}
|
||||
@snippets = []
|
||||
@scope = nil
|
||||
@search_url = nil
|
||||
end
|
||||
|
||||
def for_project?
|
||||
project.present? && project.persisted?
|
||||
end
|
||||
|
||||
def for_group?
|
||||
group.present? && group.persisted?
|
||||
end
|
||||
|
||||
def for_snippets?
|
||||
snippets.any?
|
||||
end
|
||||
|
||||
def code_search?
|
||||
project.present? && scope.nil?
|
||||
end
|
||||
|
||||
class Builder
|
||||
def initialize(view_context)
|
||||
@view_context = view_context
|
||||
@snippets = []
|
||||
end
|
||||
|
||||
def with_snippet(snippet)
|
||||
@snippets << snippet
|
||||
|
||||
self
|
||||
end
|
||||
|
||||
def with_project(project)
|
||||
@project = project
|
||||
with_group(project&.group)
|
||||
|
||||
self
|
||||
end
|
||||
|
||||
def with_group(group)
|
||||
@group = group
|
||||
|
||||
self
|
||||
end
|
||||
|
||||
def with_ref(ref)
|
||||
@ref = ref
|
||||
|
||||
self
|
||||
end
|
||||
|
||||
def build!
|
||||
SearchContext.new.tap do |context|
|
||||
context.project = @project
|
||||
context.group = @group
|
||||
context.ref = @ref
|
||||
context.snippets = @snippets.dup
|
||||
context.scope = search_scope
|
||||
context.search_url = search_url
|
||||
context.group_metadata = group_search_metadata(@group)
|
||||
context.project_metadata = project_search_metadata(@project)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_accessor :view_context
|
||||
|
||||
def project_search_metadata(project)
|
||||
return {} unless project
|
||||
|
||||
{
|
||||
project_path: project.path,
|
||||
name: project.name,
|
||||
issues_path: view_context.project_issues_path(project),
|
||||
mr_path: view_context.project_merge_requests_path(project),
|
||||
issues_disabled: !project.issues_enabled?
|
||||
}
|
||||
end
|
||||
|
||||
def group_search_metadata(group)
|
||||
return {} unless group
|
||||
|
||||
{
|
||||
group_path: group.path,
|
||||
name: group.name,
|
||||
issues_path: view_context.issues_group_path(group),
|
||||
mr_path: view_context.merge_requests_group_path(group)
|
||||
}
|
||||
end
|
||||
|
||||
def search_url
|
||||
if @project.present?
|
||||
view_context.search_path(project_id: @project.id)
|
||||
elsif @group.present?
|
||||
view_context.search_path(group_id: @group.id)
|
||||
else
|
||||
view_context.search_path
|
||||
end
|
||||
end
|
||||
|
||||
def search_scope
|
||||
if view_context.current_controller?(:issues)
|
||||
'issues'
|
||||
elsif view_context.current_controller?(:merge_requests)
|
||||
'merge_requests'
|
||||
elsif view_context.current_controller?(:wikis)
|
||||
'wiki_blobs'
|
||||
elsif view_context.current_controller?(:commits)
|
||||
'commits'
|
||||
else nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module ControllerConcern
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
helper_method :search_context
|
||||
end
|
||||
|
||||
# rubocop:disable Gitlab/ModuleWithInstanceVariables
|
||||
#
|
||||
# Introspect the current controller's assignments and
|
||||
# and builds the proper SearchContext object for it.
|
||||
def search_context
|
||||
builder = Builder.new(view_context)
|
||||
|
||||
builder.with_snippet(@snippet) if @snippet.present?
|
||||
@snippets.each(&builder.method(:with_snippet)) if @snippets.present?
|
||||
builder.with_project(@project) if @project.present? && @project.persisted?
|
||||
builder.with_group(@group) if @group.present? && @group.persisted?
|
||||
builder.with_ref(@ref) if @ref.present?
|
||||
|
||||
builder.build!
|
||||
end
|
||||
# rubocop:enable Gitlab/ModuleWithInstanceVariables
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -14300,6 +14300,9 @@ msgstr ""
|
|||
msgid "NetworkPolicies|Environment does not have deployment platform"
|
||||
msgstr ""
|
||||
|
||||
msgid "NetworkPolicies|If you are using Auto DevOps, your %{monospacedStart}auto-deploy-values.yaml%{monospacedEnd} file will not be updated if you change a policy in this section. Auto DevOps users should make changes by following the %{linkStart}Container Network Policy documentation%{linkEnd}."
|
||||
msgstr ""
|
||||
|
||||
msgid "NetworkPolicies|Invalid or empty policy"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -14315,7 +14318,7 @@ msgstr ""
|
|||
msgid "NetworkPolicies|No policies detected"
|
||||
msgstr ""
|
||||
|
||||
msgid "NetworkPolicies|Policies are a specification of how groups of pods are allowed to communicate with each other network endpoints."
|
||||
msgid "NetworkPolicies|Policies are a specification of how groups of pods are allowed to communicate with each other's network endpoints."
|
||||
msgstr ""
|
||||
|
||||
msgid "NetworkPolicies|Policy %{policyName} was successfully changed"
|
||||
|
|
@ -19086,10 +19089,10 @@ msgstr ""
|
|||
msgid "SearchAutocomplete|in all GitLab"
|
||||
msgstr ""
|
||||
|
||||
msgid "SearchAutocomplete|in this group"
|
||||
msgid "SearchAutocomplete|in group %{groupName}"
|
||||
msgstr ""
|
||||
|
||||
msgid "SearchAutocomplete|in this project"
|
||||
msgid "SearchAutocomplete|in project %{projectName}"
|
||||
msgstr ""
|
||||
|
||||
msgid "SearchCodeResults|in"
|
||||
|
|
@ -24477,6 +24480,9 @@ msgstr ""
|
|||
msgid "View the performance dashboard at"
|
||||
msgstr ""
|
||||
|
||||
msgid "View users statistics"
|
||||
msgstr ""
|
||||
|
||||
msgid "Viewing commit"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -25688,6 +25694,12 @@ msgstr ""
|
|||
msgid "Your groups"
|
||||
msgstr ""
|
||||
|
||||
msgid "Your instance has %{remaining_user_count} users remaining of the %{total_user_count} included in your subscription. You can add more users than the number included in your license, and we will include the overage in your next bill."
|
||||
msgstr ""
|
||||
|
||||
msgid "Your instance is approaching its licensed user count"
|
||||
msgstr ""
|
||||
|
||||
msgid "Your issues are being imported. Once finished, you'll get a confirmation email."
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -332,8 +332,7 @@ describe Projects::IssuesController do
|
|||
end
|
||||
|
||||
before do
|
||||
allow(controller).to receive(:find_routable!)
|
||||
.with(Project, project.full_path, any_args).and_return(project)
|
||||
allow(controller).to receive(:find_routable!).and_return(project)
|
||||
allow(project).to receive(:default_branch).and_return(master_branch)
|
||||
allow_next_instance_of(Issues::RelatedBranchesService) do |service|
|
||||
allow(service).to receive(:execute).and_return(related_branches)
|
||||
|
|
|
|||
|
|
@ -95,14 +95,6 @@ describe 'User uses header search field', :js do
|
|||
|
||||
expect(page).not_to have_selector('.dropdown-header', text: /#{scope_name}/i)
|
||||
end
|
||||
|
||||
it 'hides the dropdown when there are no results' do
|
||||
page.within('.search-input-wrap') do
|
||||
fill_in('search', with: 'a_search_term_with_no_results')
|
||||
end
|
||||
|
||||
expect(page).not_to have_selector('.dropdown-menu')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -278,7 +278,7 @@ describe ApplicationHelper do
|
|||
page: 'application',
|
||||
page_type_id: nil,
|
||||
find_file: nil,
|
||||
group: ''
|
||||
group: nil
|
||||
}
|
||||
)
|
||||
end
|
||||
|
|
@ -317,7 +317,7 @@ describe ApplicationHelper do
|
|||
page: 'application',
|
||||
page_type_id: nil,
|
||||
find_file: nil,
|
||||
group: '',
|
||||
group: nil,
|
||||
project_id: project.id,
|
||||
project: project.name,
|
||||
namespace_id: project.namespace.id
|
||||
|
|
@ -325,6 +325,25 @@ describe ApplicationHelper do
|
|||
)
|
||||
end
|
||||
|
||||
context 'when @project is owned by a group' do
|
||||
let_it_be(:project) { create(:project, :repository, group: create(:group)) }
|
||||
|
||||
it 'includes all possible body data elements and associates the project elements with project' do
|
||||
expect(helper).to receive(:can?).with(nil, :download_code, project)
|
||||
expect(helper.body_data).to eq(
|
||||
{
|
||||
page: 'application',
|
||||
page_type_id: nil,
|
||||
find_file: nil,
|
||||
group: project.group.name,
|
||||
project_id: project.id,
|
||||
project: project.name,
|
||||
namespace_id: project.namespace.id
|
||||
}
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when controller is issues' do
|
||||
before do
|
||||
stub_controller_method(:controller_path, 'projects:issues')
|
||||
|
|
@ -342,7 +361,7 @@ describe ApplicationHelper do
|
|||
page: 'projects:issues:show',
|
||||
page_type_id: issue.id,
|
||||
find_file: nil,
|
||||
group: '',
|
||||
group: nil,
|
||||
project_id: issue.project.id,
|
||||
project: issue.project.name,
|
||||
namespace_id: issue.project.namespace.id
|
||||
|
|
|
|||
|
|
@ -117,4 +117,19 @@ describe PageLayoutHelper do
|
|||
expect(tags).to include(%q{content="foo" http-equiv="refresh"})
|
||||
end
|
||||
end
|
||||
|
||||
describe '#search_context' do
|
||||
subject(:search_context) { helper.search_context }
|
||||
|
||||
describe 'a bare controller' do
|
||||
it 'returns an empty context' do
|
||||
expect(search_context).to have_attributes(project: nil,
|
||||
group: nil,
|
||||
snippets: [],
|
||||
project_metadata: {},
|
||||
group_metadata: {},
|
||||
search_url: '/search')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,152 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::SearchContext::Builder, type: :controller do
|
||||
controller(ApplicationController) { }
|
||||
|
||||
subject(:builder) { described_class.new(controller.view_context) }
|
||||
|
||||
shared_examples "has a fluid interface" do
|
||||
it { is_expected.to be_instance_of(described_class) }
|
||||
end
|
||||
|
||||
def expected_project_metadata(project)
|
||||
return {} if project.nil?
|
||||
|
||||
a_hash_including(project_path: project.path,
|
||||
name: project.name,
|
||||
issues_path: a_string_including("/issues"),
|
||||
mr_path: a_string_including("/merge_requests"),
|
||||
issues_disabled: !project.issues_enabled?)
|
||||
end
|
||||
|
||||
def expected_group_metadata(group)
|
||||
return {} if group.nil?
|
||||
|
||||
a_hash_including(group_path: group.path,
|
||||
name: group.name,
|
||||
issues_path: a_string_including("/issues"),
|
||||
mr_path: a_string_including("/merge_requests"))
|
||||
end
|
||||
|
||||
def expected_search_url(project, group)
|
||||
if project
|
||||
search_path(project_id: project.id)
|
||||
elsif group
|
||||
search_path(group_id: group.id)
|
||||
else
|
||||
search_path
|
||||
end
|
||||
end
|
||||
|
||||
def be_search_context(project: nil, group: nil, snippets: [], ref: nil)
|
||||
group = project ? project.group : group
|
||||
snippets.compact!
|
||||
ref = ref
|
||||
|
||||
have_attributes(
|
||||
project: project,
|
||||
group: group,
|
||||
ref: ref,
|
||||
snippets: snippets,
|
||||
project_metadata: expected_project_metadata(project),
|
||||
group_metadata: expected_group_metadata(group),
|
||||
search_url: expected_search_url(project, group)
|
||||
)
|
||||
end
|
||||
|
||||
describe '#with_project' do
|
||||
let(:project) { create(:project) }
|
||||
|
||||
subject { builder.with_project(project) }
|
||||
|
||||
it_behaves_like "has a fluid interface"
|
||||
|
||||
describe '#build!' do
|
||||
subject(:context) { builder.with_project(project).build! }
|
||||
|
||||
context 'when a project is not owned by a group' do
|
||||
it { is_expected.to be_for_project }
|
||||
it { is_expected.to be_search_context(project: project) }
|
||||
end
|
||||
|
||||
context 'when a project is owned by a group' do
|
||||
let(:project) { create(:project, group: create(:group)) }
|
||||
|
||||
it 'delegates to `#with_group`' do
|
||||
expect(builder).to receive(:with_group).with(project.group)
|
||||
expect(context).to be
|
||||
end
|
||||
|
||||
it { is_expected.to be_search_context(project: project, group: project.group) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#with_snippet' do
|
||||
context 'when there is a single snippet' do
|
||||
let(:snippet) { create(:snippet) }
|
||||
|
||||
subject { builder.with_snippet(snippet) }
|
||||
|
||||
it_behaves_like "has a fluid interface"
|
||||
|
||||
describe '#build!' do
|
||||
subject(:context) { builder.with_snippet(snippet).build! }
|
||||
|
||||
it { is_expected.to be_for_snippet }
|
||||
it { is_expected.to be_search_context(snippets: [snippet]) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when there are multiple snippets' do
|
||||
let(:snippets) { create_list(:snippet, 3) }
|
||||
|
||||
describe '#build!' do
|
||||
subject(:context) do
|
||||
snippets.each(&builder.method(:with_snippet))
|
||||
builder.build!
|
||||
end
|
||||
|
||||
it { is_expected.to be_for_snippet }
|
||||
it { is_expected.to be_search_context(snippets: snippets) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#with_group' do
|
||||
let(:group) { create(:group) }
|
||||
|
||||
subject { builder.with_group(group) }
|
||||
|
||||
it_behaves_like "has a fluid interface"
|
||||
|
||||
describe '#build!' do
|
||||
subject(:context) { builder.with_group(group).build! }
|
||||
|
||||
it { is_expected.to be_for_group }
|
||||
it { is_expected.to be_search_context(group: group) }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#with_ref' do
|
||||
let(:ref) { Gitlab::Git::EMPTY_TREE_ID }
|
||||
|
||||
subject { builder.with_ref(ref) }
|
||||
|
||||
it_behaves_like "has a fluid interface"
|
||||
|
||||
describe '#build!' do
|
||||
subject(:context) { builder.with_ref(ref).build! }
|
||||
|
||||
it { is_expected.to be_search_context(ref: ref) }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#build!' do
|
||||
subject(:context) { builder.build! }
|
||||
|
||||
it { is_expected.to be_a(Gitlab::SearchContext) }
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::SearchContext::ControllerConcern, type: :controller do
|
||||
controller(ApplicationController) do
|
||||
include Gitlab::SearchContext::ControllerConcern
|
||||
end
|
||||
|
||||
let(:project) { nil }
|
||||
let(:group) { nil }
|
||||
let(:snippet) { nil }
|
||||
let(:snippets) { [] }
|
||||
let(:ref) { nil }
|
||||
|
||||
let(:builder) { Gitlab::SearchContext::Builder.new(controller.view_context) }
|
||||
|
||||
subject(:search_context) { controller.search_context }
|
||||
|
||||
def weak_assign(ivar, value)
|
||||
return if value.nil?
|
||||
|
||||
controller.instance_variable_set(ivar.to_sym, value)
|
||||
end
|
||||
|
||||
before do
|
||||
weak_assign(:@project, project)
|
||||
weak_assign(:@group, group)
|
||||
weak_assign(:@ref, ref)
|
||||
weak_assign(:@snippet, snippet)
|
||||
weak_assign(:@snippets, snippets)
|
||||
|
||||
allow(Gitlab::SearchContext::Builder).to receive(:new).and_return(builder)
|
||||
end
|
||||
|
||||
shared_examples 'has the proper context' do
|
||||
it :aggregate_failures do
|
||||
expected_group = project ? project.group : group
|
||||
expected_snippets = [snippet, *snippets].compact
|
||||
|
||||
expect(builder).to receive(:with_project).with(project).and_call_original if project
|
||||
expect(builder).to receive(:with_group).with(expected_group).and_call_original if expected_group
|
||||
expect(builder).to receive(:with_ref).with(ref).and_call_original if ref
|
||||
expected_snippets.each do |snippet|
|
||||
expect(builder).to receive(:with_snippet).with(snippet).and_call_original
|
||||
end
|
||||
|
||||
is_expected.to be_a(Gitlab::SearchContext)
|
||||
end
|
||||
end
|
||||
|
||||
context 'exposing @project' do
|
||||
let(:project) { create(:project) }
|
||||
|
||||
it_behaves_like 'has the proper context'
|
||||
|
||||
context 'when the project is owned by a group' do
|
||||
let(:project) { create(:project, group: create(:group)) }
|
||||
|
||||
it_behaves_like 'has the proper context'
|
||||
end
|
||||
end
|
||||
|
||||
context 'exposing @group' do
|
||||
let(:group) { create(:group) }
|
||||
|
||||
it_behaves_like 'has the proper context'
|
||||
end
|
||||
|
||||
context 'exposing @snippet, @snippets' do
|
||||
let(:snippet) { create(:snippet) }
|
||||
let(:snippets) { create_list(:snippet, 3) }
|
||||
|
||||
it_behaves_like 'has the proper context'
|
||||
end
|
||||
|
||||
context 'exposing @ref' do
|
||||
let(:ref) { Gitlab::Git::EMPTY_TREE_ID }
|
||||
|
||||
it_behaves_like 'has the proper context'
|
||||
end
|
||||
end
|
||||
|
|
@ -52,7 +52,7 @@ describe ChatMessage::MergeMessage do
|
|||
context 'open' do
|
||||
it 'returns a message regarding opening of merge requests' do
|
||||
expect(subject.pretext).to eq(
|
||||
'Test User (test.user) opened <http://somewhere.com/-/merge_requests/100|!100 *Merge Request title*> in <http://somewhere.com|project_name>')
|
||||
'Test User (test.user) opened merge request <http://somewhere.com/-/merge_requests/100|!100 *Merge Request title*> in <http://somewhere.com|project_name>')
|
||||
expect(subject.attachments).to be_empty
|
||||
end
|
||||
end
|
||||
|
|
@ -63,7 +63,7 @@ describe ChatMessage::MergeMessage do
|
|||
end
|
||||
it 'returns a message regarding closing of merge requests' do
|
||||
expect(subject.pretext).to eq(
|
||||
'Test User (test.user) closed <http://somewhere.com/-/merge_requests/100|!100 *Merge Request title*> in <http://somewhere.com|project_name>')
|
||||
'Test User (test.user) closed merge request <http://somewhere.com/-/merge_requests/100|!100 *Merge Request title*> in <http://somewhere.com|project_name>')
|
||||
expect(subject.attachments).to be_empty
|
||||
end
|
||||
end
|
||||
|
|
@ -77,7 +77,7 @@ describe ChatMessage::MergeMessage do
|
|||
context 'open' do
|
||||
it 'returns a message regarding opening of merge requests' do
|
||||
expect(subject.pretext).to eq(
|
||||
'Test User (test.user) opened [!100 *Merge Request title*](http://somewhere.com/-/merge_requests/100) in [project_name](http://somewhere.com)')
|
||||
'Test User (test.user) opened merge request [!100 *Merge Request title*](http://somewhere.com/-/merge_requests/100) in [project_name](http://somewhere.com)')
|
||||
expect(subject.attachments).to be_empty
|
||||
expect(subject.activity).to eq({
|
||||
title: 'Merge Request opened by Test User (test.user)',
|
||||
|
|
@ -95,7 +95,7 @@ describe ChatMessage::MergeMessage do
|
|||
|
||||
it 'returns a message regarding closing of merge requests' do
|
||||
expect(subject.pretext).to eq(
|
||||
'Test User (test.user) closed [!100 *Merge Request title*](http://somewhere.com/-/merge_requests/100) in [project_name](http://somewhere.com)')
|
||||
'Test User (test.user) closed merge request [!100 *Merge Request title*](http://somewhere.com/-/merge_requests/100) in [project_name](http://somewhere.com)')
|
||||
expect(subject.attachments).to be_empty
|
||||
expect(subject.activity).to eq({
|
||||
title: 'Merge Request closed by Test User (test.user)',
|
||||
|
|
|
|||
Loading…
Reference in New Issue