Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
b762fdffd0
commit
fa10e47f6e
|
|
@ -4,7 +4,7 @@ import ScopeNavigation from '~/search/sidebar/components/scope_navigation.vue';
|
|||
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
import { SCOPE_ISSUES, SCOPE_MERGE_REQUESTS, SCOPE_BLOB } from '../constants';
|
||||
import ResultsFilters from './results_filters.vue';
|
||||
import LanguageFilter from './language_filter.vue';
|
||||
import LanguageFilter from './language_filter/index.vue';
|
||||
|
||||
export default {
|
||||
name: 'GlobalSearchSidebar',
|
||||
|
|
|
|||
|
|
@ -1,10 +1,15 @@
|
|||
<script>
|
||||
import Vue from 'vue';
|
||||
import { GlFormCheckboxGroup, GlFormCheckbox } from '@gitlab/ui';
|
||||
import { mapState, mapActions, mapGetters } from 'vuex';
|
||||
import { intersection } from 'lodash';
|
||||
import Tracking from '~/tracking';
|
||||
import { NAV_LINK_COUNT_DEFAULT_CLASSES, LABEL_DEFAULT_CLASSES } from '../constants';
|
||||
import { formatSearchResultCount } from '../../store/utils';
|
||||
|
||||
export const TRACKING_LABEL_SET = 'set';
|
||||
export const TRACKING_LABEL_CHECKBOX = 'checkbox';
|
||||
|
||||
export default {
|
||||
name: 'CheckboxFilter',
|
||||
components: {
|
||||
|
|
@ -16,6 +21,10 @@ export default {
|
|||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
trackingNamespace: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapState(['query']),
|
||||
|
|
@ -30,8 +39,11 @@ export default {
|
|||
get() {
|
||||
return intersection(this.flatDataFilterValues, this.queryLanguageFilters);
|
||||
},
|
||||
set(value) {
|
||||
async set(value) {
|
||||
this.setQuery({ key: this.filtersData?.filterParam, value });
|
||||
|
||||
await Vue.nextTick();
|
||||
this.trackSelectCheckbox();
|
||||
},
|
||||
},
|
||||
labelCountClasses() {
|
||||
|
|
@ -40,9 +52,15 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
...mapActions(['setQuery']),
|
||||
getFormatedCount(count) {
|
||||
getFormattedCount(count) {
|
||||
return formatSearchResultCount(count);
|
||||
},
|
||||
trackSelectCheckbox() {
|
||||
Tracking.event(this.trackingNamespace, TRACKING_LABEL_CHECKBOX, {
|
||||
label: TRACKING_LABEL_SET,
|
||||
property: this.selectedFilter,
|
||||
});
|
||||
},
|
||||
},
|
||||
NAV_LINK_COUNT_DEFAULT_CLASSES,
|
||||
LABEL_DEFAULT_CLASSES,
|
||||
|
|
@ -67,7 +85,7 @@ export default {
|
|||
{{ f.label }}
|
||||
</span>
|
||||
<span v-if="f.count" :class="labelCountClasses" data-testid="labelCount">
|
||||
{{ getFormatedCount(f.count) }}
|
||||
{{ getFormattedCount(f.count) }}
|
||||
</span>
|
||||
</span>
|
||||
</gl-form-checkbox>
|
||||
|
|
|
|||
|
|
@ -3,10 +3,18 @@ import { GlButton, GlAlert, GlForm } from '@gitlab/ui';
|
|||
import { mapState, mapActions, mapGetters } from 'vuex';
|
||||
import { __, s__, sprintf } from '~/locale';
|
||||
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
import { DEFAULT_ITEM_LENGTH, MAX_ITEM_LENGTH } from '../constants/language_filter_data';
|
||||
import { HR_DEFAULT_CLASSES, ONLY_SHOW_MD } from '../constants';
|
||||
import { convertFiltersData } from '../utils';
|
||||
import CheckboxFilter from './checkbox_filter.vue';
|
||||
import { HR_DEFAULT_CLASSES, ONLY_SHOW_MD } from '../../constants';
|
||||
import { convertFiltersData } from '../../utils';
|
||||
import CheckboxFilter from '../checkbox_filter.vue';
|
||||
import {
|
||||
trackShowMore,
|
||||
trackShowHasOverMax,
|
||||
trackSubmitQuery,
|
||||
trackResetQuery,
|
||||
TRACKING_ACTION_SELECT,
|
||||
} from './tracking';
|
||||
|
||||
import { DEFAULT_ITEM_LENGTH, MAX_ITEM_LENGTH } from './data';
|
||||
|
||||
export default {
|
||||
name: 'LanguageFilter',
|
||||
|
|
@ -76,11 +84,21 @@ export default {
|
|||
]),
|
||||
onShowMore() {
|
||||
this.showAll = true;
|
||||
trackShowMore();
|
||||
|
||||
if (this.hasOverMax) {
|
||||
trackShowHasOverMax();
|
||||
}
|
||||
},
|
||||
submitQuery() {
|
||||
trackSubmitQuery();
|
||||
this.applyQuery();
|
||||
},
|
||||
trimBuckets(length) {
|
||||
return this.languageAggregationBuckets.slice(0, length);
|
||||
},
|
||||
cleanResetFilters() {
|
||||
trackResetQuery();
|
||||
if (this.currentUrlQueryHasLanguageFilters) {
|
||||
return this.resetLanguageQueryWithRedirect();
|
||||
}
|
||||
|
|
@ -89,6 +107,7 @@ export default {
|
|||
},
|
||||
},
|
||||
HR_DEFAULT_CLASSES,
|
||||
TRACKING_ACTION_SELECT,
|
||||
};
|
||||
</script>
|
||||
|
||||
|
|
@ -96,7 +115,7 @@ export default {
|
|||
<gl-form
|
||||
v-if="hasBuckets"
|
||||
class="gl-pt-5 gl-md-pt-0 language-filter-checkbox"
|
||||
@submit.prevent="applyQuery"
|
||||
@submit.prevent="submitQuery"
|
||||
>
|
||||
<hr :class="dividerClasses" />
|
||||
<div
|
||||
|
|
@ -104,7 +123,10 @@ export default {
|
|||
class="gl-overflow-x-hidden gl-overflow-y-auto"
|
||||
:class="{ 'language-filter-max-height': showAll }"
|
||||
>
|
||||
<checkbox-filter :filters-data="filtersData" />
|
||||
<checkbox-filter
|
||||
:filters-data="filtersData"
|
||||
:tracking-namespace="$options.TRACKING_ACTION_SELECT"
|
||||
/>
|
||||
<span v-if="showAll && hasOverMax" data-testid="has-over-max-text">{{
|
||||
$options.i18n.showingMax
|
||||
}}</span>
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
import Tracking from '~/tracking';
|
||||
import { MAX_ITEM_LENGTH } from './data';
|
||||
|
||||
export const TRACKING_CATEGORY = 'Language filters';
|
||||
export const TRACKING_LABEL_FILTERS = 'Filters';
|
||||
|
||||
export const TRACKING_LABEL_MAX = 'Max Shown';
|
||||
export const TRACKING_LABEL_SHOW_MORE = 'Show More';
|
||||
export const TRACKING_LABEL_APPLY = 'Apply Filters';
|
||||
export const TRACKING_LABEL_RESET = 'Reset Filters';
|
||||
export const TRACKING_LABEL_ALL = 'All Filters';
|
||||
export const TRACKING_PROPERTY_MAX = `More than ${MAX_ITEM_LENGTH} filters to show`;
|
||||
|
||||
export const TRACKING_ACTION_CLICK = 'search:agreggations:language:click';
|
||||
export const TRACKING_ACTION_SHOW = 'search:agreggations:language:show';
|
||||
|
||||
// select is imported and used in checkbox_filter.vue
|
||||
export const TRACKING_ACTION_SELECT = 'search:agreggations:language:select';
|
||||
|
||||
export const trackShowMore = () =>
|
||||
Tracking.event(TRACKING_ACTION_CLICK, TRACKING_LABEL_SHOW_MORE, {
|
||||
label: TRACKING_LABEL_ALL,
|
||||
});
|
||||
|
||||
export const trackShowHasOverMax = () =>
|
||||
Tracking.event(TRACKING_ACTION_SHOW, TRACKING_LABEL_FILTERS, {
|
||||
label: TRACKING_LABEL_MAX,
|
||||
property: TRACKING_PROPERTY_MAX,
|
||||
});
|
||||
|
||||
export const trackSubmitQuery = () =>
|
||||
Tracking.event(TRACKING_ACTION_CLICK, TRACKING_LABEL_APPLY, {
|
||||
label: TRACKING_CATEGORY,
|
||||
});
|
||||
|
||||
export const trackResetQuery = () =>
|
||||
Tracking.event(TRACKING_ACTION_CLICK, TRACKING_LABEL_RESET, {
|
||||
label: TRACKING_CATEGORY,
|
||||
});
|
||||
|
|
@ -14,3 +14,5 @@ export const NAV_LINK_DEFAULT_CLASSES = [
|
|||
export const NAV_LINK_COUNT_DEFAULT_CLASSES = ['gl-font-sm', 'gl-font-weight-normal'];
|
||||
export const HR_DEFAULT_CLASSES = ['gl-my-5', 'gl-mx-5', 'gl-border-gray-100'];
|
||||
export const ONLY_SHOW_MD = ['gl-display-none', 'gl-md-display-block'];
|
||||
|
||||
export const TRACKING_LABEL_CHECKBOX = 'Checkbox';
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { languageFilterData } from '~/search/sidebar/constants/language_filter_data';
|
||||
import { languageFilterData } from '~/search/sidebar/components/language_filter/data';
|
||||
|
||||
export const convertFiltersData = (rawBuckets) =>
|
||||
rawBuckets.reduce(
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import axios from '~/lib/utils/axios_utils';
|
|||
import { visitUrl, setUrlParams } from '~/lib/utils/url_utility';
|
||||
import { logError } from '~/lib/logger';
|
||||
import { __ } from '~/locale';
|
||||
import { languageFilterData } from '~/search/sidebar/constants/language_filter_data';
|
||||
import { languageFilterData } from '~/search/sidebar/components/language_filter/data';
|
||||
import { GROUPS_LOCAL_STORAGE_KEY, PROJECTS_LOCAL_STORAGE_KEY, SIDEBAR_PARAMS } from './constants';
|
||||
import * as types from './mutation_types';
|
||||
import {
|
||||
|
|
@ -140,8 +140,7 @@ export const fetchLanguageAggregation = ({ commit, state }) => {
|
|||
commit(types.REQUEST_AGGREGATIONS);
|
||||
return axios
|
||||
.get(getAggregationsUrl())
|
||||
.then((result) => {
|
||||
const { data } = result;
|
||||
.then(({ data }) => {
|
||||
commit(types.RECEIVE_AGGREGATIONS_SUCCESS, prepareSearchAggregations(state, data));
|
||||
})
|
||||
.catch((e) => {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { stateFilterData } from '~/search/sidebar/constants/state_filter_data';
|
||||
import { confidentialFilterData } from '~/search/sidebar/constants/confidential_filter_data';
|
||||
import { languageFilterData } from '~/search/sidebar/constants/language_filter_data';
|
||||
import { languageFilterData } from '~/search/sidebar/components/language_filter/data';
|
||||
|
||||
export const MAX_FREQUENT_ITEMS = 5;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { findKey, has } from 'lodash';
|
||||
import { languageFilterData } from '~/search/sidebar/constants/language_filter_data';
|
||||
import { languageFilterData } from '~/search/sidebar/components/language_filter/data';
|
||||
|
||||
import { GROUPS_LOCAL_STORAGE_KEY, PROJECTS_LOCAL_STORAGE_KEY } from './constants';
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { isEqual, orderBy } from 'lodash';
|
|||
import AccessorUtilities from '~/lib/utils/accessor';
|
||||
import { formatNumber } from '~/locale';
|
||||
import { joinPaths } from '~/lib/utils/url_utility';
|
||||
import { languageFilterData } from '~/search/sidebar/constants/language_filter_data';
|
||||
import { languageFilterData } from '~/search/sidebar/components/language_filter/data';
|
||||
import {
|
||||
MAX_FREQUENT_ITEMS,
|
||||
MAX_FREQUENCY,
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ module BlobViewer
|
|||
end
|
||||
|
||||
def package_name
|
||||
@package_name ||= package_name_from_json('name')
|
||||
@package_name ||= fetch_from_json('name')
|
||||
end
|
||||
|
||||
def package_url
|
||||
|
|
|
|||
|
|
@ -38,8 +38,10 @@ module BlobViewer
|
|||
end
|
||||
end
|
||||
|
||||
def package_name_from_json(key)
|
||||
json_data[key]
|
||||
def fetch_from_json(...)
|
||||
json_data.dig(...)
|
||||
rescue TypeError
|
||||
nil
|
||||
end
|
||||
|
||||
def package_name_from_method_call(name)
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ module BlobViewer
|
|||
end
|
||||
|
||||
def yarn?
|
||||
json_data['engines'].present? && json_data['engines']['yarn'].present?
|
||||
fetch_from_json('engines', 'yarn').present?
|
||||
end
|
||||
|
||||
def manager_url
|
||||
|
|
@ -19,7 +19,7 @@ module BlobViewer
|
|||
end
|
||||
|
||||
def package_name
|
||||
@package_name ||= package_name_from_json('name')
|
||||
@package_name ||= fetch_from_json('name')
|
||||
end
|
||||
|
||||
def package_type
|
||||
|
|
@ -33,11 +33,11 @@ module BlobViewer
|
|||
private
|
||||
|
||||
def private?
|
||||
!!json_data['private']
|
||||
!!fetch_from_json('private')
|
||||
end
|
||||
|
||||
def homepage
|
||||
url = json_data['homepage']
|
||||
url = fetch_from_json('homepage')
|
||||
url if Gitlab::UrlSanitizer.valid?(url)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ module BlobViewer
|
|||
self.file_types = %i(podspec_json)
|
||||
|
||||
def package_name
|
||||
@package_name ||= package_name_from_json('name')
|
||||
@package_name ||= fetch_from_json('name')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,31 +1,32 @@
|
|||
.card
|
||||
.card-header
|
||||
= render Pajamas::CardComponent.new(body_options: { class: 'gl-py-0' }) do |c|
|
||||
- c.header do
|
||||
= _('Profile')
|
||||
%ul.content-list
|
||||
%li
|
||||
%span.light= _('Member since')
|
||||
%strong= user.created_at.to_s(:medium)
|
||||
- unless user.public_email.blank?
|
||||
- c.body do
|
||||
%ul.content-list
|
||||
%li
|
||||
%span.light= _('E-mail:')
|
||||
%strong= link_to user.public_email, "mailto:#{user.public_email}"
|
||||
- unless user.skype.blank?
|
||||
%li
|
||||
%span.light= _('Skype:')
|
||||
%strong= link_to user.skype, "skype:#{user.skype}"
|
||||
- unless user.linkedin.blank?
|
||||
%li
|
||||
%span.light= _('LinkedIn:')
|
||||
%strong= link_to user.linkedin, "https://www.linkedin.com/in/#{user.linkedin}"
|
||||
- unless user.twitter.blank?
|
||||
%li
|
||||
%span.light= _('Twitter:')
|
||||
%strong= link_to user.twitter, "https://twitter.com/#{user.twitter}"
|
||||
- unless user.website_url.blank?
|
||||
%li
|
||||
%span.light= _('Website:')
|
||||
%strong= link_to user.short_website_url, user.full_website_url
|
||||
- unless user.location.blank?
|
||||
%li
|
||||
%span.light= _('Location:')
|
||||
%strong= user.location
|
||||
%span.light= _('Member since')
|
||||
%strong= user.created_at.to_s(:medium)
|
||||
- unless user.public_email.blank?
|
||||
%li
|
||||
%span.light= _('E-mail:')
|
||||
%strong= link_to user.public_email, "mailto:#{user.public_email}"
|
||||
- unless user.skype.blank?
|
||||
%li
|
||||
%span.light= _('Skype:')
|
||||
%strong= link_to user.skype, "skype:#{user.skype}"
|
||||
- unless user.linkedin.blank?
|
||||
%li
|
||||
%span.light= _('LinkedIn:')
|
||||
%strong= link_to user.linkedin, "https://www.linkedin.com/in/#{user.linkedin}"
|
||||
- unless user.twitter.blank?
|
||||
%li
|
||||
%span.light= _('Twitter:')
|
||||
%strong= link_to user.twitter, "https://twitter.com/#{user.twitter}"
|
||||
- unless user.website_url.blank?
|
||||
%li
|
||||
%span.light= _('Website:')
|
||||
%strong= link_to user.short_website_url, user.full_website_url
|
||||
- unless user.location.blank?
|
||||
%li
|
||||
%span.light= _('Location:')
|
||||
%strong= user.location
|
||||
|
|
|
|||
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
name: git_abuse_rate_limit_feature_flag
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/87872
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/364782
|
||||
milestone: '15.1'
|
||||
type: development
|
||||
group: group::anti-abuse
|
||||
default_enabled: false
|
||||
|
|
@ -24,10 +24,12 @@ module Net
|
|||
line = line.sub(/\s{0,10}\z/, '')
|
||||
break if line.empty?
|
||||
if line[0] == ?\s or line[0] == ?\t and value
|
||||
# rubocop:disable Gitlab/NoCodeCoverageComment
|
||||
# :nocov:
|
||||
value << ' ' unless value.empty?
|
||||
value << line.strip
|
||||
# :nocov:
|
||||
# rubocop:enable Gitlab/NoCodeCoverageComment
|
||||
else
|
||||
yield key, value if key
|
||||
key, value = line.strip.split(/\s{0,10}:\s{0,10}/, 2)
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
PostgreSQL 12 will be supported for the full GitLab 15 release cycle.
|
||||
PostgreSQL 13 will also be supported for instances that want to upgrade prior to GitLab 16.0.
|
||||
|
||||
Upgrading to PostgreSQL 13 is not yet supported for GitLab instances with Geo enabled. Geo support for PostgreSQL 13 will be announced in a minor release version of GitLab 15, after the process is fully supported and validated. For more information, read the Geo related verifications on the [support epic for PostgreSQL 13](https://gitlab.com/groups/gitlab-org/-/epics/3832).
|
||||
Support for PostgreSQL 13 was added to Geo in GitLab 15.2.
|
||||
stage: Enablement
|
||||
tiers: [Free, Premium, Ultimate]
|
||||
issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/349185
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
# This is a template for announcing a feature deprecation or other important planned change.
|
||||
#
|
||||
# Please refer to the deprecation guidelines to confirm your understanding of GitLab's definitions.
|
||||
# https://docs.gitlab.com/ee/development/deprecation_guidelines/#terminology
|
||||
#
|
||||
# Deprecations and other future breaking changes must be announced at least
|
||||
# three releases prior to removal.
|
||||
#
|
||||
# Breaking changes must happen in a major release.
|
||||
#
|
||||
# See the OPTIONAL END OF SUPPORT FIELDS section below if an End of Support period also applies.
|
||||
#
|
||||
# For more information please refer to the handbook documentation here:
|
||||
# https://about.gitlab.com/handbook/marketing/blog/release-posts/#deprecations-and-other-planned-breaking-change-announcements
|
||||
#
|
||||
# Please delete this line and above before submitting your merge request.
|
||||
#
|
||||
# REQUIRED FIELDS
|
||||
#
|
||||
- title: "Bundled Grafana Helm Chart is deprecated" # (required) Clearly explain the change, or planned change. For example, "The `confidential` field for a `Note` is deprecated" or "CI/CD job names will be limited to 250 characters."
|
||||
announcement_milestone: "15.10" # (required) The milestone when this feature was first announced as deprecated.
|
||||
removal_milestone: "16.0" # (required) The milestone when this feature is planned to be removed
|
||||
breaking_change: true # (required) Change to false if this is not a breaking change.
|
||||
reporter: twk3 # (required) GitLab username of the person reporting the change
|
||||
stage: enablement # (required) String value of the stage that the feature was created in. e.g., Growth
|
||||
issue_url: https://gitlab.com/gitlab-org/charts/gitlab/-/issues/4353 # (required) Link to the deprecation issue in GitLab
|
||||
body: | # (required) Do not modify this line, instead modify the lines below.
|
||||
The Grafana Helm chart that is bundled with the GitLab Helm Chart is deprecated and will be removed in the GitLab Helm Chart 7.0 release (releasing along with GitLab 16.0).
|
||||
|
||||
The bundled Grafana Helm chart is an optional service that can be turned on to provide the Grafana UI connected to the GitLab Helm Chart's Prometheus metrics.
|
||||
|
||||
The version of Grafana that the GitLab Helm Chart is currently providing is no longer a supported Grafana version.
|
||||
If you're using the bundled Grafana, you should switch to the [newer chart version from Grafana Labs](https://artifacthub.io/packages/helm/grafana/grafana)
|
||||
or a Grafana Operator from a trusted provider.
|
||||
|
||||
In your new Grafana instance, you can [configure the GitLab provided Prometheus as a data source](https://docs.gitlab.com/ee/administration/monitoring/performance/grafana_configuration.html#integration-with-gitlab-ui)
|
||||
and [connect Grafana to the GitLab UI](https://docs.gitlab.com/ee/administration/monitoring/performance/grafana_configuration.html#integration-with-gitlab-ui).
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
# This is a template for announcing a feature deprecation or other important planned change.
|
||||
#
|
||||
# Please refer to the deprecation guidelines to confirm your understanding of GitLab's definitions.
|
||||
# https://docs.gitlab.com/ee/development/deprecation_guidelines/#terminology
|
||||
#
|
||||
# Deprecations and other future breaking changes must be announced at least
|
||||
# three releases prior to removal.
|
||||
#
|
||||
# Breaking changes must happen in a major release.
|
||||
#
|
||||
# See the OPTIONAL END OF SUPPORT FIELDS section below if an End of Support period also applies.
|
||||
#
|
||||
# For more information please refer to the handbook documentation here:
|
||||
# https://about.gitlab.com/handbook/marketing/blog/release-posts/#deprecations-and-other-planned-breaking-change-announcements
|
||||
#
|
||||
# Please delete this line and above before submitting your merge request.
|
||||
#
|
||||
# REQUIRED FIELDS
|
||||
#
|
||||
- title: "Major bundled Helm Chart updates for the GitLab Helm Chart" # (required) Clearly explain the change, or planned change. For example, "The `confidential` field for a `Note` is deprecated" or "CI/CD job names will be limited to 250 characters."
|
||||
announcement_milestone: "15.10" # (required) The milestone when this feature was first announced as deprecated.
|
||||
removal_milestone: "16.0" # (required) The milestone when this feature is planned to be removed
|
||||
breaking_change: true # (required) Change to false if this is not a breaking change.
|
||||
reporter: twk3 # (required) GitLab username of the person reporting the change
|
||||
stage: enablement # (required) String value of the stage that the feature was created in. e.g., Growth
|
||||
issue_url: https://gitlab.com/gitlab-org/charts/gitlab/-/issues/3442 # (required) Link to the deprecation issue in GitLab
|
||||
body: | # (required) Do not modify this line, instead modify the lines below.
|
||||
To coincide with GitLab 16.0, the GitLab Helm Chart will release the 7.0 major version. The following major bundled chart updates will be included:
|
||||
|
||||
- In GitLab 16.0, [PostgreSQL 12 support is being removed, and PostgreSQL 13 is becoming the new minimum](#postgresql-12-deprecated).
|
||||
- Installs using production-ready external databases will need to complete their migration to a newer PostgreSQL version before upgrading.
|
||||
- Installs using the [non-production bundled PostgreSQL 12 chart](https://docs.gitlab.com/charts/installation/tools.html#postgresql) will have the chart upgraded to the new version. For more information, [see issue 4118](https://gitlab.com/gitlab-org/charts/gitlab/-/issues/4118)
|
||||
- Installs using the [non-production bundled Redis chart](https://docs.gitlab.com/charts/installation/tools.html#redis) will have the chart upgraded to a newer version. For more information, [see issue 3375](https://gitlab.com/gitlab-org/charts/gitlab/-/issues/3375)
|
||||
- Installs using the [bundled cert-manager chart](https://docs.gitlab.com/charts/installation/tls.html#option-1-cert-manager-and-lets-encrypt) will have the chart upgraded to a newer version. For more information, [see issue 4313](https://gitlab.com/gitlab-org/charts/gitlab/-/issues/4313)
|
||||
|
||||
The full GitLab Helm Chart 7.0 upgrade steps will be available in the [upgrade docs](https://docs.gitlab.com/charts/installation/upgrade.html).
|
||||
|
|
@ -7,7 +7,9 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
# LDAP synchronization **(PREMIUM SELF)**
|
||||
|
||||
If you have [configured LDAP to work with GitLab](index.md), GitLab can automatically synchronize
|
||||
users and groups. This process updates user and group information.
|
||||
users and groups.
|
||||
|
||||
LDAP synchronization updates existing GitLab user and group information. It does not create new GitLab users through LDAP.
|
||||
|
||||
You can change when synchronization occurs.
|
||||
|
||||
|
|
|
|||
|
|
@ -126,3 +126,17 @@ kubectl delete pods -l release=<helm release name>,app=<component name>
|
|||
```
|
||||
|
||||
The release name can be obtained from the output of the `helm list` command.
|
||||
|
||||
## Docker installation
|
||||
|
||||
If you change the configuration on your [Docker installation](../install/docker.md), for that change to take effect you must restart:
|
||||
|
||||
- The main `gitlab` container.
|
||||
- Any separate component containers.
|
||||
|
||||
For example, if you deployed Sidekiq on a separate container, to restart the containers, run:
|
||||
|
||||
```shell
|
||||
sudo docker restart gitlab
|
||||
sudo docker restart sidekiq
|
||||
```
|
||||
|
|
|
|||
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
redirect_to: 'cells-feature-admin-area.md'
|
||||
remove_date: '2023-06-14'
|
||||
---
|
||||
|
||||
This document was moved to [another location](cells-feature-admin-area.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <2023-06-14>. -->
|
||||
<!-- Redirects that point to other docs in the same project expire in three months. -->
|
||||
<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
redirect_to: 'cells-feature-agent-for-kubernetes.md'
|
||||
remove_date: '2023-06-14'
|
||||
---
|
||||
|
||||
This document was moved to [another location](cells-feature-agent-for-kubernetes.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <2023-06-14>. -->
|
||||
<!-- Redirects that point to other docs in the same project expire in three months. -->
|
||||
<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
redirect_to: 'cells-feature-backups.md'
|
||||
remove_date: '2023-06-14'
|
||||
---
|
||||
|
||||
This document was moved to [another location](cells-feature-backups.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <2023-06-14>. -->
|
||||
<!-- Redirects that point to other docs in the same project expire in three months. -->
|
||||
<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
redirect_to: 'cells-feature-ci-runners.md'
|
||||
remove_date: '2023-06-14'
|
||||
---
|
||||
|
||||
This document was moved to [another location](cells-feature-ci-runners.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <2023-06-14>. -->
|
||||
<!-- Redirects that point to other docs in the same project expire in three months. -->
|
||||
<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
redirect_to: 'cells-feature-container-registry.md'
|
||||
remove_date: '2023-06-14'
|
||||
---
|
||||
|
||||
This document was moved to [another location](cells-feature-container-registry.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <2023-06-14>. -->
|
||||
<!-- Redirects that point to other docs in the same project expire in three months. -->
|
||||
<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
redirect_to: 'cells-feature-contributions-forks.md'
|
||||
remove_date: '2023-06-14'
|
||||
---
|
||||
|
||||
This document was moved to [another location](cells-feature-contributions-forks.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <2023-06-14>. -->
|
||||
<!-- Redirects that point to other docs in the same project expire in three months. -->
|
||||
<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
redirect_to: 'cells-feature-dashboard.md'
|
||||
remove_date: '2023-06-14'
|
||||
---
|
||||
|
||||
This document was moved to [another location](cells-feature-dashboard.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <2023-06-14>. -->
|
||||
<!-- Redirects that point to other docs in the same project expire in three months. -->
|
||||
<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
redirect_to: 'cells-feature-data-migration.md'
|
||||
remove_date: '2023-06-14'
|
||||
---
|
||||
|
||||
This document was moved to [another location](cells-feature-data-migration.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <2023-06-14>. -->
|
||||
<!-- Redirects that point to other docs in the same project expire in three months. -->
|
||||
<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
redirect_to: 'cells-feature-database-sequences.md'
|
||||
remove_date: '2023-06-14'
|
||||
---
|
||||
|
||||
This document was moved to [another location](cells-feature-database-sequences.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <2023-06-14>. -->
|
||||
<!-- Redirects that point to other docs in the same project expire in three months. -->
|
||||
<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
redirect_to: 'cells-feature-git-access.md'
|
||||
remove_date: '2023-06-14'
|
||||
---
|
||||
|
||||
This document was moved to [another location](cells-feature-git-access.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <2023-06-14>. -->
|
||||
<!-- Redirects that point to other docs in the same project expire in three months. -->
|
||||
<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
redirect_to: 'cells-feature-gitlab-pages.md'
|
||||
remove_date: '2023-06-14'
|
||||
---
|
||||
|
||||
This document was moved to [another location](cells-feature-gitlab-pages.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <2023-06-14>. -->
|
||||
<!-- Redirects that point to other docs in the same project expire in three months. -->
|
||||
<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
redirect_to: 'cells-feature-global-search.md'
|
||||
remove_date: '2023-06-14'
|
||||
---
|
||||
|
||||
This document was moved to [another location](cells-feature-global-search.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <2023-06-14>. -->
|
||||
<!-- Redirects that point to other docs in the same project expire in three months. -->
|
||||
<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
redirect_to: 'cells-feature-graphql.md'
|
||||
remove_date: '2023-06-14'
|
||||
---
|
||||
|
||||
This document was moved to [another location](cells-feature-graphql.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <2023-06-14>. -->
|
||||
<!-- Redirects that point to other docs in the same project expire in three months. -->
|
||||
<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
redirect_to: 'cells-feature-organizations.md'
|
||||
remove_date: '2023-06-14'
|
||||
---
|
||||
|
||||
This document was moved to [another location](cells-feature-organizations.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <2023-06-14>. -->
|
||||
<!-- Redirects that point to other docs in the same project expire in three months. -->
|
||||
<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
redirect_to: 'cells-feature-personal-namespaces.md'
|
||||
remove_date: '2023-06-14'
|
||||
---
|
||||
|
||||
This document was moved to [another location](cells-feature-personal-namespaces.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <2023-06-14>. -->
|
||||
<!-- Redirects that point to other docs in the same project expire in three months. -->
|
||||
<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
redirect_to: 'cells-feature-router-endpoints-classification.md'
|
||||
remove_date: '2023-06-14'
|
||||
---
|
||||
|
||||
This document was moved to [another location](cells-feature-router-endpoints-classification.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <2023-06-14>. -->
|
||||
<!-- Redirects that point to other docs in the same project expire in three months. -->
|
||||
<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
redirect_to: 'cells-feature-schema-changes.md'
|
||||
remove_date: '2023-06-14'
|
||||
---
|
||||
|
||||
This document was moved to [another location](cells-feature-schema-changes.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <2023-06-14>. -->
|
||||
<!-- Redirects that point to other docs in the same project expire in three months. -->
|
||||
<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
redirect_to: 'cells-feature-secrets.md'
|
||||
remove_date: '2023-06-14'
|
||||
---
|
||||
|
||||
This document was moved to [another location](cells-feature-secrets.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <2023-06-14>. -->
|
||||
<!-- Redirects that point to other docs in the same project expire in three months. -->
|
||||
<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
redirect_to: 'cells-feature-snippets.md'
|
||||
remove_date: '2023-06-14'
|
||||
---
|
||||
|
||||
This document was moved to [another location](cells-feature-snippets.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <2023-06-14>. -->
|
||||
<!-- Redirects that point to other docs in the same project expire in three months. -->
|
||||
<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
redirect_to: 'cells-feature-template.md'
|
||||
remove_date: '2023-06-14'
|
||||
---
|
||||
|
||||
This document was moved to [another location](cells-feature-template.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <2023-06-14>. -->
|
||||
<!-- Redirects that point to other docs in the same project expire in three months. -->
|
||||
<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
redirect_to: 'cells-feature-uploads.md'
|
||||
remove_date: '2023-06-14'
|
||||
---
|
||||
|
||||
This document was moved to [another location](cells-feature-uploads.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <2023-06-14>. -->
|
||||
<!-- Redirects that point to other docs in the same project expire in three months. -->
|
||||
<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
|
||||
|
|
@ -19,6 +19,8 @@ are very appreciative of the work done by translators and proofreaders!
|
|||
- Tsegaselassie Tadesse - [GitLab](https://gitlab.com/tsega), [Crowdin](https://crowdin.com/profile/tsegaselassi)
|
||||
- Arabic
|
||||
- Proofreaders needed.
|
||||
- Belarusian
|
||||
- Anton Katsuba - [GitLab](https://gitlab.com/coinvariant), [Crowdin](https://crowdin.com/profile/aerialfiddle)
|
||||
- Bosnian
|
||||
- Haris Delalić - [GitLab](https://gitlab.com/haris.delalic), [Crowdin](https://crowdin.com/profile/haris.delalic)
|
||||
- Bulgarian
|
||||
|
|
|
|||
|
|
@ -221,6 +221,7 @@ graph LR;
|
|||
MergeRequestLastBuildFinished --> MergeRequestLabelRemoved;
|
||||
MergeRequestLabelAdded --> MergeRequestLabelAdded;
|
||||
MergeRequestLabelAdded --> MergeRequestLabelRemoved;
|
||||
MergeRequestLabelAdded --> MergeRequestMerged;
|
||||
MergeRequestLabelRemoved --> MergeRequestLabelAdded;
|
||||
MergeRequestLabelRemoved --> MergeRequestLabelRemoved;
|
||||
```
|
||||
|
|
|
|||
|
|
@ -47,6 +47,29 @@ and [GraphQL](https://docs.gitlab.com/ee/api/graphql/removed_items.html) depreca
|
|||
|
||||
<div class="deprecation removal-160 breaking-change">
|
||||
|
||||
### Bundled Grafana Helm Chart is deprecated
|
||||
|
||||
Planned removal: GitLab <span class="removal-milestone">16.0</span> <span class="removal-date"></span>
|
||||
|
||||
WARNING:
|
||||
This is a [breaking change](https://docs.gitlab.com/ee/development/deprecation_guidelines/).
|
||||
Review the details carefully before upgrading.
|
||||
|
||||
The Grafana Helm chart that is bundled with the GitLab Helm Chart is deprecated and will be removed in the GitLab Helm Chart 7.0 release (releasing along with GitLab 16.0).
|
||||
|
||||
The bundled Grafana Helm chart is an optional service that can be turned on to provide the Grafana UI connected to the GitLab Helm Chart's Prometheus metrics.
|
||||
|
||||
The version of Grafana that the GitLab Helm Chart is currently providing is no longer a supported Grafana version.
|
||||
If you're using the bundled Grafana, you should switch to the [newer chart version from Grafana Labs](https://artifacthub.io/packages/helm/grafana/grafana)
|
||||
or a Grafana Operator from a trusted provider.
|
||||
|
||||
In your new Grafana instance, you can [configure the GitLab provided Prometheus as a data source](https://docs.gitlab.com/ee/administration/monitoring/performance/grafana_configuration.html#integration-with-gitlab-ui)
|
||||
and [connect Grafana to the GitLab UI](https://docs.gitlab.com/ee/administration/monitoring/performance/grafana_configuration.html#integration-with-gitlab-ui).
|
||||
|
||||
</div>
|
||||
|
||||
<div class="deprecation removal-160 breaking-change">
|
||||
|
||||
### Deprecated Consul http metrics
|
||||
|
||||
Planned removal: GitLab <span class="removal-milestone">16.0</span> <span class="removal-date"></span>
|
||||
|
|
@ -115,6 +138,28 @@ The change improves consistency between Omnibus GitLab and source installs and e
|
|||
You should update to the new configuration structure as soon as possible using
|
||||
[the upgrade instructions](https://docs.gitlab.com/ee/update/#gitaly-omnibus-gitlab-configuration-structure-change).
|
||||
|
||||
</div>
|
||||
|
||||
<div class="deprecation removal-160 breaking-change">
|
||||
|
||||
### Major bundled Helm Chart updates for the GitLab Helm Chart
|
||||
|
||||
Planned removal: GitLab <span class="removal-milestone">16.0</span> <span class="removal-date"></span>
|
||||
|
||||
WARNING:
|
||||
This is a [breaking change](https://docs.gitlab.com/ee/development/deprecation_guidelines/).
|
||||
Review the details carefully before upgrading.
|
||||
|
||||
To coincide with GitLab 16.0, the GitLab Helm Chart will release the 7.0 major version. The following major bundled chart updates will be included:
|
||||
|
||||
- In GitLab 16.0, [PostgreSQL 12 support is being removed, and PostgreSQL 13 is becoming the new minimum](#postgresql-12-deprecated).
|
||||
- Installs using production-ready external databases will need to complete their migration to a newer PostgreSQL version before upgrading.
|
||||
- Installs using the [non-production bundled PostgreSQL 12 chart](https://docs.gitlab.com/charts/installation/tools.html#postgresql) will have the chart upgraded to the new version. For more information, [see issue 4118](https://gitlab.com/gitlab-org/charts/gitlab/-/issues/4118)
|
||||
- Installs using the [non-production bundled Redis chart](https://docs.gitlab.com/charts/installation/tools.html#redis) will have the chart upgraded to a newer version. For more information, [see issue 3375](https://gitlab.com/gitlab-org/charts/gitlab/-/issues/3375)
|
||||
- Installs using the [bundled cert-manager chart](https://docs.gitlab.com/charts/installation/tls.html#option-1-cert-manager-and-lets-encrypt) will have the chart upgraded to a newer version. For more information, [see issue 4313](https://gitlab.com/gitlab-org/charts/gitlab/-/issues/4313)
|
||||
|
||||
The full GitLab Helm Chart 7.0 upgrade steps will be available in the [upgrade docs](https://docs.gitlab.com/charts/installation/upgrade.html).
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -1988,7 +2033,7 @@ In GitLab 16.0, PostgreSQL 13 becomes the minimum required PostgreSQL version.
|
|||
PostgreSQL 12 will be supported for the full GitLab 15 release cycle.
|
||||
PostgreSQL 13 will also be supported for instances that want to upgrade prior to GitLab 16.0.
|
||||
|
||||
Upgrading to PostgreSQL 13 is not yet supported for GitLab instances with Geo enabled. Geo support for PostgreSQL 13 will be announced in a minor release version of GitLab 15, after the process is fully supported and validated. For more information, read the Geo related verifications on the [support epic for PostgreSQL 13](https://gitlab.com/groups/gitlab-org/-/epics/3832).
|
||||
Support for PostgreSQL 13 was added to Geo in GitLab 15.2.
|
||||
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -4,12 +4,10 @@ group: Anti-Abuse
|
|||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
# Git abuse rate limit (administration) **(ULTIMATE)**
|
||||
# Git abuse rate limit (administration) **(ULTIMATE SELF)**
|
||||
|
||||
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/8066) in GitLab 15.2 [with a flag](../../../administration/feature_flags.md) named `git_abuse_rate_limit_feature_flag`. Disabled by default.
|
||||
|
||||
FLAG:
|
||||
On self-managed GitLab, by default this feature is not available. To make it available, ask an administrator to [enable the feature flag](../../../administration/feature_flags.md) named `git_abuse_rate_limit_feature_flag`. On GitLab.com, this feature is available.
|
||||
> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/8066) in GitLab 15.2 [with a flag](../../../administration/feature_flags.md) named `git_abuse_rate_limit_feature_flag`. Disabled by default.
|
||||
> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/394996) in GitLab 15.10. Feature flag `git_abuse_rate_limit_feature_flag` removed.
|
||||
|
||||
This is the administration documentation. For information about Git abuse rate limiting at the group level, see the [group-level documentation](../../group/reporting/git_abuse_rate_limit.md).
|
||||
|
||||
|
|
@ -17,14 +15,6 @@ Git abuse rate limiting is a feature to automatically [ban users](../moderate_us
|
|||
|
||||
Git abuse rate limiting does not apply to instance administrators, [deploy tokens](../../../user/project/deploy_tokens/index.md), or [deploy keys](../../../user/project/deploy_keys/index.md).
|
||||
|
||||
## Automatic ban notifications
|
||||
|
||||
If the `git_abuse_rate_limit_feature_flag` feature flag is enabled, selected users receive an email when a user is about to be banned.
|
||||
|
||||
If automatic banning is disabled, a user is not banned automatically when they exceed the limit. However, notifications are still sent. You can use this setup to determine the correct values of the rate limit settings before enabling automatic banning.
|
||||
|
||||
If automatic banning is enabled, an email notification is sent when a user is about to be banned, and the user is automatically banned from the GitLab instance.
|
||||
|
||||
## Configure Git abuse rate limiting
|
||||
|
||||
1. On the top bar, select **Main menu > Admin**.
|
||||
|
|
@ -38,6 +28,12 @@ If automatic banning is enabled, an email notification is sent when a user is ab
|
|||
1. Optional. Turn on the **Automatically ban users from this namespace when they exceed the specified limits** toggle to enable automatic banning.
|
||||
1. Select **Save changes**.
|
||||
|
||||
## Automatic ban notifications
|
||||
|
||||
If automatic banning is disabled, a user is not banned automatically when they exceed the limit. However, notifications are still sent to the users listed under **Send notifications to**. You can use this setup to determine the correct values of the rate limit settings before enabling automatic banning.
|
||||
|
||||
If automatic banning is enabled, an email notification is sent when a user is about to be banned, and the user is automatically banned from the GitLab instance.
|
||||
|
||||
## Unban a user
|
||||
|
||||
1. On the top bar, select **Main menu > Admin**.
|
||||
|
|
|
|||
|
|
@ -29,6 +29,48 @@ Value stream analytics is also available for [projects](../../analytics/value_st
|
|||
|
||||
## How value stream analytics works
|
||||
|
||||
Value stream analytics calculates the duration of every stage of your software development process.
|
||||
|
||||
Value stream analytics is made of three core objects:
|
||||
|
||||
- A **value stream** contains a value stream stage list.
|
||||
- Each value stream stage list contains one or more **stages**.
|
||||
- Each stage has two **events**: start and stop.
|
||||
|
||||
### Value stream stages
|
||||
|
||||
A stage represents an event pair (start and end events) with additional metadata, such as the name of the stage. You can configure the stages in the pairing rules defined in the backend.
|
||||
|
||||
### Value streams
|
||||
|
||||
Value streams are container objects for the stages. You can have multiple value streams per group, to focus on different aspects of the DevOps lifecycle.
|
||||
|
||||
### Value stream stage events
|
||||
|
||||
Events are the smallest building blocks of the value stream analytics feature. A stage consists of a start event and an end event.
|
||||
|
||||
The following stage events are available:
|
||||
|
||||
- Issue closed
|
||||
- Issue created
|
||||
- Issue first added to board
|
||||
- Issue first associated with milestone
|
||||
- Issue first mentioned
|
||||
- Issue label added
|
||||
- Issue label removed
|
||||
- MR closed
|
||||
- MR merged
|
||||
- MR created
|
||||
- MR first commit time
|
||||
- MR first deployed
|
||||
- MR label added
|
||||
- MR label removed
|
||||
- MR last pipeline duration
|
||||
|
||||
These events play a key role in the duration calculation, which is calculated by the formula: duration = end event time - start event time.
|
||||
|
||||
To learn what start and end events can be paired, see [Validating start and end events](../../../development/value_stream_analytics.md#validating-start-and-end-events).
|
||||
|
||||
### How value stream analytics aggregates data
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/335391) in GitLab 14.5.
|
||||
|
|
|
|||
|
|
@ -1392,6 +1392,7 @@ Payload example:
|
|||
"build_started_at": null,
|
||||
"build_finished_at": null,
|
||||
"build_duration": null,
|
||||
"build_queued_duration": 1095.588715, // duration in seconds
|
||||
"build_allow_failure": false,
|
||||
"build_failure_reason": "script_failure",
|
||||
"retries_count": 2, // the second retry of this job
|
||||
|
|
|
|||
|
|
@ -142,6 +142,8 @@ Items that are exported include:
|
|||
- Group members are exported as project members, as long as the user has the Maintainer role in the
|
||||
exported project's group, or is an administrator
|
||||
|
||||
### Items that are not exported
|
||||
|
||||
Items that are **not** exported include:
|
||||
|
||||
- [Child pipeline history](https://gitlab.com/gitlab-org/gitlab/-/issues/221088)
|
||||
|
|
@ -240,11 +242,11 @@ possible through a [professional services engagement](https://about.gitlab.com/s
|
|||
|
||||
To help avoid abuse, by default, users are rate limited to:
|
||||
|
||||
| Request Type | Limit |
|
||||
| ---------------- | ----- |
|
||||
| Export | 6 projects per minute |
|
||||
| Download export | 1 download per group per minute |
|
||||
| Import | 6 projects per minute |
|
||||
| Request type | Limit |
|
||||
|:----------------|:--------------------------------|
|
||||
| Export | 6 projects per minute |
|
||||
| Download export | 1 download per group per minute |
|
||||
| Import | 6 projects per minute |
|
||||
|
||||
## Related topics
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ export const MOCK_QUERY = {
|
|||
state: 'all',
|
||||
confidential: null,
|
||||
group_id: 1,
|
||||
language: ['C', 'JavaScript'],
|
||||
};
|
||||
|
||||
export const MOCK_GROUP = {
|
||||
|
|
@ -193,214 +194,6 @@ export const MOCK_NAVIGATION_ACTION_MUTATION = {
|
|||
payload: { key: 'projects', count: '13' },
|
||||
};
|
||||
|
||||
export const MOCK_AGGREGATIONS = [
|
||||
{
|
||||
name: 'language',
|
||||
buckets: [
|
||||
{ key: 'random-label-edumingos0', count: 1 },
|
||||
{ key: 'random-label-rbourgourd1', count: 2 },
|
||||
{ key: 'random-label-dfearnside2', count: 3 },
|
||||
{ key: 'random-label-gewins3', count: 4 },
|
||||
{ key: 'random-label-telverstone4', count: 5 },
|
||||
{ key: 'random-label-ygerriets5', count: 6 },
|
||||
{ key: 'random-label-lmoffet6', count: 7 },
|
||||
{ key: 'random-label-ehinnerk7', count: 8 },
|
||||
{ key: 'random-label-flanceley8', count: 9 },
|
||||
{ key: 'random-label-adoyle9', count: 10 },
|
||||
{ key: 'random-label-rmcgirla', count: 11 },
|
||||
{ key: 'random-label-dwhellansb', count: 12 },
|
||||
{ key: 'random-label-apitkethlyc', count: 13 },
|
||||
{ key: 'random-label-senevoldsend', count: 14 },
|
||||
{ key: 'random-label-tlardnare', count: 15 },
|
||||
{ key: 'random-label-fcoilsf', count: 16 },
|
||||
{ key: 'random-label-qgeckg', count: 17 },
|
||||
{ key: 'random-label-rgrabenh', count: 18 },
|
||||
{ key: 'random-label-lashardi', count: 19 },
|
||||
{ key: 'random-label-sadamovitchj', count: 20 },
|
||||
{ key: 'random-label-rlyddiardk', count: 21 },
|
||||
{ key: 'random-label-jpoell', count: 22 },
|
||||
{ key: 'random-label-kcharitym', count: 23 },
|
||||
{ key: 'random-label-cbertenshawn', count: 24 },
|
||||
{ key: 'random-label-jsturgeso', count: 25 },
|
||||
{ key: 'random-label-ohouldcroftp', count: 26 },
|
||||
{ key: 'random-label-rheijnenq', count: 27 },
|
||||
{ key: 'random-label-snortheyr', count: 28 },
|
||||
{ key: 'random-label-vpairpoints', count: 29 },
|
||||
{ key: 'random-label-odavidovicit', count: 30 },
|
||||
{ key: 'random-label-fmccartu', count: 31 },
|
||||
{ key: 'random-label-cwansburyv', count: 32 },
|
||||
{ key: 'random-label-bdimontw', count: 33 },
|
||||
{ key: 'random-label-adocketx', count: 34 },
|
||||
{ key: 'random-label-obavridgey', count: 35 },
|
||||
{ key: 'random-label-jperezz', count: 36 },
|
||||
{ key: 'random-label-gdeneve10', count: 37 },
|
||||
{ key: 'random-label-rmckeand11', count: 38 },
|
||||
{ key: 'random-label-kwestmerland12', count: 39 },
|
||||
{ key: 'random-label-mpryer13', count: 40 },
|
||||
{ key: 'random-label-rmcneil14', count: 41 },
|
||||
{ key: 'random-label-ablondel15', count: 42 },
|
||||
{ key: 'random-label-wbalducci16', count: 43 },
|
||||
{ key: 'random-label-swigley17', count: 44 },
|
||||
{ key: 'random-label-gferroni18', count: 45 },
|
||||
{ key: 'random-label-icollings19', count: 46 },
|
||||
{ key: 'random-label-wszymanski1a', count: 47 },
|
||||
{ key: 'random-label-jelson1b', count: 48 },
|
||||
{ key: 'random-label-fsambrook1c', count: 49 },
|
||||
{ key: 'random-label-kconey1d', count: 50 },
|
||||
{ key: 'random-label-agoodread1e', count: 51 },
|
||||
{ key: 'random-label-nmewton1f', count: 52 },
|
||||
{ key: 'random-label-gcodman1g', count: 53 },
|
||||
{ key: 'random-label-rpoplee1h', count: 54 },
|
||||
{ key: 'random-label-mhug1i', count: 55 },
|
||||
{ key: 'random-label-ggowrie1j', count: 56 },
|
||||
{ key: 'random-label-ctonepohl1k', count: 57 },
|
||||
{ key: 'random-label-cstillman1l', count: 58 },
|
||||
{ key: 'random-label-dcollyer1m', count: 59 },
|
||||
{ key: 'random-label-idimelow1n', count: 60 },
|
||||
{ key: 'random-label-djarley1o', count: 61 },
|
||||
{ key: 'random-label-omclleese1p', count: 62 },
|
||||
{ key: 'random-label-dstivers1q', count: 63 },
|
||||
{ key: 'random-label-svose1r', count: 64 },
|
||||
{ key: 'random-label-clanfare1s', count: 65 },
|
||||
{ key: 'random-label-aport1t', count: 66 },
|
||||
{ key: 'random-label-hcarlett1u', count: 67 },
|
||||
{ key: 'random-label-dstillmann1v', count: 68 },
|
||||
{ key: 'random-label-ncorpe1w', count: 69 },
|
||||
{ key: 'random-label-mjacobsohn1x', count: 70 },
|
||||
{ key: 'random-label-ycleiment1y', count: 71 },
|
||||
{ key: 'random-label-owherton1z', count: 72 },
|
||||
{ key: 'random-label-anowaczyk20', count: 73 },
|
||||
{ key: 'random-label-rmckennan21', count: 74 },
|
||||
{ key: 'random-label-cmoulding22', count: 75 },
|
||||
{ key: 'random-label-sswate23', count: 76 },
|
||||
{ key: 'random-label-cbarge24', count: 77 },
|
||||
{ key: 'random-label-agrainger25', count: 78 },
|
||||
{ key: 'random-label-ncosin26', count: 79 },
|
||||
{ key: 'random-label-pkears27', count: 80 },
|
||||
{ key: 'random-label-cmcarthur28', count: 81 },
|
||||
{ key: 'random-label-jmantripp29', count: 82 },
|
||||
{ key: 'random-label-cjekel2a', count: 83 },
|
||||
{ key: 'random-label-hdilleway2b', count: 84 },
|
||||
{ key: 'random-label-lbovaird2c', count: 85 },
|
||||
{ key: 'random-label-mweld2d', count: 86 },
|
||||
{ key: 'random-label-marnowitz2e', count: 87 },
|
||||
{ key: 'random-label-nbertomieu2f', count: 88 },
|
||||
{ key: 'random-label-mledward2g', count: 89 },
|
||||
{ key: 'random-label-mhince2h', count: 90 },
|
||||
{ key: 'random-label-baarons2i', count: 91 },
|
||||
{ key: 'random-label-kfrancie2j', count: 92 },
|
||||
{ key: 'random-label-ishooter2k', count: 93 },
|
||||
{ key: 'random-label-glowmass2l', count: 94 },
|
||||
{ key: 'random-label-rgeorgi2m', count: 95 },
|
||||
{ key: 'random-label-bproby2n', count: 96 },
|
||||
{ key: 'random-label-hsteffan2o', count: 97 },
|
||||
{ key: 'random-label-doruane2p', count: 98 },
|
||||
{ key: 'random-label-rlunny2q', count: 99 },
|
||||
{ key: 'random-label-geles2r', count: 100 },
|
||||
{ key: 'random-label-nmaggiore2s', count: 101 },
|
||||
{ key: 'random-label-aboocock2t', count: 102 },
|
||||
{ key: 'random-label-eguilbert2u', count: 103 },
|
||||
{ key: 'random-label-emccutcheon2v', count: 104 },
|
||||
{ key: 'random-label-hcowser2w', count: 105 },
|
||||
{ key: 'random-label-dspeeding2x', count: 106 },
|
||||
{ key: 'random-label-oseebright2y', count: 107 },
|
||||
{ key: 'random-label-hpresdee2z', count: 108 },
|
||||
{ key: 'random-label-pesseby30', count: 109 },
|
||||
{ key: 'random-label-hpusey31', count: 110 },
|
||||
{ key: 'random-label-dmanthorpe32', count: 111 },
|
||||
{ key: 'random-label-natley33', count: 112 },
|
||||
{ key: 'random-label-iferentz34', count: 113 },
|
||||
{ key: 'random-label-adyble35', count: 114 },
|
||||
{ key: 'random-label-dlockitt36', count: 115 },
|
||||
{ key: 'random-label-acoxwell37', count: 116 },
|
||||
{ key: 'random-label-amcgarvey38', count: 117 },
|
||||
{ key: 'random-label-rmcgougan39', count: 118 },
|
||||
{ key: 'random-label-mscole3a', count: 119 },
|
||||
{ key: 'random-label-lmalim3b', count: 120 },
|
||||
{ key: 'random-label-cends3c', count: 121 },
|
||||
{ key: 'random-label-dmannie3d', count: 122 },
|
||||
{ key: 'random-label-lgoodricke3e', count: 123 },
|
||||
{ key: 'random-label-rcaghy3f', count: 124 },
|
||||
{ key: 'random-label-mprozillo3g', count: 125 },
|
||||
{ key: 'random-label-mcardnell3h', count: 126 },
|
||||
{ key: 'random-label-gericssen3i', count: 127 },
|
||||
{ key: 'random-label-fspooner3j', count: 128 },
|
||||
{ key: 'random-label-achadney3k', count: 129 },
|
||||
{ key: 'random-label-corchard3l', count: 130 },
|
||||
{ key: 'random-label-lyerill3m', count: 131 },
|
||||
{ key: 'random-label-jrusk3n', count: 132 },
|
||||
{ key: 'random-label-lbonelle3o', count: 133 },
|
||||
{ key: 'random-label-eduny3p', count: 134 },
|
||||
{ key: 'random-label-mhutchence3q', count: 135 },
|
||||
{ key: 'random-label-rmargeram3r', count: 136 },
|
||||
{ key: 'random-label-smaudlin3s', count: 137 },
|
||||
{ key: 'random-label-sfarrance3t', count: 138 },
|
||||
{ key: 'random-label-eclendennen3u', count: 139 },
|
||||
{ key: 'random-label-cyabsley3v', count: 140 },
|
||||
{ key: 'random-label-ahensmans3w', count: 141 },
|
||||
{ key: 'random-label-tsenchenko3x', count: 142 },
|
||||
{ key: 'random-label-ryurchishin3y', count: 143 },
|
||||
{ key: 'random-label-teby3z', count: 144 },
|
||||
{ key: 'random-label-dvaillant40', count: 145 },
|
||||
{ key: 'random-label-kpetyakov41', count: 146 },
|
||||
{ key: 'random-label-cmorrison42', count: 147 },
|
||||
{ key: 'random-label-ltwiddy43', count: 148 },
|
||||
{ key: 'random-label-ineame44', count: 149 },
|
||||
{ key: 'random-label-blucock45', count: 150 },
|
||||
{ key: 'random-label-kdunsford46', count: 151 },
|
||||
{ key: 'random-label-dducham47', count: 152 },
|
||||
{ key: 'random-label-javramovitz48', count: 153 },
|
||||
{ key: 'random-label-mascraft49', count: 154 },
|
||||
{ key: 'random-label-bloughead4a', count: 155 },
|
||||
{ key: 'random-label-sduckit4b', count: 156 },
|
||||
{ key: 'random-label-hhardman4c', count: 157 },
|
||||
{ key: 'random-label-cstaniforth4d', count: 158 },
|
||||
{ key: 'random-label-jedney4e', count: 159 },
|
||||
{ key: 'random-label-bobbard4f', count: 160 },
|
||||
{ key: 'random-label-cgiraux4g', count: 161 },
|
||||
{ key: 'random-label-tkiln4h', count: 162 },
|
||||
{ key: 'random-label-jwansbury4i', count: 163 },
|
||||
{ key: 'random-label-dquinlan4j', count: 164 },
|
||||
{ key: 'random-label-hgindghill4k', count: 165 },
|
||||
{ key: 'random-label-jjowle4l', count: 166 },
|
||||
{ key: 'random-label-egambrell4m', count: 167 },
|
||||
{ key: 'random-label-jmcgloughlin4n', count: 168 },
|
||||
{ key: 'random-label-bbabb4o', count: 169 },
|
||||
{ key: 'random-label-achuck4p', count: 170 },
|
||||
{ key: 'random-label-tsyers4q', count: 171 },
|
||||
{ key: 'random-label-jlandon4r', count: 172 },
|
||||
{ key: 'random-label-wteather4s', count: 173 },
|
||||
{ key: 'random-label-dfoskin4t', count: 174 },
|
||||
{ key: 'random-label-gmorlon4u', count: 175 },
|
||||
{ key: 'random-label-jseely4v', count: 176 },
|
||||
{ key: 'random-label-cbrass4w', count: 177 },
|
||||
{ key: 'random-label-fmanilo4x', count: 178 },
|
||||
{ key: 'random-label-bfrangleton4y', count: 179 },
|
||||
{ key: 'random-label-vbartkiewicz4z', count: 180 },
|
||||
{ key: 'random-label-tclymer50', count: 181 },
|
||||
{ key: 'random-label-pqueen51', count: 182 },
|
||||
{ key: 'random-label-bpol52', count: 183 },
|
||||
{ key: 'random-label-jclaeskens53', count: 184 },
|
||||
{ key: 'random-label-cstranieri54', count: 185 },
|
||||
{ key: 'random-label-drumbelow55', count: 186 },
|
||||
{ key: 'random-label-wbrumham56', count: 187 },
|
||||
{ key: 'random-label-azeal57', count: 188 },
|
||||
{ key: 'random-label-msnooks58', count: 189 },
|
||||
{ key: 'random-label-blapre59', count: 190 },
|
||||
{ key: 'random-label-cduckers5a', count: 191 },
|
||||
{ key: 'random-label-mgumary5b', count: 192 },
|
||||
{ key: 'random-label-rtebbs5c', count: 193 },
|
||||
{ key: 'random-label-eroe5d', count: 194 },
|
||||
{ key: 'random-label-rconfait5e', count: 195 },
|
||||
{ key: 'random-label-fsinderland5f', count: 196 },
|
||||
{ key: 'random-label-tdallywater5g', count: 197 },
|
||||
{ key: 'random-label-glindenman5h', count: 198 },
|
||||
{ key: 'random-label-fbauser5i', count: 199 },
|
||||
{ key: 'random-label-bdownton5j', count: 200 },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export const MOCK_LANGUAGE_AGGREGATIONS_BUCKETS = [
|
||||
{ key: 'random-label-edumingos0', count: 1 },
|
||||
{ key: 'random-label-rbourgourd1', count: 2 },
|
||||
|
|
@ -604,13 +397,27 @@ export const MOCK_LANGUAGE_AGGREGATIONS_BUCKETS = [
|
|||
{ key: 'random-label-bdownton5j', count: 200 },
|
||||
];
|
||||
|
||||
export const MOCK_AGGREGATIONS = [
|
||||
{
|
||||
name: 'language',
|
||||
buckets: MOCK_LANGUAGE_AGGREGATIONS_BUCKETS,
|
||||
},
|
||||
];
|
||||
|
||||
export const SORTED_MOCK_AGGREGATIONS = [
|
||||
{
|
||||
name: 'language',
|
||||
buckets: MOCK_LANGUAGE_AGGREGATIONS_BUCKETS.reverse(),
|
||||
},
|
||||
];
|
||||
|
||||
export const MOCK_RECEIVE_AGGREGATIONS_SUCCESS_MUTATION = [
|
||||
{
|
||||
type: types.REQUEST_AGGREGATIONS,
|
||||
},
|
||||
{
|
||||
type: types.RECEIVE_AGGREGATIONS_SUCCESS,
|
||||
payload: MOCK_AGGREGATIONS,
|
||||
payload: SORTED_MOCK_AGGREGATIONS,
|
||||
},
|
||||
];
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { MOCK_QUERY } from 'jest/search/mock_data';
|
|||
import GlobalSearchSidebar from '~/search/sidebar/components/app.vue';
|
||||
import ResultsFilters from '~/search/sidebar/components/results_filters.vue';
|
||||
import ScopeNavigation from '~/search/sidebar/components/scope_navigation.vue';
|
||||
import LanguageFilter from '~/search/sidebar/components/language_filter.vue';
|
||||
import LanguageFilter from '~/search/sidebar/components/language_filter/index.vue';
|
||||
|
||||
Vue.use(Vuex);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,17 +1,22 @@
|
|||
import { GlFormCheckboxGroup, GlFormCheckbox } from '@gitlab/ui';
|
||||
import Vue from 'vue';
|
||||
import Vuex from 'vuex';
|
||||
import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
|
||||
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import { MOCK_QUERY, MOCK_LANGUAGE_AGGREGATIONS_BUCKETS } from 'jest/search/mock_data';
|
||||
import CheckboxFilter from '~/search/sidebar/components/checkbox_filter.vue';
|
||||
import CheckboxFilter, {
|
||||
TRACKING_LABEL_CHECKBOX,
|
||||
TRACKING_LABEL_SET,
|
||||
} from '~/search/sidebar/components/checkbox_filter.vue';
|
||||
|
||||
import { languageFilterData } from '~/search/sidebar/constants/language_filter_data';
|
||||
import { languageFilterData } from '~/search/sidebar/components/language_filter/data';
|
||||
import { convertFiltersData } from '~/search/sidebar/utils';
|
||||
|
||||
Vue.use(Vuex);
|
||||
|
||||
describe('CheckboxFilter', () => {
|
||||
let wrapper;
|
||||
let trackingSpy;
|
||||
|
||||
const actionSpies = {
|
||||
setQuery: jest.fn(),
|
||||
|
|
@ -23,9 +28,10 @@ describe('CheckboxFilter', () => {
|
|||
|
||||
const defaultProps = {
|
||||
filtersData: convertFiltersData(MOCK_LANGUAGE_AGGREGATIONS_BUCKETS),
|
||||
trackingNamespace: 'testNameSpace',
|
||||
};
|
||||
|
||||
const createComponent = () => {
|
||||
const createComponent = (Props = defaultProps) => {
|
||||
const store = new Vuex.Store({
|
||||
state: {
|
||||
query: MOCK_QUERY,
|
||||
|
|
@ -37,13 +43,13 @@ describe('CheckboxFilter', () => {
|
|||
wrapper = shallowMountExtended(CheckboxFilter, {
|
||||
store,
|
||||
propsData: {
|
||||
...defaultProps,
|
||||
...Props,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
createComponent();
|
||||
afterEach(() => {
|
||||
unmockTracking();
|
||||
});
|
||||
|
||||
const findFormCheckboxGroup = () => wrapper.findComponent(GlFormCheckboxGroup);
|
||||
|
|
@ -52,6 +58,11 @@ describe('CheckboxFilter', () => {
|
|||
const fintAllCheckboxLabelCounts = () => wrapper.findAllByTestId('labelCount');
|
||||
|
||||
describe('Renders correctly', () => {
|
||||
beforeEach(() => {
|
||||
createComponent();
|
||||
trackingSpy = mockTracking(undefined, undefined, jest.spyOn);
|
||||
});
|
||||
|
||||
it('renders form', () => {
|
||||
expect(findFormCheckboxGroup().exists()).toBe(true);
|
||||
});
|
||||
|
|
@ -76,15 +87,34 @@ describe('CheckboxFilter', () => {
|
|||
});
|
||||
|
||||
describe('actions', () => {
|
||||
it('triggers setQuery', () => {
|
||||
const filter =
|
||||
defaultProps.filtersData.filters[Object.keys(defaultProps.filtersData.filters)[0]].value;
|
||||
findFormCheckboxGroup().vm.$emit('input', filter);
|
||||
const checkedLanguageName = MOCK_LANGUAGE_AGGREGATIONS_BUCKETS[0].key;
|
||||
|
||||
beforeEach(async () => {
|
||||
defaultProps.filtersData = convertFiltersData(MOCK_LANGUAGE_AGGREGATIONS_BUCKETS.slice(0, 3));
|
||||
CheckboxFilter.computed.selectedFilter.get = jest.fn(() => checkedLanguageName);
|
||||
|
||||
createComponent();
|
||||
trackingSpy = mockTracking(undefined, undefined, jest.spyOn);
|
||||
findFormCheckboxGroup().vm.$emit('input', checkedLanguageName);
|
||||
});
|
||||
|
||||
it('triggers setQuery', () => {
|
||||
expect(actionSpies.setQuery).toHaveBeenCalledWith(expect.any(Object), {
|
||||
key: languageFilterData.filterParam,
|
||||
value: filter,
|
||||
value: checkedLanguageName,
|
||||
});
|
||||
});
|
||||
|
||||
it('sends tracking information when setQuery', () => {
|
||||
findFormCheckboxGroup().vm.$emit('input', checkedLanguageName);
|
||||
expect(trackingSpy).toHaveBeenCalledWith(
|
||||
defaultProps.trackingNamespace,
|
||||
TRACKING_LABEL_CHECKBOX,
|
||||
{
|
||||
label: TRACKING_LABEL_SET,
|
||||
property: checkedLanguageName,
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,20 +1,35 @@
|
|||
import { GlAlert, GlFormCheckbox, GlForm } from '@gitlab/ui';
|
||||
import Vue, { nextTick } from 'vue';
|
||||
import Vuex from 'vuex';
|
||||
import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
|
||||
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import {
|
||||
MOCK_QUERY,
|
||||
MOCK_AGGREGATIONS,
|
||||
MOCK_LANGUAGE_AGGREGATIONS_BUCKETS,
|
||||
} from 'jest/search/mock_data';
|
||||
import LanguageFilter from '~/search/sidebar/components/language_filter.vue';
|
||||
import LanguageFilter from '~/search/sidebar/components/language_filter/index.vue';
|
||||
import CheckboxFilter from '~/search/sidebar/components/checkbox_filter.vue';
|
||||
import { MAX_ITEM_LENGTH } from '~/search/sidebar/constants/language_filter_data';
|
||||
|
||||
import {
|
||||
TRACKING_LABEL_SHOW_MORE,
|
||||
TRACKING_CATEGORY,
|
||||
TRACKING_PROPERTY_MAX,
|
||||
TRACKING_LABEL_MAX,
|
||||
TRACKING_LABEL_FILTERS,
|
||||
TRACKING_ACTION_SHOW,
|
||||
TRACKING_ACTION_CLICK,
|
||||
TRACKING_LABEL_APPLY,
|
||||
TRACKING_LABEL_ALL,
|
||||
} from '~/search/sidebar/components/language_filter/tracking';
|
||||
|
||||
import { MAX_ITEM_LENGTH } from '~/search/sidebar/components/language_filter/data';
|
||||
|
||||
Vue.use(Vuex);
|
||||
|
||||
describe('GlobalSearchSidebarLanguageFilter', () => {
|
||||
let wrapper;
|
||||
let trackingSpy;
|
||||
|
||||
const actionSpies = {
|
||||
fetchLanguageAggregation: jest.fn(),
|
||||
|
|
@ -46,6 +61,10 @@ describe('GlobalSearchSidebarLanguageFilter', () => {
|
|||
});
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
unmockTracking();
|
||||
});
|
||||
|
||||
const findForm = () => wrapper.findComponent(GlForm);
|
||||
const findCheckboxFilter = () => wrapper.findComponent(CheckboxFilter);
|
||||
const findApplyButton = () => wrapper.findByTestId('apply-button');
|
||||
|
|
@ -58,6 +77,7 @@ describe('GlobalSearchSidebarLanguageFilter', () => {
|
|||
describe('Renders correctly', () => {
|
||||
beforeEach(() => {
|
||||
createComponent();
|
||||
trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
|
||||
});
|
||||
|
||||
it('renders form', () => {
|
||||
|
|
@ -130,20 +150,40 @@ describe('GlobalSearchSidebarLanguageFilter', () => {
|
|||
describe('Show All button works', () => {
|
||||
beforeEach(() => {
|
||||
createComponent();
|
||||
trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
|
||||
});
|
||||
|
||||
it(`renders ${MAX_ITEM_LENGTH} amount of items`, async () => {
|
||||
findShowMoreButton().vm.$emit('click');
|
||||
|
||||
await nextTick();
|
||||
|
||||
expect(findAllCheckboxes()).toHaveLength(MAX_ITEM_LENGTH);
|
||||
});
|
||||
|
||||
it('sends tracking information when show more clicked', () => {
|
||||
findShowMoreButton().vm.$emit('click');
|
||||
|
||||
expect(trackingSpy).toHaveBeenCalledWith(TRACKING_ACTION_CLICK, TRACKING_LABEL_SHOW_MORE, {
|
||||
label: TRACKING_LABEL_ALL,
|
||||
});
|
||||
});
|
||||
|
||||
it(`renders more then ${MAX_ITEM_LENGTH} text`, async () => {
|
||||
findShowMoreButton().vm.$emit('click');
|
||||
await nextTick();
|
||||
expect(findHasOverMax().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('sends tracking information when show more clicked and max item reached', () => {
|
||||
findShowMoreButton().vm.$emit('click');
|
||||
|
||||
expect(trackingSpy).toHaveBeenCalledWith(TRACKING_ACTION_SHOW, TRACKING_LABEL_FILTERS, {
|
||||
label: TRACKING_LABEL_MAX,
|
||||
property: TRACKING_PROPERTY_MAX,
|
||||
});
|
||||
});
|
||||
|
||||
it(`doesn't render show more button after click`, async () => {
|
||||
findShowMoreButton().vm.$emit('click');
|
||||
await nextTick();
|
||||
|
|
@ -154,6 +194,7 @@ describe('GlobalSearchSidebarLanguageFilter', () => {
|
|||
describe('actions', () => {
|
||||
beforeEach(() => {
|
||||
createComponent({});
|
||||
trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
|
||||
});
|
||||
|
||||
it('uses getter languageAggregationBuckets', () => {
|
||||
|
|
@ -169,5 +210,13 @@ describe('GlobalSearchSidebarLanguageFilter', () => {
|
|||
|
||||
expect(actionSpies.applyQuery).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('sends tracking information clicking ApplyButton', () => {
|
||||
findForm().vm.$emit('submit', { preventDefault: () => {} });
|
||||
|
||||
expect(trackingSpy).toHaveBeenCalledWith(TRACKING_ACTION_CLICK, TRACKING_LABEL_APPLY, {
|
||||
label: TRACKING_CATEGORY,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ import Vue from 'vue';
|
|||
import VueApollo from 'vue-apollo';
|
||||
import VuexModuleProvider from '~/vue_shared/components/vuex_module_provider.vue';
|
||||
|
||||
const TestComponent = Vue.extend({
|
||||
const TestComponent = {
|
||||
inject: ['vuexModule'],
|
||||
template: `<div data-testid="vuexModule">{{ vuexModule }}</div> `,
|
||||
});
|
||||
};
|
||||
|
||||
const TEST_VUEX_MODULE = 'testVuexModule';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { GlLink } from '@gitlab/ui';
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import { nextTick } from 'vue';
|
||||
import { useFakeDate } from 'helpers/fake_date';
|
||||
|
||||
import IssuableBody from '~/vue_shared/issuable/show/components/issuable_body.vue';
|
||||
|
|
@ -14,96 +14,76 @@ import { mockIssuableShowProps, mockIssuable } from '../mock_data';
|
|||
|
||||
jest.mock('~/autosave');
|
||||
jest.mock('~/alert');
|
||||
jest.mock('~/task_list');
|
||||
|
||||
const issuableBodyProps = {
|
||||
...mockIssuableShowProps,
|
||||
issuable: mockIssuable,
|
||||
};
|
||||
|
||||
const createComponent = (propsData = issuableBodyProps) =>
|
||||
shallowMount(IssuableBody, {
|
||||
propsData,
|
||||
stubs: {
|
||||
IssuableTitle,
|
||||
IssuableDescription,
|
||||
IssuableEditForm,
|
||||
TimeAgoTooltip,
|
||||
},
|
||||
slots: {
|
||||
'status-badge': 'Open',
|
||||
'edit-form-actions': `
|
||||
<button class="js-save">Save changes</button>
|
||||
<button class="js-cancel">Cancel</button>
|
||||
`,
|
||||
},
|
||||
});
|
||||
|
||||
describe('IssuableBody', () => {
|
||||
// Some assertions expect a date later than our default
|
||||
useFakeDate(2020, 11, 11);
|
||||
|
||||
let wrapper;
|
||||
|
||||
const createComponent = (propsData = {}) => {
|
||||
wrapper = shallowMount(IssuableBody, {
|
||||
propsData: {
|
||||
...issuableBodyProps,
|
||||
...propsData,
|
||||
},
|
||||
stubs: {
|
||||
IssuableTitle,
|
||||
IssuableDescription,
|
||||
IssuableEditForm,
|
||||
TimeAgoTooltip,
|
||||
},
|
||||
slots: {
|
||||
'status-badge': 'Open',
|
||||
'edit-form-actions': `
|
||||
<button class="js-save">Save changes</button>
|
||||
<button class="js-cancel">Cancel</button>
|
||||
`,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const findUpdatedLink = () => wrapper.findComponent(GlLink);
|
||||
const findIssuableEditForm = () => wrapper.findComponent(IssuableEditForm);
|
||||
const findIssuableEditFormButton = (type) => findIssuableEditForm().find(`button.js-${type}`);
|
||||
const findIssuableTitle = () => wrapper.findComponent(IssuableTitle);
|
||||
|
||||
beforeEach(() => {
|
||||
wrapper = createComponent();
|
||||
createComponent();
|
||||
TaskList.mockClear();
|
||||
});
|
||||
|
||||
describe('computed', () => {
|
||||
describe('isUpdated', () => {
|
||||
it.each`
|
||||
updatedAt | returnValue
|
||||
${mockIssuable.updatedAt} | ${true}
|
||||
${null} | ${false}
|
||||
${''} | ${false}
|
||||
`(
|
||||
'returns $returnValue when value of `updateAt` prop is `$updatedAt`',
|
||||
async ({ updatedAt, returnValue }) => {
|
||||
wrapper.setProps({
|
||||
issuable: {
|
||||
...mockIssuable,
|
||||
updatedAt,
|
||||
},
|
||||
});
|
||||
|
||||
await nextTick();
|
||||
|
||||
expect(wrapper.vm.isUpdated).toBe(returnValue);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
describe('updatedBy', () => {
|
||||
it('returns value of `issuable.updatedBy`', () => {
|
||||
expect(wrapper.vm.updatedBy).toBe(mockIssuable.updatedBy);
|
||||
expect(findUpdatedLink().text()).toBe(mockIssuable.updatedBy.name);
|
||||
expect(findUpdatedLink().attributes('href')).toBe(mockIssuable.updatedBy.webUrl);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('watchers', () => {
|
||||
describe('editFormVisible', () => {
|
||||
it('calls initTaskList in nextTick', async () => {
|
||||
jest.spyOn(wrapper.vm, 'initTaskList');
|
||||
wrapper.setProps({
|
||||
editFormVisible: true,
|
||||
});
|
||||
|
||||
await nextTick();
|
||||
|
||||
wrapper.setProps({
|
||||
it('calls initTaskList in nextTick', () => {
|
||||
createComponent({
|
||||
editFormVisible: false,
|
||||
});
|
||||
|
||||
await nextTick();
|
||||
|
||||
expect(wrapper.vm.initTaskList).toHaveBeenCalled();
|
||||
expect(TaskList).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('mounted', () => {
|
||||
it('initializes TaskList instance when enabledEdit and enableTaskList props are true', () => {
|
||||
expect(wrapper.vm.taskList instanceof TaskList).toBe(true);
|
||||
expect(wrapper.vm.taskList).toMatchObject({
|
||||
createComponent();
|
||||
expect(TaskList).toHaveBeenCalledWith({
|
||||
dataType: 'issue',
|
||||
fieldName: 'description',
|
||||
lockVersion: issuableBodyProps.taskListLockVersion,
|
||||
|
|
@ -114,14 +94,12 @@ describe('IssuableBody', () => {
|
|||
});
|
||||
|
||||
it('does not initialize TaskList instance when either enabledEdit or enableTaskList prop is false', () => {
|
||||
const wrapperNoTaskList = createComponent({
|
||||
createComponent({
|
||||
...issuableBodyProps,
|
||||
enableTaskList: false,
|
||||
});
|
||||
|
||||
expect(wrapperNoTaskList.vm.taskList).not.toBeDefined();
|
||||
|
||||
wrapperNoTaskList.destroy();
|
||||
expect(TaskList).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -150,10 +128,8 @@ describe('IssuableBody', () => {
|
|||
|
||||
describe('template', () => {
|
||||
it('renders issuable-title component', () => {
|
||||
const titleEl = wrapper.findComponent(IssuableTitle);
|
||||
|
||||
expect(titleEl.exists()).toBe(true);
|
||||
expect(titleEl.props()).toMatchObject({
|
||||
expect(findIssuableTitle().exists()).toBe(true);
|
||||
expect(findIssuableTitle().props()).toMatchObject({
|
||||
issuable: issuableBodyProps.issuable,
|
||||
statusIcon: issuableBodyProps.statusIcon,
|
||||
enableEdit: issuableBodyProps.enableEdit,
|
||||
|
|
@ -168,42 +144,37 @@ describe('IssuableBody', () => {
|
|||
});
|
||||
|
||||
it('renders issuable edit info', () => {
|
||||
const editedEl = wrapper.find('small');
|
||||
|
||||
expect(editedEl.text()).toMatchInterpolatedText('Edited 3 months ago by Administrator');
|
||||
expect(wrapper.find('small').text()).toMatchInterpolatedText(
|
||||
'Edited 3 months ago by Administrator',
|
||||
);
|
||||
});
|
||||
|
||||
it('renders issuable-edit-form when `editFormVisible` prop is true', async () => {
|
||||
wrapper.setProps({
|
||||
it('renders issuable-edit-form when `editFormVisible` prop is true', () => {
|
||||
createComponent({
|
||||
editFormVisible: true,
|
||||
});
|
||||
|
||||
await nextTick();
|
||||
|
||||
const editFormEl = wrapper.findComponent(IssuableEditForm);
|
||||
expect(editFormEl.exists()).toBe(true);
|
||||
expect(editFormEl.props()).toMatchObject({
|
||||
expect(findIssuableEditForm().exists()).toBe(true);
|
||||
expect(findIssuableEditForm().props()).toMatchObject({
|
||||
issuable: issuableBodyProps.issuable,
|
||||
enableAutocomplete: issuableBodyProps.enableAutocomplete,
|
||||
descriptionPreviewPath: issuableBodyProps.descriptionPreviewPath,
|
||||
descriptionHelpPath: issuableBodyProps.descriptionHelpPath,
|
||||
});
|
||||
expect(editFormEl.find('button.js-save').exists()).toBe(true);
|
||||
expect(editFormEl.find('button.js-cancel').exists()).toBe(true);
|
||||
expect(findIssuableEditFormButton('save').exists()).toBe(true);
|
||||
expect(findIssuableEditFormButton('cancel').exists()).toBe(true);
|
||||
});
|
||||
|
||||
describe('events', () => {
|
||||
it('component emits `edit-issuable` event bubbled via issuable-title', () => {
|
||||
const issuableTitle = wrapper.findComponent(IssuableTitle);
|
||||
|
||||
issuableTitle.vm.$emit('edit-issuable');
|
||||
findIssuableTitle().vm.$emit('edit-issuable');
|
||||
|
||||
expect(wrapper.emitted('edit-issuable')).toHaveLength(1);
|
||||
});
|
||||
|
||||
it.each(['keydown-title', 'keydown-description'])(
|
||||
'component emits `%s` event with event object and issuableMeta params via issuable-edit-form',
|
||||
async (eventName) => {
|
||||
(eventName) => {
|
||||
const eventObj = {
|
||||
preventDefault: jest.fn(),
|
||||
stopPropagation: jest.fn(),
|
||||
|
|
@ -213,15 +184,11 @@ describe('IssuableBody', () => {
|
|||
issuableDescription: 'foobar',
|
||||
};
|
||||
|
||||
wrapper.setProps({
|
||||
createComponent({
|
||||
editFormVisible: true,
|
||||
});
|
||||
|
||||
await nextTick();
|
||||
|
||||
const issuableEditForm = wrapper.findComponent(IssuableEditForm);
|
||||
|
||||
issuableEditForm.vm.$emit(eventName, eventObj, issuableMeta);
|
||||
findIssuableEditForm().vm.$emit(eventName, eventObj, issuableMeta);
|
||||
|
||||
expect(wrapper.emitted(eventName)).toHaveLength(1);
|
||||
expect(wrapper.emitted(eventName)[0]).toMatchObject([eventObj, issuableMeta]);
|
||||
|
|
|
|||
|
|
@ -2,15 +2,15 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'Net::HTTPResponse patch header read timeout' do
|
||||
RSpec.describe 'Net::HTTPResponse patch header read timeout', feature_category: :integrations do
|
||||
describe '.each_response_header' do
|
||||
let(:server_response) do
|
||||
<<~EOS
|
||||
<<~HTTP
|
||||
Content-Type: text/html
|
||||
Header-Two: foo
|
||||
|
||||
Hello World
|
||||
EOS
|
||||
HTTP
|
||||
end
|
||||
|
||||
before do
|
||||
|
|
@ -30,14 +30,12 @@ RSpec.describe 'Net::HTTPResponse patch header read timeout' do
|
|||
end
|
||||
|
||||
context 'when the response contains many consecutive spaces' do
|
||||
before do
|
||||
it 'has no regex backtracking issues' do
|
||||
expect(socket).to receive(:readuntil).and_return(
|
||||
"a: #{' ' * 100_000} b",
|
||||
''
|
||||
)
|
||||
end
|
||||
|
||||
it 'has no regex backtracking issues' do
|
||||
Timeout.timeout(1) do
|
||||
each_response_header
|
||||
end
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe BlobViewer::PackageJson do
|
||||
RSpec.describe BlobViewer::PackageJson, feature_category: :source_code_management do
|
||||
include FakeBlobHelpers
|
||||
|
||||
let(:project) { build_stubbed(:project) }
|
||||
|
|
@ -59,6 +59,17 @@ RSpec.describe BlobViewer::PackageJson do
|
|||
expect(subject.manager_url).to eq("https://yarnpkg.com/")
|
||||
end
|
||||
end
|
||||
|
||||
context 'when json is an array' do
|
||||
let(:data) { '[]' }
|
||||
|
||||
it 'does not raise an error', :aggregate_failures do
|
||||
expect(subject).to receive(:prepare!)
|
||||
|
||||
expect { subject.yarn? }.not_to raise_error
|
||||
expect(subject.yarn?).to be_falsey
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'npm' do
|
||||
|
|
|
|||
|
|
@ -0,0 +1,155 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'tempfile'
|
||||
require_relative '../../../../tooling/lib/tooling/find_tests'
|
||||
require_relative '../../../support/helpers/stub_env'
|
||||
|
||||
RSpec.describe Tooling::FindTests, feature_category: :tooling do
|
||||
include StubENV
|
||||
|
||||
attr_accessor :changes_file, :matching_tests_paths
|
||||
|
||||
let(:instance) { described_class.new(changes_file, matching_tests_paths) }
|
||||
let(:mock_test_file_finder) { instance_double(TestFileFinder::FileFinder) }
|
||||
let(:new_matching_tests) { ["new_matching_spec.rb"] }
|
||||
let(:changes_file_content) { "changed_file1 changed_file2" }
|
||||
let(:matching_tests_paths_content) { "previously_matching_spec.rb" }
|
||||
|
||||
around do |example|
|
||||
self.changes_file = Tempfile.new('changes')
|
||||
self.matching_tests_paths = Tempfile.new('matching_tests')
|
||||
|
||||
# See https://ruby-doc.org/stdlib-1.9.3/libdoc/tempfile/rdoc/
|
||||
# Tempfile.html#class-Tempfile-label-Explicit+close
|
||||
begin
|
||||
example.run
|
||||
ensure
|
||||
changes_file.close
|
||||
matching_tests_paths.close
|
||||
changes_file.unlink
|
||||
matching_tests_paths.unlink
|
||||
end
|
||||
end
|
||||
|
||||
before do
|
||||
allow(mock_test_file_finder).to receive(:use)
|
||||
allow(mock_test_file_finder).to receive(:test_files).and_return(new_matching_tests)
|
||||
allow(TestFileFinder::FileFinder).to receive(:new).and_return(mock_test_file_finder)
|
||||
|
||||
stub_env(
|
||||
'RSPEC_TESTS_MAPPING_ENABLED' => nil,
|
||||
'RSPEC_TESTS_MAPPING_PATH' => '/tmp/does-not-exist.out'
|
||||
)
|
||||
|
||||
# We write into the temp files initially, to later check how the code modified those files
|
||||
File.write(changes_file, changes_file_content)
|
||||
File.write(matching_tests_paths, matching_tests_paths_content)
|
||||
end
|
||||
|
||||
describe '#execute' do
|
||||
subject { instance.execute }
|
||||
|
||||
context 'when the matching_tests_paths file does not exist' do
|
||||
before do
|
||||
allow(File).to receive(:exist?).and_return(false)
|
||||
allow(File).to receive(:write).with(matching_tests_paths, any_args)
|
||||
end
|
||||
|
||||
it 'creates an empty file' do
|
||||
expect(File).to receive(:write).with(matching_tests_paths, '')
|
||||
|
||||
subject
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the matching_tests_paths file already exists' do
|
||||
it 'does not create an empty file' do
|
||||
expect(File).not_to receive(:write).with(matching_tests_paths, '')
|
||||
|
||||
subject
|
||||
end
|
||||
end
|
||||
|
||||
it 'does not modify the content of the input file' do
|
||||
expect { subject }.not_to change { File.read(changes_file) }
|
||||
end
|
||||
|
||||
it 'does not overwrite the output file' do
|
||||
expect { subject }.to change { File.read(matching_tests_paths) }
|
||||
.from(matching_tests_paths_content)
|
||||
.to("#{matching_tests_paths_content} #{new_matching_tests.uniq.join(' ')}")
|
||||
end
|
||||
|
||||
it 'loads the tests.yml file with a pattern matching mapping' do
|
||||
expect(TestFileFinder::MappingStrategies::PatternMatching).to receive(:load).with('tests.yml')
|
||||
|
||||
subject
|
||||
end
|
||||
|
||||
context 'when RSPEC_TESTS_MAPPING_ENABLED env variable is set' do
|
||||
before do
|
||||
stub_env(
|
||||
'RSPEC_TESTS_MAPPING_ENABLED' => 'true',
|
||||
'RSPEC_TESTS_MAPPING_PATH' => 'crystalball-test/mapping.json'
|
||||
)
|
||||
end
|
||||
|
||||
it 'loads the direct matching pattern file' do
|
||||
expect(TestFileFinder::MappingStrategies::DirectMatching)
|
||||
.to receive(:load_json)
|
||||
.with('crystalball-test/mapping.json')
|
||||
|
||||
subject
|
||||
end
|
||||
end
|
||||
|
||||
context 'when RSPEC_TESTS_MAPPING_ENABLED env variable is not set' do
|
||||
let(:rspec_tests_mapping_enabled) { '' }
|
||||
|
||||
before do
|
||||
stub_env(
|
||||
'RSPEC_TESTS_MAPPING_ENABLED' => rspec_tests_mapping_enabled,
|
||||
'RSPEC_TESTS_MAPPING_PATH' => rspec_tests_mapping_path
|
||||
)
|
||||
end
|
||||
|
||||
context 'when RSPEC_TESTS_MAPPING_PATH is set' do
|
||||
let(:rspec_tests_mapping_path) { 'crystalball-test/mapping.json' }
|
||||
|
||||
it 'does not load the direct matching pattern file' do
|
||||
expect(TestFileFinder::MappingStrategies::DirectMatching).not_to receive(:load_json)
|
||||
|
||||
subject
|
||||
end
|
||||
end
|
||||
|
||||
context 'when RSPEC_TESTS_MAPPING_PATH is not set' do
|
||||
let(:rspec_tests_mapping_path) { nil }
|
||||
|
||||
it 'does not load the direct matching pattern file' do
|
||||
expect(TestFileFinder::MappingStrategies::DirectMatching).not_to receive(:load_json)
|
||||
|
||||
subject
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the same spec is matching multiple times' do
|
||||
let(:new_matching_tests) do
|
||||
[
|
||||
"new_matching_spec.rb",
|
||||
"duplicate_spec.rb",
|
||||
"duplicate_spec.rb"
|
||||
]
|
||||
end
|
||||
|
||||
it 'writes uniquely matching specs to the output' do
|
||||
subject
|
||||
|
||||
expect(File.read(matching_tests_paths).split(' ')).to match_array(
|
||||
matching_tests_paths_content.split(' ') + new_matching_tests.uniq
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -230,12 +230,12 @@ RSpec.describe Tooling::Mappings::ViewToJsMappings, feature_category: :tooling d
|
|||
= render partial: "subfolder/my-partial4"
|
||||
= render(partial:"subfolder/my-partial5", path: 'else')
|
||||
= render partial:"subfolder/my-partial6"
|
||||
= render_if_exist("subfolder/my-partial7", path: 'else')
|
||||
= render_if_exist "subfolder/my-partial8"
|
||||
= render_if_exist(partial: "subfolder/my-partial9", path: 'else')
|
||||
= render_if_exist partial: "subfolder/my-partial10"
|
||||
= render_if_exist(partial:"subfolder/my-partial11", path: 'else')
|
||||
= render_if_exist partial:"subfolder/my-partial12"
|
||||
= render_if_exists("subfolder/my-partial7", path: 'else')
|
||||
= render_if_exists "subfolder/my-partial8"
|
||||
= render_if_exists(partial: "subfolder/my-partial9", path: 'else')
|
||||
= render_if_exists partial: "subfolder/my-partial10"
|
||||
= render_if_exists(partial:"subfolder/my-partial11", path: 'else')
|
||||
= render_if_exists partial:"subfolder/my-partial12"
|
||||
|
||||
End of file
|
||||
FILE
|
||||
|
|
|
|||
|
|
@ -6,10 +6,6 @@ RSpec.describe 'layouts/application' do
|
|||
let(:user) { create(:user) }
|
||||
|
||||
before do
|
||||
allow(view).to receive(:current_application_settings).and_return(Gitlab::CurrentSettings.current_application_settings)
|
||||
allow(view).to receive(:experiment_enabled?).and_return(false)
|
||||
allow(view).to receive(:session).and_return({})
|
||||
allow(view).to receive(:user_signed_in?).and_return(true)
|
||||
allow(view).to receive(:current_user).and_return(user)
|
||||
allow(view).to receive(:current_user_mode).and_return(Gitlab::Auth::CurrentUserMode.new(user))
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,19 +1,9 @@
|
|||
#!/usr/bin/env ruby
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'test_file_finder'
|
||||
require_relative '../lib/tooling/find_tests'
|
||||
|
||||
changes = ARGV.shift
|
||||
output_file = ARGV.shift
|
||||
changes_file = ARGV.shift
|
||||
matching_tests_paths = ARGV.shift
|
||||
|
||||
changed_files = File.read(changes).split(' ')
|
||||
|
||||
tff = TestFileFinder::FileFinder.new(paths: changed_files).tap do |file_finder|
|
||||
file_finder.use TestFileFinder::MappingStrategies::PatternMatching.load('tests.yml')
|
||||
|
||||
if ENV['RSPEC_TESTS_MAPPING_ENABLED']
|
||||
file_finder.use TestFileFinder::MappingStrategies::DirectMatching.load_json(ENV['RSPEC_TESTS_MAPPING_PATH'])
|
||||
end
|
||||
end
|
||||
|
||||
File.write(output_file, tff.test_files.uniq.join(' '))
|
||||
Tooling::FindTests.new(changes_file, matching_tests_paths).execute
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'test_file_finder'
|
||||
|
||||
module Tooling
|
||||
class FindTests
|
||||
def initialize(changes_file, matching_tests_paths)
|
||||
@matching_tests_paths = matching_tests_paths
|
||||
@changed_files = File.read(changes_file).split(' ')
|
||||
|
||||
File.write(matching_tests_paths, '') unless File.exist?(matching_tests_paths)
|
||||
|
||||
@matching_tests = File.read(matching_tests_paths).split(' ')
|
||||
end
|
||||
|
||||
def execute
|
||||
tff = TestFileFinder::FileFinder.new(paths: changed_files).tap do |file_finder|
|
||||
file_finder.use TestFileFinder::MappingStrategies::PatternMatching.load('tests.yml')
|
||||
|
||||
if ENV['RSPEC_TESTS_MAPPING_ENABLED'] == 'true'
|
||||
file_finder.use TestFileFinder::MappingStrategies::DirectMatching.load_json(ENV['RSPEC_TESTS_MAPPING_PATH'])
|
||||
end
|
||||
end
|
||||
|
||||
new_matching_tests = tff.test_files.uniq
|
||||
File.write(matching_tests_paths, (matching_tests + new_matching_tests).join(' '))
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :changed_files, :matching_tests, :matching_tests_paths
|
||||
end
|
||||
end
|
||||
|
|
@ -11,7 +11,7 @@ module Tooling
|
|||
HTML_ATTRIBUTE_VALUE_REGEXP = /js-[-\w]+/.freeze
|
||||
|
||||
# Search for Rails partials included in an HTML file
|
||||
RAILS_PARTIAL_INVOCATION_REGEXP = %r{(?:render|render_if_exist)(?: |\()(?:partial: ?)?['"]([\w/-]+)['"]}.freeze
|
||||
RAILS_PARTIAL_INVOCATION_REGEXP = %r{(?:render|render_if_exists)(?: |\()(?:partial: ?)?['"]([\w/-]+)['"]}.freeze
|
||||
|
||||
def initialize(view_base_folder: 'app/views', js_base_folder: 'app/assets/javascripts')
|
||||
@view_base_folders = folders_for_available_editions(view_base_folder)
|
||||
|
|
|
|||
Loading…
Reference in New Issue