Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
9ff690d328
commit
9f31f06ca0
|
|
@ -442,7 +442,6 @@ Lint/RedundantCopDisableDirective:
|
|||
- 'spec/scripts/duo_chat/reporter_spec.rb'
|
||||
- 'spec/services/alert_management/metric_images/upload_service_spec.rb'
|
||||
- 'spec/services/boards/lists/list_service_spec.rb'
|
||||
- 'spec/services/pages_domains/create_acme_order_service_spec.rb'
|
||||
- 'spec/support/finder_collection.rb'
|
||||
- 'spec/support/forgery_protection.rb'
|
||||
- 'spec/support/helpers/database/multiple_databases_helpers.rb'
|
||||
|
|
|
|||
|
|
@ -1442,7 +1442,6 @@ RSpec/BeEq:
|
|||
- 'spec/services/packages/maven/metadata/create_plugins_xml_service_spec.rb'
|
||||
- 'spec/services/packages/npm/create_package_service_spec.rb'
|
||||
- 'spec/services/pages/delete_service_spec.rb'
|
||||
- 'spec/services/pages_domains/update_service_spec.rb'
|
||||
- 'spec/services/projects/auto_devops/disable_service_spec.rb'
|
||||
- 'spec/services/projects/autocomplete_service_spec.rb'
|
||||
- 'spec/services/projects/batch_open_issues_count_service_spec.rb'
|
||||
|
|
|
|||
|
|
@ -1267,7 +1267,6 @@ RSpec/BeforeAllRoleAssignment:
|
|||
- 'spec/services/packages/mark_packages_for_destruction_service_spec.rb'
|
||||
- 'spec/services/packages/maven/metadata/sync_service_spec.rb'
|
||||
- 'spec/services/packages/rubygems/dependency_resolver_service_spec.rb'
|
||||
- 'spec/services/pages_domains/create_service_spec.rb'
|
||||
- 'spec/services/post_receive_service_spec.rb'
|
||||
- 'spec/services/projects/autocomplete_service_spec.rb'
|
||||
- 'spec/services/projects/container_repository/destroy_service_spec.rb'
|
||||
|
|
|
|||
|
|
@ -2518,7 +2518,6 @@ RSpec/ContextWording:
|
|||
- 'spec/services/packages/rubygems/dependency_resolver_service_spec.rb'
|
||||
- 'spec/services/packages/rubygems/process_gem_service_spec.rb'
|
||||
- 'spec/services/packages/terraform_module/create_package_service_spec.rb'
|
||||
- 'spec/services/pages_domains/obtain_lets_encrypt_certificate_service_spec.rb'
|
||||
- 'spec/services/personal_access_tokens/create_service_spec.rb'
|
||||
- 'spec/services/personal_access_tokens/revoke_service_spec.rb'
|
||||
- 'spec/services/post_receive_service_spec.rb'
|
||||
|
|
|
|||
|
|
@ -360,7 +360,6 @@ RSpec/ExpectInHook:
|
|||
- 'spec/services/packages/maven/metadata/sync_service_spec.rb'
|
||||
- 'spec/services/packages/rubygems/process_gem_service_spec.rb'
|
||||
- 'spec/services/packages/update_package_file_service_spec.rb'
|
||||
- 'spec/services/pages_domains/obtain_lets_encrypt_certificate_service_spec.rb'
|
||||
- 'spec/services/projects/branches_by_mode_service_spec.rb'
|
||||
- 'spec/services/projects/container_repository/delete_tags_service_spec.rb'
|
||||
- 'spec/services/projects/container_repository/gitlab/delete_tags_service_spec.rb'
|
||||
|
|
|
|||
|
|
@ -222,7 +222,6 @@ RSpec/VerifiedDoubleReference:
|
|||
- 'spec/services/issues/close_service_spec.rb'
|
||||
- 'spec/services/merge_requests/after_create_service_spec.rb'
|
||||
- 'spec/services/merge_requests/mergeability/check_lfs_file_locks_service_spec.rb'
|
||||
- 'spec/services/pages_domains/create_acme_order_service_spec.rb'
|
||||
- 'spec/services/projects/destroy_service_spec.rb'
|
||||
- 'spec/services/projects/fork_service_spec.rb'
|
||||
- 'spec/services/repositories/replicate_service_spec.rb'
|
||||
|
|
|
|||
|
|
@ -44,17 +44,6 @@ Style/IfUnlessModifier:
|
|||
- 'app/models/ci/pending_build.rb'
|
||||
- 'app/models/ci/pipeline.rb'
|
||||
- 'app/models/ci/runner.rb'
|
||||
- 'app/models/ci/running_build.rb'
|
||||
- 'app/models/clusters/cluster.rb'
|
||||
- 'app/models/clusters/clusters_hierarchy.rb'
|
||||
- 'app/models/clusters/platforms/kubernetes.rb'
|
||||
- 'app/models/commit.rb'
|
||||
- 'app/models/concerns/atomic_internal_id.rb'
|
||||
- 'app/models/concerns/avatarable.rb'
|
||||
- 'app/models/concerns/bulk_insert_safe.rb'
|
||||
- 'app/models/concerns/bulk_insertable_associations.rb'
|
||||
- 'app/models/concerns/bulk_users_by_email_load.rb'
|
||||
- 'app/models/concerns/cache_markdown_field.rb'
|
||||
- 'app/models/concerns/ci/artifactable.rb'
|
||||
- 'app/models/concerns/deprecated_assignee.rb'
|
||||
- 'app/models/concerns/group_descendant.rb'
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<script>
|
||||
import { GlBadge, GlButton, GlTab, GlTabs, GlSprintf, GlIcon, GlLink } from '@gitlab/ui';
|
||||
import { GlAvatar, GlBadge, GlButton, GlTab, GlTabs, GlSprintf, GlIcon, GlLink } from '@gitlab/ui';
|
||||
import VueRouter from 'vue-router';
|
||||
import { n__, s__, sprintf } from '~/locale';
|
||||
import TitleArea from '~/vue_shared/components/registry/title_area.vue';
|
||||
|
|
@ -46,6 +46,7 @@ export default {
|
|||
ActionsDropdown,
|
||||
DeleteModelDisclosureDropdownItem,
|
||||
TitleArea,
|
||||
GlAvatar,
|
||||
GlButton,
|
||||
GlTabs,
|
||||
GlTab,
|
||||
|
|
@ -169,6 +170,12 @@ export default {
|
|||
showCreatedDetail() {
|
||||
return this.model?.author && this.model?.createdAt;
|
||||
},
|
||||
showModelAuthor() {
|
||||
return this.model?.author;
|
||||
},
|
||||
showModelLatestVersion() {
|
||||
return Boolean(this.model?.latestVersion);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
goTo(name) {
|
||||
|
|
@ -197,8 +204,11 @@ export default {
|
|||
i18n: {
|
||||
createModelVersionLinkTitle: s__('MlModelRegistry|Create model version'),
|
||||
editModelButtonLabel: s__('MlModelRegistry|Edit model'),
|
||||
tabTitle: s__('MlModelRegistry|Model card'),
|
||||
tabInnerTitle: s__('MlModelRegistry|Versions'),
|
||||
tabModelCardTitle: s__('MlModelRegistry|Model card'),
|
||||
tabVersionsTitle: s__('MlModelRegistry|Versions'),
|
||||
versionCountTitle: s__('MlModelRegistry|Total versions'),
|
||||
latestVersionTitle: s__('MlModelRegistry|Latest version'),
|
||||
authorTitle: s__('MlModelRegistry|Publisher'),
|
||||
},
|
||||
modelVersionEntity: MODEL_ENTITIES.modelVersion,
|
||||
ROUTE_DETAILS,
|
||||
|
|
@ -260,23 +270,62 @@ export default {
|
|||
</template>
|
||||
</title-area>
|
||||
|
||||
<load-or-error-or-show :is-loading="isLoading" :error-message="errorMessage">
|
||||
<gl-tabs class="gl-mt-4" :value="tabIndex">
|
||||
<gl-tab
|
||||
v-if="latestVersion"
|
||||
:title="s__('MlModelRegistry|Model card')"
|
||||
@click="goTo($options.ROUTE_DETAILS)"
|
||||
/>
|
||||
<gl-tab v-if="latestVersion" @click="goTo($options.ROUTE_VERSIONS)">
|
||||
<template #title>
|
||||
{{ s__('MlModelRegistry|Versions') }}
|
||||
<gl-badge class="gl-tab-counter-badge">{{ versionCount }}</gl-badge>
|
||||
</template>
|
||||
</gl-tab>
|
||||
<div class="gl-grid gl-gap-3 md:gl-grid-cols-4">
|
||||
<div class="gl-pr-8 md:gl-col-span-3">
|
||||
<load-or-error-or-show :is-loading="isLoading" :error-message="errorMessage">
|
||||
<gl-tabs class="gl-mt-4" :value="tabIndex">
|
||||
<gl-tab
|
||||
v-if="latestVersion"
|
||||
:title="$options.i18n.tabModelCardTitle"
|
||||
@click="goTo($options.ROUTE_DETAILS)"
|
||||
/>
|
||||
<gl-tab v-if="latestVersion" @click="goTo($options.ROUTE_VERSIONS)">
|
||||
<template #title>
|
||||
{{ $options.i18n.tabVersionsTitle }}
|
||||
<gl-badge class="gl-tab-counter-badge">{{ versionCount }}</gl-badge>
|
||||
</template>
|
||||
</gl-tab>
|
||||
|
||||
<router-view :model-id="model.id" :model="model" />
|
||||
</gl-tabs>
|
||||
</load-or-error-or-show>
|
||||
<router-view :model-id="model.id" :model="model" />
|
||||
</gl-tabs>
|
||||
</load-or-error-or-show>
|
||||
</div>
|
||||
|
||||
<div class="gl-pt-6 md:gl-col-span-1">
|
||||
<div>
|
||||
<div class="gl-text-lg gl-font-bold">{{ $options.i18n.authorTitle }}</div>
|
||||
<div v-if="showModelAuthor" class="gl-pt-2 gl-text-gray-500">
|
||||
<gl-link
|
||||
data-testid="sidebar-author-link"
|
||||
class="js-user-link gl-font-bold !gl-text-gray-500"
|
||||
:href="model.author.webUrl"
|
||||
>
|
||||
<gl-avatar :label="model.author.name" :src="model.author.avatarUrl" :size="24" />
|
||||
{{ model.author.name }}
|
||||
</gl-link>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gl-mt-5">
|
||||
<div class="gl-text-lg gl-font-bold">{{ $options.i18n.latestVersionTitle }}</div>
|
||||
<div v-if="showModelLatestVersion" class="gl-pt-2 gl-text-gray-500">
|
||||
<gl-link
|
||||
data-testid="sidebar-latest-version-link"
|
||||
:href="model.latestVersion._links.showPath"
|
||||
>
|
||||
{{ model.latestVersion.version }}
|
||||
</gl-link>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gl-mt-5">
|
||||
<div class="gl-text-lg gl-font-bold">{{ $options.i18n.versionCountTitle }}</div>
|
||||
<div v-if="showCreatedDetail" class="gl-pt-2 gl-text-gray-500">
|
||||
<span data-testid="sidebar-version-count">
|
||||
{{ versionCount }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</delete-model>
|
||||
|
|
|
|||
|
|
@ -4,6 +4,9 @@ import { s__, __ } from '~/locale';
|
|||
export const RESOURCE_TYPE_GROUPS = 'groups';
|
||||
export const RESOURCE_TYPE_PROJECTS = 'projects';
|
||||
|
||||
export const ACCESS_LEVEL_DEFAULT = 'default';
|
||||
export const ACCESS_LEVEL_OWNER = 'owner';
|
||||
|
||||
export const ORGANIZATION_ROOT_ROUTE_NAME = 'root';
|
||||
|
||||
export const FORM_FIELD_NAME = 'name';
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
import { __, s__ } from '~/locale';
|
||||
import { createAlert } from '~/alert';
|
||||
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
|
||||
import organizationUsersQuery from '../graphql/organization_users.query.graphql';
|
||||
import organizationUsersQuery from '../graphql/queries/organization_users.query.graphql';
|
||||
import { ORGANIZATION_USERS_PER_PAGE } from '../constants';
|
||||
import UsersView from './users_view.vue';
|
||||
|
||||
|
|
@ -51,8 +51,16 @@ export default {
|
|||
const { nodes, pageInfo } = data.organization.organizationUsers;
|
||||
this.pageInfo = pageInfo;
|
||||
|
||||
return nodes.map(({ badges, user }) => {
|
||||
return { ...user, id: getIdFromGraphQLId(user.id), badges, email: user.publicEmail };
|
||||
return nodes.map(({ id, badges, accessLevel, userPermissions, user }) => {
|
||||
return {
|
||||
...user,
|
||||
gid: id,
|
||||
id: getIdFromGraphQLId(user.id),
|
||||
badges,
|
||||
accessLevel,
|
||||
userPermissions,
|
||||
email: user.publicEmail,
|
||||
};
|
||||
});
|
||||
},
|
||||
error(error) {
|
||||
|
|
|
|||
|
|
@ -1,15 +1,40 @@
|
|||
<script>
|
||||
import { GlLoadingIcon, GlKeysetPagination } from '@gitlab/ui';
|
||||
import { GlLoadingIcon, GlKeysetPagination, GlCollapsibleListbox } from '@gitlab/ui';
|
||||
import UsersTable from '~/vue_shared/components/users_table/users_table.vue';
|
||||
import {
|
||||
FIELD_NAME,
|
||||
FIELD_ORGANIZATION_ROLE,
|
||||
FIELD_CREATED_AT,
|
||||
FIELD_LAST_ACTIVITY_ON,
|
||||
} from '~/vue_shared/components/users_table/constants';
|
||||
import { ACCESS_LEVEL_DEFAULT, ACCESS_LEVEL_OWNER } from '~/organizations/shared/constants';
|
||||
import { __ } from '~/locale';
|
||||
|
||||
export default {
|
||||
name: 'UsersView',
|
||||
components: {
|
||||
GlLoadingIcon,
|
||||
GlKeysetPagination,
|
||||
GlCollapsibleListbox,
|
||||
UsersTable,
|
||||
},
|
||||
inject: ['paths'],
|
||||
roleListboxItems: [
|
||||
{
|
||||
text: __('User'),
|
||||
value: ACCESS_LEVEL_DEFAULT.toUpperCase(),
|
||||
},
|
||||
{
|
||||
text: __('Owner'),
|
||||
value: ACCESS_LEVEL_OWNER.toUpperCase(),
|
||||
},
|
||||
],
|
||||
usersTable: {
|
||||
fieldsToRender: [FIELD_NAME, FIELD_ORGANIZATION_ROLE, FIELD_CREATED_AT, FIELD_LAST_ACTIVITY_ON],
|
||||
columnWidths: {
|
||||
[FIELD_ORGANIZATION_ROLE]: 'gl-w-20',
|
||||
},
|
||||
},
|
||||
props: {
|
||||
users: {
|
||||
type: Array,
|
||||
|
|
@ -26,6 +51,11 @@ export default {
|
|||
default: false,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
roleListboxItemText(accessLevel) {
|
||||
return this.$options.roleListboxItems.find((item) => item.value === accessLevel).text;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
|
|
@ -33,7 +63,23 @@ export default {
|
|||
<div>
|
||||
<gl-loading-icon v-if="loading" class="gl-mt-5" size="md" />
|
||||
<template v-else>
|
||||
<users-table :users="users" :admin-user-path="paths.adminUser" />
|
||||
<users-table
|
||||
:users="users"
|
||||
:admin-user-path="paths.adminUser"
|
||||
:fields-to-render="$options.usersTable.fieldsToRender"
|
||||
:column-widths="$options.usersTable.columnWidths"
|
||||
>
|
||||
<template #organization-role="{ user }">
|
||||
<gl-collapsible-listbox
|
||||
v-if="user.userPermissions.adminOrganization"
|
||||
:selected="user.accessLevel.stringValue"
|
||||
block
|
||||
toggle-class="gl-form-input-xl"
|
||||
:items="$options.roleListboxItems"
|
||||
/>
|
||||
<span v-else>{{ roleListboxItemText(user.accessLevel.stringValue) }}</span>
|
||||
</template>
|
||||
</users-table>
|
||||
<div class="gl-flex gl-justify-center">
|
||||
<gl-keyset-pagination v-bind="pageInfo" @prev="$emit('prev')" @next="$emit('next')" />
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -25,6 +25,12 @@ query getOrganizationUsers(
|
|||
createdAt
|
||||
lastActivityOn
|
||||
}
|
||||
accessLevel {
|
||||
stringValue
|
||||
}
|
||||
userPermissions {
|
||||
adminOrganization
|
||||
}
|
||||
}
|
||||
pageInfo {
|
||||
...PageInfo
|
||||
|
|
@ -200,7 +200,7 @@ export default {
|
|||
<div ref="overlay" class="super-sidebar-overlay" @click="collapseSidebar"></div>
|
||||
<gl-button
|
||||
v-if="sidebarData.is_logged_in"
|
||||
class="super-sidebar-skip-to gl-sr-only gl-fixed gl-left-0 gl-m-3 focus:gl-not-sr-only"
|
||||
class="super-sidebar-skip-to gl-sr-only !gl-fixed gl-left-0 gl-m-3 focus:gl-not-sr-only"
|
||||
data-testid="super-sidebar-skip-to"
|
||||
href="#content-body"
|
||||
variant="confirm"
|
||||
|
|
|
|||
|
|
@ -1,3 +1,11 @@
|
|||
export const USER_AVATAR_SIZE = 32;
|
||||
|
||||
export const LENGTH_OF_USER_NOTE_TOOLTIP = 100;
|
||||
|
||||
export const FIELD_NAME = 'name';
|
||||
export const FIELD_ORGANIZATION_ROLE = 'organizationRole';
|
||||
export const FIELD_PROJECTS_COUNT = 'projectsCount';
|
||||
export const FIELD_GROUP_COUNT = 'groupCount';
|
||||
export const FIELD_CREATED_AT = 'createdAt';
|
||||
export const FIELD_LAST_ACTIVITY_ON = 'lastActivityOn';
|
||||
export const FIELD_SETTINGS = 'settings';
|
||||
|
|
|
|||
|
|
@ -1,10 +1,19 @@
|
|||
<script>
|
||||
import NO_USERS_SVG from '@gitlab/svgs/dist/illustrations/empty-state/empty-user-settings-md.svg';
|
||||
import { GlSkeletonLoader, GlTable } from '@gitlab/ui';
|
||||
import { __ } from '~/locale';
|
||||
import { __, s__ } from '~/locale';
|
||||
import EmptyResult from '~/vue_shared/components/empty_result.vue';
|
||||
import UserDate from '~/vue_shared/components/user_date.vue';
|
||||
import UserAvatar from './user_avatar.vue';
|
||||
import {
|
||||
FIELD_NAME,
|
||||
FIELD_ORGANIZATION_ROLE,
|
||||
FIELD_PROJECTS_COUNT,
|
||||
FIELD_GROUP_COUNT,
|
||||
FIELD_CREATED_AT,
|
||||
FIELD_LAST_ACTIVITY_ON,
|
||||
FIELD_SETTINGS,
|
||||
} from './constants';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
|
@ -33,39 +42,79 @@ export default {
|
|||
required: false,
|
||||
default: false,
|
||||
},
|
||||
fieldsToRender: {
|
||||
type: Array,
|
||||
required: false,
|
||||
default() {
|
||||
return [
|
||||
FIELD_NAME,
|
||||
FIELD_PROJECTS_COUNT,
|
||||
FIELD_GROUP_COUNT,
|
||||
FIELD_CREATED_AT,
|
||||
FIELD_LAST_ACTIVITY_ON,
|
||||
FIELD_SETTINGS,
|
||||
];
|
||||
},
|
||||
},
|
||||
columnWidths: {
|
||||
type: Object,
|
||||
required: false,
|
||||
default() {
|
||||
return {
|
||||
[FIELD_NAME]: 'gl-w-8/20',
|
||||
[FIELD_PROJECTS_COUNT]: 'gl-w-2/20',
|
||||
[FIELD_GROUP_COUNT]: 'gl-w-2/20',
|
||||
[FIELD_CREATED_AT]: 'gl-w-3/20',
|
||||
[FIELD_LAST_ACTIVITY_ON]: 'gl-w-3/20',
|
||||
[FIELD_SETTINGS]: 'gl-w-2/20',
|
||||
};
|
||||
},
|
||||
},
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
key: 'name',
|
||||
label: __('Name'),
|
||||
thClass: 'gl-w-8/20',
|
||||
computed: {
|
||||
availableFields() {
|
||||
return [
|
||||
{
|
||||
key: FIELD_NAME,
|
||||
label: __('Name'),
|
||||
thClass: this.columnWidths[FIELD_NAME],
|
||||
},
|
||||
{
|
||||
key: FIELD_ORGANIZATION_ROLE,
|
||||
label: s__('Organization|Organization role'),
|
||||
thClass: this.columnWidths[FIELD_ORGANIZATION_ROLE],
|
||||
},
|
||||
{
|
||||
key: FIELD_PROJECTS_COUNT,
|
||||
label: __('Projects'),
|
||||
thClass: this.columnWidths[FIELD_PROJECTS_COUNT],
|
||||
},
|
||||
{
|
||||
key: FIELD_GROUP_COUNT,
|
||||
label: __('Groups'),
|
||||
thClass: this.columnWidths[FIELD_GROUP_COUNT],
|
||||
},
|
||||
{
|
||||
key: FIELD_CREATED_AT,
|
||||
label: __('Created on'),
|
||||
thClass: this.columnWidths[FIELD_CREATED_AT],
|
||||
},
|
||||
{
|
||||
key: FIELD_LAST_ACTIVITY_ON,
|
||||
label: __('Last activity'),
|
||||
thClass: this.columnWidths[FIELD_LAST_ACTIVITY_ON],
|
||||
},
|
||||
{
|
||||
key: FIELD_SETTINGS,
|
||||
label: '',
|
||||
thClass: this.columnWidths[FIELD_SETTINGS],
|
||||
},
|
||||
];
|
||||
},
|
||||
{
|
||||
key: 'projectsCount',
|
||||
label: __('Projects'),
|
||||
thClass: 'gl-w-2/20',
|
||||
fields() {
|
||||
return this.availableFields.filter((field) => this.fieldsToRender.includes(field.key));
|
||||
},
|
||||
{
|
||||
key: 'groupCount',
|
||||
label: __('Groups'),
|
||||
thClass: 'gl-w-2/20',
|
||||
},
|
||||
{
|
||||
key: 'createdAt',
|
||||
label: __('Created on'),
|
||||
thClass: 'gl-w-3/20',
|
||||
},
|
||||
{
|
||||
key: 'lastActivityOn',
|
||||
label: __('Last activity'),
|
||||
thClass: 'gl-w-3/20',
|
||||
},
|
||||
{
|
||||
key: 'settings',
|
||||
label: '',
|
||||
thClass: 'gl-w-2/20',
|
||||
},
|
||||
],
|
||||
},
|
||||
NO_USERS_SVG,
|
||||
};
|
||||
</script>
|
||||
|
|
@ -74,7 +123,7 @@ export default {
|
|||
<gl-table
|
||||
v-if="users.length > 0"
|
||||
:items="users"
|
||||
:fields="$options.fields"
|
||||
:fields="fields"
|
||||
stacked="md"
|
||||
:tbody-tr-attr="{ 'data-testid': 'user-row-content' }"
|
||||
>
|
||||
|
|
@ -82,6 +131,10 @@ export default {
|
|||
<user-avatar :user="user" :admin-user-path="adminUserPath" />
|
||||
</template>
|
||||
|
||||
<template v-if="$scopedSlots['organization-role']" #cell(organizationRole)="{ item: user }">
|
||||
<slot name="organization-role" :user="user"></slot>
|
||||
</template>
|
||||
|
||||
<template #cell(createdAt)="{ item: { createdAt } }">
|
||||
<user-date :date="createdAt" />
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,14 +1,16 @@
|
|||
<script>
|
||||
import { GlButton, GlModal, GlDisclosureDropdownItem } from '@gitlab/ui';
|
||||
import { GlButton, GlModal, GlDisclosureDropdownItem, GlTooltipDirective } from '@gitlab/ui';
|
||||
import { visitUrl } from '~/lib/utils/url_utility';
|
||||
import { __ } from '~/locale';
|
||||
import { setNewWorkItemCache } from '~/work_items/graphql/cache_utils';
|
||||
import { isWorkItemItemValidEnum } from '~/work_items/utils';
|
||||
import { isMetaClick } from '~/lib/utils/common_utils';
|
||||
import { isWorkItemItemValidEnum, newWorkItemPath } from '~/work_items/utils';
|
||||
import {
|
||||
I18N_NEW_WORK_ITEM_BUTTON_LABEL,
|
||||
I18N_WORK_ITEM_CREATED,
|
||||
sprintfWorkItem,
|
||||
I18N_WORK_ITEM_ERROR_FETCHING_TYPES,
|
||||
ROUTES,
|
||||
} from '../constants';
|
||||
import namespaceWorkItemTypesQuery from '../graphql/namespace_work_item_types.query.graphql';
|
||||
import CreateWorkItem from './create_work_item.vue';
|
||||
|
|
@ -20,6 +22,9 @@ export default {
|
|||
GlModal,
|
||||
GlDisclosureDropdownItem,
|
||||
},
|
||||
directives: {
|
||||
GlTooltip: GlTooltipDirective,
|
||||
},
|
||||
inject: ['fullPath'],
|
||||
props: {
|
||||
description: {
|
||||
|
|
@ -117,18 +122,26 @@ export default {
|
|||
},
|
||||
},
|
||||
computed: {
|
||||
useVueRouter() {
|
||||
return (
|
||||
!this.asDropdownItem &&
|
||||
this.$router &&
|
||||
this.$router.options.routes.some((route) => route.name === 'workItem')
|
||||
);
|
||||
},
|
||||
newWorkItemPath() {
|
||||
return newWorkItemPath({
|
||||
fullPath: this.fullPath,
|
||||
isGroup: this.isGroup,
|
||||
workItemTypeName: this.workItemTypeName,
|
||||
});
|
||||
},
|
||||
newWorkItemText() {
|
||||
return sprintfWorkItem(I18N_NEW_WORK_ITEM_BUTTON_LABEL, this.workItemTypeName);
|
||||
},
|
||||
workItemCreatedText() {
|
||||
return sprintfWorkItem(I18N_WORK_ITEM_CREATED, this.workItemTypeName);
|
||||
},
|
||||
dropdownItem() {
|
||||
return {
|
||||
text: this.newWorkItemText,
|
||||
action: this.showModal,
|
||||
};
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
visible: {
|
||||
|
|
@ -143,7 +156,15 @@ export default {
|
|||
this.$emit('hideModal');
|
||||
this.isVisible = false;
|
||||
},
|
||||
showModal() {
|
||||
showModal(event) {
|
||||
if (isMetaClick(event)) {
|
||||
// opening in a new tab
|
||||
return;
|
||||
}
|
||||
|
||||
// don't follow the link for normal clicks - open in modal
|
||||
event.preventDefault();
|
||||
|
||||
this.isVisible = true;
|
||||
},
|
||||
handleCreated(workItem) {
|
||||
|
|
@ -151,11 +172,7 @@ export default {
|
|||
action: {
|
||||
text: __('View details'),
|
||||
onClick: () => {
|
||||
if (
|
||||
!this.asDropdownItem &&
|
||||
this.$router &&
|
||||
this.$router.options.routes.some((route) => route.name === 'workItem')
|
||||
) {
|
||||
if (this.useVueRouter) {
|
||||
this.$router.push({ name: 'workItem', params: { iid: workItem.iid } });
|
||||
} else {
|
||||
visitUrl(workItem.webUrl);
|
||||
|
|
@ -175,6 +192,20 @@ export default {
|
|||
}
|
||||
this.hideModal();
|
||||
},
|
||||
redirectToNewPage(event) {
|
||||
if (isMetaClick(event)) {
|
||||
// opening in a new tab
|
||||
return;
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
if (this.useVueRouter) {
|
||||
this.$router.push({ name: ROUTES.new });
|
||||
} else {
|
||||
visitUrl(this.newWorkItemPath);
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
@ -182,12 +213,21 @@ export default {
|
|||
<template>
|
||||
<div>
|
||||
<template v-if="!hideButton">
|
||||
<gl-disclosure-dropdown-item v-if="asDropdownItem" :item="dropdownItem" />
|
||||
<!-- overriding default slow because using item.action doesn't pass the click event, so can't prevent href nav -->
|
||||
<gl-disclosure-dropdown-item v-if="asDropdownItem">
|
||||
<!-- using an a instead of gl-link to prevent unwanted underline style when active -->
|
||||
<template #default
|
||||
><a class="gl-new-dropdown-item-content" :href="newWorkItemPath" @click="showModal"
|
||||
><span class="gl-new-dropdown-item-text-wrapper">{{ newWorkItemText }}</span></a
|
||||
></template
|
||||
>
|
||||
</gl-disclosure-dropdown-item>
|
||||
<gl-button
|
||||
v-else
|
||||
category="primary"
|
||||
variant="confirm"
|
||||
data-testid="new-epic-button"
|
||||
:href="newWorkItemPath"
|
||||
@click="showModal"
|
||||
>{{ newWorkItemText }}
|
||||
</gl-button>
|
||||
|
|
@ -196,11 +236,27 @@ export default {
|
|||
modal-id="create-work-item-modal"
|
||||
modal-class="create-work-item-modal"
|
||||
:visible="isVisible"
|
||||
:title="newWorkItemText"
|
||||
size="lg"
|
||||
hide-footer
|
||||
@hide="hideModal"
|
||||
>
|
||||
<template #modal-header>
|
||||
<div class="gl-text gl-flex gl-w-full gl-items-center gl-gap-x-2">
|
||||
<h2 class="modal-title">{{ newWorkItemText }}</h2>
|
||||
<gl-button
|
||||
v-gl-tooltip
|
||||
data-testid="new-work-item-modal-link"
|
||||
:href="newWorkItemPath"
|
||||
:title="__('Open in full page')"
|
||||
category="tertiary"
|
||||
class="gl-text-secondary"
|
||||
icon="maximize"
|
||||
size="small"
|
||||
:aria-label="__('Open in full page')"
|
||||
@click="redirectToNewPage"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<create-work-item
|
||||
:description="description"
|
||||
hide-form-title
|
||||
|
|
|
|||
|
|
@ -171,6 +171,7 @@ export const WORK_ITEMS_TYPE_MAP = {
|
|||
icon: `issue-type-issue`,
|
||||
name: s__('WorkItem|Issue'),
|
||||
value: WORK_ITEM_TYPE_VALUE_ISSUE,
|
||||
routeParamName: 'issues',
|
||||
},
|
||||
[WORK_ITEM_TYPE_ENUM_TASK]: {
|
||||
icon: `issue-type-task`,
|
||||
|
|
@ -201,6 +202,7 @@ export const WORK_ITEMS_TYPE_MAP = {
|
|||
icon: `epic`,
|
||||
name: s__('WorkItem|Epic'),
|
||||
value: WORK_ITEM_TYPE_VALUE_EPIC,
|
||||
routeParamName: 'epics',
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import {
|
|||
WORK_ITEM_TYPE_ENUM_OBJECTIVE,
|
||||
WORK_ITEM_TYPE_ENUM_KEY_RESULT,
|
||||
WORK_ITEM_TYPE_ENUM_REQUIREMENTS,
|
||||
WORK_ITEM_TYPE_ROUTE_WORK_ITEM,
|
||||
NEW_WORK_ITEM_GID,
|
||||
DEFAULT_PAGE_SIZE_CHILD_ITEMS,
|
||||
} from './constants';
|
||||
|
|
@ -154,6 +155,15 @@ export const markdownPreviewPath = ({ fullPath, iid, isGroup = false }) => {
|
|||
return `${domain}/${basePath}/-/preview_markdown?target_type=WorkItem&target_id=${iid}`;
|
||||
};
|
||||
|
||||
// the path for creating a new work item of that type, e.g. /groups/gitlab-org/-/epics/new
|
||||
export const newWorkItemPath = ({ fullPath, isGroup = false, workItemTypeName }) => {
|
||||
const domain = gon.relative_url_root || '';
|
||||
const basePath = isGroup ? `groups/${fullPath}` : fullPath;
|
||||
const type =
|
||||
WORK_ITEMS_TYPE_MAP[workItemTypeName]?.routeParamName || WORK_ITEM_TYPE_ROUTE_WORK_ITEM;
|
||||
return `${domain}/${basePath}/-/${type}/new`;
|
||||
};
|
||||
|
||||
export const getDisplayReference = (workItemFullPath, workitemReference) => {
|
||||
// The reference is replaced by work item fullpath in case the project and group are same.
|
||||
// e.g., gitlab-org/gitlab-test#45 will be shown as #45
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ module Types
|
|||
class OrganizationUser < BasePermissionType
|
||||
graphql_name 'OrganizationUserPermissions'
|
||||
|
||||
abilities :remove_user, :delete_user
|
||||
abilities :remove_user, :delete_user, :admin_organization
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ module ApplicationSettingImplementation
|
|||
disabled_direct_code_suggestions: false,
|
||||
disabled_oauth_sign_in_sources: [],
|
||||
disable_password_authentication_for_users_with_sso_identities: false,
|
||||
dns_rebinding_protection_enabled: true,
|
||||
dns_rebinding_protection_enabled: Settings.gitlab['dns_rebinding_protection_enabled'],
|
||||
domain_allowlist: Settings.gitlab['domain_allowlist'],
|
||||
dsa_key_restriction: default_min_key_size(:dsa),
|
||||
ecdsa_key_restriction: default_min_key_size(:ecdsa),
|
||||
|
|
|
|||
|
|
@ -17,9 +17,7 @@ module Ci
|
|||
enum runner_type: ::Ci::Runner.runner_types
|
||||
|
||||
def self.upsert_build!(build)
|
||||
if build.runner.nil?
|
||||
raise ArgumentError, 'build has not been picked by a runner'
|
||||
end
|
||||
raise ArgumentError, 'build has not been picked by a runner' if build.runner.nil?
|
||||
|
||||
# Owner namespace of the runner that executed the build
|
||||
runner_owner_namespace_id = build.runner.owner_runner_namespace.namespace_id if build.runner.group_type?
|
||||
|
|
|
|||
|
|
@ -324,9 +324,7 @@ module Clusters
|
|||
.where(environment_scope: environment_scope)
|
||||
.where.not(id: id)
|
||||
|
||||
if duplicate_management_clusters.any?
|
||||
errors.add(:environment_scope, 'cannot add duplicated environment scope')
|
||||
end
|
||||
errors.add(:environment_scope, 'cannot add duplicated environment scope') if duplicate_management_clusters.any?
|
||||
end
|
||||
|
||||
def unique_environment_scope
|
||||
|
|
@ -395,15 +393,11 @@ module Clusters
|
|||
end
|
||||
|
||||
def no_groups
|
||||
if groups.any?
|
||||
errors.add(:cluster, 'cannot have groups assigned')
|
||||
end
|
||||
errors.add(:cluster, 'cannot have groups assigned') if groups.any?
|
||||
end
|
||||
|
||||
def no_projects
|
||||
if projects.any?
|
||||
errors.add(:cluster, 'cannot have projects assigned')
|
||||
end
|
||||
errors.add(:cluster, 'cannot have projects assigned') if projects.any?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -38,9 +38,7 @@ module Clusters
|
|||
raise ArgumentError, "unknown type for #{clusterable}"
|
||||
end
|
||||
|
||||
if clusterable.is_a?(::Project)
|
||||
cte << same_namespace_management_clusters_query
|
||||
end
|
||||
cte << same_namespace_management_clusters_query if clusterable.is_a?(::Project)
|
||||
|
||||
cte << base_query
|
||||
cte << parent_query(cte)
|
||||
|
|
|
|||
|
|
@ -236,9 +236,7 @@ module Clusters
|
|||
def build_kube_client!
|
||||
raise "Incomplete settings" unless api_url
|
||||
|
||||
unless (username && password) || token
|
||||
raise "Either username/password or token is required to access API"
|
||||
end
|
||||
raise "Either username/password or token is required to access API" unless (username && password) || token
|
||||
|
||||
Gitlab::Kubernetes::KubeClient.new(
|
||||
api_url,
|
||||
|
|
@ -290,9 +288,7 @@ module Clusters
|
|||
end
|
||||
|
||||
def no_namespace
|
||||
if namespace
|
||||
errors.add(:namespace, 'only allowed for project cluster')
|
||||
end
|
||||
errors.add(:namespace, 'only allowed for project cluster') if namespace
|
||||
end
|
||||
|
||||
def prevent_modification
|
||||
|
|
|
|||
|
|
@ -147,9 +147,7 @@ class Commit
|
|||
# Commit in turn expects Time-like instances upon input, so we have to
|
||||
# manually parse these values.
|
||||
hash.each do |key, value|
|
||||
if key.to_s.end_with?(date_suffix) && value.is_a?(String)
|
||||
hash[key] = Time.zone.parse(value)
|
||||
end
|
||||
hash[key] = Time.zone.parse(value) if key.to_s.end_with?(date_suffix) && value.is_a?(String)
|
||||
end
|
||||
|
||||
from_hash(hash, project)
|
||||
|
|
@ -293,9 +291,7 @@ class Commit
|
|||
}
|
||||
}
|
||||
|
||||
if with_changed_files
|
||||
data.merge!(repo_changes)
|
||||
end
|
||||
data.merge!(repo_changes) if with_changed_files
|
||||
|
||||
data
|
||||
end
|
||||
|
|
|
|||
|
|
@ -135,9 +135,7 @@ module AtomicInternalId
|
|||
internal_id_scope_usage,
|
||||
value)
|
||||
|
||||
if did_reset
|
||||
write_attribute(column, nil)
|
||||
end
|
||||
write_attribute(column, nil) if did_reset
|
||||
end
|
||||
|
||||
read_attribute(column)
|
||||
|
|
|
|||
|
|
@ -57,13 +57,9 @@ module Avatarable
|
|||
end
|
||||
|
||||
def avatar_path(only_path: true, size: nil)
|
||||
unless self.try(:id)
|
||||
return uncached_avatar_path(only_path: only_path, size: size)
|
||||
end
|
||||
return uncached_avatar_path(only_path: only_path, size: size) unless self.try(:id)
|
||||
|
||||
if self.try(:should_use_security_policy_bot_avatar?)
|
||||
return self.security_policy_bot_static_avatar_path(size)
|
||||
end
|
||||
return self.security_policy_bot_static_avatar_path(size) if self.try(:should_use_security_policy_bot_avatar?)
|
||||
|
||||
# Cache this avatar path only within the request because avatars in
|
||||
# object storage may be generated with time-limited, signed URLs.
|
||||
|
|
|
|||
|
|
@ -157,9 +157,7 @@ module BulkInsertSafe
|
|||
|
||||
# Handle insertions for tables with a composite primary key
|
||||
primary_keys = connection.schema_cache.primary_keys(table_name)
|
||||
if unique_by.blank? && (composite_primary_key || primary_key != primary_keys)
|
||||
unique_by = primary_keys
|
||||
end
|
||||
unique_by = primary_keys if unique_by.blank? && (composite_primary_key || primary_key != primary_keys)
|
||||
|
||||
transaction do
|
||||
items.each_slice(batch_size).flat_map do |item_batch|
|
||||
|
|
|
|||
|
|
@ -102,9 +102,7 @@ module BulkInsertableAssociations
|
|||
items.each do |item|
|
||||
item[reflection.foreign_key] = primary_key_value
|
||||
|
||||
if reflection.type
|
||||
item[reflection.type] = self.class.polymorphic_name
|
||||
end
|
||||
item[reflection.type] = self.class.polymorphic_name if reflection.type
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,9 @@ module BulkUsersByEmailLoad
|
|||
grouped_users_by_email = User.by_any_email(emails, confirmed: true).preload(:emails).group_by(&:all_emails)
|
||||
|
||||
grouped_users_by_email.each_with_object({}) do |(found_emails, users), h|
|
||||
found_emails.each { |e| h[e] = users.first if emails.include?(e) } # don't include all emails for an account, only the ones we want
|
||||
found_emails.each do |e| # don't include all emails for an account, only the ones we want
|
||||
h[e] = users.first if emails.include?(e)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -40,9 +40,7 @@ module CacheMarkdownField
|
|||
# Banzai is less strict about authors, so don't always have an author key
|
||||
context[:author] = self.author if self.respond_to?(:author)
|
||||
|
||||
if Feature.enabled?(:personal_snippet_reference_filters, context[:author])
|
||||
context[:user] = self.parent_user
|
||||
end
|
||||
context[:user] = self.parent_user if Feature.enabled?(:personal_snippet_reference_filters, context[:author])
|
||||
|
||||
context
|
||||
end
|
||||
|
|
|
|||
|
|
@ -11,12 +11,15 @@ module Namespaces
|
|||
end
|
||||
|
||||
override :self_and_descendant_ids
|
||||
def self_and_descendant_ids
|
||||
def self_and_descendant_ids(skope: self.class)
|
||||
# Cache only works for descendants
|
||||
# of the same type as the caller.
|
||||
return super unless skope == self.class
|
||||
return super unless attempt_to_use_cached_data?
|
||||
|
||||
scope_with_cached_ids(
|
||||
super,
|
||||
self.class,
|
||||
skope,
|
||||
Namespaces::Descendants.arel_table[:self_and_descendant_group_ids]
|
||||
)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -120,16 +120,16 @@ module Namespaces
|
|||
all_projects.select(:id)
|
||||
end
|
||||
|
||||
def self_and_descendants
|
||||
def self_and_descendants(skope: self.class)
|
||||
return super unless use_traversal_ids?
|
||||
|
||||
lineage(top: self)
|
||||
lineage(top: self, skope: skope)
|
||||
end
|
||||
|
||||
def self_and_descendant_ids
|
||||
def self_and_descendant_ids(skope: self.class)
|
||||
return super unless use_traversal_ids?
|
||||
|
||||
self_and_descendants.as_ids
|
||||
self_and_descendants(skope: skope).as_ids
|
||||
end
|
||||
|
||||
def descendants
|
||||
|
|
@ -265,11 +265,9 @@ module Namespaces
|
|||
end
|
||||
|
||||
# Search this namespace's lineage. Bound inclusively by top node.
|
||||
def lineage(top: nil, bottom: nil, hierarchy_order: nil)
|
||||
def lineage(top: nil, bottom: nil, hierarchy_order: nil, skope: self.class)
|
||||
raise UnboundedSearch, 'Must bound search by either top or bottom' unless top || bottom
|
||||
|
||||
skope = self.class
|
||||
|
||||
if top
|
||||
skope = skope.where("traversal_ids @> ('{?}')", top.id)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -73,13 +73,13 @@ module Namespaces
|
|||
end
|
||||
alias_method :recursive_descendants, :descendants
|
||||
|
||||
def self_and_descendants
|
||||
object_hierarchy(self.class.where(id: id)).base_and_descendants
|
||||
def self_and_descendants(skope: self.class)
|
||||
object_hierarchy(skope.where(id: id)).base_and_descendants
|
||||
end
|
||||
alias_method :recursive_self_and_descendants, :self_and_descendants
|
||||
|
||||
def self_and_descendant_ids
|
||||
object_hierarchy(self.class.where(id: id)).base_and_descendant_ids
|
||||
def self_and_descendant_ids(skope: self.class)
|
||||
object_hierarchy(skope.where(id: id)).base_and_descendant_ids
|
||||
end
|
||||
alias_method :recursive_self_and_descendant_ids, :self_and_descendant_ids
|
||||
|
||||
|
|
|
|||
|
|
@ -144,6 +144,10 @@ ci_runners:
|
|||
- table: users
|
||||
column: creator_id
|
||||
on_delete: async_nullify
|
||||
ci_runners_e59bb2812d:
|
||||
- table: users
|
||||
column: creator_id
|
||||
on_delete: async_nullify
|
||||
ci_running_builds:
|
||||
- table: projects
|
||||
column: project_id
|
||||
|
|
@ -295,6 +299,13 @@ group_security_exclusions:
|
|||
- table: namespaces
|
||||
column: group_id
|
||||
on_delete: async_delete
|
||||
group_type_ci_runners_e59bb2812d:
|
||||
- table: users
|
||||
column: creator_id
|
||||
on_delete: async_nullify
|
||||
- table: namespaces
|
||||
column: sharding_key_id
|
||||
on_delete: async_delete
|
||||
groups_visits:
|
||||
- table: namespaces
|
||||
column: entity_id
|
||||
|
|
@ -302,6 +313,10 @@ groups_visits:
|
|||
- table: users
|
||||
column: user_id
|
||||
on_delete: async_delete
|
||||
instance_type_ci_runners_e59bb2812d:
|
||||
- table: users
|
||||
column: creator_id
|
||||
on_delete: async_nullify
|
||||
member_approvals:
|
||||
- table: users
|
||||
column: requested_by_id
|
||||
|
|
@ -460,6 +475,13 @@ project_security_statistics:
|
|||
- table: projects
|
||||
column: project_id
|
||||
on_delete: async_delete
|
||||
project_type_ci_runners_e59bb2812d:
|
||||
- table: users
|
||||
column: creator_id
|
||||
on_delete: async_nullify
|
||||
- table: projects
|
||||
column: sharding_key_id
|
||||
on_delete: async_delete
|
||||
projects:
|
||||
- table: users
|
||||
column: marked_for_deletion_by_user_id
|
||||
|
|
|
|||
|
|
@ -188,6 +188,7 @@ Settings.gitlab['default_branch_protection_defaults'] ||= ::Gitlab::Access::Bran
|
|||
# `default_can_create_group` is deprecated since GitLab 15.5 in favour of the `can_create_group` column on `ApplicationSetting`.
|
||||
Settings.gitlab['default_can_create_group'] = true if Settings.gitlab['default_can_create_group'].nil?
|
||||
Settings.gitlab['default_theme'] = Gitlab::Themes::APPLICATION_DEFAULT if Settings.gitlab['default_theme'].nil?
|
||||
Settings.gitlab['dns_rebinding_protection_enabled'] ||= !Gitlab.http_proxy_env?
|
||||
Settings.gitlab['custom_html_header_tags'] ||= Settings.gitlab['custom_html_header_tags'] || ''
|
||||
Settings.gitlab['host'] ||= ENV['GITLAB_HOST'] || 'localhost'
|
||||
Settings.gitlab['cdn_host'] ||= ENV['GITLAB_CDN_HOST'].presence
|
||||
|
|
|
|||
|
|
@ -16,4 +16,8 @@ tier:
|
|||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
tiers:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
performance_indicator_type: []
|
||||
|
|
|
|||
|
|
@ -17,4 +17,8 @@ tier:
|
|||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
tiers:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
performance_indicator_type: []
|
||||
|
|
|
|||
|
|
@ -17,4 +17,8 @@ tier:
|
|||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
tiers:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
performance_indicator_type: []
|
||||
|
|
|
|||
|
|
@ -16,5 +16,9 @@ tier:
|
|||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
tiers:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/557
|
||||
performance_indicator_type: []
|
||||
|
|
|
|||
|
|
@ -16,5 +16,9 @@ tier:
|
|||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
tiers:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
performance_indicator_type:
|
||||
- customer_health_score
|
||||
|
|
|
|||
|
|
@ -16,4 +16,8 @@ tier:
|
|||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
tiers:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
performance_indicator_type: []
|
||||
|
|
|
|||
|
|
@ -16,4 +16,8 @@ tier:
|
|||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
tiers:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
performance_indicator_type: []
|
||||
|
|
|
|||
|
|
@ -17,4 +17,8 @@ tier:
|
|||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
tiers:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
performance_indicator_type: []
|
||||
|
|
|
|||
|
|
@ -17,4 +17,8 @@ tier:
|
|||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
tiers:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
performance_indicator_type: []
|
||||
|
|
|
|||
|
|
@ -16,4 +16,8 @@ tier:
|
|||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
tiers:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
performance_indicator_type: []
|
||||
|
|
|
|||
|
|
@ -17,4 +17,8 @@ tier:
|
|||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
tiers:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
performance_indicator_type: []
|
||||
|
|
|
|||
|
|
@ -19,4 +19,8 @@ tier:
|
|||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
tiers:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
milestone_removed: "<16.4"
|
||||
|
|
|
|||
|
|
@ -15,3 +15,5 @@ distribution:
|
|||
- ee
|
||||
tier:
|
||||
- ultimate
|
||||
tiers:
|
||||
- ultimate
|
||||
|
|
|
|||
|
|
@ -12,9 +12,13 @@ data_category: operational
|
|||
instrumentation_class: InstallationCreationDateApproximationMetric
|
||||
performance_indicator_type: []
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
tiers:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
|
|
|
|||
|
|
@ -18,3 +18,7 @@ tier:
|
|||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
tiers:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
|
|
|
|||
|
|
@ -16,3 +16,6 @@ distribution:
|
|||
tier:
|
||||
- premium
|
||||
- ultimate
|
||||
tiers:
|
||||
- premium
|
||||
- ultimate
|
||||
|
|
|
|||
|
|
@ -5,5 +5,5 @@ feature_category: mlops
|
|||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/165214
|
||||
milestone: '17.5'
|
||||
queued_migration_version: 20241003061916
|
||||
finalize_after: '2024-11-25'
|
||||
finalized_by:
|
||||
finalize_after: '2024-10-22'
|
||||
finalized_by: 20241022155022
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
migration_job_name: RequeueBackfillApprovalProjectRulesProtectedBranchesProjectId
|
||||
description: Requeue backfill sharding key `approval_project_rules_protected_branches.project_id` from `approval_project_rules` for gitlab.com.
|
||||
feature_category: source_code_management
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/170799
|
||||
milestone: '17.6'
|
||||
queued_migration_version: 20241028141411
|
||||
finalized_by: # version of the migration that finalized this BBM
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
---
|
||||
table_name: ci_runners_e59bb2812d
|
||||
classes:
|
||||
- Ci::Runner
|
||||
feature_categories:
|
||||
- runner
|
||||
- fleet_visibility
|
||||
- hosted_runners
|
||||
description: Routing table for CI runners
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/166308
|
||||
milestone: '17.6'
|
||||
gitlab_schema: gitlab_ci
|
||||
exempt_from_sharding: true
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
---
|
||||
table_name: group_type_ci_runners_e59bb2812d
|
||||
classes:
|
||||
- Ci::Runner
|
||||
feature_categories:
|
||||
- runner
|
||||
- fleet_visibility
|
||||
description: Registered CI group runners
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/166308
|
||||
milestone: '17.6'
|
||||
gitlab_schema: gitlab_ci
|
||||
sharding_key:
|
||||
sharding_key_id: namespaces
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
---
|
||||
table_name: instance_type_ci_runners_e59bb2812d
|
||||
classes:
|
||||
- Ci::Runner
|
||||
feature_categories:
|
||||
- runner
|
||||
- fleet_visibility
|
||||
- hosted_runners
|
||||
description: Registered CI instance runners
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/166308
|
||||
milestone: '17.6'
|
||||
gitlab_schema: gitlab_ci
|
||||
exempt_from_sharding: true
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
---
|
||||
table_name: project_type_ci_runners_e59bb2812d
|
||||
classes:
|
||||
- Ci::Runner
|
||||
feature_categories:
|
||||
- runner
|
||||
- fleet_visibility
|
||||
description: Registered CI project runners
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/166308
|
||||
milestone: '17.6'
|
||||
gitlab_schema: gitlab_ci
|
||||
sharding_key:
|
||||
sharding_key_id: projects
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class CreatePartitionedCiRunners < Gitlab::Database::Migration[2.2]
|
||||
include Gitlab::Database::PartitioningMigrationHelpers::TableManagementHelpers
|
||||
|
||||
milestone '17.6'
|
||||
disable_ddl_transaction!
|
||||
|
||||
TABLE_NAME = 'ci_runners'
|
||||
PARTITIONED_TABLE_PK = %w[id runner_type]
|
||||
CONSTRAINT_NAME = 'check_sharding_key_id_nullness'
|
||||
|
||||
def up
|
||||
partition_table_by_list(
|
||||
TABLE_NAME, 'runner_type', primary_key: PARTITIONED_TABLE_PK,
|
||||
partition_mappings: { instance_type: 1, group_type: 2, project_type: 3 },
|
||||
partition_name_format: '%{partition_name}_%{table_name}',
|
||||
create_partitioned_table_fn: ->(name) { create_partitioned_table(name) }
|
||||
)
|
||||
|
||||
Gitlab::Database::PostgresPartitionedTable.each_partition(:ci_runners_e59bb2812d) do |partition|
|
||||
source = partition.to_s
|
||||
|
||||
add_check_constraint(source,
|
||||
source.start_with?('instance_type') ? 'sharding_key_id IS NULL' : 'sharding_key_id IS NOT NULL',
|
||||
CONSTRAINT_NAME)
|
||||
end
|
||||
end
|
||||
|
||||
def down
|
||||
drop_partitioned_table_for(TABLE_NAME)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def create_partitioned_table(name)
|
||||
options = 'PARTITION BY LIST (runner_type)'
|
||||
# rubocop: disable Migration/EnsureFactoryForTable -- we'll reuse the ci_runners factory once migrated
|
||||
create_table name, primary_key: PARTITIONED_TABLE_PK, options: options do |t|
|
||||
t.bigint :id, null: false
|
||||
t.bigint :creator_id
|
||||
t.bigint :sharding_key_id, null: true
|
||||
t.timestamps_with_timezone null: true
|
||||
t.datetime_with_timezone :contacted_at
|
||||
t.datetime_with_timezone :token_expires_at
|
||||
t.float :public_projects_minutes_cost_factor, null: false, default: 1.0
|
||||
t.float :private_projects_minutes_cost_factor, null: false, default: 1.0
|
||||
t.integer :access_level, null: false, default: 0
|
||||
t.integer :maximum_timeout
|
||||
t.integer :runner_type, null: false, limit: 2
|
||||
t.integer :registration_type, null: false, limit: 2, default: 0
|
||||
t.integer :creation_state, null: false, limit: 2, default: 0
|
||||
t.boolean :active, null: false, default: true
|
||||
t.boolean :run_untagged, null: false, default: true
|
||||
t.boolean :locked, null: false, default: false
|
||||
t.text :name, limit: 256
|
||||
t.text :token_encrypted, limit: 128
|
||||
t.text :token, limit: 128
|
||||
t.text :description, limit: 1024
|
||||
t.text :maintainer_note, limit: 1024
|
||||
t.text :allowed_plans, array: true, null: false, default: []
|
||||
t.bigint :allowed_plan_ids, array: true, null: false, default: []
|
||||
|
||||
t.index [:token_encrypted, :runner_type], name: "index_uniq_#{name}_on_token_encrypted_and_type", unique: true
|
||||
t.index [:token, :runner_type], name: "idx_uniq_#{name}_on_token_and_type_where_not_null", unique: true,
|
||||
where: "token IS NOT NULL"
|
||||
t.index :creator_id, name: "index_#{name}_on_creator_id_where_not_null",
|
||||
where: 'creator_id IS NOT NULL'
|
||||
t.index :sharding_key_id, name: "index_#{name}_on_sharding_key_id_where_not_null",
|
||||
where: 'sharding_key_id IS NOT NULL'
|
||||
t.index %i[active id], name: "index_#{name}_on_active_and_id"
|
||||
t.index %i[contacted_at id], name: "index_#{name}_on_contacted_at_and_id_desc",
|
||||
order: { contacted_at: :asc, id: :desc }
|
||||
t.index %i[contacted_at id], name: "idx_#{name}_on_contacted_at_and_id_where_inactive",
|
||||
order: { contacted_at: :desc, runner_type: :asc, id: :desc }, where: 'active = false'
|
||||
t.index %i[contacted_at id], name: "index_#{name}_on_contacted_at_desc_and_id_desc",
|
||||
order: { contacted_at: :desc, runner_type: :asc, id: :desc }
|
||||
t.index %i[created_at id], name: "index_#{name}_on_created_at_and_id_desc",
|
||||
order: { runner_type: :asc, id: :desc }
|
||||
t.index %i[created_at id], name: "index_#{name}_on_created_at_and_id_where_inactive",
|
||||
order: { created_at: :desc, runner_type: :asc, id: :desc }, where: 'active = false'
|
||||
t.index %i[created_at id], name: "index_#{name}_on_created_at_desc_and_id_desc",
|
||||
order: { created_at: :desc, runner_type: :asc, id: :desc }
|
||||
t.index :description, name: "index_#{name}_on_description_trigram", using: :gin, opclass: :gin_trgm_ops
|
||||
t.index :locked, name: "index_#{name}_on_locked"
|
||||
t.index %i[token_expires_at id], name: "index_#{name}_on_token_expires_at_and_id_desc",
|
||||
order: { runner_type: :asc, id: :desc }
|
||||
t.index %i[token_expires_at id], name: "idx_#{name}_on_token_expires_at_desc_and_id_desc",
|
||||
order: { token_expires_at: :desc, runner_type: :asc, id: :desc }
|
||||
end
|
||||
# rubocop: enable Migration/EnsureFactoryForTable
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class FinalizeRecoverDeletedMlModelVersionPackages < Gitlab::Database::Migration[2.2]
|
||||
milestone '17.6'
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
restrict_gitlab_migration gitlab_schema: :gitlab_main
|
||||
|
||||
def up
|
||||
ensure_batched_background_migration_is_finished(
|
||||
job_class_name: 'RecoverDeletedMlModelVersionPackages',
|
||||
table_name: :ml_model_versions,
|
||||
column_name: :id,
|
||||
job_arguments: []
|
||||
)
|
||||
end
|
||||
|
||||
def down
|
||||
# no-op
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class RequeueBackfillApprovalProjectRulesProtectedBranchesProjectId < Gitlab::Database::Migration[2.2]
|
||||
milestone '17.6'
|
||||
|
||||
restrict_gitlab_migration gitlab_schema: :gitlab_main_cell
|
||||
|
||||
MIGRATION = "BackfillApprovalProjectRulesProtectedBranchesProjectId"
|
||||
DELAY_INTERVAL = 2.minutes
|
||||
BATCH_SIZE = 5000
|
||||
SUB_BATCH_SIZE = 500
|
||||
TABLE_NAME = :approval_project_rules_protected_branches
|
||||
BATCH_COLUMN = :approval_project_rule_id
|
||||
JOB_ARGS = %i[project_id approval_project_rules project_id approval_project_rule_id]
|
||||
|
||||
def up
|
||||
return unless Gitlab.com_except_jh?
|
||||
|
||||
delete_batched_background_migration(MIGRATION, TABLE_NAME, BATCH_COLUMN, JOB_ARGS)
|
||||
|
||||
queue_batched_background_migration(
|
||||
MIGRATION,
|
||||
TABLE_NAME,
|
||||
BATCH_COLUMN,
|
||||
*JOB_ARGS,
|
||||
job_interval: DELAY_INTERVAL,
|
||||
batch_size: BATCH_SIZE,
|
||||
sub_batch_size: SUB_BATCH_SIZE
|
||||
)
|
||||
end
|
||||
|
||||
def down
|
||||
return unless Gitlab.com_except_jh?
|
||||
|
||||
delete_batched_background_migration(MIGRATION, TABLE_NAME, BATCH_COLUMN, JOB_ARGS)
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
86e7ca3910488c0b943d350f84b16bbdf4a4479851e4bc221a435fab22a6ce3f
|
||||
|
|
@ -0,0 +1 @@
|
|||
4d53b41a006e4a1802d444aa9b769935de5b12905d6cc2a5525ed24bc4e719dc
|
||||
|
|
@ -0,0 +1 @@
|
|||
f31f9caedeb9665cb122da90be23ed8d0646b105d78f245c00af9ec8950bad21
|
||||
457
db/structure.sql
457
db/structure.sql
|
|
@ -750,6 +750,95 @@ $$;
|
|||
|
||||
COMMENT ON FUNCTION table_sync_function_3f39f64fc3() IS 'Partitioning migration: table sync for merge_request_diff_files table';
|
||||
|
||||
CREATE FUNCTION table_sync_function_686d6c7993() RETURNS trigger
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
BEGIN
|
||||
IF (TG_OP = 'DELETE') THEN
|
||||
DELETE FROM ci_runners_e59bb2812d where "id" = OLD."id";
|
||||
ELSIF (TG_OP = 'UPDATE') THEN
|
||||
UPDATE ci_runners_e59bb2812d
|
||||
SET "creator_id" = NEW."creator_id",
|
||||
"sharding_key_id" = NEW."sharding_key_id",
|
||||
"created_at" = NEW."created_at",
|
||||
"updated_at" = NEW."updated_at",
|
||||
"contacted_at" = NEW."contacted_at",
|
||||
"token_expires_at" = NEW."token_expires_at",
|
||||
"public_projects_minutes_cost_factor" = NEW."public_projects_minutes_cost_factor",
|
||||
"private_projects_minutes_cost_factor" = NEW."private_projects_minutes_cost_factor",
|
||||
"access_level" = NEW."access_level",
|
||||
"maximum_timeout" = NEW."maximum_timeout",
|
||||
"runner_type" = NEW."runner_type",
|
||||
"registration_type" = NEW."registration_type",
|
||||
"creation_state" = NEW."creation_state",
|
||||
"active" = NEW."active",
|
||||
"run_untagged" = NEW."run_untagged",
|
||||
"locked" = NEW."locked",
|
||||
"name" = NEW."name",
|
||||
"token_encrypted" = NEW."token_encrypted",
|
||||
"token" = NEW."token",
|
||||
"description" = NEW."description",
|
||||
"maintainer_note" = NEW."maintainer_note",
|
||||
"allowed_plans" = NEW."allowed_plans",
|
||||
"allowed_plan_ids" = NEW."allowed_plan_ids"
|
||||
WHERE ci_runners_e59bb2812d."id" = NEW."id";
|
||||
ELSIF (TG_OP = 'INSERT') THEN
|
||||
INSERT INTO ci_runners_e59bb2812d ("id",
|
||||
"creator_id",
|
||||
"sharding_key_id",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
"contacted_at",
|
||||
"token_expires_at",
|
||||
"public_projects_minutes_cost_factor",
|
||||
"private_projects_minutes_cost_factor",
|
||||
"access_level",
|
||||
"maximum_timeout",
|
||||
"runner_type",
|
||||
"registration_type",
|
||||
"creation_state",
|
||||
"active",
|
||||
"run_untagged",
|
||||
"locked",
|
||||
"name",
|
||||
"token_encrypted",
|
||||
"token",
|
||||
"description",
|
||||
"maintainer_note",
|
||||
"allowed_plans",
|
||||
"allowed_plan_ids")
|
||||
VALUES (NEW."id",
|
||||
NEW."creator_id",
|
||||
NEW."sharding_key_id",
|
||||
NEW."created_at",
|
||||
NEW."updated_at",
|
||||
NEW."contacted_at",
|
||||
NEW."token_expires_at",
|
||||
NEW."public_projects_minutes_cost_factor",
|
||||
NEW."private_projects_minutes_cost_factor",
|
||||
NEW."access_level",
|
||||
NEW."maximum_timeout",
|
||||
NEW."runner_type",
|
||||
NEW."registration_type",
|
||||
NEW."creation_state",
|
||||
NEW."active",
|
||||
NEW."run_untagged",
|
||||
NEW."locked",
|
||||
NEW."name",
|
||||
NEW."token_encrypted",
|
||||
NEW."token",
|
||||
NEW."description",
|
||||
NEW."maintainer_note",
|
||||
NEW."allowed_plans",
|
||||
NEW."allowed_plan_ids");
|
||||
END IF;
|
||||
RETURN NULL;
|
||||
|
||||
END
|
||||
$$;
|
||||
|
||||
COMMENT ON FUNCTION table_sync_function_686d6c7993() IS 'Partitioning migration: table sync for ci_runners table';
|
||||
|
||||
CREATE FUNCTION trigger_01b3fc052119() RETURNS trigger
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
|
|
@ -9273,6 +9362,39 @@ CREATE TABLE ci_runners (
|
|||
CONSTRAINT check_ce275cee06 CHECK ((char_length(maintainer_note) <= 1024))
|
||||
);
|
||||
|
||||
CREATE TABLE ci_runners_e59bb2812d (
|
||||
id bigint NOT NULL,
|
||||
creator_id bigint,
|
||||
sharding_key_id bigint,
|
||||
created_at timestamp with time zone,
|
||||
updated_at timestamp with time zone,
|
||||
contacted_at timestamp with time zone,
|
||||
token_expires_at timestamp with time zone,
|
||||
public_projects_minutes_cost_factor double precision DEFAULT 1.0 NOT NULL,
|
||||
private_projects_minutes_cost_factor double precision DEFAULT 1.0 NOT NULL,
|
||||
access_level integer DEFAULT 0 NOT NULL,
|
||||
maximum_timeout integer,
|
||||
runner_type smallint NOT NULL,
|
||||
registration_type smallint DEFAULT 0 NOT NULL,
|
||||
creation_state smallint DEFAULT 0 NOT NULL,
|
||||
active boolean DEFAULT true NOT NULL,
|
||||
run_untagged boolean DEFAULT true NOT NULL,
|
||||
locked boolean DEFAULT false NOT NULL,
|
||||
name text,
|
||||
token_encrypted text,
|
||||
token text,
|
||||
description text,
|
||||
maintainer_note text,
|
||||
allowed_plans text[] DEFAULT '{}'::text[] NOT NULL,
|
||||
allowed_plan_ids bigint[] DEFAULT '{}'::bigint[] NOT NULL,
|
||||
CONSTRAINT check_1f8618ab23 CHECK ((char_length(name) <= 256)),
|
||||
CONSTRAINT check_24b281f5bf CHECK ((char_length(maintainer_note) <= 1024)),
|
||||
CONSTRAINT check_31c16b2a99 CHECK ((char_length(token_encrypted) <= 128)),
|
||||
CONSTRAINT check_5db8ae9d30 CHECK ((char_length(description) <= 1024)),
|
||||
CONSTRAINT check_af25130d5a CHECK ((char_length(token) <= 128))
|
||||
)
|
||||
PARTITION BY LIST (runner_type);
|
||||
|
||||
CREATE SEQUENCE ci_runners_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
|
|
@ -12258,6 +12380,39 @@ CREATE SEQUENCE group_ssh_certificates_id_seq
|
|||
|
||||
ALTER SEQUENCE group_ssh_certificates_id_seq OWNED BY group_ssh_certificates.id;
|
||||
|
||||
CREATE TABLE group_type_ci_runners_e59bb2812d (
|
||||
id bigint NOT NULL,
|
||||
creator_id bigint,
|
||||
sharding_key_id bigint,
|
||||
created_at timestamp with time zone,
|
||||
updated_at timestamp with time zone,
|
||||
contacted_at timestamp with time zone,
|
||||
token_expires_at timestamp with time zone,
|
||||
public_projects_minutes_cost_factor double precision DEFAULT 1.0 NOT NULL,
|
||||
private_projects_minutes_cost_factor double precision DEFAULT 1.0 NOT NULL,
|
||||
access_level integer DEFAULT 0 NOT NULL,
|
||||
maximum_timeout integer,
|
||||
runner_type smallint NOT NULL,
|
||||
registration_type smallint DEFAULT 0 NOT NULL,
|
||||
creation_state smallint DEFAULT 0 NOT NULL,
|
||||
active boolean DEFAULT true NOT NULL,
|
||||
run_untagged boolean DEFAULT true NOT NULL,
|
||||
locked boolean DEFAULT false NOT NULL,
|
||||
name text,
|
||||
token_encrypted text,
|
||||
token text,
|
||||
description text,
|
||||
maintainer_note text,
|
||||
allowed_plans text[] DEFAULT '{}'::text[] NOT NULL,
|
||||
allowed_plan_ids bigint[] DEFAULT '{}'::bigint[] NOT NULL,
|
||||
CONSTRAINT check_1f8618ab23 CHECK ((char_length(name) <= 256)),
|
||||
CONSTRAINT check_24b281f5bf CHECK ((char_length(maintainer_note) <= 1024)),
|
||||
CONSTRAINT check_31c16b2a99 CHECK ((char_length(token_encrypted) <= 128)),
|
||||
CONSTRAINT check_5db8ae9d30 CHECK ((char_length(description) <= 1024)),
|
||||
CONSTRAINT check_af25130d5a CHECK ((char_length(token) <= 128)),
|
||||
CONSTRAINT check_sharding_key_id_nullness CHECK ((sharding_key_id IS NOT NULL))
|
||||
);
|
||||
|
||||
CREATE TABLE group_wiki_repositories (
|
||||
shard_id bigint NOT NULL,
|
||||
group_id bigint NOT NULL,
|
||||
|
|
@ -12783,6 +12938,39 @@ CREATE SEQUENCE instance_integrations_id_seq
|
|||
|
||||
ALTER SEQUENCE instance_integrations_id_seq OWNED BY instance_integrations.id;
|
||||
|
||||
CREATE TABLE instance_type_ci_runners_e59bb2812d (
|
||||
id bigint NOT NULL,
|
||||
creator_id bigint,
|
||||
sharding_key_id bigint,
|
||||
created_at timestamp with time zone,
|
||||
updated_at timestamp with time zone,
|
||||
contacted_at timestamp with time zone,
|
||||
token_expires_at timestamp with time zone,
|
||||
public_projects_minutes_cost_factor double precision DEFAULT 1.0 NOT NULL,
|
||||
private_projects_minutes_cost_factor double precision DEFAULT 1.0 NOT NULL,
|
||||
access_level integer DEFAULT 0 NOT NULL,
|
||||
maximum_timeout integer,
|
||||
runner_type smallint NOT NULL,
|
||||
registration_type smallint DEFAULT 0 NOT NULL,
|
||||
creation_state smallint DEFAULT 0 NOT NULL,
|
||||
active boolean DEFAULT true NOT NULL,
|
||||
run_untagged boolean DEFAULT true NOT NULL,
|
||||
locked boolean DEFAULT false NOT NULL,
|
||||
name text,
|
||||
token_encrypted text,
|
||||
token text,
|
||||
description text,
|
||||
maintainer_note text,
|
||||
allowed_plans text[] DEFAULT '{}'::text[] NOT NULL,
|
||||
allowed_plan_ids bigint[] DEFAULT '{}'::bigint[] NOT NULL,
|
||||
CONSTRAINT check_1f8618ab23 CHECK ((char_length(name) <= 256)),
|
||||
CONSTRAINT check_24b281f5bf CHECK ((char_length(maintainer_note) <= 1024)),
|
||||
CONSTRAINT check_31c16b2a99 CHECK ((char_length(token_encrypted) <= 128)),
|
||||
CONSTRAINT check_5db8ae9d30 CHECK ((char_length(description) <= 1024)),
|
||||
CONSTRAINT check_af25130d5a CHECK ((char_length(token) <= 128)),
|
||||
CONSTRAINT check_sharding_key_id_nullness CHECK ((sharding_key_id IS NULL))
|
||||
);
|
||||
|
||||
CREATE TABLE integrations (
|
||||
id bigint NOT NULL,
|
||||
project_id bigint,
|
||||
|
|
@ -17604,6 +17792,39 @@ CREATE SEQUENCE project_topics_id_seq
|
|||
|
||||
ALTER SEQUENCE project_topics_id_seq OWNED BY project_topics.id;
|
||||
|
||||
CREATE TABLE project_type_ci_runners_e59bb2812d (
|
||||
id bigint NOT NULL,
|
||||
creator_id bigint,
|
||||
sharding_key_id bigint,
|
||||
created_at timestamp with time zone,
|
||||
updated_at timestamp with time zone,
|
||||
contacted_at timestamp with time zone,
|
||||
token_expires_at timestamp with time zone,
|
||||
public_projects_minutes_cost_factor double precision DEFAULT 1.0 NOT NULL,
|
||||
private_projects_minutes_cost_factor double precision DEFAULT 1.0 NOT NULL,
|
||||
access_level integer DEFAULT 0 NOT NULL,
|
||||
maximum_timeout integer,
|
||||
runner_type smallint NOT NULL,
|
||||
registration_type smallint DEFAULT 0 NOT NULL,
|
||||
creation_state smallint DEFAULT 0 NOT NULL,
|
||||
active boolean DEFAULT true NOT NULL,
|
||||
run_untagged boolean DEFAULT true NOT NULL,
|
||||
locked boolean DEFAULT false NOT NULL,
|
||||
name text,
|
||||
token_encrypted text,
|
||||
token text,
|
||||
description text,
|
||||
maintainer_note text,
|
||||
allowed_plans text[] DEFAULT '{}'::text[] NOT NULL,
|
||||
allowed_plan_ids bigint[] DEFAULT '{}'::bigint[] NOT NULL,
|
||||
CONSTRAINT check_1f8618ab23 CHECK ((char_length(name) <= 256)),
|
||||
CONSTRAINT check_24b281f5bf CHECK ((char_length(maintainer_note) <= 1024)),
|
||||
CONSTRAINT check_31c16b2a99 CHECK ((char_length(token_encrypted) <= 128)),
|
||||
CONSTRAINT check_5db8ae9d30 CHECK ((char_length(description) <= 1024)),
|
||||
CONSTRAINT check_af25130d5a CHECK ((char_length(token) <= 128)),
|
||||
CONSTRAINT check_sharding_key_id_nullness CHECK ((sharding_key_id IS NOT NULL))
|
||||
);
|
||||
|
||||
CREATE TABLE project_wiki_repositories (
|
||||
id bigint NOT NULL,
|
||||
project_id bigint NOT NULL,
|
||||
|
|
@ -21996,6 +22217,12 @@ ALTER TABLE ONLY p_ci_pipelines ATTACH PARTITION ci_pipelines FOR VALUES IN ('10
|
|||
|
||||
ALTER TABLE ONLY p_ci_stages ATTACH PARTITION ci_stages FOR VALUES IN ('100', '101');
|
||||
|
||||
ALTER TABLE ONLY ci_runners_e59bb2812d ATTACH PARTITION group_type_ci_runners_e59bb2812d FOR VALUES IN ('2');
|
||||
|
||||
ALTER TABLE ONLY ci_runners_e59bb2812d ATTACH PARTITION instance_type_ci_runners_e59bb2812d FOR VALUES IN ('1');
|
||||
|
||||
ALTER TABLE ONLY ci_runners_e59bb2812d ATTACH PARTITION project_type_ci_runners_e59bb2812d FOR VALUES IN ('3');
|
||||
|
||||
ALTER TABLE ONLY abuse_events ALTER COLUMN id SET DEFAULT nextval('abuse_events_id_seq'::regclass);
|
||||
|
||||
ALTER TABLE ONLY abuse_report_assignees ALTER COLUMN id SET DEFAULT nextval('abuse_report_assignees_id_seq'::regclass);
|
||||
|
|
@ -24321,6 +24548,9 @@ ALTER TABLE ONLY ci_runner_projects
|
|||
ALTER TABLE ONLY ci_runner_versions
|
||||
ADD CONSTRAINT ci_runner_versions_pkey PRIMARY KEY (version);
|
||||
|
||||
ALTER TABLE ONLY ci_runners_e59bb2812d
|
||||
ADD CONSTRAINT ci_runners_e59bb2812d_pkey PRIMARY KEY (id, runner_type);
|
||||
|
||||
ALTER TABLE ONLY ci_runners
|
||||
ADD CONSTRAINT ci_runners_pkey PRIMARY KEY (id);
|
||||
|
||||
|
|
@ -24771,6 +25001,9 @@ ALTER TABLE ONLY group_security_exclusions
|
|||
ALTER TABLE ONLY group_ssh_certificates
|
||||
ADD CONSTRAINT group_ssh_certificates_pkey PRIMARY KEY (id);
|
||||
|
||||
ALTER TABLE ONLY group_type_ci_runners_e59bb2812d
|
||||
ADD CONSTRAINT group_type_ci_runners_e59bb2812d_pkey PRIMARY KEY (id, runner_type);
|
||||
|
||||
ALTER TABLE ONLY group_wiki_repositories
|
||||
ADD CONSTRAINT group_wiki_repositories_pkey PRIMARY KEY (group_id);
|
||||
|
||||
|
|
@ -24855,6 +25088,9 @@ ALTER TABLE ONLY instance_audit_events_streaming_headers
|
|||
ALTER TABLE ONLY instance_integrations
|
||||
ADD CONSTRAINT instance_integrations_pkey PRIMARY KEY (id);
|
||||
|
||||
ALTER TABLE ONLY instance_type_ci_runners_e59bb2812d
|
||||
ADD CONSTRAINT instance_type_ci_runners_e59bb2812d_pkey PRIMARY KEY (id, runner_type);
|
||||
|
||||
ALTER TABLE ONLY integrations
|
||||
ADD CONSTRAINT integrations_pkey PRIMARY KEY (id);
|
||||
|
||||
|
|
@ -25542,6 +25778,9 @@ ALTER TABLE ONLY project_statistics
|
|||
ALTER TABLE ONLY project_topics
|
||||
ADD CONSTRAINT project_topics_pkey PRIMARY KEY (id);
|
||||
|
||||
ALTER TABLE ONLY project_type_ci_runners_e59bb2812d
|
||||
ADD CONSTRAINT project_type_ci_runners_e59bb2812d_pkey PRIMARY KEY (id, runner_type);
|
||||
|
||||
ALTER TABLE ONLY project_wiki_repositories
|
||||
ADD CONSTRAINT project_wiki_repositories_pkey PRIMARY KEY (id);
|
||||
|
||||
|
|
@ -27308,6 +27547,66 @@ CREATE UNIQUE INDEX finding_link_name_url_idx ON vulnerability_finding_links USI
|
|||
|
||||
CREATE UNIQUE INDEX finding_link_url_idx ON vulnerability_finding_links USING btree (vulnerability_occurrence_id, url) WHERE (name IS NULL);
|
||||
|
||||
CREATE UNIQUE INDEX index_uniq_ci_runners_e59bb2812d_on_token_encrypted_and_type ON ONLY ci_runners_e59bb2812d USING btree (token_encrypted, runner_type);
|
||||
|
||||
CREATE UNIQUE INDEX group_type_ci_runners_e59bb2812_token_encrypted_runner_type_idx ON group_type_ci_runners_e59bb2812d USING btree (token_encrypted, runner_type);
|
||||
|
||||
CREATE INDEX index_ci_runners_e59bb2812d_on_active_and_id ON ONLY ci_runners_e59bb2812d USING btree (active, id);
|
||||
|
||||
CREATE INDEX group_type_ci_runners_e59bb2812d_active_id_idx ON group_type_ci_runners_e59bb2812d USING btree (active, id);
|
||||
|
||||
CREATE INDEX index_ci_runners_e59bb2812d_on_contacted_at_and_id_desc ON ONLY ci_runners_e59bb2812d USING btree (contacted_at, id DESC);
|
||||
|
||||
CREATE INDEX group_type_ci_runners_e59bb2812d_contacted_at_id_idx ON group_type_ci_runners_e59bb2812d USING btree (contacted_at, id DESC);
|
||||
|
||||
CREATE INDEX idx_ci_runners_e59bb2812d_on_contacted_at_and_id_where_inactive ON ONLY ci_runners_e59bb2812d USING btree (contacted_at DESC, id DESC) WHERE (active = false);
|
||||
|
||||
CREATE INDEX group_type_ci_runners_e59bb2812d_contacted_at_id_idx1 ON group_type_ci_runners_e59bb2812d USING btree (contacted_at DESC, id DESC) WHERE (active = false);
|
||||
|
||||
CREATE INDEX index_ci_runners_e59bb2812d_on_contacted_at_desc_and_id_desc ON ONLY ci_runners_e59bb2812d USING btree (contacted_at DESC, id DESC);
|
||||
|
||||
CREATE INDEX group_type_ci_runners_e59bb2812d_contacted_at_id_idx2 ON group_type_ci_runners_e59bb2812d USING btree (contacted_at DESC, id DESC);
|
||||
|
||||
CREATE INDEX index_ci_runners_e59bb2812d_on_created_at_and_id_desc ON ONLY ci_runners_e59bb2812d USING btree (created_at, id DESC);
|
||||
|
||||
CREATE INDEX group_type_ci_runners_e59bb2812d_created_at_id_idx ON group_type_ci_runners_e59bb2812d USING btree (created_at, id DESC);
|
||||
|
||||
CREATE INDEX index_ci_runners_e59bb2812d_on_created_at_and_id_where_inactive ON ONLY ci_runners_e59bb2812d USING btree (created_at DESC, id DESC) WHERE (active = false);
|
||||
|
||||
CREATE INDEX group_type_ci_runners_e59bb2812d_created_at_id_idx1 ON group_type_ci_runners_e59bb2812d USING btree (created_at DESC, id DESC) WHERE (active = false);
|
||||
|
||||
CREATE INDEX index_ci_runners_e59bb2812d_on_created_at_desc_and_id_desc ON ONLY ci_runners_e59bb2812d USING btree (created_at DESC, id DESC);
|
||||
|
||||
CREATE INDEX group_type_ci_runners_e59bb2812d_created_at_id_idx2 ON group_type_ci_runners_e59bb2812d USING btree (created_at DESC, id DESC);
|
||||
|
||||
CREATE INDEX index_ci_runners_e59bb2812d_on_creator_id_where_not_null ON ONLY ci_runners_e59bb2812d USING btree (creator_id) WHERE (creator_id IS NOT NULL);
|
||||
|
||||
CREATE INDEX group_type_ci_runners_e59bb2812d_creator_id_idx ON group_type_ci_runners_e59bb2812d USING btree (creator_id) WHERE (creator_id IS NOT NULL);
|
||||
|
||||
CREATE INDEX index_ci_runners_e59bb2812d_on_description_trigram ON ONLY ci_runners_e59bb2812d USING gin (description gin_trgm_ops);
|
||||
|
||||
CREATE INDEX group_type_ci_runners_e59bb2812d_description_idx ON group_type_ci_runners_e59bb2812d USING gin (description gin_trgm_ops);
|
||||
|
||||
CREATE INDEX index_ci_runners_e59bb2812d_on_locked ON ONLY ci_runners_e59bb2812d USING btree (locked);
|
||||
|
||||
CREATE INDEX group_type_ci_runners_e59bb2812d_locked_idx ON group_type_ci_runners_e59bb2812d USING btree (locked);
|
||||
|
||||
CREATE INDEX index_ci_runners_e59bb2812d_on_sharding_key_id_where_not_null ON ONLY ci_runners_e59bb2812d USING btree (sharding_key_id) WHERE (sharding_key_id IS NOT NULL);
|
||||
|
||||
CREATE INDEX group_type_ci_runners_e59bb2812d_sharding_key_id_idx ON group_type_ci_runners_e59bb2812d USING btree (sharding_key_id) WHERE (sharding_key_id IS NOT NULL);
|
||||
|
||||
CREATE INDEX index_ci_runners_e59bb2812d_on_token_expires_at_and_id_desc ON ONLY ci_runners_e59bb2812d USING btree (token_expires_at, id DESC);
|
||||
|
||||
CREATE INDEX group_type_ci_runners_e59bb2812d_token_expires_at_id_idx ON group_type_ci_runners_e59bb2812d USING btree (token_expires_at, id DESC);
|
||||
|
||||
CREATE INDEX idx_ci_runners_e59bb2812d_on_token_expires_at_desc_and_id_desc ON ONLY ci_runners_e59bb2812d USING btree (token_expires_at DESC, id DESC);
|
||||
|
||||
CREATE INDEX group_type_ci_runners_e59bb2812d_token_expires_at_id_idx1 ON group_type_ci_runners_e59bb2812d USING btree (token_expires_at DESC, id DESC);
|
||||
|
||||
CREATE UNIQUE INDEX idx_uniq_ci_runners_e59bb2812d_on_token_and_type_where_not_null ON ONLY ci_runners_e59bb2812d USING btree (token, runner_type) WHERE (token IS NOT NULL);
|
||||
|
||||
CREATE UNIQUE INDEX group_type_ci_runners_e59bb2812d_token_runner_type_idx ON group_type_ci_runners_e59bb2812d USING btree (token, runner_type) WHERE (token IS NOT NULL);
|
||||
|
||||
CREATE UNIQUE INDEX i_affected_packages_unique_for_upsert ON pm_affected_packages USING btree (pm_advisory_id, purl_type, package_name, distro_version);
|
||||
|
||||
CREATE INDEX i_batched_background_migration_job_transition_logs_on_job_id ON ONLY batched_background_migration_job_transition_logs USING btree (batched_background_migration_job_id);
|
||||
|
|
@ -31894,6 +32193,36 @@ CREATE INDEX index_zoom_meetings_on_issue_status ON zoom_meetings USING btree (i
|
|||
|
||||
CREATE INDEX index_zoom_meetings_on_project_id ON zoom_meetings USING btree (project_id);
|
||||
|
||||
CREATE INDEX instance_type_ci_runners_e59bb2812d_active_id_idx ON instance_type_ci_runners_e59bb2812d USING btree (active, id);
|
||||
|
||||
CREATE INDEX instance_type_ci_runners_e59bb2812d_contacted_at_id_idx ON instance_type_ci_runners_e59bb2812d USING btree (contacted_at, id DESC);
|
||||
|
||||
CREATE INDEX instance_type_ci_runners_e59bb2812d_contacted_at_id_idx1 ON instance_type_ci_runners_e59bb2812d USING btree (contacted_at DESC, id DESC) WHERE (active = false);
|
||||
|
||||
CREATE INDEX instance_type_ci_runners_e59bb2812d_contacted_at_id_idx2 ON instance_type_ci_runners_e59bb2812d USING btree (contacted_at DESC, id DESC);
|
||||
|
||||
CREATE INDEX instance_type_ci_runners_e59bb2812d_created_at_id_idx ON instance_type_ci_runners_e59bb2812d USING btree (created_at, id DESC);
|
||||
|
||||
CREATE INDEX instance_type_ci_runners_e59bb2812d_created_at_id_idx1 ON instance_type_ci_runners_e59bb2812d USING btree (created_at DESC, id DESC) WHERE (active = false);
|
||||
|
||||
CREATE INDEX instance_type_ci_runners_e59bb2812d_created_at_id_idx2 ON instance_type_ci_runners_e59bb2812d USING btree (created_at DESC, id DESC);
|
||||
|
||||
CREATE INDEX instance_type_ci_runners_e59bb2812d_creator_id_idx ON instance_type_ci_runners_e59bb2812d USING btree (creator_id) WHERE (creator_id IS NOT NULL);
|
||||
|
||||
CREATE INDEX instance_type_ci_runners_e59bb2812d_description_idx ON instance_type_ci_runners_e59bb2812d USING gin (description gin_trgm_ops);
|
||||
|
||||
CREATE INDEX instance_type_ci_runners_e59bb2812d_locked_idx ON instance_type_ci_runners_e59bb2812d USING btree (locked);
|
||||
|
||||
CREATE INDEX instance_type_ci_runners_e59bb2812d_sharding_key_id_idx ON instance_type_ci_runners_e59bb2812d USING btree (sharding_key_id) WHERE (sharding_key_id IS NOT NULL);
|
||||
|
||||
CREATE INDEX instance_type_ci_runners_e59bb2812d_token_expires_at_id_idx ON instance_type_ci_runners_e59bb2812d USING btree (token_expires_at, id DESC);
|
||||
|
||||
CREATE INDEX instance_type_ci_runners_e59bb2812d_token_expires_at_id_idx1 ON instance_type_ci_runners_e59bb2812d USING btree (token_expires_at DESC, id DESC);
|
||||
|
||||
CREATE UNIQUE INDEX instance_type_ci_runners_e59bb2812d_token_runner_type_idx ON instance_type_ci_runners_e59bb2812d USING btree (token, runner_type) WHERE (token IS NOT NULL);
|
||||
|
||||
CREATE UNIQUE INDEX instance_type_ci_runners_e59bb2_token_encrypted_runner_type_idx ON instance_type_ci_runners_e59bb2812d USING btree (token_encrypted, runner_type);
|
||||
|
||||
CREATE UNIQUE INDEX issue_user_mentions_on_issue_id_and_note_id_index ON issue_user_mentions USING btree (issue_id, note_id);
|
||||
|
||||
CREATE UNIQUE INDEX issue_user_mentions_on_issue_id_index ON issue_user_mentions USING btree (issue_id) WHERE (note_id IS NULL);
|
||||
|
|
@ -31938,6 +32267,36 @@ CREATE INDEX partial_index_user_id_app_id_created_at_token_not_revoked ON oauth_
|
|||
|
||||
CREATE UNIQUE INDEX pm_checkpoints_path_components ON pm_checkpoints USING btree (purl_type, data_type, version_format);
|
||||
|
||||
CREATE INDEX project_type_ci_runners_e59bb2812d_active_id_idx ON project_type_ci_runners_e59bb2812d USING btree (active, id);
|
||||
|
||||
CREATE INDEX project_type_ci_runners_e59bb2812d_contacted_at_id_idx ON project_type_ci_runners_e59bb2812d USING btree (contacted_at, id DESC);
|
||||
|
||||
CREATE INDEX project_type_ci_runners_e59bb2812d_contacted_at_id_idx1 ON project_type_ci_runners_e59bb2812d USING btree (contacted_at DESC, id DESC) WHERE (active = false);
|
||||
|
||||
CREATE INDEX project_type_ci_runners_e59bb2812d_contacted_at_id_idx2 ON project_type_ci_runners_e59bb2812d USING btree (contacted_at DESC, id DESC);
|
||||
|
||||
CREATE INDEX project_type_ci_runners_e59bb2812d_created_at_id_idx ON project_type_ci_runners_e59bb2812d USING btree (created_at, id DESC);
|
||||
|
||||
CREATE INDEX project_type_ci_runners_e59bb2812d_created_at_id_idx1 ON project_type_ci_runners_e59bb2812d USING btree (created_at DESC, id DESC) WHERE (active = false);
|
||||
|
||||
CREATE INDEX project_type_ci_runners_e59bb2812d_created_at_id_idx2 ON project_type_ci_runners_e59bb2812d USING btree (created_at DESC, id DESC);
|
||||
|
||||
CREATE INDEX project_type_ci_runners_e59bb2812d_creator_id_idx ON project_type_ci_runners_e59bb2812d USING btree (creator_id) WHERE (creator_id IS NOT NULL);
|
||||
|
||||
CREATE INDEX project_type_ci_runners_e59bb2812d_description_idx ON project_type_ci_runners_e59bb2812d USING gin (description gin_trgm_ops);
|
||||
|
||||
CREATE INDEX project_type_ci_runners_e59bb2812d_locked_idx ON project_type_ci_runners_e59bb2812d USING btree (locked);
|
||||
|
||||
CREATE INDEX project_type_ci_runners_e59bb2812d_sharding_key_id_idx ON project_type_ci_runners_e59bb2812d USING btree (sharding_key_id) WHERE (sharding_key_id IS NOT NULL);
|
||||
|
||||
CREATE INDEX project_type_ci_runners_e59bb2812d_token_expires_at_id_idx ON project_type_ci_runners_e59bb2812d USING btree (token_expires_at, id DESC);
|
||||
|
||||
CREATE INDEX project_type_ci_runners_e59bb2812d_token_expires_at_id_idx1 ON project_type_ci_runners_e59bb2812d USING btree (token_expires_at DESC, id DESC);
|
||||
|
||||
CREATE UNIQUE INDEX project_type_ci_runners_e59bb2812d_token_runner_type_idx ON project_type_ci_runners_e59bb2812d USING btree (token, runner_type) WHERE (token IS NOT NULL);
|
||||
|
||||
CREATE UNIQUE INDEX project_type_ci_runners_e59bb28_token_encrypted_runner_type_idx ON project_type_ci_runners_e59bb2812d USING btree (token_encrypted, runner_type);
|
||||
|
||||
CREATE INDEX releases_published_at_index ON releases USING btree (release_published_at);
|
||||
|
||||
CREATE INDEX revised_idx_for_owasp_top_10_group_level_reports ON vulnerability_reads USING btree (owasp_top_10, state, report_type, resolved_on_default_branch, severity, traversal_ids, vulnerability_id) WHERE (archived = false);
|
||||
|
|
@ -33578,6 +33937,38 @@ ALTER INDEX p_ci_pipelines_pkey ATTACH PARTITION ci_pipelines_pkey;
|
|||
|
||||
ALTER INDEX p_ci_stages_pkey ATTACH PARTITION ci_stages_pkey;
|
||||
|
||||
ALTER INDEX index_uniq_ci_runners_e59bb2812d_on_token_encrypted_and_type ATTACH PARTITION group_type_ci_runners_e59bb2812_token_encrypted_runner_type_idx;
|
||||
|
||||
ALTER INDEX index_ci_runners_e59bb2812d_on_active_and_id ATTACH PARTITION group_type_ci_runners_e59bb2812d_active_id_idx;
|
||||
|
||||
ALTER INDEX index_ci_runners_e59bb2812d_on_contacted_at_and_id_desc ATTACH PARTITION group_type_ci_runners_e59bb2812d_contacted_at_id_idx;
|
||||
|
||||
ALTER INDEX idx_ci_runners_e59bb2812d_on_contacted_at_and_id_where_inactive ATTACH PARTITION group_type_ci_runners_e59bb2812d_contacted_at_id_idx1;
|
||||
|
||||
ALTER INDEX index_ci_runners_e59bb2812d_on_contacted_at_desc_and_id_desc ATTACH PARTITION group_type_ci_runners_e59bb2812d_contacted_at_id_idx2;
|
||||
|
||||
ALTER INDEX index_ci_runners_e59bb2812d_on_created_at_and_id_desc ATTACH PARTITION group_type_ci_runners_e59bb2812d_created_at_id_idx;
|
||||
|
||||
ALTER INDEX index_ci_runners_e59bb2812d_on_created_at_and_id_where_inactive ATTACH PARTITION group_type_ci_runners_e59bb2812d_created_at_id_idx1;
|
||||
|
||||
ALTER INDEX index_ci_runners_e59bb2812d_on_created_at_desc_and_id_desc ATTACH PARTITION group_type_ci_runners_e59bb2812d_created_at_id_idx2;
|
||||
|
||||
ALTER INDEX index_ci_runners_e59bb2812d_on_creator_id_where_not_null ATTACH PARTITION group_type_ci_runners_e59bb2812d_creator_id_idx;
|
||||
|
||||
ALTER INDEX index_ci_runners_e59bb2812d_on_description_trigram ATTACH PARTITION group_type_ci_runners_e59bb2812d_description_idx;
|
||||
|
||||
ALTER INDEX index_ci_runners_e59bb2812d_on_locked ATTACH PARTITION group_type_ci_runners_e59bb2812d_locked_idx;
|
||||
|
||||
ALTER INDEX ci_runners_e59bb2812d_pkey ATTACH PARTITION group_type_ci_runners_e59bb2812d_pkey;
|
||||
|
||||
ALTER INDEX index_ci_runners_e59bb2812d_on_sharding_key_id_where_not_null ATTACH PARTITION group_type_ci_runners_e59bb2812d_sharding_key_id_idx;
|
||||
|
||||
ALTER INDEX index_ci_runners_e59bb2812d_on_token_expires_at_and_id_desc ATTACH PARTITION group_type_ci_runners_e59bb2812d_token_expires_at_id_idx;
|
||||
|
||||
ALTER INDEX idx_ci_runners_e59bb2812d_on_token_expires_at_desc_and_id_desc ATTACH PARTITION group_type_ci_runners_e59bb2812d_token_expires_at_id_idx1;
|
||||
|
||||
ALTER INDEX idx_uniq_ci_runners_e59bb2812d_on_token_and_type_where_not_null ATTACH PARTITION group_type_ci_runners_e59bb2812d_token_runner_type_idx;
|
||||
|
||||
ALTER INDEX p_ci_job_artifacts_job_id_file_type_partition_id_idx ATTACH PARTITION idx_ci_job_artifacts_on_job_id_file_type_and_partition_id_uniq;
|
||||
|
||||
ALTER INDEX p_ci_pipelines_ci_ref_id_id_idx ATTACH PARTITION idx_ci_pipelines_artifacts_locked;
|
||||
|
|
@ -33710,8 +34101,72 @@ ALTER INDEX p_ci_builds_user_id_name_created_at_idx ATTACH PARTITION index_secur
|
|||
|
||||
ALTER INDEX p_ci_builds_name_id_idx ATTACH PARTITION index_security_ci_builds_on_name_and_id_parser_features;
|
||||
|
||||
ALTER INDEX index_ci_runners_e59bb2812d_on_active_and_id ATTACH PARTITION instance_type_ci_runners_e59bb2812d_active_id_idx;
|
||||
|
||||
ALTER INDEX index_ci_runners_e59bb2812d_on_contacted_at_and_id_desc ATTACH PARTITION instance_type_ci_runners_e59bb2812d_contacted_at_id_idx;
|
||||
|
||||
ALTER INDEX idx_ci_runners_e59bb2812d_on_contacted_at_and_id_where_inactive ATTACH PARTITION instance_type_ci_runners_e59bb2812d_contacted_at_id_idx1;
|
||||
|
||||
ALTER INDEX index_ci_runners_e59bb2812d_on_contacted_at_desc_and_id_desc ATTACH PARTITION instance_type_ci_runners_e59bb2812d_contacted_at_id_idx2;
|
||||
|
||||
ALTER INDEX index_ci_runners_e59bb2812d_on_created_at_and_id_desc ATTACH PARTITION instance_type_ci_runners_e59bb2812d_created_at_id_idx;
|
||||
|
||||
ALTER INDEX index_ci_runners_e59bb2812d_on_created_at_and_id_where_inactive ATTACH PARTITION instance_type_ci_runners_e59bb2812d_created_at_id_idx1;
|
||||
|
||||
ALTER INDEX index_ci_runners_e59bb2812d_on_created_at_desc_and_id_desc ATTACH PARTITION instance_type_ci_runners_e59bb2812d_created_at_id_idx2;
|
||||
|
||||
ALTER INDEX index_ci_runners_e59bb2812d_on_creator_id_where_not_null ATTACH PARTITION instance_type_ci_runners_e59bb2812d_creator_id_idx;
|
||||
|
||||
ALTER INDEX index_ci_runners_e59bb2812d_on_description_trigram ATTACH PARTITION instance_type_ci_runners_e59bb2812d_description_idx;
|
||||
|
||||
ALTER INDEX index_ci_runners_e59bb2812d_on_locked ATTACH PARTITION instance_type_ci_runners_e59bb2812d_locked_idx;
|
||||
|
||||
ALTER INDEX ci_runners_e59bb2812d_pkey ATTACH PARTITION instance_type_ci_runners_e59bb2812d_pkey;
|
||||
|
||||
ALTER INDEX index_ci_runners_e59bb2812d_on_sharding_key_id_where_not_null ATTACH PARTITION instance_type_ci_runners_e59bb2812d_sharding_key_id_idx;
|
||||
|
||||
ALTER INDEX index_ci_runners_e59bb2812d_on_token_expires_at_and_id_desc ATTACH PARTITION instance_type_ci_runners_e59bb2812d_token_expires_at_id_idx;
|
||||
|
||||
ALTER INDEX idx_ci_runners_e59bb2812d_on_token_expires_at_desc_and_id_desc ATTACH PARTITION instance_type_ci_runners_e59bb2812d_token_expires_at_id_idx1;
|
||||
|
||||
ALTER INDEX idx_uniq_ci_runners_e59bb2812d_on_token_and_type_where_not_null ATTACH PARTITION instance_type_ci_runners_e59bb2812d_token_runner_type_idx;
|
||||
|
||||
ALTER INDEX index_uniq_ci_runners_e59bb2812d_on_token_encrypted_and_type ATTACH PARTITION instance_type_ci_runners_e59bb2_token_encrypted_runner_type_idx;
|
||||
|
||||
ALTER INDEX p_ci_builds_scheduled_at_idx ATTACH PARTITION partial_index_ci_builds_on_scheduled_at_with_scheduled_jobs;
|
||||
|
||||
ALTER INDEX index_ci_runners_e59bb2812d_on_active_and_id ATTACH PARTITION project_type_ci_runners_e59bb2812d_active_id_idx;
|
||||
|
||||
ALTER INDEX index_ci_runners_e59bb2812d_on_contacted_at_and_id_desc ATTACH PARTITION project_type_ci_runners_e59bb2812d_contacted_at_id_idx;
|
||||
|
||||
ALTER INDEX idx_ci_runners_e59bb2812d_on_contacted_at_and_id_where_inactive ATTACH PARTITION project_type_ci_runners_e59bb2812d_contacted_at_id_idx1;
|
||||
|
||||
ALTER INDEX index_ci_runners_e59bb2812d_on_contacted_at_desc_and_id_desc ATTACH PARTITION project_type_ci_runners_e59bb2812d_contacted_at_id_idx2;
|
||||
|
||||
ALTER INDEX index_ci_runners_e59bb2812d_on_created_at_and_id_desc ATTACH PARTITION project_type_ci_runners_e59bb2812d_created_at_id_idx;
|
||||
|
||||
ALTER INDEX index_ci_runners_e59bb2812d_on_created_at_and_id_where_inactive ATTACH PARTITION project_type_ci_runners_e59bb2812d_created_at_id_idx1;
|
||||
|
||||
ALTER INDEX index_ci_runners_e59bb2812d_on_created_at_desc_and_id_desc ATTACH PARTITION project_type_ci_runners_e59bb2812d_created_at_id_idx2;
|
||||
|
||||
ALTER INDEX index_ci_runners_e59bb2812d_on_creator_id_where_not_null ATTACH PARTITION project_type_ci_runners_e59bb2812d_creator_id_idx;
|
||||
|
||||
ALTER INDEX index_ci_runners_e59bb2812d_on_description_trigram ATTACH PARTITION project_type_ci_runners_e59bb2812d_description_idx;
|
||||
|
||||
ALTER INDEX index_ci_runners_e59bb2812d_on_locked ATTACH PARTITION project_type_ci_runners_e59bb2812d_locked_idx;
|
||||
|
||||
ALTER INDEX ci_runners_e59bb2812d_pkey ATTACH PARTITION project_type_ci_runners_e59bb2812d_pkey;
|
||||
|
||||
ALTER INDEX index_ci_runners_e59bb2812d_on_sharding_key_id_where_not_null ATTACH PARTITION project_type_ci_runners_e59bb2812d_sharding_key_id_idx;
|
||||
|
||||
ALTER INDEX index_ci_runners_e59bb2812d_on_token_expires_at_and_id_desc ATTACH PARTITION project_type_ci_runners_e59bb2812d_token_expires_at_id_idx;
|
||||
|
||||
ALTER INDEX idx_ci_runners_e59bb2812d_on_token_expires_at_desc_and_id_desc ATTACH PARTITION project_type_ci_runners_e59bb2812d_token_expires_at_id_idx1;
|
||||
|
||||
ALTER INDEX idx_uniq_ci_runners_e59bb2812d_on_token_and_type_where_not_null ATTACH PARTITION project_type_ci_runners_e59bb2812d_token_runner_type_idx;
|
||||
|
||||
ALTER INDEX index_uniq_ci_runners_e59bb2812d_on_token_encrypted_and_type ATTACH PARTITION project_type_ci_runners_e59bb28_token_encrypted_runner_type_idx;
|
||||
|
||||
ALTER INDEX p_ci_job_artifacts_expire_at_job_id_idx1 ATTACH PARTITION tmp_index_ci_job_artifacts_on_expire_at_where_locked_unknown;
|
||||
|
||||
ALTER INDEX p_ci_builds_token_encrypted_partition_id_idx ATTACH PARTITION unique_ci_builds_token_encrypted_and_partition_id;
|
||||
|
|
@ -33772,6 +34227,8 @@ CREATE TRIGGER push_rules_loose_fk_trigger AFTER DELETE ON push_rules REFERENCIN
|
|||
|
||||
CREATE TRIGGER table_sync_trigger_57c8465cd7 AFTER INSERT OR DELETE OR UPDATE ON merge_request_diff_commits FOR EACH ROW EXECUTE FUNCTION table_sync_function_0992e728d3();
|
||||
|
||||
CREATE TRIGGER table_sync_trigger_61879721b5 AFTER INSERT OR DELETE OR UPDATE ON ci_runners FOR EACH ROW EXECUTE FUNCTION table_sync_function_686d6c7993();
|
||||
|
||||
CREATE TRIGGER table_sync_trigger_cd362c20e2 AFTER INSERT OR DELETE OR UPDATE ON merge_request_diff_files FOR EACH ROW EXECUTE FUNCTION table_sync_function_3f39f64fc3();
|
||||
|
||||
CREATE TRIGGER tags_loose_fk_trigger AFTER DELETE ON tags REFERENCING OLD TABLE AS old_table FOR EACH STATEMENT EXECUTE FUNCTION insert_into_loose_foreign_keys_deleted_records();
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ described, it is possible to adapt these instructions to your needs.
|
|||
|
||||
## Architecture overview
|
||||
|
||||

|
||||

|
||||
|
||||
_[diagram source - GitLab employees only](https://docs.google.com/drawings/d/1z0VlizKiLNXVVVaERFwgsIOuEgjcUqDTWPdQYsE7Z4c/edit)_
|
||||
|
||||
|
|
|
|||
|
|
@ -105,6 +105,10 @@ DETAILS:
|
|||
**Tier:** Premium, Ultimate
|
||||
**Offering:** Self-managed
|
||||
|
||||
NOTE:
|
||||
The repository size limit includes repository files and LFS, but does not include artifacts, uploads,
|
||||
wiki, packages, containers, or snippets. The repository size limit applies to both private and public projects.
|
||||
|
||||
Repositories in your GitLab instance can grow quickly, especially if you are
|
||||
using LFS. Their size can grow exponentially, rapidly consuming available storage.
|
||||
To prevent this from happening, you can set a hard limit for your repositories' size.
|
||||
|
|
@ -150,10 +154,6 @@ The first push of a new project, including LFS objects, is checked for size.
|
|||
If the sum of their sizes exceeds the maximum allowed repository size, the push
|
||||
is rejected.
|
||||
|
||||
NOTE:
|
||||
The repository size limit includes repository files and LFS, but does not include artifacts, uploads,
|
||||
wiki, packages, or snippets. The repository size limit applies to both private and public projects.
|
||||
|
||||
For details on manually purging files, see [reducing the repository size using Git](../../user/project/repository/repository_size.md#methods-to-reduce-repository-size).
|
||||
|
||||
## Session duration
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
|
|
@ -102,7 +102,7 @@ for all authenticated users, and on the **Admin** area pages. The statuses are:
|
|||
- Red: The version of GitLab you are running is vulnerable. You should install
|
||||
the latest version with security fixes as soon as possible.
|
||||
|
||||

|
||||

|
||||
|
||||
### Enable or disable version check
|
||||
|
||||
|
|
|
|||
|
|
@ -29338,6 +29338,7 @@ An organization user badge.
|
|||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="organizationuserpermissionsadminorganization"></a>`adminOrganization` | [`Boolean!`](#boolean) | If `true`, the user can perform `admin_organization` on this resource. |
|
||||
| <a id="organizationuserpermissionsdeleteuser"></a>`deleteUser` | [`Boolean!`](#boolean) | If `true`, the user can perform `delete_user` on this resource. |
|
||||
| <a id="organizationuserpermissionsremoveuser"></a>`removeUser` | [`Boolean!`](#boolean) | If `true`, the user can perform `remove_user` on this resource. |
|
||||
|
||||
|
|
|
|||
|
|
@ -352,7 +352,7 @@ GitLab can display the results of one or more reports in the
|
|||
## `artifacts:reports:repository_xray`
|
||||
|
||||
DETAILS:
|
||||
**Tier:** Ultimate
|
||||
**Tier:** Premium, Ultimate
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/432235) in GitLab 16.7.
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@ When a project's repository and LFS exceed 10 GiB, the project is set to a read-
|
|||
You cannot push changes to a read-only project. To increase storage of the project's repository and LFS to more than 10 GiB,
|
||||
you must [purchase more storage](../subscriptions/gitlab_com/index.md#purchase-more-storage).
|
||||
|
||||
Only the project's repository and LFS are included in the storage limit. The container registry, package registry, and build artifacts are not included in the limit.
|
||||
|
||||
## View storage
|
||||
|
||||
DETAILS:
|
||||
|
|
|
|||
|
|
@ -43,9 +43,12 @@ module Gitlab
|
|||
argument :key_paths, type: :array, desc: 'Unique JSON key paths for the metrics'
|
||||
|
||||
def create_metric_file
|
||||
say("This generator is DEPRECATED. Use Internal Events tracking framework instead.")
|
||||
# rubocop: disable Gitlab/DocUrl -- link for developers, not users
|
||||
say("This generator is DEPRECATED. For event based metrics use Internal Events tracking framework instead.")
|
||||
# rubocop: disable Gitlab/DocUrl -- links for developers, not users
|
||||
say("https://docs.gitlab.com/ee/development/internal_analytics/internal_event_instrumentation/quick_start.html")
|
||||
|
||||
say("If you need to implement Database, Prometheus or custom metrics, see")
|
||||
say("https://docs.gitlab.com/ee/development/internal_analytics/metrics/metrics_instrumentation.html")
|
||||
# rubocop: enable Gitlab/DocUrl
|
||||
desc = ask("Would you like to continue anyway? y/N") || 'n'
|
||||
return unless desc.casecmp('y') == 0
|
||||
|
|
|
|||
|
|
@ -9,7 +9,8 @@ module Gitlab
|
|||
include ::Gitlab::Database::MigrationHelpers::LooseForeignKeyHelpers
|
||||
|
||||
ALLOWED_TABLES = %w[group_audit_events project_audit_events instance_audit_events user_audit_events
|
||||
audit_events web_hook_logs merge_request_diff_files merge_request_diff_commits].freeze
|
||||
audit_events web_hook_logs merge_request_diff_files merge_request_diff_commits
|
||||
ci_runners ci_runner_machines].freeze
|
||||
|
||||
ERROR_SCOPE = 'table partitioning'
|
||||
|
||||
|
|
|
|||
|
|
@ -35072,6 +35072,9 @@ msgstr ""
|
|||
msgid "MlModelRegistry|Provide the max allowed file size"
|
||||
msgstr ""
|
||||
|
||||
msgid "MlModelRegistry|Publisher"
|
||||
msgstr ""
|
||||
|
||||
msgid "MlModelRegistry|Save changes"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -35090,6 +35093,9 @@ msgstr ""
|
|||
msgid "MlModelRegistry|This model has no candidates"
|
||||
msgstr ""
|
||||
|
||||
msgid "MlModelRegistry|Total versions"
|
||||
msgstr ""
|
||||
|
||||
msgid "MlModelRegistry|Triggered by"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -38409,6 +38415,9 @@ msgstr ""
|
|||
msgid "Organization|Organization overview"
|
||||
msgstr ""
|
||||
|
||||
msgid "Organization|Organization role"
|
||||
msgstr ""
|
||||
|
||||
msgid "Organization|Organization settings"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
source 'https://rubygems.org'
|
||||
|
||||
gem 'gitlab-qa', '~> 14', '>= 14.19.0', require: 'gitlab/qa'
|
||||
gem 'gitlab-qa', '~> 14', '>= 14.19.1', require: 'gitlab/qa'
|
||||
gem 'gitlab_quality-test_tooling', '~> 2.1.0', require: false
|
||||
gem 'gitlab-utils', path: '../gems/gitlab-utils'
|
||||
gem 'activesupport', '~> 7.0.8.4' # This should stay in sync with the root's Gemfile
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ GEM
|
|||
gitlab (4.19.0)
|
||||
httparty (~> 0.20)
|
||||
terminal-table (>= 1.5.1)
|
||||
gitlab-qa (14.19.0)
|
||||
gitlab-qa (14.19.1)
|
||||
activesupport (>= 6.1, < 7.2)
|
||||
gitlab (~> 4.19)
|
||||
http (~> 5.0)
|
||||
|
|
@ -362,7 +362,7 @@ DEPENDENCIES
|
|||
fog-core (= 2.1.0)
|
||||
fog-google (~> 1.24, >= 1.24.1)
|
||||
gitlab-cng!
|
||||
gitlab-qa (~> 14, >= 14.19.0)
|
||||
gitlab-qa (~> 14, >= 14.19.1)
|
||||
gitlab-utils!
|
||||
gitlab_quality-test_tooling (~> 2.1.0)
|
||||
googleauth (~> 1.9.0)
|
||||
|
|
|
|||
|
|
@ -517,7 +517,7 @@ module QA
|
|||
# Uses the API to wait until a pull mirroring update is successful (pull mirroring is treated as an import)
|
||||
def wait_for_pull_mirroring
|
||||
mirror_succeeded = Support::Retrier.retry_until(
|
||||
max_duration: 180,
|
||||
max_duration: 360,
|
||||
raise_on_failure: false,
|
||||
sleep_interval: 1
|
||||
) do
|
||||
|
|
@ -525,7 +525,10 @@ module QA
|
|||
api_resource[:import_status] == "finished"
|
||||
end
|
||||
|
||||
raise "Mirroring failed with error: #{api_resource[:import_error]}" unless mirror_succeeded
|
||||
return if mirror_succeeded
|
||||
|
||||
mirror_error = api_resource[:import_error] || 'Did not complete within 360 seconds'
|
||||
raise "Mirroring was not successful: #{mirror_error}}"
|
||||
end
|
||||
|
||||
def remove_via_api!
|
||||
|
|
|
|||
|
|
@ -110,6 +110,8 @@ RSpec.describe 'Database schema',
|
|||
ci_runners: %w[sharding_key_id], # This value is meant to populate the partitioned table, no other usage
|
||||
ci_runner_machines: %w[sharding_key_id], # This value is meant to populate the partitioned table, no other usage
|
||||
ci_runner_projects: %w[runner_id],
|
||||
ci_runners_e59bb2812d: %w[sharding_key_id], # This field is only used in the partitions, and has the appropriate FKs
|
||||
instance_type_ci_runners_e59bb2812d: %w[sharding_key_id], # This field is always NULL in this partition
|
||||
ci_sources_pipelines: %w[partition_id source_partition_id source_job_id],
|
||||
ci_sources_projects: %w[partition_id],
|
||||
ci_stages: %w[partition_id project_id pipeline_id],
|
||||
|
|
|
|||
|
|
@ -169,7 +169,7 @@ RSpec.describe 'Organizations (GraphQL fixtures)', feature_category: :cell do
|
|||
end
|
||||
|
||||
describe 'organization users' do
|
||||
base_input_path = 'organizations/users/graphql/'
|
||||
base_input_path = 'organizations/users/graphql/queries/'
|
||||
base_output_path = 'graphql/organizations/'
|
||||
query_name = 'organization_users.query.graphql'
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { GlBadge, GlTab, GlTabs, GlIcon, GlSprintf, GlLink } from '@gitlab/ui';
|
||||
import { GlAvatar, GlBadge, GlTab, GlTabs, GlIcon, GlSprintf, GlLink } from '@gitlab/ui';
|
||||
import Vue from 'vue';
|
||||
import VueApollo from 'vue-apollo';
|
||||
import VueRouter from 'vue-router';
|
||||
|
|
@ -305,4 +305,50 @@ describe('ml/model_registry/apps/show_ml_model', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Sidebar', () => {
|
||||
beforeEach(() => createWrapper());
|
||||
|
||||
const findSidebarAuthorLink = () => wrapper.findByTestId('sidebar-author-link');
|
||||
const findAvatar = () => wrapper.findComponent(GlAvatar);
|
||||
const findLatestVersionLink = () => wrapper.findByTestId('sidebar-latest-version-link');
|
||||
const findVersionCount = () => wrapper.findByTestId('sidebar-version-count');
|
||||
|
||||
it('displays sidebar author link', () => {
|
||||
expect(findSidebarAuthorLink().attributes('href')).toBe('path/to/user');
|
||||
expect(findSidebarAuthorLink().text()).toBe('Root');
|
||||
});
|
||||
|
||||
it('displays sidebar avatar', () => {
|
||||
expect(findAvatar().props('src')).toBe('path/to/avatar');
|
||||
});
|
||||
|
||||
it('displays sidebar latest version link', () => {
|
||||
expect(findLatestVersionLink().attributes('href')).toBe(
|
||||
'/root/test-project/-/ml/models/1/versions/5000',
|
||||
);
|
||||
expect(findLatestVersionLink().text()).toBe('1.0.4999');
|
||||
});
|
||||
|
||||
it('displays sidebar version count', () => {
|
||||
expect(findVersionCount().text()).toBe('1');
|
||||
});
|
||||
|
||||
describe('when model does not get loaded', () => {
|
||||
const error = new Error('Failure!');
|
||||
beforeEach(() => createWrapper({ modelDetailsResolver: jest.fn().mockRejectedValue(error) }));
|
||||
|
||||
it('does not display sidebar author link', () => {
|
||||
expect(findSidebarAuthorLink().exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('does not display sidebar latest version link', () => {
|
||||
expect(findLatestVersionLink().exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('does not display sidebar version count', () => {
|
||||
expect(findVersionCount().exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
|||
import createMockApollo from 'helpers/mock_apollo_helper';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import { createAlert } from '~/alert';
|
||||
import organizationUsersQuery from '~/organizations/users/graphql/organization_users.query.graphql';
|
||||
import organizationUsersQuery from '~/organizations/users/graphql/queries/organization_users.query.graphql';
|
||||
import OrganizationsUsersApp from '~/organizations/users/components/app.vue';
|
||||
import OrganizationsUsersView from '~/organizations/users/components/users_view.vue';
|
||||
import { ORGANIZATION_USERS_PER_PAGE } from '~/organizations/users/constants';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { GlLoadingIcon, GlKeysetPagination } from '@gitlab/ui';
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import { GlLoadingIcon, GlKeysetPagination, GlCollapsibleListbox } from '@gitlab/ui';
|
||||
import { mountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import UsersView from '~/organizations/users/components/users_view.vue';
|
||||
import UsersTable from '~/vue_shared/components/users_table/users_table.vue';
|
||||
import { pageInfoMultiplePages } from 'jest/organizations/mock_data';
|
||||
|
|
@ -9,7 +9,7 @@ describe('UsersView', () => {
|
|||
let wrapper;
|
||||
|
||||
const createComponent = (props = {}) => {
|
||||
wrapper = shallowMount(UsersView, {
|
||||
wrapper = mountExtended(UsersView, {
|
||||
propsData: {
|
||||
loading: false,
|
||||
users: MOCK_USERS_FORMATTED,
|
||||
|
|
@ -66,4 +66,46 @@ describe('UsersView', () => {
|
|||
expect(wrapper.emitted('prev')).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Organization role', () => {
|
||||
describe('when user has permissions to change organization role', () => {
|
||||
const users = MOCK_USERS_FORMATTED.map((user) => ({
|
||||
...user,
|
||||
userPermissions: { ...user.userPermissions, adminOrganization: true },
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
createComponent({
|
||||
loading: false,
|
||||
users,
|
||||
});
|
||||
});
|
||||
|
||||
it('renders listbox with role options', () => {
|
||||
expect(wrapper.findComponent(GlCollapsibleListbox).props()).toMatchObject({
|
||||
items: [
|
||||
{
|
||||
text: 'User',
|
||||
value: 'DEFAULT',
|
||||
},
|
||||
{
|
||||
text: 'Owner',
|
||||
value: 'OWNER',
|
||||
},
|
||||
],
|
||||
selected: users[0].accessLevel.stringValue,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when does not have permissions to change organization role', () => {
|
||||
beforeEach(() => {
|
||||
createComponent({ loading: false, users: MOCK_USERS_FORMATTED });
|
||||
});
|
||||
|
||||
it('renders role as text', () => {
|
||||
expect(wrapper.findByRole('cell', { name: 'User' }).exists()).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -13,6 +13,16 @@ export const MOCK_PATHS = {
|
|||
adminUser: '/admin/users/:id',
|
||||
};
|
||||
|
||||
export const MOCK_USERS_FORMATTED = users.map(({ badges, user }) => {
|
||||
return { ...user, id: getIdFromGraphQLId(user.id), badges, email: user.publicEmail };
|
||||
});
|
||||
export const MOCK_USERS_FORMATTED = users.map(
|
||||
({ id, badges, user, accessLevel, userPermissions }) => {
|
||||
return {
|
||||
...user,
|
||||
gid: id,
|
||||
id: getIdFromGraphQLId(user.id),
|
||||
badges,
|
||||
accessLevel,
|
||||
userPermissions,
|
||||
email: user.publicEmail,
|
||||
};
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { mountExtended } from 'helpers/vue_test_utils_helper';
|
|||
import UsersTable from '~/vue_shared/components/users_table/users_table.vue';
|
||||
import UserAvatar from '~/vue_shared/components/users_table/user_avatar.vue';
|
||||
import UserDate from '~/vue_shared/components/user_date.vue';
|
||||
import { FIELD_NAME, FIELD_ORGANIZATION_ROLE } from '~/vue_shared/components/users_table/constants';
|
||||
import { MOCK_USERS, MOCK_ADMIN_USER_PATH, MOCK_GROUP_COUNTS } from './mock_data';
|
||||
|
||||
describe('UsersTable component', () => {
|
||||
|
|
@ -21,7 +22,7 @@ describe('UsersTable component', () => {
|
|||
.find(`[data-label="${label}"][role="cell"]`);
|
||||
};
|
||||
|
||||
const initComponent = (props = {}) => {
|
||||
const initComponent = (props = {}, scopedSlots = {}) => {
|
||||
wrapper = mountExtended(UsersTable, {
|
||||
propsData: {
|
||||
users: MOCK_USERS,
|
||||
|
|
@ -30,6 +31,7 @@ describe('UsersTable component', () => {
|
|||
groupCountsLoading: false,
|
||||
...props,
|
||||
},
|
||||
scopedSlots,
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -93,4 +95,34 @@ describe('UsersTable component', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when fieldsToRender prop is passed', () => {
|
||||
beforeEach(() => {
|
||||
initComponent({ fieldsToRender: [FIELD_NAME] });
|
||||
});
|
||||
|
||||
it('only renders specified fields', () => {
|
||||
expect(getCellByLabel(0, 'Name').exists()).toBe(true);
|
||||
expect(getCellByLabel(0, 'Created on').exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when columnWidths prop is passed', () => {
|
||||
beforeEach(() => {
|
||||
initComponent({ columnWidths: { [FIELD_NAME]: 'gl-w-5/20' } });
|
||||
});
|
||||
|
||||
it('sets th CSS class', () => {
|
||||
expect(wrapper.findByRole('columnheader', { name: 'Name' }).classes()).toContain('gl-w-5/20');
|
||||
});
|
||||
});
|
||||
|
||||
it('renders organization role slot', () => {
|
||||
initComponent(
|
||||
{ fieldsToRender: [FIELD_ORGANIZATION_ROLE] },
|
||||
{ 'organization-role': '<div data-testid="organization-role-slot"></div>' },
|
||||
);
|
||||
|
||||
expect(wrapper.findByTestId('organization-role-slot').exists()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import createMockApollo from 'helpers/mock_apollo_helper';
|
|||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import CreateWorkItem from '~/work_items/components/create_work_item.vue';
|
||||
import CreateWorkItemModal from '~/work_items/components/create_work_item_modal.vue';
|
||||
import { WORK_ITEMS_TYPE_MAP, WORK_ITEM_TYPE_ROUTE_WORK_ITEM } from '~/work_items/constants';
|
||||
import namespaceWorkItemTypesQuery from '~/work_items/graphql/namespace_work_item_types.query.graphql';
|
||||
|
||||
const showToast = jest.fn();
|
||||
|
|
@ -25,6 +26,7 @@ describe('CreateWorkItemModal', () => {
|
|||
const findDropdownItem = () => wrapper.findComponent(GlDisclosureDropdownItem);
|
||||
const findModal = () => wrapper.findComponent(GlModal);
|
||||
const findForm = () => wrapper.findComponent(CreateWorkItem);
|
||||
const findOpenInFullPageButton = () => wrapper.find('[data-testid="new-work-item-modal-link"]');
|
||||
|
||||
const namespaceSingleWorkItemTypeQueryResponse = {
|
||||
data: {
|
||||
|
|
@ -77,6 +79,9 @@ describe('CreateWorkItemModal', () => {
|
|||
show: showToast,
|
||||
},
|
||||
},
|
||||
stubs: {
|
||||
GlModal,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -100,16 +105,32 @@ describe('CreateWorkItemModal', () => {
|
|||
});
|
||||
|
||||
describe('default trigger', () => {
|
||||
it('opens modal on trigger click', async () => {
|
||||
it('opens modal and prevents following link on click', async () => {
|
||||
createComponent();
|
||||
|
||||
await waitForPromises();
|
||||
|
||||
findTrigger().vm.$emit('click');
|
||||
const mockEvent = { preventDefault: jest.fn() };
|
||||
findTrigger().vm.$emit('click', mockEvent);
|
||||
|
||||
await nextTick();
|
||||
|
||||
expect(findModal().props('visible')).toBe(true);
|
||||
expect(mockEvent.preventDefault).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not open modal or prevent link default on ctrl+click', async () => {
|
||||
createComponent();
|
||||
|
||||
await waitForPromises();
|
||||
|
||||
const mockEvent = { preventDefault: jest.fn(), ctrlKey: true };
|
||||
findTrigger().vm.$emit('click', mockEvent);
|
||||
|
||||
await nextTick();
|
||||
|
||||
expect(findModal().props('visible')).toBe(false);
|
||||
expect(mockEvent.preventDefault).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not render when hideButton=true', () => {
|
||||
|
|
@ -149,6 +170,20 @@ describe('CreateWorkItemModal', () => {
|
|||
expect(findModal().props('visible')).toBe(false);
|
||||
});
|
||||
|
||||
for (const [workItemTypeName, vals] of Object.entries(WORK_ITEMS_TYPE_MAP)) {
|
||||
it(`has link to new work item page in modal header for ${workItemTypeName}`, async () => {
|
||||
createComponent({ workItemTypeName });
|
||||
|
||||
const routeParamName = vals.routeParamName || WORK_ITEM_TYPE_ROUTE_WORK_ITEM;
|
||||
|
||||
await waitForPromises();
|
||||
|
||||
expect(findOpenInFullPageButton().attributes().href).toBe(
|
||||
`/full-path/-/${routeParamName}/new`,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
it('when there are no work item types it does not set the cache', async () => {
|
||||
createComponent({ namespaceWorkItemTypesQueryHandler: workItemTypesEmptyQueryHandler });
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,12 @@
|
|||
import { NEW_WORK_ITEM_IID } from '~/work_items/constants';
|
||||
import {
|
||||
NEW_WORK_ITEM_IID,
|
||||
WORK_ITEM_TYPE_ENUM_ISSUE,
|
||||
WORK_ITEM_TYPE_ENUM_EPIC,
|
||||
} from '~/work_items/constants';
|
||||
import {
|
||||
autocompleteDataSources,
|
||||
markdownPreviewPath,
|
||||
newWorkItemPath,
|
||||
isReference,
|
||||
getWorkItemIcon,
|
||||
workItemRoadmapPath,
|
||||
|
|
@ -112,6 +117,34 @@ describe('markdownPreviewPath', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('newWorkItemPath', () => {
|
||||
beforeEach(() => {
|
||||
gon.relative_url_root = '/foobar';
|
||||
});
|
||||
|
||||
it('returns correct path', () => {
|
||||
expect(newWorkItemPath({ fullPath: 'group/project' })).toBe(
|
||||
'/foobar/group/project/-/work_items/new',
|
||||
);
|
||||
});
|
||||
|
||||
it('returns correct path for workItemType', () => {
|
||||
expect(
|
||||
newWorkItemPath({ fullPath: 'group/project', workItemTypeName: WORK_ITEM_TYPE_ENUM_ISSUE }),
|
||||
).toBe('/foobar/group/project/-/issues/new');
|
||||
});
|
||||
|
||||
it('returns correct data sources with group context', () => {
|
||||
expect(
|
||||
newWorkItemPath({
|
||||
fullPath: 'group',
|
||||
isGroup: true,
|
||||
workItemTypeName: WORK_ITEM_TYPE_ENUM_EPIC,
|
||||
}),
|
||||
).toBe('/foobar/groups/group/-/epics/new');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getWorkItemIcon', () => {
|
||||
it.each(['epic', 'issue-type-epic'])('returns epic icon in case of %s', (icon) => {
|
||||
expect(getWorkItemIcon(icon)).toBe('epic');
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ RSpec.describe Types::PermissionTypes::OrganizationUser, feature_category: :cell
|
|||
expected_permissions = %i[
|
||||
remove_user
|
||||
delete_user
|
||||
admin_organization
|
||||
]
|
||||
|
||||
expect(described_class).to have_graphql_fields(expected_permissions)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe '1_settings', feature_category: :shared do
|
||||
include_context 'when loading 1_settings initializer'
|
||||
|
||||
it 'settings do not change after reload' do
|
||||
original_settings = Settings.to_h
|
||||
|
||||
load_settings
|
||||
|
||||
new_settings = Settings.to_h
|
||||
|
||||
# Gitlab::Pages::Settings is a SimpleDelegator, so each time the settings
|
||||
# are reloaded a new SimpleDelegator wraps the original object. Convert
|
||||
# the settings to a Hash to ensure the comparison works.
|
||||
[new_settings, original_settings].each do |settings|
|
||||
settings['pages'] = settings['pages'].to_h
|
||||
end
|
||||
expect(new_settings).to eq(original_settings)
|
||||
end
|
||||
|
||||
describe 'DNS rebinding protection' do
|
||||
subject(:dns_rebinding_protection_enabled) { Settings.gitlab.dns_rebinding_protection_enabled }
|
||||
|
||||
let(:http_proxy) { nil }
|
||||
|
||||
before do
|
||||
# Reset it, because otherwise we might memoize the value across tests.
|
||||
Settings.gitlab['dns_rebinding_protection_enabled'] = nil
|
||||
stub_env('http_proxy', http_proxy)
|
||||
load_settings
|
||||
end
|
||||
|
||||
it { is_expected.to be(true) }
|
||||
|
||||
context 'when an HTTP proxy environment variable is set' do
|
||||
let(:http_proxy) { 'http://myproxy.com:8080' }
|
||||
|
||||
it { is_expected.to be(false) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -4,95 +4,107 @@ require 'spec_helper'
|
|||
|
||||
RSpec.describe Gitlab::BackgroundMigration::BackfillShardingKeyIdOnCiRunners, schema: 20240923132401,
|
||||
migration: :gitlab_ci, feature_category: :runner do
|
||||
let(:runners) { table(:ci_runners) }
|
||||
let(:runner_projects) { table(:ci_runner_projects) }
|
||||
let(:runner_namespaces) { table(:ci_runner_namespaces) }
|
||||
include Database::TableSchemaHelpers
|
||||
|
||||
let(:connection) { Ci::ApplicationRecord.connection }
|
||||
|
||||
let(:args) do
|
||||
min, max = runners.pick('MIN(id)', 'MAX(id)')
|
||||
|
||||
{
|
||||
start_id: min,
|
||||
end_id: max,
|
||||
batch_table: 'ci_runners',
|
||||
batch_column: 'id',
|
||||
sub_batch_size: 100,
|
||||
pause_ms: 0,
|
||||
connection: connection
|
||||
}
|
||||
end
|
||||
|
||||
let(:group_id) { 100 }
|
||||
let(:other_group_id) { 101 }
|
||||
let(:project_id) { 1000 }
|
||||
let(:other_project_id) { 1001 }
|
||||
let!(:orphaned_project_runner) { create_project_runner(project_ids: []) }
|
||||
|
||||
subject(:perform_migration) { described_class.new(**args).perform }
|
||||
|
||||
before do
|
||||
runners.create!(runner_type: 1)
|
||||
|
||||
create_project_runner(project_ids: project_id)
|
||||
create_project_runner(project_ids: other_project_id)
|
||||
|
||||
create_group_runner(group_id: group_id)
|
||||
create_group_runner(group_id: other_group_id)
|
||||
end
|
||||
|
||||
it 'backfills sharding_key_id', :aggregate_failures do
|
||||
expect { perform_migration }.not_to change { orphaned_project_runner.sharding_key_id }
|
||||
|
||||
runners.where(runner_type: 1).find_each do |runner|
|
||||
expect(runner.sharding_key_id).to be_nil
|
||||
end
|
||||
|
||||
runner_namespaces.find_each do |runner_namespace|
|
||||
expect(runners.find(runner_namespace.runner_id).sharding_key_id).to eq(runner_namespace.namespace_id)
|
||||
end
|
||||
|
||||
runner_projects.find_each do |runner_project|
|
||||
expect(runners.find(runner_project.runner_id).sharding_key_id).to eq(runner_project.project_id)
|
||||
if table_oid('ci_runners_e59bb2812d').present?
|
||||
connection.execute("ALTER TABLE ci_runners_e59bb2812d DROP CONSTRAINT IF EXISTS check_sharding_key_id_nullness")
|
||||
end
|
||||
end
|
||||
|
||||
context 'when a project runner is shared with other projects' do
|
||||
let(:runner_project_ids) { [other_project_id, project_id] }
|
||||
describe '#perform' do
|
||||
let(:runners) { table(:ci_runners) }
|
||||
let(:runner_projects) { table(:ci_runner_projects) }
|
||||
let(:runner_namespaces) { table(:ci_runner_namespaces) }
|
||||
|
||||
it 'backfills sharding_key_id with the id of the owner project' do
|
||||
shared_project_runner = create_project_runner(project_ids: runner_project_ids)
|
||||
let(:args) do
|
||||
min, max = runners.pick('MIN(id)', 'MAX(id)')
|
||||
|
||||
expect do
|
||||
perform_migration
|
||||
end.to change { shared_project_runner.reload.sharding_key_id }.from(nil).to(other_project_id)
|
||||
{
|
||||
start_id: min,
|
||||
end_id: max,
|
||||
batch_table: 'ci_runners',
|
||||
batch_column: 'id',
|
||||
sub_batch_size: 100,
|
||||
pause_ms: 0,
|
||||
connection: connection
|
||||
}
|
||||
end
|
||||
|
||||
context 'when the project has a different owner project' do
|
||||
let(:runner_project_ids) { [project_id, other_project_id] }
|
||||
let(:group_id) { 100 }
|
||||
let(:other_group_id) { 101 }
|
||||
let(:project_id) { 1000 }
|
||||
let(:other_project_id) { 1001 }
|
||||
let(:orphaned_project_runner) { create_project_runner(project_ids: []) }
|
||||
|
||||
subject(:perform_migration) { described_class.new(**args).perform }
|
||||
|
||||
before do
|
||||
runners.create!(runner_type: 1)
|
||||
|
||||
orphaned_project_runner
|
||||
create_project_runner(project_ids: project_id)
|
||||
create_project_runner(project_ids: other_project_id)
|
||||
|
||||
create_group_runner(group_id: group_id)
|
||||
create_group_runner(group_id: other_group_id)
|
||||
end
|
||||
|
||||
it 'backfills sharding_key_id', :aggregate_failures do
|
||||
expect { perform_migration }.not_to change { orphaned_project_runner.sharding_key_id }
|
||||
|
||||
runners.where(runner_type: 1).find_each do |runner|
|
||||
expect(runner.sharding_key_id).to be_nil
|
||||
end
|
||||
|
||||
runner_namespaces.find_each do |runner_namespace|
|
||||
expect(runners.find(runner_namespace.runner_id).sharding_key_id).to eq(runner_namespace.namespace_id)
|
||||
end
|
||||
|
||||
runner_projects.find_each do |runner_project|
|
||||
expect(runners.find(runner_project.runner_id).sharding_key_id).to eq(runner_project.project_id)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when a project runner is shared with other projects' do
|
||||
let(:runner_project_ids) { [other_project_id, project_id] }
|
||||
|
||||
it 'backfills sharding_key_id with the id of the owner project' do
|
||||
shared_project_runner = create_project_runner(project_ids: runner_project_ids)
|
||||
|
||||
expect do
|
||||
perform_migration
|
||||
end.to change { shared_project_runner.reload.sharding_key_id }.from(nil).to(project_id)
|
||||
end.to change { shared_project_runner.reload.sharding_key_id }.from(nil).to(other_project_id)
|
||||
end
|
||||
|
||||
context 'when the project has a different owner project' do
|
||||
let(:runner_project_ids) { [project_id, other_project_id] }
|
||||
|
||||
it 'backfills sharding_key_id with the id of the owner project' do
|
||||
shared_project_runner = create_project_runner(project_ids: runner_project_ids)
|
||||
|
||||
expect do
|
||||
perform_migration
|
||||
end.to change { shared_project_runner.reload.sharding_key_id }.from(nil).to(project_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def create_group_runner(group_id:)
|
||||
runners.create!(runner_type: 2, sharding_key_id: nil).tap do |runner|
|
||||
runner_namespaces.create!(runner_id: runner.id, namespace_id: group_id)
|
||||
def create_group_runner(group_id:)
|
||||
runners.create!(runner_type: 2, sharding_key_id: nil).tap do |runner|
|
||||
runner_namespaces.create!(runner_id: runner.id, namespace_id: group_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def create_project_runner(project_ids:)
|
||||
project_ids = Array.wrap(project_ids)
|
||||
def create_project_runner(project_ids:)
|
||||
project_ids = Array.wrap(project_ids)
|
||||
|
||||
runners.create!(runner_type: 3, sharding_key_id: nil).tap do |runner|
|
||||
project_ids.each do |project_id|
|
||||
runner_projects.create!(runner_id: runner.id, project_id: project_id)
|
||||
runners.create!(runner_type: 3, sharding_key_id: nil).tap do |runner|
|
||||
project_ids.each do |project_id|
|
||||
runner_projects.create!(runner_id: runner.id, project_id: project_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ RSpec.describe 'new tables missing sharding_key', feature_category: :cell do
|
|||
"since it now has a valid constraint."
|
||||
else
|
||||
expect(not_nullable || has_null_check_constraint).to eq(true),
|
||||
"Missing a not null constraint for `#{table_name}.#{column_name}` . " \
|
||||
"Missing a not null constraint for `#{table_name}.#{column_name}`. " \
|
||||
"All sharding keys must be not nullable or have a NOT NULL check constraint"
|
||||
end
|
||||
else
|
||||
|
|
|
|||
|
|
@ -18,48 +18,42 @@ RSpec.describe ::Gitlab::LetsEncrypt::Order, feature_category: :pages do
|
|||
end
|
||||
|
||||
describe '#new_challenge' do
|
||||
it 'returns challenge' do
|
||||
expect(order.new_challenge).to be_a(::Gitlab::LetsEncrypt::Challenge)
|
||||
end
|
||||
it { expect(order.new_challenge).to be_a ::Gitlab::LetsEncrypt::Challenge }
|
||||
end
|
||||
|
||||
describe '#request_certificate' do
|
||||
let(:private_key) do
|
||||
OpenSSL::PKey::RSA.new(4096).to_pem
|
||||
let(:private_key) { OpenSSL::PKey::RSA.new(4096).to_pem }
|
||||
|
||||
before do
|
||||
allow(acme_order).to receive(:finalize)
|
||||
end
|
||||
|
||||
it 'generates csr and finalizes order' do
|
||||
expect(acme_order).to receive(:finalize) do |csr:|
|
||||
expect do
|
||||
csr.csr # it's being evaluated lazily
|
||||
end.not_to raise_error
|
||||
end
|
||||
|
||||
order.request_certificate(domain: 'example.com', private_key: private_key)
|
||||
|
||||
expect(acme_order).to have_received(:finalize) do |csr:|
|
||||
# it's being evaluated lazily
|
||||
expect { csr.csr }.not_to raise_error
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#challenge_error' do
|
||||
it 'returns error if challenge has errors' do
|
||||
challenge = acme_challenge_double
|
||||
|
||||
# error just to give an example
|
||||
error = {
|
||||
let(:acme_order) { acme_order_double(authorizations: [acme_authorization_double(challenge)]) }
|
||||
let(:challenge) { acme_challenge_double(error: expected_challenge_error) }
|
||||
let(:expected_challenge_error) do
|
||||
{
|
||||
"type" => "urn:ietf:params:acme:error:dns",
|
||||
"detail" => "No valid IP addresses found for test.example.com",
|
||||
"status" => 400
|
||||
}
|
||||
|
||||
allow(challenge).to receive(:error).and_return(error)
|
||||
|
||||
acme_order = acme_order_double(authorizations: [acme_authorization_double(challenge)])
|
||||
|
||||
expect(described_class.new(acme_order).challenge_error).to eq(error)
|
||||
end
|
||||
|
||||
context 'when requesting authorizations raises error' do
|
||||
subject { order.challenge_error }
|
||||
subject(:challenge_order) { order.challenge_error }
|
||||
|
||||
it { is_expected.to eq expected_challenge_error }
|
||||
|
||||
context 'when requesting authorizations raises error' do
|
||||
let(:acme_order) { acme_order_double }
|
||||
|
||||
before do
|
||||
|
|
|
|||
|
|
@ -0,0 +1,47 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
require_migration!
|
||||
|
||||
RSpec.describe RequeueBackfillApprovalProjectRulesProtectedBranchesProjectId, feature_category: :source_code_management do
|
||||
let!(:batched_migration) { described_class::MIGRATION }
|
||||
let(:expected_job_args) { %i[project_id approval_project_rules project_id approval_project_rule_id] }
|
||||
|
||||
it 'does not schedule a new batched migratio' do
|
||||
reversible_migration do |migration|
|
||||
migration.before -> {
|
||||
expect(batched_migration).not_to have_scheduled_batched_migration
|
||||
}
|
||||
|
||||
migration.after -> {
|
||||
expect(batched_migration).not_to have_scheduled_batched_migration
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
context 'when executed on .com' do
|
||||
before do
|
||||
allow(Gitlab).to receive(:com_except_jh?).and_return(true)
|
||||
end
|
||||
|
||||
it 'schedules a new batched migration' do
|
||||
reversible_migration do |migration|
|
||||
migration.before -> {
|
||||
expect(batched_migration).not_to have_scheduled_batched_migration
|
||||
}
|
||||
|
||||
migration.after -> {
|
||||
expect(batched_migration).to have_scheduled_batched_migration(
|
||||
table_name: described_class::TABLE_NAME,
|
||||
column_name: described_class::BATCH_COLUMN,
|
||||
interval: described_class::DELAY_INTERVAL,
|
||||
batch_size: described_class::BATCH_SIZE,
|
||||
sub_batch_size: described_class::SUB_BATCH_SIZE,
|
||||
gitlab_schema: :gitlab_main_cell,
|
||||
job_arguments: expected_job_args
|
||||
)
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -150,6 +150,16 @@ RSpec.describe Namespaces::Traversal::Cached, feature_category: :database do
|
|||
expect(ids.sort).to eq([group.id, subgroup.id, subsubgroup.id])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the scope is specified' do
|
||||
it 'returns uncached values that match the scope' do
|
||||
ids = group.self_and_descendant_ids(skope: Namespace).pluck(:id)
|
||||
|
||||
expect(ids).to contain_exactly(
|
||||
group.id, subgroup.id, subsubgroup.id, project1.project_namespace.id, project2.project_namespace.id
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#all_project_ids' do
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ RSpec.describe PagesDomains::CreateAcmeOrderService, feature_category: :pages do
|
|||
end
|
||||
|
||||
let(:lets_encrypt_client) do
|
||||
instance_double('Gitlab::LetsEncrypt::Client').tap do |client|
|
||||
instance_double(Gitlab::LetsEncrypt::Client).tap do |client|
|
||||
allow(client).to receive(:new_order).with(pages_domain.domain)
|
||||
.and_return(order_double)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ RSpec.describe ::PagesDomains::CreateService, feature_category: :pages do
|
|||
end
|
||||
|
||||
context 'when the user has the required permissions' do
|
||||
before do
|
||||
before_all do
|
||||
project.add_maintainer(user)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ RSpec.describe PagesDomains::ObtainLetsEncryptCertificateService, feature_catego
|
|||
end
|
||||
|
||||
%w[pending processing].each do |status|
|
||||
context "there is an order in '#{status}' status" do
|
||||
context "when there is an order in '#{status}' status" do
|
||||
let(:existing_order) do
|
||||
create(:pages_domain_acme_order, pages_domain: pages_domain)
|
||||
end
|
||||
|
|
@ -180,7 +180,7 @@ RSpec.describe PagesDomains::ObtainLetsEncryptCertificateService, feature_catego
|
|||
end
|
||||
|
||||
before do
|
||||
expect(api_order).to receive(:certificate) { certificate }
|
||||
allow(api_order).to receive(:certificate).and_return(certificate)
|
||||
end
|
||||
|
||||
it 'saves private_key and certificate for domain' do
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ RSpec.describe PagesDomains::UpdateService, feature_category: :pages do
|
|||
|
||||
context 'when it updates the domain successfully' do
|
||||
it 'updates the domain' do
|
||||
expect(service.execute(pages_domain)).to eq(true)
|
||||
expect(service.execute(pages_domain)).to be true
|
||||
end
|
||||
|
||||
it 'publishes a PagesDomainUpdatedEvent' do
|
||||
|
|
|
|||
|
|
@ -38,9 +38,9 @@ module LetsEncryptHelpers
|
|||
client
|
||||
end
|
||||
|
||||
def acme_challenge_double
|
||||
def acme_challenge_double(attributes = {})
|
||||
challenge = instance_double('Acme::Client::Resources::Challenges::HTTP01')
|
||||
allow(challenge).to receive_messages(ACME_CHALLENGE_METHODS)
|
||||
allow(challenge).to receive_messages(ACME_CHALLENGE_METHODS.merge(attributes))
|
||||
challenge
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
RSpec.shared_context 'when loading 1_settings initializer' do
|
||||
def load_settings
|
||||
# Avoid wrapping Gitlab::Pages::Settings again
|
||||
Settings.pages = Settings.pages.__getobj__
|
||||
|
||||
load Rails.root.join('config/initializers/1_settings.rb')
|
||||
end
|
||||
end
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue