Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
2d277754eb
commit
f3b2c53677
|
|
@ -16,6 +16,7 @@ import SidebarSeverityWidget from '~/sidebar/components/severity/sidebar_severit
|
|||
import SidebarSubscriptionsWidget from '~/sidebar/components/subscriptions/sidebar_subscriptions_widget.vue';
|
||||
import SidebarTodoWidget from '~/sidebar/components/todo_toggle/sidebar_todo_widget.vue';
|
||||
import SidebarLabelsWidget from '~/sidebar/components/labels/labels_select_widget/labels_select_root.vue';
|
||||
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
import { setError } from '../graphql/cache_updates';
|
||||
|
||||
export default {
|
||||
|
|
@ -39,6 +40,7 @@ export default {
|
|||
SidebarWeightWidget: () =>
|
||||
import('ee_component/sidebar/components/weight/sidebar_weight_widget.vue'),
|
||||
},
|
||||
mixins: [glFeatureFlagMixin()],
|
||||
inject: {
|
||||
multipleAssigneesFeatureAvailable: {
|
||||
default: false,
|
||||
|
|
@ -143,6 +145,17 @@ export default {
|
|||
const { referencePath = '' } = this.activeBoardIssuable;
|
||||
return referencePath.slice(0, referencePath.indexOf('#'));
|
||||
},
|
||||
showWorkItemEpics() {
|
||||
return this.glFeatures.displayWorkItemEpicIssueSidebar;
|
||||
},
|
||||
showEpicSidebarDropdownWidget() {
|
||||
return this.epicFeatureAvailable && !this.isIncidentSidebar && this.activeBoardIssuable.id;
|
||||
},
|
||||
showIterationSidebarDropdownWidget() {
|
||||
return (
|
||||
this.iterationFeatureAvailable && !this.isIncidentSidebar && this.activeBoardIssuable.id
|
||||
);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
handleClose() {
|
||||
|
|
@ -189,29 +202,34 @@ export default {
|
|||
:editable="canUpdate"
|
||||
/>
|
||||
<sidebar-dropdown-widget
|
||||
v-if="epicFeatureAvailable && !isIncidentSidebar"
|
||||
v-if="showEpicSidebarDropdownWidget"
|
||||
:key="`epic-${activeBoardIssuable.iid}`"
|
||||
:iid="activeBoardIssuable.iid"
|
||||
issuable-attribute="epic"
|
||||
:workspace-path="projectPathForActiveIssue"
|
||||
:attr-workspace-path="groupPathForActiveIssue"
|
||||
:issuable-type="issuableType"
|
||||
:issue-id="activeBoardIssuable.id"
|
||||
:show-work-item-epics="showWorkItemEpics"
|
||||
data-testid="sidebar-epic"
|
||||
/>
|
||||
<div>
|
||||
<sidebar-dropdown-widget
|
||||
v-if="activeBoardIssuable.id"
|
||||
:key="`milestone-${activeBoardIssuable.iid}`"
|
||||
:iid="activeBoardIssuable.iid"
|
||||
issuable-attribute="milestone"
|
||||
:workspace-path="projectPathForActiveIssue"
|
||||
:attr-workspace-path="projectPathForActiveIssue"
|
||||
:issuable-type="issuableType"
|
||||
:issue-id="activeBoardIssuable.id"
|
||||
data-testid="sidebar-milestones"
|
||||
/>
|
||||
<sidebar-iteration-widget
|
||||
v-if="iterationFeatureAvailable && !isIncidentSidebar"
|
||||
v-if="showIterationSidebarDropdownWidget"
|
||||
:key="`iteration-${activeBoardIssuable.iid}`"
|
||||
:iid="activeBoardIssuable.iid"
|
||||
:issue-id="activeBoardIssuable.id"
|
||||
:workspace-path="projectPathForActiveIssue"
|
||||
:attr-workspace-path="groupPathForActiveIssue"
|
||||
:issuable-type="issuableType"
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
import { GlSprintf, GlButton, GlButtonGroup, GlLoadingIcon } from '@gitlab/ui';
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { mapGetters, mapState, mapActions } from 'vuex';
|
||||
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
|
||||
import { __ } from '~/locale';
|
||||
import FileIcon from '~/vue_shared/components/file_icon.vue';
|
||||
import DiffFileEditor from './components/diff_file_editor.vue';
|
||||
|
|
@ -23,6 +24,7 @@ export default {
|
|||
components: {
|
||||
GlButton,
|
||||
GlButtonGroup,
|
||||
ClipboardButton,
|
||||
GlSprintf,
|
||||
GlLoadingIcon,
|
||||
FileIcon,
|
||||
|
|
@ -122,6 +124,12 @@ export default {
|
|||
<div class="file-header-content" data-testid="file-name">
|
||||
<file-icon :file-name="file.filePath" :size="16" css-classes="gl-mr-2" />
|
||||
<strong class="file-title-name">{{ file.filePath }}</strong>
|
||||
<clipboard-button
|
||||
:title="__('Copy file path')"
|
||||
:text="file.filePath"
|
||||
size="small"
|
||||
category="tertiary"
|
||||
/>
|
||||
</div>
|
||||
<div class="file-actions d-flex align-items-center gl-ml-auto gl-align-self-start">
|
||||
<gl-button-group v-if="file.type === 'text'" class="gl-mr-3">
|
||||
|
|
|
|||
|
|
@ -1,10 +1,13 @@
|
|||
<script>
|
||||
import { GlFilteredSearchToken } from '@gitlab/ui';
|
||||
import { sortableFields } from '~/packages_and_registries/package_registry/utils';
|
||||
import {
|
||||
FILTERED_SEARCH_TERM,
|
||||
OPERATORS_IS,
|
||||
TOKEN_TITLE_TYPE,
|
||||
TOKEN_TYPE_TYPE,
|
||||
TOKEN_TITLE_VERSION,
|
||||
TOKEN_TYPE_VERSION,
|
||||
} from '~/vue_shared/components/filtered_search_bar/constants';
|
||||
import PersistedSearch from '~/packages_and_registries/shared/components/persisted_search.vue';
|
||||
import { LIST_KEY_CREATED_AT } from '~/packages_and_registries/package_registry/constants';
|
||||
|
|
@ -21,6 +24,14 @@ export default {
|
|||
token: PackageTypeToken,
|
||||
operators: OPERATORS_IS,
|
||||
},
|
||||
{
|
||||
type: TOKEN_TYPE_VERSION,
|
||||
icon: 'doc-versions',
|
||||
title: TOKEN_TITLE_VERSION,
|
||||
unique: true,
|
||||
token: GlFilteredSearchToken,
|
||||
operators: OPERATORS_IS,
|
||||
},
|
||||
],
|
||||
components: {
|
||||
LocalStorageSync,
|
||||
|
|
@ -57,6 +68,7 @@ export default {
|
|||
const parsed = {
|
||||
packageName: '',
|
||||
packageType: undefined,
|
||||
packageVersion: '',
|
||||
};
|
||||
|
||||
return filters.reduce((acc, filter) => {
|
||||
|
|
@ -67,6 +79,13 @@ export default {
|
|||
};
|
||||
}
|
||||
|
||||
if (filter.type === TOKEN_TYPE_VERSION && filter.value?.data) {
|
||||
return {
|
||||
...acc,
|
||||
packageVersion: filter.value.data.trim(),
|
||||
};
|
||||
}
|
||||
|
||||
if (filter.type === FILTERED_SEARCH_TERM) {
|
||||
return {
|
||||
...acc,
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ query getPackages(
|
|||
$groupSort: PackageGroupSort
|
||||
$packageName: String
|
||||
$packageType: PackageTypeEnum
|
||||
$packageVersion: String
|
||||
$first: Int
|
||||
$last: Int
|
||||
$after: String
|
||||
|
|
@ -20,6 +21,7 @@ query getPackages(
|
|||
sort: $sort
|
||||
packageName: $packageName
|
||||
packageType: $packageType
|
||||
packageVersion: $packageVersion
|
||||
after: $after
|
||||
before: $before
|
||||
first: $first
|
||||
|
|
@ -43,6 +45,7 @@ query getPackages(
|
|||
sort: $groupSort
|
||||
packageName: $packageName
|
||||
packageType: $packageType
|
||||
packageVersion: $packageVersion
|
||||
after: $after
|
||||
before: $before
|
||||
first: $first
|
||||
|
|
|
|||
|
|
@ -82,6 +82,7 @@ export default {
|
|||
groupSort: this.isGroupPage ? this.sort : undefined,
|
||||
packageName: this.filters?.packageName,
|
||||
packageType: this.filters?.packageType,
|
||||
packageVersion: this.filters?.packageVersion,
|
||||
first: GRAPHQL_PAGE_SIZE,
|
||||
...this.pageParams,
|
||||
};
|
||||
|
|
@ -96,10 +97,10 @@ export default {
|
|||
return this.packages?.count;
|
||||
},
|
||||
hasFilters() {
|
||||
return this.filters.packageName && this.filters.packageType;
|
||||
return this.filters.packageName || this.filters.packageType || this.filters.packageVersion;
|
||||
},
|
||||
emptySearch() {
|
||||
return !this.filters.packageName && !this.filters.packageType;
|
||||
return !this.filters.packageName && !this.filters.packageType && !this.filters.packageVersion;
|
||||
},
|
||||
emptyStateTitle() {
|
||||
return this.emptySearch
|
||||
|
|
|
|||
|
|
@ -10,13 +10,16 @@ export const searchArrayToFilterTokens = (search) =>
|
|||
search.map((s) => keyValueToFilterToken(FILTERED_SEARCH_TERM, s));
|
||||
|
||||
export const extractFilterAndSorting = (queryObject) => {
|
||||
const { type, search, sort, orderBy } = queryObject;
|
||||
const { type, search, version, sort, orderBy } = queryObject;
|
||||
const filters = [];
|
||||
const sorting = {};
|
||||
|
||||
if (type) {
|
||||
filters.push(keyValueToFilterToken('type', type));
|
||||
}
|
||||
if (version) {
|
||||
filters.push(keyValueToFilterToken('version', version));
|
||||
}
|
||||
if (search) {
|
||||
filters.push(...searchArrayToFilterTokens(search));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,6 +87,11 @@ export default {
|
|||
return [WORKSPACE_GROUP, WORKSPACE_PROJECT].includes(value);
|
||||
},
|
||||
},
|
||||
showWorkItemEpics: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
|
@ -115,6 +120,7 @@ export default {
|
|||
fullPath: this.attrWorkspacePath,
|
||||
state: this.issuableAttributesState[this.issuableAttribute],
|
||||
sort: defaultEpicSort,
|
||||
includeWorkItems: this.showWorkItemEpics,
|
||||
};
|
||||
|
||||
if (epicIidPattern.test(this.searchTerm)) {
|
||||
|
|
@ -127,7 +133,12 @@ export default {
|
|||
|
||||
return variables;
|
||||
},
|
||||
update: (data) => data?.workspace?.attributes?.nodes ?? [],
|
||||
update(data) {
|
||||
return [
|
||||
...(data?.workspace?.attributes?.nodes ?? []),
|
||||
...(data?.workspace?.workItems?.nodes ?? []),
|
||||
];
|
||||
},
|
||||
error(error) {
|
||||
createAlert({ message: this.i18n.listFetchError, captureError: true, error });
|
||||
},
|
||||
|
|
@ -188,7 +199,7 @@ export default {
|
|||
this.skipQuery = false;
|
||||
},
|
||||
setFocus() {
|
||||
this.$refs.search.focusInput();
|
||||
this.$refs?.search?.focusInput();
|
||||
},
|
||||
show() {
|
||||
this.$refs.dropdown.show();
|
||||
|
|
@ -211,7 +222,12 @@ export default {
|
|||
@show="handleShow"
|
||||
@shown="setFocus"
|
||||
>
|
||||
<gl-search-box-by-type ref="search" v-model="searchTerm" :placeholder="__('Search')" />
|
||||
<gl-search-box-by-type
|
||||
v-if="!showWorkItemEpics"
|
||||
ref="search"
|
||||
v-model="searchTerm"
|
||||
:placeholder="__('Search')"
|
||||
/>
|
||||
<gl-dropdown-item
|
||||
:data-testid="`no-${formatIssuableAttribute.kebab}-item`"
|
||||
is-check-item
|
||||
|
|
|
|||
|
|
@ -3,10 +3,11 @@ import { GlButton, GlIcon, GlLink, GlPopover, GlTooltipDirective } from '@gitlab
|
|||
import { kebabCase, snakeCase } from 'lodash';
|
||||
import { createAlert } from '~/alert';
|
||||
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
|
||||
import { TYPE_EPIC, TYPE_ISSUE, TYPE_MERGE_REQUEST } from '~/issues/constants';
|
||||
import { TYPE_ISSUE, TYPE_MERGE_REQUEST } from '~/issues/constants';
|
||||
import { timeFor } from '~/lib/utils/datetime_utility';
|
||||
import { __ } from '~/locale';
|
||||
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
|
||||
import {
|
||||
dropdowni18nText,
|
||||
LocalizedIssuableAttributeType,
|
||||
|
|
@ -79,6 +80,21 @@ export default {
|
|||
required: false,
|
||||
default: undefined,
|
||||
},
|
||||
showWorkItemEpics: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
isEpicAttribute: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
issuableParent: {
|
||||
type: Object,
|
||||
required: false,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
apollo: {
|
||||
issuable: {
|
||||
|
|
@ -98,7 +114,7 @@ export default {
|
|||
return data.workspace?.issuable || {};
|
||||
},
|
||||
result({ data }) {
|
||||
if (this.glFeatures?.epicWidgetEditConfirmation && this.isEpic) {
|
||||
if (this.glFeatures?.epicWidgetEditConfirmation && this.isEpicAttribute) {
|
||||
this.hasCurrentAttribute = data?.workspace?.issuable.hasEpic;
|
||||
}
|
||||
},
|
||||
|
|
@ -140,6 +156,9 @@ export default {
|
|||
},
|
||||
computed: {
|
||||
currentAttribute() {
|
||||
if (this.isEpicAttribute && this.issuableParent?.attribute) {
|
||||
return this.issuableParent.attribute;
|
||||
}
|
||||
return this.issuable.attribute;
|
||||
},
|
||||
issuableId() {
|
||||
|
|
@ -171,10 +190,6 @@ export default {
|
|||
LocalizedIssuableAttributeType[IssuableAttributeTypeKeyMap[this.issuableAttribute]];
|
||||
return dropdowni18nText(localizedAttribute, this.issuableType);
|
||||
},
|
||||
isEpic() {
|
||||
// MV to EE https://gitlab.com/gitlab-org/gitlab/-/issues/345311
|
||||
return this.issuableAttribute === TYPE_EPIC;
|
||||
},
|
||||
formatIssuableAttribute() {
|
||||
return {
|
||||
kebab: kebabCase(this.issuableAttribute),
|
||||
|
|
@ -186,7 +201,7 @@ export default {
|
|||
return false;
|
||||
}
|
||||
|
||||
return this.isEpic && this.currentAttribute === null && this.hasCurrentAttribute
|
||||
return this.isEpicAttribute && this.currentAttribute === null && this.hasCurrentAttribute
|
||||
? !this.editConfirmation
|
||||
: false;
|
||||
},
|
||||
|
|
@ -195,46 +210,50 @@ export default {
|
|||
},
|
||||
},
|
||||
methods: {
|
||||
updateAttribute({ id }) {
|
||||
updateAttribute({ id, workItemType }) {
|
||||
if (this.currentAttribute === null && id === null) return;
|
||||
if (id === this.currentAttribute?.id) return;
|
||||
|
||||
this.updating = true;
|
||||
if (this.showWorkItemEpics && this.isEpicAttribute) {
|
||||
this.$emit('updateAttribute', { id, workItemType });
|
||||
} else {
|
||||
this.updating = true;
|
||||
|
||||
const { current } = this.issuableAttributeQuery;
|
||||
const { mutation } = current[this.issuableType];
|
||||
const { current } = this.issuableAttributeQuery;
|
||||
const { mutation } = current[this.issuableType];
|
||||
|
||||
this.$apollo
|
||||
.mutate({
|
||||
mutation,
|
||||
variables: {
|
||||
fullPath: this.workspacePath,
|
||||
attributeId:
|
||||
this.issuableAttribute === IssuableAttributeType.Milestone &&
|
||||
this.issuableType === TYPE_ISSUE
|
||||
? getIdFromGraphQLId(id)
|
||||
: id,
|
||||
iid: this.iid,
|
||||
},
|
||||
})
|
||||
.then(({ data }) => {
|
||||
if (data.issuableSetAttribute?.errors?.length) {
|
||||
createAlert({
|
||||
message: data.issuableSetAttribute.errors[0],
|
||||
captureError: true,
|
||||
error: data.issuableSetAttribute.errors[0],
|
||||
});
|
||||
} else {
|
||||
this.$emit('attribute-updated', data);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
createAlert({ message: this.i18n.updateError, captureError: true, error });
|
||||
})
|
||||
.finally(() => {
|
||||
this.updating = false;
|
||||
this.selectedTitle = null;
|
||||
});
|
||||
this.$apollo
|
||||
.mutate({
|
||||
mutation,
|
||||
variables: {
|
||||
fullPath: this.workspacePath,
|
||||
attributeId:
|
||||
this.issuableAttribute === IssuableAttributeType.Milestone &&
|
||||
this.issuableType === TYPE_ISSUE
|
||||
? getIdFromGraphQLId(id)
|
||||
: id,
|
||||
iid: this.iid,
|
||||
},
|
||||
})
|
||||
.then(({ data }) => {
|
||||
if (data.issuableSetAttribute?.errors?.length) {
|
||||
createAlert({
|
||||
message: data.issuableSetAttribute.errors[0],
|
||||
captureError: true,
|
||||
error: data.issuableSetAttribute.errors[0],
|
||||
});
|
||||
} else {
|
||||
this.$emit('attribute-updated', data);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
createAlert({ message: this.i18n.updateError, captureError: true, error });
|
||||
})
|
||||
.finally(() => {
|
||||
this.updating = false;
|
||||
this.selectedTitle = null;
|
||||
});
|
||||
}
|
||||
},
|
||||
isAttributeOverdue(attribute) {
|
||||
return this.issuableAttribute === IssuableAttributeType.Milestone
|
||||
|
|
@ -356,6 +375,7 @@ export default {
|
|||
:current-attribute="currentAttribute"
|
||||
:issuable-attribute="issuableAttribute"
|
||||
:issuable-type="issuableType"
|
||||
:show-work-item-epics="showWorkItemEpics"
|
||||
@change="updateAttribute"
|
||||
>
|
||||
<template #list="{ attributesList, isAttributeChecked, updateAttribute: update }">
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@ export const TOKEN_TITLE_STATUS = __('Status');
|
|||
export const TOKEN_TITLE_JOBS_RUNNER_TYPE = s__('Job|Runner type');
|
||||
export const TOKEN_TITLE_TARGET_BRANCH = __('Target Branch');
|
||||
export const TOKEN_TITLE_TYPE = __('Type');
|
||||
export const TOKEN_TITLE_VERSION = __('Version');
|
||||
export const TOKEN_TITLE_SEARCH_WITHIN = __('Search Within');
|
||||
export const TOKEN_TITLE_CREATED = __('Created date');
|
||||
export const TOKEN_TITLE_CLOSED = __('Closed date');
|
||||
|
|
@ -108,6 +109,7 @@ export const TOKEN_TYPE_STATUS = 'status';
|
|||
export const TOKEN_TYPE_JOBS_RUNNER_TYPE = 'jobs-runner-type';
|
||||
export const TOKEN_TYPE_TARGET_BRANCH = 'target-branch';
|
||||
export const TOKEN_TYPE_TYPE = 'type';
|
||||
export const TOKEN_TYPE_VERSION = 'version';
|
||||
export const TOKEN_TYPE_WEIGHT = 'weight';
|
||||
export const TOKEN_TYPE_SEARCH_WITHIN = 'in';
|
||||
export const TOKEN_TYPE_CREATED = 'created';
|
||||
|
|
|
|||
|
|
@ -20,7 +20,8 @@ module Projects
|
|||
path: model.path,
|
||||
description: model.description,
|
||||
latest_version: latest_version_view_model,
|
||||
version_count: model.version_count
|
||||
version_count: model.version_count,
|
||||
candidate_count: model.candidate_count
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ class Groups::BoardsController < Groups::ApplicationController
|
|||
before_action do
|
||||
push_frontend_feature_flag(:board_multi_select, group)
|
||||
push_frontend_feature_flag(:apollo_boards, group)
|
||||
push_frontend_feature_flag(:display_work_item_epic_issue_sidebar, group)
|
||||
experiment(:prominent_create_board_btn, subject: current_user) do |e|
|
||||
e.control {}
|
||||
e.candidate {}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ class Projects::BoardsController < Projects::ApplicationController
|
|||
before_action do
|
||||
push_frontend_feature_flag(:board_multi_select, project)
|
||||
push_frontend_feature_flag(:apollo_boards, project)
|
||||
push_frontend_feature_flag(:display_work_item_epic_issue_sidebar, project)
|
||||
experiment(:prominent_create_board_btn, subject: current_user) do |e|
|
||||
e.control {}
|
||||
e.candidate {}
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ class Projects::IssuesController < Projects::ApplicationController
|
|||
push_frontend_feature_flag(:service_desk_ticket)
|
||||
push_frontend_feature_flag(:issues_list_drawer, project)
|
||||
push_frontend_feature_flag(:linked_work_items, project)
|
||||
push_frontend_feature_flag(:display_work_item_epic_issue_sidebar, project)
|
||||
end
|
||||
|
||||
before_action only: [:index, :show] do
|
||||
|
|
@ -67,6 +68,7 @@ class Projects::IssuesController < Projects::ApplicationController
|
|||
push_force_frontend_feature_flag(:work_items_mvc_2, project&.work_items_mvc_2_feature_flag_enabled?)
|
||||
push_frontend_feature_flag(:epic_widget_edit_confirmation, project)
|
||||
push_frontend_feature_flag(:moved_mr_sidebar, project)
|
||||
push_frontend_feature_flag(:display_work_item_epic_issue_sidebar, project)
|
||||
push_force_frontend_feature_flag(:linked_work_items, project.linked_work_items_feature_flag_enabled?)
|
||||
push_frontend_feature_flag(:notifications_todos_buttons, current_user)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ module DropdownsHelper
|
|||
end
|
||||
|
||||
content_tag_options = { class: "dropdown-menu dropdown-select #{options[:dropdown_class] if options.key?(:dropdown_class)}" }
|
||||
content_tag_options[:data] = options[:dropdown_qa_selector] ? { qa_selector: (options[:dropdown_qa_selector]).to_s } : {}
|
||||
content_tag_options[:data] ||= {}
|
||||
content_tag_options[:data][:testid] = (options[:dropdown_testid]).to_s if options[:dropdown_testid]
|
||||
|
||||
dropdown_output << content_tag(:div, content_tag_options) do
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ module ProjectsHelper
|
|||
link_to(author_html, user_path(author), class: inject_classes, data: data_attrs).html_safe
|
||||
else
|
||||
title = opts[:title].sub(":name", sanitize(author.name))
|
||||
link_to(author_html, user_path(author), class: inject_classes, title: title, data: { container: 'body', qa_selector: 'assignee_link' }).html_safe
|
||||
link_to(author_html, user_path(author), class: inject_classes, title: title, data: { container: 'body' }).html_safe
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -8,14 +8,6 @@ module SidebarsHelper
|
|||
sidebar_attributes_for_object(object).fetch(:tracking_attrs, {})
|
||||
end
|
||||
|
||||
def sidebar_qa_selector(object)
|
||||
sidebar_attributes_for_object(object).fetch(:sidebar_qa_selector, nil)
|
||||
end
|
||||
|
||||
def scope_qa_menu_item(object)
|
||||
sidebar_attributes_for_object(object).fetch(:scope_qa_menu_item, nil)
|
||||
end
|
||||
|
||||
def scope_avatar_classes(object)
|
||||
%w[avatar-container rect-avatar s32].tap do |klasses|
|
||||
klass = sidebar_attributes_for_object(object).fetch(:scope_avatar_class, nil)
|
||||
|
|
@ -267,8 +259,6 @@ module SidebarsHelper
|
|||
def sidebar_project_attributes
|
||||
{
|
||||
tracking_attrs: sidebar_project_tracking_attrs,
|
||||
sidebar_qa_selector: 'project_sidebar',
|
||||
scope_qa_menu_item: 'Project scope',
|
||||
scope_avatar_class: 'project_avatar'
|
||||
}
|
||||
end
|
||||
|
|
@ -276,8 +266,6 @@ module SidebarsHelper
|
|||
def sidebar_group_attributes
|
||||
{
|
||||
tracking_attrs: sidebar_group_tracking_attrs,
|
||||
sidebar_qa_selector: 'group_sidebar',
|
||||
scope_qa_menu_item: 'Group scope',
|
||||
scope_avatar_class: 'group_avatar'
|
||||
}
|
||||
end
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ module SshKeysHelper
|
|||
{
|
||||
path: path,
|
||||
method: 'delete',
|
||||
qa_selector: 'revoke_ssh_key_button',
|
||||
title: title,
|
||||
aria_label: title,
|
||||
modal_attributes: {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ class NamespaceSetting < ApplicationRecord
|
|||
include ChronicDurationAttribute
|
||||
|
||||
cascading_attr :delayed_project_removal
|
||||
cascading_attr :toggle_security_policy_custom_ci
|
||||
|
||||
belongs_to :namespace, inverse_of: :namespace_settings
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,10 @@ module Ml
|
|||
model.versions.size
|
||||
end
|
||||
|
||||
def candidate_count
|
||||
model.candidates.size
|
||||
end
|
||||
|
||||
def latest_package_path
|
||||
latest_version&.package_path
|
||||
end
|
||||
|
|
|
|||
|
|
@ -22,6 +22,12 @@ module Ml
|
|||
|
||||
add_metadata(model, @metadata)
|
||||
|
||||
Gitlab::InternalEvents.track_event(
|
||||
'model_registry_ml_model_created',
|
||||
project: @project,
|
||||
user: @user
|
||||
)
|
||||
|
||||
model
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -24,6 +24,12 @@ module Ml
|
|||
{ model_version: model_version }
|
||||
).execute
|
||||
|
||||
Gitlab::InternalEvents.track_event(
|
||||
'model_registry_ml_model_version_created',
|
||||
project: @model.project,
|
||||
user: @user
|
||||
)
|
||||
|
||||
model_version
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,77 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# KubernetesPodContainerResourcesValidator
|
||||
#
|
||||
# Validates that value is a Kubernetes resource specifying cpu and memory.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# class Group < ActiveRecord::Base
|
||||
# validates :resource, presence: true, kubernetes_pod_container_resources: true
|
||||
# end
|
||||
|
||||
class KubernetesContainerResourcesValidator < ActiveModel::EachValidator # rubocop:disable Gitlab/NamespacedClass -- This is a globally shareable validator, but it's unclear what namespace it should belong in
|
||||
# https://kubernetes.io/docs/tasks/configure-pod-container/assign-cpu-resource/#cpu-units
|
||||
# The CPU resource is measured in CPU units. Fractional values are allowed. You can use the suffix m to mean milli.
|
||||
# (\d+m|\d+(\.\d*)?): Two alternatives separated by |:
|
||||
# \d+m: Matches positive whole numbers followed by "m".
|
||||
# \d+(\.\d*)?: Matches positive decimal numbers.
|
||||
CPU_UNITS = /^(\d+m|\d+(\.\d*)?)$/
|
||||
|
||||
# https://kubernetes.io/docs/tasks/configure-pod-container/assign-memory-resource/#memory-units
|
||||
# The memory resource is measured in bytes. You can express memory as a plain integer or a fixed-point integer
|
||||
# with one of these suffixes: E, P, T, G, M, K, Ei, Pi, Ti, Gi, Mi, Ki.
|
||||
# \d+(\.\d*)?: Matches positive decimal numbers.
|
||||
# ([EPTGMK]|[EPTGMK][i])?: Optional suffix part, where:
|
||||
# [EPTGMK]: Matches a single character from the set E, P, T, G, M, K.
|
||||
# [EPTGMK]i: Matches characters from the set followed by an "i".
|
||||
MEMORY_UNITS = /^\d+(\.\d*)?([EPTGMK]|[EPTGMK]i)?$/
|
||||
|
||||
def validate_each(record, attribute, value)
|
||||
unless value.is_a?(Hash)
|
||||
record.errors.add(attribute, _("must be a hash"))
|
||||
return
|
||||
end
|
||||
|
||||
if value == {}
|
||||
record.errors.add(
|
||||
attribute,
|
||||
_("must be a hash containing 'cpu' and 'memory' attribute of type string")
|
||||
)
|
||||
return
|
||||
end
|
||||
|
||||
cpu = value.deep_symbolize_keys.fetch(:cpu, nil)
|
||||
unless cpu.is_a?(String)
|
||||
record.errors.add(
|
||||
attribute,
|
||||
format(_("'cpu: %{cpu}' must be a string"), cpu: cpu)
|
||||
)
|
||||
end
|
||||
|
||||
if cpu.is_a?(String) && !CPU_UNITS.match?(cpu)
|
||||
record.errors.add(
|
||||
attribute,
|
||||
format(_("'cpu: %{cpu}' must match the regex '%{cpu_regex}'"), cpu: cpu, cpu_regex: CPU_UNITS.source)
|
||||
)
|
||||
end
|
||||
|
||||
memory = value.deep_symbolize_keys.fetch(:memory, nil)
|
||||
unless memory.is_a?(String)
|
||||
record.errors.add(
|
||||
attribute,
|
||||
format(_("'memory: %{memory}' must be a string"), memory: memory)
|
||||
)
|
||||
end
|
||||
|
||||
if memory.is_a?(String) && !MEMORY_UNITS.match?(memory) # rubocop:disable Style/GuardClause -- Easier to read this way
|
||||
record.errors.add(
|
||||
attribute,
|
||||
format(_("'memory: %{memory}' must match the regex '%{memory_regex}'"),
|
||||
memory: memory,
|
||||
memory_regex: MEMORY_UNITS.source
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -20,7 +20,7 @@
|
|||
.js-vue-notification-dropdown{ data: { disabled: emails_disabled.to_s, dropdown_items: notification_dropdown_items(@notification_setting).to_json, notification_level: @notification_setting.level, help_page_path: help_page_path('user/profile/notifications'), group_id: @group.id, container_class: 'gl-vertical-align-top', no_flip: 'true' } }
|
||||
- if can_create_subgroups
|
||||
.gl-sm-w-auto.gl-w-full
|
||||
= render Pajamas::ButtonComponent.new(href: new_group_path(parent_id: @group.id, anchor: 'create-group-pane'), button_options: { data: { qa_selector: 'new_subgroup_button' }, class: 'gl-sm-w-auto gl-w-full'}) do
|
||||
= render Pajamas::ButtonComponent.new(href: new_group_path(parent_id: @group.id, anchor: 'create-group-pane'), button_options: { data: { testid: 'new-subgroup-button' }, class: 'gl-sm-w-auto gl-w-full'}) do
|
||||
= _("New subgroup")
|
||||
|
||||
- if can_create_projects
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
.settings-content
|
||||
= render 'groups/settings/general'
|
||||
|
||||
%section.settings.gs-permissions.no-animate#js-permissions-settings{ class: ('expanded' if expanded), data: { qa_selector: 'permission_lfs_2fa_content', testid: 'permissions-settings' } }
|
||||
%section.settings.gs-permissions.no-animate#js-permissions-settings{ class: ('expanded' if expanded), data: { testid: 'permissions-settings' } }
|
||||
.settings-header
|
||||
%h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only{ role: 'button' }
|
||||
= _('Permissions and group features')
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@
|
|||
- if project.namespace
|
||||
= project.namespace.human_name
|
||||
\/
|
||||
%span.project-name{ data: { qa_selector: 'project_name_content', qa_project_name: project.name } }
|
||||
%span.project-name
|
||||
= project.name
|
||||
= visibility_level_content(project, css_class: 'visibility-icon gl-text-secondary gl-ml-2', icon_css_class: 'icon')
|
||||
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
%li= _('Runner tokens')
|
||||
%li= _('SAML discovery tokens')
|
||||
- if group.export_file_exists?
|
||||
= render Pajamas::ButtonComponent.new(href: download_export_group_path(group), button_options: { rel: 'nofollow', data: { method: :get, qa_selector: 'download_export_link' } }) do
|
||||
= render Pajamas::ButtonComponent.new(href: download_export_group_path(group), button_options: { rel: 'nofollow', data: { method: :get } }) do
|
||||
= _('Download export')
|
||||
= render Pajamas::ButtonComponent.new(href: export_group_path(group), button_options: { data: { method: :post } }) do
|
||||
= _('Regenerate export')
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
.row
|
||||
.form-group.col-md-5
|
||||
= f.label :name, s_('Groups|Group name'), class: 'label-bold'
|
||||
= f.text_field :name, class: 'form-control', data: { qa_selector: 'group_name_field' }
|
||||
= f.text_field :name, class: 'form-control', data: { testid: 'group-name-field' }
|
||||
.text-muted
|
||||
= s_('Groups|Must start with letter, digit, emoji, or underscore. Can also contain periods, dashes, spaces, and parentheses.')
|
||||
|
||||
|
|
@ -36,4 +36,4 @@
|
|||
= link_button_to s_('Groups|Remove avatar'), group_avatar_path(@group.to_param), aria: { label: s_('Groups|Remove avatar') }, data: { confirm: s_('Groups|Avatar will be removed. Are you sure?'), 'confirm-btn-variant': 'danger' }, method: :delete, variant: :danger, category: :secondary
|
||||
.form-group.gl-form-group
|
||||
= render 'shared/visibility_level', f: f, visibility_level: @group.visibility_level, can_change_visibility_level: can_change_group_visibility_level?(@group), form_model: @group
|
||||
= f.submit s_('Groups|Save changes'), pajamas_button: true, class: 'js-dirty-submit', data: { qa_selector: 'save_name_visibility_settings_button' }
|
||||
= f.submit s_('Groups|Save changes'), pajamas_button: true, class: 'js-dirty-submit', data: { testid: 'save-name-visibility-settings-button' }
|
||||
|
|
|
|||
|
|
@ -9,4 +9,4 @@
|
|||
= f.gitlab_ui_checkbox_component :lfs_enabled,
|
||||
_('Projects in this group can use Git LFS'),
|
||||
help_text: _('Possible to override in each project.'),
|
||||
checkbox_options: { checked: @group.lfs_enabled?, data: { qa_selector: 'lfs_checkbox' } }
|
||||
checkbox_options: { checked: @group.lfs_enabled?, data: { testid: 'lfs-checkbox' } }
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@
|
|||
= render 'groups/settings/two_factor_auth', f: f, group: @group
|
||||
= render_if_exists 'groups/personal_access_token_expiration_policy', f: f, group: @group
|
||||
= render 'groups/settings/membership', f: f, group: @group
|
||||
= render_if_exists 'groups/settings/security_policies_custom_ci', f: f, group: @group
|
||||
|
||||
%h5= _('Customer relations')
|
||||
.form-group.gl-mb-3
|
||||
|
|
@ -56,4 +57,4 @@
|
|||
checkbox_options: { checked: @group.crm_enabled? },
|
||||
help_text: s_('GroupSettings|Organizations and contacts can be created and associated with issues.')
|
||||
|
||||
= f.submit _('Save changes'), pajamas_button: true, class: 'gl-mt-3 js-dirty-submit', data: { qa_selector: 'save_permissions_changes_button' }
|
||||
= f.submit _('Save changes'), pajamas_button: true, class: 'gl-mt-3 js-dirty-submit', data: { testid: 'save-permissions-changes-button' }
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
.form-group
|
||||
= f.label s_('ProjectCreationLevel|Roles allowed to create projects'), class: 'label-bold'
|
||||
= f.select :project_creation_level, options_for_select(::Gitlab::Access.project_creation_options, group.project_creation_level), {}, class: 'form-control', data: { qa_selector: 'project_creation_level_dropdown' }
|
||||
= f.select :project_creation_level, options_for_select(::Gitlab::Access.project_creation_options, group.project_creation_level), {}, class: 'form-control', data: { testid: 'project-creation-level-dropdown' }
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
.form-group
|
||||
= f.gitlab_ui_checkbox_component :require_two_factor_authentication,
|
||||
_('All users in this group must set up two-factor authentication'),
|
||||
checkbox_options: { data: { qa_selector: 'require_2fa_checkbox' } }
|
||||
checkbox_options: { data: { testid: 'require-2fa-checkbox' } }
|
||||
.form-group
|
||||
= f.label :two_factor_grace_period, _('Delay 2FA enforcement (hours)')
|
||||
= f.text_field :two_factor_grace_period, class: 'form-control form-control-sm w-auto gl-form-input gl-mb-3'
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
= form.gitlab_ui_checkbox_component :request_access_enabled,
|
||||
_('Users can request access (if visibility is public or internal)'),
|
||||
checkbox_options: { data: { qa_selector: 'request_access_checkbox' } }
|
||||
checkbox_options: { data: { testid: 'request-access-checkbox' } }
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@
|
|||
|
||||
- if in_group_context_with_iterations
|
||||
.block.gl-collapse-empty{ data: { testid: 'iteration-container' } }<
|
||||
= render_if_exists 'shared/issuable/iteration_select', can_edit: can_edit_issuable.to_s, group_path: @project.group.full_path, project_path: issuable_sidebar[:project_full_path], issue_iid: issuable_sidebar[:iid], issuable_type: issuable_type
|
||||
= render_if_exists 'shared/issuable/iteration_select', can_edit: can_edit_issuable.to_s, group_path: @project.group.full_path, project_path: issuable_sidebar[:project_full_path], issue_iid: issuable_sidebar[:iid], issuable_type: issuable_type, issue_id: issuable_sidebar[:id]
|
||||
|
||||
- if issuable_sidebar[:show_crm_contacts]
|
||||
.block.contact
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Abuse
|
||||
class TrustScoreWorker
|
||||
include ApplicationWorker
|
||||
|
||||
data_consistency :delayed
|
||||
|
||||
idempotent!
|
||||
feature_category :instance_resiliency
|
||||
urgency :low
|
||||
|
||||
def perform(user_id, source, score, correlation_id = '')
|
||||
user = User.find_by_id(user_id)
|
||||
unless user
|
||||
logger.info(structured_payload(message: "User not found.", user_id: user_id))
|
||||
return
|
||||
end
|
||||
|
||||
Abuse::TrustScore.create!(user: user, source: source, score: score.to_f, correlation_id_value: correlation_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -2316,6 +2316,15 @@
|
|||
:weight: 1
|
||||
:idempotent: true
|
||||
:tags: []
|
||||
- :name: abuse_trust_score
|
||||
:worker_name: Abuse::TrustScoreWorker
|
||||
:feature_category: :instance_resiliency
|
||||
:has_external_dependencies: false
|
||||
:urgency: :low
|
||||
:resource_boundary: :unknown
|
||||
:weight: 1
|
||||
:idempotent: true
|
||||
:tags: []
|
||||
- :name: analytics_usage_trends_counter_job
|
||||
:worker_name: Analytics::UsageTrends::CounterJobWorker
|
||||
:feature_category: :devops_reports
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ value_description:
|
|||
extra_properties:
|
||||
identifiers:
|
||||
- user
|
||||
- project
|
||||
- namespace
|
||||
product_section: ops
|
||||
product_stage: deploy
|
||||
product_group: environments
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ value_description:
|
|||
extra_properties:
|
||||
identifiers:
|
||||
- user
|
||||
- project
|
||||
- namespace
|
||||
product_section: ops
|
||||
product_stage: deploy
|
||||
product_group: environments
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ value_description:
|
|||
extra_properties:
|
||||
identifiers:
|
||||
- user
|
||||
- project
|
||||
- namespace
|
||||
product_section: ops
|
||||
product_stage: deploy
|
||||
product_group: environments
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
---
|
||||
description: Tracks the creation of Machine learning models (Ml::Model) through Ml::CreateModelService
|
||||
category: InternalEventTracking
|
||||
action: model_registry_ml_model_created
|
||||
label_description:
|
||||
property_description:
|
||||
value_description:
|
||||
extra_properties:
|
||||
identifiers:
|
||||
- project
|
||||
- user
|
||||
- namespace
|
||||
product_section: data-science
|
||||
product_stage: modelops
|
||||
product_group: mlops
|
||||
milestone: "16.8"
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/139798
|
||||
distributions:
|
||||
- ce
|
||||
- ee
|
||||
tiers:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
---
|
||||
description: Tracks the creation of Machine learning models versions (Ml::ModelVersion) through Ml::CreateModelVersionService
|
||||
category: InternalEventTracking
|
||||
action: model_registry_ml_model_version_created
|
||||
label_description:
|
||||
property_description:
|
||||
value_description:
|
||||
extra_properties:
|
||||
identifiers:
|
||||
- project
|
||||
- user
|
||||
- namespace
|
||||
product_section: data-science
|
||||
product_stage: modelops
|
||||
product_group: mlops
|
||||
milestone: "16.8"
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/139798
|
||||
distributions:
|
||||
- ce
|
||||
- ee
|
||||
tiers:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
name: display_work_item_epic_issue_sidebar
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/135480
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/430337
|
||||
milestone: '16.8'
|
||||
type: development
|
||||
group: group::product planning
|
||||
default_enabled: false
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
name: exempt_paid_namespace_members_and_enterprise_users_from_identity_verification
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/139101
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/434810
|
||||
milestone: '16.7'
|
||||
type: development
|
||||
group: group::anti-abuse
|
||||
default_enabled: false
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
---
|
||||
key_path: count_total_model_registry_ml_model_created_28d
|
||||
description: Tracks the creation of Machine learning models (Ml::Model) through Ml::CreateModelService in the last 28 days.
|
||||
product_section: data-science
|
||||
product_stage: modelops
|
||||
product_group: mlops
|
||||
performance_indicator_type: []
|
||||
value_type: number
|
||||
status: active
|
||||
milestone: "16.8"
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/139798
|
||||
time_frame: 28d
|
||||
data_source: internal_events
|
||||
data_category: optional
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
options:
|
||||
events:
|
||||
- model_registry_ml_model_created
|
||||
events:
|
||||
- name: model_registry_ml_model_created
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
---
|
||||
key_path: count_total_model_registry_ml_model_version_created_28d
|
||||
description: Tracks the creation of Machine learning models versions (Ml::ModelVersion) through Ml::CreateModelVersionService in the last 28 days.
|
||||
product_section: data-science
|
||||
product_stage: modelops
|
||||
product_group: mlops
|
||||
performance_indicator_type: []
|
||||
value_type: number
|
||||
status: active
|
||||
milestone: "16.8"
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/139798
|
||||
time_frame: 28d
|
||||
data_source: internal_events
|
||||
data_category: optional
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
options:
|
||||
events:
|
||||
- model_registry_ml_model_version_created
|
||||
events:
|
||||
- name: model_registry_ml_model_version_created
|
||||
|
|
@ -7,7 +7,7 @@ product_group: code_creation
|
|||
performance_indicator_type: []
|
||||
value_type: number
|
||||
status: active
|
||||
milestone: "16.7"
|
||||
milestone: "16.8"
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/138848
|
||||
time_frame: 7d
|
||||
data_source: internal_events
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
---
|
||||
key_path: count_total_model_registry_ml_model_created_7d
|
||||
description: Tracks the creation of Machine learning models (Ml::Model) through Ml::CreateModelService in the last 7 days.
|
||||
product_section: data-science
|
||||
product_stage: modelops
|
||||
product_group: mlops
|
||||
performance_indicator_type: []
|
||||
value_type: number
|
||||
status: active
|
||||
milestone: "16.8"
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/139798
|
||||
time_frame: 7d
|
||||
data_source: internal_events
|
||||
data_category: optional
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
options:
|
||||
events:
|
||||
- model_registry_ml_model_created
|
||||
events:
|
||||
- name: model_registry_ml_model_created
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
---
|
||||
key_path: count_total_model_registry_ml_model_version_created_7d
|
||||
description: Tracks the creation of Machine learning models versions (Ml::ModelVersion) through Ml::CreateModelVersionService in the last 7 days.
|
||||
product_section: data-science
|
||||
product_stage: modelops
|
||||
product_group: mlops
|
||||
performance_indicator_type: []
|
||||
value_type: number
|
||||
status: active
|
||||
milestone: "16.8"
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/139798
|
||||
time_frame: 7d
|
||||
data_source: internal_events
|
||||
data_category: optional
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
options:
|
||||
events:
|
||||
- model_registry_ml_model_version_created
|
||||
events:
|
||||
- name: model_registry_ml_model_version_created
|
||||
|
|
@ -27,6 +27,8 @@
|
|||
- 1
|
||||
- - abuse_spam_abuse_events
|
||||
- 1
|
||||
- - abuse_trust_score
|
||||
- 1
|
||||
- - activity_pub
|
||||
- 1
|
||||
- - adjourned_project_deletion
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddCascadingToggleSecurityPolicyCustomCiSetting < Gitlab::Database::Migration[2.2]
|
||||
milestone '16.8'
|
||||
|
||||
include Gitlab::Database::MigrationHelpers::CascadingNamespaceSettings
|
||||
|
||||
enable_lock_retries!
|
||||
|
||||
def up
|
||||
add_cascading_namespace_setting :toggle_security_policy_custom_ci, :boolean, default: false, null: false
|
||||
end
|
||||
|
||||
def down
|
||||
remove_cascading_namespace_setting :toggle_security_policy_custom_ci
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class RemoveMaxWorkspacesFromRemoteDevelopmentAgentConfigs < Gitlab::Database::Migration[2.2]
|
||||
milestone '16.8'
|
||||
enable_lock_retries!
|
||||
|
||||
def change
|
||||
remove_column :remote_development_agent_configs, :max_workspaces, :bigint, default: -1, null: false
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class RemoveMaxWorkspacesPerUserFromRemoteDevelopmentAgentConfigs < Gitlab::Database::Migration[2.2]
|
||||
milestone '16.8'
|
||||
enable_lock_retries!
|
||||
|
||||
def change
|
||||
remove_column :remote_development_agent_configs, :max_workspaces_per_user, :bigint, default: -1, null: false
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
29c39f7290a075ead472b5b5d41e60160073d5d49f05ae2b281e48a123990dfc
|
||||
|
|
@ -0,0 +1 @@
|
|||
90b8a5342c57f8383b20684774ee5f7a551be4e93dcdf6d17bb2c2490fcd5214
|
||||
|
|
@ -0,0 +1 @@
|
|||
814dc93e655e9f4abb2af348b67069f2b747300614e8251346bf252477cf3dbe
|
||||
|
|
@ -12282,6 +12282,8 @@ CREATE TABLE application_settings (
|
|||
security_txt_content text,
|
||||
encrypted_arkose_labs_data_exchange_key bytea,
|
||||
encrypted_arkose_labs_data_exchange_key_iv bytea,
|
||||
toggle_security_policy_custom_ci boolean DEFAULT false NOT NULL,
|
||||
lock_toggle_security_policy_custom_ci boolean DEFAULT false NOT NULL,
|
||||
CONSTRAINT app_settings_container_reg_cleanup_tags_max_list_size_positive CHECK ((container_registry_cleanup_tags_service_max_list_size >= 0)),
|
||||
CONSTRAINT app_settings_container_registry_pre_import_tags_rate_positive CHECK ((container_registry_pre_import_tags_rate >= (0)::numeric)),
|
||||
CONSTRAINT app_settings_dep_proxy_ttl_policies_worker_capacity_positive CHECK ((dependency_proxy_ttl_group_policy_worker_capacity >= 0)),
|
||||
|
|
@ -19608,6 +19610,8 @@ CREATE TABLE namespace_settings (
|
|||
product_analytics_enabled boolean DEFAULT false NOT NULL,
|
||||
allow_merge_without_pipeline boolean DEFAULT false NOT NULL,
|
||||
enforce_ssh_certificates boolean DEFAULT false NOT NULL,
|
||||
toggle_security_policy_custom_ci boolean,
|
||||
lock_toggle_security_policy_custom_ci boolean DEFAULT false NOT NULL,
|
||||
CONSTRAINT check_0ba93c78c7 CHECK ((char_length(default_branch_name) <= 255)),
|
||||
CONSTRAINT namespace_settings_unique_project_download_limit_alertlist_size CHECK ((cardinality(unique_project_download_limit_alertlist) <= 100)),
|
||||
CONSTRAINT namespace_settings_unique_project_download_limit_allowlist_size CHECK ((cardinality(unique_project_download_limit_allowlist) <= 100))
|
||||
|
|
@ -22774,8 +22778,6 @@ CREATE TABLE remote_development_agent_configs (
|
|||
network_policy_egress jsonb DEFAULT '[{"allow": "0.0.0.0/0", "except": ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"]}]'::jsonb NOT NULL,
|
||||
default_resources_per_workspace_container jsonb DEFAULT '{}'::jsonb NOT NULL,
|
||||
max_resources_per_workspace jsonb DEFAULT '{}'::jsonb NOT NULL,
|
||||
max_workspaces bigint DEFAULT '-1'::integer NOT NULL,
|
||||
max_workspaces_per_user bigint DEFAULT '-1'::integer NOT NULL,
|
||||
workspaces_quota bigint DEFAULT '-1'::integer NOT NULL,
|
||||
workspaces_per_user_quota bigint DEFAULT '-1'::integer NOT NULL,
|
||||
CONSTRAINT check_72947a4495 CHECK ((char_length(gitlab_workspaces_proxy_namespace) <= 63)),
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ You can use the following environment variables to override certain values:
|
|||
| `GITLAB_RAILS_CACHE_DEFAULT_TTL_SECONDS` | integer | The default TTL used for entries stored in the Rails-cache. Default is `28800`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/95042) in 15.3. |
|
||||
| `GITLAB_CI_CONFIG_FETCH_TIMEOUT_SECONDS` | integer | Timeout for resolving remote includes in CI config in seconds. Must be between `0` and `60`. Default is `30`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/116383) in 15.11. |
|
||||
| `GITLAB_LFS_MAX_OID_TO_FETCH` | integer | Sets the maximum number of LFS objects to link. Default is `100,000`. |
|
||||
| `SIDEKIQ_SEMI_RELIABLE_FETCH_TIMEOUT` | integer | Sets the timeout for Sidekiq semi-reliable fetch. Default is `5`. [Before GitLab 16.7](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/139583), default was `3`. If you experience high Redis CPU consumption on GitLab 16.6 and earlier, or if you have customized this variable, you should update this variable to `5`. |
|
||||
|
||||
## Adding more variables
|
||||
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ housekeeping tasks. The manual trigger can be useful when either:
|
|||
To trigger housekeeping tasks manually:
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find your project.
|
||||
1. On the left sidebar, select **Settings > General**.
|
||||
1. Select **Settings > General**.
|
||||
1. Expand **Advanced**.
|
||||
1. Select **Run housekeeping**.
|
||||
|
||||
|
|
@ -136,7 +136,7 @@ reduce the likelihood of such race conditions.
|
|||
To trigger a manual prune of unreachable objects:
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find your project.
|
||||
1. On the left sidebar, select **Settings > General**.
|
||||
1. Select **Settings > General**.
|
||||
1. Expand **Advanced**.
|
||||
1. Select **Run housekeeping**.
|
||||
1. Wait 30 minutes for the operation to complete.
|
||||
|
|
|
|||
|
|
@ -842,7 +842,7 @@ Prerequisites:
|
|||
To set the maximum size of each GitLab Pages site in a group, overriding the inherited setting:
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find your group.
|
||||
1. On the left sidebar, select **Settings > General**.
|
||||
1. Select **Settings > General**.
|
||||
1. Expand **Pages**.
|
||||
1. Enter a value under **Maximum size** in MB.
|
||||
1. Select **Save changes**.
|
||||
|
|
@ -856,7 +856,7 @@ Prerequisites:
|
|||
To set the maximum size of GitLab Pages site in a project, overriding the inherited setting:
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find your project.
|
||||
1. On the left sidebar, select **Deploy > Pages**.
|
||||
1. Select **Deploy > Pages**.
|
||||
1. In **Maximum size of pages**, enter the size in MB.
|
||||
1. Select **Save changes**.
|
||||
|
||||
|
|
|
|||
|
|
@ -77,6 +77,11 @@ repl_backlog_first_byte_offset:0
|
|||
repl_backlog_histlen:0
|
||||
```
|
||||
|
||||
## High CPU usage on Redis instance
|
||||
|
||||
High CPU usage on Redis instance can be cause by Sidekiq `BRPOP` calls. The `BRPOP` command is expensive and increases CPU usage on Redis.
|
||||
Increase the [`SIDEKIQ_SEMI_RELIABLE_FETCH_TIMEOUT` environment variable](../environment_variables.md) to improve CPU usage on Redis.
|
||||
|
||||
## Troubleshooting Sentinel
|
||||
|
||||
If you get an error like: `Redis::CannotConnectError: No sentinels available.`,
|
||||
|
|
|
|||
|
|
@ -641,6 +641,11 @@ indicate that additional Sidekiq processes would be beneficial.
|
|||
Consider [adding additional Sidekiq processes](extra_sidekiq_processes.md)
|
||||
to compensate for removing the `sidekiq-cluster` service.
|
||||
|
||||
## CPU saturation in Redis caused by Sidekiq BRPOP calls
|
||||
|
||||
Sidekiq `BROP` calls can cause CPU usage to increase on Redis.
|
||||
Increase the [`SIDEKIQ_SEMI_RELIABLE_FETCH_TIMEOUT` environment variable](../environment_variables.md) to improve CPU usage on Redis.
|
||||
|
||||
## Related topics
|
||||
|
||||
- [Elasticsearch workers overload Sidekiq](../../integration/advanced_search/elasticsearch_troubleshooting.md#elasticsearch-workers-overload-sidekiq).
|
||||
|
|
|
|||
|
|
@ -633,7 +633,7 @@ The next time the pipeline runs, the cache is stored in a different location.
|
|||
You can clear the cache in the GitLab UI:
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find your project.
|
||||
1. On the left sidebar, select **Build > Pipelines**.
|
||||
1. Select **Build > Pipelines**.
|
||||
1. In the upper-right corner, select **Clear runner caches**.
|
||||
|
||||
On the next commit, your CI/CD jobs use a new cache.
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ To trigger a pipeline schedule manually, so that it runs immediately instead of
|
|||
the next scheduled time:
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find your project.
|
||||
1. On the left sidebar, select **Build > Pipeline schedules**.
|
||||
1. Select **Build > Pipeline schedules**.
|
||||
1. On the right of the list, for
|
||||
the pipeline you want to run, select **Play** (**{play}**).
|
||||
|
||||
|
|
@ -79,7 +79,7 @@ including [protected environments](../environments/protected_environments.md) an
|
|||
To take ownership of a pipeline created by a different user:
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find your project.
|
||||
1. On the left sidebar, select **Build > Pipeline schedules**.
|
||||
1. Select **Build > Pipeline schedules**.
|
||||
1. On the right of the list, for
|
||||
the pipeline you want to become owner of, select **Take ownership**.
|
||||
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ To see the evolution of your project code coverage over time,
|
|||
you can view a graph or download a CSV file with this data.
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find your project.
|
||||
1. On the left sidebar, select **Analyze > Repository analytics**.
|
||||
1. Select **Analyze > Repository analytics**.
|
||||
|
||||
The historic data for each job is listed in the dropdown list above the graph.
|
||||
|
||||
|
|
|
|||
|
|
@ -217,10 +217,10 @@ on merge request rates.
|
|||
See the [Verify issue](https://gitlab.com/gitlab-org/gitlab/-/issues/411559) for a good example.
|
||||
|
||||
All other cases should not use mandatory sections as we favor
|
||||
[responsbility over ridigity](https://handbook.gitlab.com/handbook/values/#freedom-and-responsibility-over-rigidity).
|
||||
[responsibility over ridigity](https://handbook.gitlab.com/handbook/values/#freedom-and-responsibility-over-rigidity).
|
||||
|
||||
Additionally, the current structure of the monolith means that merge requests
|
||||
are likely to touch seemingly un-related parts.
|
||||
are likely to touch seemingly unrelated parts.
|
||||
Multiple mandatory approvals means that such merge requests require the author
|
||||
to seek approvals, which is not efficient.
|
||||
|
||||
|
|
|
|||
|
|
@ -257,6 +257,41 @@ Make sure the newly-created data is either migrated, or
|
|||
saved in both the old and new version upon creation. Removals in
|
||||
turn can be handled by defining foreign keys with cascading deletes.
|
||||
|
||||
### Finalize a batched background migration
|
||||
|
||||
Finalizing a batched background migration is done by calling
|
||||
`ensure_batched_background_migration_is_finished`.
|
||||
|
||||
It is important to finalize all batched background migrations when it is safe
|
||||
to do so. Leaving around old batched background migration is a form of
|
||||
technical debt that needs to be maintained in tests and in application
|
||||
behavior. It is important to note that you cannot depend on any batched
|
||||
background migration being completed until after it is finalized.
|
||||
|
||||
We recommend that batched background migrations are finalized after all of the
|
||||
following conditions are met:
|
||||
|
||||
- The batched background migration is completed on GitLab.com
|
||||
- The batched background migration was added in or before the last [required stop](required_stops.md)
|
||||
|
||||
The `ensure_batched_background_migration_is_finished` call must exactly match
|
||||
the migration that was used to enqueue it. Pay careful attention to:
|
||||
|
||||
- The job arguments: Needs to exactly match or it will not find the queued migration
|
||||
- The `gitlab_schema`: Needs to exactly match or it will not find the queued
|
||||
migration. Even if the `gitlab_schema` of the table has changed from
|
||||
`gitlab_main` to `gitlab_main_cell` in the meantime you must finalize it
|
||||
with `gitlab_main` if that's what was used when queueing the batched
|
||||
background migration.
|
||||
|
||||
When finalizing a batched background migration you also need to update the
|
||||
`finalized_by` in the corresponding `db/docs/batched_background_migrations`
|
||||
file. The value should be the timestamp/version of the migration you added to
|
||||
finalize it.
|
||||
|
||||
See the below [Examples](#examples) for specific details on what the actual
|
||||
migration code should be.
|
||||
|
||||
### Use job arguments
|
||||
|
||||
`BatchedMigrationJob` provides the `job_arguments` helper method for job classes to define the job arguments they need.
|
||||
|
|
|
|||
|
|
@ -1274,6 +1274,9 @@ This group SCIM API is different to the [SCIM API](../../api/scim.md). The SCIM
|
|||
- Does not implement the [RFC7644 protocol](https://www.rfc-editor.org/rfc/rfc7644).
|
||||
- Gets, checks, updates, and deletes SCIM identities within groups.
|
||||
|
||||
NOTE:
|
||||
This API does not require the `Gitlab-Shell-Api-Request` header.
|
||||
|
||||
### Get a list of SCIM provisioned users
|
||||
|
||||
This endpoint is used as part of the SCIM syncing mechanism. It returns a list of users depending on the filter used.
|
||||
|
|
@ -1519,6 +1522,9 @@ This instance SCIM API is different to the [SCIM API](../../api/scim.md). The SC
|
|||
- Does not implement the [RFC7644 protocol](https://www.rfc-editor.org/rfc/rfc7644).
|
||||
- Gets, checks, updates, and deletes SCIM identities within groups.
|
||||
|
||||
NOTE:
|
||||
This API does not require the `Gitlab-Shell-Api-Request` header.
|
||||
|
||||
### Get a list of SCIM provisioned users
|
||||
|
||||
This endpoint is used as part of the SCIM syncing mechanism. It returns a list of users depending on the filter used.
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@ provided your GitLab administrator [has configured the integration](configure.md
|
|||
To view Jira issues:
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find your project.
|
||||
1. On the left sidebar, select **Plan > Jira issues**.
|
||||
1. Select **Plan > Jira issues**.
|
||||
|
||||
The issues are sorted by **Created date** by default, with the most recently created issues listed at the top.
|
||||
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ Benefits of the GitLab Open Source Program apply to all projects in a GitLab nam
|
|||
#### Screenshot 1: License overview
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find your project.
|
||||
1. On the left sidebar, select your project avatar. If you haven't specified an avatar for your project, the avatar displays as a single letter.
|
||||
1. Select your project avatar. If you haven't specified an avatar for your project, the avatar displays as a single letter.
|
||||
1. Take a screenshot of the project overview that clearly displays the license you've chosen for your project.
|
||||
|
||||

|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
|
||||
Make sure you view [this update guide](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/update/patch_versions.md) from the tag (version) of GitLab you would like to install.
|
||||
In most cases this should be the highest numbered production tag (without `rc` in it).
|
||||
You can select the tag in the version dropdown list in the upper-left corner of GitLab (below the menu bar).
|
||||
You can select the tag in the version dropdown list in the upper-left corner of GitLab.
|
||||
|
||||
### 0. Backup
|
||||
|
||||
|
|
|
|||
|
|
@ -95,6 +95,12 @@ against this, infrastructure analysis occurs on every merge request. Checks are
|
|||
- Infrastructure as Code (IaC) configuration files that define your application's deployment
|
||||
environment - [Infrastructure as Code (IaC) Scanning](iac_scanning/index.md).
|
||||
|
||||
## Data privacy
|
||||
|
||||
Concerning data privacy in the domain of security scanners, GitLab processes the source code and performs analysis locally on the GitLab Runner. No data is transmitted outside GitLab infrastructure (server and runners).
|
||||
|
||||
Our scanners access the internet only to download the latest sets of signatures, rules, and patches. If you prefer the scanners do not access the internet, consider using an [offline environment](offline_deployments/index.md).
|
||||
|
||||
## Vulnerability scanner maintenance
|
||||
|
||||
The following vulnerability scanners and their databases are regularly updated:
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ Prerequisite:
|
|||
- You must have the Owner role for the group.
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find your group.
|
||||
1. On the left sidebar, select **Settings > Usage Quotas**.
|
||||
1. Select **Settings > Usage Quotas**.
|
||||
1. To view all members, select the **Seats** tab.
|
||||
1. To remove a member, select **Remove user**.
|
||||
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ To leave a group:
|
|||
To remove a group and its contents:
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find your group.
|
||||
1. On the left sidebar, select **Settings > General**.
|
||||
1. Select **Settings > General**.
|
||||
1. Expand the **Advanced** section.
|
||||
1. In the **Remove group** section, select **Remove group**.
|
||||
1. On the confirmation dialog, type the group name and select **Confirm**.
|
||||
|
|
|
|||
|
|
@ -178,7 +178,7 @@ Prerequisites:
|
|||
To create an iteration:
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find your group.
|
||||
1. On the left sidebar, select **Plan > Iterations** and select an iteration cadence.
|
||||
1. Select **Plan > Iterations** and select an iteration cadence.
|
||||
1. Select **New iteration**.
|
||||
1. Enter the title, a description (optional), a start date, and a due date.
|
||||
1. Select **Create iteration**. The iteration details page opens.
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ To learn how to create better OKRs and how we use them at GitLab, see the
|
|||
To create an objective:
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find your project.
|
||||
1. On the left sidebar, select **Plan > Issues**.
|
||||
1. Select **Plan > Issues**.
|
||||
1. In the upper-right corner, next to **New issue**, select the down arrow **{chevron-lg-down}** and then select **New objective**.
|
||||
1. Select **New objective** again.
|
||||
1. Enter the objective title.
|
||||
|
|
@ -70,7 +70,7 @@ To create a key result, [add it as a child](#add-a-child-key-result) to an exist
|
|||
To view an objective:
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find your project.
|
||||
1. On the left sidebar, select **Plan > Issues**.
|
||||
1. Select **Plan > Issues**.
|
||||
1. [Filter the list of issues](project/issues/managing_issues.md#filter-the-list-of-issues)
|
||||
for `Type = objective`.
|
||||
1. Select the title of an objective from the list.
|
||||
|
|
@ -80,7 +80,7 @@ for `Type = objective`.
|
|||
To view a key result:
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find your project.
|
||||
1. On the left sidebar, select **Plan > Issues**.
|
||||
1. Select **Plan > Issues**.
|
||||
1. [Filter the list of issues](project/issues/managing_issues.md#filter-the-list-of-issues)
|
||||
for `Type = key_result`.
|
||||
1. Select the title of a key result from the list.
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ For **self-managed** GitLab instances, make sure your administrator has
|
|||
Once you've met the requirements, enable Let's Encrypt integration:
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find your project.
|
||||
1. On the left sidebar, select **Deploy > Pages**.
|
||||
1. Select **Deploy > Pages**.
|
||||
1. Next to the domain name, select **Edit**.
|
||||
1. Turn on the **Automatic certificate management using Let's Encrypt** toggle.
|
||||
|
||||
|
|
@ -69,7 +69,7 @@ associated Pages domain. GitLab also renews it automatically.
|
|||
If you get an error **Something went wrong while obtaining the Let's Encrypt certificate**, first, make sure that your pages site is set to "Everyone" in your project's **Settings > General > Visibility**. This allows the Let's Encrypt Servers reach your pages site. Once this is confirmed, you can try obtaining the certificate again by following these steps:
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find your project.
|
||||
1. On the left sidebar, select **Deploy > Pages**.
|
||||
1. Select **Deploy > Pages**.
|
||||
1. Next to the domain name, select **Edit**.
|
||||
1. In **Verification status**, select **Retry verification** (**{retry}**).
|
||||
1. If you're still getting the same error:
|
||||
|
|
@ -84,7 +84,7 @@ If you get an error **Something went wrong while obtaining the Let's Encrypt cer
|
|||
If you've enabled Let's Encrypt integration, but a certificate is absent after an hour and you see the message, "GitLab is obtaining a Let's Encrypt SSL certificate for this domain. This process can take some time. Please try again later.", try to remove and add the domain for GitLab Pages again by following these steps:
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find your project.
|
||||
1. On the left sidebar, select **Deploy > Pages**.
|
||||
1. Select **Deploy > Pages**.
|
||||
1. Next to the domain name, select **Remove**.
|
||||
1. [Add the domain again, and verify it](index.md#1-add-a-custom-domain).
|
||||
1. [Enable Let's Encrypt integration for your domain](#enabling-lets-encrypt-integration-for-your-custom-domain).
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ You can configure redirects for your site using a `_redirects` file. For more in
|
|||
To remove your pages:
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find your project.
|
||||
1. On the left sidebar, select **Deploy > Pages**.
|
||||
1. Select **Deploy > Pages**.
|
||||
1. Select **Remove pages**.
|
||||
|
||||
## Subdomains of subdomains
|
||||
|
|
@ -100,7 +100,7 @@ By default, every project in a group shares the same domain, for example, `group
|
|||
To ensure your project uses a unique Pages domain, enable the unique domains feature for the project:
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find your project.
|
||||
1. On the left sidebar, select **Deploy > Pages**.
|
||||
1. Select **Deploy > Pages**.
|
||||
1. Select the **Use unique domain** checkbox.
|
||||
1. Select **Save changes**.
|
||||
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ Prerequisites:
|
|||
To create a release in the Releases page:
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find your project.
|
||||
1. On the left sidebar, select **Deploy > Releases** and select **New release**.
|
||||
1. Select **Deploy > Releases** and select **New release**.
|
||||
1. From the [**Tag name**](release_fields.md#tag-name) dropdown list, either:
|
||||
- Select an existing Git tag. Selecting an existing tag that is already associated with a release
|
||||
results in a validation error.
|
||||
|
|
@ -216,7 +216,7 @@ To delete a release, use either the
|
|||
In the UI:
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find your project.
|
||||
1. On the left sidebar, select **Deploy > Releases**.
|
||||
1. Select **Deploy > Releases**.
|
||||
1. In the upper-right corner of the release you want to delete, select **Edit this release**
|
||||
(**{pencil}**).
|
||||
1. On the **Edit Release** page, select **Delete**.
|
||||
|
|
@ -321,7 +321,7 @@ To set a deploy freeze window in the UI, complete these steps:
|
|||
|
||||
1. Sign in to GitLab as a user with the Maintainer role.
|
||||
1. On the left sidebar, select **Search or go to** and find your project.
|
||||
1. On the left sidebar, select **Settings > CI/CD**.
|
||||
1. Select **Settings > CI/CD**.
|
||||
1. Scroll to **Deploy freezes**.
|
||||
1. Select **Expand** to see the deploy freeze table.
|
||||
1. Select **Add deploy freeze** to open the deploy freeze modal.
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ Prerequisites:
|
|||
To view the blame for a file:
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find your project.
|
||||
1. On the left sidebar, select **Code > Repository**.
|
||||
1. Select **Code > Repository**.
|
||||
1. Select the file you want to review.
|
||||
1. In the upper-right corner, select **Blame**, and go to the line you want to see.
|
||||
|
||||
|
|
@ -39,7 +39,7 @@ changes to light gray.
|
|||
To see earlier revisions of a specific line:
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find your project.
|
||||
1. On the left sidebar, select **Code > Repository**.
|
||||
1. Select **Code > Repository**.
|
||||
1. Select the file you want to review.
|
||||
1. In the upper-right corner, select **Blame**, and go to the line you want to see.
|
||||
1. Select **View blame prior to this change** (**{doc-versions}**)
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ To create the webhook in the downstream instance:
|
|||
|
||||
1. Create a [personal access token](../../../profile/personal_access_tokens.md) with `API` scope.
|
||||
1. On the left sidebar, select **Search or go to** and find your project.
|
||||
1. On the left sidebar, select **Settings > Webhooks**.
|
||||
1. Select **Settings > Webhooks**.
|
||||
1. Add the webhook **URL**, which (in this case) uses the
|
||||
[Pull Mirror API](../../../../api/projects.md#start-the-pull-mirroring-process-for-a-project)
|
||||
request to trigger an immediate pull after a repository update:
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ Prerequisites:
|
|||
to private if a subgroup or project in that group is public.
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find your group.
|
||||
1. On the left sidebar, select **Settings > General**.
|
||||
1. Select **Settings > General**.
|
||||
1. Expand **Naming, visibility**.
|
||||
1. For **Visibility level**, select an option.
|
||||
The visibility setting for a project must be at least as restrictive
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ To report abuse from a user's profile page:
|
|||
To report abuse from a user's comment:
|
||||
|
||||
1. In the comment, in the upper-right corner, select **More actions** (**{ellipsis_v}**).
|
||||
1. Select **Report abuse to administrator**.
|
||||
1. Select **Report abuse**.
|
||||
1. Select a reason for reporting the user.
|
||||
1. Complete an abuse report.
|
||||
1. Select **Send report**.
|
||||
|
|
@ -63,7 +63,7 @@ A URL to the reported user's comment is pre-filled in the abuse report's
|
|||
## Report abuse from a merge request
|
||||
|
||||
1. On the merge request, in the upper-right corner, select **Merge request actions** (**{ellipsis_v}**).
|
||||
1. Select **Report abuse to administrator**.
|
||||
1. Select **Report abuse**.
|
||||
1. Select a reason for reporting this user.
|
||||
1. Complete an abuse report.
|
||||
1. Select **Send report**.
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ To display a window in GitLab that lists its keyboard shortcuts, use one of the
|
|||
following methods:
|
||||
|
||||
- Press <kbd>?</kbd>.
|
||||
- In the Help menu, in the upper-right corner of the application, select **Keyboard shortcuts**.
|
||||
- In the lower-left corner of the application, select **Help** and then **Keyboard shortcuts**.
|
||||
|
||||
Although [global shortcuts](#global-shortcuts) work from any area of GitLab,
|
||||
you must be in specific pages for the other shortcuts to be available, as
|
||||
|
|
|
|||
|
|
@ -232,7 +232,7 @@ Prerequisites:
|
|||
To do this task:
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find your project.
|
||||
1. On the left sidebar, select **Code > Snippets**.
|
||||
1. Select **Code > Snippets**.
|
||||
1. Select the snippet you want to report as spam.
|
||||
1. Select **Submit as spam**.
|
||||
|
||||
|
|
|
|||
|
|
@ -139,6 +139,8 @@ module API
|
|||
authorize!(:create_deployment, user_project)
|
||||
authorize!(:create_environment, user_project)
|
||||
|
||||
render_api_error!({ ref: ["The branch or tag does not exist"] }, 400) unless user_project.commit(declared_params[:ref])
|
||||
|
||||
environment = user_project
|
||||
.environments
|
||||
.find_or_create_by_name(params[:environment])
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ module Gitlab
|
|||
module SidekiqMiddleware
|
||||
module PauseControl
|
||||
class Server
|
||||
def call(worker_class, job, _queue, &block)
|
||||
::Gitlab::SidekiqMiddleware::PauseControl::StrategyHandler.new(worker_class, job).perform(&block)
|
||||
def call(worker, job, _queue, &block)
|
||||
::Gitlab::SidekiqMiddleware::PauseControl::StrategyHandler.new(worker, job).perform(&block)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -17,7 +17,8 @@ module Gitlab
|
|||
def strategy_for(worker:)
|
||||
return unless @workers
|
||||
|
||||
@workers.find { |_, v| v.include?(worker) }&.first
|
||||
worker_class = worker.is_a?(Class) ? worker : worker.class
|
||||
@workers.find { |_, v| v.include?(worker_class) }&.first
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -70,13 +70,19 @@ module Integrations
|
|||
|
||||
override :issuer
|
||||
def issuer
|
||||
Settings.gitlab.host
|
||||
Feature.enabled?(:oidc_issuer_url) ? Gitlab.config.gitlab.url : Settings.gitlab.base_url
|
||||
end
|
||||
|
||||
override :audience
|
||||
def audience
|
||||
@claims[:audience]
|
||||
end
|
||||
|
||||
override :kid
|
||||
def kid
|
||||
rsa_key = OpenSSL::PKey::RSA.new(key_data)
|
||||
rsa_key.public_key.to_jwk[:kid]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1386,9 +1386,21 @@ msgstr ""
|
|||
msgid "'allow: %{allow}' must be a string"
|
||||
msgstr ""
|
||||
|
||||
msgid "'cpu: %{cpu}' must be a string"
|
||||
msgstr ""
|
||||
|
||||
msgid "'cpu: %{cpu}' must match the regex '%{cpu_regex}'"
|
||||
msgstr ""
|
||||
|
||||
msgid "'except: %{except}' must be an array of string"
|
||||
msgstr ""
|
||||
|
||||
msgid "'memory: %{memory}' must be a string"
|
||||
msgstr ""
|
||||
|
||||
msgid "'memory: %{memory}' must match the regex '%{memory_regex}'"
|
||||
msgstr ""
|
||||
|
||||
msgid "'projects' is not yet supported"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -10306,9 +10318,6 @@ msgstr ""
|
|||
msgid "Choose a file"
|
||||
msgstr ""
|
||||
|
||||
msgid "Choose a group"
|
||||
msgstr ""
|
||||
|
||||
msgid "Choose a template"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -11984,9 +11993,6 @@ msgstr ""
|
|||
msgid "CodeSuggestionsSM|Enable Code Suggestions for this instance"
|
||||
msgstr ""
|
||||
|
||||
msgid "CodeSuggestionsSM|Enable Code Suggestions for this instance %{beta}"
|
||||
msgstr ""
|
||||
|
||||
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -23530,6 +23536,9 @@ msgstr ""
|
|||
msgid "GroupSettings|Reporting"
|
||||
msgstr ""
|
||||
|
||||
msgid "GroupSettings|Security policy custom CI Experiment"
|
||||
msgstr ""
|
||||
|
||||
msgid "GroupSettings|Select a subgroup to use as a source of custom templates for new projects in this group. %{link_start}Learn more%{link_end}."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -23572,6 +23581,9 @@ msgstr ""
|
|||
msgid "GroupSettings|These features are being developed and might be unstable."
|
||||
msgstr ""
|
||||
|
||||
msgid "GroupSettings|This feature is being developed and might be unstable."
|
||||
msgstr ""
|
||||
|
||||
msgid "GroupSettings|This setting is applied on %{ancestor_group} and has been overridden on this subgroup."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -45323,6 +45335,12 @@ msgstr ""
|
|||
msgid "Settings for the License Compliance feature"
|
||||
msgstr ""
|
||||
|
||||
msgid "Settings|Enable this feature allows you to add customized CI YAML file to run as part of the policies action. This features is your acceptance of the %{link_start}GitLab Testing Agreement%{link_end}."
|
||||
msgstr ""
|
||||
|
||||
msgid "Settings|Run customized CI YAML file as security policy actions"
|
||||
msgstr ""
|
||||
|
||||
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -58320,6 +58338,18 @@ msgstr ""
|
|||
msgid "must be a boolean value"
|
||||
msgstr ""
|
||||
|
||||
msgid "must be a hash"
|
||||
msgstr ""
|
||||
|
||||
msgid "must be a hash containing 'cpu' and 'memory' attribute of type string"
|
||||
msgstr ""
|
||||
|
||||
msgid "must be a hash containing 'limits' attribute of type hash"
|
||||
msgstr ""
|
||||
|
||||
msgid "must be a hash containing 'requests' attribute of type hash"
|
||||
msgstr ""
|
||||
|
||||
msgid "must be a root group."
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@
|
|||
"@gitlab/favicon-overlay": "2.0.0",
|
||||
"@gitlab/fonts": "^1.3.0",
|
||||
"@gitlab/svgs": "3.72.0",
|
||||
"@gitlab/ui": "^71.11.1",
|
||||
"@gitlab/ui": "^72.0.0",
|
||||
"@gitlab/visual-review-tools": "1.7.3",
|
||||
"@gitlab/web-ide": "^0.0.1-dev-20231211152737",
|
||||
"@mattiasbuelens/web-streams-adapter": "^0.1.0",
|
||||
|
|
|
|||
|
|
@ -11,33 +11,33 @@ module QA
|
|||
include Page::Component::NamespaceSelect
|
||||
|
||||
view 'app/views/groups/edit.html.haml' do
|
||||
element :permission_lfs_2fa_content
|
||||
element 'permissions-settings'
|
||||
element 'advanced-settings-content'
|
||||
end
|
||||
|
||||
view 'app/views/groups/settings/_permissions.html.haml' do
|
||||
element :save_permissions_changes_button
|
||||
element 'save-permissions-changes-button'
|
||||
end
|
||||
|
||||
view 'app/views/groups/settings/_general.html.haml' do
|
||||
element :group_name_field
|
||||
element :save_name_visibility_settings_button
|
||||
element 'group-name-field'
|
||||
element 'save-name-visibility-settings-button'
|
||||
end
|
||||
|
||||
view 'app/views/groups/settings/_lfs.html.haml' do
|
||||
element :lfs_checkbox
|
||||
element 'lfs-checkbox'
|
||||
end
|
||||
|
||||
view 'app/views/shared/_allow_request_access.html.haml' do
|
||||
element :request_access_checkbox
|
||||
element 'request-access-checkbox'
|
||||
end
|
||||
|
||||
view 'app/views/groups/settings/_two_factor_auth.html.haml' do
|
||||
element :require_2fa_checkbox
|
||||
element 'require-2fa-checkbox'
|
||||
end
|
||||
|
||||
view 'app/views/groups/settings/_project_creation_level.html.haml' do
|
||||
element :project_creation_level_dropdown
|
||||
element 'project-creation-level-dropdown'
|
||||
end
|
||||
|
||||
view 'app/views/groups/settings/_transfer.html.haml' do
|
||||
|
|
@ -49,66 +49,66 @@ module QA
|
|||
end
|
||||
|
||||
def set_group_name(name)
|
||||
find_element(:group_name_field).send_keys([:command, 'a'], :backspace)
|
||||
find_element(:group_name_field).set name
|
||||
find_element('group-name-field').send_keys([:command, 'a'], :backspace)
|
||||
find_element('group-name-field').set name
|
||||
end
|
||||
|
||||
def click_save_name_visibility_settings_button
|
||||
click_element(:save_name_visibility_settings_button)
|
||||
click_element('save-name-visibility-settings-button')
|
||||
end
|
||||
|
||||
def set_lfs_enabled
|
||||
expand_content(:permission_lfs_2fa_content)
|
||||
check_element(:lfs_checkbox, true)
|
||||
click_element(:save_permissions_changes_button)
|
||||
expand_content('permissions-settings')
|
||||
check_element('lfs-checkbox', true)
|
||||
click_element('save-permissions-changes-button')
|
||||
end
|
||||
|
||||
def set_lfs_disabled
|
||||
expand_content(:permission_lfs_2fa_content)
|
||||
uncheck_element(:lfs_checkbox, true)
|
||||
click_element(:save_permissions_changes_button)
|
||||
expand_content('permissions-settings')
|
||||
uncheck_element('lfs-checkbox', true)
|
||||
click_element('save-permissions-changes-button')
|
||||
end
|
||||
|
||||
def set_request_access_enabled
|
||||
expand_content(:permission_lfs_2fa_content)
|
||||
check_element(:request_access_checkbox, true)
|
||||
click_element(:save_permissions_changes_button)
|
||||
expand_content('permissions-settings')
|
||||
check_element('request-access-checkbox', true)
|
||||
click_element('save-permissions-changes-button')
|
||||
end
|
||||
|
||||
def set_request_access_disabled
|
||||
expand_content(:permission_lfs_2fa_content)
|
||||
uncheck_element(:request_access_checkbox, true)
|
||||
click_element(:save_permissions_changes_button)
|
||||
expand_content('permissions-settings')
|
||||
uncheck_element('request-access-checkbox', true)
|
||||
click_element('save-permissions-changes-button')
|
||||
end
|
||||
|
||||
def set_require_2fa_enabled
|
||||
expand_content(:permission_lfs_2fa_content)
|
||||
check_element(:require_2fa_checkbox, true)
|
||||
click_element(:save_permissions_changes_button)
|
||||
expand_content('permissions-settings')
|
||||
check_element('require-2fa-checkbox', true)
|
||||
click_element('save-permissions-changes-button')
|
||||
end
|
||||
|
||||
def set_require_2fa_disabled
|
||||
expand_content(:permission_lfs_2fa_content)
|
||||
uncheck_element(:require_2fa_checkbox, true)
|
||||
click_element(:save_permissions_changes_button)
|
||||
expand_content('permissions-settings')
|
||||
uncheck_element('require-2fa-checkbox', true)
|
||||
click_element('save-permissions-changes-button')
|
||||
end
|
||||
|
||||
def set_project_creation_level(value)
|
||||
expand_content(:permission_lfs_2fa_content)
|
||||
select_element(:project_creation_level_dropdown, value)
|
||||
click_element(:save_permissions_changes_button)
|
||||
expand_content('permissions-settings')
|
||||
select_element('project-creation-level-dropdown', value)
|
||||
click_element('save-permissions-changes-button')
|
||||
end
|
||||
|
||||
def toggle_request_access
|
||||
expand_content(:permission_lfs_2fa_content)
|
||||
expand_content('permissions-settings')
|
||||
|
||||
if find_element(:request_access_checkbox, visible: false).checked?
|
||||
uncheck_element(:request_access_checkbox, true)
|
||||
if find_element('request-access-checkbox', visible: false).checked?
|
||||
uncheck_element('request-access-checkbox', true)
|
||||
else
|
||||
check_element(:request_access_checkbox, true)
|
||||
check_element('request-access-checkbox', true)
|
||||
end
|
||||
|
||||
click_element(:save_permissions_changes_button)
|
||||
click_element('save-permissions-changes-button')
|
||||
end
|
||||
|
||||
def transfer_group(source_group, target_group)
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ module QA
|
|||
|
||||
view 'app/views/groups/_home_panel.html.haml' do
|
||||
element 'new-project-button'
|
||||
element :new_subgroup_button
|
||||
element 'new-subgroup-button'
|
||||
end
|
||||
|
||||
def click_subgroup(name)
|
||||
|
|
@ -18,7 +18,7 @@ module QA
|
|||
|
||||
def has_new_project_and_new_subgroup_buttons?
|
||||
has_element?('new_project_button')
|
||||
has_element?(:new_subgroup_button)
|
||||
has_element?('new-subgroup-button')
|
||||
end
|
||||
|
||||
def has_subgroup?(name)
|
||||
|
|
@ -26,7 +26,7 @@ module QA
|
|||
end
|
||||
|
||||
def go_to_new_subgroup
|
||||
click_element :new_subgroup_button
|
||||
click_element('new-subgroup-button')
|
||||
end
|
||||
|
||||
def go_to_new_project
|
||||
|
|
|
|||
|
|
@ -3,15 +3,14 @@
|
|||
require "spec_helper"
|
||||
|
||||
RSpec.describe Projects::Ml::ShowMlModelComponent, type: :component, feature_category: :mlops do
|
||||
# rubocop:disable RSpec/FactoryBot/AvoidCreate -- build_stubbed breaks because it doesn't create iids properly.
|
||||
let_it_be(:project) { create(:project) }
|
||||
let_it_be(:project) { build_stubbed(:project) }
|
||||
let_it_be(:model1) do
|
||||
create(:ml_models, :with_latest_version_and_package, project: project, description: "A description")
|
||||
build_stubbed(:ml_models, :with_latest_version_and_package, project: project, description: "A description")
|
||||
end
|
||||
# rubocop:enable RSpec/FactoryBot/AvoidCreate
|
||||
|
||||
let_it_be(:experiment) { model1.default_experiment }
|
||||
let_it_be(:candidate) { model1.latest_version.candidate }
|
||||
let_it_be(:experiment) { model1.default_experiment.tap { |e| e.iid = 100 } }
|
||||
let_it_be(:candidate) { model1.latest_version.candidate.tap { |c| c.iid = 101 } }
|
||||
let_it_be(:candidates) { Array.new(2) { build_stubbed(:ml_candidates, experiment: experiment) } }
|
||||
|
||||
subject(:component) do
|
||||
described_class.new(model: model1, current_user: model1.user)
|
||||
|
|
@ -19,6 +18,8 @@ RSpec.describe Projects::Ml::ShowMlModelComponent, type: :component, feature_cat
|
|||
|
||||
describe 'rendered' do
|
||||
before do
|
||||
allow(model1).to receive(:candidates).and_return(candidates)
|
||||
|
||||
render_inline component
|
||||
end
|
||||
|
||||
|
|
@ -52,7 +53,8 @@ RSpec.describe Projects::Ml::ShowMlModelComponent, type: :component, feature_cat
|
|||
'metadata' => []
|
||||
}
|
||||
},
|
||||
'versionCount' => 1
|
||||
'versionCount' => 1,
|
||||
'candidateCount' => 2
|
||||
}
|
||||
})
|
||||
end
|
||||
|
|
|
|||
|
|
@ -11,5 +11,13 @@ FactoryBot.define do
|
|||
e.metadata = FactoryBot.create_list(:ml_experiment_metadata, 2, experiment: e) # rubocop:disable StrategyInCallback
|
||||
end
|
||||
end
|
||||
|
||||
trait :with_candidates do
|
||||
candidates do
|
||||
Array.new(2) do
|
||||
association(:ml_candidates, project: project)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import { shallowMountExtended, extendedWrapper } from 'helpers/vue_test_utils_he
|
|||
import InlineConflictLines from '~/merge_conflicts/components/inline_conflict_lines.vue';
|
||||
import ParallelConflictLines from '~/merge_conflicts/components/parallel_conflict_lines.vue';
|
||||
import component from '~/merge_conflicts/merge_conflict_resolver_app.vue';
|
||||
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
|
||||
import { createStore } from '~/merge_conflicts/store';
|
||||
import { decorateFiles } from '~/merge_conflicts/utils';
|
||||
import { conflictsMock } from '../mock_data';
|
||||
|
|
@ -49,6 +50,7 @@ describe('Merge Conflict Resolver App', () => {
|
|||
const findInlineConflictLines = (w = wrapper) => w.findComponent(InlineConflictLines);
|
||||
const findParallelConflictLines = (w = wrapper) => w.findComponent(ParallelConflictLines);
|
||||
const findCommitMessageTextarea = () => wrapper.findByTestId('commit-message');
|
||||
const findClipboardButton = (w = wrapper) => w.findComponent(ClipboardButton);
|
||||
|
||||
it('shows the amount of conflicts', () => {
|
||||
mountComponent();
|
||||
|
|
@ -131,6 +133,21 @@ describe('Merge Conflict Resolver App', () => {
|
|||
expect(parallelConflictLinesComponent.props('file')).toEqual(decoratedMockFiles[0]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('clipboard button', () => {
|
||||
it('exists', () => {
|
||||
mountComponent();
|
||||
expect(findClipboardButton().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('has the correct props', () => {
|
||||
mountComponent();
|
||||
expect(findClipboardButton().attributes()).toMatchObject({
|
||||
text: decoratedMockFiles[0].filePath,
|
||||
title: 'Copy file path',
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('submit form', () => {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { nextTick } from 'vue';
|
||||
import { GlFilteredSearchToken } from '@gitlab/ui';
|
||||
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import { sortableFields } from '~/packages_and_registries/package_registry/utils';
|
||||
import component from '~/packages_and_registries/package_registry/components/list/package_search.vue';
|
||||
|
|
@ -7,7 +8,11 @@ import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
|
|||
import PersistedSearch from '~/packages_and_registries/shared/components/persisted_search.vue';
|
||||
import { LIST_KEY_CREATED_AT } from '~/packages_and_registries/package_registry/constants';
|
||||
|
||||
import { TOKEN_TYPE_TYPE } from '~/vue_shared/components/filtered_search_bar/constants';
|
||||
import {
|
||||
OPERATORS_IS,
|
||||
TOKEN_TYPE_TYPE,
|
||||
TOKEN_TYPE_VERSION,
|
||||
} from '~/vue_shared/components/filtered_search_bar/constants';
|
||||
|
||||
describe('Package Search', () => {
|
||||
let wrapper;
|
||||
|
|
@ -74,6 +79,13 @@ describe('Package Search', () => {
|
|||
token: PackageTypeToken,
|
||||
type: TOKEN_TYPE_TYPE,
|
||||
icon: 'package',
|
||||
operators: OPERATORS_IS,
|
||||
}),
|
||||
expect.objectContaining({
|
||||
token: GlFilteredSearchToken,
|
||||
type: TOKEN_TYPE_VERSION,
|
||||
icon: 'doc-versions',
|
||||
operators: OPERATORS_IS,
|
||||
}),
|
||||
]),
|
||||
sortableFields: sortableFields(isGroupPage),
|
||||
|
|
@ -102,6 +114,7 @@ describe('Package Search', () => {
|
|||
filters: {
|
||||
packageName: '',
|
||||
packageType: undefined,
|
||||
packageVersion: '',
|
||||
},
|
||||
sort: payload.sort,
|
||||
sorting: payload.sorting,
|
||||
|
|
@ -114,6 +127,7 @@ describe('Package Search', () => {
|
|||
sort: 'CREATED_FOO',
|
||||
filters: [
|
||||
{ type: 'type', value: { data: 'Generic', operator: '=' }, id: 'token-3' },
|
||||
{ type: 'version', value: { data: '1.0.1', operator: '=' }, id: 'token-6' },
|
||||
{ id: 'token-4', type: 'filtered-search-term', value: { data: 'gl' } },
|
||||
{ id: 'token-5', type: 'filtered-search-term', value: { data: '' } },
|
||||
],
|
||||
|
|
@ -133,6 +147,7 @@ describe('Package Search', () => {
|
|||
filters: {
|
||||
packageName: 'gl',
|
||||
packageType: 'GENERIC',
|
||||
packageVersion: '1.0.1',
|
||||
},
|
||||
sort: payload.sort,
|
||||
sorting: payload.sorting,
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ describe('PackagesListApp', () => {
|
|||
|
||||
const searchPayload = {
|
||||
sort: 'VERSION_DESC',
|
||||
filters: { packageName: 'foo', packageType: 'CONAN' },
|
||||
filters: { packageName: 'foo', packageType: 'CONAN', packageVersion: '1.0.1' },
|
||||
};
|
||||
|
||||
const findPackageTitle = () => wrapper.findComponent(PackageTitle);
|
||||
|
|
@ -304,7 +304,12 @@ describe('PackagesListApp', () => {
|
|||
|
||||
await waitForFirstRequest();
|
||||
|
||||
findSearch().vm.$emit('update', searchPayload);
|
||||
findSearch().vm.$emit('update', {
|
||||
sort: 'VERSION_DESC',
|
||||
filters: {
|
||||
packageName: 'test',
|
||||
},
|
||||
});
|
||||
|
||||
return nextTick();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -41,19 +41,20 @@ describe('Packages And Registries shared utils', () => {
|
|||
});
|
||||
describe('extractFilterAndSorting', () => {
|
||||
it.each`
|
||||
search | type | sort | orderBy | result
|
||||
${['one']} | ${'myType'} | ${'asc'} | ${'foo'} | ${{ sorting: { sort: 'asc', orderBy: 'foo' }, filters: [{ type: 'type', value: { data: 'myType' } }, { type: FILTERED_SEARCH_TERM, value: { data: 'one' } }] }}
|
||||
${['one']} | ${null} | ${'asc'} | ${'foo'} | ${{ sorting: { sort: 'asc', orderBy: 'foo' }, filters: [{ type: FILTERED_SEARCH_TERM, value: { data: 'one' } }] }}
|
||||
${[]} | ${null} | ${'asc'} | ${'foo'} | ${{ sorting: { sort: 'asc', orderBy: 'foo' }, filters: [] }}
|
||||
${null} | ${null} | ${'asc'} | ${'foo'} | ${{ sorting: { sort: 'asc', orderBy: 'foo' }, filters: [] }}
|
||||
${null} | ${null} | ${null} | ${'foo'} | ${{ sorting: { orderBy: 'foo' }, filters: [] }}
|
||||
${null} | ${null} | ${null} | ${null} | ${{ sorting: {}, filters: [] }}
|
||||
search | type | version | sort | orderBy | result
|
||||
${['one']} | ${'myType'} | ${'1.0.1'} | ${'asc'} | ${'foo'} | ${{ sorting: { sort: 'asc', orderBy: 'foo' }, filters: [{ type: 'type', value: { data: 'myType' } }, { type: 'version', value: { data: '1.0.1' } }, { type: FILTERED_SEARCH_TERM, value: { data: 'one' } }] }}
|
||||
${['one']} | ${null} | ${null} | ${'asc'} | ${'foo'} | ${{ sorting: { sort: 'asc', orderBy: 'foo' }, filters: [{ type: FILTERED_SEARCH_TERM, value: { data: 'one' } }] }}
|
||||
${[]} | ${null} | ${null} | ${'asc'} | ${'foo'} | ${{ sorting: { sort: 'asc', orderBy: 'foo' }, filters: [] }}
|
||||
${null} | ${null} | ${null} | ${'asc'} | ${'foo'} | ${{ sorting: { sort: 'asc', orderBy: 'foo' }, filters: [] }}
|
||||
${null} | ${null} | ${null} | ${null} | ${'foo'} | ${{ sorting: { orderBy: 'foo' }, filters: [] }}
|
||||
${null} | ${null} | ${null} | ${null} | ${null} | ${{ sorting: {}, filters: [] }}
|
||||
`(
|
||||
'returns sorting and filters objects in the correct form',
|
||||
({ search, type, sort, orderBy, result }) => {
|
||||
({ search, type, version, sort, orderBy, result }) => {
|
||||
const queryObject = {
|
||||
search,
|
||||
type,
|
||||
version,
|
||||
sort,
|
||||
orderBy,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::SidekiqMiddleware::PauseControl::WorkersMap, feature_category: :global_search do
|
||||
let(:worker_class) do
|
||||
Class.new do
|
||||
def self.name
|
||||
'TestPauseWorker'
|
||||
end
|
||||
|
||||
include ApplicationWorker
|
||||
|
||||
pause_control :zoekt
|
||||
|
||||
def perform(*); end
|
||||
end
|
||||
end
|
||||
|
||||
before do
|
||||
stub_const('TestPauseWorker', worker_class)
|
||||
end
|
||||
|
||||
describe '.strategy_for' do
|
||||
it 'accepts classname' do
|
||||
expect(described_class.strategy_for(worker: worker_class)).to eq(:zoekt)
|
||||
end
|
||||
|
||||
it 'accepts worker instance' do
|
||||
expect(described_class.strategy_for(worker: worker_class.new)).to eq(:zoekt)
|
||||
end
|
||||
|
||||
it 'returns nil for unknown worker' do
|
||||
expect(described_class.strategy_for(worker: described_class)).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -20,7 +20,7 @@ RSpec.describe Integrations::GoogleCloudPlatform::Jwt, feature_category: :shared
|
|||
end
|
||||
|
||||
it 'creates a valid jwt' do
|
||||
payload, _ = JWT.decode(encoded, rsa_key.public_key, true, { algorithm: 'RS256' })
|
||||
payload, headers = JWT.decode(encoded, rsa_key.public_key, true, { algorithm: 'RS256' })
|
||||
|
||||
expect(payload).to include(
|
||||
'root_namespace_path' => project.root_namespace.full_path,
|
||||
|
|
@ -31,7 +31,12 @@ RSpec.describe Integrations::GoogleCloudPlatform::Jwt, feature_category: :shared
|
|||
'project_path' => project.full_path,
|
||||
'user_id' => user.id.to_s,
|
||||
'user_email' => user.email,
|
||||
'sub' => "project_#{project.id}_user_#{user.id}"
|
||||
'sub' => "project_#{project.id}_user_#{user.id}",
|
||||
'iss' => Gitlab.config.gitlab.url
|
||||
)
|
||||
|
||||
expect(headers).to include(
|
||||
'kid' => rsa_key.public_key.to_jwk[:kid]
|
||||
)
|
||||
end
|
||||
|
||||
|
|
@ -60,5 +65,22 @@ RSpec.describe Integrations::GoogleCloudPlatform::Jwt, feature_category: :shared
|
|||
expect { encoded }.to raise_error(described_class::NoSigningKeyError)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with oidc_issuer_url feature flag disabled' do
|
||||
before do
|
||||
stub_feature_flags(oidc_issuer_url: false)
|
||||
# Settings.gitlab.base_url and Gitlab.config.gitlab.url are the
|
||||
# same for test. Changing that to assert the proper behavior here.
|
||||
allow(Settings.gitlab).to receive(:base_url).and_return('test.dev')
|
||||
end
|
||||
|
||||
it 'uses a different issuer' do
|
||||
payload, _ = JWT.decode(encoded, rsa_key.public_key, true, { algorithm: 'RS256' })
|
||||
|
||||
expect(payload).to include(
|
||||
'iss' => Settings.gitlab.base_url
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ RSpec.describe Ml::ModelPresenter, feature_category: :mlops do
|
|||
let_it_be(:model2) { build_stubbed(:ml_models, :with_latest_version_and_package, project: project) }
|
||||
let_it_be(:model3) { build_stubbed(:ml_models, :with_versions, project: project) }
|
||||
|
||||
let_it_be(:model4) { build_stubbed(:ml_models, project: project) }
|
||||
|
||||
describe '#latest_version_name' do
|
||||
subject { model.present.latest_version_name }
|
||||
|
||||
|
|
@ -42,6 +44,18 @@ RSpec.describe Ml::ModelPresenter, feature_category: :mlops do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#candidate_count' do
|
||||
let(:candidates) { build_stubbed_list(:ml_candidates, 2, experiment: model4.default_experiment) }
|
||||
|
||||
before do
|
||||
allow(model4).to receive(:candidates).and_return(candidates)
|
||||
end
|
||||
|
||||
subject { model4.present.candidate_count }
|
||||
|
||||
it { is_expected.to eq(2) }
|
||||
end
|
||||
|
||||
describe '#latest_package_path' do
|
||||
subject { model.present.latest_package_path }
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue