Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2024-05-30 18:15:18 +00:00
parent c07f9b1c78
commit cd9a4ce166
119 changed files with 995 additions and 355 deletions

View File

@ -1405,6 +1405,7 @@ lib/gitlab/checks/**
# Overrides for Verify. These files below require approval from teams outside Verify.
/**/lib/**/ci/reports/**/ @gitlab-org/maintainers/rails-backend
/**/lib/**/ci/parsers/**/ @gitlab-org/maintainers/rails-backend
/**/app/views/ci/**/ @gitlab-org/maintainers/rails-backend
/ee/lib/gitlab/ci/parsers/license_compliance/ @gitlab-org/secure/composition-analysis-be
/ee/lib/gitlab/ci/parsers/security/ @gitlab-org/govern/threat-insights-backend-team
/ee/lib/gitlab/ci/reports/coverage_fuzzing/ @gitlab-org/secure/fuzzing-be

View File

@ -2267,7 +2267,6 @@ Gitlab/BoundedContexts:
- 'ee/app/experiments/issues_mrs_empty_state_experiment.rb'
- 'ee/app/experiments/project_templates_during_registration_experiment.rb'
- 'ee/app/experiments/signup_intent_step_one_experiment.rb'
- 'ee/app/experiments/trial_discover_page_experiment.rb'
- 'ee/app/finders/app_sec/fuzzing/coverage/corpuses_finder.rb'
- 'ee/app/finders/approval_rules/group_finder.rb'
- 'ee/app/finders/audit_event_finder.rb'

View File

@ -180,19 +180,7 @@ Layout/ArgumentAlignment:
- 'lib/api/entities/pull_mirror.rb'
- 'lib/api/entities/release.rb'
- 'lib/api/entities/resource_access_token.rb'
- 'lib/gitlab/ci/yaml_processor/result.rb'
- 'lib/gitlab/config/entry/node.rb'
- 'lib/gitlab/config_checker/external_database_checker.rb'
- 'lib/gitlab/conflict/file.rb'
- 'lib/gitlab/cross_project_access.rb'
- 'lib/gitlab/data_builder/push.rb'
- 'lib/gitlab/database/consistency_checker.rb'
- 'lib/gitlab/database/count/reltuples_count_strategy.rb'
- 'lib/gitlab/database/load_balancing/configuration.rb'
- 'lib/gitlab/database/load_balancing/service_discovery.rb'
- 'lib/gitlab/database/migration_helpers.rb'
- 'lib/gitlab/database/migrations/base_background_runner.rb'
- 'lib/gitlab/database/partitioning/detached_partition_dropper.rb'
- 'lib/gitlab/database/partitioning/partition_manager.rb'
- 'lib/gitlab/database/partitioning/replace_table.rb'
- 'lib/gitlab/database/partitioning_migration_helpers/table_management_helpers.rb'

View File

@ -1 +1 @@
5449172da31e92e636d7a04bf460e359bc44aa1b
42a2e519ca55a42f8cf420012b1f14af0830be59

View File

@ -91,7 +91,7 @@ export default {
<template>
<div
class="gl-display-flex gl-justify-content-end -gl-my-2 gl-mx-n2"
class="gl-display-flex gl-justify-content-end -gl-my-2 -gl-mx-2"
:data-testid="`user-actions-${user.id}`"
>
<div v-if="hasEditAction" class="gl-p-2" :class="{ 'gl-mr-3': hasEditActionOnly }">

View File

@ -122,7 +122,7 @@ export default {
</li>
</ul>
</gl-card>
<div class="-gl-my-2 gl-mx-n2 gl-display-flex gl-flex-wrap">
<div class="-gl-my-2 -gl-mx-2 gl-display-flex gl-flex-wrap">
<div class="gl-p-2">
<clipboard-button
:title="$options.i18n.copyButton"

View File

@ -68,7 +68,7 @@ export default {
<template>
<div>
<div class="gl-text-truncate gl-p-3 -gl-mt-3 gl-mx-n3 -gl-mb-2">
<div class="gl-text-truncate gl-p-3 -gl-mt-3 -gl-mx-3 -gl-mb-2">
<gl-icon
v-if="jobStuck"
v-gl-tooltip="$options.i18n.stuckText"

View File

@ -40,7 +40,7 @@ export default {
<template>
<div>
<div class="gl-p-3 -gl-mt-3 gl-mx-n3">
<div class="gl-p-3 -gl-mt-3 -gl-mx-3">
<gl-link class="gl-text-truncate" :href="pipelinePath" data-testid="pipeline-id">
{{ pipelineId }}
</gl-link>

View File

@ -1,5 +1,5 @@
<script>
import { GlBadge, GlTooltipDirective } from '@gitlab/ui';
import { GlBadge, GlSprintf, GlLink, GlTooltipDirective } from '@gitlab/ui';
import {
DETACHED_EVENT_TYPE,
AUTO_DEVOPS_SOURCE,
@ -12,6 +12,8 @@ export default {
name: 'HeaderBadges',
components: {
GlBadge,
GlSprintf,
GlLink,
},
directives: {
GlTooltip: GlTooltipDirective,
@ -47,6 +49,9 @@ export default {
yamlErrorMessages() {
return this.pipeline?.yamlErrorMessages || '';
},
triggeredByPath() {
return this.pipeline?.triggeredByPath;
},
badges() {
return {
schedule: this.isScheduledPipeline,

View File

@ -217,9 +217,6 @@ export default {
refText() {
return this.pipeline?.refText;
},
triggeredByPath() {
return this.pipeline?.triggeredByPath;
},
},
methods: {
reportFailure(errorType, errorMessages = []) {

View File

@ -85,14 +85,14 @@ export default {
:visible="visible"
@hidden="$emit('hidden')"
>
<div class="gl-display-flex gl-flex-wrap gl-mx-n4 gl-my-3">
<div class="gl-display-flex gl-flex-wrap -gl-mx-4 gl-my-3">
<strong class="col-sm-3">{{ $options.text.name }}</strong>
<div class="col-sm-9" data-testid="test-case-name">
{{ testCase.name }}
</div>
</div>
<div v-if="testCase.file" class="gl-display-flex gl-flex-wrap gl-mx-n4 gl-my-3">
<div v-if="testCase.file" class="gl-display-flex gl-flex-wrap -gl-mx-4 gl-my-3">
<strong class="col-sm-3">{{ $options.text.file }}</strong>
<div class="col-sm-9" data-testid="test-case-file">
<gl-link v-if="testCase.filePath" :href="testCase.filePath">
@ -109,7 +109,7 @@ export default {
</div>
</div>
<div class="gl-display-flex gl-flex-wrap gl-mx-n4 gl-my-3">
<div class="gl-display-flex gl-flex-wrap -gl-mx-4 gl-my-3">
<strong class="col-sm-3">{{ $options.text.duration }}</strong>
<div v-if="testCase.formattedTime" class="col-sm-9" data-testid="test-case-duration">
{{ testCase.formattedTime }}
@ -119,14 +119,14 @@ export default {
</div>
</div>
<div v-if="testCase.recent_failures" class="gl-display-flex gl-flex-wrap gl-mx-n4 gl-my-3">
<div v-if="testCase.recent_failures" class="gl-display-flex gl-flex-wrap -gl-mx-4 gl-my-3">
<strong class="col-sm-3">{{ $options.text.history }}</strong>
<div class="col-sm-9" data-testid="test-case-recent-failures">
<gl-badge variant="warning">{{ failureHistoryMessage }}</gl-badge>
</div>
</div>
<div v-if="testCase.attachment_url" class="gl-display-flex gl-flex-wrap gl-mx-n4 gl-my-3">
<div v-if="testCase.attachment_url" class="gl-display-flex gl-flex-wrap -gl-mx-4 gl-my-3">
<strong class="col-sm-3">{{ $options.text.attachment }}</strong>
<gl-link
class="col-sm-9"
@ -140,7 +140,7 @@ export default {
<div
v-if="testCase.system_output"
class="gl-display-flex gl-flex-wrap gl-mx-n4 gl-my-3"
class="gl-display-flex gl-flex-wrap -gl-mx-4 gl-my-3"
data-testid="test-case-trace"
>
<strong class="col-sm-3 gl-mb-2">{{ $options.text.trace }}</strong>

View File

@ -3,3 +3,21 @@ export const getModifierKey = (removeSuffix = false) => {
const winKey = `Ctrl${removeSuffix ? '' : '+'}`;
return window.gl?.client?.isMac ? '⌘' : winKey;
};
// The following default values are for frontend unit tests
const DEFAULT_FORUM_URL = 'https://forum.gitlab.com';
// eslint-disable-next-line no-restricted-syntax
const DEFAULT_DOCS_URL = 'https://docs.gitlab.com';
// eslint-disable-next-line no-restricted-syntax
const DEFAULT_PROMO_URL = 'https://about.gitlab.com';
const {
forum_url: FORUM_URL = DEFAULT_FORUM_URL,
docs_url: DOCS_URL = DEFAULT_DOCS_URL,
promo_url: PROMO_URL = DEFAULT_PROMO_URL,
} = window.gon;
// eslint-disable-next-line no-restricted-syntax
export const DOCS_URL_IN_EE_DIR = `${DOCS_URL}/ee`;
export { FORUM_URL, DOCS_URL, PROMO_URL };

View File

@ -158,7 +158,7 @@ export default {
<template>
<form class="feature-flags-form">
<fieldset>
<div class="gl-display-flex gl-flex-wrap gl-mx-n5">
<div class="gl-display-flex gl-flex-wrap -gl-mx-5">
<div class="gl-mb-5 gl-px-5 gl-w-full md:gl-basis-1/3">
<label for="feature-flag-name" class="gl-font-weight-bold"
>{{ s__('FeatureFlags|Name') }} *</label
@ -167,7 +167,7 @@ export default {
</div>
</div>
<div class="gl-display-flex gl-flex-wrap gl-mx-n5">
<div class="gl-display-flex gl-flex-wrap -gl-mx-5">
<div class="gl-mb-5 gl-px-5 gl-w-full md:gl-basis-1/3">
<label for="feature-flag-description" class="gl-font-weight-bold">
{{ s__('FeatureFlags|Description') }}
@ -188,7 +188,7 @@ export default {
:show-categorized-issues="false"
/>
<div class="gl-display-flex gl-flex-wrap gl-mx-n5">
<div class="gl-display-flex gl-flex-wrap -gl-mx-5">
<div class="gl-mb-5 gl-px-5 gl-w-full">
<h4>{{ s__('FeatureFlags|Strategies') }}</h4>
<div class="gl-display-flex gl-align-items-baseline gl-justify-content-space-between">

View File

@ -53,7 +53,7 @@ export default {
<template>
<div v-if="canCreateSubgroups || canCreateProjects" class="gl-mt-5">
<div class="gl-display-flex gl-mx-n3 -gl-my-3 gl-flex-wrap">
<div class="gl-display-flex -gl-mx-3 -gl-my-3 gl-flex-wrap">
<div v-if="canCreateSubgroups" class="gl-p-3 gl-w-full gl-sm-w-half">
<gl-link :href="newSubgroupPath" :class="$options.linkClasses">
<div class="svg-content gl-w-15 gl-flex-shrink-0 gl-mr-5">

View File

@ -227,7 +227,7 @@ export default {
</gl-tab>
<template #tabs-end>
<li class="gl-flex-grow-1 gl-align-self-center gl-w-full gl-lg-w-auto gl-py-2">
<div class="gl-lg-display-flex gl-justify-content-end gl-mx-n2 -gl-my-2">
<div class="gl-lg-display-flex gl-justify-content-end -gl-mx-2 -gl-my-2">
<div class="gl-p-2 gl-lg-form-input-md gl-w-full">
<gl-search-box-by-type
:value="search"

View File

@ -120,7 +120,7 @@ export default {
:is-merge-request="true"
:pipeline-status="mr.head_pipeline && mr.head_pipeline.detailed_status"
path-id-separator="!"
class="gl-mx-n2"
class="-gl-mx-2"
/>
</li>
</ul>

View File

@ -31,7 +31,7 @@ export default {
</script>
<template>
<div class="gl-display-flex gl-flex-wrap gl-sm-flex-nowrap gl-mx-n3">
<div class="gl-display-flex gl-flex-wrap gl-sm-flex-nowrap -gl-mx-3">
<gl-single-stat
v-for="(stat, index) in stats"
:key="index"

View File

@ -5,7 +5,7 @@ export default {
</script>
<template>
<div class="gl-display-flex gl-align-items-center gl-justify-content-end gl-mx-n1">
<div class="gl-display-flex gl-align-items-center gl-justify-content-end -gl-mx-1">
<slot></slot>
</div>
</template>

View File

@ -3,7 +3,7 @@ import { GlTabs, GlTab, GlBadge, GlButton } from '@gitlab/ui';
// eslint-disable-next-line no-restricted-imports
import { mapState } from 'vuex';
import { queryToObject } from '~/lib/utils/url_utility';
import { MEMBER_TYPES, ACTIVE_TAB_QUERY_PARAM_NAME } from 'ee_else_ce/members/constants';
import { MEMBERS_TAB_TYPES, ACTIVE_TAB_QUERY_PARAM_NAME } from 'ee_else_ce/members/constants';
import { TABS } from 'ee_else_ce/members/tabs_metadata';
import MembersApp from './app.vue';
@ -22,7 +22,7 @@ export default {
},
computed: {
...mapState(
Object.values(MEMBER_TYPES).reduce((getters, memberType) => {
Object.values(MEMBERS_TAB_TYPES).reduce((getters, memberType) => {
return {
...getters,
// eslint-disable-next-line @gitlab/require-i18n-strings
@ -68,7 +68,7 @@ export default {
return this[`${namespace}Count`];
},
showTab(tab, index) {
if (tab.namespace === MEMBER_TYPES.user) {
if (tab.namespace === MEMBERS_TAB_TYPES.user) {
return true;
}

View File

@ -1,5 +1,5 @@
<script>
import { MEMBER_TYPES, EE_ACTION_BUTTONS } from 'ee_else_ce/members/constants';
import { MEMBERS_TAB_TYPES, ACTION_BUTTONS } from 'ee_else_ce/members/constants';
import AccessRequestActionButtons from '../action_buttons/access_request_action_buttons.vue';
import GroupActionButtons from '../action_buttons/group_action_buttons.vue';
import InviteActionButtons from '../action_buttons/invite_action_buttons.vue';
@ -36,11 +36,11 @@ export default {
computed: {
actionButtonComponent() {
const dictionary = {
[MEMBER_TYPES.user]: 'user-action-dropdown',
[MEMBER_TYPES.group]: 'group-action-buttons',
[MEMBER_TYPES.invite]: 'invite-action-buttons',
[MEMBER_TYPES.accessRequest]: 'access-request-action-buttons',
...EE_ACTION_BUTTONS,
[MEMBERS_TAB_TYPES.user]: 'user-action-dropdown',
[MEMBERS_TAB_TYPES.group]: 'group-action-buttons',
[MEMBERS_TAB_TYPES.invite]: 'invite-action-buttons',
[MEMBERS_TAB_TYPES.accessRequest]: 'access-request-action-buttons',
...ACTION_BUTTONS,
};
return dictionary[this.memberType];

View File

@ -1,5 +1,5 @@
<script>
import { MEMBER_TYPES } from 'ee_else_ce/members/constants';
import { MEMBERS_TAB_TYPES } from 'ee_else_ce/members/constants';
import {
isGroup,
isDirectMember,
@ -31,16 +31,16 @@ export default {
},
memberType() {
if (this.isGroup) {
return MEMBER_TYPES.group;
return MEMBERS_TAB_TYPES.group;
}
if (this.isInvite) {
return MEMBER_TYPES.invite;
return MEMBERS_TAB_TYPES.invite;
}
if (this.isAccessRequest) {
return MEMBER_TYPES.accessRequest;
return MEMBERS_TAB_TYPES.accessRequest;
}
return MEMBER_TYPES.user;
return MEMBERS_TAB_TYPES.user;
},
isDirectMember() {
return isDirectMember(this.member);

View File

@ -4,10 +4,10 @@ import { __, s__ } from '~/locale';
import { OPERATORS_IS } from '~/vue_shared/components/filtered_search_bar/constants';
// Overridden in EE
export const EE_GROUPS_APP_OPTIONS = {};
export const EE_PROJECTS_APP_OPTIONS = {};
export const GROUPS_APP_OPTIONS = {};
export const PROJECTS_APP_OPTIONS = {};
export const EE_ACTION_BUTTONS = {};
export const ACTION_BUTTONS = {};
export const FIELD_KEY_ACCOUNT = 'account';
export const FIELD_KEY_SOURCE = 'source';
@ -161,7 +161,7 @@ export const AVAILABLE_FILTERED_SEARCH_TOKENS = [
export const AVATAR_SIZE = 48;
export const MEMBER_TYPES = Object.freeze({
export const MEMBERS_TAB_TYPES = Object.freeze({
user: 'user',
group: 'group',
invite: 'invite',

View File

@ -1,33 +1,33 @@
import { __, s__ } from '~/locale';
import PlaceholdersTabApp from './components/placeholders/app.vue';
import { MEMBER_TYPES, TAB_QUERY_PARAM_VALUES } from './constants';
import { MEMBERS_TAB_TYPES, TAB_QUERY_PARAM_VALUES } from './constants';
// Overridden in EE
export const TABS = [
{
namespace: MEMBER_TYPES.user,
namespace: MEMBERS_TAB_TYPES.user,
title: __('Members'),
},
{
namespace: MEMBER_TYPES.group,
namespace: MEMBERS_TAB_TYPES.group,
title: __('Groups'),
attrs: { 'data-testid': 'groups-list-tab' },
queryParamValue: TAB_QUERY_PARAM_VALUES.group,
},
{
namespace: MEMBER_TYPES.invite,
namespace: MEMBERS_TAB_TYPES.invite,
title: s__('Members|Pending invitations'),
requiredPermissions: ['canManageMembers'],
queryParamValue: TAB_QUERY_PARAM_VALUES.invite,
},
{
namespace: MEMBER_TYPES.accessRequest,
namespace: MEMBERS_TAB_TYPES.accessRequest,
title: __('Access requests'),
requiredPermissions: ['canManageAccessRequests'],
queryParamValue: TAB_QUERY_PARAM_VALUES.accessRequest,
},
{
namespace: MEMBER_TYPES.placeholder,
namespace: MEMBERS_TAB_TYPES.placeholder,
title: s__('UserMapping|Placeholders'),
queryParamValue: TAB_QUERY_PARAM_VALUES.placeholder,
component: PlaceholdersTabApp,

View File

@ -1,5 +1,14 @@
<script>
import { GlAlert, GlButton, GlFormGroup, GlForm, GlFormInput, GlFormSelect } from '@gitlab/ui';
import {
GlAlert,
GlButton,
GlFormGroup,
GlForm,
GlFormInput,
GlFormSelect,
GlSprintf,
} from '@gitlab/ui';
import HelpPageLink from '~/vue_shared/components/help_page_link/help_page_link.vue';
import createPackagesProtectionRuleMutation from '~/packages_and_registries/settings/project/graphql/mutations/create_packages_protection_rule.mutation.graphql';
import { s__, __ } from '~/locale';
@ -20,11 +29,16 @@ export default {
GlFormGroup,
GlAlert,
GlForm,
GlSprintf,
HelpPageLink,
},
inject: ['projectPath'],
i18n: {
PACKAGES_PROTECTION_RULES_SAVED_SUCCESS_MESSAGE,
PACKAGES_PROTECTION_RULES_SAVED_ERROR_MESSAGE,
packageNamePatternInputHelpText: s__(
'PackageRegistry|%{linkStart}Wildcards%{linkEnd} such as `@my-scope/my-package-*` are supported.',
),
},
data() {
return {
@ -132,6 +146,17 @@ export default {
required
:disabled="isFieldDisabled"
/>
<template #description>
<gl-sprintf :message="$options.i18n.packageNamePatternInputHelpText">
<template #link="{ content }">
<help-page-link
href="user/packages/package_registry/package_protection_rules.md"
target="_blank"
>{{ content }}</help-page-link
>
</template>
</gl-sprintf>
</template>
</gl-form-group>
<gl-form-group

View File

@ -3,12 +3,12 @@ import initInviteGroupTrigger from '~/invite_members/init_invite_group_trigger';
import initInviteGroupsModal from '~/invite_members/init_invite_groups_modal';
import { s__ } from '~/locale';
import { initMembersApp } from '~/members';
import { EE_GROUPS_APP_OPTIONS, MEMBER_TYPES } from 'ee_else_ce/members/constants';
import { GROUPS_APP_OPTIONS, MEMBERS_TAB_TYPES } from 'ee_else_ce/members/constants';
import { groupLinkRequestFormatter } from '~/members/utils';
const SHARED_FIELDS = ['account', 'maxRole', 'expiration', 'actions'];
const APP_OPTIONS = {
[MEMBER_TYPES.user]: {
[MEMBERS_TAB_TYPES.user]: {
tableFields: SHARED_FIELDS.concat(['source', 'activity']),
tableSortableFields: [
'account',
@ -27,7 +27,7 @@ const APP_OPTIONS = {
recentSearchesStorageKey: 'group_members',
},
},
[MEMBER_TYPES.group]: {
[MEMBERS_TAB_TYPES.group]: {
tableFields: SHARED_FIELDS.concat(['source', 'granted']),
requestFormatter: groupLinkRequestFormatter,
filteredSearchBar: {
@ -38,7 +38,7 @@ const APP_OPTIONS = {
recentSearchesStorageKey: 'group_links_members',
},
},
[MEMBER_TYPES.invite]: {
[MEMBERS_TAB_TYPES.invite]: {
tableFields: SHARED_FIELDS.concat('invited'),
requestFormatter: groupMemberRequestFormatter,
filteredSearchBar: {
@ -49,11 +49,11 @@ const APP_OPTIONS = {
recentSearchesStorageKey: 'group_invited_members',
},
},
[MEMBER_TYPES.accessRequest]: {
[MEMBERS_TAB_TYPES.accessRequest]: {
tableFields: SHARED_FIELDS.concat('requested'),
requestFormatter: groupMemberRequestFormatter,
},
...EE_GROUPS_APP_OPTIONS,
...GROUPS_APP_OPTIONS,
};
initMembersApp(document.querySelector('.js-group-members-list-app'), APP_OPTIONS);

View File

@ -1,4 +1,4 @@
import { EE_PROJECTS_APP_OPTIONS, MEMBER_TYPES } from 'ee_else_ce/members/constants';
import { PROJECTS_APP_OPTIONS, MEMBERS_TAB_TYPES } from 'ee_else_ce/members/constants';
import initImportProjectMembersTrigger from '~/invite_members/init_import_project_members_trigger';
import initImportProjectMembersModal from '~/invite_members/init_import_project_members_modal';
import initInviteGroupTrigger from '~/invite_members/init_invite_group_trigger';
@ -15,7 +15,7 @@ initImportProjectMembersTrigger();
const SHARED_FIELDS = ['account', 'maxRole', 'expiration', 'actions'];
initMembersApp(document.querySelector('.js-project-members-list-app'), {
[MEMBER_TYPES.user]: {
[MEMBERS_TAB_TYPES.user]: {
tableFields: SHARED_FIELDS.concat(['source', 'activity']),
tableSortableFields: [
'account',
@ -34,7 +34,7 @@ initMembersApp(document.querySelector('.js-project-members-list-app'), {
recentSearchesStorageKey: 'project_members',
},
},
[MEMBER_TYPES.group]: {
[MEMBERS_TAB_TYPES.group]: {
tableFields: SHARED_FIELDS.concat(['source', 'granted']),
requestFormatter: groupLinkRequestFormatter,
filteredSearchBar: {
@ -45,13 +45,13 @@ initMembersApp(document.querySelector('.js-project-members-list-app'), {
recentSearchesStorageKey: 'project_group_links',
},
},
[MEMBER_TYPES.invite]: {
[MEMBERS_TAB_TYPES.invite]: {
tableFields: SHARED_FIELDS.concat('invited'),
requestFormatter: projectMemberRequestFormatter,
},
[MEMBER_TYPES.accessRequest]: {
[MEMBERS_TAB_TYPES.accessRequest]: {
tableFields: SHARED_FIELDS.concat('requested'),
requestFormatter: projectMemberRequestFormatter,
},
...EE_PROJECTS_APP_OPTIONS,
...PROJECTS_APP_OPTIONS,
});

View File

@ -87,7 +87,7 @@ export default {
:title="emptyStateTitle"
/>
<div v-else>
<div class="-gl-my-3 gl-mx-n3 gl-display-flex gl-flex-wrap">
<div class="-gl-my-3 -gl-mx-3 gl-display-flex gl-flex-wrap">
<div v-for="user in users" :key="user.id" class="gl-p-3 gl-w-full gl-md-w-half gl-lg-w-25p">
<gl-avatar-link
:href="user.web_url"

View File

@ -199,7 +199,7 @@ export default {
<gl-alert
v-if="alertMessage"
variant="warning"
class="-gl-mt-5 gl-mb-4 gl-mx-n5"
class="-gl-mt-5 gl-mb-4 -gl-mx-5"
@dismiss="dismissAlert"
>
{{ alertMessage }}

View File

@ -147,7 +147,7 @@ export default {
:work-item-type="issue.type"
event-namespace="relatedIssue"
data-testid="related-issuable-content"
class="gl-mx-n2"
class="-gl-mx-2"
@relatedIssueRemoveRequest="$emit('relatedIssueRemoveRequest', $event)"
/>
</li>

View File

@ -126,7 +126,7 @@ export default {
<template>
<div
:id="`${targetId}-flyout`"
class="gl-fixed gl-p-4 gl-mx-n1 gl-z-9999 gl-max-h-full gl-overflow-y-auto"
class="gl-fixed gl-p-4 -gl-mx-1 gl-z-9999 gl-max-h-full gl-overflow-y-auto"
@mouseover="$emit('mouseover')"
@mouseleave="$emit('mouseleave')"
>

View File

@ -60,7 +60,7 @@ export default {
</div>
</div>
<div class="gl-mt-5">
<div class="gl-display-flex gl-align-items-center gl-flex-wrap -gl-my-3 gl-mx-n3">
<div class="gl-display-flex gl-align-items-center gl-flex-wrap -gl-my-3 -gl-mx-3">
<div
v-for="{ id, label, backgroundColor, formattedValue } in computedSections"
:key="id"

View File

@ -158,7 +158,7 @@ export default {
>
<a
v-if="showBlameLink"
class="gl-select-none !gl-shadow-none file-line-blame gl-mx-n2"
class="gl-select-none !gl-shadow-none file-line-blame -gl-mx-2"
:href="`${blamePath}#L${line}`"
></a>
<a

View File

@ -155,7 +155,7 @@ export default {
>
<template #meta>
<div class="gl-px-2">
<div class="gl-mx-n2 gl-display-flex gl-align-items-center gl-flex-wrap">
<div class="-gl-mx-2 gl-display-flex gl-align-items-center gl-flex-wrap">
<div class="gl-px-2">
<gl-icon
v-if="visibility"

View File

@ -268,7 +268,7 @@ export default {
>
<template #meta>
<div class="gl-px-2">
<div class="gl-mx-n2 gl-display-flex gl-align-items-center gl-flex-wrap">
<div class="-gl-mx-2 gl-display-flex gl-align-items-center gl-flex-wrap">
<div class="gl-px-2">
<gl-icon
v-if="visibility"
@ -306,7 +306,7 @@ export default {
</gl-truncate-text>
<div v-if="hasTopics" class="gl-mt-3" data-testid="project-topics">
<div
class="gl-w-full gl-display-inline-flex gl-flex-wrap gl-font-base gl-font-weight-normal gl-align-items-center gl-mx-n2 -gl-my-2"
class="gl-w-full gl-display-inline-flex gl-flex-wrap gl-font-base gl-font-weight-normal gl-align-items-center -gl-mx-2 -gl-my-2"
>
<span class="gl-p-2 gl-font-sm gl-text-secondary">{{ $options.i18n.topics }}:</span>
<div v-for="topic in visibleTopics" :key="topic" class="gl-p-2">
@ -330,7 +330,7 @@ export default {
</gl-sprintf>
</div>
<gl-popover :target="topicsPopoverTarget" :title="$options.i18n.moreTopics">
<div class="gl-font-base gl-font-weight-normal gl-mx-n2 -gl-my-2">
<div class="gl-font-base gl-font-weight-normal -gl-mx-2 -gl-my-2">
<div
v-for="topic in popoverTopics"
:key="topic"

View File

@ -38,7 +38,7 @@ export default {
class="gl-p-0! gl-absolute gl-z-3 diff-line-num gl-border-r gl-display-flex line-links line-numbers"
>
<a
class="gl-select-none !gl-shadow-none file-line-blame gl-mx-n2 gl-flex-grow-1"
class="gl-select-none !gl-shadow-none file-line-blame -gl-mx-2 gl-flex-grow-1"
:href="`${blamePath}${pageSearchString}#L${number}`"
></a>
<a

View File

@ -243,10 +243,14 @@ module ApplicationHelper
ApplicationHelper.community_forum
end
def promo_url
def self.promo_url
"https://#{promo_host}"
end
def promo_url
ApplicationHelper.promo_url
end
def support_url
Gitlab::CurrentSettings.current_application_settings.help_page_support_url.presence || "#{promo_url}/get-help/"
end

View File

@ -335,7 +335,7 @@ module EventsHelper
end
def user_profile_activity_classes
current_path?('users#activity') ? ' gl-font-weight-semibold gl-text-black-normal' : ''
current_path?('users#activity') ? ' gl-font-semibold gl-text-black-normal' : ''
end
private

View File

@ -1,10 +1,10 @@
# frozen_string_literal: true
module ListboxHelper
DROPDOWN_CONTAINER_CLASSES = %w[dropdown b-dropdown gl-dropdown js-redirect-listbox].freeze
DROPDOWN_BUTTON_CLASSES = %w[btn dropdown-toggle btn-default btn-md gl-button gl-dropdown-toggle].freeze
DROPDOWN_INNER_CLASS = 'gl-dropdown-button-text'
DROPDOWN_ICON_CLASS = 'gl-button-icon dropdown-chevron gl-icon'
DROPDOWN_CONTAINER_CLASSES = %w[gl-new-dropdown js-redirect-listbox].freeze
DROPDOWN_BUTTON_CLASSES = 'gl-new-dropdown-toggle'
DROPDOWN_INNER_CLASS = 'gl-new-dropdown-button-text'
DROPDOWN_ICON_CLASS = 'gl-button-icon gl-new-dropdown-chevron gl-icon'
# Creates a listbox component with redirect behavior.
#
@ -46,7 +46,8 @@ module ListboxHelper
selected = selected_option[:value]
end
button = button_tag(type: :button, class: DROPDOWN_BUTTON_CLASSES) do
button = render Pajamas::ButtonComponent.new(variant: :default,
button_options: { class: DROPDOWN_BUTTON_CLASSES }) do
content_tag(:span, selected_option[:text], class: DROPDOWN_INNER_CLASS) +
sprite_icon('chevron-down', css_class: DROPDOWN_ICON_CLASS)
end

View File

@ -300,7 +300,7 @@ module MergeRequestsHelper
end
def merge_request_header(project, merge_request)
link_to_author = link_to_member(project, merge_request.author, size: 24, extra_class: 'gl-font-weight-bold gl-mr-2', avatar: false)
link_to_author = link_to_member(project, merge_request.author, size: 24, extra_class: 'gl-font-bold gl-mr-2', avatar: false)
copy_action_description = _('Copy branch name')
copy_action_shortcut = 'b'
copy_button_title = "#{copy_action_description} <kbd class='flat ml-1' aria-hidden=true>#{copy_action_shortcut}</kbd>"

View File

@ -19,7 +19,7 @@
= render_if_exists 'admin/users/auditor_user_badge'
= render_if_exists 'admin/users/gma_user_badge'
.gl-my-3.gl-display-flex.gl-flex-wrap.-gl-my-2.gl-mx-n2
.gl-my-3.gl-display-flex.gl-flex-wrap.-gl-my-2.-gl-mx-2
- if @user != current_user
- if impersonation_enabled?
.gl-p-2

View File

@ -42,7 +42,7 @@
.todos-filters
.issues-details-filters.row-content-block.second-block
= form_tag todos_filter_path(without: [:project_id, :author_id, :type, :action_id]), method: :get, class: 'filter-form gl-display-flex gl-flex-direction-column gl-sm-flex-direction-row' do
.filter-categories.gl-display-flex.gl-flex-direction-column.gl-md-flex-direction-row.gl-flex-grow-1.gl-flex-wrap.gl-mx-n2
.filter-categories.gl-display-flex.gl-flex-direction-column.gl-md-flex-direction-row.gl-flex-grow-1.gl-flex-wrap.-gl-mx-2
.filter-item.gl-m-2
- if params[:group_id].present?
= hidden_field_tag(:group_id, params[:group_id])

View File

@ -1,5 +1,5 @@
.gl-text-center.gl-pt-5
%label.gl-font-weight-normal
%label.gl-font-normal
= _("Register with:")
.gl-display-flex.gl-flex-direction-column.gl-gap-3
- providers.each do |provider|

View File

@ -1,2 +1,2 @@
= gl_tabs_nav({ class: 'gl-mx-n5 gl-my-5 nav-justified' }) do
= gl_tabs_nav({ class: '-gl-mx-5 gl-my-5 nav-justified' }) do
= gl_tab_link_to tab_title, '#', { item_active: true, class: 'gl-cursor-default!', tabindex: '-1', data: { testid: 'sign-in-tab' } }

View File

@ -1,6 +1,6 @@
- render_standard_signin = admin_mode ? allow_admin_mode_password_authentication_for_web? : password_authentication_enabled_for_web?
= gl_tabs_nav({ class: 'gl-mx-n5 gl-my-5 nav-justified', id: 'js-signin-tabs' }) do
= gl_tabs_nav({ class: '-gl-mx-5 gl-my-5 nav-justified', id: 'js-signin-tabs' }) do
- if crowd_enabled?
= gl_tab_link_to _('Crowd'), '#crowd', { item_active: form_based_auth_provider_has_active_class?(:crowd), data: { toggle: 'tab' } }

View File

@ -23,7 +23,7 @@
.gl-mb-5
= render Pajamas::CardComponent.new do |c|
- c.with_body do
%p.gl-mt-0.gl-mb-3.gl-font-weight-bold
%p.gl-mt-0.gl-mb-3.gl-font-bold
= _("Can't scan the code?")
%p.gl-mt-0.gl-mb-3
= _("To add the entry manually, provide the following details to the application on your phone.")

View File

@ -14,7 +14,7 @@
%ul.related-merge-requests.content-list
- @related_branches.each do |branch|
%li.list-item{ class: "gl-py-0! gl-border-0!" }
.item-body.gl-display-flex.gl-align-items-center.gl-px-3.gl-pr-2.gl-mx-n2
.item-body.gl-display-flex.gl-align-items-center.gl-px-3.gl-pr-2.-gl-mx-2
.item-contents.gl-display-flex.gl-align-items-center.gl-flex-wrap.gl-flex-grow-1.gl-min-h-7
.item-title.gl-display-flex.mb-xl-0.gl-min-w-0.gl-align-items-center
- if branch[:pipeline_status].present?

View File

@ -1,7 +1,7 @@
- max_project_topic_length = 15
- if project.topics.present?
.gl-w-full.gl-display-inline-flex.gl-flex-wrap.gl-font-base.gl-font-weight-normal.gl-align-items-center.gl-mx-n2.-gl-my-2{ 'data-testid': 'project_topic_list' }
.gl-w-full.gl-display-inline-flex.gl-flex-wrap.gl-font-base.gl-font-weight-normal.gl-align-items-center.-gl-mx-2.-gl-my-2{ 'data-testid': 'project_topic_list' }
- project.topics_to_show.each do |topic|
- explore_project_topic_path = topic_explore_projects_cleaned_path(topic_name: topic[:name])
- if topic[:title].length > max_project_topic_length

View File

@ -77,6 +77,7 @@ en:
email: Allows read-only access to the user's primary email address using OpenID Connect
admin_mode: Admin Mode is a functionality designed to limit the access level of administrator's personal access tokens.
create_runner: Grants create access to the runners
manage_runner: Grants access to manage the runners
k8s_proxy: Grants permission to perform Kubernetes API calls using the agent for Kubernetes.
ai_features: Access to API endpoints needed for GitLab Duo features
read_service_ping: Grant access to download Service Ping payload via API when authenticated as an admin user
@ -113,6 +114,8 @@ en:
Grants permission to perform API actions as an administrator, when Admin Mode is enabled.
create_runner:
Grants create access to the runners.
manage_runner:
Grants access to manage the runners.
k8s_proxy:
Grants permission to perform Kubernetes API calls using the agent for Kubernetes.
read_service_ping:
@ -150,6 +153,8 @@ en:
Grants permission to perform API actions as an administrator, when Admin Mode is enabled.
create_runner:
Grants permission to create runners in a group.
manage_runner:
Grants access to manage the runners in a group.
k8s_proxy:
Grants permission to perform Kubernetes API calls using the agent for Kubernetes in a group.
project_access_token_scope_desc:
@ -171,6 +176,8 @@ en:
Grants write access to GitLab Observability.
create_runner:
Grants create access to the runners.
manage_runner:
Grants access to manage the runners.
k8s_proxy:
Grants permission to perform Kubernetes API calls using the agent for Kubernetes.
ai_features:

View File

@ -11,5 +11,7 @@ description: a temporary table to store the orphaned notes records that have bee
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/146023
milestone: "16.10"
gitlab_schema: gitlab_main_cell
removed_in_milestone: "17.1"
removed_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/154317
sharding_key:
project_id: projects

View File

@ -0,0 +1,9 @@
# frozen_string_literal: true
class AddAllSeatsUsedNotificationAtColumnToNamespaceLimit < Gitlab::Database::Migration[2.2]
milestone '17.1'
def change
add_column :namespace_limits, :last_seat_all_used_seats_notification_at, :datetime_with_timezone
end
end

View File

@ -0,0 +1,16 @@
# frozen_string_literal: true
class DropTempNotesBackupTable < Gitlab::Database::Migration[2.2]
milestone '17.1'
TABLE_NAME = :temp_notes_backup
def up
drop_table TABLE_NAME
end
def down
execute "CREATE TABLE IF NOT EXISTS #{TABLE_NAME} (LIKE notes);"
execute "ALTER TABLE #{TABLE_NAME} ADD PRIMARY KEY (id);"
end
end

View File

@ -0,0 +1 @@
7e59489752226c7f2832be54db5887db50519d894f308a4d405a904cfc5aed52

View File

@ -0,0 +1 @@
77bc16c84599f4ec935eacc20cc1e4b58dc0f9b78c2c9f2d8b093e381ab06818

View File

@ -12240,7 +12240,8 @@ CREATE TABLE namespace_limits (
temporary_storage_increase_ends_on date,
pre_enforcement_notification_at timestamp with time zone,
first_enforced_at timestamp with time zone,
last_enforced_at timestamp with time zone
last_enforced_at timestamp with time zone,
last_seat_all_used_seats_notification_at timestamp with time zone
);
CREATE TABLE namespace_package_settings (
@ -17040,40 +17041,6 @@ CREATE SEQUENCE target_branch_rules_id_seq
ALTER SEQUENCE target_branch_rules_id_seq OWNED BY target_branch_rules.id;
CREATE TABLE temp_notes_backup (
note text,
noteable_type character varying,
author_id integer,
created_at timestamp without time zone,
updated_at timestamp without time zone,
project_id integer,
attachment character varying,
line_code character varying,
commit_id character varying,
noteable_id integer,
system boolean NOT NULL,
st_diff text,
updated_by_id integer,
type character varying,
"position" text,
original_position text,
resolved_at timestamp without time zone,
resolved_by_id integer,
discussion_id character varying,
note_html text,
cached_markdown_version integer,
change_position text,
resolved_by_push boolean,
review_id bigint,
confidential boolean,
last_edited_at timestamp with time zone,
internal boolean NOT NULL,
id bigint NOT NULL,
namespace_id bigint,
imported smallint DEFAULT 0 NOT NULL,
imported_from smallint DEFAULT 0 NOT NULL
);
CREATE TABLE term_agreements (
id integer NOT NULL,
term_id integer NOT NULL,
@ -22975,9 +22942,6 @@ ALTER TABLE ONLY tags
ALTER TABLE ONLY target_branch_rules
ADD CONSTRAINT target_branch_rules_pkey PRIMARY KEY (id);
ALTER TABLE ONLY temp_notes_backup
ADD CONSTRAINT temp_notes_backup_pkey PRIMARY KEY (id);
ALTER TABLE ONLY term_agreements
ADD CONSTRAINT term_agreements_pkey PRIMARY KEY (id);

View File

@ -18,6 +18,9 @@ To set up your self-hosted model deployment infrastructure:
1. Install the large language model (LLM) serving infrastructure.
1. Install the GitLab AI Gateway.
- [Installation video guide](https://youtu.be/UNmD9-sgUvw)
- [Installation video guide (French version)](https://www.youtube.com/watch?v=aU5vnzO-MSM)
## Step 1: Install LLM serving infrastructure
Install one of the following GitLab-approved LLM models:

View File

@ -49,6 +49,11 @@ GitLab and the runner are then connected.
Get a list of runners available to the user.
Prerequisites:
- You must be an administrator of or have the Owner role in the target namespace or project.
- For `instance_type`, you must be an administrator of the GitLab instance.
```plaintext
GET /runners
GET /runners?scope=active
@ -127,6 +132,11 @@ DETAILS:
Get a list of all runners in the GitLab instance (project and shared). Access
is restricted to users with administrator access.
Prerequisites:
- You must be an administrator of or have the Owner role in the target namespace or project.
- For `instance_type`, you must be an administrator of the GitLab instance.
```plaintext
GET /runners/all
GET /runners/all?scope=online
@ -226,11 +236,13 @@ To view more than the first 20 runners, use [pagination](rest/index.md#paginatio
Get details of a runner.
At least the Maintainer role is required to get runner details at the
project and group level.
Instance-level runner details via this endpoint are available to all authenticated users.
Prerequisites:
- You must at least the Developer role in the target namespace or project.
- An access token with the `manage_runner` scope and the appropriate role.
```plaintext
GET /runners/:id
```
@ -313,6 +325,13 @@ Update details of a runner.
PUT /runners/:id
```
Prerequisites:
- For `instance_type`, you must be an administrator of the GitLab instance.
- For `group_type`, you must have the Owner role in the target namespace.
- For `project_type`, you must have at least the Maintainer role in the target project.
- An access token with the `manage_runner` scope and the appropriate role.
| Attribute | Type | Required | Description |
|--------------------|---------|----------|-------------------------------------------------------------------------------------------------|
| `id` | integer | yes | The ID of a runner |
@ -390,6 +409,13 @@ Example response:
Pause a runner.
Prerequisites:
- For `instance_type`, you must be an administrator of the GitLab instance.
- For `group_type`, you must have the Owner role in the target namespace.
- For `project_type`, you must have at least the Maintainer role in the target project.
- An access token with the `manage_runner` scope and the appropriate role.
```plaintext
PUT --form "paused=true" /runners/:runner_id
@ -515,6 +541,10 @@ Example response:
List all runners available in the project, including from ancestor groups and [any allowed shared runners](../ci/runners/runners_scope.md#enable-instance-runners-for-a-project).
Prerequisites:
- You must be an administrator of or have at least the Maintainer role in the target project.
```plaintext
GET /projects/:id/runners
GET /projects/:id/runners?scope=active
@ -589,6 +619,12 @@ Example response:
Enable an available project runner in the project.
Prerequisites:
- For `instance_type`, you must be an administrator of the GitLab instance.
- For `group_type`, you must have the Owner role in the target namespace.
- For `project_type`, you must have at least the Maintainer role in the target project.
```plaintext
POST /projects/:id/runners
```
@ -633,6 +669,12 @@ Disable a project runner from the project. It works only if the project isn't
the only project associated with the specified runner. If so, an error is
returned. Use the call to [delete a runner](#delete-a-runner) instead.
Prerequisites:
- For `instance_type`, you must be an administrator of the GitLab instance.
- For `group_type`, you must have the Owner role in the target namespace.
- For `project_type`, you must have at least the Maintainer role in the target project.
```plaintext
DELETE /projects/:id/runners/:runner_id
```
@ -650,6 +692,10 @@ curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://git
List all runners available in the group as well as its ancestor groups, including [any allowed shared runners](../ci/runners/runners_scope.md#enable-instance-runners-for-a-group).
Prerequisites:
- You must be an administrator or have the Maintainer role of the target namespace.
```plaintext
GET /groups/:id/runners
GET /groups/:id/runners?type=group_type
@ -788,6 +834,13 @@ There are two ways to delete a runner:
To delete the runner by ID, use your access token with the runner's ID:
Prerequisites:
- For `instance_type`, you must be an administrator of the GitLab instance.
- For `group_type`, you must have the Owner role in the target namespace.
- For `project_type`, you must have at least the Maintainer role in the target project.
- An access token with the `manage_runner` scope and the appropriate role.
```plaintext
DELETE /runners/:id
```
@ -804,6 +857,11 @@ curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://git
To delete the runner by using its authentication token:
Prerequisites:
- You must be an administrator of or have the Owner role in the target namespace or project.
- For `instance_type`, you must be an administrator of the GitLab instance.
```plaintext
DELETE /runners
```
@ -910,6 +968,13 @@ curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" \
Reset the runner's authentication token by using its runner ID.
Prerequisites:
- For `instance_type`, you must be an administrator of the GitLab instance.
- For `group_type`, you must have the Owner role in the target namespace.
- For `project_type`, you must have at least the Maintainer role in the target project.
- An access token with the `manage_runner` scope and the appropriate role.
```plaintext
POST /runners/:id/reset_authentication_token
```
@ -936,6 +1001,11 @@ Example response:
Reset the runner's authentication token by using the current token's value as an input.
Prerequisites:
- You must be an administrator of or have the Owner role in the target namespace or project.
- For `instance_type`, you must be an administrator of the GitLab instance.
```plaintext
POST /runners/reset_authentication_token
```

View File

@ -42,6 +42,79 @@ This change makes the order distinct so we have "stable" sorting.
NOTE:
To make the query efficient, we need an index covering both columns: `(created_at, id)`. The order of the columns **should match** the columns in the `ORDER BY` clause.
### Incremental sorting
In PostgreSQL 13 incremental sorting was added which can help introducing a tie-breaker column to the `ORDER BY` clause without adding or replacing an index. Also, with incremental sorting, introducing a new keyset-paginated database query can happen before the new index is built (async indexes). Incremental sorting is enabled by default.
Consider the following database query:
```sql
SELECT *
FROM merge_requests
WHERE author_id = 1
ORDER BY created_at ASC
LIMIT 20
```
The query will read 20 rows using the following index:
```plaintext
"index_merge_requests_on_author_id_and_created_at" btree (author_id, created_at)
```
Using this query with keyset pagination is not possible because the `created_at` column is not unique. Let's add a tie-breaker column:
```sql
SELECT *
FROM merge_requests
WHERE author_id = 1
ORDER BY created_at ASC, id ASC
LIMIT 20
```
Execution plan:
```plaintext
Limit (cost=1.99..30.97 rows=20 width=910) (actual time=1.217..1.220 rows=20 loops=1)
Buffers: shared hit=33 read=2
I/O Timings: read=0.983 write=0.000
-> Incremental Sort (cost=1.99..919.33 rows=633 width=910) (actual time=1.215..1.216 rows=20 loops=1)
Sort Key: merge_requests.created_at, merge_requests.id
Buffers: shared hit=33 read=2
I/O Timings: read=0.983 write=0.000
-> Index Scan using index_merge_requests_on_author_id_and_created_at on public.merge_requests (cost=0.57..890.84 rows=633 width=910) (actual time=0.038..1.139 rows=22 loops=1)
Index Cond: (merge_requests.author_id = 1)
Buffers: shared hit=24 read=2
I/O Timings: read=0.983 write=0.000
```
As you can see the query read 22 rows using the same index. The database compared the 20th, 21th and 22th value of the `created_at` column and determined that the 22th value differ thus checking the next record is not needed. In this example the 20th and 21th column had the same `created_at` value.
Incremental sorting works well with timestamp columns where duplicated values are unlikely hence the incremental sorting will perform badly or won't be used at all when the column has very few distinct values (like an enum).
As an example, when incremental sorting is disabled, the database reads all merge requests records by the author and sorts data in memory.
```sql
set enable_incremental_sort=off;
```
```plaintext
Limit (cost=907.69..907.74 rows=20 width=910) (actual time=2.911..2.917 rows=20 loops=1)
Buffers: shared hit=1004
-> Sort (cost=907.69..909.27 rows=633 width=910) (actual time=2.908..2.911 rows=20 loops=1)
Sort Key: created_at, id
Sort Method: top-N heapsort Memory: 52kB
Buffers: shared hit=1004
-> Index Scan using index_merge_requests_on_author_id_and_created_at on merge_requests (cost=0.57..890.84 rows=633 width=910) (actual time=0.042..1.974 rows=1111 loops=1)
Index Cond: (author_id = 1)
Buffers: shared hit=1111
Planning Time: 0.386 ms
Execution Time: 3.000 ms
(11 rows)
```
In this example the database read 1111 rows and sorted the rows in memory.
## Ordering by joined table column
Oftentimes, we want to order the data by a column on a joined database table. The following example orders `issues` records by the `first_mentioned_in_commit_at` metric column:

View File

@ -401,11 +401,11 @@ adds the start and end tags with the correct styling classes.
| Placeholder | Style |
|-------------|-----------------------------------------|
| success | `gl-font-weight-bold gl-text-green-500` |
| danger | `gl-font-weight-bold gl-text-red-500` |
| critical | `gl-font-weight-bold gl-text-red-800` |
| same | `gl-font-weight-bold gl-text-gray-700` |
| strong | `gl-font-weight-bold` |
| success | `gl-font-bold gl-text-green-500` |
| danger | `gl-font-bold gl-text-red-500` |
| critical | `gl-font-bold gl-text-red-800` |
| same | `gl-font-bold gl-text-gray-700` |
| strong | `gl-font-bold` |
| small | `gl-font-sm` |
## Action buttons

View File

@ -34,7 +34,7 @@ for a description on what each tag semantically means.
<!-- good - prefer semantic classes used accurately -->
<section class="...">
<p>
Simply visit your <span class="gl-font-weight-bold">Settings</span> to say hello to the world.
Simply visit your <span class="gl-font-bold">Settings</span> to say hello to the world.
</p>
<footer class="...">...</footer>
</section>

View File

@ -106,6 +106,7 @@ different actions. See the following table for all available scopes.
| `profile` | Grants read-only access to the user's profile data using [OpenID Connect](openid_connect_provider.md). |
| `email` | Grants read-only access to the user's primary email address using [OpenID Connect](openid_connect_provider.md). |
| `create_runner` | Grants permission to create runners. |
| `manage_runner` | Grants permission to manage runners. |
| `k8s_proxy` | Grants permission to perform Kubernetes API calls using the agent for Kubernetes. |
At any time you can revoke any access by selecting **Revoke**.

View File

@ -32,8 +32,8 @@ DETAILS:
**Tier:** Premium and Ultimate with [GitLab Duo Pro or Enterprise](../subscriptions/subscription-add-ons.md).
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
- Helps you write code more efficiently by showing code suggestions as you type.
- LLM for code completion: Vertex AI Codey [`code-gecko`](https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/code-completion)
- Helps you write code more efficiently by generating code and showing suggestions as you type.
- Large language model (LLM) for code completion: Vertex AI Codey [`code-gecko`](https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/code-completion)
- LLM for code generation: Anthropic [`claude-3-sonnet-20240229`](https://docs.anthropic.com/claude/docs/models-overview)
- <i class="fa fa-youtube-play youtube" aria-hidden="true"></i> [Watch overview](https://youtu.be/ds7SG1wgcVM)
- [View documentation](project/repository/code_suggestions/index.md).
@ -44,9 +44,8 @@ DETAILS:
**Tier:** GitLab.com and Self-managed: For a limited time, Premium and Ultimate. In the future, [GitLab Duo Pro or Enterprise](../subscriptions/subscription-add-ons.md). <br>GitLab Dedicated: GitLab Duo Pro or Enterprise.
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
- Processes and generates text and code in a conversational manner.
Help you write and understand code faster, get up to speed on the status of projects,
and quickly learn about GitLab.
- Help you write and understand code faster, get up to speed on the status of projects,
and quickly learn about GitLab by answering your questions in a chat window.
- LLM: Anthropic [`claude-3-sonnet-20240229`](https://docs.anthropic.com/en/docs/models-overview#claude-3-a-new-generation-of-ai),
Anthropic [`claude-3-haiku-20240307`](https://docs.anthropic.com/en/docs/models-overview#claude-3-a-new-generation-of-ai),
[`claude-2.1`](https://docs.anthropic.com/en/docs/legacy-model-guide#anthropics-legacy-models),
@ -66,7 +65,7 @@ DETAILS:
**Tier:** Ultimate
**Offering:** GitLab.com
- Assists in creating faster and higher-quality reviews by automatically suggesting reviewers for your merge request.
- Helps create faster and higher-quality reviews by automatically suggesting reviewers for your merge request.
- LLM: GitLab creates a machine learning model for each project, which is used to generate reviewers. [View the issue](https://gitlab.com/gitlab-org/modelops/applied-ml/applied-ml-updates/-/issues/10).
- <i class="fa fa-youtube-play youtube" aria-hidden="true"></i> [Watch overview](https://www.youtube.com/watch?v=ivwZQgh4Rxw)
- [View documentation](project/merge_requests/reviews/index.md#gitlab-duo-suggested-reviewers).
@ -77,7 +76,7 @@ DETAILS:
**Tier:** GitLab.com and Self-managed: For a limited time, Premium and Ultimate. In the future, [GitLab Duo Pro or Enterprise](../subscriptions/subscription-add-ons.md). <br>GitLab Dedicated: GitLab Duo Pro or Enterprise.
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
- Automates repetitive tasks and helps catch bugs early.
- Helps catch bugs early by generating tests for the selected code.
- LLM: Anthropic [`Claude-2.1`](https://docs.anthropic.com/claude/docs/models-overview#model-comparison)
- <i class="fa fa-youtube-play youtube" aria-hidden="true"></i> [Watch overview](https://www.youtube.com/watch?v=zWhwuixUkYU&list=PLFGfElNsQthYDx0A_FaNNfUm9NHsK6zED)
- [View documentation](gitlab_duo_chat_examples.md#write-tests-in-the-ide).
@ -88,7 +87,7 @@ DETAILS:
**Tier:** For a limited time, Premium and Ultimate. In the future, [GitLab Duo Pro or Enterprise](../subscriptions/subscription-add-ons.md).
**Offering:** GitLab.com
- Helps you understand code by explaining it in English language.
- Helps you understand the selected code by explaining it more clearly.
- LLM: Anthropic: [`claude-3-haiku-20240307`](https://docs.anthropic.com/en/docs/models-overview#claude-3-a-new-generation-of-ai)
- View documentation for [explaining code in the IDE](../user/gitlab_duo_chat_examples.md#explain-code-in-the-ide).
@ -100,7 +99,7 @@ DETAILS:
**Tier:** For a limited time, Ultimate. In the future, [GitLab Duo Enterprise](../subscriptions/subscription-add-ons.md).
**Offering:** GitLab.com
- Efficiently communicates the impact of your merge request changes.
- Helps populate a merge request more quickly by generating a description based on the code changes.
- LLM: Vertex AI Codey [`text-bison`](https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/text)
- [View documentation](project/merge_requests/ai_in_merge_requests.md#generate-a-description-by-summarizing-code-changes).
@ -110,7 +109,7 @@ DETAILS:
**Tier:** For a limited time, Ultimate. In the future, [GitLab Duo Enterprise](../subscriptions/subscription-add-ons.md).
**Offering:** GitLab.com
- Generates a description for the merge request based on the contents of the template.
- Helps populate a merge request more quickly by generating a description based on the contents of the template.
- LLM: Vertex AI Codey [`text-bison`](https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/text)
- [View documentation](project/merge_requests/ai_in_merge_requests.md#generate-a-description-from-a-template).
@ -120,7 +119,7 @@ DETAILS:
**Tier:** For a limited time, Ultimate. In the future, [GitLab Duo Enterprise](../subscriptions/subscription-add-ons.md).
**Offering:** GitLab.com
- Helps you remediate vulnerabilities more efficiently, boost your skills, and write more secure code.
- Helps you understand vulnerabilities, how they can be exploited, and how to fix them.
- LLM: Vertex AI Codey [`text-bison`](https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/text). If degraded performance, then Anthropic [`Claude-2.1`](https://docs.anthropic.com/claude/docs/models-overview#model-comparison).
- <i class="fa fa-youtube-play youtube" aria-hidden="true"></i> [Watch overview](https://youtu.be/ctD_qcVpIJY)
- [View documentation](application_security/vulnerabilities/index.md#explaining-a-vulnerability).
@ -143,7 +142,7 @@ DETAILS:
**Tier:** For a limited time, Ultimate. In the future, [GitLab Duo Enterprise](../subscriptions/subscription-add-ons.md).
**Offering:** GitLab.com
- Assists with quickly getting everyone up to speed on lengthy conversations to help ensure you are all on the same page.
- Helps everyone get up to speed by summarizing lengthy conversations.
- LLM: Anthropic [`Claude-2.1`](https://docs.anthropic.com/claude/docs/models-overview#model-comparison)
- <i class="fa fa-youtube-play youtube" aria-hidden="true"></i> [Watch overview](https://www.youtube.com/watch?v=IcdxLfTIUgc)
- [View documentation](ai_experiments.md#summarize-issue-discussions-with-discussion-summary).
@ -154,7 +153,7 @@ DETAILS:
**Tier:** For a limited time, Ultimate. In the future, [GitLab Duo Enterprise](../subscriptions/subscription-add-ons.md).
**Offering:** GitLab.com
- Generates issue descriptions.
- Helps populate an issue more quickly by generating a more in-depth description, based on a short summary you provide.
- LLM: Anthropic [`Claude-2.1`](https://docs.anthropic.com/claude/docs/models-overview#model-comparison)
- [View documentation](ai_experiments.md#summarize-an-issue-with-issue-description-generation).
@ -164,7 +163,7 @@ DETAILS:
**Tier:** For a limited time, Ultimate. In the future, [GitLab Duo Enterprise](../subscriptions/subscription-add-ons.md).
**Offering:** GitLab.com
- Helps ease merge request handoff between authors and reviewers and help reviewers efficiently understand suggestions.
- Helps make merge request handover to reviewers easier by summarizing all the comments in a merge request review.
- LLM: Vertex AI Codey [`text-bison`](https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/text)
- <i class="fa fa-youtube-play youtube" aria-hidden="true"></i> [Watch overview](https://www.youtube.com/watch?v=Bx6Zajyuy9k&list=PLFGfElNsQthYDx0A_FaNNfUm9NHsK6zED)
- [View documentation](project/merge_requests/ai_in_merge_requests.md#summarize-a-code-review).
@ -175,7 +174,7 @@ DETAILS:
**Tier:** For a limited time, Ultimate. In the future, [GitLab Duo Enterprise](../subscriptions/subscription-add-ons.md).
**Offering:** GitLab.com
- Generates a merge request containing the changes required to mitigate a vulnerability.
- Help resolve a vulnerability by generating a merge request that addresses it.
- LLM: Vertex AI Codey [`code-bison`](https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/code-generation)
- [View documentation](application_security/vulnerabilities/index.md#vulnerability-resolution).
@ -185,7 +184,7 @@ DETAILS:
**Tier:** For a limited time, Premium and Ultimate. In the future, [GitLab Duo Pro or Enterprise](../subscriptions/subscription-add-ons.md).
**Offering:** GitLab.com
- Helps you understand code by explaining it in English language.
- Helps you understand the selected code by explaining it more clearly.
- LLM: Anthropic: [`claude-3-haiku-20240307`](https://docs.anthropic.com/en/docs/models-overview#claude-3-a-new-generation-of-ai)
- View documentation for explaining code in:
- [A file](../user/project/repository/code_explain.md).
@ -197,7 +196,7 @@ DETAILS:
**Tier:** For a limited time, Ultimate. In the future, [GitLab Duo Enterprise](../subscriptions/subscription-add-ons.md).
**Offering:** GitLab.com
- Assists you in determining the root cause for a CI/CD job failure by analyzing the logs.
- Helps you determine the root cause for a CI/CD job failure by analyzing the logs.
- LLM: Vertex AI Codey [`text-bison`](https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/text)
- [View documentation](ai_experiments.md#root-cause-analysis).
@ -207,7 +206,7 @@ DETAILS:
**Tier:** GitLab.com and Self-managed: For a limited time, Ultimate. In the future, [GitLab Duo Enterprise](../subscriptions/subscription-add-ons.md). <br>GitLab Dedicated: GitLab Duo Enterprise.
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
- Assists you with predicting productivity metrics and identifying anomalies across your software development lifecycle.
- Helps you improve planning and decision-making by predicting productivity metrics and identifying anomalies across your software development lifecycle.
- LLM: Statistical forecasting
- <i class="fa fa-youtube-play youtube" aria-hidden="true"></i> [Watch overview](https://www.youtube.com/watch?v=6u8_8QQ5pEQ&list=PLFGfElNsQthYDx0A_FaNNfUm9NHsK6zED)
- [View documentation](ai_experiments.md#forecast-deployment-frequency-with-value-stream-forecasting).
@ -228,7 +227,7 @@ DETAILS:
**Tier:** For a limited time, Ultimate. In the future, [GitLab Duo Enterprise](../subscriptions/subscription-add-ons.md).
**Offering:** GitLab.com
- Helps users generate meaningful commit messages for merge and squash commits.
- Helps you merge more quickly by generating meaningful commit messages.
- LLM: Vertex AI Codey [`text-bison`](https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/text).
- [View documentation](project/merge_requests/ai_in_merge_requests.md#generate-a-merge-or-squash-commit-message).

View File

@ -246,6 +246,10 @@ To ensure GitLab maps users and their contributions correctly:
1. If users already exist on the destination instance and you use [SAML SSO for GitLab.com groups](../../group/saml_sso/index.md), all users must
[link their SAML identity to their GitLab.com account](../../group/saml_sso/index.md#link-saml-to-your-existing-gitlabcom-account).
There is no way in the GitLab UI or API to automatically set public email addresses for users. If you need to set
a lot of user accounts to have public email addresses, see
[issue 284495](https://gitlab.com/gitlab-org/gitlab/-/issues/284495#note_1910159855) for a potential workaround.
## Connect the source GitLab instance
Create the group you want to import to and connect the source GitLab instance:

View File

@ -147,6 +147,7 @@ The scope determines the actions you can perform when you authenticate with a gr
| `read_repository` | Grants read access (pull) to all repositories within a group. |
| `write_repository` | Grants read and write access (pull and push) to all repositories within a group. |
| `create_runner` | Grants permission to create runners in a group. |
| `manage_runner` | Grants permission to manage runners in a group. |
| `ai_features` | Grants permission to perform API actions for GitLab Duo. This scope is designed to work with the GitLab Duo Plugin for JetBrains. For all other extensions, see scope requirements. |
| `k8s_proxy` | Grants permission to perform Kubernetes API calls using the agent for Kubernetes in a group. |

View File

@ -52,6 +52,22 @@ To protect a package:
The package protection rule is created, and appears in the settings.
### Protecting multiple packages
You can use a wildcard to protect multiple packages with the same package protection rule.
For example, you can protect all the temporary packages built during a CI/CD pipeline.
The following table contains examples of package protection rules that match multiple packages:
| Package name pattern with wildcard | Matching packages |
|------------------------------------|-----------------------------------------------------------------------------|
| `@group/package-*` | `@group/package-prod`, `@group/package-prod-sha123456789` |
| `@group/*package` | `@group/package`, `@group/prod-package`, `@group/prod-sha123456789-package` |
| `@group/*package*` | `@group/package`, `@group/prod-sha123456789-package-v1` |
It's possible to apply several protection rules to the same package.
If at least one protection rule applies to the package, the package is protected.
## Delete a package protection rule and unprotect a package
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/140483) in GitLab 16.10.

View File

@ -160,6 +160,7 @@ A personal access token can perform actions based on the assigned scopes.
| `sudo` | Grants permission to perform API actions as any user in the system, when authenticated as an administrator. |
| `admin_mode` | Grants permission to perform API actions as an administrator, when Admin Mode is enabled. ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/107875) in GitLab 15.8.) |
| `create_runner` | Grants permission to create runners. |
| `manage_runner` | Grants permission to manage runners. |
| `ai_features` | Grants permission to perform API actions for GitLab Duo. This scope is designed to work with the GitLab Duo Plugin for JetBrains. For all other extensions, see scope requirements. |
| `k8s_proxy` | Grants permission to perform Kubernetes API calls using the agent for Kubernetes. |
| `read_service_ping`| Grant access to download Service Ping payload through the API when authenticated as an admin use. ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/107875) in GitLab 16.8. |

View File

@ -92,6 +92,7 @@ See the warning in [create a project access token](#create-a-project-access-toke
| `read_repository` | Grants read access (pull) to the repository. |
| `write_repository` | Grants read and write access (pull and push) to the repository. |
| `create_runner` | Grants permission to create runners in the project. |
| `manage_runner` | Grants permission to manage runners in the project. |
| `ai_features` | Grants permission to perform API actions for GitLab Duo. This scope is designed to work with the GitLab Duo Plugin for JetBrains. For all other extensions, see scope requirements. |
| `k8s_proxy` | Grants permission to perform Kubernetes API calls using the agent for Kubernetes in the project. |

View File

@ -3,9 +3,9 @@
module ClickHouse
module Client
class Query < QueryLike
SUBQUERY_PLACEHOLDER_REGEX = /{\w+:Subquery}/ # exmaple: {var:Subquery}, special "internal" type for subqueries
PLACEHOLDER_REGEX = /{\w+:\w+}/ # exmaple: {var:UInt8}
PLACEHOLDER_NAME_REGEX = /{(\w+):/ # exmaple: {var:UInt8} => var
SUBQUERY_PLACEHOLDER_REGEX = /{\w+:Subquery}/ # example: {var:Subquery}, special "internal" type for subqueries
PLACEHOLDER_REGEX = /{\w+:\w+}/ # example: {var:UInt8}
PLACEHOLDER_NAME_REGEX = /{(\w+):/ # example: {var:UInt8} => var
def initialize(raw_query:, placeholders: {})
raise QueryError, 'Empty query string given' if raw_query.blank?

View File

@ -3,6 +3,7 @@
module API
module Ci
class Runners < ::API::Base
include APIGuard
include PaginationParams
before { authenticate! }
@ -104,6 +105,10 @@ module API
end
end
allow_access_with_scope :manage_runner, if: ->(request) do
request.params.key?(:id) && request.path.match?(%r{\A/api/v[34]/runners/})
end
resource :runners do
desc 'Get runners available for user' do
summary 'List owned runners'
@ -274,7 +279,7 @@ module API
desc: 'The ID or URL-encoded path of the project owned by the authenticated user'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
before { authorize_admin_project }
before { authorize! :read_project_runners, user_project }
desc 'Get runners available for project' do
summary "List project's runners"
@ -310,6 +315,8 @@ module API
requires :runner_id, type: Integer, desc: 'The ID of a runner'
end
post ':id/runners' do
authorize! :create_runner, user_project # Ensure the user is allowed to create a runner on the target project
runner = get_runner(params[:runner_id])
authenticate_enable_runner!(runner)
@ -335,6 +342,8 @@ module API
end
# rubocop: disable CodeReuse/ActiveRecord
delete ':id/runners/:runner_id' do
authorize! :admin_project_runners, user_project
runner_project = user_project.runner_projects.find_by(runner_id: params[:runner_id])
not_found!('Runner') unless runner_project
@ -350,7 +359,7 @@ module API
requires :id, type: String, desc: 'The ID of a group'
end
resource :groups, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
before { authorize_admin_group }
before { authorize! :read_group_runners, user_group }
desc 'Get runners available for group' do
summary "List group's runners"

View File

@ -12,7 +12,13 @@ module Gitlab
READ_API_SCOPE = :read_api
READ_USER_SCOPE = :read_user
CREATE_RUNNER_SCOPE = :create_runner
API_SCOPES = [API_SCOPE, READ_API_SCOPE, READ_USER_SCOPE, CREATE_RUNNER_SCOPE, K8S_PROXY_SCOPE].freeze
MANAGE_RUNNER_SCOPE = :manage_runner
API_SCOPES = [
API_SCOPE, READ_API_SCOPE,
READ_USER_SCOPE,
CREATE_RUNNER_SCOPE, MANAGE_RUNNER_SCOPE,
K8S_PROXY_SCOPE
].freeze
# Scopes for Duo
AI_FEATURES = :ai_features
@ -272,11 +278,12 @@ module Gitlab
abilities_by_scope = {
api: full_authentication_abilities,
read_api: read_only_authentication_abilities,
read_registry: [:read_container_image],
write_registry: [:create_container_image],
read_repository: [:download_code],
write_repository: [:download_code, :push_code],
create_runner: [:create_instance_runner, :create_runner]
read_registry: %i[read_container_image],
write_registry: %i[create_container_image],
read_repository: %i[download_code],
write_repository: %i[download_code push_code],
create_runner: %i[create_instance_runner create_runner],
manage_runner: %i[assign_runner update_runner delete_runner]
}
scopes.flat_map do |scope|

View File

@ -9,9 +9,9 @@ module Gitlab
include Gitlab::Utils::StrongMemoize
attr_reader :errors, :warnings,
:root_variables, :root_variables_with_prefill_data,
:stages, :jobs,
:workflow_rules, :workflow_name, :workflow_auto_cancel
:root_variables, :root_variables_with_prefill_data,
:stages, :jobs,
:workflow_rules, :workflow_name, :workflow_auto_cancel
def initialize(ci_config: nil, errors: [], warnings: [])
@ci_config = ci_config

View File

@ -139,9 +139,9 @@ module Gitlab
if project && user
Gitlab::AppJsonLogger.info(event: 'ci_used_deprecated_keyword',
entry: entry.key.to_s,
user_id: user.id,
project_id: project.id)
entry: entry.key.to_s,
user_id: user.id,
project_id: project.id)
end
deprecation = entry.deprecation

View File

@ -222,9 +222,9 @@ module Gitlab
def content_path
conflict_for_path_project_merge_request_path(merge_request.project,
merge_request,
old_path: their_path,
new_path: our_path)
merge_request,
old_path: their_path,
new_path: our_path)
end
def conflict_type(when_renamed: false)

View File

@ -4,7 +4,7 @@ module Gitlab
class CrossProjectAccess
class << self
delegate :add_check, :find_check, :checks,
to: :instance
to: :instance
end
def self.instance
@ -25,10 +25,10 @@ module Gitlab
skip: false)
new_check = CheckInfo.new(actions,
positive_condition,
negative_condition,
skip
)
positive_condition,
negative_condition,
skip
)
@checks[klass] ||= Gitlab::CrossProjectAccess::CheckCollection.new
@checks[klass].add_check(new_check)

View File

@ -141,7 +141,7 @@ module Gitlab
push_options: push_options,
# DEPRECATED
repository: project.hook_attrs.slice(:name, :url, :description, :homepage,
:git_http_url, :git_ssh_url, :visibility_level)
:git_http_url, :git_ssh_url, :visibility_level)
}
end
@ -169,11 +169,11 @@ module Gitlab
commits = project.repository.commits(project.default_branch.to_s, limit: 3)
build(project: project,
user: user,
oldrev: commits.last&.id,
newrev: commits.first&.id,
ref: ref,
commits: commits)
user: user,
oldrev: commits.last&.id,
newrev: commits.first&.id,
ref: ref,
commits: commits)
end
def sample_data(is_tag = false)

View File

@ -57,7 +57,7 @@ module Gitlab
private
attr_reader :source_model, :target_model, :source_columns, :target_columns,
:source_sort_column, :target_sort_column, :start_time, :result
:source_sort_column, :target_sort_column, :start_time, :result
def build_result(next_start_id:)
{ next_start_id: next_start_id }.merge(result)

View File

@ -91,7 +91,7 @@ module Gitlab
if check_statistics
query = query.where('last_vacuum > ? OR last_autovacuum > ? OR last_analyze > ? OR last_autoanalyze > ?',
time, time, time, time)
time, time, time, time)
end
query

View File

@ -6,8 +6,8 @@ module Gitlab
# Configuration settings for a single LoadBalancer instance.
class Configuration
attr_accessor :hosts, :max_replication_difference,
:max_replication_lag_time, :replica_check_interval,
:service_discovery
:max_replication_lag_time, :replica_check_interval,
:service_discovery
# Creates a configuration object for the given ActiveRecord model.
def self.for_model(model)

View File

@ -18,7 +18,7 @@ module Gitlab
attr_accessor :refresh_thread, :refresh_thread_last_run, :refresh_thread_interruption_logged
attr_reader :interval, :record, :record_type, :disconnect_timeout,
:load_balancer
:load_balancer
MAX_SLEEP_ADJUSTMENT = 10
MAX_DISCOVERY_RETRIES = 3

View File

@ -970,9 +970,9 @@ module Gitlab
def copy_foreign_keys(table, old, new)
foreign_keys_for(table, old).each do |fk|
add_concurrent_foreign_key(fk.from_table,
fk.to_table,
column: new,
on_delete: fk.on_delete)
fk.to_table,
column: new,
on_delete: fk.on_delete)
end
end
@ -1316,9 +1316,9 @@ into similar problems in the future (e.g. when new tables are created).
new_limit = limit || old_col.limit
add_column(table, new, new_type,
limit: new_limit,
precision: old_col.precision,
scale: old_col.scale)
limit: new_limit,
precision: old_col.precision,
scale: old_col.scale)
# We set the default value _after_ adding the column so we don't end up
# updating any existing data with the default value. This isn't

View File

@ -39,7 +39,7 @@ module Gitlab
per_background_migration_result_dir = File.join(@result_dir, migration_name)
instrumentation = Instrumentation.new(result_dir: per_background_migration_result_dir,
observer_classes: observers)
observer_classes: observers)
batch_names = (1..).each.lazy.map { |i| "batch_#{i}" }
@ -49,9 +49,9 @@ module Gitlab
meta = { job_meta: job_meta(j) }
instrumentation.observe(version: nil,
name: batch_names.next,
connection: connection,
meta: meta) do
name: batch_names.next,
connection: connection,
meta: meta) do
run_job(j)
end
end

View File

@ -14,9 +14,9 @@ module Gitlab
end
rescue StandardError => e
Gitlab::AppLogger.error(message: "Failed to drop previously detached partition",
partition_name: detached_partition.table_name,
exception_class: e.class,
exception_message: e.message)
partition_name: detached_partition.table_name,
exception_class: e.class,
exception_message: e.message)
end
end
@ -76,9 +76,9 @@ module Gitlab
connection.execute("ALTER TABLE #{connection.quote_table_name(partition_identifier)} DROP CONSTRAINT #{connection.quote_table_name(foreign_key.name)}")
Gitlab::AppLogger.info(message: "Dropped foreign key for previously detached partition",
partition_name: detached_partition.table_name,
referenced_table_name: foreign_key.referenced_table_identifier,
foreign_key_name: foreign_key.name)
partition_name: detached_partition.table_name,
referenced_table_name: foreign_key.referenced_table_identifier,
foreign_key_name: foreign_key.name)
end
end
end

View File

@ -33,6 +33,9 @@ module Gitlab
gon.recaptcha_api_server_url = ::Recaptcha.configuration.api_server_url
gon.recaptcha_sitekey = Gitlab::CurrentSettings.recaptcha_site_key
gon.gitlab_url = Gitlab.config.gitlab.url
gon.promo_url = ApplicationHelper.promo_url
gon.forum_url = Gitlab::Saas.community_forum_url
gon.docs_url = Gitlab::Saas.doc_url
gon.organization_http_header_name = ::Organizations::ORGANIZATION_HTTP_HEADER
gon.revision = Gitlab.revision
gon.feature_category = Gitlab::ApplicationContext.current_context_attribute(:feature_category).presence

View File

@ -36712,6 +36712,9 @@ msgstr ""
msgid "PackageRegistry|%{count} packages were not published to the registry. Remove these packages and try again."
msgstr ""
msgid "PackageRegistry|%{linkStart}Wildcards%{linkEnd} such as `@my-scope/my-package-*` are supported."
msgstr ""
msgid "PackageRegistry|%{name} version %{version} was first created %{datetime}"
msgstr ""

View File

@ -29,7 +29,7 @@ RSpec.describe Admin::GroupsController, feature_category: :groups_and_projects d
get :index
html_rendered = Nokogiri::HTML(response.body)
sort_options = Gitlab::Json.parse(html_rendered.css('div.dropdown')[0]['data-items'])
sort_options = Gitlab::Json.parse(html_rendered.css('[data-items]')[0]['data-items'])
expect(response).to render_template('shared/groups/_dropdown')

View File

@ -136,8 +136,6 @@ RSpec.describe 'Database schema', feature_category: :database do
subscriptions: %w[user_id subscribable_id],
suggestions: %w[commit_id],
taggings: %w[tag_id taggable_id tagger_id],
# temp_notes_backup is a temporary table created to store orphaned records from the notes table to insure against data loss.
temp_notes_backup: %w[author_id project_id commit_id noteable_id updated_by_id resolved_by_id discussion_id review_id namespace_id],
timelogs: %w[user_id],
todos: %w[target_id commit_id],
uploads: %w[model_id],

View File

@ -52,7 +52,7 @@ RSpec.describe 'User creates a merge request', :js, feature_category: :code_revi
project.repository.create_branch("<img/src='x'/onerror=alert('oops')>", 'master')
end
it 'does not execute the suspicious branch name' do
it 'does not execute the suspicious branch name', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/447484' do
visit(project_new_merge_request_path(project))
compare_source_and_target("<img/src='x'/onerror=alert('oops')>", 'feature')

View File

@ -1,4 +1,4 @@
import { GlBadge } from '@gitlab/ui';
import { GlBadge, GlSprintf } from '@gitlab/ui';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import HeaderBadges from '~/ci/pipeline_details/header/components/header_badges.vue';
@ -8,6 +8,11 @@ describe('Header badges', () => {
let wrapper;
const findAllBadges = () => wrapper.findAllComponents(GlBadge);
const findChildPipelineBadge = () =>
findAllBadges().filter((badge) => {
const sprintf = badge.findComponent(GlSprintf);
return sprintf.exists() && sprintf.attributes('message').includes('Child pipeline');
});
const createComponent = (mockPipeline = pipelineHeaderSuccess.data.project.pipeline) => {
wrapper = shallowMountExtended(HeaderBadges, {
@ -45,4 +50,19 @@ describe('Header badges', () => {
expect(wrapper.findByText('Scheduled').exists()).toBe(true);
expect(wrapper.findByText('trigger token').exists()).toBe(true);
});
describe('in a child pipeline', () => {
const triggeredByPath = 'https://example.com';
it('displays the link to the parent', () => {
createComponent({
...pipelineHeaderTrigger.data.project.pipeline,
child: true,
triggeredByPath,
});
expect(findAllBadges()).toHaveLength(4);
expect(findChildPipelineBadge().exists()).toBe(true);
});
});
});

View File

@ -5,7 +5,7 @@ import Vue from 'vue';
import Vuex from 'vuex';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import ApproveAccessRequestButton from '~/members/components/action_buttons/approve_access_request_button.vue';
import { MEMBER_TYPES } from '~/members/constants';
import { MEMBERS_TAB_TYPES } from '~/members/constants';
jest.mock('~/lib/utils/csrf', () => ({ token: 'mock-csrf-token' }));
@ -17,7 +17,7 @@ describe('ApproveAccessRequestButton', () => {
const createStore = (state = {}) => {
return new Vuex.Store({
modules: {
[MEMBER_TYPES.accessRequest]: {
[MEMBERS_TAB_TYPES.accessRequest]: {
namespaced: true,
state: {
memberPath: '/groups/foo-bar/-/group_members/:id',
@ -32,7 +32,7 @@ describe('ApproveAccessRequestButton', () => {
wrapper = shallowMount(ApproveAccessRequestButton, {
store: createStore(state),
provide: {
namespace: MEMBER_TYPES.accessRequest,
namespace: MEMBERS_TAB_TYPES.accessRequest,
},
propsData: {
memberId: 1,

View File

@ -5,7 +5,7 @@ import Vue from 'vue';
import Vuex from 'vuex';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import RemoveGroupLinkButton from '~/members/components/action_buttons/remove_group_link_button.vue';
import { MEMBER_TYPES } from '~/members/constants';
import { MEMBERS_TAB_TYPES } from '~/members/constants';
import { group } from '../../mock_data';
Vue.use(Vuex);
@ -20,7 +20,7 @@ describe('RemoveGroupLinkButton', () => {
const createStore = () => {
return new Vuex.Store({
modules: {
[MEMBER_TYPES.group]: {
[MEMBERS_TAB_TYPES.group]: {
namespaced: true,
actions,
},
@ -32,7 +32,7 @@ describe('RemoveGroupLinkButton', () => {
wrapper = mount(RemoveGroupLinkButton, {
store: createStore(),
provide: {
namespace: MEMBER_TYPES.group,
namespace: MEMBERS_TAB_TYPES.group,
},
propsData: {
groupLink: group,

View File

@ -6,7 +6,7 @@ import Vuex from 'vuex';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import { modalData } from 'jest/members/mock_data';
import RemoveMemberButton from '~/members/components/action_buttons/remove_member_button.vue';
import { MEMBER_TYPES } from '~/members/constants';
import { MEMBERS_TAB_TYPES } from '~/members/constants';
Vue.use(Vuex);
@ -20,7 +20,7 @@ describe('RemoveMemberButton', () => {
const createStore = (state = {}) => {
return new Vuex.Store({
modules: {
[MEMBER_TYPES.user]: {
[MEMBERS_TAB_TYPES.user]: {
namespaced: true,
state: {
memberPath: '/groups/foo-bar/-/group_members/:id',
@ -36,7 +36,7 @@ describe('RemoveMemberButton', () => {
wrapper = shallowMount(RemoveMemberButton, {
store: createStore(state),
provide: {
namespace: MEMBER_TYPES.user,
namespace: MEMBERS_TAB_TYPES.user,
},
propsData: {
memberId: 1,

View File

@ -5,7 +5,7 @@ import Vue from 'vue';
import Vuex from 'vuex';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import ResendInviteButton from '~/members/components/action_buttons/resend_invite_button.vue';
import { MEMBER_TYPES } from '~/members/constants';
import { MEMBERS_TAB_TYPES } from '~/members/constants';
jest.mock('~/lib/utils/csrf', () => ({ token: 'mock-csrf-token' }));
@ -17,7 +17,7 @@ describe('ResendInviteButton', () => {
const createStore = (state = {}) => {
return new Vuex.Store({
modules: {
[MEMBER_TYPES.invite]: {
[MEMBERS_TAB_TYPES.invite]: {
namespaced: true,
state: {
memberPath: '/groups/foo-bar/-/group_members/:id',
@ -32,7 +32,7 @@ describe('ResendInviteButton', () => {
wrapper = shallowMount(ResendInviteButton, {
store: createStore(state),
provide: {
namespace: MEMBER_TYPES.invite,
namespace: MEMBERS_TAB_TYPES.invite,
},
propsData: {
memberId: 1,

View File

@ -5,7 +5,7 @@ import Vue from 'vue';
import Vuex from 'vuex';
import { modalData } from 'jest/members/mock_data';
import RemoveMemberDropdownItem from '~/members/components/action_dropdowns/remove_member_dropdown_item.vue';
import { MEMBER_TYPES, MEMBER_MODEL_TYPE_GROUP_MEMBER } from '~/members/constants';
import { MEMBERS_TAB_TYPES, MEMBER_MODEL_TYPE_GROUP_MEMBER } from '~/members/constants';
Vue.use(Vuex);
@ -20,7 +20,7 @@ describe('RemoveMemberDropdownItem', () => {
const createStore = (state = {}) => {
return new Vuex.Store({
modules: {
[MEMBER_TYPES.user]: {
[MEMBERS_TAB_TYPES.user]: {
namespaced: true,
state: {
memberPath: '/groups/foo-bar/-/group_members/:id',
@ -36,7 +36,7 @@ describe('RemoveMemberDropdownItem', () => {
wrapper = shallowMount(RemoveMemberDropdownItem, {
store: createStore(state),
provide: {
namespace: MEMBER_TYPES.user,
namespace: MEMBERS_TAB_TYPES.user,
},
propsData: {
memberId: 1,

View File

@ -7,7 +7,7 @@ import * as commonUtils from '~/lib/utils/common_utils';
import MembersApp from '~/members/components/app.vue';
import FilterSortContainer from '~/members/components/filter_sort/filter_sort_container.vue';
import MembersTable from '~/members/components/table/members_table.vue';
import { MEMBER_TYPES, TAB_QUERY_PARAM_VALUES } from '~/members/constants';
import { MEMBERS_TAB_TYPES, TAB_QUERY_PARAM_VALUES } from '~/members/constants';
import { RECEIVE_MEMBER_ROLE_ERROR, HIDE_ERROR } from '~/members/store/mutation_types';
import mutations from '~/members/store/mutations';
@ -20,7 +20,7 @@ describe('MembersApp', () => {
const createComponent = (state = {}, options = {}) => {
store = new Vuex.Store({
modules: {
[MEMBER_TYPES.group]: {
[MEMBERS_TAB_TYPES.group]: {
namespaced: true,
state: {
showError: true,
@ -34,7 +34,7 @@ describe('MembersApp', () => {
wrapper = shallowMount(MembersApp, {
propsData: {
namespace: MEMBER_TYPES.group,
namespace: MEMBERS_TAB_TYPES.group,
tabQueryParamValue: TAB_QUERY_PARAM_VALUES.group,
},
store,
@ -57,7 +57,7 @@ describe('MembersApp', () => {
it('renders and scrolls to error alert', async () => {
createComponent({ showError: false, errorMessage: '' });
store.commit(`${MEMBER_TYPES.group}/${RECEIVE_MEMBER_ROLE_ERROR}`, {
store.commit(`${MEMBERS_TAB_TYPES.group}/${RECEIVE_MEMBER_ROLE_ERROR}`, {
error: new Error('Network Error'),
});
@ -77,7 +77,7 @@ describe('MembersApp', () => {
it('does not render and scroll to error alert', async () => {
createComponent();
store.commit(`${MEMBER_TYPES.group}/${HIDE_ERROR}`);
store.commit(`${MEMBERS_TAB_TYPES.group}/${HIDE_ERROR}`);
await nextTick();

View File

@ -5,7 +5,7 @@ import Vuex from 'vuex';
import FilterSortContainer from '~/members/components/filter_sort/filter_sort_container.vue';
import MembersFilteredSearchBar from '~/members/components/filter_sort/members_filtered_search_bar.vue';
import SortDropdown from '~/members/components/filter_sort/sort_dropdown.vue';
import { MEMBER_TYPES } from '~/members/constants';
import { MEMBERS_TAB_TYPES } from '~/members/constants';
Vue.use(Vuex);
@ -15,7 +15,7 @@ describe('FilterSortContainer', () => {
const createComponent = (state) => {
const store = new Vuex.Store({
modules: {
[MEMBER_TYPES.user]: {
[MEMBERS_TAB_TYPES.user]: {
namespaced: true,
state: {
filteredSearchBar: {
@ -35,7 +35,7 @@ describe('FilterSortContainer', () => {
wrapper = shallowMount(FilterSortContainer, {
store,
provide: {
namespace: MEMBER_TYPES.user,
namespace: MEMBERS_TAB_TYPES.user,
},
});
};

View File

@ -6,7 +6,7 @@ import setWindowLocation from 'helpers/set_window_location_helper';
import { visitUrl } from '~/lib/utils/url_utility';
import MembersFilteredSearchBar from '~/members/components/filter_sort/members_filtered_search_bar.vue';
import {
MEMBER_TYPES,
MEMBERS_TAB_TYPES,
FILTERED_SEARCH_TOKEN_TWO_FACTOR,
FILTERED_SEARCH_TOKEN_WITH_INHERITED_PERMISSIONS,
} from '~/members/constants';
@ -31,7 +31,7 @@ describe('MembersFilteredSearchBar', () => {
const createComponent = ({ state = {}, provide = {} } = {}) => {
const store = new Vuex.Store({
modules: {
[MEMBER_TYPES.user]: {
[MEMBERS_TAB_TYPES.user]: {
namespaced: true,
state: {
filteredSearchBar: {
@ -51,7 +51,7 @@ describe('MembersFilteredSearchBar', () => {
provide: {
sourceId: 1,
canManageMembers: true,
namespace: MEMBER_TYPES.user,
namespace: MEMBERS_TAB_TYPES.user,
...provide,
},
store,

View File

@ -6,7 +6,7 @@ import Vuex from 'vuex';
import setWindowLocation from 'helpers/set_window_location_helper';
import * as urlUtilities from '~/lib/utils/url_utility';
import SortDropdown from '~/members/components/filter_sort/sort_dropdown.vue';
import { MEMBER_TYPES, FIELD_KEY_MAX_ROLE } from '~/members/constants';
import { MEMBERS_TAB_TYPES, FIELD_KEY_MAX_ROLE } from '~/members/constants';
Vue.use(Vuex);
@ -18,7 +18,7 @@ describe('SortDropdown', () => {
const createComponent = (state) => {
const store = new Vuex.Store({
modules: {
[MEMBER_TYPES.user]: {
[MEMBERS_TAB_TYPES.user]: {
namespaced: true,
state: {
tableSortableFields: ['account', 'granted', 'expires', 'maxRole', 'lastSignIn'],
@ -38,7 +38,7 @@ describe('SortDropdown', () => {
wrapper = mount(SortDropdown, {
provide: {
sourceId: 1,
namespace: MEMBER_TYPES.user,
namespace: MEMBERS_TAB_TYPES.user,
},
store,
});

View File

@ -7,7 +7,7 @@ import { mountExtended } from 'helpers/vue_test_utils_helper';
import MembersApp from '~/members/components/app.vue';
import MembersTabs from '~/members/components/members_tabs.vue';
import {
MEMBER_TYPES,
MEMBERS_TAB_TYPES,
TAB_QUERY_PARAM_VALUES,
ACTIVE_TAB_QUERY_PARAM_NAME,
FILTERED_SEARCH_TOKEN_GROUPS_WITH_INHERITED_PERMISSIONS,
@ -23,7 +23,7 @@ describe('MembersTabs', () => {
const createComponent = ({ totalItems = 10, provide = {} } = {}) => {
const store = new Vuex.Store({
modules: {
[MEMBER_TYPES.user]: {
[MEMBERS_TAB_TYPES.user]: {
namespaced: true,
state: {
pagination: {
@ -35,7 +35,7 @@ describe('MembersTabs', () => {
},
},
},
[MEMBER_TYPES.group]: {
[MEMBERS_TAB_TYPES.group]: {
namespaced: true,
state: {
pagination: {
@ -49,7 +49,7 @@ describe('MembersTabs', () => {
},
},
},
[MEMBER_TYPES.invite]: {
[MEMBERS_TAB_TYPES.invite]: {
namespaced: true,
state: {
pagination: {
@ -62,7 +62,7 @@ describe('MembersTabs', () => {
},
},
},
[MEMBER_TYPES.accessRequest]: {
[MEMBERS_TAB_TYPES.accessRequest]: {
namespaced: true,
state: {
pagination: {
@ -132,10 +132,10 @@ describe('MembersTabs', () => {
const membersApps = wrapper.findAllComponents(MembersApp).wrappers;
expect(membersApps[0].props('namespace')).toBe(MEMBER_TYPES.user);
expect(membersApps[1].props('namespace')).toBe(MEMBER_TYPES.group);
expect(membersApps[2].props('namespace')).toBe(MEMBER_TYPES.invite);
expect(membersApps[3].props('namespace')).toBe(MEMBER_TYPES.accessRequest);
expect(membersApps[0].props('namespace')).toBe(MEMBERS_TAB_TYPES.user);
expect(membersApps[1].props('namespace')).toBe(MEMBERS_TAB_TYPES.group);
expect(membersApps[2].props('namespace')).toBe(MEMBERS_TAB_TYPES.invite);
expect(membersApps[3].props('namespace')).toBe(MEMBERS_TAB_TYPES.accessRequest);
expect(membersApps[1].props('tabQueryParamValue')).toBe(TAB_QUERY_PARAM_VALUES.group);
expect(membersApps[2].props('tabQueryParamValue')).toBe(TAB_QUERY_PARAM_VALUES.invite);

View File

@ -7,7 +7,7 @@ import { mountExtended, extendedWrapper } from 'helpers/vue_test_utils_helper';
import LeaveModal from '~/members/components/modals/leave_modal.vue';
import {
LEAVE_MODAL_ID,
MEMBER_TYPES,
MEMBERS_TAB_TYPES,
MEMBER_MODEL_TYPE_PROJECT_MEMBER,
} from '~/members/constants';
import UserDeletionObstaclesList from '~/vue_shared/components/user_deletion_obstacles/user_deletion_obstacles_list.vue';
@ -24,7 +24,7 @@ describe('LeaveModal', () => {
const createStore = (state = {}) => {
return new Vuex.Store({
modules: {
[MEMBER_TYPES.user]: {
[MEMBERS_TAB_TYPES.user]: {
namespaced: true,
state: {
memberPath: '/groups/foo-bar/-/group_members/:id',
@ -39,7 +39,7 @@ describe('LeaveModal', () => {
wrapper = mountExtended(LeaveModal, {
store: createStore(state),
provide: {
namespace: MEMBER_TYPES.user,
namespace: MEMBERS_TAB_TYPES.user,
},
propsData: {
member,

View File

@ -5,7 +5,7 @@ import Vue, { nextTick } from 'vue';
// eslint-disable-next-line no-restricted-imports
import Vuex from 'vuex';
import RemoveGroupLinkModal from '~/members/components/modals/remove_group_link_modal.vue';
import { REMOVE_GROUP_LINK_MODAL_ID, MEMBER_TYPES } from '~/members/constants';
import { REMOVE_GROUP_LINK_MODAL_ID, MEMBERS_TAB_TYPES } from '~/members/constants';
import { group } from '../../mock_data';
jest.mock('~/lib/utils/csrf', () => ({ token: 'mock-csrf-token' }));
@ -22,7 +22,7 @@ describe('RemoveGroupLinkModal', () => {
const createStore = (state = {}) => {
return new Vuex.Store({
modules: {
[MEMBER_TYPES.group]: {
[MEMBERS_TAB_TYPES.group]: {
namespaced: true,
state: {
memberPath: '/groups/foo-bar/-/group_links/:id',
@ -40,7 +40,7 @@ describe('RemoveGroupLinkModal', () => {
wrapper = mount(RemoveGroupLinkModal, {
store: createStore(state),
provide: {
namespace: MEMBER_TYPES.group,
namespace: MEMBERS_TAB_TYPES.group,
},
attrs: {
static: true,

View File

@ -5,7 +5,7 @@ import Vue from 'vue';
import Vuex from 'vuex';
import RemoveMemberModal from '~/members/components/modals/remove_member_modal.vue';
import {
MEMBER_TYPES,
MEMBERS_TAB_TYPES,
MEMBER_MODEL_TYPE_GROUP_MEMBER,
MEMBER_MODEL_TYPE_PROJECT_MEMBER,
} from '~/members/constants';
@ -32,7 +32,7 @@ describe('RemoveMemberModal', () => {
const createStore = (removeMemberModalData) =>
new Vuex.Store({
modules: {
[MEMBER_TYPES.user]: {
[MEMBERS_TAB_TYPES.user]: {
namespaced: true,
state: {
removeMemberModalData,
@ -46,7 +46,7 @@ describe('RemoveMemberModal', () => {
wrapper = shallowMount(RemoveMemberModal, {
store: createStore(state),
provide: {
namespace: MEMBER_TYPES.user,
namespace: MEMBERS_TAB_TYPES.user,
},
});
};

Some files were not shown because too many files have changed in this diff Show More