Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
48902b7e07
commit
68d3938909
|
|
@ -41,7 +41,7 @@ review-docs-cleanup:
|
|||
|
||||
.docs-markdown-lint-image:
|
||||
# When updating the image version here, update it in /scripts/lint-doc.sh too.
|
||||
image: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-docs/lint-markdown:alpine-3.20-vale-3.4.2-markdownlint2-0.13.0-lychee-0.15.1
|
||||
image: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-docs/lint-markdown:alpine-3.20-vale-3.6.1-markdownlint2-0.13.0-lychee-0.15.1
|
||||
|
||||
docs-lint markdown:
|
||||
extends:
|
||||
|
|
|
|||
|
|
@ -4317,7 +4317,6 @@ RSpec/FeatureCategory:
|
|||
- 'spec/views/dashboard/milestones/index.html.haml_spec.rb'
|
||||
- 'spec/views/dashboard/projects/_blank_state_admin_welcome.haml_spec.rb'
|
||||
- 'spec/views/dashboard/projects/_blank_state_welcome.html.haml_spec.rb'
|
||||
- 'spec/views/dashboard/projects/_nav.html.haml_spec.rb'
|
||||
- 'spec/views/devise/confirmations/almost_there.html.haml_spec.rb'
|
||||
- 'spec/views/errors/access_denied.html.haml_spec.rb'
|
||||
- 'spec/views/errors/omniauth_error.html.haml_spec.rb'
|
||||
|
|
|
|||
|
|
@ -0,0 +1,60 @@
|
|||
<script>
|
||||
import { GlIcon, GlButton } from '@gitlab/ui';
|
||||
import { uniqueId } from 'lodash';
|
||||
import { s__ } from '~/locale';
|
||||
import LockTooltip from './lock_tooltip.vue';
|
||||
|
||||
export default {
|
||||
name: 'CascadingLockIcon',
|
||||
i18n: {
|
||||
lockIconLabel: s__('CascadingSettings|Lock tooltip icon'),
|
||||
},
|
||||
components: {
|
||||
GlIcon,
|
||||
GlButton,
|
||||
LockTooltip,
|
||||
},
|
||||
props: {
|
||||
ancestorNamespace: {
|
||||
type: Object,
|
||||
required: false,
|
||||
default: null,
|
||||
validator: (value) => value?.path && value?.fullName,
|
||||
},
|
||||
isLockedByApplicationSettings: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
isLockedByGroupAncestor: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
targetElement: null,
|
||||
};
|
||||
},
|
||||
async mounted() {
|
||||
// Wait until all children components are mounted
|
||||
await this.$nextTick();
|
||||
this.targetElement = this.$refs[this.$options.refName].$el;
|
||||
},
|
||||
refName: uniqueId('cascading-lock-icon-'),
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<span>
|
||||
<gl-button :ref="$options.refName" class="gl-hover-bg-transparent! !gl-p-0" category="tertiary">
|
||||
<gl-icon name="lock" :aria-label="$options.i18n.lockIconLabel" class="!gl-text-gray-400" />
|
||||
</gl-button>
|
||||
<lock-tooltip
|
||||
v-if="targetElement"
|
||||
:ancestor-namespace="ancestorNamespace"
|
||||
:is-locked-by-admin="isLockedByApplicationSettings"
|
||||
:is-locked-by-group-ancestor="isLockedByGroupAncestor"
|
||||
:target-element="targetElement"
|
||||
/>
|
||||
</span>
|
||||
</template>
|
||||
|
|
@ -1,17 +1,17 @@
|
|||
<script>
|
||||
/**
|
||||
* This component is a utility that can be used in a HAML settings pages
|
||||
* It will get all popover targets and create a popover for each one.
|
||||
* It will get all tooltip targets and create a tooltip for each one.
|
||||
* This should not be used in Vue Apps as we we are breaking component isolation.
|
||||
* Instead, use `lock_popover.vue` and provide a list of vue $refs to loop through.
|
||||
* Instead, use `lock_tooltip.vue` and provide a list of vue $refs to loop through.
|
||||
*/
|
||||
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
|
||||
import LockPopover from './lock_popover.vue';
|
||||
import LockTooltip from './lock_tooltip.vue';
|
||||
|
||||
export default {
|
||||
name: 'HamlLockPopovers',
|
||||
name: 'HamlLockTooltips',
|
||||
components: {
|
||||
LockPopover,
|
||||
LockTooltip,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
|
@ -19,14 +19,14 @@ export default {
|
|||
};
|
||||
},
|
||||
mounted() {
|
||||
this.targets = [...document.querySelectorAll('.js-cascading-settings-lock-popover-target')].map(
|
||||
this.targets = [...document.querySelectorAll('.js-cascading-settings-lock-tooltip-target')].map(
|
||||
(el) => {
|
||||
const {
|
||||
dataset: { popoverData },
|
||||
dataset: { tooltipData },
|
||||
} = el;
|
||||
|
||||
const { lockedByAncestor, lockedByApplicationSetting, ancestorNamespace } =
|
||||
convertObjectPropsToCamelCase(JSON.parse(popoverData || '{}'), { deep: true });
|
||||
convertObjectPropsToCamelCase(JSON.parse(tooltipData || '{}'), { deep: true });
|
||||
|
||||
return {
|
||||
el,
|
||||
|
|
@ -42,7 +42,7 @@ export default {
|
|||
|
||||
<template>
|
||||
<div>
|
||||
<lock-popover
|
||||
<lock-tooltip
|
||||
v-for="(
|
||||
{ el, lockedByApplicationSetting, lockedByAncestor, ancestorNamespace }, index
|
||||
) in targets"
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
<script>
|
||||
import { GlPopover, GlSprintf, GlLink } from '@gitlab/ui';
|
||||
import { GlTooltip, GlSprintf, GlLink } from '@gitlab/ui';
|
||||
|
||||
export default {
|
||||
name: 'LockPopover',
|
||||
name: 'LockTooltip',
|
||||
components: {
|
||||
GlPopover,
|
||||
GlTooltip,
|
||||
GlSprintf,
|
||||
GlLink,
|
||||
},
|
||||
|
|
@ -24,8 +24,8 @@ export default {
|
|||
required: true,
|
||||
},
|
||||
targetElement: {
|
||||
required: true,
|
||||
type: Element,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
|
|
@ -37,9 +37,9 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<gl-popover v-if="isLocked" :target="targetElement" placement="top">
|
||||
<gl-tooltip v-if="isLocked" :target="targetElement" placement="top">
|
||||
<template #title>{{ s__('CascadingSettings|Setting cannot be changed') }}</template>
|
||||
<span data-testid="cascading-settings-lock-popover">
|
||||
<span data-testid="cascading-settings-lock-tooltip">
|
||||
<template v-if="isLockedByAdmin">{{
|
||||
s__(
|
||||
'CascadingSettings|An administrator selected this setting for the instance and you cannot change it.',
|
||||
|
|
@ -61,5 +61,5 @@ export default {
|
|||
}}
|
||||
</template>
|
||||
</span>
|
||||
</gl-popover>
|
||||
</gl-tooltip>
|
||||
</template>
|
||||
|
|
@ -1,15 +1,15 @@
|
|||
import Vue from 'vue';
|
||||
import HamlLockPopovers from './components/haml_lock_popovers.vue';
|
||||
import HamlLockTooltips from './components/haml_lock_tooltips.vue';
|
||||
|
||||
export const initCascadingSettingsLockPopovers = () => {
|
||||
const el = document.querySelector('.js-cascading-settings-lock-popovers');
|
||||
export const initCascadingSettingsLockTooltips = () => {
|
||||
const el = document.querySelector('.js-cascading-settings-lock-tooltips');
|
||||
|
||||
if (!el) return false;
|
||||
|
||||
return new Vue({
|
||||
el,
|
||||
render(createElement) {
|
||||
return createElement(HamlLockPopovers);
|
||||
return createElement(HamlLockTooltips);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
import ProjectsList from '~/projects_list';
|
||||
import { initYourWorkProjects } from '~/projects/your_work';
|
||||
import { initProjectsFilteredSearchAndSort } from '~/projects/filtered_search_and_sort';
|
||||
|
||||
new ProjectsList(); // eslint-disable-line no-new
|
||||
initYourWorkProjects();
|
||||
initProjectsFilteredSearchAndSort();
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
import { initProjectsExploreFilteredSearchAndSort } from '~/projects/explore';
|
||||
import { initProjectsFilteredSearchAndSort } from '~/projects/filtered_search_and_sort';
|
||||
|
||||
initProjectsExploreFilteredSearchAndSort();
|
||||
initProjectsFilteredSearchAndSort({
|
||||
sortEventName: 'use_sort_projects_explore',
|
||||
filterEventName: 'use_filter_bar_projects_explore',
|
||||
});
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import initFilePickers from '~/file_pickers';
|
|||
import initTransferGroupForm from '~/groups/init_transfer_group_form';
|
||||
import { initGroupSelects } from '~/vue_shared/components/entity_select/init_group_selects';
|
||||
import { initProjectSelects } from '~/vue_shared/components/entity_select/init_project_selects';
|
||||
import { initCascadingSettingsLockPopovers } from '~/namespaces/cascading_settings';
|
||||
import { initCascadingSettingsLockTooltips } from '~/namespaces/cascading_settings';
|
||||
import { initDormantUsersInputSection } from '~/pages/admin/application_settings/account_and_limits';
|
||||
import mountBadgeSettings from '~/pages/shared/mount_badge_settings';
|
||||
import initSearchSettings from '~/search_settings';
|
||||
|
|
@ -42,6 +42,6 @@ initGroupSelects();
|
|||
initProjectSelects();
|
||||
|
||||
initSearchSettings();
|
||||
initCascadingSettingsLockPopovers();
|
||||
initCascadingSettingsLockTooltips();
|
||||
|
||||
initGroupSettingsReadme();
|
||||
|
|
|
|||
|
|
@ -16,17 +16,25 @@ export default {
|
|||
required: false,
|
||||
default: null,
|
||||
},
|
||||
locked: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="project-feature-row">
|
||||
<label v-if="label" class="label-bold">
|
||||
<div class="gl-flex">
|
||||
<label v-if="label" class="label-bold" :class="{ 'gl-text-gray-400': locked }">
|
||||
{{ label }}
|
||||
</label>
|
||||
<slot name="label-icon"></slot>
|
||||
</div>
|
||||
<div>
|
||||
<span v-if="helpText" class="text-muted"> {{ helpText }} </span>
|
||||
<span v-if="helpText" class="gl-text-gray-400"> {{ helpText }} </span>
|
||||
<span v-if="helpPath"
|
||||
><a :href="helpPath" target="_blank">{{ __('Learn more') }}</a
|
||||
>.</span
|
||||
|
|
|
|||
|
|
@ -114,7 +114,6 @@ export default {
|
|||
),
|
||||
},
|
||||
mixins: [settingsMixin, glFeatureFlagMixin()],
|
||||
|
||||
props: {
|
||||
requestCveAvailable: {
|
||||
type: Boolean,
|
||||
|
|
@ -1056,6 +1055,7 @@ export default {
|
|||
:label="$options.i18n.duoLabel"
|
||||
:help-text="$options.i18n.duoHelpText"
|
||||
:help-path="$options.duoHelpPath"
|
||||
:locked="duoFeaturesLocked"
|
||||
>
|
||||
<gl-toggle
|
||||
v-model="duoFeaturesEnabled"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import Vue from 'vue';
|
||||
import VueApollo from 'vue-apollo';
|
||||
import createDefaultClient from '~/lib/graphql';
|
||||
|
||||
import { parseBoolean } from '~/lib/utils/common_utils';
|
||||
import settingsPanel from './components/settings_panel.vue';
|
||||
|
||||
|
|
@ -20,12 +19,12 @@ export default function initProjectPermissionsSettings() {
|
|||
const componentProps = JSON.parse(componentPropsEl.innerHTML);
|
||||
|
||||
const {
|
||||
targetFormId,
|
||||
additionalInformation,
|
||||
confirmDangerMessage,
|
||||
confirmButtonText,
|
||||
showVisibilityConfirmModal,
|
||||
confirmDangerMessage,
|
||||
htmlConfirmationMessage,
|
||||
showVisibilityConfirmModal,
|
||||
targetFormId,
|
||||
phrase: confirmationPhrase,
|
||||
} = mountPoint.dataset;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,25 +0,0 @@
|
|||
import Vue from 'vue';
|
||||
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
|
||||
import FilteredSearchAndSort from './components/filtered_search_and_sort.vue';
|
||||
|
||||
export const initProjectsExploreFilteredSearchAndSort = () => {
|
||||
const el = document.getElementById('js-projects-explore-filtered-search-and-sort');
|
||||
|
||||
if (!el) return false;
|
||||
|
||||
const {
|
||||
dataset: { appData },
|
||||
} = el;
|
||||
|
||||
const { initialSort, programmingLanguages, starredExploreProjectsPath, exploreRootPath } =
|
||||
convertObjectPropsToCamelCase(JSON.parse(appData));
|
||||
|
||||
return new Vue({
|
||||
el,
|
||||
name: 'ProjectsExploreFilteredSearchAndSortRoot',
|
||||
provide: { initialSort, programmingLanguages, starredExploreProjectsPath, exploreRootPath },
|
||||
render(createElement) {
|
||||
return createElement(FilteredSearchAndSort);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
|
@ -19,7 +19,7 @@ import {
|
|||
const trackingMixin = InternalEvents.mixin();
|
||||
|
||||
export default {
|
||||
name: 'ProjectsExploreFilteredSearchAndSort',
|
||||
name: 'ProjectsFilteredSearchAndSort',
|
||||
filteredSearch: {
|
||||
namespace: FILTERED_SEARCH_NAMESPACE,
|
||||
recentSearchesStorageKey: RECENT_SEARCHES_STORAGE_KEY_PROJECTS,
|
||||
|
|
@ -29,7 +29,13 @@ export default {
|
|||
FilteredSearchAndSort,
|
||||
},
|
||||
mixins: [trackingMixin],
|
||||
inject: ['initialSort', 'programmingLanguages', 'starredExploreProjectsPath', 'exploreRootPath'],
|
||||
inject: [
|
||||
'initialSort',
|
||||
'programmingLanguages',
|
||||
'pathsToExcludeSortOn',
|
||||
'sortEventName',
|
||||
'filterEventName',
|
||||
],
|
||||
computed: {
|
||||
filteredSearchTokens() {
|
||||
return [
|
||||
|
|
@ -85,8 +91,7 @@ export default {
|
|||
return this.queryAsObject?.[FILTERED_SEARCH_TERM_KEY] || '';
|
||||
},
|
||||
sortOptions() {
|
||||
const mostStarredPathnames = [this.starredExploreProjectsPath, this.exploreRootPath];
|
||||
if (mostStarredPathnames.includes(window.location.pathname)) {
|
||||
if (this.pathsToExcludeSortOn.includes(window.location.pathname)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
|
|
@ -114,7 +119,7 @@ export default {
|
|||
isAscending ? SORT_DIRECTION_ASC : SORT_DIRECTION_DESC
|
||||
}`;
|
||||
|
||||
this.trackEvent('use_sort_projects_explore', {
|
||||
this.trackEvent(this.sortEventName, {
|
||||
label: sort,
|
||||
});
|
||||
|
||||
|
|
@ -126,7 +131,7 @@ export default {
|
|||
onSortByChange(sortBy) {
|
||||
const sort = `${sortBy}_${this.isAscending ? SORT_DIRECTION_ASC : SORT_DIRECTION_DESC}`;
|
||||
|
||||
this.trackEvent('use_sort_projects_explore', {
|
||||
this.trackEvent(this.sortEventName, {
|
||||
label: sort,
|
||||
});
|
||||
|
||||
|
|
@ -143,6 +148,10 @@ export default {
|
|||
queryObject.archived = this.queryAsObject.archived;
|
||||
}
|
||||
|
||||
if (this.queryAsObject.personal) {
|
||||
queryObject.personal = this.queryAsObject.personal;
|
||||
}
|
||||
|
||||
const trackingProperty = Object.entries(filtersQuery).reduce(
|
||||
(accumulator, [tokenType, optionValue]) => {
|
||||
if (tokenType === FILTERED_SEARCH_TERM_KEY) {
|
||||
|
|
@ -160,7 +169,7 @@ export default {
|
|||
{},
|
||||
);
|
||||
|
||||
this.trackEvent('use_filter_bar_projects_explore', {
|
||||
this.trackEvent(this.filterEventName, {
|
||||
label: JSON.stringify(trackingProperty),
|
||||
});
|
||||
|
||||
|
|
@ -172,6 +181,7 @@ export default {
|
|||
|
||||
<template>
|
||||
<filtered-search-and-sort
|
||||
class="gl-w-full"
|
||||
:filtered-search-namespace="$options.filteredSearch.namespace"
|
||||
:filtered-search-tokens="filteredSearchTokens"
|
||||
:filtered-search-term-key="$options.filteredSearch.searchTermKey"
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
import Vue from 'vue';
|
||||
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
|
||||
import FilteredSearchAndSort from './components/filtered_search_and_sort.vue';
|
||||
|
||||
export const initProjectsFilteredSearchAndSort = ({ sortEventName, filterEventName } = {}) => {
|
||||
const el = document.getElementById('js-projects-filtered-search-and-sort');
|
||||
|
||||
if (!el) return false;
|
||||
|
||||
const {
|
||||
dataset: { appData },
|
||||
} = el;
|
||||
|
||||
const { initialSort, programmingLanguages, pathsToExcludeSortOn } = convertObjectPropsToCamelCase(
|
||||
JSON.parse(appData),
|
||||
);
|
||||
|
||||
return new Vue({
|
||||
el,
|
||||
name: 'ProjectsFilteredSearchAndSortRoot',
|
||||
provide: {
|
||||
initialSort,
|
||||
programmingLanguages,
|
||||
pathsToExcludeSortOn,
|
||||
sortEventName,
|
||||
filterEventName,
|
||||
},
|
||||
render(createElement) {
|
||||
return createElement(FilteredSearchAndSort);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
|
@ -5,10 +5,10 @@ module NamespacesHelper
|
|||
params.dig(:project, :namespace_id) || params[:namespace_id]
|
||||
end
|
||||
|
||||
def cascading_namespace_settings_popover_data(attribute, group, settings_path_helper)
|
||||
def cascading_namespace_settings_tooltip_data(attribute, group, settings_path_helper)
|
||||
locked_by_ancestor = group.namespace_settings.public_send("#{attribute}_locked_by_ancestor?") # rubocop:disable GitlabSecurity/PublicSend
|
||||
|
||||
popover_data = {
|
||||
tooltip_data = {
|
||||
locked_by_application_setting: group.namespace_settings.public_send("#{attribute}_locked_by_application_setting?"), # rubocop:disable GitlabSecurity/PublicSend
|
||||
locked_by_ancestor: locked_by_ancestor
|
||||
}
|
||||
|
|
@ -16,14 +16,14 @@ module NamespacesHelper
|
|||
if locked_by_ancestor
|
||||
ancestor_namespace = group.namespace_settings.public_send("#{attribute}_locked_ancestor").namespace # rubocop:disable GitlabSecurity/PublicSend
|
||||
|
||||
popover_data[:ancestor_namespace] = {
|
||||
tooltip_data[:ancestor_namespace] = {
|
||||
full_name: ancestor_namespace.full_name,
|
||||
path: settings_path_helper.call(ancestor_namespace)
|
||||
}
|
||||
end
|
||||
|
||||
{
|
||||
popover_data: popover_data.to_json,
|
||||
tooltip_data: tooltip_data.to_json,
|
||||
testid: 'cascading-settings-lock-icon'
|
||||
}
|
||||
end
|
||||
|
|
|
|||
|
|
@ -308,7 +308,13 @@ module ProjectsHelper
|
|||
end
|
||||
|
||||
def show_projects?(projects, params)
|
||||
!!(params[:personal] || params[:name] || params[:language] || any_projects?(projects))
|
||||
!!(
|
||||
params[:personal] ||
|
||||
params[:name] ||
|
||||
params[:language] ||
|
||||
params[:archived] == 'only' ||
|
||||
any_projects?(projects)
|
||||
)
|
||||
end
|
||||
|
||||
def push_to_create_project_command(user = current_user)
|
||||
|
|
@ -640,12 +646,11 @@ module ProjectsHelper
|
|||
'manual-ordering'
|
||||
end
|
||||
|
||||
def projects_explore_filtered_search_and_sort_app_data
|
||||
def projects_filtered_search_and_sort_app_data
|
||||
{
|
||||
initial_sort: project_list_sort_by,
|
||||
programming_languages: programming_languages,
|
||||
starred_explore_projects_path: starred_explore_projects_path,
|
||||
explore_root_path: explore_root_path
|
||||
paths_to_exclude_sort_on: [starred_explore_projects_path, explore_root_path]
|
||||
}.to_json
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -9,12 +9,4 @@
|
|||
= render Pajamas::ButtonComponent.new(href: new_project_path, variant: :confirm, button_options: { data: { testid: 'new-project-button' } }) do
|
||||
= _("New project")
|
||||
|
||||
.top-area
|
||||
.scrolling-tabs-container.inner-page-scroll-tabs.gl-grow.gl-basis-0.gl-min-w-0
|
||||
%button.fade-left{ type: 'button', title: _('Scroll left'), 'aria-label': _('Scroll left') }
|
||||
= sprite_icon('chevron-lg-left', size: 12)
|
||||
%button.fade-right{ type: 'button', title: _('Scroll right'), 'aria-label': _('Scroll right') }
|
||||
= sprite_icon('chevron-lg-right', size: 12)
|
||||
= render 'dashboard/projects_nav'
|
||||
.nav-controls
|
||||
= render 'shared/projects/search_form'
|
||||
= render 'dashboard/projects_nav'
|
||||
|
|
|
|||
|
|
@ -1,10 +1,16 @@
|
|||
- is_your_projects_path = current_page?(dashboard_projects_path) || current_page?(root_path)
|
||||
|
||||
= gl_tabs_nav({ class: 'scrolling-tabs nav-links gl-display-flex gl-flex-grow-1 gl-w-full nav gl-tabs-nav' }) do
|
||||
= gl_tab_link_to dashboard_projects_path, { item_active: is_your_projects_path, class: 'shortcuts-activity', data: { placement: 'right' } } do
|
||||
%div
|
||||
= gl_tabs_nav({ class: 'gl-flex gl-grow gl-border-none'}) do
|
||||
= gl_tab_link_to dashboard_projects_path, { item_active: is_your_projects_path && !params['archived'] && !params['personal'], class: 'shortcuts-activity', data: { placement: 'right' } } do
|
||||
= s_("ProjectList|Yours")
|
||||
= gl_tab_counter_badge(limited_counter_with_delimiter(@all_user_projects))
|
||||
= gl_tab_link_to starred_dashboard_projects_path, { data: { placement: 'right' } } do
|
||||
= s_("ProjectList|Starred")
|
||||
= gl_tab_counter_badge(limited_counter_with_delimiter(@all_starred_projects))
|
||||
= gl_tab_link_to _('Personal'), dashboard_projects_path({ personal: true }), { item_active: params['personal'] == 'true' }
|
||||
= gl_tab_link_to _('Inactive'), dashboard_projects_path({ archived: 'only' }), { item_active: params['archived'] == 'only' }
|
||||
= render_if_exists "dashboard/removed_projects_tab"
|
||||
#js-projects-filtered-search-and-sort.gl-py-5.gl-border-t.gl-border-b.gl-w-full{ data: { app_data: projects_filtered_search_and_sort_app_data } }
|
||||
-# This element takes up space while Vue is rendering to avoid page jump
|
||||
.gl-h-7
|
||||
|
|
|
|||
|
|
@ -1,4 +0,0 @@
|
|||
.nav-block
|
||||
= gl_tabs_nav do
|
||||
= gl_tab_link_to s_('DashboardProjects|All'), dashboard_projects_path, { item_active: params[:personal].blank? }
|
||||
= gl_tab_link_to s_('DashboardProjects|Personal'), filter_projects_path(personal: true), { item_active: params[:personal].present? }
|
||||
|
|
@ -14,7 +14,6 @@
|
|||
- else
|
||||
- if show_projects?(@projects, params)
|
||||
= render 'dashboard/projects_head'
|
||||
= render 'nav'
|
||||
= render 'projects'
|
||||
- else
|
||||
= render "zero_authorized_projects"
|
||||
|
|
|
|||
|
|
@ -6,6 +6,6 @@
|
|||
= gl_tab_link_to _('Inactive'), explore_projects_path({ archived: 'only' }), { item_active: current_page?(explore_projects_path) && params['archived'] == 'only', data: { event_tracking: 'click_tab_projects_explore', event_label: 'Inactive' } }
|
||||
= gl_tab_link_to _('All'), explore_projects_path({ archived: true }), { item_active: current_page?(explore_projects_path) && params['archived'] == 'true', data: { event_tracking: 'click_tab_projects_explore', event_label: 'All' } }
|
||||
|
||||
#js-projects-explore-filtered-search-and-sort.gl-py-5.gl-border-t.gl-border-b{ data: { app_data: projects_explore_filtered_search_and_sort_app_data } }
|
||||
#js-projects-filtered-search-and-sort.gl-py-5.gl-border-t.gl-border-b{ data: { app_data: projects_filtered_search_and_sort_app_data } }
|
||||
-# This element takes up space while Vue is rendering to avoid page jump
|
||||
.gl-h-7
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
- expanded = expanded_by_default?
|
||||
- @force_desktop_expanded_sidebar = true
|
||||
|
||||
= render 'shared/namespaces/cascading_settings/lock_popovers'
|
||||
= render 'shared/namespaces/cascading_settings/lock_tooltips'
|
||||
|
||||
%h1.gl-sr-only= @breadcrumb_title
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
- class_list = local_assigns.fetch(:class_list, '')
|
||||
|
||||
= render Pajamas::ButtonComponent.new(category: 'tertiary', icon: 'lock', button_options: { class: "gl-absolute gl-top-3 gl-right-0 -gl-translate-y-1/2 gl-p-1! gl-bg-transparent! gl-cursor-default! js-cascading-settings-lock-popover-target #{class_list}", data: cascading_namespace_settings_popover_data(attribute, group, settings_path_helper) })
|
||||
= render Pajamas::ButtonComponent.new(category: 'tertiary', icon: 'lock', button_options: { class: "gl-absolute gl-top-3 gl-right-0 -gl-translate-y-1/2 !gl-p-1 !gl-bg-transparent !gl-cursor-default js-cascading-settings-lock-tooltip-target #{class_list}", data: cascading_namespace_settings_tooltip_data(attribute, group, settings_path_helper) })
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
.js-cascading-settings-lock-popovers
|
||||
|
|
@ -0,0 +1 @@
|
|||
.js-cascading-settings-lock-tooltips
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
name: request_authenticator_exclude_job_token_basic_auth
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4322
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/474769
|
||||
milestone: "17.3"
|
||||
type: development
|
||||
group: group::pipeline security
|
||||
default_enabled: false
|
||||
|
|
@ -11,3 +11,5 @@ analytics_instrumentation.check_usage_data_insertions!
|
|||
analytics_instrumentation.check_deprecated_data_sources!
|
||||
|
||||
analytics_instrumentation.check_removed_metric_fields!
|
||||
|
||||
analytics_instrumentation.warn_about_migrated_redis_keys_specs!
|
||||
|
|
|
|||
|
|
@ -895,10 +895,10 @@ fetch responses. This can reduce server load when your server receives
|
|||
lots of CI fetch traffic.
|
||||
|
||||
The pack-objects cache wraps `git pack-objects`, an internal part of
|
||||
Git that gets invoked indirectly via the PostUploadPack and
|
||||
Git that gets invoked indirectly by using the PostUploadPack and
|
||||
SSHUploadPack Gitaly RPCs. Gitaly runs PostUploadPack when a
|
||||
user does a Git fetch via HTTP, or SSHUploadPack when a
|
||||
user does a Git fetch via SSH.
|
||||
user does a Git fetch by using HTTP, or SSHUploadPack when a
|
||||
user does a Git fetch by using SSH.
|
||||
When the cache is enabled, anything that uses PostUploadPack or SSHUploadPack can
|
||||
benefit from it. It is orthogonal to:
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ DETAILS:
|
|||
**Tier:** Free, Premium, Ultimate
|
||||
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
|
||||
|
||||
Discussions are a set of related notes on:
|
||||
Discussions are attached to:
|
||||
|
||||
- Snippets
|
||||
- Issues
|
||||
|
|
@ -18,11 +18,24 @@ Discussions are a set of related notes on:
|
|||
- Merge requests
|
||||
- Commits
|
||||
|
||||
This includes [comments and threads](../user/discussions/index.md) and system notes.
|
||||
This includes [comments, threads](../user/discussions/index.md), and system notes.
|
||||
System notes are notes about changes to the object (for example, when a milestone changes).
|
||||
|
||||
Label notes are not part of this API, but recorded as separate events in
|
||||
[resource label events](resource_label_events.md).
|
||||
|
||||
## Understand note types in the API
|
||||
|
||||
Not all discussion types are equally available in the API:
|
||||
|
||||
- **Note**: A comment left on the _root_ of an issue, merge request, commit,
|
||||
or snippet.
|
||||
- **Discussion**: A collection, often called a _thread_, of `DiscussionNotes` in
|
||||
an issue, merge request, commit, or snippet.
|
||||
- **DiscussionNote**: An individual item in a discussion on an issue, merge request,
|
||||
commit, or snippet. These are not returned as part of the Note API.
|
||||
Not available in the [Events API](events.md).
|
||||
|
||||
## Discussions pagination
|
||||
|
||||
By default, `GET` requests return 20 results at a time because the API results are paginated.
|
||||
|
|
|
|||
|
|
@ -24,13 +24,15 @@ Available target types for the `target_type` parameter are:
|
|||
- `issue`
|
||||
- `milestone`
|
||||
- `merge_request`
|
||||
- `note`
|
||||
- `note` - Some notes on merge requests may be of the type `DiscussionNote`, instead of `Note`.
|
||||
`DiscussionNote` items are [not available using the API](discussions.md#understand-note-types-in-the-api).
|
||||
- `project`
|
||||
- `snippet`
|
||||
- `user`
|
||||
|
||||
These options are in lowercase.
|
||||
Events associated with epics are not available using the API.
|
||||
Some discussions on merge requests may be of type `DiscussionNote`. These are not available using the API.
|
||||
|
||||
### Date formatting
|
||||
|
||||
|
|
@ -56,7 +58,7 @@ GET /events
|
|||
Parameters:
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
|---------------|--------|----------|-----------------------------------------------------------------------------------------------------|
|
||||
| `action` | string | no | Include only events of a particular [action type](#actions) |
|
||||
| `target_type` | string | no | Include only events of a particular [target type](#target-types) |
|
||||
| `before` | date | no | Include only events created before a particular date. [View how to format dates](#date-formatting). |
|
||||
|
|
@ -135,7 +137,7 @@ GET /users/:id/events
|
|||
Parameters:
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
|---------------|---------|----------|-----------------------------------------------------------------------------------------------------|
|
||||
| `id` | integer | yes | The ID or Username of the user |
|
||||
| `action` | string | no | Include only events of a particular [action type](#actions) |
|
||||
| `target_type` | string | no | Include only events of a particular [target type](#target-types) |
|
||||
|
|
@ -285,7 +287,7 @@ GET /projects/:project_id/events
|
|||
Parameters:
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
|---------------|----------------|----------|-----------------------------------------------------------------------------------------------------|
|
||||
| `project_id` | integer/string | yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding) |
|
||||
| `action` | string | no | Include only events of a particular [action type](#actions) |
|
||||
| `target_type` | string | no | Include only events of a particular [target type](#target-types) |
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ See also:
|
|||
|
||||
These styles are not backed by a RuboCop rule.
|
||||
|
||||
For every style added to this section, link the discussion from the section's [history note](../documentation/versions.md#add-a-history-item) to provide context and serve as a reference.
|
||||
For every style added to this section, link the discussion from the section's [history note](../documentation/styleguide/availability_details.md#history) to provide context and serve as a reference.
|
||||
|
||||
### Instance variable access using `attr_reader`
|
||||
|
||||
|
|
|
|||
|
|
@ -159,15 +159,15 @@ Renders the label for a `fieldset` setting.
|
|||
| `settings_path_helper` | Lambda function that generates a path to the ancestor setting. For example, `-> (locked_ancestor) { edit_group_path(locked_ancestor, anchor: 'js-permissions-settings') }` | `Lambda` | `true` |
|
||||
| `help_text` | Text shown below the checkbox. | `String` | `false` (`nil`) |
|
||||
|
||||
[`_lock_popovers.html.haml`](https://gitlab.com/gitlab-org/gitlab/-/blob/b73353e47e283a7d9c9eda5bdedb345dcfb685b6/app/views/shared/namespaces/cascading_settings/_lock_popovers.html.haml)
|
||||
[`_lock_tooltips.html.haml`](https://gitlab.com/gitlab-org/gitlab/-/blob/b73353e47e283a7d9c9eda5bdedb345dcfb685b6/app/views/shared/namespaces/cascading_settings/_lock_tooltips.html.haml)
|
||||
|
||||
Renders the mount element needed to initialize the JavaScript used to display the popover when hovering over the lock icon. This partial is only needed once per page.
|
||||
Renders the mount element needed to initialize the JavaScript used to display the tooltip when hovering over the lock icon. This partial is only needed once per page.
|
||||
|
||||
### JavaScript
|
||||
|
||||
[`initCascadingSettingsLockPopovers`](https://gitlab.com/gitlab-org/gitlab/-/blob/b73353e47e283a7d9c9eda5bdedb345dcfb685b6/app/assets/javascripts/namespaces/cascading_settings/index.js#L4)
|
||||
[`initCascadingSettingsLockTooltips`](https://gitlab.com/gitlab-org/gitlab/-/blob/b73353e47e283a7d9c9eda5bdedb345dcfb685b6/app/assets/javascripts/namespaces/cascading_settings/index.js#L4)
|
||||
|
||||
Initializes the JavaScript needed to display the popover when hovering over the lock icon (**{lock}**).
|
||||
Initializes the JavaScript needed to display the tooltip when hovering over the lock icon (**{lock}**).
|
||||
This function should be imported and called in the [page-specific JavaScript](fe_guide/performance.md#page-specific-javascript).
|
||||
|
||||
### Put it all together
|
||||
|
|
@ -175,7 +175,7 @@ This function should be imported and called in the [page-specific JavaScript](fe
|
|||
```haml
|
||||
-# app/views/groups/edit.html.haml
|
||||
|
||||
= render 'shared/namespaces/cascading_settings/lock_popovers'
|
||||
= render 'shared/namespaces/cascading_settings/lock_tooltips'
|
||||
|
||||
- delayed_project_removal_locked = cascading_namespace_setting_locked?(:delayed_project_removal, @group)
|
||||
- merge_method_locked = cascading_namespace_setting_locked?(:merge_method, @group)
|
||||
|
|
@ -222,7 +222,7 @@ This function should be imported and called in the [page-specific JavaScript](fe
|
|||
```javascript
|
||||
// app/assets/javascripts/pages/groups/edit/index.js
|
||||
|
||||
import { initCascadingSettingsLockPopovers } from '~/namespaces/cascading_settings';
|
||||
import { initCascadingSettingsLockTooltips } from '~/namespaces/cascading_settings';
|
||||
|
||||
initCascadingSettingsLockPopovers();
|
||||
initCascadingSettingsLockTooltips();
|
||||
```
|
||||
|
|
|
|||
|
|
@ -102,4 +102,4 @@ Related Handbook pages:
|
|||
|
||||
## Update the related documentation
|
||||
|
||||
When features are deprecated and removed, [update the related documentation](../documentation/versions.md#deprecations-and-removals).
|
||||
When features are deprecated and removed, [update the related documentation](../documentation/styleguide/deprecations_and_removals.md).
|
||||
|
|
|
|||
|
|
@ -141,3 +141,16 @@ in the `gitlab-docs-archives` repository.
|
|||
|
||||
1. After the pipeline finishes, go to `https://archives.docs.gitlab.com` and verify
|
||||
that the changes are available for the correct version.
|
||||
|
||||
## View older documentation versions
|
||||
|
||||
Previous versions of the documentation are available on `docs.gitlab.com`.
|
||||
To view a previous version, in the upper-right corner, select the version
|
||||
number from the dropdown list.
|
||||
|
||||
To view versions that are not available on `docs.gitlab.com`:
|
||||
|
||||
- View the [documentation archives](https://docs.gitlab.com/archives/).
|
||||
- Go to the GitLab repository and select the version-specific branch. For example,
|
||||
the [13.2 branch](https://gitlab.com/gitlab-org/gitlab/-/tree/13-2-stable-ee/doc) has the
|
||||
documentation for GitLab 13.2.
|
||||
|
|
|
|||
|
|
@ -42,7 +42,9 @@ the list of users testing this feature, do this thing. If you find a bug,
|
|||
[open an issue](https://link).
|
||||
```
|
||||
|
||||
When the feature is ready for production, remove:
|
||||
## When features become generally available
|
||||
|
||||
When the feature changes from experiment or beta to generally available, remove:
|
||||
|
||||
- The **Status** from the availability details.
|
||||
- Any language about the feature not being ready for production in the body
|
||||
|
|
@ -50,3 +52,14 @@ When the feature is ready for production, remove:
|
|||
- The feature flag information if available.
|
||||
|
||||
Ensure the history is up-to-date by adding a note about the production release.
|
||||
|
||||
### GitLab Duo features
|
||||
|
||||
When a GitLab Duo feature becomes generally available:
|
||||
|
||||
- In the [top-level GitLab Duo page](../../user/gitlab_duo/index.md), move the topic from the
|
||||
`Beta features` or `Experimental features` section to the `Generally available features` section.
|
||||
- If the feature is documented in [GitLab Duo experiments](../../user/gitlab_duo/experiments.md),
|
||||
move the content somewhere more appropriate (to other related features).
|
||||
- Make sure you update the history and status values, including any
|
||||
[add-on information](styleguide/availability_details.md#gitlab-duo-pro-or-enterprise-add-on).
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ To document feature flags:
|
|||
## Add history text
|
||||
|
||||
When the state of a flag changes (for example, from disabled by default to enabled by default), add the change to the
|
||||
[history](versions.md#add-a-history-item).
|
||||
[history](../documentation/styleguide/availability_details.md#history).
|
||||
|
||||
Possible history entries are:
|
||||
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ Example response:
|
|||
|
||||
## History
|
||||
|
||||
Add [history](versions.md#documenting-version-specific-features)
|
||||
Add [history](../documentation/styleguide/availability_details.md#history)
|
||||
to describe new or updated API calls.
|
||||
|
||||
To add history for an individual attribute, include it in the history
|
||||
|
|
@ -115,7 +115,7 @@ If the API or attribute is deployed behind a feature flag,
|
|||
## Deprecations
|
||||
|
||||
To document the deprecation of an API endpoint, follow the steps to
|
||||
[deprecate a page or topic](versions.md#deprecate-a-page-or-topic).
|
||||
[deprecate a page or topic](../documentation/styleguide/deprecations_and_removals.md).
|
||||
|
||||
To deprecate an attribute:
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ DETAILS:
|
|||
|
||||
## Available options
|
||||
|
||||
Use the following text for the tier, offering, and status.
|
||||
Use the following text for the tier, offering, status, and version history.
|
||||
|
||||
### Offering
|
||||
|
||||
|
|
@ -52,18 +52,9 @@ For tier, choose one:
|
|||
- `Premium, Ultimate`
|
||||
- `Ultimate`
|
||||
|
||||
### Status
|
||||
#### GitLab Duo Pro or Enterprise add-on
|
||||
|
||||
For status, choose one:
|
||||
|
||||
- `Beta`
|
||||
- `Experiment`
|
||||
|
||||
Generally available features should not have a status.
|
||||
|
||||
### GitLab Duo Pro or Enterprise add-on
|
||||
|
||||
The add-ons belong with other subscription tiers. Document them by using the phrase `with` and the add-on.
|
||||
Document add-ons by using the phrase `with` and the add-on.
|
||||
For example, `with GitLab Duo Pro`.
|
||||
|
||||
The possibilities are:
|
||||
|
|
@ -87,6 +78,116 @@ You might have to differentiate which add-on applies for each offering (GitLab.c
|
|||
NOTE:
|
||||
GitLab Dedicated always includes an Ultimate subscription.
|
||||
|
||||
### Status
|
||||
|
||||
For status, choose one:
|
||||
|
||||
- `Beta`
|
||||
- `Experiment`
|
||||
|
||||
Generally available features should not have a status.
|
||||
|
||||
### History
|
||||
|
||||
For version history, include these words in this order. Capitalization doesn't matter (with the exception of `GitLab`).
|
||||
|
||||
- `introduced`, `added`, `enabled`, `deprecated`, `changed`, `moved`, `recommended`, `removed`, or `renamed`
|
||||
- `in` or `to`
|
||||
- `GitLab` (or, for external projects, the name of the project)
|
||||
|
||||
The docs site uses [Ruby code](https://gitlab.com/gitlab-org/gitlab-docs/-/blob/main/lib/filters/introduced_in.rb) to render the version history based on these words.
|
||||
|
||||
In addition:
|
||||
|
||||
- Ensure that the output generates properly.
|
||||
- Ensure the version history begins with `> -`.
|
||||
- If possible, include a link to the related issue, merge request, or epic.
|
||||
- Do not link to the pricing page. Do not include the subscription tier.
|
||||
|
||||
#### Updated features
|
||||
|
||||
For features that have changed or been updated, add a new list item.
|
||||
Start the sentence with the feature name or a gerund.
|
||||
|
||||
For example:
|
||||
|
||||
```markdown
|
||||
> - [Introduced](https://issue-link) in GitLab 13.1.
|
||||
> - Creating an issue from an issue board [introduced](https://issue-link) in GitLab 14.1.
|
||||
```
|
||||
|
||||
Or:
|
||||
|
||||
```markdown
|
||||
> - [Introduced](https://issue-link) in GitLab 13.1.
|
||||
> - Notifications for expiring tokens [introduced](https://issue-link) in GitLab 14.3.
|
||||
```
|
||||
|
||||
#### Moved subscription tiers
|
||||
|
||||
For features that move to another subscription tier, use `moved`:
|
||||
|
||||
```markdown
|
||||
> - [Moved](https://issue-link) from GitLab Ultimate to GitLab Premium in 11.8.
|
||||
> - [Moved](https://issue-link) from GitLab Premium to GitLab Free in 12.0.
|
||||
```
|
||||
|
||||
#### Changed feature status
|
||||
|
||||
For a feature status change from experiment to beta, use `changed`:
|
||||
|
||||
```markdown
|
||||
> - [Introduced](https://issue-link) as an [experiment](../../policy/experiment-beta-support.md) in GitLab 15.7.
|
||||
> - [Changed](https://issue-link) to beta in GitLab 16.0.
|
||||
```
|
||||
|
||||
For a change to generally available, use:
|
||||
|
||||
```markdown
|
||||
> - [Generally available](https://issue-link) in GitLab 16.10.
|
||||
```
|
||||
|
||||
#### Features made available as part of a program
|
||||
|
||||
For features made available to users as part of a program, add a new list item and link to the program.
|
||||
|
||||
```markdown
|
||||
> - [Introduced](https://issue-link) in GitLab 15.1.
|
||||
> - Merged results pipelines [added](https://issue-link) to the [Registration Features Program](https://page-link) in GitLab 16.7.
|
||||
```
|
||||
|
||||
#### Features behind feature flags
|
||||
|
||||
For features introduced behind feature flags, add details about the feature flag. For more information, see [Document features deployed behind feature flags](../feature_flags.md).
|
||||
|
||||
#### Removing versions
|
||||
|
||||
Remove history items and inline text that refer to unsupported versions.
|
||||
|
||||
GitLab supports the current major version and two previous major versions.
|
||||
For example, if 16.0 is the current major version, all major and minor releases of
|
||||
GitLab 16.0, 15.0, and 14.0 are supported.
|
||||
|
||||
For the list of current supported versions, see [Version support](https://about.gitlab.com/support/statement-of-support/#version-support).
|
||||
|
||||
Remove information about [features behind feature flags](../feature_flags.md)
|
||||
only if all events related to the feature flag happened in unsupported versions.
|
||||
If the flag hasn't been removed, readers should know when it was introduced.
|
||||
|
||||
#### Timing version removals
|
||||
|
||||
When a new major version is about to be released, create merge
|
||||
requests to remove mentions of the last unsupported version. Only merge
|
||||
them during the milestone of the new major release.
|
||||
|
||||
For example, if GitLab 17.0 is the next major upcoming release:
|
||||
|
||||
- The supported versions are 16, 15, and 14.
|
||||
- When GitLab 17.0 is released, GitLab 14 is no longer supported.
|
||||
|
||||
Create merge requests to remove mentions of GitLab 14, but only
|
||||
merge them during the 17.0 milestone, after 16.11 is released.
|
||||
|
||||
## When to add availability details
|
||||
|
||||
Assign availability details under:
|
||||
|
|
@ -163,6 +264,17 @@ IDs of the users to assign the issue to. Ultimate only.
|
|||
|
||||
For more examples, see the [REST API style guide](../restful_api_styleguide.md).
|
||||
|
||||
## Inline history text
|
||||
|
||||
If you're adding content to an existing topic, add historical information
|
||||
inline with the existing text. If possible, include a link to the related issue,
|
||||
merge request, or epic. For example:
|
||||
|
||||
```markdown
|
||||
The voting strategy [in GitLab 13.4 and later](https://issue-link) requires the primary and secondary
|
||||
voters to agree.
|
||||
```
|
||||
|
||||
## Administrator documentation for availability details
|
||||
|
||||
Topics that are only for instance administrators should have the `Self-managed` tier.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,160 @@
|
|||
---
|
||||
info: For assistance with this Style Guide page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments-to-other-projects-and-subjects.
|
||||
stage: none
|
||||
group: unassigned
|
||||
description: 'Guidelines for deprecations and page removals'
|
||||
---
|
||||
|
||||
## Deprecations and removals
|
||||
|
||||
When GitLab deprecates or removes a feature, use the following process to update the documentation.
|
||||
This process requires temporarily changing content to be "deprecated" or "removed" before it's deleted.
|
||||
|
||||
If a feature is not generally available, you can delete the content outright instead of following these instructions.
|
||||
|
||||
NOTE:
|
||||
A separate process exists for [GraphQL docs](../../api_graphql_styleguide.md#deprecating-schema-items)
|
||||
and [REST API docs](../restful_api_styleguide.md#deprecations).
|
||||
|
||||
### Deprecate a page or topic
|
||||
|
||||
To deprecate a page or topic:
|
||||
|
||||
1. Add `(deprecated)` after the title. Use a warning to explain when it was deprecated,
|
||||
when it will be removed, and the replacement feature.
|
||||
|
||||
```markdown
|
||||
## Title (deprecated)
|
||||
|
||||
DETAILS:
|
||||
**Tier:** Premium, Ultimate
|
||||
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
|
||||
|
||||
WARNING:
|
||||
This feature was [deprecated](https://issue-link) in GitLab 14.8
|
||||
and is planned for removal in 15.4. Use [feature X](link-to-docs.md) instead.
|
||||
```
|
||||
|
||||
If you're not sure when the feature will be removed or no
|
||||
replacement feature exists, you don't need to add this information.
|
||||
|
||||
1. If the deprecation is a [breaking change](../../../update/terminology.md#breaking-change), add this text:
|
||||
|
||||
```markdown
|
||||
This change is a breaking change.
|
||||
```
|
||||
|
||||
You can add any additional context-specific details that might help users.
|
||||
|
||||
1. Add the following HTML comments above and below the content. For `remove_date`,
|
||||
set a date three months after the [release where it will be removed](https://about.gitlab.com/releases/).
|
||||
|
||||
```markdown
|
||||
<!--- start_remove The following content will be removed on remove_date: 'YYYY-MM-DD' -->
|
||||
|
||||
## Title (deprecated)
|
||||
|
||||
DETAILS:
|
||||
**Tier:** Premium, Ultimate
|
||||
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
|
||||
|
||||
WARNING:
|
||||
This feature was [deprecated](https://issue-link) in GitLab 14.8
|
||||
and is planned for removal in 15.4. Use [feature X](link-to-docs.md) instead.
|
||||
|
||||
<!--- end_remove -->
|
||||
```
|
||||
|
||||
1. Open a merge request to add the word `(deprecated)` to the left nav, after the page title.
|
||||
|
||||
### Remove a page
|
||||
|
||||
Mark content as removed during the release the feature was removed.
|
||||
The title and a removed indicator remains until three months after the removal.
|
||||
|
||||
To remove a page:
|
||||
|
||||
1. Leave the page title. Remove all other content, including the history items and the word `WARNING:`.
|
||||
1. After the title, change `(deprecated)` to `(removed)`.
|
||||
1. Update the YAML metadata:
|
||||
- For `remove_date`, set the value to a date three months after
|
||||
the release when the feature was removed.
|
||||
- For the `redirect_to`, set a path to a file that makes sense. If no obvious
|
||||
page exists, use the docs home page.
|
||||
|
||||
```markdown
|
||||
---
|
||||
stage: Data Stores
|
||||
group: Global Search
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
remove_date: '2022-08-02'
|
||||
redirect_to: '../newpath/to/file/index.md'
|
||||
---
|
||||
|
||||
# Title (removed)
|
||||
|
||||
DETAILS:
|
||||
**Tier:** Premium, Ultimate
|
||||
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
|
||||
|
||||
This feature was [deprecated](https://issue-link) in GitLab X.Y
|
||||
and [removed](https://issue-link) in X.Y.
|
||||
Use [feature X](link-to-docs.md) instead.
|
||||
```
|
||||
|
||||
1. Remove the page's entry from the global navigation by editing [`navigation.yaml`](https://gitlab.com/gitlab-org/gitlab-docs/blob/main/content/_data/navigation.yaml) in `gitlab-docs`.
|
||||
|
||||
This content is removed from the documentation as part of the Technical Writing team's
|
||||
[regularly scheduled tasks](https://handbook.gitlab.com/handbook/product/ux/technical-writing/#regularly-scheduled-tasks).
|
||||
|
||||
### Remove a topic
|
||||
|
||||
To remove a topic:
|
||||
|
||||
1. Leave the title and the details of the deprecation and removal. Remove all other content,
|
||||
including the history items and the word `WARNING:`.
|
||||
1. Add `(removed)` after the title.
|
||||
1. Add the following HTML comments above and below the topic.
|
||||
For `remove_date`, set a date three months after the release where it was removed.
|
||||
|
||||
```markdown
|
||||
<!--- start_remove The following content will be removed on remove_date: 'YYYY-MM-DD' -->
|
||||
|
||||
## Title (removed)
|
||||
|
||||
DETAILS:
|
||||
**Tier:** Premium, Ultimate
|
||||
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
|
||||
|
||||
This feature was [deprecated](https://issue-link) in GitLab X.Y
|
||||
and [removed](https://issue-link) in X.Y.
|
||||
Use [feature X](link-to-docs.md) instead.
|
||||
|
||||
<!--- end_remove -->
|
||||
```
|
||||
|
||||
This content is removed from the documentation as part of the Technical Writing team's
|
||||
[regularly scheduled tasks](https://handbook.gitlab.com/handbook/product/ux/technical-writing/#regularly-scheduled-tasks).
|
||||
|
||||
### Removing version-specific upgrade pages
|
||||
|
||||
Version-specific upgrade pages are in the `doc/update/versions/` directory.
|
||||
|
||||
We don't remove version-specific upgrade pages immediately for a major milestone. This gives
|
||||
users time to upgrade from older versions.
|
||||
|
||||
For example, `doc/update/versions/14_changes.md` should
|
||||
be removed during the `.3` milestone. Therefore `14_changes.md` are
|
||||
removed in GitLab 17.3.
|
||||
|
||||
Instead of removing the unsupported page:
|
||||
|
||||
- [Add a note](#remove-a-topic) with a date three months
|
||||
in the future to ensure the page is removed during the
|
||||
[monthly maintenance task](https://handbook.gitlab.com/handbook/product/ux/technical-writing/#regularly-scheduled-tasks).
|
||||
- Do not add `Removed` to the title.
|
||||
|
||||
If the `X_changes.md` page contains relative links to other sections
|
||||
that are removed as part of the versions cleanup, the `docs-lint links`
|
||||
job might fail. You can replace those relative links with an [archived version](https://archives.docs.gitlab.com).
|
||||
Choose the latest minor version of the unsupported version to be removed.
|
||||
|
|
@ -1626,8 +1626,31 @@ This is something to be warned about.
|
|||
|
||||
### Disclaimer
|
||||
|
||||
Use to describe future functionality only.
|
||||
For more information, see [Legal disclaimer for future features](../versions.md#legal-disclaimer-for-future-features).
|
||||
If you **must** write about features we have not yet delivered, put this exact disclaimer about forward-looking statements near the content it applies to.
|
||||
|
||||
```markdown
|
||||
DISCLAIMER:
|
||||
This page contains information related to upcoming products, features, and functionality.
|
||||
It is important to note that the information presented is for informational purposes only.
|
||||
Please do not rely on this information for purchasing or planning purposes.
|
||||
The development, release, and timing of any products, features, or functionality may be subject to change or delay and remain at the
|
||||
sole discretion of GitLab Inc.
|
||||
```
|
||||
|
||||
It renders on the GitLab documentation site as:
|
||||
|
||||
DISCLAIMER:
|
||||
This page contains information related to upcoming products, features, and functionality.
|
||||
It is important to note that the information presented is for informational purposes only.
|
||||
Please do not rely on this information for purchasing or planning purposes.
|
||||
The development, release, and timing of any products, features, or functionality may be subject to change or delay and remain at the
|
||||
sole discretion of GitLab Inc.
|
||||
|
||||
If all of the content on the page is not available, use the disclaimer about forward-looking statements once at the top of the page.
|
||||
|
||||
If the content in a topic is not ready, use the disclaimer in the topic.
|
||||
|
||||
For more information, see [Promising features in future versions](#promising-features-in-future-versions).
|
||||
|
||||
### Details
|
||||
|
||||
|
|
@ -1721,6 +1744,22 @@ Do not copy and paste content from other sources unless it is a limited
|
|||
quotation with the source cited. Typically it is better to rephrase
|
||||
relevant information in your own words or link out to the other source.
|
||||
|
||||
## Promising features in future versions
|
||||
|
||||
Do not promise to deliver features in a future release. For example, avoid phrases like,
|
||||
"Support for this feature is planned."
|
||||
|
||||
We cannot guarantee future feature work, and promises
|
||||
like these can raise legal issues. Instead, say that an issue exists.
|
||||
For example:
|
||||
|
||||
- Support for improvements is proposed in `[issue <issue_number>](https://link-to-issue)`.
|
||||
- You cannot do this thing, but `[issue 12345](https://link-to-issue)` proposes to change this behavior.
|
||||
|
||||
You can say that we plan to remove a feature.
|
||||
|
||||
If you must document a future feature, use the [disclaimer](#disclaimer).
|
||||
|
||||
## Products and features
|
||||
|
||||
Refer to the information in this section when describing products and features
|
||||
|
|
|
|||
|
|
@ -2286,7 +2286,7 @@ Sometimes you might need to use **yet** when writing a task. If you use
|
|||
**yet**, ensure the surrounding phrases are written
|
||||
in present tense, active voice.
|
||||
|
||||
[View guidance about how to write about future features](../versions.md#promising-features-in-future-versions).
|
||||
[View guidance about how to write about future features](index.md#promising-features-in-future-versions).
|
||||
|
||||
## you, your, yours
|
||||
|
||||
|
|
|
|||
|
|
@ -1,351 +1,11 @@
|
|||
---
|
||||
info: For assistance with this Style Guide page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments-to-other-projects-and-subjects.
|
||||
stage: none
|
||||
group: unassigned
|
||||
description: 'Writing styles, markup, formatting, and other standards for GitLab Documentation.'
|
||||
redirect_to: '../documentation/styleguide/availability_details.md'
|
||||
remove_date: '2024-11-02'
|
||||
---
|
||||
|
||||
# Documenting product versions
|
||||
This document was moved to [another location](../documentation/styleguide/availability_details.md).
|
||||
|
||||
The GitLab product documentation includes version-specific information,
|
||||
including when features were introduced and when they were updated or removed.
|
||||
|
||||
## View older documentation versions
|
||||
|
||||
Previous versions of the documentation are available on `docs.gitlab.com`.
|
||||
To view a previous version, in the upper-right corner, select **Versions**.
|
||||
|
||||
To view versions that are not available on `docs.gitlab.com`:
|
||||
|
||||
- View the [documentation archives](https://docs.gitlab.com/archives/).
|
||||
- Go to the GitLab repository and select the version-specific branch. For example,
|
||||
the [13.2 branch](https://gitlab.com/gitlab-org/gitlab/-/tree/13-2-stable-ee/doc) has the
|
||||
documentation for GitLab 13.2.
|
||||
|
||||
## Documenting version-specific features
|
||||
|
||||
When a feature is added or updated, update the documentation with
|
||||
a **History** list item or as an inline text reference.
|
||||
|
||||
You do not need to add historical information on the pages in the `/development` directory.
|
||||
|
||||
### Add a **History** item
|
||||
|
||||
If all content in a topic is related, add a history item after the topic title.
|
||||
For example:
|
||||
|
||||
```markdown
|
||||
## Feature name
|
||||
|
||||
> - [Introduced](https://issue-link) in GitLab 11.3.
|
||||
|
||||
This feature does something.
|
||||
```
|
||||
|
||||
The item text must include these words in order. Capitalization doesn't matter.
|
||||
|
||||
- `introduced`, `added`, `enabled`, `deprecated`, `changed`, `moved`, `recommended`, `removed`, or `renamed`
|
||||
- `in` or `to`
|
||||
- `GitLab` (or, for external projects, the name of the project)
|
||||
|
||||
The docs site uses [Ruby code](https://gitlab.com/gitlab-org/gitlab-docs/-/blob/main/lib/filters/introduced_in.rb)
|
||||
to render the notes based on these words.
|
||||
|
||||
In addition:
|
||||
|
||||
- Try to be consistent with other notes on the page, or other notes on the docs site.
|
||||
- Ensure that the output generates properly.
|
||||
- If possible, include a link to the related issue, merge request, or epic.
|
||||
- Do not link to the pricing page. Do not include the subscription tier.
|
||||
- Even if you have only one item, ensure it begins with `> -`.
|
||||
|
||||
#### Documenting updates to a feature
|
||||
|
||||
When a feature is changed or updated, add a new list item.
|
||||
Start the sentence with the feature name or a gerund.
|
||||
|
||||
For example, on the issue boards page:
|
||||
|
||||
```markdown
|
||||
> - [Introduced](https://issue-link) in GitLab 13.1.
|
||||
> - Creating an issue from an issue board [introduced](https://issue-link) in GitLab 14.1.
|
||||
```
|
||||
|
||||
Or on email notifications page:
|
||||
|
||||
```markdown
|
||||
> - [Introduced](https://issue-link) in GitLab 13.1.
|
||||
> - Notifications for expiring tokens [introduced](https://issue-link) in GitLab 14.3.
|
||||
```
|
||||
|
||||
#### Making features available as part of a program
|
||||
|
||||
When a feature is made available to users as a part of a program, add a new list item.
|
||||
|
||||
```markdown
|
||||
> - [Introduced](https://issue-link) in GitLab 15.1.
|
||||
> - Merged results pipelines [added](https://issue-link) to the [Registration Features Program](https://page-link) in GitLab 16.7.
|
||||
```
|
||||
|
||||
#### Moving subscription tiers
|
||||
|
||||
If a feature is moved to another subscription tier, use `moved`:
|
||||
|
||||
```markdown
|
||||
> - [Moved](https://issue-link) from GitLab Ultimate to GitLab Premium in 11.8.
|
||||
> - [Moved](https://issue-link) from GitLab Premium to GitLab Free in 12.0.
|
||||
```
|
||||
|
||||
#### Changing the feature status
|
||||
|
||||
If the feature status changes to experiment or beta, use `changed`:
|
||||
|
||||
```markdown
|
||||
> - [Introduced](https://issue-link) as an [experiment](../../policy/experiment-beta-support.md) in GitLab 15.7.
|
||||
> - [Changed](https://issue-link) to beta in GitLab 16.0.
|
||||
```
|
||||
|
||||
For a change to generally available, use:
|
||||
|
||||
```markdown
|
||||
> - [Generally available](https://issue-link) in GitLab 16.10.
|
||||
```
|
||||
|
||||
#### Features introduced behind feature flags
|
||||
|
||||
When features are introduced behind feature flags, you must add details about the feature flag to the documentation.
|
||||
For more information, see [Document features deployed behind feature flags](feature_flags.md).
|
||||
|
||||
### Inline history text
|
||||
|
||||
If you're adding content to an existing topic, you can add historical information
|
||||
inline with the existing text. If possible, include a link to the related issue,
|
||||
merge request, or epic. For example:
|
||||
|
||||
```markdown
|
||||
The voting strategy [in GitLab 13.4 and later](https://issue-link) requires the primary and secondary
|
||||
voters to agree.
|
||||
```
|
||||
|
||||
## Deprecations and removals
|
||||
|
||||
When GitLab deprecates or removes a feature, use the following process to update the documentation.
|
||||
This process requires temporarily changing content to be "deprecated" or "removed" before it's deleted.
|
||||
|
||||
If a feature is not generally available, you can delete the content outright instead of following these instructions.
|
||||
|
||||
NOTE:
|
||||
A separate process exists for [GraphQL docs](../api_graphql_styleguide.md#deprecating-schema-items)
|
||||
and [REST API docs](restful_api_styleguide.md#deprecations).
|
||||
|
||||
### Deprecate a page or topic
|
||||
|
||||
To deprecate a page or topic:
|
||||
|
||||
1. Add `(deprecated)` after the title. Use a warning to explain when it was deprecated,
|
||||
when it will be removed, and the replacement feature.
|
||||
|
||||
```markdown
|
||||
## Title (deprecated)
|
||||
|
||||
DETAILS:
|
||||
**Tier:** Premium, Ultimate
|
||||
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
|
||||
|
||||
WARNING:
|
||||
This feature was [deprecated](https://issue-link) in GitLab 14.8
|
||||
and is planned for removal in 15.4. Use [feature X](link-to-docs.md) instead.
|
||||
```
|
||||
|
||||
If you're not sure when the feature will be removed or no
|
||||
replacement feature exists, you don't need to add this information.
|
||||
|
||||
1. If the deprecation is a [breaking change](../../update/terminology.md#breaking-change), add this text:
|
||||
|
||||
```markdown
|
||||
This change is a breaking change.
|
||||
```
|
||||
|
||||
You can add any additional context-specific details that might help users.
|
||||
|
||||
1. Add the following HTML comments above and below the content. For `remove_date`,
|
||||
set a date three months after the [release where it will be removed](https://about.gitlab.com/releases/).
|
||||
|
||||
```markdown
|
||||
<!--- start_remove The following content will be removed on remove_date: 'YYYY-MM-DD' -->
|
||||
|
||||
## Title (deprecated)
|
||||
|
||||
DETAILS:
|
||||
**Tier:** Premium, Ultimate
|
||||
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
|
||||
|
||||
WARNING:
|
||||
This feature was [deprecated](https://issue-link) in GitLab 14.8
|
||||
and is planned for removal in 15.4. Use [feature X](link-to-docs.md) instead.
|
||||
|
||||
<!--- end_remove -->
|
||||
```
|
||||
|
||||
1. Open a merge request to add the word `(deprecated)` to the left nav, after the page title.
|
||||
|
||||
### Remove a page
|
||||
|
||||
Mark content as removed during the release the feature was removed.
|
||||
The title and a removed indicator remains until three months after the removal.
|
||||
|
||||
To remove a page:
|
||||
|
||||
1. Leave the page title. Remove all other content, including the history items and the word `WARNING:`.
|
||||
1. After the title, change `(deprecated)` to `(removed)`.
|
||||
1. Update the YAML metadata:
|
||||
- For `remove_date`, set the value to a date three months after
|
||||
the release when the feature was removed.
|
||||
- For the `redirect_to`, set a path to a file that makes sense. If no obvious
|
||||
page exists, use the docs home page.
|
||||
|
||||
```markdown
|
||||
---
|
||||
stage: Data Stores
|
||||
group: Global Search
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
remove_date: '2022-08-02'
|
||||
redirect_to: '../newpath/to/file/index.md'
|
||||
---
|
||||
|
||||
# Title (removed)
|
||||
|
||||
DETAILS:
|
||||
**Tier:** Premium, Ultimate
|
||||
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
|
||||
|
||||
This feature was [deprecated](https://issue-link) in GitLab X.Y
|
||||
and [removed](https://issue-link) in X.Y.
|
||||
Use [feature X](link-to-docs.md) instead.
|
||||
```
|
||||
|
||||
1. Remove the page's entry from the global navigation by editing [`navigation.yaml`](https://gitlab.com/gitlab-org/gitlab-docs/blob/main/content/_data/navigation.yaml) in `gitlab-docs`.
|
||||
|
||||
This content is removed from the documentation as part of the Technical Writing team's
|
||||
[regularly scheduled tasks](https://handbook.gitlab.com/handbook/product/ux/technical-writing/#regularly-scheduled-tasks).
|
||||
|
||||
### Remove a topic
|
||||
|
||||
To remove a topic:
|
||||
|
||||
1. Leave the title and the details of the deprecation and removal. Remove all other content,
|
||||
including the history items and the word `WARNING:`.
|
||||
1. Add `(removed)` after the title.
|
||||
1. Add the following HTML comments above and below the topic.
|
||||
For `remove_date`, set a date three months after the release where it was removed.
|
||||
|
||||
```markdown
|
||||
<!--- start_remove The following content will be removed on remove_date: 'YYYY-MM-DD' -->
|
||||
|
||||
## Title (removed)
|
||||
|
||||
DETAILS:
|
||||
**Tier:** Premium, Ultimate
|
||||
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
|
||||
|
||||
This feature was [deprecated](https://issue-link) in GitLab X.Y
|
||||
and [removed](https://issue-link) in X.Y.
|
||||
Use [feature X](link-to-docs.md) instead.
|
||||
|
||||
<!--- end_remove -->
|
||||
```
|
||||
|
||||
This content is removed from the documentation as part of the Technical Writing team's
|
||||
[regularly scheduled tasks](https://handbook.gitlab.com/handbook/product/ux/technical-writing/#regularly-scheduled-tasks).
|
||||
|
||||
## Which versions are removed
|
||||
|
||||
GitLab supports the current major version and two previous major versions.
|
||||
For example, if 16.0 is the current major version, all major and minor releases of
|
||||
GitLab 16.0, 15.0, and 14.0 are supported.
|
||||
|
||||
[View the list of supported versions](https://about.gitlab.com/support/statement-of-support/#version-support).
|
||||
|
||||
If you see history items or inline text that refers to unsupported versions, you can remove it.
|
||||
|
||||
In the history, remove information about [features behind feature flags](feature_flags.md)
|
||||
only if all events related to the feature flag happened in unsupported versions.
|
||||
If the flag hasn't been removed, readers should know when it was introduced.
|
||||
|
||||
Historical feature information is available in [release posts](https://about.gitlab.com/releases/)
|
||||
or by searching for the issue or merge request where the work was done.
|
||||
|
||||
### Timing of removals
|
||||
|
||||
When a new major version is about to be released, you can start creating merge
|
||||
requests to remove any mentions of the last unsupported version, but only merge
|
||||
them during the milestone of the new major release.
|
||||
|
||||
For example, if GitLab 17.0 is the new major upcoming release:
|
||||
|
||||
- The supported versions are 16, 15, and 14.
|
||||
- When GitLab 17.0 is released, GitLab 14 is no longer supported.
|
||||
|
||||
You can then create merge requests to remove any mentions to GitLab 14, but only
|
||||
merge them during the 17.0 milestone, which is after 16.11 is released.
|
||||
|
||||
### Exception for upgrade pages
|
||||
|
||||
The [version-specific pages](../../update/index.md#version-specific-upgrading-instructions) are the only exception to the previous guideline.
|
||||
For example, `doc/update/versions/14_changes.md` should
|
||||
be removed during the `.3` milestone. In this example, the changes would be removed in 17.3.
|
||||
|
||||
We don't remove those pages immediately so that users have time to upgrade
|
||||
from older versions.
|
||||
|
||||
Instead of removing the unsupported page,
|
||||
[add a note](#remove-a-topic) with a date three months in the future.
|
||||
This note ensures the page is cleaned up as part of the
|
||||
[monthly maintenance tasks](https://handbook.gitlab.com/handbook/product/ux/technical-writing/#regularly-scheduled-tasks).
|
||||
|
||||
Also, if the `X_changes.md` page contains relative links to other sections
|
||||
that are removed as part of the versions cleanup, the `docs-lint links`
|
||||
job will likely fail. You can replace those relative links with an archived
|
||||
version. Be sure to pick the latest minor version of the
|
||||
unsupported version to be removed as shown in
|
||||
<https://archives.docs.gitlab.com/>.
|
||||
|
||||
## Promising features in future versions
|
||||
|
||||
Do not promise to deliver features in a future release. For example, avoid phrases like,
|
||||
"Support for this feature is planned."
|
||||
|
||||
We cannot guarantee future feature work, and promises
|
||||
like these can raise legal issues. Instead, say that an issue exists.
|
||||
For example:
|
||||
|
||||
- Support for improvements is proposed in `[issue <issue_number>](https://link-to-issue)`.
|
||||
- You cannot do this thing, but `[issue 12345](https://link-to-issue)` proposes to change this behavior.
|
||||
|
||||
You can say that we plan to remove a feature.
|
||||
|
||||
### Legal disclaimer for future features
|
||||
|
||||
If you **must** write about features we have not yet delivered, put this exact disclaimer about forward-looking statements near the content it applies to.
|
||||
|
||||
```markdown
|
||||
DISCLAIMER:
|
||||
This page contains information related to upcoming products, features, and functionality.
|
||||
It is important to note that the information presented is for informational purposes only.
|
||||
Please do not rely on this information for purchasing or planning purposes.
|
||||
The development, release, and timing of any products, features, or functionality may be subject to change or delay and remain at the
|
||||
sole discretion of GitLab Inc.
|
||||
```
|
||||
|
||||
It renders on the GitLab documentation site as:
|
||||
|
||||
DISCLAIMER:
|
||||
This page contains information related to upcoming products, features, and functionality.
|
||||
It is important to note that the information presented is for informational purposes only.
|
||||
Please do not rely on this information for purchasing or planning purposes.
|
||||
The development, release, and timing of any products, features, or functionality may be subject to change or delay and remain at the
|
||||
sole discretion of GitLab Inc.
|
||||
|
||||
If all of the content on the page is not available, use the disclaimer about forward-looking statements once at the top of the page.
|
||||
|
||||
If the content in a topic is not ready, use the disclaimer in the topic.
|
||||
<!-- This redirect file can be deleted after <2024-11-02>. -->
|
||||
<!-- 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 (for example, link is not relative and starts with `https:`) expire in one year. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
|
||||
|
|
|
|||
|
|
@ -430,7 +430,7 @@ You must announce any deprecation [no later than the third milestone preceding i
|
|||
To deprecate an integration:
|
||||
|
||||
- [Add a deprecation entry](../../development/deprecation_guidelines/index.md#update-the-deprecations-and-removals-documentation).
|
||||
- [Mark the integration documentation as deprecated](../../development/documentation/versions.md#deprecate-a-page-or-topic).
|
||||
- [Mark the integration documentation as deprecated](../../development/documentation/styleguide/deprecations_and_removals.md).
|
||||
- Optional. To prevent any new project-level records from
|
||||
being created, add the integration to `Project#disabled_integrations` (see [example merge request](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/114835)).
|
||||
|
||||
|
|
@ -443,7 +443,7 @@ In the major milestone of intended removal (M.0), disable the integration and de
|
|||
- Remove the integration from `Integration::INTEGRATION_NAMES`.
|
||||
- Delete the integration model's `#execute` and `#test` methods (if defined), but keep the model.
|
||||
- Add a post-migration to delete the integration records from PostgreSQL (see [example merge request](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/114721)).
|
||||
- [Mark the integration documentation as removed](../../development/documentation/versions.md#remove-a-page).
|
||||
- [Mark the integration documentation as removed](../../development/documentation/styleguide/deprecations_and_removals.md#remove-a-page).
|
||||
- [Update the integration API documentation](../../api/integrations.md).
|
||||
|
||||
In the next minor release (M.1):
|
||||
|
|
|
|||
|
|
@ -169,9 +169,12 @@ after more changes are added to the merge request:
|
|||
clear the **Remove all approvals** checkbox.
|
||||
1. Select **Save changes**.
|
||||
|
||||
Approvals aren't removed when a merge request is
|
||||
[rebased from the UI](../methods/index.md#rebasing-in-semi-linear-merge-methods)
|
||||
However, approvals are reset if the target branch changes.
|
||||
GitLab uses [`git patch-id`](https://git-scm.com/docs/git-patch-id) to identify diffs
|
||||
in merge requests. This value is a reasonably stable and unique identifier, and it enables
|
||||
smarter decisions about resetting approvals inside a merge request. When you push new changes
|
||||
to a merge request, the `patch-id` is evaluated against the previous `patch-id` to determine
|
||||
if the approvals should be reset. This enables GitLab to make better reset decisions when
|
||||
you perform commands like `git rebase` or `git merge <target>` on a feature branch.
|
||||
|
||||
## Remove approvals by Code Owners if their files changed
|
||||
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ module Gitlab
|
|||
find_user_from_web_access_token(request_format, scopes: [:api, :read_api]) ||
|
||||
find_user_from_feed_token(request_format) ||
|
||||
find_user_from_static_object_token(request_format) ||
|
||||
find_user_from_job_token_basic_auth ||
|
||||
find_user_from_job_token_basic_auth_feature_flag_wrapper ||
|
||||
find_user_from_job_token ||
|
||||
find_user_from_personal_access_token_for_api_or_git ||
|
||||
find_user_for_git_or_lfs_request
|
||||
|
|
@ -81,6 +81,13 @@ module Gitlab
|
|||
|
||||
private
|
||||
|
||||
def find_user_from_job_token_basic_auth_feature_flag_wrapper
|
||||
user = find_user_from_job_token_basic_auth
|
||||
return if ::Feature.enabled?(:request_authenticator_exclude_job_token_basic_auth, user)
|
||||
|
||||
user
|
||||
end
|
||||
|
||||
def access_token
|
||||
strong_memoize(:access_token) do
|
||||
super || find_personal_access_token_from_http_basic_auth
|
||||
|
|
|
|||
|
|
@ -10533,6 +10533,9 @@ msgstr ""
|
|||
msgid "CascadingSettings|Enforce for all subgroups"
|
||||
msgstr ""
|
||||
|
||||
msgid "CascadingSettings|Lock tooltip icon"
|
||||
msgstr ""
|
||||
|
||||
msgid "CascadingSettings|Setting cannot be changed"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -16727,12 +16730,6 @@ msgstr ""
|
|||
msgid "Dashboard"
|
||||
msgstr ""
|
||||
|
||||
msgid "DashboardProjects|All"
|
||||
msgstr ""
|
||||
|
||||
msgid "DashboardProjects|Personal"
|
||||
msgstr ""
|
||||
|
||||
msgid "Dashboard|%{firstProject} and %{secondProject}"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -4,10 +4,6 @@ module QA
|
|||
module Page
|
||||
module Dashboard
|
||||
class Projects < Page::Base
|
||||
view 'app/views/shared/projects/_search_form.html.haml' do
|
||||
element 'project-filter-form-container', required: true
|
||||
end
|
||||
|
||||
view 'app/views/shared/projects/_project.html.haml' do
|
||||
element 'project-content'
|
||||
element 'user-access-role'
|
||||
|
|
@ -35,9 +31,10 @@ module QA
|
|||
end
|
||||
|
||||
def filter_by_name(name)
|
||||
within_element('project-filter-form-container') do
|
||||
fill_in :name, with: name
|
||||
end
|
||||
filter_input = find_element('filtered-search-term-input')
|
||||
filter_input.click
|
||||
filter_input.set(name)
|
||||
click_element 'search-button'
|
||||
end
|
||||
|
||||
def go_to_project(name)
|
||||
|
|
@ -55,7 +52,7 @@ module QA
|
|||
end
|
||||
|
||||
def clear_project_filter
|
||||
fill_element('project-filter-form-container', "")
|
||||
click_element 'filtered-search-clear-button'
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
|||
|
|
@ -189,7 +189,7 @@ function run_locally_or_in_container() {
|
|||
local cmd=$1
|
||||
local args=$2
|
||||
local files=$3
|
||||
local registry_url="registry.gitlab.com/gitlab-org/gitlab-docs/lint-markdown:alpine-3.20-vale-3.4.2-markdownlint2-0.13.0-lychee-0.15.1"
|
||||
local registry_url="registry.gitlab.com/gitlab-org/gitlab-docs/lint-markdown:alpine-3.20-vale-3.6.1-markdownlint2-0.13.0-lychee-0.15.1"
|
||||
|
||||
if hash "${cmd}" 2>/dev/null
|
||||
then
|
||||
|
|
|
|||
|
|
@ -3,14 +3,18 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'Dashboard Archived Project', feature_category: :groups_and_projects do
|
||||
let(:user) { create :user }
|
||||
let(:project) { create :project }
|
||||
let(:archived_project) { create(:project, :archived) }
|
||||
let_it_be(:user) { create :user }
|
||||
let_it_be(:project) { create :project }
|
||||
let_it_be(:archived_project) { create(:project, :archived) }
|
||||
let_it_be(:archived_project_2) { create(:project, :archived) }
|
||||
|
||||
before do
|
||||
before_all do
|
||||
project.add_maintainer(user)
|
||||
archived_project.add_maintainer(user)
|
||||
archived_project_2.add_maintainer(user)
|
||||
end
|
||||
|
||||
before do
|
||||
sign_in(user)
|
||||
|
||||
visit dashboard_projects_path
|
||||
|
|
@ -21,32 +25,30 @@ RSpec.describe 'Dashboard Archived Project', feature_category: :groups_and_proje
|
|||
expect(page).not_to have_link(archived_project.name)
|
||||
end
|
||||
|
||||
it 'renders all projects' do
|
||||
click_link 'Show archived projects'
|
||||
|
||||
expect(page).to have_link(project.name)
|
||||
expect(page).to have_link(archived_project.name)
|
||||
end
|
||||
|
||||
it 'renders only archived projects' do
|
||||
click_link 'Show archived projects only'
|
||||
click_link 'Inactive'
|
||||
|
||||
expect(page).to have_content(archived_project.name)
|
||||
expect(page).not_to have_content(project.name)
|
||||
end
|
||||
|
||||
it 'searches archived projects', :js do
|
||||
click_button 'Name'
|
||||
click_link 'Show archived projects'
|
||||
click_link 'Inactive'
|
||||
|
||||
expect(page).to have_link(project.name)
|
||||
expect(page).to have_link(archived_project.name)
|
||||
expect(page).to have_link(archived_project_2.name)
|
||||
|
||||
fill_in 'project-filter-form-field', with: archived_project.name
|
||||
search(archived_project.name)
|
||||
|
||||
find('#project-filter-form-field').native.send_keys :return
|
||||
|
||||
expect(page).not_to have_link(project.name)
|
||||
expect(page).not_to have_link(archived_project_2.name)
|
||||
expect(page).to have_link(archived_project.name)
|
||||
end
|
||||
|
||||
def search(term)
|
||||
filter_input = find_by_testid('filtered-search-term-input')
|
||||
filter_input.click
|
||||
filter_input.set(term)
|
||||
click_button 'Search'
|
||||
wait_for_requests
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'Dashboard > User filters projects', feature_category: :groups_and_projects do
|
||||
RSpec.describe 'Dashboard > User filters projects', :js, feature_category: :groups_and_projects do
|
||||
let(:user) { create(:user) }
|
||||
let(:project) { create(:project, name: 'Victorialand', namespace: user.namespace, created_at: 2.seconds.ago, updated_at: 2.seconds.ago) }
|
||||
let(:user2) { create(:user) }
|
||||
|
|
@ -14,51 +14,58 @@ RSpec.describe 'Dashboard > User filters projects', feature_category: :groups_an
|
|||
sign_in(user)
|
||||
end
|
||||
|
||||
describe 'filtering personal projects' do
|
||||
before do
|
||||
it 'allows viewing personal projects' do
|
||||
project2.add_developer(user)
|
||||
|
||||
visit dashboard_projects_path
|
||||
|
||||
click_link 'Personal'
|
||||
|
||||
expect(page).to have_content(project.name)
|
||||
expect(page).not_to have_content(project2.name)
|
||||
end
|
||||
|
||||
it 'filters by projects "Owned by me"' do
|
||||
click_link 'Owned by me'
|
||||
|
||||
expect(page).to have_css('.is-active', text: 'Owned by me')
|
||||
expect(page).to have_content('Victorialand')
|
||||
expect(page).not_to have_content('Treasure')
|
||||
end
|
||||
end
|
||||
|
||||
describe 'filtering starred projects', :js do
|
||||
describe 'starred projects', :js do
|
||||
before do
|
||||
user.toggle_star(project)
|
||||
|
||||
visit dashboard_projects_path
|
||||
end
|
||||
|
||||
it 'returns message when starred projects filter returns no results' do
|
||||
fill_in 'project-filter-form-field', with: 'Beta\n'
|
||||
|
||||
expect(page).to have_content('There are no projects available to be displayed here')
|
||||
expect(page).not_to have_content('You don\'t have starred projects yet')
|
||||
end
|
||||
end
|
||||
|
||||
describe 'without search bar', :js do
|
||||
before do
|
||||
it 'allows viewing starred projects' do
|
||||
project2.add_developer(user)
|
||||
visit dashboard_projects_path
|
||||
|
||||
click_link 'Starred'
|
||||
|
||||
expect(page).to have_content(project.name)
|
||||
expect(page).not_to have_content(project2.name)
|
||||
end
|
||||
|
||||
it 'autocompletes searches upon typing', :js do
|
||||
expect(page).to have_content 'Victorialand'
|
||||
expect(page).to have_content 'Treasure'
|
||||
it 'shows empty state when starred projects filter returns no results' do
|
||||
search('foo')
|
||||
|
||||
fill_in 'project-filter-form-field', with: 'Lord beerus\n'
|
||||
|
||||
expect(page).not_to have_content 'Victorialand'
|
||||
expect(page).not_to have_content 'Treasure'
|
||||
expect(page).not_to have_content("You don't have starred projects yet.")
|
||||
end
|
||||
end
|
||||
|
||||
it 'searches for projects' do
|
||||
project2.add_developer(user)
|
||||
visit dashboard_projects_path
|
||||
|
||||
expect(page).to have_content(project.name)
|
||||
expect(page).to have_content(project2.name)
|
||||
|
||||
search(project.name)
|
||||
|
||||
expect(page).to have_content(project.name)
|
||||
expect(page).not_to have_content(project2.name)
|
||||
end
|
||||
|
||||
def search(term)
|
||||
filter_input = find_by_testid('filtered-search-term-input')
|
||||
filter_input.click
|
||||
filter_input.set(term)
|
||||
click_button 'Search'
|
||||
wait_for_requests
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -19,7 +19,8 @@ RSpec.describe 'Projects > Settings > Packages', :js, feature_category: :package
|
|||
let(:packages_enabled) { true }
|
||||
|
||||
it 'displays the packages access level setting' do
|
||||
expect(page).to have_selector('[data-testid="package-registry-access-level"] > label', text: 'Package registry')
|
||||
within_testid('package-registry-access-level') do
|
||||
expect(page).to have_content('Package registry')
|
||||
expect(page).to have_selector('input[name="package_registry_enabled"]', visible: false)
|
||||
expect(page).to have_selector('input[name="package_registry_enabled"] + button', visible: true)
|
||||
expect(page).to have_selector('input[name="package_registry_api_for_everyone_enabled"]', visible: false)
|
||||
|
|
@ -30,6 +31,7 @@ RSpec.describe 'Projects > Settings > Packages', :js, feature_category: :package
|
|||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'Packages disabled in config' do
|
||||
let(:packages_enabled) { false }
|
||||
|
|
|
|||
|
|
@ -14,18 +14,20 @@ RSpec.describe 'User sorts projects and order persists', feature_category: :grou
|
|||
find('button[data-testid=base-dropdown-toggle]')
|
||||
end
|
||||
|
||||
shared_examples_for "sort order persists across all views" do |project_paths_label, vue_sort_label|
|
||||
shared_examples_for "sort order persists across all views" do |sort_label|
|
||||
it "is set on the dashboard_projects_path" do
|
||||
visit(dashboard_projects_path)
|
||||
|
||||
expect(find('#sort-projects-dropdown')).to have_content(project_paths_label)
|
||||
within '[data-testid=groups-projects-sort]' do
|
||||
expect(find_dropdown_toggle).to have_content(sort_label)
|
||||
end
|
||||
end
|
||||
|
||||
it "is set on the explore_projects_path" do
|
||||
visit(explore_projects_path)
|
||||
|
||||
within '[data-testid=groups-projects-sort]' do
|
||||
expect(find_dropdown_toggle).to have_content(vue_sort_label)
|
||||
expect(find_dropdown_toggle).to have_content(sort_label)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -33,7 +35,7 @@ RSpec.describe 'User sorts projects and order persists', feature_category: :grou
|
|||
visit(group_canonical_path(group))
|
||||
|
||||
within '[data-testid=groups-projects-sort]' do
|
||||
expect(find_dropdown_toggle).to have_content(vue_sort_label)
|
||||
expect(find_dropdown_toggle).to have_content(sort_label)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -41,7 +43,7 @@ RSpec.describe 'User sorts projects and order persists', feature_category: :grou
|
|||
visit(details_group_path(group))
|
||||
|
||||
within '[data-testid=groups-projects-sort]' do
|
||||
expect(find_dropdown_toggle).to have_content(vue_sort_label)
|
||||
expect(find_dropdown_toggle).to have_content(sort_label)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -57,18 +59,21 @@ RSpec.describe 'User sorts projects and order persists', feature_category: :grou
|
|||
end
|
||||
end
|
||||
|
||||
it_behaves_like "sort order persists across all views", 'Name', 'Name'
|
||||
it_behaves_like "sort order persists across all views", 'Name'
|
||||
end
|
||||
|
||||
context 'from dashboard projects', :js do
|
||||
before do
|
||||
sign_in(user)
|
||||
visit(dashboard_projects_path)
|
||||
find('#sort-projects-dropdown').click
|
||||
first(:link, 'Name').click
|
||||
within '[data-testid=groups-projects-sort]' do
|
||||
find_dropdown_toggle.click
|
||||
find('li', text: 'Created').click
|
||||
wait_for_requests
|
||||
end
|
||||
end
|
||||
|
||||
it_behaves_like "sort order persists across all views", "Name", "Name"
|
||||
it_behaves_like "sort order persists across all views", "Created"
|
||||
end
|
||||
|
||||
context 'from group homepage', :js do
|
||||
|
|
@ -82,7 +87,7 @@ RSpec.describe 'User sorts projects and order persists', feature_category: :grou
|
|||
end
|
||||
end
|
||||
|
||||
it_behaves_like "sort order persists across all views", "Oldest created", "Created"
|
||||
it_behaves_like "sort order persists across all views", "Created"
|
||||
end
|
||||
|
||||
context 'from group details', :js do
|
||||
|
|
@ -96,6 +101,6 @@ RSpec.describe 'User sorts projects and order persists', feature_category: :grou
|
|||
end
|
||||
end
|
||||
|
||||
it_behaves_like "sort order persists across all views", "Oldest updated", "Updated"
|
||||
it_behaves_like "sort order persists across all views", "Updated"
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,89 @@
|
|||
import { shallowMount } from '@vue/test-utils';
|
||||
import { GlIcon } from '@gitlab/ui';
|
||||
import { nextTick } from 'vue';
|
||||
import CascadingLockIcon from '~/namespaces/cascading_settings/components/cascading_lock_icon.vue';
|
||||
import LockTooltip from '~/namespaces/cascading_settings/components/lock_tooltip.vue';
|
||||
|
||||
describe('CascadingLockIcon', () => {
|
||||
let wrapper;
|
||||
|
||||
const createComponent = (props = {}) => {
|
||||
return shallowMount(CascadingLockIcon, {
|
||||
propsData: {
|
||||
isLockedByApplicationSettings: false,
|
||||
isLockedByGroupAncestor: false,
|
||||
...props,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const findLockTooltip = () => wrapper.findComponent(LockTooltip);
|
||||
const findIcon = () => wrapper.findComponent(GlIcon);
|
||||
|
||||
beforeEach(() => {
|
||||
wrapper = createComponent();
|
||||
});
|
||||
|
||||
it('renders the GlIcon component', () => {
|
||||
expect(findIcon().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('sets correct attributes on GlIcon', () => {
|
||||
wrapper = createComponent();
|
||||
expect(findIcon().props()).toMatchObject({
|
||||
name: 'lock',
|
||||
ariaLabel: 'Lock tooltip icon',
|
||||
});
|
||||
});
|
||||
|
||||
it('does not render LockTooltip when targetElement is null', () => {
|
||||
wrapper = createComponent();
|
||||
expect(findLockTooltip().exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('renders LockTooltip after mounting', async () => {
|
||||
wrapper = createComponent();
|
||||
await nextTick();
|
||||
await nextTick();
|
||||
expect(findLockTooltip().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('sets targetElement after mounting', async () => {
|
||||
wrapper = createComponent();
|
||||
await nextTick();
|
||||
await nextTick();
|
||||
expect(findLockTooltip().props().targetElement).not.toBeNull();
|
||||
});
|
||||
|
||||
it('passes correct props to LockTooltip', async () => {
|
||||
const ancestorNamespace = { path: '/test', fullName: 'Test' };
|
||||
wrapper = createComponent({
|
||||
ancestorNamespace,
|
||||
isLockedByApplicationSettings: true,
|
||||
isLockedByGroupAncestor: true,
|
||||
});
|
||||
|
||||
await nextTick();
|
||||
await nextTick();
|
||||
|
||||
expect(findLockTooltip().props()).toMatchObject({
|
||||
ancestorNamespace,
|
||||
isLockedByAdmin: true,
|
||||
isLockedByGroupAncestor: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('validates ancestorNamespace prop', () => {
|
||||
const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
|
||||
// Valid prop
|
||||
createComponent({ ancestorNamespace: { path: '/test', fullName: 'Test' } });
|
||||
expect(consoleErrorSpy).not.toHaveBeenCalled();
|
||||
|
||||
// Invalid prop
|
||||
createComponent({ ancestorNamespace: { path: '/test' } });
|
||||
expect(consoleErrorSpy).toHaveBeenCalled();
|
||||
|
||||
consoleErrorSpy.mockRestore();
|
||||
});
|
||||
});
|
||||
|
|
@ -1,44 +1,44 @@
|
|||
import { GlPopover } from '@gitlab/ui';
|
||||
import { GlTooltip } from '@gitlab/ui';
|
||||
import { mountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import HamlLockPopover from '~/namespaces/cascading_settings/components/haml_lock_popovers.vue';
|
||||
import LockPopover from '~/namespaces/cascading_settings/components/lock_popover.vue';
|
||||
import HamlLockTooltips from '~/namespaces/cascading_settings/components/haml_lock_tooltips.vue';
|
||||
import LockTooltip from '~/namespaces/cascading_settings/components/lock_tooltip.vue';
|
||||
|
||||
describe('HamlLockPopover', () => {
|
||||
describe('HamlLockTooltips', () => {
|
||||
const mockNamespace = {
|
||||
fullName: 'GitLab Org / GitLab',
|
||||
path: '/gitlab-org/gitlab/-/edit',
|
||||
};
|
||||
|
||||
const createPopoverMountEl = ({
|
||||
const createTooltipMountEl = ({
|
||||
lockedByApplicationSetting = false,
|
||||
lockedByAncestor = false,
|
||||
}) => {
|
||||
const popoverMountEl = document.createElement('div');
|
||||
popoverMountEl.classList.add('js-cascading-settings-lock-popover-target');
|
||||
const tooltipMountEl = document.createElement('div');
|
||||
tooltipMountEl.classList.add('js-cascading-settings-lock-tooltip-target');
|
||||
|
||||
const popoverData = {
|
||||
const tooltipData = {
|
||||
locked_by_application_setting: lockedByApplicationSetting,
|
||||
locked_by_ancestor: lockedByAncestor,
|
||||
};
|
||||
|
||||
popoverMountEl.dataset.popoverData = JSON.stringify(popoverData);
|
||||
popoverMountEl.dataset.popoverData = JSON.stringify({
|
||||
...popoverData,
|
||||
tooltipMountEl.dataset.tooltipData = JSON.stringify(tooltipData);
|
||||
tooltipMountEl.dataset.tooltipData = JSON.stringify({
|
||||
...tooltipData,
|
||||
ancestor_namespace: lockedByAncestor && !lockedByApplicationSetting ? mockNamespace : null,
|
||||
});
|
||||
|
||||
document.body.appendChild(popoverMountEl);
|
||||
document.body.appendChild(tooltipMountEl);
|
||||
|
||||
return popoverMountEl;
|
||||
return tooltipMountEl;
|
||||
};
|
||||
|
||||
let wrapper;
|
||||
|
||||
const createWrapper = () => {
|
||||
wrapper = mountExtended(HamlLockPopover);
|
||||
wrapper = mountExtended(HamlLockTooltips);
|
||||
};
|
||||
|
||||
const findLockPopovers = () => wrapper.findAllComponents(LockPopover);
|
||||
const findLockTooltips = () => wrapper.findAllComponents(LockTooltip);
|
||||
|
||||
afterEach(() => {
|
||||
document.body.innerHTML = '';
|
||||
|
|
@ -57,7 +57,7 @@ describe('HamlLockPopover', () => {
|
|||
'when locked_by_application_setting is $lockedByApplicationSetting and locked_by_ancestor is $lockedByAncestor and ancestor_namespace is $ancestorNamespace',
|
||||
({ ancestorNamespace, lockedByAncestor, lockedByApplicationSetting }) => {
|
||||
beforeEach(() => {
|
||||
domElement = createPopoverMountEl({
|
||||
domElement = createTooltipMountEl({
|
||||
ancestorNamespace,
|
||||
lockedByApplicationSetting,
|
||||
lockedByAncestor,
|
||||
|
|
@ -66,40 +66,40 @@ describe('HamlLockPopover', () => {
|
|||
});
|
||||
|
||||
it('locked_by_application_setting attribute', () => {
|
||||
expect(findLockPopovers().at(0).props().isLockedByAdmin).toBe(lockedByApplicationSetting);
|
||||
expect(findLockTooltips().at(0).props().isLockedByAdmin).toBe(lockedByApplicationSetting);
|
||||
});
|
||||
|
||||
it('locked_by_ancestor attribute', () => {
|
||||
expect(findLockPopovers().at(0).props().isLockedByGroupAncestor).toBe(lockedByAncestor);
|
||||
expect(findLockTooltips().at(0).props().isLockedByGroupAncestor).toBe(lockedByAncestor);
|
||||
});
|
||||
|
||||
it('ancestor_namespace attribute', () => {
|
||||
expect(findLockPopovers().at(0).props().ancestorNamespace).toEqual(ancestorNamespace);
|
||||
expect(findLockTooltips().at(0).props().ancestorNamespace).toEqual(ancestorNamespace);
|
||||
});
|
||||
|
||||
it('target element', () => {
|
||||
expect(findLockPopovers().at(0).props().targetElement).toBe(domElement);
|
||||
expect(findLockTooltips().at(0).props().targetElement).toBe(domElement);
|
||||
});
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
describe('when there are multiple mount elements', () => {
|
||||
let popoverMountEl1;
|
||||
let popoverMountEl2;
|
||||
let tooltipMountEl1;
|
||||
let tooltipMountEl2;
|
||||
|
||||
beforeEach(() => {
|
||||
popoverMountEl1 = createPopoverMountEl({ lockedByApplicationSetting: true });
|
||||
popoverMountEl2 = createPopoverMountEl({ lockedByAncestor: true });
|
||||
tooltipMountEl1 = createTooltipMountEl({ lockedByApplicationSetting: true });
|
||||
tooltipMountEl2 = createTooltipMountEl({ lockedByAncestor: true });
|
||||
createWrapper();
|
||||
});
|
||||
|
||||
it('mounts multiple popovers', () => {
|
||||
const popovers = wrapper.findAllComponents(GlPopover).wrappers;
|
||||
it('mounts multiple tooltips', () => {
|
||||
const tooltips = wrapper.findAllComponents(GlTooltip).wrappers;
|
||||
|
||||
expect(popovers).toHaveLength(2);
|
||||
expect(popovers[0].props('target')).toBe(popoverMountEl1);
|
||||
expect(popovers[1].props('target')).toBe(popoverMountEl2);
|
||||
expect(tooltips).toHaveLength(2);
|
||||
expect(tooltips[0].props('target')).toBe(tooltipMountEl1);
|
||||
expect(tooltips[1].props('target')).toBe(tooltipMountEl2);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
import { GlLink, GlPopover, GlSprintf } from '@gitlab/ui';
|
||||
import { GlLink, GlTooltip, GlSprintf } from '@gitlab/ui';
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import LockPopover from '~/namespaces/cascading_settings/components/lock_popover.vue';
|
||||
import LockTooltip from '~/namespaces/cascading_settings/components/lock_tooltip.vue';
|
||||
|
||||
describe('LockPopover', () => {
|
||||
describe('LockTooltip', () => {
|
||||
const mockNamespace = {
|
||||
fullName: 'GitLab Org / GitLab',
|
||||
path: '/gitlab-org/gitlab/-/edit',
|
||||
|
|
@ -12,15 +12,15 @@ describe('LockPopover', () => {
|
|||
'An administrator selected this setting for the instance and you cannot change it.';
|
||||
|
||||
let wrapper;
|
||||
const popoverMountEl = document.createElement('div');
|
||||
const tooltipMountEl = document.createElement('div');
|
||||
|
||||
const createWrapper = (props = {}) => {
|
||||
wrapper = shallowMount(LockPopover, {
|
||||
wrapper = shallowMount(LockTooltip, {
|
||||
propsData: {
|
||||
ancestorNamespace: mockNamespace,
|
||||
isLockedByAdmin: false,
|
||||
isLockedByGroupAncestor: true,
|
||||
targetElement: popoverMountEl,
|
||||
isLockedByGroupAncestor: false,
|
||||
targetElement: tooltipMountEl,
|
||||
...props,
|
||||
},
|
||||
stubs: {
|
||||
|
|
@ -30,30 +30,33 @@ describe('LockPopover', () => {
|
|||
};
|
||||
|
||||
const findLink = () => wrapper.findComponent(GlLink);
|
||||
const findPopover = () => wrapper.findComponent(GlPopover);
|
||||
const findTooltip = () => wrapper.findComponent(GlTooltip);
|
||||
|
||||
describe('when setting is locked by an admin setting', () => {
|
||||
beforeEach(() => {
|
||||
createWrapper({ isLockedByAdmin: true });
|
||||
});
|
||||
|
||||
it('displays correct popover message', () => {
|
||||
expect(findPopover().text()).toBe(applicationSettingMessage);
|
||||
it('displays correct tooltip message', () => {
|
||||
expect(findTooltip().text()).toBe(applicationSettingMessage);
|
||||
});
|
||||
|
||||
it('sets `target` prop correctly', () => {
|
||||
expect(findPopover().props().target).toBe(popoverMountEl);
|
||||
expect(findTooltip().props().target).toBe(tooltipMountEl);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when setting is locked by an ancestor namespace', () => {
|
||||
describe('and ancestorNamespace is set', () => {
|
||||
beforeEach(() => {
|
||||
createWrapper({ isLockedByGroupAncestor: true, ancestorNamespace: mockNamespace });
|
||||
createWrapper({
|
||||
isLockedByGroupAncestor: true,
|
||||
ancestorNamespace: mockNamespace,
|
||||
});
|
||||
});
|
||||
|
||||
it('displays correct popover message', () => {
|
||||
expect(findPopover().text()).toBe(
|
||||
it('displays correct tooltip message', () => {
|
||||
expect(findTooltip().text()).toBe(
|
||||
`This setting has been enforced by an owner of ${mockNamespace.fullName}.`,
|
||||
);
|
||||
});
|
||||
|
|
@ -63,7 +66,7 @@ describe('LockPopover', () => {
|
|||
});
|
||||
|
||||
it('sets `target` prop correctly', () => {
|
||||
expect(findPopover().props().target).toBe(popoverMountEl);
|
||||
expect(findTooltip().props().target).toBe(tooltipMountEl);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -73,7 +76,7 @@ describe('LockPopover', () => {
|
|||
});
|
||||
|
||||
it('displays a generic message', () => {
|
||||
expect(findPopover().text()).toBe(
|
||||
expect(findTooltip().text()).toBe(
|
||||
`This setting has been enforced by an owner and cannot be changed.`,
|
||||
);
|
||||
});
|
||||
|
|
@ -82,15 +85,18 @@ describe('LockPopover', () => {
|
|||
|
||||
describe('when setting is locked by an application setting and an ancestor namespace', () => {
|
||||
beforeEach(() => {
|
||||
createWrapper({ isLockedByAdmin: true, isLockedByGroupAncestor: true });
|
||||
createWrapper({
|
||||
isLockedByAdmin: true,
|
||||
isLockedByGroupAncestor: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('displays correct popover message', () => {
|
||||
expect(findPopover().text()).toBe(applicationSettingMessage);
|
||||
it('displays correct tooltip message', () => {
|
||||
expect(findTooltip().text()).toBe(applicationSettingMessage);
|
||||
});
|
||||
|
||||
it('sets `target` prop correctly', () => {
|
||||
expect(findPopover().props().target).toBe(popoverMountEl);
|
||||
expect(findTooltip().props().target).toBe(tooltipMountEl);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -99,8 +105,8 @@ describe('LockPopover', () => {
|
|||
createWrapper({ isLockedByAdmin: false, isLockedByGroupAncestor: false });
|
||||
});
|
||||
|
||||
it('does not render popover', () => {
|
||||
expect(findPopover().exists()).toBe(false);
|
||||
it('does not render tooltip', () => {
|
||||
expect(findTooltip().exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -1,22 +1,22 @@
|
|||
import { shallowMount } from '@vue/test-utils';
|
||||
|
||||
import { nextTick } from 'vue';
|
||||
import { GlIcon } from '@gitlab/ui';
|
||||
import projectSettingRow from '~/pages/projects/shared/permissions/components/project_setting_row.vue';
|
||||
|
||||
describe('Project Setting Row', () => {
|
||||
let wrapper;
|
||||
|
||||
const mountComponent = (customProps = {}) => {
|
||||
const createComponent = (customProps = {}) => {
|
||||
const propsData = { ...customProps };
|
||||
return shallowMount(projectSettingRow, { propsData });
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
wrapper = mountComponent();
|
||||
wrapper = createComponent();
|
||||
});
|
||||
|
||||
it('should show the label if it is set', async () => {
|
||||
wrapper.setProps({ label: 'Test label' });
|
||||
wrapper = createComponent({ label: 'Test label' });
|
||||
|
||||
await nextTick();
|
||||
expect(wrapper.find('label').text()).toEqual('Test label');
|
||||
|
|
@ -26,8 +26,24 @@ describe('Project Setting Row', () => {
|
|||
expect(wrapper.find('label').exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('should apply gl-text-gray-400 class to label when locked', async () => {
|
||||
wrapper = createComponent({ label: 'Test label', locked: true });
|
||||
|
||||
await nextTick();
|
||||
expect(wrapper.find('label').classes()).toContain('gl-text-gray-400');
|
||||
});
|
||||
|
||||
it('should render default slot content', () => {
|
||||
wrapper = shallowMount(projectSettingRow, {
|
||||
slots: {
|
||||
'label-icon': GlIcon,
|
||||
},
|
||||
});
|
||||
expect(wrapper.findComponent(GlIcon).exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('should show the help icon with the correct help path if it is set', async () => {
|
||||
wrapper.setProps({ label: 'Test label', helpPath: '/123' });
|
||||
wrapper = createComponent({ label: 'Test label', helpPath: '/123' });
|
||||
|
||||
await nextTick();
|
||||
const link = wrapper.find('a');
|
||||
|
|
@ -37,14 +53,14 @@ describe('Project Setting Row', () => {
|
|||
});
|
||||
|
||||
it('should hide the help icon if no help path is set', async () => {
|
||||
wrapper.setProps({ label: 'Test label' });
|
||||
wrapper = createComponent({ label: 'Test label' });
|
||||
|
||||
await nextTick();
|
||||
expect(wrapper.find('a').exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('should show the help text if it is set', async () => {
|
||||
wrapper.setProps({ helpText: 'Test text' });
|
||||
wrapper = createComponent({ helpText: 'Test text' });
|
||||
|
||||
await nextTick();
|
||||
expect(wrapper.find('span').text()).toEqual('Test text');
|
||||
|
|
|
|||
|
|
@ -8,10 +8,10 @@ import {
|
|||
SORT_OPTIONS,
|
||||
SORT_DIRECTION_ASC,
|
||||
SORT_DIRECTION_DESC,
|
||||
} from '~/projects/explore/constants';
|
||||
} from '~/projects/filtered_search_and_sort/constants';
|
||||
import { RECENT_SEARCHES_STORAGE_KEY_PROJECTS } from '~/filtered_search/recent_searches_storage_keys';
|
||||
import FilteredSearchAndSort from '~/groups_projects/components/filtered_search_and_sort.vue';
|
||||
import ProjectsExploreFilteredSearchAndSort from '~/projects/explore/components/filtered_search_and_sort.vue';
|
||||
import ProjectsExploreFilteredSearchAndSort from '~/projects/filtered_search_and_sort/components/filtered_search_and_sort.vue';
|
||||
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import setWindowLocation from 'helpers/set_window_location_helper';
|
||||
import { visitUrl } from '~/lib/utils/url_utility';
|
||||
|
|
@ -37,8 +37,9 @@ describe('ProjectsExploreFilteredSearchAndSort', () => {
|
|||
{ id: 6, name: 'Ruby', color: '#701516', created_at: '2023-09-19T14:42:01.493Z' },
|
||||
{ id: 11, name: 'Shell', color: '#89e051', created_at: '2023-09-19T14:42:11.923Z' },
|
||||
],
|
||||
starredExploreProjectsPath: '/explore/projects/starred',
|
||||
exploreRootPath: '/explore',
|
||||
pathsToExcludeSortOn: ['/explore/projects/starred', '/explore'],
|
||||
sortEventName: 'use_sort_projects_explore',
|
||||
filterEventName: 'use_filter_bar_projects_explore',
|
||||
};
|
||||
|
||||
const createComponent = ({
|
||||
|
|
@ -124,7 +125,7 @@ describe('ProjectsExploreFilteredSearchAndSort', () => {
|
|||
const { trackEventSpy } = bindInternalEventDocument(wrapper.element);
|
||||
|
||||
expect(trackEventSpy).toHaveBeenCalledWith(
|
||||
'use_filter_bar_projects_explore',
|
||||
defaultProvide.filterEventName,
|
||||
{
|
||||
label: JSON.stringify({ search: searchTerm, language: 'CSS' }),
|
||||
},
|
||||
|
|
@ -152,7 +153,7 @@ describe('ProjectsExploreFilteredSearchAndSort', () => {
|
|||
const { trackEventSpy } = bindInternalEventDocument(wrapper.element);
|
||||
|
||||
expect(trackEventSpy).toHaveBeenCalledWith(
|
||||
'use_sort_projects_explore',
|
||||
defaultProvide.sortEventName,
|
||||
{
|
||||
label: `${SORT_OPTION_UPDATED.value}_${SORT_DIRECTION_ASC}`,
|
||||
},
|
||||
|
|
@ -180,7 +181,7 @@ describe('ProjectsExploreFilteredSearchAndSort', () => {
|
|||
const { trackEventSpy } = bindInternalEventDocument(wrapper.element);
|
||||
|
||||
expect(trackEventSpy).toHaveBeenCalledWith(
|
||||
'use_sort_projects_explore',
|
||||
defaultProvide.sortEventName,
|
||||
{
|
||||
label: `${SORT_OPTION_CREATED.value}_${SORT_DIRECTION_DESC}`,
|
||||
},
|
||||
|
|
@ -190,13 +191,10 @@ describe('ProjectsExploreFilteredSearchAndSort', () => {
|
|||
});
|
||||
|
||||
describe('when on the "Most starred" tab', () => {
|
||||
it.each([defaultProvide.starredExploreProjectsPath, defaultProvide.exploreRootPath])(
|
||||
'does not show sort dropdown',
|
||||
(pathname) => {
|
||||
it.each(defaultProvide.pathsToExcludeSortOn)('does not show sort dropdown', (pathname) => {
|
||||
createComponent({ pathname });
|
||||
|
||||
expect(findFilteredSearchAndSort().props('sortOptions')).toEqual([]);
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -42,11 +42,11 @@ RSpec.describe NamespacesHelper, feature_category: :groups_and_projects do
|
|||
user_group.add_owner(user)
|
||||
end
|
||||
|
||||
describe '#cascading_namespace_settings_popover_data' do
|
||||
describe '#cascading_namespace_settings_tooltip_data' do
|
||||
attribute = :math_rendering_limits_enabled
|
||||
|
||||
subject do
|
||||
helper.cascading_namespace_settings_popover_data(
|
||||
helper.cascading_namespace_settings_tooltip_data(
|
||||
attribute,
|
||||
subgroup1,
|
||||
->(locked_ancestor) { edit_group_path(locked_ancestor, anchor: 'js-permissions-settings') }
|
||||
|
|
@ -61,7 +61,7 @@ RSpec.describe NamespacesHelper, feature_category: :groups_and_projects do
|
|||
|
||||
it 'returns expected hash' do
|
||||
expect(subject).to match({
|
||||
popover_data: {
|
||||
tooltip_data: {
|
||||
locked_by_application_setting: true,
|
||||
locked_by_ancestor: false
|
||||
}.to_json,
|
||||
|
|
@ -79,7 +79,7 @@ RSpec.describe NamespacesHelper, feature_category: :groups_and_projects do
|
|||
|
||||
it 'returns expected hash' do
|
||||
expect(subject).to match({
|
||||
popover_data: {
|
||||
tooltip_data: {
|
||||
locked_by_application_setting: false,
|
||||
locked_by_ancestor: true,
|
||||
ancestor_namespace: {
|
||||
|
|
|
|||
|
|
@ -434,6 +434,10 @@ RSpec.describe ProjectsHelper, feature_category: :source_code_management do
|
|||
it 'returns false when there are no projects and there is no name' do
|
||||
expect(helper.show_projects?(Project.none, {})).to eq(false)
|
||||
end
|
||||
|
||||
it 'returns true when there are no projects but archived param is "only"' do
|
||||
expect(helper.show_projects?(Project.none, archived: 'only')).to eq(true)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#push_to_create_project_command' do
|
||||
|
|
@ -1893,14 +1897,13 @@ RSpec.describe ProjectsHelper, feature_category: :source_code_management do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#projects_explore_filtered_search_and_sort_app_data' do
|
||||
describe '#projects_filtered_search_and_sort_app_data' do
|
||||
it 'returns expected json' do
|
||||
expect(Gitlab::Json.parse(helper.projects_explore_filtered_search_and_sort_app_data)).to eq(
|
||||
expect(Gitlab::Json.parse(helper.projects_filtered_search_and_sort_app_data)).to eq(
|
||||
{
|
||||
'initial_sort' => 'created_desc',
|
||||
'programming_languages' => ProgrammingLanguage.most_popular,
|
||||
'starred_explore_projects_path' => starred_explore_projects_path,
|
||||
'explore_root_path' => explore_root_path
|
||||
'paths_to_exclude_sort_on' => [starred_explore_projects_path, explore_root_path]
|
||||
}
|
||||
)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -363,6 +363,32 @@ RSpec.describe Gitlab::Auth::RequestAuthenticator do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#find_user_from_job_token_basic_auth' do
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:job) { create(:ci_build, user: user, status: :running) }
|
||||
|
||||
before do
|
||||
allow(subject).to receive(:has_basic_credentials?).and_return(true)
|
||||
allow(subject).to receive(:user_name_and_password).and_return([::Gitlab::Auth::CI_JOB_USER, job.token])
|
||||
end
|
||||
|
||||
context 'when feature flag request_authenticator_exclude_job_token_basic_auth is enabled' do
|
||||
it 'does not find a user' do
|
||||
expect(subject.user([:api])).to eq nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'when feature flag request_authenticator_exclude_job_token_basic_auth is disabled' do
|
||||
before do
|
||||
stub_feature_flags(request_authenticator_exclude_job_token_basic_auth: false)
|
||||
end
|
||||
|
||||
it 'finds a job token user' do
|
||||
expect(subject.user([:api])).to eq user
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#find_user_from_job_token' do
|
||||
let_it_be(:user) { build(:user) }
|
||||
let_it_be(:job) { build(:ci_build, user: user, status: :running) }
|
||||
|
|
|
|||
|
|
@ -30,14 +30,14 @@ RSpec.shared_examples 'a cascading setting' do
|
|||
expect(page).not_to have_selector '[data-testid="enforce-for-all-subgroups-checkbox"]'
|
||||
end
|
||||
|
||||
it 'displays lock icon with popover', :js do
|
||||
it 'displays lock icon with tooltip', :js do
|
||||
visit subgroup_path
|
||||
|
||||
page.within form_group_selector do
|
||||
find('[data-testid="cascading-settings-lock-icon"]').click
|
||||
end
|
||||
|
||||
page.within '[data-testid="cascading-settings-lock-popover"]' do
|
||||
page.within '[data-testid="cascading-settings-lock-tooltip"]' do
|
||||
expect(page).to have_text 'This setting has been enforced by an owner of Foo bar.'
|
||||
expect(page).to have_link 'Foo bar', href: setting_path
|
||||
end
|
||||
|
|
|
|||
|
|
@ -443,4 +443,38 @@ RSpec.describe Tooling::Danger::AnalyticsInstrumentation, feature_category: :ser
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#warn_about_migrated_redis_keys_specs!' do
|
||||
let(:redis_hll_file) { 'lib/gitlab/usage_data_counters/hll_redis_key_overrides.yml' }
|
||||
let(:total_counter_file) { 'lib/gitlab/usage_data_counters/total_counter_redis_key_overrides.yml' }
|
||||
|
||||
subject(:check_redis_keys_files_overrides) { analytics_instrumentation.warn_about_migrated_redis_keys_specs! }
|
||||
|
||||
before do
|
||||
allow(fake_helper).to receive(:changed_lines).with(redis_hll_file).and_return([file_diff_hll])
|
||||
allow(fake_helper).to receive(:changed_lines).with(total_counter_file).and_return([file_diff_total])
|
||||
end
|
||||
|
||||
context 'when new keys added to overrides files' do
|
||||
let(:file_diff_hll) { "+user_viewed_cluster_configuration-user: user_viewed_cluster_configuration" }
|
||||
let(:file_diff_total) { "+user_viewed_cluster_configuration-user: USER_VIEWED_CLUSTER_CONFIGURATION" }
|
||||
|
||||
it 'adds suggestion to add specs' do
|
||||
expect(analytics_instrumentation).to receive(:warn)
|
||||
|
||||
check_redis_keys_files_overrides
|
||||
end
|
||||
end
|
||||
|
||||
context 'when no new keys added to overrides files' do
|
||||
let(:file_diff_hll) { "-user_viewed_cluster_configuration-user: user_viewed_cluster_configuration" }
|
||||
let(:file_diff_total) { "-user_viewed_cluster_configuration-user: USER_VIEWED_CLUSTER_CONFIGURATION" }
|
||||
|
||||
it 'adds suggestion to add specs' do
|
||||
expect(analytics_instrumentation).not_to receive(:warn)
|
||||
|
||||
check_redis_keys_files_overrides
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,19 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'dashboard/projects/_nav.html.haml' do
|
||||
it 'highlights All tab by default' do
|
||||
render
|
||||
|
||||
expect(rendered).to have_css('a.active', text: 'All')
|
||||
end
|
||||
|
||||
it 'highlights Personal tab personal param is present' do
|
||||
controller.params[:personal] = true
|
||||
|
||||
render
|
||||
|
||||
expect(rendered).to have_css('a.active', text: 'Personal')
|
||||
end
|
||||
end
|
||||
|
|
@ -97,12 +97,22 @@ module Tooling
|
|||
end
|
||||
end
|
||||
|
||||
def modified_config_files
|
||||
helper.modified_files.select { |f| f.include?('config/metrics') && f.end_with?('yml') }
|
||||
def warn_about_migrated_redis_keys_specs!
|
||||
override_files_changes = ["lib/gitlab/usage_data_counters/hll_redis_key_overrides.yml",
|
||||
"lib/gitlab/usage_data_counters/total_counter_redis_key_overrides.yml"].map do |filename|
|
||||
helper.changed_lines(filename).filter { |line| line.start_with?("+") }
|
||||
end
|
||||
return if override_files_changes.flatten.none?
|
||||
|
||||
warn "Redis keys overrides were added. Please consider cover keys merging with specs. See the [related issue](https://gitlab.com/gitlab-org/gitlab/-/issues/475191) for details"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def modified_config_files
|
||||
helper.modified_files.select { |f| f.include?('config/metrics') && f.end_with?('yml') }
|
||||
end
|
||||
|
||||
def comment_removed_metric(filename, has_removed_url, has_removed_milestone)
|
||||
mr_has_milestone = !helper.mr_milestone.nil?
|
||||
milestone = mr_has_milestone ? helper.mr_milestone['title'] : '[PLEASE SET MILESTONE]'
|
||||
|
|
|
|||
Loading…
Reference in New Issue