Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
cbb6a29694
commit
59d0f7a222
|
|
@ -748,6 +748,7 @@ lib/gitlab/checks/**
|
|||
/doc/api/project_aliases.md @msedlakjakubowski
|
||||
/doc/api/project_badges.md @msedlakjakubowski
|
||||
/doc/api/project_clusters.md @phillipwells
|
||||
/doc/api/project_container_registry_protection_rules.md @marcel.amirault
|
||||
/doc/api/project_import_export.md @eread
|
||||
/doc/api/project_job_token_scopes.md @marcel.amirault
|
||||
/doc/api/project_level_variables.md @marcel.amirault
|
||||
|
|
@ -830,8 +831,12 @@ lib/gitlab/checks/**
|
|||
/doc/ci/testing/code_quality.md @rdickenson
|
||||
/doc/ci/testing/code_quality_troubleshooting.md @rdickenson @phillipwells
|
||||
/doc/ci/variables/ @marcel.amirault
|
||||
/doc/ci/yaml/ci_job_log_timestamps.md @ashrafkhamis
|
||||
/doc/ci/yaml/signing_examples.md @marcel.amirault
|
||||
/doc/development/advanced_search.md @gitlab-org/search-team/migration-maintainers
|
||||
/doc/development/ai_architecture.md @gitlab-org/ai-powered
|
||||
/doc/development/ai_features/ @gitlab-org/ai-powered
|
||||
/doc/development/ai_features/embeddings.md @gitlab-org/search-team/migration-maintainers
|
||||
/doc/development/application_limits.md @gitlab-org/distribution
|
||||
/doc/development/audit_event_guide/ @gitlab-org/govern/security-policies-frontend @gitlab-org/govern/threat-insights-frontend-team @gitlab-org/govern/threat-insights-backend-team
|
||||
/doc/development/avoiding_required_stops.md @gitlab-org/distribution
|
||||
|
|
@ -1013,9 +1018,7 @@ lib/gitlab/checks/**
|
|||
/doc/user/project/remote_development/ @ashrafkhamis
|
||||
/doc/user/project/repository/code_explain.md @sselhorn @jglassman1 @fneill
|
||||
/doc/user/project/repository/code_suggestions/ @jglassman1
|
||||
/doc/user/project/repository/files/geojson.md @msedlakjakubowski
|
||||
/doc/user/project/repository/files/index.md @ashrafkhamis
|
||||
/doc/user/project/repository/files/jupyter_notebooks/ @msedlakjakubowski
|
||||
/doc/user/project/repository/monorepos/ @eread
|
||||
/doc/user/project/repository/web_editor.md @ashrafkhamis
|
||||
/doc/user/project/settings/import_export.md @eread
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
include:
|
||||
- local: .gitlab/ci/cng/main.gitlab-ci.yml
|
||||
- project: 'gitlab-org/quality/pipeline-common'
|
||||
ref: '8.18.0'
|
||||
ref: '8.18.1'
|
||||
file: ci/base.gitlab-ci.yml
|
||||
|
||||
stages:
|
||||
|
|
|
|||
|
|
@ -2706,7 +2706,6 @@ RSpec/FeatureCategory:
|
|||
- 'spec/lib/gitlab/email/message/repository_push_spec.rb'
|
||||
- 'spec/lib/gitlab/email/smime/signer_spec.rb'
|
||||
- 'spec/lib/gitlab/emoji_spec.rb'
|
||||
- 'spec/lib/gitlab/empty_search_results_spec.rb'
|
||||
- 'spec/lib/gitlab/encrypted_configuration_spec.rb'
|
||||
- 'spec/lib/gitlab/error_tracking/context_payload_generator_spec.rb'
|
||||
- 'spec/lib/gitlab/error_tracking/error_repository/open_api_strategy_spec.rb'
|
||||
|
|
|
|||
|
|
@ -2042,7 +2042,6 @@ RSpec/NamedSubject:
|
|||
- 'spec/lib/gitlab/doctor/secrets_spec.rb'
|
||||
- 'spec/lib/gitlab/email/handler/service_desk_handler_spec.rb'
|
||||
- 'spec/lib/gitlab/email/html_to_markdown_parser_spec.rb'
|
||||
- 'spec/lib/gitlab/empty_search_results_spec.rb'
|
||||
- 'spec/lib/gitlab/encoding_helper_spec.rb'
|
||||
- 'spec/lib/gitlab/error_tracking/error_repository/open_api_strategy_spec.rb'
|
||||
- 'spec/lib/gitlab/etag_caching/store_spec.rb'
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@ RSpec/RepeatedExampleGroupBody:
|
|||
- 'spec/lib/gitlab/ci/pipeline/seed/build_spec.rb'
|
||||
- 'spec/lib/gitlab/ci/yaml_processor_spec.rb'
|
||||
- 'spec/lib/gitlab/database/migrations/batched_background_migration_helpers_spec.rb'
|
||||
- 'spec/lib/gitlab/empty_search_results_spec.rb'
|
||||
- 'spec/lib/gitlab/import_export/project/sample/relation_factory_spec.rb'
|
||||
- 'spec/lib/gitlab/lfs/client_spec.rb'
|
||||
- 'spec/lib/gitlab/sanitizers/exif_spec.rb'
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
117d83886351afe9c05c3a3464cba7e22bc234a3
|
||||
01ac062b95b09b5d2f6390a7b73799d26ef42de2
|
||||
|
|
|
|||
|
|
@ -30,12 +30,12 @@ export const TARGET_NAMESPACE_FIELD = 'targetNamespace';
|
|||
export const ROOT_NAMESPACE = { fullPath: '', id: null };
|
||||
|
||||
const PLACEHOLDER_STATUS_PENDING_ASSIGNMENT = 'pending_assignment';
|
||||
const PLACEHOLDER_STATUS_AWAITING_APPROVAL = 'awaiting_approval';
|
||||
export const PLACEHOLDER_STATUS_AWAITING_APPROVAL = 'awaiting_approval';
|
||||
const PLACEHOLDER_STATUS_REJECTED = 'rejected';
|
||||
const PLACEHOLDER_STATUS_REASSIGNING = 'reassigning'; // backend state still pending
|
||||
export const PLACEHOLDER_STATUS_REASSIGNING = 'reassignment_in_progress';
|
||||
const PLACEHOLDER_STATUS_FAILED = 'failed';
|
||||
const PLACEHOLDER_STATUS_SAVED = 'saved'; // backend state still pending
|
||||
const PLACEHOLDER_STATUS_COMPLETED = 'completed';
|
||||
export const PLACEHOLDER_STATUS_KEPT_AS_PLACEHOLDER = 'keep_as_placeholder';
|
||||
export const PLACEHOLDER_STATUS_COMPLETED = 'completed';
|
||||
|
||||
export const placeholderUserBadges = {
|
||||
[PLACEHOLDER_STATUS_PENDING_ASSIGNMENT]: {
|
||||
|
|
@ -63,7 +63,7 @@ export const placeholderUserBadges = {
|
|||
variant: 'danger',
|
||||
tooltip: s__('UserMapping|Reassignment failed.'),
|
||||
},
|
||||
[PLACEHOLDER_STATUS_SAVED]: {
|
||||
[PLACEHOLDER_STATUS_KEPT_AS_PLACEHOLDER]: {
|
||||
text: s__('UserMapping|Kept as placeholder'),
|
||||
variant: 'success',
|
||||
tooltip: s__('UserMapping|Placeholder user was made permanent.'),
|
||||
|
|
|
|||
|
|
@ -7,6 +7,10 @@ import { createAlert } from '~/alert';
|
|||
|
||||
import searchUsersQuery from '~/graphql_shared/queries/users_search_all_paginated.query.graphql';
|
||||
import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants';
|
||||
import {
|
||||
PLACEHOLDER_STATUS_AWAITING_APPROVAL,
|
||||
PLACEHOLDER_STATUS_REASSIGNING,
|
||||
} from '~/import_entities/import_groups/constants';
|
||||
|
||||
const USERS_PER_PAGE = 20;
|
||||
|
||||
|
|
@ -36,6 +40,7 @@ export default {
|
|||
return {
|
||||
isLoadingInitial: true,
|
||||
isLoadingMore: false,
|
||||
isValidated: false,
|
||||
search: '',
|
||||
selectedUser: null,
|
||||
};
|
||||
|
|
@ -74,6 +79,10 @@ export default {
|
|||
return this.$apollo.queries.users.loading && !this.isLoadingMore;
|
||||
},
|
||||
|
||||
userSelectInvalid() {
|
||||
return this.isValidated && !this.selectedUser;
|
||||
},
|
||||
|
||||
userItems() {
|
||||
return this.users?.nodes?.map((user) => createUserObject(user));
|
||||
},
|
||||
|
|
@ -101,9 +110,20 @@ export default {
|
|||
confirmText() {
|
||||
return this.dontReassignSelected ? __('Confirm') : s__('UserMapping|Reassign');
|
||||
},
|
||||
|
||||
statusIsAwaitingApproval() {
|
||||
return this.placeholder.status === PLACEHOLDER_STATUS_AWAITING_APPROVAL;
|
||||
},
|
||||
statusIsReassigning() {
|
||||
return this.placeholder.status === PLACEHOLDER_STATUS_REASSIGNING;
|
||||
},
|
||||
},
|
||||
|
||||
created() {
|
||||
if (this.statusIsAwaitingApproval || this.statusIsReassigning) {
|
||||
this.selectedUser = this.placeholder.reassignToUser;
|
||||
}
|
||||
|
||||
this.debouncedSetSearch = debounce(this.setSearch, DEFAULT_DEBOUNCE_AND_THROTTLE_MS);
|
||||
},
|
||||
|
||||
|
|
@ -154,56 +174,87 @@ export default {
|
|||
this.selectedUser = this.userItems.find((user) => user.value === value);
|
||||
}
|
||||
},
|
||||
|
||||
onNotify() {
|
||||
this.$toast.show(s__('UserMapping|Notification email sent.'));
|
||||
},
|
||||
onCancel() {
|
||||
this.$emit('cancel');
|
||||
},
|
||||
onConfirm() {
|
||||
this.isValidated = true;
|
||||
if (!this.userSelectInvalid) {
|
||||
this.$emit('confirm', this.selectedUserValue);
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="gl-flex gl-gap-3">
|
||||
<gl-collapsible-listbox
|
||||
ref="userSelect"
|
||||
block
|
||||
is-check-centered
|
||||
toggle-class="gl-w-28"
|
||||
:header-text="s__('UserMapping|Re-assign to')"
|
||||
:toggle-text="toggleText"
|
||||
:loading="isLoadingInitial"
|
||||
:items="userItems"
|
||||
:selected="selectedUserValue"
|
||||
searchable
|
||||
:searching="isLoading"
|
||||
infinite-scroll
|
||||
:infinite-scroll-loading="isLoadingMore"
|
||||
@search="debouncedSetSearch"
|
||||
@select="onSelect"
|
||||
@bottom-reached="loadMoreUsers"
|
||||
>
|
||||
<template #list-item="{ item }">
|
||||
<gl-avatar-labeled
|
||||
shape="circle"
|
||||
:size="32"
|
||||
:src="item.avatarUrl"
|
||||
:label="item.text"
|
||||
:sub-label="item.username"
|
||||
/>
|
||||
</template>
|
||||
<div class="gl-flex gl-items-start gl-gap-3">
|
||||
<div>
|
||||
<gl-collapsible-listbox
|
||||
ref="userSelect"
|
||||
block
|
||||
is-check-centered
|
||||
toggle-class="gl-w-28"
|
||||
:class="{ 'is-invalid': userSelectInvalid }"
|
||||
:header-text="s__('UserMapping|Re-assign to')"
|
||||
:toggle-text="toggleText"
|
||||
:disabled="statusIsAwaitingApproval || statusIsReassigning"
|
||||
:loading="isLoadingInitial"
|
||||
:items="userItems"
|
||||
:selected="selectedUserValue"
|
||||
searchable
|
||||
:searching="isLoading"
|
||||
infinite-scroll
|
||||
:infinite-scroll-loading="isLoadingMore"
|
||||
@search="debouncedSetSearch"
|
||||
@select="onSelect"
|
||||
@bottom-reached="loadMoreUsers"
|
||||
>
|
||||
<template #list-item="{ item }">
|
||||
<gl-avatar-labeled
|
||||
shape="circle"
|
||||
:size="32"
|
||||
:src="item.avatarUrl"
|
||||
:label="item.text"
|
||||
:sub-label="item.username"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template #footer>
|
||||
<div
|
||||
class="gl-border-t-solid gl-border-t-1 gl-border-t-gray-200 gl-flex gl-flex-col !gl-p-2 !gl-pt-0"
|
||||
>
|
||||
<gl-button
|
||||
category="tertiary"
|
||||
class="!gl-justify-start gl-mt-2"
|
||||
data-testid="dont-reassign-button"
|
||||
@click="onSelect('')"
|
||||
<template #footer>
|
||||
<div
|
||||
class="gl-border-t-solid gl-border-t-1 gl-border-t-gray-200 gl-flex gl-flex-col !gl-p-2 !gl-pt-0"
|
||||
>
|
||||
{{ s__("UserMapping|Don't reassign") }}
|
||||
</gl-button>
|
||||
</div>
|
||||
</template>
|
||||
</gl-collapsible-listbox>
|
||||
<gl-button
|
||||
category="tertiary"
|
||||
class="!gl-justify-start gl-mt-2"
|
||||
data-testid="dont-reassign-button"
|
||||
@click="onSelect('')"
|
||||
>
|
||||
{{ s__("UserMapping|Don't reassign") }}
|
||||
</gl-button>
|
||||
</div>
|
||||
</template>
|
||||
</gl-collapsible-listbox>
|
||||
|
||||
<gl-button variant="confirm" data-testid="confirm-button">{{ confirmText }}</gl-button>
|
||||
<span v-if="userSelectInvalid" class="invalid-feedback">
|
||||
{{ __('This field is required.') }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<template v-if="statusIsAwaitingApproval || statusIsReassigning">
|
||||
<gl-button :disabled="statusIsReassigning" data-testid="notify-button" @click="onNotify">{{
|
||||
s__('UserMapping|Notify again')
|
||||
}}</gl-button>
|
||||
<gl-button :disabled="statusIsReassigning" data-testid="cancel-button" @click="onCancel">{{
|
||||
__('Cancel')
|
||||
}}</gl-button>
|
||||
</template>
|
||||
<gl-button v-else variant="confirm" data-testid="confirm-button" @click="onConfirm">{{
|
||||
confirmText
|
||||
}}</gl-button>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,11 @@
|
|||
import { GlAvatarLabeled, GlBadge, GlTableLite, GlTooltipDirective } from '@gitlab/ui';
|
||||
import { s__ } from '~/locale';
|
||||
|
||||
import { placeholderUserBadges } from '~/import_entities/import_groups/constants';
|
||||
import {
|
||||
PLACEHOLDER_STATUS_KEPT_AS_PLACEHOLDER,
|
||||
PLACEHOLDER_STATUS_COMPLETED,
|
||||
placeholderUserBadges,
|
||||
} from '~/import_entities/import_groups/constants';
|
||||
import PlaceholderActions from './placeholder_actions.vue';
|
||||
|
||||
export default {
|
||||
|
|
@ -59,6 +63,21 @@ export default {
|
|||
statusBadge(item) {
|
||||
return placeholderUserBadges[item.status];
|
||||
},
|
||||
|
||||
isReassignedItem(item) {
|
||||
return (
|
||||
(item.status === PLACEHOLDER_STATUS_KEPT_AS_PLACEHOLDER ||
|
||||
item.status === PLACEHOLDER_STATUS_COMPLETED) &&
|
||||
item.reassignToUser
|
||||
);
|
||||
},
|
||||
|
||||
onCancel(item) {
|
||||
this.$emit('cancel', item);
|
||||
},
|
||||
onConfirm(item, selectedUserId) {
|
||||
this.$emit('confirm', item, selectedUserId);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
@ -88,8 +107,20 @@ export default {
|
|||
>
|
||||
</template>
|
||||
|
||||
<template #cell(actions)>
|
||||
<placeholder-actions />
|
||||
<template #cell(actions)="{ item }">
|
||||
<gl-avatar-labeled
|
||||
v-if="isReassignedItem(item)"
|
||||
:size="32"
|
||||
:src="item.reassignToUser.avatar_url"
|
||||
:label="item.reassignToUser.name"
|
||||
:sub-label="item.reassignToUser.username"
|
||||
/>
|
||||
<placeholder-actions
|
||||
v-else
|
||||
:placeholder="item"
|
||||
@confirm="onConfirm(item, $event)"
|
||||
@cancel="onCancel(item)"
|
||||
/>
|
||||
</template>
|
||||
</gl-table-lite>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<script>
|
||||
import { GlDrawer, GlBadge, GlSprintf, GlButton, GlIcon, GlAlert } from '@gitlab/ui';
|
||||
import { GlDrawer, GlSprintf, GlButton, GlIcon, GlAlert } from '@gitlab/ui';
|
||||
import { DRAWER_Z_INDEX } from '~/lib/utils/constants';
|
||||
import { getContentWrapperHeight } from '~/lib/utils/dom_utils';
|
||||
import { helpPagePath } from '~/helpers/help_page_helper';
|
||||
|
|
@ -14,7 +14,7 @@ import {
|
|||
MEMBERS_TAB_TYPES,
|
||||
} from '~/members/constants';
|
||||
import * as Sentry from '~/ci/runner/sentry_utils';
|
||||
import MemberAvatar from './member_avatar.vue';
|
||||
import MemberAvatar from '../member_avatar.vue';
|
||||
import RoleSelector from './role_selector.vue';
|
||||
|
||||
// The API to update members uses different property names for the access level, depending on if it's a user or a group.
|
||||
|
|
@ -29,12 +29,12 @@ export default {
|
|||
MemberAvatar,
|
||||
MembersTableCell,
|
||||
GlDrawer,
|
||||
GlBadge,
|
||||
GlSprintf,
|
||||
GlButton,
|
||||
GlIcon,
|
||||
GlAlert,
|
||||
RoleSelector,
|
||||
RoleBadges: () => import('ee_component/members/components/table/role_badges.vue'),
|
||||
GuestOverageConfirmation: () =>
|
||||
import('ee_component/members/components/table/guest_overage_confirmation.vue'),
|
||||
},
|
||||
|
|
@ -193,19 +193,16 @@ export default {
|
|||
|
||||
<dl>
|
||||
<dt class="gl-mb-3" data-testid="role-header">{{ s__('MemberRole|Role') }}</dt>
|
||||
<dd>
|
||||
<dd class="gl-flex gl-flex-wrap gl-gap-x-2 gl-gap-y-3">
|
||||
<role-selector
|
||||
v-if="permissions.canUpdate"
|
||||
v-model="selectedRole"
|
||||
:roles="roles"
|
||||
:loading="isSavingRole"
|
||||
class="gl-mb-3"
|
||||
class="gl-w-full"
|
||||
/>
|
||||
<span v-else class="gl-mr-1" data-testid="role-text">{{ selectedRole.text }}</span>
|
||||
|
||||
<gl-badge v-if="selectedRole.memberRoleId">
|
||||
{{ s__('MemberRole|Custom role') }}
|
||||
</gl-badge>
|
||||
<span v-else data-testid="role-text">{{ selectedRole.text }}</span>
|
||||
<role-badges :member="member" :role="selectedRole" />
|
||||
</dd>
|
||||
|
||||
<template v-if="selectedRole.description">
|
||||
|
|
@ -33,7 +33,7 @@ import MemberSource from './member_source.vue';
|
|||
import MemberActivity from './member_activity.vue';
|
||||
import MaxRole from './max_role.vue';
|
||||
import MembersPagination from './members_pagination.vue';
|
||||
import RoleDetailsDrawer from './role_details_drawer.vue';
|
||||
import RoleDetailsDrawer from './drawer/role_details_drawer.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
|
@ -58,6 +58,7 @@ export default {
|
|||
import('ee_component/members/components/modals/ldap_override_confirmation_modal.vue'),
|
||||
UserLimitReachedAlert: () =>
|
||||
import('ee_component/members/components/table/user_limit_reached_alert.vue'),
|
||||
RoleBadges: () => import('ee_component/members/components/table/role_badges.vue'),
|
||||
},
|
||||
directives: { GlTooltip: GlTooltipDirective },
|
||||
mixins: [glFeatureFlagsMixin()],
|
||||
|
|
@ -299,9 +300,7 @@ export default {
|
|||
>
|
||||
{{ member.accessLevel.stringValue }}
|
||||
</gl-button>
|
||||
<gl-badge v-if="member.accessLevel.memberRoleId" class="gl-mt-3">
|
||||
{{ s__('MemberRole|Custom role') }}
|
||||
</gl-badge>
|
||||
<role-badges :member="member" :role="member.accessLevel" class="gl-mt-3" />
|
||||
</div>
|
||||
<max-role v-else :permissions="permissions" :member="member" />
|
||||
</members-table-cell>
|
||||
|
|
|
|||
|
|
@ -21,11 +21,14 @@ import {
|
|||
RECENT_SEARCHES_STORAGE_KEY_GROUPS,
|
||||
RECENT_SEARCHES_STORAGE_KEY_PROJECTS,
|
||||
} from '~/filtered_search/recent_searches_storage_keys';
|
||||
import * as Sentry from '~/sentry/sentry_browser_wrapper';
|
||||
import userPreferencesUpdate from '../graphql/mutations/user_preferences_update.mutation.graphql';
|
||||
import {
|
||||
DISPLAY_LISTBOX_ITEMS,
|
||||
SORT_ITEMS,
|
||||
FILTERED_SEARCH_TERM_KEY,
|
||||
FILTERED_SEARCH_NAMESPACE,
|
||||
SORT_ITEMS_GRAPHQL_ENUMS,
|
||||
} from '../constants';
|
||||
|
||||
export default {
|
||||
|
|
@ -47,11 +50,12 @@ export default {
|
|||
},
|
||||
displayListboxItems: DISPLAY_LISTBOX_ITEMS,
|
||||
sortItems: SORT_ITEMS,
|
||||
inject: ['userPreferenceSortName', 'userPreferenceSortDirection', 'userPreferenceDisplay'],
|
||||
computed: {
|
||||
displayQuery() {
|
||||
const { display } = this.$route.query;
|
||||
|
||||
return display;
|
||||
return display || this.userPreferenceDisplay;
|
||||
},
|
||||
routerView() {
|
||||
switch (this.displayQuery) {
|
||||
|
|
@ -84,10 +88,10 @@ export default {
|
|||
);
|
||||
},
|
||||
sortName() {
|
||||
return this.$route.query.sort_name || SORT_ITEM_NAME.value;
|
||||
return this.$route.query.sort_name || this.userPreferenceSortName;
|
||||
},
|
||||
sortDirection() {
|
||||
return this.$route.query.sort_direction || SORT_DIRECTION_ASC;
|
||||
return this.$route.query.sort_direction || this.userPreferenceSortDirection;
|
||||
},
|
||||
isAscending() {
|
||||
return this.sortDirection !== SORT_DIRECTION_DESC;
|
||||
|
|
@ -102,10 +106,8 @@ export default {
|
|||
return this.$route.query[QUERY_PARAM_END_CURSOR] || null;
|
||||
},
|
||||
displayListboxSelected() {
|
||||
const { display } = this.$route.query;
|
||||
|
||||
return [RESOURCE_TYPE_GROUPS, RESOURCE_TYPE_PROJECTS].includes(display)
|
||||
? display
|
||||
return [RESOURCE_TYPE_GROUPS, RESOURCE_TYPE_PROJECTS].includes(this.displayQuery)
|
||||
? this.displayQuery
|
||||
: RESOURCE_TYPE_GROUPS;
|
||||
},
|
||||
search() {
|
||||
|
|
@ -133,19 +135,24 @@ export default {
|
|||
},
|
||||
onDisplayListboxSelect(display) {
|
||||
this.pushQuery({ display });
|
||||
this.userPreferencesUpdateMutate({
|
||||
organizationGroupsProjectsDisplay: display.toUpperCase(),
|
||||
});
|
||||
},
|
||||
onSortByChange(sortValue) {
|
||||
if (this.$route.query.sort_name === sortValue) {
|
||||
onSortByChange(sortName) {
|
||||
if (this.$route.query.sort_name === sortName) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.pushQuery({ ...this.routeQueryWithoutPagination, sort_name: sortValue });
|
||||
this.pushQuery({ ...this.routeQueryWithoutPagination, sort_name: sortName });
|
||||
this.userPreferencesUpdateSort();
|
||||
},
|
||||
onSortDirectionChange(isAscending) {
|
||||
this.pushQuery({
|
||||
...this.routeQueryWithoutPagination,
|
||||
sort_direction: isAscending ? SORT_DIRECTION_ASC : SORT_DIRECTION_DESC,
|
||||
});
|
||||
this.userPreferencesUpdateSort();
|
||||
},
|
||||
onFilter(filters) {
|
||||
const { display, sort_name, sort_direction } = this.$route.query;
|
||||
|
|
@ -167,6 +174,32 @@ export default {
|
|||
onPageChange(pagination) {
|
||||
this.pushQuery(onPageChange({ ...pagination, routeQuery: this.$route.query }));
|
||||
},
|
||||
async userPreferencesUpdateMutate(input) {
|
||||
try {
|
||||
await this.$apollo.mutate({
|
||||
mutation: userPreferencesUpdate,
|
||||
variables: {
|
||||
input,
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
// Silently fail but capture exception in Sentry
|
||||
Sentry.captureException(error);
|
||||
}
|
||||
},
|
||||
userPreferencesUpdateSort() {
|
||||
const sortGraphQLEnum = SORT_ITEMS_GRAPHQL_ENUMS[this.sortName];
|
||||
|
||||
if (!sortGraphQLEnum) {
|
||||
return;
|
||||
}
|
||||
|
||||
const direction = this.isAscending ? SORT_DIRECTION_ASC : SORT_DIRECTION_DESC;
|
||||
|
||||
this.userPreferencesUpdateMutate({
|
||||
organizationGroupsProjectsSort: `${sortGraphQLEnum}_${direction.toUpperCase()}`,
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,12 @@
|
|||
import { __ } from '~/locale';
|
||||
import { SORT_ITEM_NAME, SORT_ITEM_CREATED_AT, SORT_ITEM_UPDATED_AT } from '../shared/constants';
|
||||
import {
|
||||
SORT_ITEM_NAME,
|
||||
SORT_ITEM_CREATED_AT,
|
||||
SORT_ITEM_UPDATED_AT,
|
||||
SORT_NAME,
|
||||
SORT_CREATED_AT,
|
||||
SORT_UPDATED_AT,
|
||||
} from '../shared/constants';
|
||||
|
||||
export const DISPLAY_QUERY_GROUPS = 'groups';
|
||||
export const DISPLAY_QUERY_PROJECTS = 'projects';
|
||||
|
|
@ -19,3 +26,9 @@ export const DISPLAY_LISTBOX_ITEMS = [
|
|||
];
|
||||
|
||||
export const SORT_ITEMS = [SORT_ITEM_NAME, SORT_ITEM_CREATED_AT, SORT_ITEM_UPDATED_AT];
|
||||
|
||||
export const SORT_ITEMS_GRAPHQL_ENUMS = {
|
||||
[SORT_NAME]: 'NAME',
|
||||
[SORT_CREATED_AT]: 'CREATED',
|
||||
[SORT_UPDATED_AT]: 'UPDATED',
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
mutation userPreferencesUpdate($input: UserPreferencesUpdateInput!) {
|
||||
userPreferencesUpdate(input: $input) {
|
||||
userPreferences {
|
||||
organizationGroupsProjectsSort
|
||||
organizationGroupsProjectsDisplay
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ import VueRouter from 'vue-router';
|
|||
import createDefaultClient from '~/lib/graphql';
|
||||
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
|
||||
import { ORGANIZATION_ROOT_ROUTE_NAME } from '~/organizations/shared/constants';
|
||||
import { userPreferenceSortName, userPreferenceSortDirection } from './utils';
|
||||
import App from './components/app.vue';
|
||||
|
||||
export const createRouter = () => {
|
||||
|
|
@ -35,6 +36,8 @@ export const initOrganizationsGroupsAndProjects = () => {
|
|||
canCreateGroup,
|
||||
canCreateProject,
|
||||
hasGroups,
|
||||
userPreferenceSort,
|
||||
userPreferenceDisplay,
|
||||
} = convertObjectPropsToCamelCase(JSON.parse(appData));
|
||||
|
||||
Vue.use(VueRouter);
|
||||
|
|
@ -57,6 +60,9 @@ export const initOrganizationsGroupsAndProjects = () => {
|
|||
canCreateGroup,
|
||||
canCreateProject,
|
||||
hasGroups,
|
||||
userPreferenceSortName: userPreferenceSortName(userPreferenceSort),
|
||||
userPreferenceSortDirection: userPreferenceSortDirection(userPreferenceSort),
|
||||
userPreferenceDisplay,
|
||||
},
|
||||
render(createElement) {
|
||||
return createElement(App);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
import {
|
||||
SORT_DIRECTION_ASC,
|
||||
SORT_DIRECTION_DESC,
|
||||
SORT_ITEM_NAME,
|
||||
} from '~/organizations/shared/constants';
|
||||
import { SORT_ITEMS_GRAPHQL_ENUMS } from './constants';
|
||||
|
||||
export const userPreferenceSortName = (userPreferenceSort) => {
|
||||
if (!userPreferenceSort) {
|
||||
return SORT_ITEM_NAME.value;
|
||||
}
|
||||
|
||||
const userPreferenceSortNameGraphQLEnum = userPreferenceSort
|
||||
.replace(`_${SORT_DIRECTION_ASC}`, '')
|
||||
.replace(`_${SORT_DIRECTION_DESC}`, '')
|
||||
.toUpperCase();
|
||||
|
||||
return (
|
||||
Object.entries(SORT_ITEMS_GRAPHQL_ENUMS).find(
|
||||
([, sortNameGraphQLEnum]) => sortNameGraphQLEnum === userPreferenceSortNameGraphQLEnum,
|
||||
)?.[0] || SORT_ITEM_NAME.value
|
||||
);
|
||||
};
|
||||
|
||||
export const userPreferenceSortDirection = (userPreferenceSort) => {
|
||||
return userPreferenceSort?.endsWith(SORT_DIRECTION_DESC)
|
||||
? SORT_DIRECTION_DESC
|
||||
: SORT_DIRECTION_ASC;
|
||||
};
|
||||
|
|
@ -33,6 +33,7 @@ import {
|
|||
STATE_MACHINE,
|
||||
MT_SKIP_TRAIN,
|
||||
MT_RESTART_TRAIN,
|
||||
MWCP_MERGE_STRATEGY,
|
||||
} from '../../constants';
|
||||
import eventHub from '../../event_hub';
|
||||
import mergeRequestQueryVariablesMixin from '../../mixins/merge_request_query_variables';
|
||||
|
|
@ -243,6 +244,9 @@ export default {
|
|||
this.state.availableAutoMergeStrategies,
|
||||
);
|
||||
},
|
||||
isPreferredAutoMergeStrategyMWPC() {
|
||||
return this.preferredAutoMergeStrategy === MWCP_MERGE_STRATEGY;
|
||||
},
|
||||
squashIsSelected() {
|
||||
return this.isSquashReadOnly ? this.state.squashOnMerge : this.state.squash;
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,8 +1,17 @@
|
|||
import { s__ } from '~/locale';
|
||||
import { MWCP_MERGE_STRATEGY } from '~/vue_merge_request_widget/constants';
|
||||
|
||||
export default {
|
||||
computed: {
|
||||
statusText() {
|
||||
const { autoMergeStrategy } = this.state;
|
||||
|
||||
if (autoMergeStrategy === MWCP_MERGE_STRATEGY) {
|
||||
return s__(
|
||||
'mrWidget|Set by %{merge_author} to be merged automatically when all merge checks pass',
|
||||
);
|
||||
}
|
||||
|
||||
return s__(
|
||||
'mrWidget|Set by %{merge_author} to be merged automatically when the pipeline succeeds',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -10,6 +10,11 @@ export const PIPELINE_MUST_SUCCEED_CONFLICT_TEXT = __(
|
|||
);
|
||||
export const PIPELINE_SKIPPED_STATUS = 'SKIPPED';
|
||||
|
||||
// TODO: Add documentation
|
||||
const MERGE_WHEN_CHECKS_PASS_HELP = helpPagePath(
|
||||
'/user/project/merge_requests/merge_when_checks_pass.html',
|
||||
);
|
||||
|
||||
export default {
|
||||
computed: {
|
||||
isMergeButtonDisabled() {
|
||||
|
|
@ -28,9 +33,23 @@ export default {
|
|||
return __('Set to auto-merge');
|
||||
},
|
||||
autoMergeHelperText() {
|
||||
if (this.isPreferredAutoMergeStrategyMWPC) {
|
||||
return __('Merge when all merge checks pass');
|
||||
}
|
||||
|
||||
return __('Merge when pipeline succeeds');
|
||||
},
|
||||
autoMergePopoverSettings() {
|
||||
if (this.isPreferredAutoMergeStrategyMWPC) {
|
||||
return {
|
||||
helpLink: MERGE_WHEN_CHECKS_PASS_HELP,
|
||||
bodyText: __(
|
||||
'When all the merge checks for this merge request pass, it will %{linkStart}automatically merge%{linkEnd}.',
|
||||
),
|
||||
title: __('Merge when checks pass'),
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
helpLink: helpPagePath('/user/project/merge_requests/merge_when_pipeline_succeeds.html'),
|
||||
bodyText: __(
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { DETAILED_MERGE_STATUS } from '../constants';
|
||||
import { DETAILED_MERGE_STATUS, MWCP_MERGE_STRATEGY } from '../constants';
|
||||
import { stateKey } from './state_maps';
|
||||
|
||||
export default function deviseState() {
|
||||
|
|
@ -22,7 +22,8 @@ export default function deviseState() {
|
|||
}
|
||||
if (
|
||||
this.detailedMergeStatus === DETAILED_MERGE_STATUS.MERGEABLE ||
|
||||
this.detailedMergeStatus === DETAILED_MERGE_STATUS.CI_STILL_RUNNING
|
||||
this.detailedMergeStatus === DETAILED_MERGE_STATUS.CI_STILL_RUNNING ||
|
||||
(!this.autoMergeEnabled && this.preferredAutoMergeStrategy === MWCP_MERGE_STRATEGY)
|
||||
) {
|
||||
return stateKey.readyToMerge;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -394,7 +394,7 @@ export default class MergeRequestStore {
|
|||
}
|
||||
|
||||
get preventMerge() {
|
||||
return this.isApprovalNeeded;
|
||||
return this.isApprovalNeeded && this.preferredAutoMergeStrategy !== MWCP_MERGE_STRATEGY;
|
||||
}
|
||||
|
||||
// Because the state machine doesn't yet handle every state and transition,
|
||||
|
|
|
|||
|
|
@ -7,7 +7,9 @@ module Groups
|
|||
feature_category :package_registry
|
||||
urgency :low
|
||||
|
||||
before_action :set_feature_flag_packages_protected_packages, only: :show
|
||||
before_action :set_feature_flag_packages_protected_packages, only: [:show, :index]
|
||||
|
||||
def index; end
|
||||
|
||||
# The show action renders index to allow frontend routing to work on page refresh
|
||||
def show
|
||||
|
|
|
|||
|
|
@ -528,7 +528,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
|
|||
AutoMergeService.new(project, current_user, merge_params)
|
||||
.execute(
|
||||
merge_request,
|
||||
params[:auto_merge_strategy] || AutoMergeService::STRATEGY_MERGE_WHEN_PIPELINE_SUCCEEDS
|
||||
params[:auto_merge_strategy] || merge_request.default_auto_merge_strategy
|
||||
)
|
||||
end
|
||||
else
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ class SearchController < ApplicationController
|
|||
@group = search_service.group
|
||||
@search_service_presenter = Gitlab::View::Presenter::Factory.new(search_service, current_user: current_user).fabricate!
|
||||
|
||||
return unless search_term_valid?
|
||||
return unless search_term_valid? && search_type_valid?
|
||||
|
||||
return if check_single_commit_result?
|
||||
|
||||
|
|
@ -73,7 +73,7 @@ class SearchController < ApplicationController
|
|||
@search_highlight = @search_service_presenter.search_highlight
|
||||
end
|
||||
|
||||
return if @search_results.respond_to?(:failed?) && @search_results.failed?
|
||||
return if @search_results.respond_to?(:failed?) && @search_results.failed?(@scope)
|
||||
|
||||
Gitlab::Metrics::GlobalSearchSlis.record_apdex(
|
||||
elapsed: @global_search_duration_s,
|
||||
|
|
@ -186,6 +186,17 @@ class SearchController < ApplicationController
|
|||
true
|
||||
end
|
||||
|
||||
def search_type_valid?
|
||||
search_type_errors = search_service.search_type_errors
|
||||
|
||||
if search_type_errors
|
||||
flash[:alert] = search_type_errors
|
||||
return false
|
||||
end
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
def check_single_commit_result?
|
||||
return false if params[:force_search_results]
|
||||
return false unless @project.present?
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Import
|
||||
class SourceUsersFinder
|
||||
def initialize(namespace, current_user, params = {})
|
||||
@namespace = namespace
|
||||
@current_user = current_user
|
||||
@params = params
|
||||
end
|
||||
|
||||
def execute
|
||||
return Import::SourceUser.none unless authorized?
|
||||
|
||||
namespace.import_source_users
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :namespace, :current_user, :params
|
||||
|
||||
def authorized?
|
||||
Ability.allowed?(current_user, :admin_namespace, namespace)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -4,29 +4,31 @@ module Packages
|
|||
module Conan
|
||||
class PackageFinder
|
||||
MAX_PACKAGES_COUNT = 500
|
||||
QUERY_SEPARATOR = '/'
|
||||
|
||||
def initialize(current_user, params, project: nil)
|
||||
@current_user = current_user
|
||||
@query = params[:query]
|
||||
@name, @version = params[:query].to_s.split(QUERY_SEPARATOR)
|
||||
@project = project
|
||||
end
|
||||
|
||||
def execute
|
||||
return ::Packages::Conan::Package.none unless query
|
||||
return ::Packages::Conan::Package.none unless name.present?
|
||||
|
||||
packages
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :current_user, :query, :project
|
||||
attr_reader :current_user, :name, :project, :version
|
||||
|
||||
def packages
|
||||
base
|
||||
.installable
|
||||
.preload_conan_metadatum
|
||||
.with_name_like(query)
|
||||
.limit_recent(MAX_PACKAGES_COUNT)
|
||||
matching_packages = base
|
||||
.installable
|
||||
.preload_conan_metadatum
|
||||
.with_name_like(name)
|
||||
matching_packages = matching_packages.with_version(version) if version
|
||||
matching_packages.limit_recent(MAX_PACKAGES_COUNT)
|
||||
end
|
||||
|
||||
def base
|
||||
|
|
|
|||
|
|
@ -23,3 +23,5 @@ module BatchLoaders
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
BatchLoaders::AwardEmojiVotesBatchLoader.prepend_mod
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Mutations
|
||||
module Import
|
||||
module SourceUsers
|
||||
class CancelReassignment < BaseMutation
|
||||
graphql_name 'ImportSourceUserCancelReassignment'
|
||||
|
||||
argument :id, Types::GlobalIDType[::Import::SourceUser],
|
||||
required: true,
|
||||
description: 'Global ID of the mapping of a user on source instance to a user on destination instance.'
|
||||
|
||||
field :import_source_user,
|
||||
Types::Import::SourceUserType,
|
||||
null: true,
|
||||
description: "Mapping of a user on source instance to a user on destination instance after mutation."
|
||||
|
||||
authorize :admin_import_source_user
|
||||
|
||||
def resolve(args)
|
||||
if Feature.disabled?(:bulk_import_user_mapping, current_user)
|
||||
raise_resource_not_available_error! '`bulk_import_user_mapping` feature flag is disabled.'
|
||||
end
|
||||
|
||||
import_source_user = authorized_find!(id: args[:id])
|
||||
result = ::Import::SourceUsers::CancelReassignmentService.new(import_source_user,
|
||||
current_user: current_user).execute
|
||||
|
||||
{ import_source_user: result.payload, errors: result.errors }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Mutations
|
||||
module Import
|
||||
module SourceUsers
|
||||
class KeepAsPlaceholder < BaseMutation
|
||||
graphql_name 'ImportSourceUserKeepAsPlaceholder'
|
||||
|
||||
argument :id, Types::GlobalIDType[::Import::SourceUser],
|
||||
required: true,
|
||||
description: 'Global ID of the mapping of a user on source instance to a user on destination instance.'
|
||||
|
||||
field :import_source_user,
|
||||
Types::Import::SourceUserType,
|
||||
null: true,
|
||||
description: "Mapping of a user on source instance to a user on destination instance after mutation."
|
||||
|
||||
authorize :admin_import_source_user
|
||||
|
||||
def resolve(args)
|
||||
if Feature.disabled?(:bulk_import_user_mapping, current_user)
|
||||
raise_resource_not_available_error! '`bulk_import_user_mapping` feature flag is disabled.'
|
||||
end
|
||||
|
||||
import_source_user = authorized_find!(id: args[:id])
|
||||
result = ::Import::SourceUsers::KeepAsPlaceholderService.new(import_source_user,
|
||||
current_user: current_user).execute
|
||||
|
||||
{ import_source_user: result.payload, errors: result.errors }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Mutations
|
||||
module Import
|
||||
module SourceUsers
|
||||
class Reassign < BaseMutation
|
||||
graphql_name 'ImportSourceUserReassign'
|
||||
|
||||
argument :id, Types::GlobalIDType[::Import::SourceUser],
|
||||
required: true,
|
||||
description: 'Global ID of the mapping of a user on source instance to a user on destination instance.'
|
||||
|
||||
argument :assignee_user_id, Types::GlobalIDType[::User],
|
||||
required: true,
|
||||
loads: Types::UserType,
|
||||
description: 'Global ID of the assignee user.'
|
||||
|
||||
field :import_source_user,
|
||||
Types::Import::SourceUserType,
|
||||
null: true,
|
||||
description: "Mapping of a user on source instance to a user on destination instance after mutation."
|
||||
|
||||
authorize :admin_import_source_user
|
||||
|
||||
def resolve(args)
|
||||
if Feature.disabled?(:bulk_import_user_mapping, current_user)
|
||||
raise_resource_not_available_error! '`bulk_import_user_mapping` feature flag is disabled.'
|
||||
end
|
||||
|
||||
import_source_user = authorized_find!(id: args[:id])
|
||||
result = ::Import::SourceUsers::ReassignService.new(import_source_user, args[:assignee_user],
|
||||
current_user: current_user).execute
|
||||
|
||||
{ import_source_user: result.payload, errors: result.errors }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Resolvers
|
||||
module Import
|
||||
class SourceUsersResolver < BaseResolver
|
||||
include ::LooksAhead
|
||||
include Gitlab::Graphql::Authorize::AuthorizeResource
|
||||
|
||||
authorizes_object!
|
||||
authorize :admin_namespace
|
||||
|
||||
type Types::Import::SourceUserType.connection_type, null: true
|
||||
|
||||
alias_method :namespace, :object
|
||||
|
||||
def resolve_with_lookahead(**args)
|
||||
return [] if Feature.disabled?(:bulk_import_user_mapping, current_user)
|
||||
|
||||
apply_lookahead(::Import::SourceUsersFinder.new(namespace, context[:current_user], args).execute)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def preloads
|
||||
{
|
||||
reassign_to_user: [:reassign_to_user],
|
||||
placeholder_user: [:placeholder_user],
|
||||
reassigned_by_user: [:reassigned_by_user]
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -21,13 +21,14 @@ module Types
|
|||
description: 'Inputs for the component.'
|
||||
|
||||
def inputs
|
||||
spec_inputs = object.spec.fetch('inputs', {})
|
||||
|
||||
spec_inputs.map do |key, value|
|
||||
object.spec.fetch('inputs', {}).map do |key, value|
|
||||
{
|
||||
name: key,
|
||||
required: !value&.key?('default'),
|
||||
default: value&.dig('default')
|
||||
default: value&.dig('default'),
|
||||
description: value&.dig('description'),
|
||||
regex: value&.dig('regex'),
|
||||
type: value&.dig('type') || 'string'
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -10,8 +10,16 @@ module Types
|
|||
graphql_name 'CiCatalogResourceComponentInput'
|
||||
|
||||
field :default, GraphQL::Types::String, null: true, description: 'Default value for the input.'
|
||||
field :description, GraphQL::Types::String, null: true, description: 'Description of the input.'
|
||||
field :name, GraphQL::Types::String, null: true, description: 'Name of the input.'
|
||||
|
||||
field :regex, GraphQL::Types::String, null: true,
|
||||
description: 'Pattern that the input value must match. Only applicable to string inputs.'
|
||||
|
||||
field :required, GraphQL::Types::Boolean, null: true, description: 'Indicates if an input is required.'
|
||||
|
||||
field :type, Types::Ci::Catalog::Resources::Components::InputTypeEnum, null: true,
|
||||
description: 'Type of the input.'
|
||||
end
|
||||
# rubocop: enable Graphql/AuthorizeTypes
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Types
|
||||
module Ci
|
||||
module Catalog
|
||||
module Resources
|
||||
module Components
|
||||
class InputTypeEnum < BaseEnum
|
||||
graphql_name 'CiCatalogResourceComponentInputType'
|
||||
description 'Available input types'
|
||||
|
||||
::Gitlab::Ci::Config::Interpolation::Inputs.input_types.each do |input_type|
|
||||
value input_type.upcase, description: "#{input_type.capitalize} input", value: input_type
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -206,6 +206,8 @@ module Types
|
|||
|
||||
field :trigger, GraphQL::Types::Boolean, method: :trigger?, null: false, description: "If the pipeline was created by a Trigger request."
|
||||
|
||||
field :manual_variables, ManualVariableType.connection_type, null: true, description: 'CI/CD variables added to a manual pipeline.'
|
||||
|
||||
def commit
|
||||
BatchLoader::GraphQL.wrap(object.commit)
|
||||
end
|
||||
|
|
@ -242,6 +244,13 @@ module Types
|
|||
pipeline.sha
|
||||
end
|
||||
|
||||
def manual_variables
|
||||
variables = object.variables
|
||||
return variables if Ability.allowed?(current_user, :read_pipeline_variable, pipeline)
|
||||
|
||||
variables.map { |variable| { key: variable.key, value: nil } }
|
||||
end
|
||||
|
||||
alias_method :pipeline, :object
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ module Types
|
|||
def import_source_description(import_source)
|
||||
return "Not imported" if import_source == :none
|
||||
|
||||
"Imported from #{import_source.to_s.titleize}."
|
||||
import_source.to_s.titleize
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Types
|
||||
module Import
|
||||
class SourceUserStatusEnum < BaseEnum
|
||||
graphql_name 'ImportSourceUserStatus'
|
||||
|
||||
::Import::SourceUser.state_machines[:status].states.each do |state|
|
||||
value state.name.upcase,
|
||||
description: "An import source user mapping that is #{state.human_name}.",
|
||||
value: state.value
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Types
|
||||
module Import
|
||||
class SourceUserType < BaseObject
|
||||
graphql_name 'ImportSourceUser'
|
||||
|
||||
authorize :admin_import_source_user
|
||||
|
||||
field :id,
|
||||
Types::GlobalIDType[::Import::SourceUser],
|
||||
null: false,
|
||||
description: 'Global ID of the mapping of a user on source instance to a user on destination instance.'
|
||||
|
||||
field :placeholder_user,
|
||||
Types::UserType,
|
||||
null: true,
|
||||
description: 'Placeholder user associated with the import source user.'
|
||||
|
||||
field :reassign_to_user,
|
||||
Types::UserType,
|
||||
null: true,
|
||||
description: 'User that contributions are reassigned to.'
|
||||
|
||||
field :reassigned_by_user,
|
||||
Types::UserType,
|
||||
null: true,
|
||||
description: 'User that did the reassignment.'
|
||||
|
||||
# rubocop:disable GraphQL/ExtractType -- no need to extract allowed types into a separate field
|
||||
field :source_user_identifier,
|
||||
GraphQL::Types::String,
|
||||
null: false,
|
||||
description: 'ID of the user in the source instance.'
|
||||
|
||||
field :source_username,
|
||||
GraphQL::Types::String,
|
||||
null: true,
|
||||
description: 'Username of user in the source instance.'
|
||||
|
||||
field :source_name,
|
||||
GraphQL::Types::String,
|
||||
null: true,
|
||||
description: 'Name of user in the source instance.'
|
||||
|
||||
field :source_hostname,
|
||||
GraphQL::Types::String,
|
||||
null: false,
|
||||
description: 'Source instance hostname.'
|
||||
# rubocop:enable GraphQL/ExtractType
|
||||
|
||||
field :import_type,
|
||||
Types::Import::ImportSourceEnum,
|
||||
null: false,
|
||||
description: 'Name of the importer.'
|
||||
|
||||
field :status,
|
||||
Types::Import::SourceUserStatusEnum,
|
||||
null: false,
|
||||
description: 'Status of the mapping.'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -58,6 +58,9 @@ module Types
|
|||
mount_mutation Mutations::Environments::Delete
|
||||
mount_mutation Mutations::Environments::Stop
|
||||
mount_mutation Mutations::Environments::Update
|
||||
mount_mutation Mutations::Import::SourceUsers::CancelReassignment, alpha: { milestone: '17.2' }
|
||||
mount_mutation Mutations::Import::SourceUsers::KeepAsPlaceholder, alpha: { milestone: '17.2' }
|
||||
mount_mutation Mutations::Import::SourceUsers::Reassign, alpha: { milestone: '17.2' }
|
||||
mount_mutation Mutations::IncidentManagement::TimelineEvent::Create, alpha: { milestone: '15.6' }
|
||||
mount_mutation Mutations::IncidentManagement::TimelineEvent::PromoteFromNote
|
||||
mount_mutation Mutations::IncidentManagement::TimelineEvent::Update
|
||||
|
|
|
|||
|
|
@ -90,6 +90,15 @@ module Types
|
|||
connection: true,
|
||||
description: "List of the namespaces's Pages Deployments."
|
||||
|
||||
field :import_source_users, Import::SourceUserType.connection_type,
|
||||
null: true,
|
||||
alpha: { milestone: '17.2' },
|
||||
resolver: Resolvers::Import::SourceUsersResolver,
|
||||
description: 'Import source users of the namespace. This field can only be resolved for one namespace in any ' \
|
||||
'single request.' do
|
||||
extension(::Gitlab::Graphql::Limit::FieldCallCount, limit: 1)
|
||||
end
|
||||
|
||||
markdown_field :description_html, null: true
|
||||
|
||||
def achievements_path
|
||||
|
|
|
|||
|
|
@ -39,3 +39,5 @@ module Types
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
Types::WorkItems::Widgets::AwardEmojiType.prepend_mod
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ module MergeRequestsHelper
|
|||
|
||||
def merge_params(merge_request)
|
||||
{
|
||||
auto_merge_strategy: AutoMergeService::STRATEGY_MERGE_WHEN_PIPELINE_SUCCEEDS,
|
||||
auto_merge_strategy: merge_request.default_auto_merge_strategy,
|
||||
should_remove_source_branch: true,
|
||||
sha: merge_request.diff_head_sha,
|
||||
squash: merge_request.squash_on_merge?
|
||||
|
|
|
|||
|
|
@ -30,7 +30,10 @@ module Organizations
|
|||
end
|
||||
|
||||
def organization_groups_and_projects_app_data(organization)
|
||||
shared_groups_and_projects_app_data(organization).to_json
|
||||
{
|
||||
user_preference_sort: current_user&.user_preference&.organization_groups_projects_sort,
|
||||
user_preference_display: current_user&.user_preference&.organization_groups_projects_display
|
||||
}.merge(shared_groups_and_projects_app_data(organization)).to_json
|
||||
end
|
||||
|
||||
def organization_index_app_data
|
||||
|
|
|
|||
|
|
@ -88,3 +88,5 @@ class AwardEmoji < ApplicationRecord
|
|||
Gitlab::HookData::EmojiBuilder.new(self).build
|
||||
end
|
||||
end
|
||||
|
||||
AwardEmoji.prepend_mod
|
||||
|
|
|
|||
|
|
@ -46,40 +46,49 @@ module Enums
|
|||
dismissed: 2
|
||||
}.with_indifferent_access.freeze
|
||||
|
||||
OWASP_TOP_10 = {
|
||||
"A1:2017-Injection" => 1,
|
||||
"A2:2017-Broken Authentication" => 2,
|
||||
"A3:2017-Sensitive Data Exposure" => 3,
|
||||
"A4:2017-XML External Entities (XXE)" => 4,
|
||||
"A5:2017-Broken Access Control" => 5,
|
||||
"A6:2017-Security Misconfiguration" => 6,
|
||||
"A7:2017-Cross-Site Scripting (XSS)" => 7,
|
||||
"A8:2017-Insecure Deserialization" => 8,
|
||||
"A9:2017-Using Components with Known Vulnerabilities" => 9,
|
||||
"A10:2017-Insufficient Logging & Monitoring" => 10,
|
||||
OWASP_TOP_10_BY_YEAR = {
|
||||
'2017' => {
|
||||
"A1:2017-Injection" => 1,
|
||||
"A2:2017-Broken Authentication" => 2,
|
||||
"A3:2017-Sensitive Data Exposure" => 3,
|
||||
"A4:2017-XML External Entities (XXE)" => 4,
|
||||
"A5:2017-Broken Access Control" => 5,
|
||||
"A6:2017-Security Misconfiguration" => 6,
|
||||
"A7:2017-Cross-Site Scripting (XSS)" => 7,
|
||||
"A8:2017-Insecure Deserialization" => 8,
|
||||
"A9:2017-Using Components with Known Vulnerabilities" => 9,
|
||||
"A10:2017-Insufficient Logging & Monitoring" => 10
|
||||
},
|
||||
'2021' => {
|
||||
# 2021 switched to zero-padded identifiers, previous mapping is temporary
|
||||
# to be fixed with https://gitlab.com/gitlab-org/gitlab/-/issues/429565
|
||||
"A1:2021-Broken Access Control" => 11,
|
||||
"A01:2021-Broken Access Control" => 11,
|
||||
"A2:2021-Cryptographic Failures" => 12,
|
||||
"A02:2021-Cryptographic Failures" => 12,
|
||||
"A3:2021-Injection" => 13,
|
||||
"A03:2021-Injection" => 13,
|
||||
"A4:2021-Insecure Design" => 14,
|
||||
"A04:2021-Insecure Design" => 14,
|
||||
"A5:2021-Security Misconfiguration" => 15,
|
||||
"A05:2021-Security Misconfiguration" => 15,
|
||||
"A6:2021-Vulnerable and Outdated Components" => 16,
|
||||
"A06:2021-Vulnerable and Outdated Components" => 16,
|
||||
"A7:2021-Identification and Authentication Failures" => 17,
|
||||
"A07:2021-Identification and Authentication Failures" => 17,
|
||||
"A8:2021-Software and Data Integrity Failures" => 18,
|
||||
"A08:2021-Software and Data Integrity Failures" => 18,
|
||||
"A9:2021-Security Logging and Monitoring Failures" => 19,
|
||||
"A09:2021-Security Logging and Monitoring Failures" => 19,
|
||||
"A10:2021-Server-Side Request Forgery" => 20
|
||||
}
|
||||
}.freeze
|
||||
|
||||
# 2021 switched to zero-padded identifiers, previous mapping is temporary
|
||||
# to be fixed with https://gitlab.com/gitlab-org/gitlab/-/issues/429565
|
||||
"A1:2021-Broken Access Control" => 11,
|
||||
"A01:2021-Broken Access Control" => 11,
|
||||
"A2:2021-Cryptographic Failures" => 12,
|
||||
"A02:2021-Cryptographic Failures" => 12,
|
||||
"A3:2021-Injection" => 13,
|
||||
"A03:2021-Injection" => 13,
|
||||
"A4:2021-Insecure Design" => 14,
|
||||
"A04:2021-Insecure Design" => 14,
|
||||
"A5:2021-Security Misconfiguration" => 15,
|
||||
"A05:2021-Security Misconfiguration" => 15,
|
||||
"A6:2021-Vulnerable and Outdated Components" => 16,
|
||||
"A06:2021-Vulnerable and Outdated Components" => 16,
|
||||
"A7:2021-Identification and Authentication Failures" => 17,
|
||||
"A07:2021-Identification and Authentication Failures" => 17,
|
||||
"A8:2021-Software and Data Integrity Failures" => 18,
|
||||
"A08:2021-Software and Data Integrity Failures" => 18,
|
||||
"A9:2021-Security Logging and Monitoring Failures" => 19,
|
||||
"A09:2021-Security Logging and Monitoring Failures" => 19,
|
||||
"A10:2021-Server-Side Request Forgery" => 20
|
||||
}.with_indifferent_access.freeze
|
||||
OWASP_TOP_10 = OWASP_TOP_10_BY_YEAR.values.inject(&:merge).with_indifferent_access.freeze
|
||||
|
||||
OWASP_CATEGORIES = OWASP_TOP_10.keys.map { |key| key.split(':').first }.uniq.freeze
|
||||
|
||||
OWASP_YEARS = OWASP_TOP_10_BY_YEAR.keys.freeze
|
||||
|
||||
def self.confidence_levels
|
||||
CONFIDENCE_LEVELS
|
||||
|
|
@ -112,6 +121,14 @@ module Enums
|
|||
def self.owasp_top_10
|
||||
OWASP_TOP_10
|
||||
end
|
||||
|
||||
def self.owasp_categories
|
||||
OWASP_CATEGORIES
|
||||
end
|
||||
|
||||
def self.owasp_years
|
||||
OWASP_YEARS
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -22,12 +22,16 @@ module Import
|
|||
state :completed, value: 5
|
||||
state :keep_as_placeholder, value: 6
|
||||
|
||||
event :cancel_assignment do
|
||||
event :reassign do
|
||||
transition [:pending_assignment, :rejected] => :awaiting_approval
|
||||
end
|
||||
|
||||
event :cancel_reassignment do
|
||||
transition [:awaiting_approval, :rejected] => :pending_assignment
|
||||
end
|
||||
|
||||
event :keep_as_placeholder do
|
||||
transition [:pending_assignment, :awaiting_approval, :rejected] => :keep_as_placeholder
|
||||
transition [:pending_assignment, :rejected] => :keep_as_placeholder
|
||||
end
|
||||
|
||||
event :accept do
|
||||
|
|
@ -61,5 +65,13 @@ module Import
|
|||
import_type: import_type
|
||||
)
|
||||
end
|
||||
|
||||
def reassignable_status?
|
||||
pending_assignment? || rejected?
|
||||
end
|
||||
|
||||
def cancelable_status?
|
||||
awaiting_approval? || rejected?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1361,7 +1361,15 @@ class MergeRequest < ApplicationRecord
|
|||
def auto_merge_strategy
|
||||
return unless auto_merge_enabled?
|
||||
|
||||
merge_params['auto_merge_strategy'] || AutoMergeService::STRATEGY_MERGE_WHEN_PIPELINE_SUCCEEDS
|
||||
merge_params['auto_merge_strategy'] || default_auto_merge_strategy
|
||||
end
|
||||
|
||||
def default_auto_merge_strategy
|
||||
if Feature.enabled?(:merge_when_checks_pass, project)
|
||||
AutoMergeService::STRATEGY_MERGE_WHEN_CHECKS_PASS
|
||||
else
|
||||
AutoMergeService::STRATEGY_MERGE_WHEN_PIPELINE_SUCCEEDS
|
||||
end
|
||||
end
|
||||
|
||||
def auto_merge_strategy=(strategy)
|
||||
|
|
|
|||
|
|
@ -110,6 +110,8 @@ class Namespace < ApplicationRecord
|
|||
|
||||
has_many :jira_connect_subscriptions, class_name: 'JiraConnectSubscription', foreign_key: :namespace_id, inverse_of: :namespace
|
||||
|
||||
has_many :import_source_users, class_name: 'Import::SourceUser', foreign_key: :namespace_id, inverse_of: :namespace
|
||||
|
||||
validates :owner, presence: true, if: ->(n) { n.owner_required? }
|
||||
validates :name,
|
||||
presence: true,
|
||||
|
|
|
|||
|
|
@ -3354,6 +3354,11 @@ class Project < ApplicationRecord
|
|||
false
|
||||
end
|
||||
|
||||
# Overridden in EE
|
||||
def merge_trains_enabled?
|
||||
false
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# overridden in EE
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Import
|
||||
class SourceUserPolicy < ::BasePolicy
|
||||
condition(:admin_source_user_namespace) { can?(:admin_namespace, @subject.namespace) }
|
||||
desc "User can administrate namespace"
|
||||
|
||||
rule { admin_source_user_namespace }.policy do
|
||||
enable :admin_import_source_user
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# rubocop:disable Gitlab/BoundedContexts -- Existing module
|
||||
module AutoMerge
|
||||
class MergeWhenChecksPassService < AutoMerge::BaseService
|
||||
extend Gitlab::Utils::Override
|
||||
|
||||
override :execute
|
||||
def execute(merge_request)
|
||||
super do
|
||||
add_system_note(merge_request)
|
||||
end
|
||||
end
|
||||
|
||||
override :process
|
||||
def process(merge_request)
|
||||
logger.info("Processing Automerge - MWCP")
|
||||
|
||||
return if merge_request.has_ci_enabled? && !merge_request.diff_head_pipeline_success?
|
||||
|
||||
logger.info("Pipeline Success - MWCP")
|
||||
|
||||
return unless merge_request.mergeable?
|
||||
|
||||
logger.info("Merge request mergeable - MWCP")
|
||||
|
||||
merge_request.merge_async(merge_request.merge_user_id, merge_request.merge_params)
|
||||
end
|
||||
|
||||
override :cancel
|
||||
def cancel(merge_request)
|
||||
super do
|
||||
SystemNoteService.cancel_auto_merge(merge_request, project, current_user)
|
||||
end
|
||||
end
|
||||
|
||||
override :abort
|
||||
def abort(merge_request, reason)
|
||||
super do
|
||||
SystemNoteService.abort_auto_merge(merge_request, project, current_user, reason)
|
||||
end
|
||||
end
|
||||
|
||||
override :available_for
|
||||
def available_for?(merge_request)
|
||||
super do
|
||||
next false if Feature.disabled?(:merge_when_checks_pass, merge_request.project)
|
||||
next false if merge_request.project.merge_trains_enabled?
|
||||
next false if merge_request.mergeable? && !merge_request.diff_head_pipeline_considered_in_progress?
|
||||
|
||||
next true
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def add_system_note(merge_request)
|
||||
return unless merge_request.saved_change_to_auto_merge_enabled?
|
||||
|
||||
SystemNoteService.merge_when_checks_pass(
|
||||
merge_request,
|
||||
project,
|
||||
current_user,
|
||||
merge_request.merge_params.symbolize_keys[:sha]
|
||||
)
|
||||
end
|
||||
|
||||
def notify(merge_request)
|
||||
return unless merge_request.saved_change_to_auto_merge_enabled?
|
||||
|
||||
notification_service.async.merge_when_pipeline_succeeds(merge_request,
|
||||
current_user)
|
||||
end
|
||||
end
|
||||
end
|
||||
# rubocop:enable Gitlab/BoundedContexts
|
||||
|
|
@ -34,6 +34,8 @@ module AutoMerge
|
|||
|
||||
def available_for?(merge_request)
|
||||
super do
|
||||
next false if Feature.enabled?(:merge_when_checks_pass, merge_request.project)
|
||||
|
||||
merge_request.diff_head_pipeline_considered_in_progress?
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@ class AutoMergeService < BaseService
|
|||
include Gitlab::Utils::StrongMemoize
|
||||
|
||||
STRATEGY_MERGE_WHEN_PIPELINE_SUCCEEDS = 'merge_when_pipeline_succeeds'
|
||||
# Currently only EE but will be moved to CE in (https://gitlab.com/gitlab-org/gitlab/-/merge_requests/146730)
|
||||
# `merge_when_checks_pass` enables auto-merge to be set before all merge checks are passing
|
||||
STRATEGY_MERGE_WHEN_CHECKS_PASS = 'merge_when_checks_pass'
|
||||
STRATEGIES = [STRATEGY_MERGE_WHEN_PIPELINE_SUCCEEDS].freeze
|
||||
STRATEGIES = [STRATEGY_MERGE_WHEN_CHECKS_PASS, STRATEGY_MERGE_WHEN_PIPELINE_SUCCEEDS].freeze
|
||||
|
||||
class << self
|
||||
def all_strategies_ordered_by_preference
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Import
|
||||
module SourceUsers
|
||||
class BaseService
|
||||
private
|
||||
|
||||
def error_invalid_permissions
|
||||
ServiceResponse.error(
|
||||
message: s_('Import|You have insufficient permissions to update the import source user'),
|
||||
reason: :forbidden
|
||||
)
|
||||
end
|
||||
|
||||
def error_invalid_status
|
||||
ServiceResponse.error(
|
||||
message: s_('Import|Import source user has an invalid status for this operation'),
|
||||
reason: :invalid_status,
|
||||
payload: import_source_user
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Import
|
||||
module SourceUsers
|
||||
class CancelReassignmentService < BaseService
|
||||
def initialize(import_source_user, current_user:)
|
||||
@import_source_user = import_source_user
|
||||
@current_user = current_user
|
||||
end
|
||||
|
||||
def execute
|
||||
return error_invalid_permissions unless current_user.can?(:admin_import_source_user, import_source_user)
|
||||
return error_invalid_status unless import_source_user.cancelable_status?
|
||||
|
||||
if cancel_reassignment
|
||||
ServiceResponse.success(payload: import_source_user)
|
||||
else
|
||||
ServiceResponse.error(payload: import_source_user, message: import_source_user.errors.full_messages)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :import_source_user, :current_user, :params
|
||||
|
||||
def cancel_reassignment
|
||||
import_source_user.reassign_to_user = nil
|
||||
import_source_user.reassigned_by_user = nil
|
||||
import_source_user.cancel_reassignment
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Import
|
||||
module SourceUsers
|
||||
class KeepAsPlaceholderService < BaseService
|
||||
def initialize(import_source_user, current_user:)
|
||||
@import_source_user = import_source_user
|
||||
@current_user = current_user
|
||||
end
|
||||
|
||||
def execute
|
||||
return error_invalid_permissions unless current_user.can?(:admin_import_source_user, import_source_user)
|
||||
return error_invalid_status unless import_source_user.reassignable_status?
|
||||
|
||||
if keep_as_placeholder
|
||||
ServiceResponse.success(payload: import_source_user)
|
||||
else
|
||||
ServiceResponse.error(payload: import_source_user, message: import_source_user.errors.full_messages)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :import_source_user, :current_user, :params
|
||||
|
||||
def keep_as_placeholder
|
||||
import_source_user.reassigned_by_user = current_user
|
||||
import_source_user.keep_as_placeholder
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Import
|
||||
module SourceUsers
|
||||
class ReassignService < BaseService
|
||||
def initialize(import_source_user, assignee_user, current_user:)
|
||||
@import_source_user = import_source_user
|
||||
@current_user = current_user
|
||||
@assignee_user = assignee_user
|
||||
end
|
||||
|
||||
def execute
|
||||
return error_invalid_permissions unless current_user.can?(:admin_import_source_user, import_source_user)
|
||||
return error_invalid_status unless import_source_user.reassignable_status?
|
||||
return error_invalid_assignee unless valid_assignee?(assignee_user)
|
||||
|
||||
if reassign_user
|
||||
ServiceResponse.success(payload: import_source_user)
|
||||
else
|
||||
ServiceResponse.error(payload: import_source_user, message: import_source_user.errors.full_messages)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :import_source_user, :current_user, :assignee_user
|
||||
|
||||
def reassign_user
|
||||
import_source_user.reassign_to_user = assignee_user
|
||||
import_source_user.reassigned_by_user = current_user
|
||||
import_source_user.reassign
|
||||
end
|
||||
|
||||
def error_invalid_assignee
|
||||
ServiceResponse.error(
|
||||
message: s_('Import|Only active regular, auditor, or administrator users can be assigned'),
|
||||
reason: :invalid_assignee,
|
||||
payload: import_source_user
|
||||
)
|
||||
end
|
||||
|
||||
def valid_assignee?(user)
|
||||
user.present? && user.human? && user.active?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -40,6 +40,10 @@ class SearchService
|
|||
# overridden in EE
|
||||
end
|
||||
|
||||
def search_type_errors
|
||||
# overridden in EE
|
||||
end
|
||||
|
||||
def global_search?
|
||||
project.blank? && group.blank?
|
||||
end
|
||||
|
|
@ -58,10 +62,9 @@ class SearchService
|
|||
delegate :valid_terms_count?, :valid_query_length?, to: :params
|
||||
|
||||
def search_results
|
||||
strong_memoize(:search_results) do
|
||||
abuse_detected? ? Gitlab::EmptySearchResults.new : search_service.execute
|
||||
end
|
||||
abuse_detected? ? ::Search::EmptySearchResults.new : search_service.execute
|
||||
end
|
||||
strong_memoize_attr :search_results
|
||||
|
||||
def search_objects(preload_method = nil)
|
||||
@search_objects ||= redact_unauthorized_results(
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
- page_title _('DevOps Reports')
|
||||
- add_page_specific_style 'page_bundles/dev_ops_reports'
|
||||
|
||||
.gl-mt-3
|
||||
.gl-mt-3{ data: { event_tracking_load: 'true', event_tracking: 'view_admin_dev_ops_reports_pageload' } }
|
||||
- if show_adoption?
|
||||
= render_if_exists 'admin/dev_ops_report/devops_tabs'
|
||||
- else
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
- if @timeout
|
||||
= render partial: "search/results/timeout"
|
||||
- elsif @search_results.respond_to?(:failed?) && @search_results.failed?
|
||||
- elsif @search_results.respond_to?(:failed?) && @search_results.failed?(@scope)
|
||||
= render partial: "search/results/error"
|
||||
- elsif @search_objects.blank?
|
||||
= render partial: "search/results/empty"
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
- group_attributes = @group&.attributes&.slice('id', 'name')&.merge(full_name: @group&.full_name)
|
||||
- project_attributes = @project&.attributes&.slice('id', 'namespace_id', 'name')&.merge(name_with_namespace: @project&.name_with_namespace)
|
||||
|
||||
- if @search_results && !(@search_results.respond_to?(:failed?) && @search_results.failed?)
|
||||
- if @search_results && !(@search_results.respond_to?(:failed?) && @search_results.failed?(@scope))
|
||||
- if @search_service_presenter.without_count?
|
||||
- page_description(_("%{scope} results for term '%{term}'") % { scope: @scope, term: @search_term })
|
||||
- else
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
---
|
||||
description: Tracks pageviews for the admin audit events / logs page
|
||||
internal_events: true
|
||||
action: view_admin_audit_logs_pageload
|
||||
identifiers:
|
||||
- user
|
||||
product_group: personal_productivity
|
||||
milestone: '17.2'
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/156830
|
||||
distributions:
|
||||
- ce
|
||||
- ee
|
||||
tiers:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
---
|
||||
description: Tracks pageviews for the admin devops reports page
|
||||
internal_events: true
|
||||
action: view_admin_dev_ops_reports_pageload
|
||||
identifiers:
|
||||
- user
|
||||
product_group: personal_productivity
|
||||
milestone: '17.2'
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/156816
|
||||
distributions:
|
||||
- ce
|
||||
- ee
|
||||
tiers:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
name: ci_expand_variables_in_compare_to
|
||||
feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/369916
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/157147
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/466374
|
||||
milestone: '17.2'
|
||||
group: group::pipeline security
|
||||
type: gitlab_com_derisk
|
||||
default_enabled: false
|
||||
|
|
@ -193,10 +193,6 @@ dast_scanner_profiles_builds:
|
|||
- table: p_ci_builds
|
||||
column: ci_build_id
|
||||
on_delete: async_delete
|
||||
dast_scanner_profiles_tags:
|
||||
- table: tags
|
||||
column: tag_id
|
||||
on_delete: async_delete
|
||||
dast_site_profiles_builds:
|
||||
- table: ci_builds
|
||||
column: ci_build_id
|
||||
|
|
@ -204,10 +200,6 @@ dast_site_profiles_builds:
|
|||
- table: p_ci_builds
|
||||
column: ci_build_id
|
||||
on_delete: async_delete
|
||||
dast_site_profiles_pipelines:
|
||||
- table: ci_pipelines
|
||||
column: ci_pipeline_id
|
||||
on_delete: async_delete
|
||||
deployment_clusters:
|
||||
- table: clusters
|
||||
column: cluster_id
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
key_path: redis_hll_counters.count_distinct_user_id_from_view_admin_audit_logs_pageload_monthly
|
||||
description: Monthly count of unique users who visited the admin audit events / audit logs page
|
||||
product_group: personal_productivity
|
||||
performance_indicator_type: []
|
||||
value_type: number
|
||||
status: active
|
||||
milestone: '17.2'
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/156830
|
||||
time_frame: 28d
|
||||
data_source: internal_events
|
||||
data_category: optional
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
events:
|
||||
- name: view_admin_audit_logs_pageload
|
||||
unique: user.id
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
key_path: redis_hll_counters.count_distinct_user_id_from_view_admin_dev_ops_reports_pageload_monthly
|
||||
description: Monthly count of unique users who visit the devops reports page
|
||||
product_group: personal_productivity
|
||||
performance_indicator_type: []
|
||||
value_type: number
|
||||
status: active
|
||||
milestone: '17.2'
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/156816
|
||||
time_frame: 28d
|
||||
data_source: internal_events
|
||||
data_category: optional
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
events:
|
||||
- name: view_admin_dev_ops_reports_pageload
|
||||
unique: user.id
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
---
|
||||
key_path: counts.count_total_view_admin_audit_logs_pageload_monthly
|
||||
description: Monthly count of total users who visited the admin audit events / audit logs page
|
||||
product_group: personal_productivity
|
||||
performance_indicator_type: []
|
||||
value_type: number
|
||||
status: active
|
||||
milestone: '17.2'
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/156830
|
||||
time_frame: 28d
|
||||
data_source: internal_events
|
||||
data_category: optional
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
events:
|
||||
- name: view_admin_audit_logs_pageload
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
---
|
||||
key_path: counts.count_total_view_admin_dev_ops_reports_pageload_monthly
|
||||
description: Monthly count of total users who visit the admin devops reports page
|
||||
product_group: personal_productivity
|
||||
performance_indicator_type: []
|
||||
value_type: number
|
||||
status: active
|
||||
milestone: '17.2'
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/156816
|
||||
time_frame: 28d
|
||||
data_source: internal_events
|
||||
data_category: optional
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
events:
|
||||
- name: view_admin_dev_ops_reports_pageload
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
key_path: redis_hll_counters.count_distinct_user_id_from_view_admin_audit_logs_pageload_weekly
|
||||
description: Weekly count of unique users who visited the admin audit events / audit logs page
|
||||
product_group: personal_productivity
|
||||
performance_indicator_type: []
|
||||
value_type: number
|
||||
status: active
|
||||
milestone: '17.2'
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/156830
|
||||
time_frame: 7d
|
||||
data_source: internal_events
|
||||
data_category: optional
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
events:
|
||||
- name: view_admin_audit_logs_pageload
|
||||
unique: user.id
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
key_path: redis_hll_counters.count_distinct_user_id_from_view_admin_dev_ops_reports_pageload_weekly
|
||||
description: Weekly count of unique users who visit the devops reports page
|
||||
product_group: personal_productivity
|
||||
performance_indicator_type: []
|
||||
value_type: number
|
||||
status: active
|
||||
milestone: '17.2'
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/156816
|
||||
time_frame: 7d
|
||||
data_source: internal_events
|
||||
data_category: optional
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
events:
|
||||
- name: view_admin_dev_ops_reports_pageload
|
||||
unique: user.id
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
---
|
||||
key_path: counts.count_total_view_admin_audit_logs_pageload_weekly
|
||||
description: Weekly count of total users who visited the admin audit events / audit logs page
|
||||
product_group: personal_productivity
|
||||
performance_indicator_type: []
|
||||
value_type: number
|
||||
status: active
|
||||
milestone: '17.2'
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/156830
|
||||
time_frame: 7d
|
||||
data_source: internal_events
|
||||
data_category: optional
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
events:
|
||||
- name: view_admin_audit_logs_pageload
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
---
|
||||
key_path: counts.count_total_view_admin_dev_ops_reports_pageload_weekly
|
||||
description: Weekly count of total users who visit the admin devops reports page
|
||||
product_group: personal_productivity
|
||||
performance_indicator_type: []
|
||||
value_type: number
|
||||
status: active
|
||||
milestone: '17.2'
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/156816
|
||||
time_frame: 7d
|
||||
data_source: internal_events
|
||||
data_category: optional
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
events:
|
||||
- name: view_admin_dev_ops_reports_pageload
|
||||
|
|
@ -9,6 +9,7 @@ lock_gitlab_schemas:
|
|||
- gitlab_main_clusterwide
|
||||
- gitlab_main_cell
|
||||
- gitlab_pm
|
||||
- gitlab_sec
|
||||
klass: Ci::ApplicationRecord
|
||||
# if CI database is not configured, use this database
|
||||
fallback_database: main
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ gitlab_schemas:
|
|||
- gitlab_pm
|
||||
lock_gitlab_schemas:
|
||||
- gitlab_ci
|
||||
- gitlab_sec
|
||||
# Note that we use ActiveRecord::Base here and not ApplicationRecord.
|
||||
# This is deliberate, as:
|
||||
# - the load balancer must be enabled for _all_ models
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
name: sec
|
||||
description: Cell-local GitLab database holding Security feature related tables.
|
||||
gitlab_schemas:
|
||||
- gitlab_internal
|
||||
- gitlab_shared
|
||||
- gitlab_sec
|
||||
lock_gitlab_schemas:
|
||||
- gitlab_main
|
||||
- gitlab_main_clusterwide
|
||||
- gitlab_main_cell
|
||||
- gitlab_ci
|
||||
- gitlab_pm
|
||||
klass: Gitlab::Database::SecApplicationRecord
|
||||
# if Sec database is not configured, use this database
|
||||
fallback_database: main
|
||||
uses_load_balancing: true
|
||||
|
|
@ -5,5 +5,7 @@ feature_categories:
|
|||
- dynamic_application_security_testing
|
||||
description: Join Table for Runner tags and DAST Scanner Profiles
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/104909
|
||||
removed_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/153443
|
||||
milestone: '15.7'
|
||||
removed_in_milestone: '17.2'
|
||||
gitlab_schema: gitlab_main
|
||||
|
|
@ -5,5 +5,7 @@ feature_categories:
|
|||
- dynamic_application_security_testing
|
||||
description: Join table between DAST Site Profiles and CI Pipelines
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/60090
|
||||
removed_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/153443
|
||||
milestone: '13.12'
|
||||
removed_in_milestone: '17.2'
|
||||
gitlab_schema: gitlab_main
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class DropTableDastScannerProfilesTags < Gitlab::Database::Migration[2.2]
|
||||
milestone '17.2'
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
drop_table :dast_scanner_profiles_tags if table_exists? :dast_scanner_profiles_tags
|
||||
end
|
||||
|
||||
def down
|
||||
unless table_exists?(:dast_scanner_profiles_tags)
|
||||
create_table :dast_scanner_profiles_tags do |t|
|
||||
t.bigint :dast_scanner_profile_id, null: false
|
||||
t.bigint :tag_id, null: false
|
||||
t.index :dast_scanner_profile_id, name: :i_dast_scanner_profiles_tags_on_scanner_profiles_id
|
||||
t.index :tag_id, name: :index_dast_scanner_profiles_tags_on_tag_id
|
||||
end
|
||||
end
|
||||
|
||||
return if foreign_key_exists?(:dast_scanner_profiles_tags, :dast_scanner_profiles, name: :fk_rails_deb79b7f19)
|
||||
|
||||
add_concurrent_foreign_key(
|
||||
:dast_scanner_profiles_tags,
|
||||
:dast_scanner_profiles,
|
||||
column: :dast_scanner_profile_id,
|
||||
name: :fk_rails_deb79b7f19)
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class DropTableDastSiteProfilesPipelines < Gitlab::Database::Migration[2.2]
|
||||
milestone '17.2'
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
drop_table :dast_site_profiles_pipelines if table_exists? :dast_site_profiles_pipelines
|
||||
end
|
||||
|
||||
def down
|
||||
unless table_exists?(:dast_site_profiles_pipelines)
|
||||
create_table :dast_site_profiles_pipelines, id: false do |t|
|
||||
t.bigint :dast_site_profile_id, null: false
|
||||
t.bigint :ci_pipeline_id, null: false
|
||||
t.index [:dast_site_profile_id, :ci_pipeline_id], name: :dast_site_profiles_pipelines_pkey, unique: true
|
||||
t.index :ci_pipeline_id, name: :index_dast_site_profiles_pipelines_on_ci_pipeline_id, unique: true
|
||||
end
|
||||
end
|
||||
|
||||
add_primary_key_using_index(
|
||||
:dast_site_profiles_pipelines,
|
||||
:dast_site_profiles_pipelines_pkey,
|
||||
:dast_site_profiles_pipelines_pkey
|
||||
)
|
||||
|
||||
return if foreign_key_exists?(:dast_site_profiles_pipelines, :dast_site_profiles, name: :fk_cf05cf8fe1)
|
||||
|
||||
add_concurrent_foreign_key(
|
||||
:dast_site_profiles_pipelines,
|
||||
:dast_site_profiles,
|
||||
column: :dast_site_profile_id,
|
||||
name: :fk_cf05cf8fe1)
|
||||
|
||||
execute(<<~SQL)
|
||||
COMMENT ON TABLE dast_site_profiles_pipelines IS '{"owner":"group::dynamic analysis","description":"Join table between DAST Site Profiles and CI Pipelines"}';
|
||||
SQL
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
ca71b00a277e322207a71d3916a3db50c13a9bef9b85653236b017de6821a45f
|
||||
|
|
@ -0,0 +1 @@
|
|||
e197e135ef13ee40965df703ffbc23c830b39887c3914f3c541a128ddac0ba01
|
||||
|
|
@ -0,0 +1 @@
|
|||
db/structure.sql
|
||||
1034
db/structure.sql
1034
db/structure.sql
File diff suppressed because it is too large
Load Diff
|
|
@ -744,8 +744,8 @@ You can solve this error in two ways.
|
|||
|
||||
### Rename references to the LDAP server
|
||||
|
||||
This solution is suitable when the LDAP servers are replicas of each other, and the affected users should be able to sign in using a configured LDAP server. For example, if a
|
||||
load balancer is now used to manage LDAP high availability and a separate secondary sign-in option is no longer needed.
|
||||
This solution is suitable when the LDAP servers are replicas of each other, and the affected users should be able to sign in using a configured LDAP server.
|
||||
For example, if a load balancer is now used to manage LDAP high availability and a separate secondary sign-in option is no longer needed.
|
||||
|
||||
NOTE:
|
||||
If the LDAP servers aren't replicas of each other, this solution stops affected users from being able to sign in.
|
||||
|
|
@ -758,8 +758,14 @@ sudo gitlab-rake gitlab:ldap:rename_provider[ldapsecondary,ldapmain]
|
|||
|
||||
### Remove the `identity` records that relate to the removed LDAP server
|
||||
|
||||
With this solution, affected users can sign in with the configured LDAP servers and a new `identity` record is created by GitLab. In a
|
||||
[Rails console](../../operations/rails_console.md), delete the `ldapsecondary` identities:
|
||||
Prerequisites:
|
||||
|
||||
- Ensure that `auto_link_ldap_user` is enabled.
|
||||
|
||||
With this solution, after the identity is deleted, affected users can sign in with the
|
||||
configured LDAP servers and a new `identity` record is created by GitLab.
|
||||
|
||||
Because the LDAP server that was removed was `ldapsecondary`, in a [Rails console](../../operations/rails_console.md), delete all the `ldapsecondary` identities:
|
||||
|
||||
```ruby
|
||||
ldap_identities = Identity.where(provider: "ldapsecondary")
|
||||
|
|
|
|||
|
|
@ -359,7 +359,6 @@ Prerequisites:
|
|||
1. Expand **Visibility and access controls**.
|
||||
1. In **Globally-allowed IP ranges**, provide a list of IP address ranges. This list:
|
||||
- Has no limit on the number of IP address ranges.
|
||||
- Has a size limit of 1 GB.
|
||||
- Applies to both SSH or HTTP authorized IP address ranges. You cannot split
|
||||
this list by authorization type.
|
||||
1. Select **Save changes**.
|
||||
|
|
|
|||
|
|
@ -5385,6 +5385,76 @@ Input type: `HttpIntegrationUpdateInput`
|
|||
| <a id="mutationhttpintegrationupdateerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
|
||||
| <a id="mutationhttpintegrationupdateintegration"></a>`integration` | [`AlertManagementHttpIntegration`](#alertmanagementhttpintegration) | HTTP integration. |
|
||||
|
||||
### `Mutation.importSourceUserCancelReassignment`
|
||||
|
||||
DETAILS:
|
||||
**Introduced** in GitLab 17.2.
|
||||
**Status**: Experiment.
|
||||
|
||||
Input type: `ImportSourceUserCancelReassignmentInput`
|
||||
|
||||
#### Arguments
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="mutationimportsourceusercancelreassignmentclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
|
||||
| <a id="mutationimportsourceusercancelreassignmentid"></a>`id` | [`ImportSourceUserID!`](#importsourceuserid) | Global ID of the mapping of a user on source instance to a user on destination instance. |
|
||||
|
||||
#### Fields
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="mutationimportsourceusercancelreassignmentclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
|
||||
| <a id="mutationimportsourceusercancelreassignmenterrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
|
||||
| <a id="mutationimportsourceusercancelreassignmentimportsourceuser"></a>`importSourceUser` | [`ImportSourceUser`](#importsourceuser) | Mapping of a user on source instance to a user on destination instance after mutation. |
|
||||
|
||||
### `Mutation.importSourceUserKeepAsPlaceholder`
|
||||
|
||||
DETAILS:
|
||||
**Introduced** in GitLab 17.2.
|
||||
**Status**: Experiment.
|
||||
|
||||
Input type: `ImportSourceUserKeepAsPlaceholderInput`
|
||||
|
||||
#### Arguments
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="mutationimportsourceuserkeepasplaceholderclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
|
||||
| <a id="mutationimportsourceuserkeepasplaceholderid"></a>`id` | [`ImportSourceUserID!`](#importsourceuserid) | Global ID of the mapping of a user on source instance to a user on destination instance. |
|
||||
|
||||
#### Fields
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="mutationimportsourceuserkeepasplaceholderclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
|
||||
| <a id="mutationimportsourceuserkeepasplaceholdererrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
|
||||
| <a id="mutationimportsourceuserkeepasplaceholderimportsourceuser"></a>`importSourceUser` | [`ImportSourceUser`](#importsourceuser) | Mapping of a user on source instance to a user on destination instance after mutation. |
|
||||
|
||||
### `Mutation.importSourceUserReassign`
|
||||
|
||||
DETAILS:
|
||||
**Introduced** in GitLab 17.2.
|
||||
**Status**: Experiment.
|
||||
|
||||
Input type: `ImportSourceUserReassignInput`
|
||||
|
||||
#### Arguments
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="mutationimportsourceuserreassignassigneeuserid"></a>`assigneeUserId` | [`UserID!`](#userid) | Global ID of the assignee user. |
|
||||
| <a id="mutationimportsourceuserreassignclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
|
||||
| <a id="mutationimportsourceuserreassignid"></a>`id` | [`ImportSourceUserID!`](#importsourceuserid) | Global ID of the mapping of a user on source instance to a user on destination instance. |
|
||||
|
||||
#### Fields
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="mutationimportsourceuserreassignclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
|
||||
| <a id="mutationimportsourceuserreassignerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
|
||||
| <a id="mutationimportsourceuserreassignimportsourceuser"></a>`importSourceUser` | [`ImportSourceUser`](#importsourceuser) | Mapping of a user on source instance to a user on destination instance after mutation. |
|
||||
|
||||
### `Mutation.instanceAuditEventStreamingDestinationsCreate`
|
||||
|
||||
DETAILS:
|
||||
|
|
@ -7539,7 +7609,7 @@ Input type: `ProjectSavedReplyUpdateInput`
|
|||
|
||||
### `Mutation.projectSetComplianceFramework`
|
||||
|
||||
Assign (or unset) a compliance framework to a project.
|
||||
Assign (or unset) a compliance framework to a project. This mutation raises an error if the project has more than one compliance framework associated with it.
|
||||
|
||||
Input type: `ProjectSetComplianceFrameworkInput`
|
||||
|
||||
|
|
@ -12750,6 +12820,29 @@ The edge type for [`GroupWikiRepositoryRegistry`](#groupwikirepositoryregistry).
|
|||
| <a id="groupwikirepositoryregistryedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
|
||||
| <a id="groupwikirepositoryregistryedgenode"></a>`node` | [`GroupWikiRepositoryRegistry`](#groupwikirepositoryregistry) | The item at the end of the edge. |
|
||||
|
||||
#### `ImportSourceUserConnection`
|
||||
|
||||
The connection type for [`ImportSourceUser`](#importsourceuser).
|
||||
|
||||
##### Fields
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="importsourceuserconnectionedges"></a>`edges` | [`[ImportSourceUserEdge]`](#importsourceuseredge) | A list of edges. |
|
||||
| <a id="importsourceuserconnectionnodes"></a>`nodes` | [`[ImportSourceUser]`](#importsourceuser) | A list of nodes. |
|
||||
| <a id="importsourceuserconnectionpageinfo"></a>`pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. |
|
||||
|
||||
#### `ImportSourceUserEdge`
|
||||
|
||||
The edge type for [`ImportSourceUser`](#importsourceuser).
|
||||
|
||||
##### Fields
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="importsourceuseredgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
|
||||
| <a id="importsourceuseredgenode"></a>`node` | [`ImportSourceUser`](#importsourceuser) | The item at the end of the edge. |
|
||||
|
||||
#### `IncidentManagementOncallRotationConnection`
|
||||
|
||||
The connection type for [`IncidentManagementOncallRotation`](#incidentmanagementoncallrotation).
|
||||
|
|
@ -17674,8 +17767,11 @@ four standard [pagination arguments](#pagination-arguments):
|
|||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="cicatalogresourcecomponentinputdefault"></a>`default` | [`String`](#string) | Default value for the input. |
|
||||
| <a id="cicatalogresourcecomponentinputdescription"></a>`description` | [`String`](#string) | Description of the input. |
|
||||
| <a id="cicatalogresourcecomponentinputname"></a>`name` | [`String`](#string) | Name of the input. |
|
||||
| <a id="cicatalogresourcecomponentinputregex"></a>`regex` | [`String`](#string) | Pattern that the input value must match. Only applicable to string inputs. |
|
||||
| <a id="cicatalogresourcecomponentinputrequired"></a>`required` | [`Boolean`](#boolean) | Indicates if an input is required. |
|
||||
| <a id="cicatalogresourcecomponentinputtype"></a>`type` | [`CiCatalogResourceComponentInputType`](#cicatalogresourcecomponentinputtype) | Type of the input. |
|
||||
|
||||
### `CiCatalogResourceVersion`
|
||||
|
||||
|
|
@ -21682,6 +21778,7 @@ GPG signature for a signed commit.
|
|||
| <a id="groupgooglecloudloggingconfigurations"></a>`googleCloudLoggingConfigurations` | [`GoogleCloudLoggingConfigurationTypeConnection`](#googlecloudloggingconfigurationtypeconnection) | Google Cloud logging configurations that receive audit events belonging to the group. (see [Connections](#connections)) |
|
||||
| <a id="groupgroupmemberscount"></a>`groupMembersCount` | [`Int!`](#int) | Count of direct members of this group. |
|
||||
| <a id="groupid"></a>`id` | [`ID!`](#id) | ID of the namespace. |
|
||||
| <a id="groupimportsourceusers"></a>`importSourceUsers` **{warning-solid}** | [`ImportSourceUserConnection`](#importsourceuserconnection) | **Introduced** in GitLab 17.2. **Status**: Experiment. Import source users of the namespace. This field can only be resolved for one namespace in any single request. |
|
||||
| <a id="groupisadjourneddeletionenabled"></a>`isAdjournedDeletionEnabled` **{warning-solid}** | [`Boolean!`](#boolean) | **Introduced** in GitLab 16.11. **Status**: Experiment. Indicates if delayed group deletion is enabled. |
|
||||
| <a id="grouplfsenabled"></a>`lfsEnabled` | [`Boolean`](#boolean) | Indicates if Large File Storage (LFS) is enabled for namespace. |
|
||||
| <a id="grouplockduofeaturesenabled"></a>`lockDuoFeaturesEnabled` **{warning-solid}** | [`Boolean`](#boolean) | **Introduced** in GitLab 16.10. **Status**: Experiment. Indicates if the GitLab Duo features enabled setting is enforced for all subgroups. |
|
||||
|
|
@ -23325,6 +23422,23 @@ IDE settings and feature flags.
|
|||
| ---- | ---- | ----------- |
|
||||
| <a id="idecodesuggestionsenabled"></a>`codeSuggestionsEnabled` | [`Boolean!`](#boolean) | Indicates whether AI assisted code suggestions are enabled. |
|
||||
|
||||
### `ImportSourceUser`
|
||||
|
||||
#### Fields
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="importsourceuserid"></a>`id` | [`ImportSourceUserID!`](#importsourceuserid) | Global ID of the mapping of a user on source instance to a user on destination instance. |
|
||||
| <a id="importsourceuserimporttype"></a>`importType` | [`ImportSource!`](#importsource) | Name of the importer. |
|
||||
| <a id="importsourceuserplaceholderuser"></a>`placeholderUser` | [`UserCore`](#usercore) | Placeholder user associated with the import source user. |
|
||||
| <a id="importsourceuserreassigntouser"></a>`reassignToUser` | [`UserCore`](#usercore) | User that contributions are reassigned to. |
|
||||
| <a id="importsourceuserreassignedbyuser"></a>`reassignedByUser` | [`UserCore`](#usercore) | User that did the reassignment. |
|
||||
| <a id="importsourceusersourcehostname"></a>`sourceHostname` | [`String!`](#string) | Source instance hostname. |
|
||||
| <a id="importsourceusersourcename"></a>`sourceName` | [`String`](#string) | Name of user in the source instance. |
|
||||
| <a id="importsourceusersourceuseridentifier"></a>`sourceUserIdentifier` | [`String!`](#string) | ID of the user in the source instance. |
|
||||
| <a id="importsourceusersourceusername"></a>`sourceUsername` | [`String`](#string) | Username of user in the source instance. |
|
||||
| <a id="importsourceuserstatus"></a>`status` | [`ImportSourceUserStatus!`](#importsourceuserstatus) | Status of the mapping. |
|
||||
|
||||
### `IncidentManagementOncallRotation`
|
||||
|
||||
Describes an incident management on-call rotation.
|
||||
|
|
@ -26098,6 +26212,7 @@ Product analytics events for a specific month and year.
|
|||
| <a id="namespacefullname"></a>`fullName` | [`String!`](#string) | Full name of the namespace. |
|
||||
| <a id="namespacefullpath"></a>`fullPath` | [`ID!`](#id) | Full path of the namespace. |
|
||||
| <a id="namespaceid"></a>`id` | [`ID!`](#id) | ID of the namespace. |
|
||||
| <a id="namespaceimportsourceusers"></a>`importSourceUsers` **{warning-solid}** | [`ImportSourceUserConnection`](#importsourceuserconnection) | **Introduced** in GitLab 17.2. **Status**: Experiment. Import source users of the namespace. This field can only be resolved for one namespace in any single request. |
|
||||
| <a id="namespacelfsenabled"></a>`lfsEnabled` | [`Boolean`](#boolean) | Indicates if Large File Storage (LFS) is enabled for namespace. |
|
||||
| <a id="namespacename"></a>`name` | [`String!`](#string) | Name of the namespace. |
|
||||
| <a id="namespacepackagesettings"></a>`packageSettings` | [`PackageSettings`](#packagesettings) | Package settings for the namespace. |
|
||||
|
|
@ -27041,6 +27156,7 @@ Returns [`UserMergeRequestInteraction`](#usermergerequestinteraction).
|
|||
| <a id="pipelineiid"></a>`iid` | [`String!`](#string) | Internal ID of the pipeline. |
|
||||
| <a id="pipelinejobartifacts"></a>`jobArtifacts` | [`[CiJobArtifact!]`](#cijobartifact) | Job artifacts of the pipeline. |
|
||||
| <a id="pipelinelatest"></a>`latest` | [`Boolean!`](#boolean) | If the pipeline is the latest one or not. |
|
||||
| <a id="pipelinemanualvariables"></a>`manualVariables` | [`CiManualVariableConnection`](#cimanualvariableconnection) | CI/CD variables added to a manual pipeline. (see [Connections](#connections)) |
|
||||
| <a id="pipelinemergerequest"></a>`mergeRequest` | [`MergeRequest`](#mergerequest) | The MR which the Pipeline is attached to. |
|
||||
| <a id="pipelinemergerequesteventtype"></a>`mergeRequestEventType` | [`PipelineMergeRequestEventType`](#pipelinemergerequesteventtype) | Event type of the pipeline associated with a merge request. |
|
||||
| <a id="pipelinename"></a>`name` | [`String`](#string) | Name of the pipeline. |
|
||||
|
|
@ -33348,6 +33464,17 @@ Status of a merge train's car.
|
|||
| <a id="carstatusskip_merged"></a>`SKIP_MERGED` | Car's status: skip_merged. |
|
||||
| <a id="carstatusstale"></a>`STALE` | Car's status: stale. |
|
||||
|
||||
### `CiCatalogResourceComponentInputType`
|
||||
|
||||
Available input types.
|
||||
|
||||
| Value | Description |
|
||||
| ----- | ----------- |
|
||||
| <a id="cicatalogresourcecomponentinputtypearray"></a>`ARRAY` | Array input. |
|
||||
| <a id="cicatalogresourcecomponentinputtypeboolean"></a>`BOOLEAN` | Boolean input. |
|
||||
| <a id="cicatalogresourcecomponentinputtypenumber"></a>`NUMBER` | Number input. |
|
||||
| <a id="cicatalogresourcecomponentinputtypestring"></a>`STRING` | String input. |
|
||||
|
||||
### `CiCatalogResourceScope`
|
||||
|
||||
Values for scoping catalog resources.
|
||||
|
|
@ -34401,19 +34528,31 @@ Import source.
|
|||
|
||||
| Value | Description |
|
||||
| ----- | ----------- |
|
||||
| <a id="importsourcebitbucket"></a>`BITBUCKET` | Imported from Bitbucket. |
|
||||
| <a id="importsourcebitbucket_server"></a>`BITBUCKET_SERVER` | Imported from Bitbucket Server. |
|
||||
| <a id="importsourcecustom_template"></a>`CUSTOM_TEMPLATE` | Imported from Custom Template. |
|
||||
| <a id="importsourcefogbugz"></a>`FOGBUGZ` | Imported from Fogbugz. |
|
||||
| <a id="importsourcegit"></a>`GIT` | Imported from Git. |
|
||||
| <a id="importsourcegitea"></a>`GITEA` | Imported from Gitea. |
|
||||
| <a id="importsourcegithub"></a>`GITHUB` | Imported from Github. |
|
||||
| <a id="importsourcegitlab_group"></a>`GITLAB_GROUP` | Imported from Gitlab Group. |
|
||||
| <a id="importsourcegitlab_migration"></a>`GITLAB_MIGRATION` | Imported from Gitlab Migration. |
|
||||
| <a id="importsourcegitlab_project"></a>`GITLAB_PROJECT` | Imported from Gitlab Project. |
|
||||
| <a id="importsourcemanifest"></a>`MANIFEST` | Imported from Manifest. |
|
||||
| <a id="importsourcebitbucket"></a>`BITBUCKET` | Bitbucket. |
|
||||
| <a id="importsourcebitbucket_server"></a>`BITBUCKET_SERVER` | Bitbucket Server. |
|
||||
| <a id="importsourcecustom_template"></a>`CUSTOM_TEMPLATE` | Custom Template. |
|
||||
| <a id="importsourcefogbugz"></a>`FOGBUGZ` | Fogbugz. |
|
||||
| <a id="importsourcegit"></a>`GIT` | Git. |
|
||||
| <a id="importsourcegitea"></a>`GITEA` | Gitea. |
|
||||
| <a id="importsourcegithub"></a>`GITHUB` | Github. |
|
||||
| <a id="importsourcegitlab_group"></a>`GITLAB_GROUP` | Gitlab Group. |
|
||||
| <a id="importsourcegitlab_migration"></a>`GITLAB_MIGRATION` | Gitlab Migration. |
|
||||
| <a id="importsourcegitlab_project"></a>`GITLAB_PROJECT` | Gitlab Project. |
|
||||
| <a id="importsourcemanifest"></a>`MANIFEST` | Manifest. |
|
||||
| <a id="importsourcenone"></a>`NONE` | Not imported. |
|
||||
|
||||
### `ImportSourceUserStatus`
|
||||
|
||||
| Value | Description |
|
||||
| ----- | ----------- |
|
||||
| <a id="importsourceuserstatusawaiting_approval"></a>`AWAITING_APPROVAL` | An import source user mapping that is awaiting approval. |
|
||||
| <a id="importsourceuserstatuscompleted"></a>`COMPLETED` | An import source user mapping that is completed. |
|
||||
| <a id="importsourceuserstatusfailed"></a>`FAILED` | An import source user mapping that is failed. |
|
||||
| <a id="importsourceuserstatuskeep_as_placeholder"></a>`KEEP_AS_PLACEHOLDER` | An import source user mapping that is keep as placeholder. |
|
||||
| <a id="importsourceuserstatuspending_assignment"></a>`PENDING_ASSIGNMENT` | An import source user mapping that is pending assignment. |
|
||||
| <a id="importsourceuserstatusreassignment_in_progress"></a>`REASSIGNMENT_IN_PROGRESS` | An import source user mapping that is reassignment in progress. |
|
||||
| <a id="importsourceuserstatusrejected"></a>`REJECTED` | An import source user mapping that is rejected. |
|
||||
|
||||
### `IntegrationType`
|
||||
|
||||
Integration Names.
|
||||
|
|
@ -36760,6 +36899,12 @@ An ISO 8601-encoded date.
|
|||
|
||||
An ISO 8601-encoded datetime.
|
||||
|
||||
### `ImportSourceUserID`
|
||||
|
||||
A `ImportSourceUserID` is a global ID. It is encoded as a string.
|
||||
|
||||
An example `ImportSourceUserID` is: `"gid://gitlab/Import::SourceUser/1"`.
|
||||
|
||||
### `IncidentManagementEscalationPolicyID`
|
||||
|
||||
A `IncidentManagementEscalationPolicyID` is a global ID. It is encoded as a string.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,73 @@
|
|||
---
|
||||
stage: Package
|
||||
group: Container Registry
|
||||
info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments"
|
||||
description: "Documentation for the REST API for container registry protection rules in GitLab."
|
||||
---
|
||||
|
||||
# Container registry protection rules API
|
||||
|
||||
DETAILS:
|
||||
**Tier:** Free, Premium, Ultimate
|
||||
**Offering:** Self-managed
|
||||
**Status:** Experiment
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/155798) in GitLab 17.2 [with a flag](../administration/feature_flags.md) named `container_registry_protected_containers`. Disabled by default.
|
||||
|
||||
FLAG:
|
||||
The availability of this feature is controlled by a feature flag.
|
||||
For more information, see the history.
|
||||
This feature is available for testing, but not ready for production use.
|
||||
|
||||
This API endpoint manages the protection rules for container registries in a project. This feature is an experiment.
|
||||
|
||||
## List container registry protection rules
|
||||
|
||||
Gets a list of container registry protection rules from a project.
|
||||
|
||||
```plaintext
|
||||
GET /api/v4/projects/:id/registry/protection/rules
|
||||
```
|
||||
|
||||
Supported attributes:
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
|-------------------------------|-----------------|----------|--------------------------------|
|
||||
| `id` | integer/string | Yes | ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding) owned by the authenticated user. |
|
||||
|
||||
If successful, returns [`200`](rest/index.md#status-codes) and a list of container registry protection rules.
|
||||
|
||||
Can return the following status codes:
|
||||
|
||||
- `200 OK`: A list of container registry protection rules.
|
||||
- `401 Unauthorized`: The access token is invalid.
|
||||
- `403 Forbidden`: The user does not have permission to list container registry protection rules for this project.
|
||||
- `404 Not Found`: The project was not found.
|
||||
|
||||
Example request:
|
||||
|
||||
```shell
|
||||
curl --header "PRIVATE-TOKEN: <your_access_token>" \
|
||||
--url "https://gitlab.example.com/api/v4/projects/7/registry/protection/rules"
|
||||
```
|
||||
|
||||
Example response:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"project_id": 7,
|
||||
"repository_path_pattern": "flightjs/flight0",
|
||||
"minimum_access_level_for_push": "maintainer",
|
||||
"minimum_access_level_for_delete": "maintainer"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"project_id": 7,
|
||||
"repository_path_pattern": "flightjs/flight1",
|
||||
"minimum_access_level_for_push": "maintainer",
|
||||
"minimum_access_level_for_delete": "maintainer"
|
||||
},
|
||||
]
|
||||
```
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
status: proposed
|
||||
status: ongoing
|
||||
creation-date: "2024-02-20"
|
||||
authors: [ "@bvenker", "@mikolaj_wawrzyniak" ]
|
||||
authors: [ "@maddievn", "@mikolaj_wawrzyniak", "@dgruzd" ]
|
||||
coach: [ "@stanhu" ]
|
||||
approvers: [ "@pwietchner", "@oregand", "@shinya.meda", "@mikolaj_wawrzyniak" ]
|
||||
owning-stage: "~devops::data stores"
|
||||
|
|
@ -50,7 +50,7 @@ LLMs:
|
|||
enhance performance but may also increase computational costs due to longer
|
||||
processing times.
|
||||
- **Duplicate Contents:** Repetitive content can reduce the diversity of search
|
||||
results. For instance, if a semantic search yields ten results indicating
|
||||
results. For instance, if a semantic search yields ten results indicating
|
||||
"Tom is a president" but the eleventh reveals "Tom lives in the United States,"
|
||||
solely using the top ten would omit critical information. Filtering out
|
||||
duplicate content, for example, through Maximal Marginal Relevance (MMR), can
|
||||
|
|
@ -101,7 +101,7 @@ execution of multiple tools and LLM inferences.
|
|||
|
||||
Choosing the appropriate search method is pivotal for feature design and UX optimization. Here are common search techniques:
|
||||
|
||||
### Semantic Search
|
||||
### Semantic Search using embeddings
|
||||
|
||||
Semantic search shines when handling complex queries that demand an
|
||||
understanding of the context or intent behind the words, not just the words
|
||||
|
|
@ -114,7 +114,7 @@ related information.
|
|||
|
||||
In the realm of semantic search, the K-Nearest Neighbors (KNN) method is
|
||||
commonly employed to identify data segments that are semantically closer to the
|
||||
user's input. To measure the semantic proximity, various methods are used:
|
||||
user's input by using embeddings. To measure the semantic proximity, various methods are used:
|
||||
|
||||
- **Cosine Similarity:** Focuses solely on the direction of vectors.
|
||||
- **L2 Distance (Euclidean Distance):** Takes into account both the direction
|
||||
|
|
@ -137,6 +137,13 @@ approximate nearest neighbors (ANN) search, is a popular strategy for this
|
|||
purpose. For insights into HNSW's effectiveness, consider reviewing
|
||||
[benchmarks on its performance in large-scale applications](https://supabase.com/blog/increase-performance-pgvector-hnsw).
|
||||
|
||||
Due to the existing framework and scalability of Elasticsearch, embeddings will
|
||||
be stored on Elasticsearch for large datasets such as
|
||||
[issues](https://gitlab.com/gitlab-org/gitlab/-/issues/451431), merge requests,
|
||||
etc. This will be used to perform [Hybrid Search](https://gitlab.com/gitlab-org/gitlab/-/issues/440424)
|
||||
but will also be useful for other features such as finding duplicates, similar results or
|
||||
categorizing documents.
|
||||
|
||||
### Keyword Search
|
||||
|
||||
Keyword search is the go-to method for straightforward, specific queries where
|
||||
|
|
@ -151,6 +158,10 @@ that have a high frequency of the query terms. Its efficiency and directness
|
|||
make it particularly useful for situations where users expect quick and precise
|
||||
results based on specific keywords or phrases.
|
||||
|
||||
Elasicsearch uses a BM25 algorigthm to perform keyword search.
|
||||
If one of the existing [indexed document types](../../../integration/advanced_search/elasticsearch.md#advanced-search-index-scopes)
|
||||
is not covered, a [new document type](../../../development/advanced_search.md#add-a-new-document-type-to-elasticsearch) can be added.
|
||||
|
||||
### Hybrid Search
|
||||
|
||||
Hybrid search combines the depth of semantic search with the precision of
|
||||
|
|
@ -169,13 +180,22 @@ contrasted with the relative efficiency of [BM25](https://pub.aimind.so/understa
|
|||
keyword searches, making hybrid search a strategic choice for optimizing
|
||||
performance across diverse datasets.
|
||||
|
||||
The first hybrid search scope is for issues which combines keyword search with kNN matches using embeddings.
|
||||
|
||||
### Code Search
|
||||
|
||||
Like the other data types above, a source code search task can utilize different
|
||||
search types, each more suited to address different queries. Currently,
|
||||
search types, each more suited to address different queries.
|
||||
|
||||
Two code searches are available currrently: `Elasticsearch` and `Zoekt`.
|
||||
|
||||
Elasticsearch provides blob search which supports [Advanced Search Syntax](../../../drawers/advanced_search_syntax.md).
|
||||
|
||||
[Zoekt](../code_search_with_zoekt/index.md) is employed on GitLab.com to provide
|
||||
exact match keyword search and regular expression search capabilities for source
|
||||
code. Semantic search and hybrid search functionalities are yet to be
|
||||
code.
|
||||
|
||||
Semantic search and hybrid search functionalities are yet to be
|
||||
implemented for code.
|
||||
|
||||
### ID Search
|
||||
|
|
@ -283,17 +303,3 @@ To read more about the [GitLab Duo Chat PoCs](../gitlab_duo_rag/index.md) conduc
|
|||
- [PGVector PoC](../gitlab_duo_rag/postgresql.md)
|
||||
- [Elasticsearch PoC](../gitlab_duo_rag/elasticsearch.md)
|
||||
- [Google Vertex PoC](../gitlab_duo_rag/vertex_ai_search.md)
|
||||
|
||||
## Proposed solution
|
||||
|
||||
_Disclaimer: This blueprint is in the first iteration and the chosen solutions could change._
|
||||
|
||||
Due to the existing framework and scalability of Elasticsearch, embeddings will
|
||||
be stored on Elasticsearch for large datasets such as
|
||||
[issues](https://gitlab.com/gitlab-org/gitlab/-/issues/451431), merge requests,
|
||||
etc. This will be used to perform [Hybrid Search](https://gitlab.com/gitlab-org/gitlab/-/issues/440424)
|
||||
but will also be useful for other features such as finding duplicates, similar results or
|
||||
categorizing documents.
|
||||
|
||||
[Vertext AI Search](../gitlab_duo_rag/vertex_ai_search.md) is going to be
|
||||
implemented to serve GitLab DUO documentation for self-managed instances.
|
||||
|
|
|
|||
|
|
@ -344,6 +344,15 @@ These [predefined variables](../variables/predefined_variables.md)
|
|||
ensure that your component also works when used on another instance, for example when using
|
||||
[a GitLab.com component in a self-managed instance](#use-a-gitlabcom-component-in-a-self-managed-instance).
|
||||
|
||||
### Do not assume API resources are always public
|
||||
|
||||
Ensure that the component and its testing pipeline work also [in a self-managed instance](#use-a-gitlabcom-component-in-a-self-managed-instance).
|
||||
While some API resources of public projects on GitLab.com could be accessed via unauthenticated requests
|
||||
on self-managed a component project could be mirrored as private or internal project.
|
||||
|
||||
It's important that an access token can optionally be provided via inputs or variables to
|
||||
authenticate requests on self-managed instances.
|
||||
|
||||
### Avoid using global keywords
|
||||
|
||||
Avoid using [global keywords](../yaml/index.md#global-keywords) in a component.
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ There are two places defined variables can be used. On the:
|
|||
| [`only:variables`](../yaml/index.md#onlyvariables--exceptvariables) (Deprecated) | no | Not applicable | The variable must be in the form of `$variable`. Not supported are the following:<br/><br/>- `CI_ENVIRONMENT_SLUG` variable.<br/>- [Persisted variables](#persisted-variables). |
|
||||
| [`resource_group`](../yaml/index.md#resource_group) | yes | GitLab | Similar to `environment:url`, but the variables expansion doesn't support the following:<br/>- `CI_ENVIRONMENT_URL`<br/>- [Persisted variables](#persisted-variables). |
|
||||
| [`rules:changes`](../yaml/index.md#ruleschanges) | yes | GitLab | The variable expansion is made by the [internal variable expansion mechanism](#gitlab-internal-variable-expansion-mechanism) in GitLab. |
|
||||
| [`rules:changes:compare_to`](../yaml/index.md#ruleschangescompare_to) | yes | GitLab | The variable expansion is made by the [internal variable expansion mechanism](#gitlab-internal-variable-expansion-mechanism) in GitLab. |
|
||||
| [`rules:exists`](../yaml/index.md#rulesexists) | yes | GitLab | The variable expansion is made by the [internal variable expansion mechanism](#gitlab-internal-variable-expansion-mechanism) in GitLab. |
|
||||
| [`rules:if`](../yaml/index.md#rulesif) | no | Not applicable | The variable must be in the form of `$variable`. Not supported are the following:<br/><br/>- `CI_ENVIRONMENT_SLUG` variable.<br/>- [Persisted variables](#persisted-variables). |
|
||||
| [`script`](../yaml/index.md#script) | yes | Script execution shell | The variable expansion is made by the [execution shell environment](#execution-shell-environment). |
|
||||
|
|
|
|||
|
|
@ -1043,8 +1043,6 @@ Use `after_script` to define an array of commands to run last, after a job's `be
|
|||
- Long commands [split over multiple lines](script.md#split-long-commands).
|
||||
- [YAML anchors](yaml_optimization.md#yaml-anchors-for-scripts).
|
||||
|
||||
CI/CD variables [are supported](../variables/where_variables_can_be_used.md#gitlab-ciyml-file).
|
||||
|
||||
**Example of `after_script`**:
|
||||
|
||||
```yaml
|
||||
|
|
@ -4201,6 +4199,7 @@ In this example, both jobs have the same behavior.
|
|||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/293645) in GitLab 15.3 [with a flag](../../administration/feature_flags.md) named `ci_rules_changes_compare`. Enabled by default.
|
||||
> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/366412) in GitLab 15.5. Feature flag `ci_rules_changes_compare` removed.
|
||||
> - Support for CI/CD variables [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/369916) in GitLab 17.2 [with a flag](../../administration/feature_flags.md) named `ci_expand_variables_in_compare_to`. Disabled by default.
|
||||
|
||||
Use `rules:changes:compare_to` to specify which ref to compare against for changes to the files
|
||||
listed under [`rules:changes:paths`](#ruleschangespaths).
|
||||
|
|
@ -4213,6 +4212,8 @@ listed under [`rules:changes:paths`](#ruleschangespaths).
|
|||
- A tag name, like `tag1` or `refs/tags/tag1`.
|
||||
- A commit SHA, like `2fg31ga14b`.
|
||||
|
||||
CI/CD variables [are supported](../variables/where_variables_can_be_used.md#gitlab-ciyml-file).
|
||||
|
||||
**Example of `rules:changes:compare_to`**:
|
||||
|
||||
```yaml
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ info: Any user with at least the Maintainer role can merge updates to this conte
|
|||
|
||||
To allow GitLab to scale further we
|
||||
[decomposed the GitLab application database into multiple databases](https://gitlab.com/groups/gitlab-org/-/epics/6168).
|
||||
The two databases are `main` and `ci`. GitLab supports being run with either one database or two databases.
|
||||
On GitLab.com we are using two separate databases.
|
||||
The main databases are `main`, `ci`, and (optionally) `sec`. GitLab supports being run with one, two, or three databases.
|
||||
On GitLab.com we are using separate `main` and `ci` databases.
|
||||
|
||||
For the purpose of building the [Cells](../../architecture/blueprints/cells/index.md) architecture, we are decomposing
|
||||
the databases further, to introduce another database `gitlab_main_clusterwide`.
|
||||
|
|
@ -47,6 +47,7 @@ The usage of schema enforces the base class to be used:
|
|||
- `Geo::TrackingBase` for `gitlab_geo`
|
||||
- `Gitlab::Database::SharedModel` for `gitlab_shared`
|
||||
- `PackageMetadata::ApplicationRecord` for `gitlab_pm`
|
||||
- `Gitlab::Database::SecApplicationRecord` for `gitlab_sec`
|
||||
|
||||
### Choose either the `gitlab_main_cell` or `gitlab_main_clusterwide` schema
|
||||
|
||||
|
|
|
|||
|
|
@ -1156,17 +1156,19 @@ Instead of:
|
|||
|
||||
## level
|
||||
|
||||
If you can, avoid using `level` in the context of an instance or group.
|
||||
If you can, avoid using `level` in the context of an instance, project, or group.
|
||||
|
||||
Use:
|
||||
|
||||
- This setting is turned on for the instance.
|
||||
- This setting is turned on for the group and its subgroups.
|
||||
- This setting is turned on for projects.
|
||||
|
||||
Instead of:
|
||||
|
||||
- This setting is turned on at the instance level.
|
||||
- This setting is turned on at the group level.
|
||||
- This is a project-level setting.
|
||||
|
||||
## list
|
||||
|
||||
|
|
|
|||
|
|
@ -456,24 +456,6 @@ end
|
|||
|
||||
This script finds tokens that do not have an expiry date, that is, `expires_at` is set to `NULL`. For users who have not yet upgraded to GitLab version 16.0 or later, the token `expires_at` value will be `NULL` and can be used to identify tokens that will be set with an expiration date.
|
||||
|
||||
```ruby
|
||||
# This script finds tokens which do not have an expires_at value set.
|
||||
|
||||
# Check for expiring personal access tokens
|
||||
PersonalAccessToken.owner_is_human.where(expires_at: nil).find_each do |token|
|
||||
puts "Expires_at is nil for Personal Access Token ID: #{token.id}, User Email: #{token.user.email}, Name: #{token.name}, Scopes: #{token.scopes}, Last used: #{token.last_used_at}"
|
||||
end
|
||||
|
||||
# Check for expiring project and group access tokens
|
||||
PersonalAccessToken.project_access_token.where(expires_at: nil).find_each do |token|
|
||||
token.user.members.each do |member|
|
||||
type = member.is_a?(GroupMember) ? 'Group' : 'Project'
|
||||
|
||||
puts "Expires_at is nil for #{type} access token in #{type} ID #{member.source_id}, Token ID: #{token.id}, Name: #{token.name}, Scopes: #{token.scopes}, Last used: #{token.last_used_at}"
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
You can use this script in either the [Rails console](../administration/operations/rails_console.md) or the [Rails Runner](../administration/operations/rails_console.md#using-the-rails-runner):
|
||||
|
||||
::Tabs
|
||||
|
|
@ -485,6 +467,24 @@ You can use this script in either the [Rails console](../administration/operatio
|
|||
1. Paste in the entire script.
|
||||
1. Press <kbd>Enter</kbd>.
|
||||
|
||||
```ruby
|
||||
# This script finds tokens which do not have an expires_at value set.
|
||||
|
||||
# Check for expiring personal access tokens
|
||||
PersonalAccessToken.owner_is_human.where(expires_at: nil).find_each do |token|
|
||||
puts "Expires_at is nil for Personal Access Token ID: #{token.id}, User Email: #{token.user.email}, Name: #{token.name}, Scopes: #{token.scopes}, Last used: #{token.last_used_at}"
|
||||
end
|
||||
|
||||
# Check for expiring project and group access tokens
|
||||
PersonalAccessToken.project_access_token.where(expires_at: nil).find_each do |token|
|
||||
token.user.members.each do |member|
|
||||
type = member.is_a?(GroupMember) ? 'Group' : 'Project'
|
||||
|
||||
puts "Expires_at is nil for #{type} access token in #{type} ID #{member.source_id}, Token ID: #{token.id}, Name: #{token.name}, Scopes: #{token.scopes}, Last used: #{token.last_used_at}"
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
:::TabTitle Rails Runner
|
||||
|
||||
1. In your terminal window, connect to your instance.
|
||||
|
|
|
|||
|
|
@ -80,7 +80,10 @@ To enable the Advanced SAST analyzer:
|
|||
when: never
|
||||
- if: $SAST_EXCLUDED_ANALYZERS =~ /gitlab-advanced-sast/
|
||||
when: never
|
||||
- if: $CI_COMMIT_BRANCH
|
||||
- if: $CI_PIPELINE_SOURCE == "merge_request_event" # Add the job to merge request pipelines if there's an open merge request.
|
||||
exists:
|
||||
- '**/*.py'
|
||||
- if: $CI_COMMIT_BRANCH # If there's no open merge request, add it to a *branch* pipeline instead.
|
||||
exists:
|
||||
- '**/*.py'
|
||||
```
|
||||
|
|
|
|||
|
|
@ -80,7 +80,6 @@ To restrict group access by IP address:
|
|||
1. In the **Restrict access by IP address** text box, enter a list of IPv4 or IPv6
|
||||
address ranges in CIDR notation. This list:
|
||||
- Has no limit on the number of IP address ranges.
|
||||
- Has a size limit of 1 GB.
|
||||
- Applies to both SSH or HTTP authorized IP address ranges. You cannot split
|
||||
this list by type of authorization.
|
||||
1. Select **Save changes**.
|
||||
|
|
|
|||
|
|
@ -31,8 +31,8 @@ module Keeps
|
|||
class QuarantineFlakyTests < ::Gitlab::Housekeeper::Keep
|
||||
MINIMUM_REMAINING_RATE = 25
|
||||
QUERY_URL_TEMPLATE = "https://gitlab.com/api/v4/projects/278964/issues/?order_by=updated_at&state=opened&labels[]=test&labels[]=failure::flaky-test&labels[]=%<flakiness_label>s¬[labels][]=QA¬[labels][]=quarantine&per_page=20"
|
||||
# https://rubular.com/r/WnMxnDPvGGjoGE
|
||||
EXAMPLE_LINE_REGEX = /\bit (?<description_and_metadata>[\w'",: ]*(?:,\n)?[\w\'",: ]+?) do$/m
|
||||
# https://rubular.com/r/OoeQIEwPkL1m7E
|
||||
EXAMPLE_LINE_REGEX = /\bit (?<description_and_metadata>[\w'",: \#\{\}]*(?:,\n)?[\w\'",: ]+?) do$/m
|
||||
FLAKINESS_LABELS = %w[flakiness::1 flakiness::2].freeze
|
||||
|
||||
def each_change
|
||||
|
|
|
|||
|
|
@ -302,6 +302,7 @@ module API
|
|||
mount ::API::ProjectAvatar
|
||||
mount ::API::ProjectClusters
|
||||
mount ::API::ProjectContainerRepositories
|
||||
mount ::API::ProjectContainerRegistryProtectionRules
|
||||
mount ::API::ProjectDebianDistributions
|
||||
mount ::API::ProjectEvents
|
||||
mount ::API::ProjectExport
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue