Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2020-06-02 00:08:07 +00:00
parent 3902d464d6
commit 2e2cd0ea3e
29 changed files with 685 additions and 202 deletions

View File

@ -1 +1 @@
d08b7024a0a2882dc55d8a480d891fc0ded5bb9b
13.1.0-rc2

View File

@ -31,7 +31,7 @@ export const getProjectSlug = () => {
};
export const getGroupSlug = () => {
if (isInGroupsPage()) {
if (isInProjectPage() || isInGroupsPage()) {
return $('body').data('group');
}
return null;

View File

@ -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();

View File

@ -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;

View File

@ -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

View File

@ -12,6 +12,7 @@ class ApplicationController < ActionController::Base
include WorkhorseHelper
include EnforcesTwoFactorAuthentication
include WithPerformanceBar
include Gitlab::SearchContext::ControllerConcern
include SessionlessAuthentication
include SessionsHelper
include ConfirmEmailWarning

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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"

View File

@ -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 }

View File

@ -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

View File

@ -0,0 +1,5 @@
---
title: Add explicit mention of Merge request in Slack message
merge_request: 33152
author:
type: changed

View File

@ -0,0 +1,5 @@
---
title: Enable the `in this group` action in the Search dropdown
merge_request: 31939
author:
type: changed

View File

@ -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)**

View File

@ -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

View File

@ -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
```

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 ""

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -117,4 +117,19 @@ describe PageLayoutHelper do
expect(tags).to include(%q{content="foo&quot; http-equiv=&quot;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

View File

@ -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

View File

@ -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

View File

@ -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)',