Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2023-03-20 12:15:52 +00:00
parent b762fdffd0
commit fa10e47f6e
65 changed files with 719 additions and 659 deletions

View File

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

View File

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

View File

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

View File

@ -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,
});

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -221,6 +221,7 @@ graph LR;
MergeRequestLastBuildFinished --> MergeRequestLabelRemoved;
MergeRequestLabelAdded --> MergeRequestLabelAdded;
MergeRequestLabelAdded --> MergeRequestLabelRemoved;
MergeRequestLabelAdded --> MergeRequestMerged;
MergeRequestLabelRemoved --> MergeRequestLabelAdded;
MergeRequestLabelRemoved --> MergeRequestLabelRemoved;
```

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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,
},
];

View File

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

View File

@ -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,
},
);
});
});
});

View File

@ -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,
});
});
});
});

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View 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

View File

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

View File

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

View File

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