Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2023-12-19 00:18:32 +00:00
parent 2d277754eb
commit f3b2c53677
106 changed files with 967 additions and 191 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -29,7 +29,6 @@ module SshKeysHelper
{
path: path,
method: 'delete',
qa_selector: 'revoke_ssh_key_button',
title: title,
aria_label: title,
modal_attributes: {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -8,6 +8,8 @@ value_description:
extra_properties:
identifiers:
- user
- project
- namespace
product_section: ops
product_stage: deploy
product_group: environments

View File

@ -8,6 +8,8 @@ value_description:
extra_properties:
identifiers:
- user
- project
- namespace
product_section: ops
product_stage: deploy
product_group: environments

View File

@ -8,6 +8,8 @@ value_description:
extra_properties:
identifiers:
- user
- project
- namespace
product_section: ops
product_stage: deploy
product_group: environments

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -27,6 +27,8 @@
- 1
- - abuse_spam_abuse_events
- 1
- - abuse_trust_score
- 1
- - activity_pub
- 1
- - adjourned_project_deletion

View File

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

View File

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

View File

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

View File

@ -0,0 +1 @@
29c39f7290a075ead472b5b5d41e60160073d5d49f05ae2b281e48a123990dfc

View File

@ -0,0 +1 @@
90b8a5342c57f8383b20684774ee5f7a551be4e93dcdf6d17bb2c2490fcd5214

View File

@ -0,0 +1 @@
814dc93e655e9f4abb2af348b67069f2b747300614e8251346bf252477cf3dbe

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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.
![License overview](img/license-overview.png)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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