Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2024-08-08 18:07:22 +00:00
parent eaaf34e042
commit 5f506364a9
120 changed files with 1947 additions and 1136 deletions

View File

@ -3006,6 +3006,7 @@ Gitlab/BoundedContexts:
- 'ee/app/models/package_metadata/advisory.rb'
- 'ee/app/models/package_metadata/affected_package.rb'
- 'ee/app/models/package_metadata/checkpoint.rb'
- 'ee/app/models/package_metadata/epss.rb'
- 'ee/app/models/package_metadata/license.rb'
- 'ee/app/models/package_metadata/package.rb'
- 'ee/app/models/package_metadata/package_version.rb'

View File

@ -344,7 +344,6 @@ Gitlab/StrongMemoizeAttr:
- 'ee/app/services/projects/restore_service.rb'
- 'ee/app/services/protected_environments/base_service.rb'
- 'ee/app/services/security/ingestion/tasks/ingest_vulnerabilities/mark_resolved_as_detected.rb'
- 'ee/app/services/security/report_fetch_service.rb'
- 'ee/app/services/security/report_summary_service.rb'
- 'ee/app/services/security/security_orchestration_policies/on_demand_scan_pipeline_configuration_service.rb'
- 'ee/app/services/security/security_orchestration_policies/operational_vulnerabilities_configuration_service.rb'

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 775 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 973 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

View File

@ -290,7 +290,7 @@
"coverage_format": {
"description": "Code coverage format used by the test framework.",
"enum": [
"cobertura"
"cobertura", "jacoco"
]
},
"path": {

View File

@ -39,6 +39,17 @@ export const PLACEHOLDER_STATUS_FAILED = 'FAILED';
export const PLACEHOLDER_STATUS_KEPT_AS_PLACEHOLDER = 'KEEP_AS_PLACEHOLDER';
export const PLACEHOLDER_STATUS_COMPLETED = 'COMPLETED';
export const PLACEHOLDER_USER_STATUS = {
UNASSIGNED: [
PLACEHOLDER_STATUS_PENDING_REASSIGNMENT,
PLACEHOLDER_STATUS_AWAITING_APPROVAL,
PLACEHOLDER_STATUS_REJECTED,
PLACEHOLDER_STATUS_REASSIGNING,
PLACEHOLDER_STATUS_FAILED,
],
REASSIGNED: [PLACEHOLDER_STATUS_COMPLETED, PLACEHOLDER_STATUS_KEPT_AS_PLACEHOLDER],
};
export const placeholderUserBadges = {
[PLACEHOLDER_STATUS_PENDING_REASSIGNMENT]: {
text: __('Not started'),

View File

@ -171,6 +171,8 @@ export const AVAILABLE_FILTERED_SEARCH_TOKENS = [
export const AVATAR_SIZE = 48;
export const DEFAULT_PAGE_SIZE = 20;
export const MEMBERS_TAB_TYPES = Object.freeze({
user: 'user',
group: 'group',

View File

@ -2,22 +2,19 @@
// eslint-disable-next-line no-restricted-imports
import { mapState } from 'vuex';
import { GlBadge, GlTab, GlTabs, GlButton, GlModalDirective } from '@gitlab/ui';
import { createAlert } from '~/alert';
import { s__, sprintf } from '~/locale';
import { getParameterByName } from '~/lib/utils/url_utility';
import {
PLACEHOLDER_STATUS_FAILED,
QUERY_PARAM_FAILED,
PLACEHOLDER_USER_STATUS,
} from '~/import_entities/import_groups/constants';
import importSourceUsersQuery from '../graphql/queries/import_source_users.query.graphql';
import PlaceholdersTable from './placeholders_table.vue';
import CsvUploadModal from './csv_upload_modal.vue';
const UPLOAD_CSV_PLACEHOLDERS_MODAL_ID = 'upload-placeholders-csv-modal';
const DEFAULT_PAGE_SIZE = 20;
export default {
name: 'PlaceholdersTabApp',
components: {
@ -31,59 +28,24 @@ export default {
directives: {
GlModal: GlModalDirective,
},
inject: ['group'],
data() {
return {
selectedTabIndex: 0,
unassignedCount: null,
reassignedCount: null,
cursor: {
before: null,
after: null,
},
};
},
apollo: {
sourceUsers: {
query: importSourceUsersQuery,
variables() {
return {
fullPath: this.group.path,
...this.cursor,
[this.cursor.before ? 'last' : 'first']: DEFAULT_PAGE_SIZE,
statuses: this.queryStatuses,
};
},
update(data) {
return data.namespace?.importSourceUsers;
},
error() {
createAlert({
message: s__('UserMapping|There was a problem fetching placeholder users.'),
});
},
},
},
computed: {
...mapState('placeholder', ['pagination']),
isLoading() {
return Boolean(this.$apollo.queries.sourceUsers.loading);
},
nodes() {
return this.sourceUsers?.nodes || [];
},
pageInfo() {
return this.sourceUsers?.pageInfo || {};
},
statusParamValue() {
return getParameterByName('status');
},
queryStatuses() {
unassignedUserStatuses() {
if (getParameterByName('status') === QUERY_PARAM_FAILED) {
return [PLACEHOLDER_STATUS_FAILED];
}
return [];
return PLACEHOLDER_USER_STATUS.UNASSIGNED;
},
reassignedUserStatuses() {
return PLACEHOLDER_USER_STATUS.REASSIGNED;
},
},
@ -129,12 +91,9 @@ export default {
<placeholders-table
key="unassigned"
:items="nodes"
:page-info="pageInfo"
:is-loading="isLoading"
data-testid="placeholders-table-unassigned"
:query-statuses="unassignedUserStatuses"
@confirm="onConfirm"
@prev="onPrevPage"
@next="onNextPage"
/>
</gl-tab>
@ -146,12 +105,9 @@ export default {
<placeholders-table
key="reassigned"
data-testid="placeholders-table-reassigned"
:query-statuses="reassignedUserStatuses"
reassigned
:items="nodes"
:page-info="pageInfo"
:is-loading="isLoading"
@prev="onPrevPage"
@next="onNextPage"
/>
</gl-tab>

View File

@ -7,13 +7,17 @@ import {
GlTable,
GlTooltipDirective,
} from '@gitlab/ui';
import { createAlert } from '~/alert';
import { s__ } from '~/locale';
import { DEFAULT_PAGE_SIZE } from '~/members/constants';
import {
PLACEHOLDER_STATUS_KEPT_AS_PLACEHOLDER,
PLACEHOLDER_STATUS_COMPLETED,
placeholderUserBadges,
} from '~/import_entities/import_groups/constants';
import importSourceUsersQuery from '../graphql/queries/import_source_users.query.graphql';
import PlaceholderActions from './placeholder_actions.vue';
export default {
@ -29,20 +33,11 @@ export default {
directives: {
GlTooltip: GlTooltipDirective,
},
inject: ['group'],
props: {
isLoading: {
type: Boolean,
required: true,
},
items: {
queryStatuses: {
type: Array,
required: false,
default: () => [],
},
pageInfo: {
type: Object,
required: false,
default: () => ({}),
required: true,
},
reassigned: {
type: Boolean,
@ -50,6 +45,36 @@ export default {
default: false,
},
},
data() {
return {
cursor: {
before: null,
after: null,
},
};
},
apollo: {
sourceUsers: {
query: importSourceUsersQuery,
variables() {
return {
fullPath: this.group.path,
...this.cursor,
[this.cursor.before ? 'last' : 'first']: DEFAULT_PAGE_SIZE,
statuses: this.queryStatuses,
};
},
update(data) {
return data.namespace?.importSourceUsers;
},
error() {
createAlert({
message: s__('UserMapping|There was a problem fetching placeholder users.'),
});
},
},
},
computed: {
fields() {
@ -75,6 +100,15 @@ export default {
},
];
},
isLoading() {
return this.$apollo.queries.sourceUsers.loading;
},
nodes() {
return this.sourceUsers?.nodes || [];
},
pageInfo() {
return this.sourceUsers?.pageInfo || {};
},
},
methods: {
@ -98,6 +132,19 @@ export default {
return {};
},
onPrevPage() {
this.cursor = {
before: this.sourceUsers.pageInfo.startCursor,
after: null,
};
},
onNextPage() {
this.cursor = {
after: this.sourceUsers.pageInfo.endCursor,
before: null,
};
},
onConfirm(item) {
this.$emit('confirm', item);
@ -108,7 +155,7 @@ export default {
<template>
<div>
<gl-table :items="items" :fields="fields" :busy="isLoading">
<gl-table :items="nodes" :fields="fields" :busy="isLoading">
<template #table-busy>
<gl-loading-icon size="lg" class="gl-my-5" />
</template>
@ -155,8 +202,8 @@ export default {
v-bind="pageInfo"
:prev-text="__('Prev')"
:next-text="__('Next')"
@prev="$emit('prev')"
@next="$emit('next')"
@prev="onPrevPage"
@next="onNextPage"
/>
</div>
</div>

View File

@ -1,12 +1,13 @@
<script>
import { GlButton, GlTooltipDirective, GlSprintf, GlSkeletonLoader } from '@gitlab/ui';
import { GlButton, GlTooltipDirective, GlSprintf, GlSkeletonLoader, GlBadge } from '@gitlab/ui';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { n__ } from '~/locale';
import { n__, s__ } from '~/locale';
import Tracking from '~/tracking';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import ListItem from '~/vue_shared/components/registry/list_item.vue';
import { joinPaths } from '~/lib/utils/url_utility';
import PublishMessage from '~/packages_and_registries/shared/components/publish_message.vue';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import {
LIST_DELETE_BUTTON_DISABLED,
LIST_DELETE_BUTTON_DISABLED_FOR_MIGRATION,
@ -33,11 +34,12 @@ export default {
GlSkeletonLoader,
CleanupStatus,
PublishMessage,
GlBadge,
},
directives: {
GlTooltip: GlTooltipDirective,
},
mixins: [Tracking.mixin()],
mixins: [Tracking.mixin(), glFeatureFlagsMixin()],
inject: ['config'],
props: {
item: {
@ -60,6 +62,9 @@ export default {
ROW_SCHEDULED_FOR_DELETION,
COPY_IMAGE_PATH_TITLE,
IMAGE_FULL_PATH_LABEL,
badgeProtectedTooltipText: s__(
'ContainerRegistry|A protection rule exists for this container repository.',
),
},
data() {
return {
@ -109,6 +114,12 @@ export default {
projectUrl() {
return this.config.isGroupPage ? this.item.project?.webUrl : '';
},
showBadgeProtected() {
return (
Boolean(this.glFeatures.containerRegistryProtectedContainers) &&
Boolean(this.item.protectionRuleExists)
);
},
},
methods: {
hideButton() {
@ -175,6 +186,17 @@ export default {
:status="item.expirationPolicyCleanupStatus"
:expiration-policy="expirationPolicy"
/>
<gl-badge
v-if="showBadgeProtected"
v-gl-tooltip
:title="$options.i18n.badgeProtectedTooltipText"
class="gl-ml-3"
size="sm"
variant="neutral"
>
{{ __('protected') }}
</gl-badge>
</template>
</template>

View File

@ -133,6 +133,7 @@ export default {
:show-divider="index !== 0"
:title="statusCheck.name"
:status-check-url="statusCheck.externalUrl"
:hmac="statusCheck.hmac"
/>
</gl-card>
</template>

View File

@ -1,6 +1,6 @@
<script>
import { GlAvatarsInline, GlAvatar, GlAvatarLink, GlTooltipDirective, GlBadge } from '@gitlab/ui';
import { n__ } from '~/locale';
import { n__, __ } from '~/locale';
import { accessLevelsConfig } from './constants';
const AVATAR_TOOLTIP_MAX_CHARS = 100;
@ -8,6 +8,9 @@ export const MAX_VISIBLE_AVATARS = 4;
export const AVATAR_SIZE = 24;
export default {
i18n: {
sharedSecret: __('HMAC enabled'),
},
name: 'ProtectionRow',
AVATAR_TOOLTIP_MAX_CHARS,
MAX_VISIBLE_AVATARS,
@ -48,6 +51,11 @@ export default {
required: false,
default: null,
},
hmac: {
type: Boolean,
required: false,
default: false,
},
},
computed: {
avatarBadgeSrOnlyText() {
@ -104,6 +112,10 @@ export default {
</template>
</gl-avatars-inline>
<gl-badge v-if="hmac" data-testid="shared-secret" class="gl-mr-2">{{
$options.i18n.sharedSecret
}}</gl-badge>
<gl-badge
v-for="(item, index) in accessLevels"
:key="index"

View File

@ -18,6 +18,7 @@ export default {
ACCESS_LEVEL_DEVELOPER_INTEGER,
ACCESS_LEVEL_MAINTAINER_INTEGER,
ACCESS_LEVEL_ADMIN_INTEGER,
ACCESS_LEVEL_NO_ACCESS_INTEGER,
components: {
GlDrawer,
GlButton,
@ -66,6 +67,7 @@ export default {
isAdminSelected: null,
isMaintainersSelected: null,
isDevelopersAndMaintainersSelected: null,
isNoOneSelected: null,
isRuleUpdated: false,
};
},
@ -73,25 +75,29 @@ export default {
getDrawerHeaderHeight() {
return getContentWrapperHeight();
},
isNoOneSelected() {
return (
!this.isAdminSelected &&
!this.isMaintainersSelected &&
!this.isDevelopersAndMaintainersSelected
);
},
},
watch: {
isOpen() {
this.isAdminSelected = this.roles.includes(ACCESS_LEVEL_ADMIN_INTEGER);
this.isMaintainersSelected = this.roles.includes(ACCESS_LEVEL_MAINTAINER_INTEGER);
this.isDevelopersAndMaintainersSelected = this.roles.includes(ACCESS_LEVEL_DEVELOPER_INTEGER);
this.isNoOneSelected = this.roles.includes(ACCESS_LEVEL_NO_ACCESS_INTEGER);
this.updatedGroups = this.groups;
this.updatedUsers = this.users;
},
},
methods: {
handleNoOneSelected() {
this.isRuleUpdated = true;
this.isAdminSelected = false;
this.isMaintainersSelected = false;
this.isDevelopersAndMaintainersSelected = false;
},
handleAccessLevelSelected() {
this.isRuleUpdated = true;
this.isNoOneSelected = false;
},
handleRuleDataUpdate(namespace, items) {
this.isRuleUpdated = true;
this[namespace] = items;
@ -100,23 +106,24 @@ export default {
return items.map((item) => ({ [keyName]: convertToGraphQLId(type, item.id) }));
},
getRuleEditData() {
let ruleEditData = [
const ruleEditRoles = [
...this.formatItemsData(this.updatedUsers, 'userId', 'User'), // eslint-disable-line @gitlab/require-i18n-strings
...this.formatItemsData(this.updatedGroups, 'groupId', 'Group'), // eslint-disable-line @gitlab/require-i18n-strings
];
let ruleEditAccessLevels = [];
if (this.isAdminSelected) {
ruleEditData.push({ accessLevel: ACCESS_LEVEL_ADMIN_INTEGER });
ruleEditAccessLevels.push({ accessLevel: ACCESS_LEVEL_ADMIN_INTEGER });
}
if (this.isMaintainersSelected) {
ruleEditData.push({ accessLevel: ACCESS_LEVEL_MAINTAINER_INTEGER });
ruleEditAccessLevels.push({ accessLevel: ACCESS_LEVEL_MAINTAINER_INTEGER });
}
if (this.isDevelopersAndMaintainersSelected) {
ruleEditData.push({ accessLevel: ACCESS_LEVEL_DEVELOPER_INTEGER });
ruleEditAccessLevels.push({ accessLevel: ACCESS_LEVEL_DEVELOPER_INTEGER });
}
if (this.isNoOneSelected) {
ruleEditData = [{ accessLevel: ACCESS_LEVEL_NO_ACCESS_INTEGER }];
ruleEditAccessLevels = [{ accessLevel: ACCESS_LEVEL_NO_ACCESS_INTEGER }];
}
return ruleEditData;
return [...ruleEditRoles, ...ruleEditAccessLevels];
},
formatItemsIds(items) {
return items.map((item) => ({ ...item, id: getIdFromGraphQLId(item.id) }));
@ -156,22 +163,27 @@ export default {
</template>
<template #default>
<gl-form-group class="gl-border-none">
<gl-form-checkbox v-model="isAdminSelected" @change="isRuleUpdated = true">
<gl-form-checkbox v-model="isAdminSelected" @change="handleAccessLevelSelected">
{{ $options.accessLevelsConfig[$options.ACCESS_LEVEL_ADMIN_INTEGER].accessLevelLabel }}
</gl-form-checkbox>
<gl-form-checkbox v-model="isMaintainersSelected" @change="isRuleUpdated = true">
<gl-form-checkbox v-model="isMaintainersSelected" @change="handleAccessLevelSelected">
{{
$options.accessLevelsConfig[$options.ACCESS_LEVEL_MAINTAINER_INTEGER].accessLevelLabel
}}
</gl-form-checkbox>
<gl-form-checkbox
v-model="isDevelopersAndMaintainersSelected"
@change="isRuleUpdated = true"
@change="handleAccessLevelSelected"
>
{{
$options.accessLevelsConfig[$options.ACCESS_LEVEL_DEVELOPER_INTEGER].accessLevelLabel
}}
</gl-form-checkbox>
<gl-form-checkbox v-model="isNoOneSelected" @change="handleNoOneSelected">
{{
$options.accessLevelsConfig[$options.ACCESS_LEVEL_NO_ACCESS_INTEGER].accessLevelLabel
}}
</gl-form-checkbox>
<items-selector
type="users"

View File

@ -17,6 +17,8 @@ import {
I18N_WORK_ITEM_CONFIDENTIALITY_CHECKBOX_LABEL,
I18N_WORK_ITEM_CONFIDENTIALITY_CHECKBOX_TOOLTIP,
WORK_ITEM_TYPE_VALUE_EPIC,
I18N_MAX_WORK_ITEMS_ERROR_MESSAGE,
MAX_WORK_ITEMS,
sprintfWorkItem,
} from '../../constants';
import WorkItemProjectsListbox from './work_item_projects_listbox.vue';
@ -240,10 +242,10 @@ export default {
: [];
},
areWorkItemsToAddValid() {
return this.invalidWorkItemsToAdd.length === 0;
return this.invalidWorkItemsToAdd.length === 0 && this.areWorkItemsToAddWithinLimit;
},
showWorkItemsToAddInvalidMessage() {
return !this.isCreateForm && !this.areWorkItemsToAddValid;
return !this.isCreateForm && this.invalidWorkItemsToAdd.length > 0;
},
workItemsToAddInvalidMessage() {
return sprintf(
@ -257,6 +259,9 @@ export default {
},
);
},
areWorkItemsToAddWithinLimit() {
return this.workItemsToAdd.length <= MAX_WORK_ITEMS;
},
},
watch: {
workItemsToAdd() {
@ -358,6 +363,7 @@ export default {
titleInputPlaceholder: s__('WorkItem|Add a title'),
projectInputPlaceholder: s__('WorkItem|Select a project'),
titleInputValidationMessage: __('Maximum of 255 characters'),
maxItemsErrorMessage: I18N_MAX_WORK_ITEMS_ERROR_MESSAGE,
},
};
</script>
@ -438,6 +444,13 @@ export default {
<div v-if="error" class="gl-text-red-500 gl-mt-3" data-testid="work-items-error">
{{ error }}
</div>
<div
v-if="!areWorkItemsToAddWithinLimit"
class="gl-mb-2 gl-text-red-500"
data-testid="work-items-limit-error"
>
{{ $options.i18n.maxItemsErrorMessage }}
</div>
</div>
<gl-button
category="primary"

View File

@ -12,7 +12,7 @@ module Groups
push_frontend_feature_flag(:show_container_registry_tag_signatures, group)
end
before_action only: [:show] do
before_action only: [:index, :show] do
push_frontend_feature_flag(:container_registry_protected_containers, group)
end

View File

@ -10,8 +10,11 @@ module Projects
push_frontend_feature_flag(:show_container_registry_tag_signatures, project)
end
before_action only: [:index, :show] do
push_frontend_feature_flag(:container_registry_protected_containers, project)
end
before_action :authorize_update_container_image!, only: [:destroy]
before_action :set_feature_flag_container_registry_protected_containers, only: [:show]
def index
respond_to do |format|
@ -55,10 +58,6 @@ module Projects
end
end
end
def set_feature_flag_container_registry_protected_containers
push_frontend_feature_flag(:container_registry_protected_containers, project)
end
end
end
end

View File

@ -35,6 +35,7 @@ query getProjectContainerRepositories(
id
path
}
protectionRuleExists
userPermissions {
destroyContainerRepository
}
@ -78,6 +79,7 @@ query getProjectContainerRepositories(
path
webUrl
}
protectionRuleExists
userPermissions {
destroyContainerRepository
}

View File

@ -33,6 +33,24 @@ module Resolvers
description: 'Filter by reviewer presence. Incompatible with reviewerUsername.'
end
argument :approved_by, [GraphQL::Types::String],
required: false,
as: :approved_by_usernames,
description: 'Usernames of the approvers.'
argument :release_tag, GraphQL::Types::String,
required: false,
description: 'Filter by release tag.'
argument :merged_by, GraphQL::Types::String,
required: false,
as: :merge_user_username,
description: 'Username of the merger.'
argument :my_reaction_emoji, GraphQL::Types::String,
required: false,
description: 'Filter by your reaction emoji.'
argument :iids, [GraphQL::Types::String],
required: false,
description: 'Array of IIDs of merge requests, for example `[1, 2]`.'
@ -124,6 +142,10 @@ module Resolvers
default_value: :created_desc
negated do
argument :approved_by, [GraphQL::Types::String],
required: false,
as: :approved_by_usernames,
description: 'Usernames of approvers to exclude.'
argument :assignee_usernames, [GraphQL::Types::String],
as: :assignee_username,
required: false,
@ -134,10 +156,16 @@ module Resolvers
description: 'Array of label names. All resolved merge requests will not have these labels.'
argument :milestone_title, GraphQL::Types::String,
required: false,
description: 'Title of the milestone.'
description: 'Title of the milestone to exclude.'
argument :my_reaction_emoji, GraphQL::Types::String,
required: false,
description: 'Filter by reaction emoji to exclude.'
argument :release_tag, GraphQL::Types::String,
required: false,
description: 'Filter by release tag to exclude.'
argument :reviewer_username, GraphQL::Types::String,
required: false,
description: 'Username of the reviewer.'
description: 'Username of the reviewer to exclude.'
end
validates mutually_exclusive: [:assignee_username, :assignee_wildcard_id]

View File

@ -231,6 +231,7 @@ module MergeRequestsHelper
def project_merge_requests_list_data(project, current_user)
{
autocomplete_award_emojis_path: autocomplete_award_emojis_path,
full_path: project.full_path,
has_any_merge_requests: project_merge_requests(project).exists?.to_s,
initial_sort: current_user&.user_preference&.issues_sort,

View File

@ -61,6 +61,10 @@ module Avatarable
return uncached_avatar_path(only_path: only_path, size: size)
end
if self.try(:should_use_security_policy_bot_avatar?)
return self.security_policy_bot_static_avatar_path(size)
end
# Cache this avatar path only within the request because avatars in
# object storage may be generated with time-limited, signed URLs.
key = "#{self.class.name}:#{self.id}:#{only_path}:#{size}"

View File

@ -10,7 +10,7 @@ module Enums
secret_detection: %w[secret_detection],
test: %w[junit],
accessibility: %w[accessibility],
coverage: %w[cobertura],
coverage: %w[cobertura jacoco],
codequality: %w[codequality],
terraform: %w[terraform]
}.freeze
@ -38,6 +38,7 @@ module Enums
lsif: 'lsif.json',
dotenv: '.env',
cobertura: 'cobertura-coverage.xml',
jacoco: 'jacoco-coverage.xml',
terraform: 'tfplan.json',
cluster_applications: 'gl-cluster-applications.json', # DEPRECATED: https://gitlab.com/gitlab-org/gitlab/-/issues/361094
requirements: 'requirements.json', # Will be DEPRECATED soon: https://gitlab.com/groups/gitlab-org/-/epics/9203
@ -62,6 +63,7 @@ module Enums
network_referee: :gzip,
dotenv: :gzip,
cobertura: :gzip,
jacoco: :gzip,
cluster_applications: :gzip, # DEPRECATED: https://gitlab.com/gitlab-org/gitlab/-/issues/361094
lsif: :zip,
cyclonedx: :gzip,
@ -98,6 +100,7 @@ module Enums
api_fuzzing
archive
cobertura
jacoco
codequality
container_scanning
dast
@ -180,7 +183,8 @@ module Enums
cyclonedx: 28, ## EE-specific
requirements_v2: 29, ## EE-specific
annotations: 30,
repository_xray: 31 ## EE-specific
repository_xray: 31, ## EE-specific
jacoco: 32
}
end

View File

@ -1,9 +1,9 @@
- remove_form_id = local_assigns.fetch(:remove_form_id, nil)
= render Pajamas::CardComponent.new(card_options: { class: 'gl-new-card' }, header_options: { class: 'gl-new-card-header' }, body_options: { class: 'gl-new-card-body gl-bg-red-50 gl-px-5 gl-py-4' }) do |c|
= render Pajamas::CardComponent.new(header_options: { class: 'gl-px-5 gl-py-4 gl-border-b-1 gl-border-b-solid gl-border-gray-100' }, body_options: { class: 'gl-bg-red-50 gl-px-5 gl-py-4' }) do |c|
- c.with_header do
.gl-new-card-title-wrapper
%h4.gl-new-card-title.danger-title= _('Delete group')
.gl-flex.gl-grow
%h4.gl-text-base.gl-leading-24.gl-m-0.gl-text-red-500= _('Delete group')
- c.with_body do
= form_tag(group, method: :delete, id: remove_form_id) do

View File

@ -0,0 +1,9 @@
---
name: jacoco_coverage_reports
feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/227345
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/161168
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/475025
milestone: '17.3'
group: group::pipeline execution
type: gitlab_com_derisk
default_enabled: false

12
db/docs/pm_epss.yml Normal file
View File

@ -0,0 +1,12 @@
---
table_name: pm_epss
classes:
- PackageMetadata::Epss
feature_categories:
- software_composition_analysis
- container_scanning
description: Stores EPSS data (https://www.first.org/epss/).
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/158908
milestone: '17.3'
gitlab_schema: gitlab_sec
exempt_from_sharding: true # See discussion on keys for pm_ tables https://gitlab.com/gitlab-org/gitlab/-/issues/434988#note_1827421068

View File

@ -0,0 +1,13 @@
# frozen_string_literal: true
class CreatePackageMetadataEpss < Gitlab::Database::Migration[2.2]
milestone '17.3'
def change
create_table :pm_epss do |t|
t.float :score, null: false
t.timestamps_with_timezone null: false
t.text :cve, limit: 24, null: false, index: { unique: true }
end
end
end

View File

@ -0,0 +1 @@
6865c7c37f109d62ad8a85c794ee5dbccbeee45397fc89bb8b4f63ff2af8b9a2

View File

@ -15298,6 +15298,24 @@ CREATE SEQUENCE pm_checkpoints_id_seq
ALTER SEQUENCE pm_checkpoints_id_seq OWNED BY pm_checkpoints.id;
CREATE TABLE pm_epss (
id bigint NOT NULL,
score double precision NOT NULL,
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL,
cve text NOT NULL,
CONSTRAINT check_33a7364ae2 CHECK ((char_length(cve) <= 24))
);
CREATE SEQUENCE pm_epss_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
ALTER SEQUENCE pm_epss_id_seq OWNED BY pm_epss.id;
CREATE TABLE pm_licenses (
id bigint NOT NULL,
spdx_identifier text NOT NULL,
@ -21574,6 +21592,8 @@ ALTER TABLE ONLY pm_affected_packages ALTER COLUMN id SET DEFAULT nextval('pm_af
ALTER TABLE ONLY pm_checkpoints ALTER COLUMN id SET DEFAULT nextval('pm_checkpoints_id_seq'::regclass);
ALTER TABLE ONLY pm_epss ALTER COLUMN id SET DEFAULT nextval('pm_epss_id_seq'::regclass);
ALTER TABLE ONLY pm_licenses ALTER COLUMN id SET DEFAULT nextval('pm_licenses_id_seq'::regclass);
ALTER TABLE ONLY pm_package_version_licenses ALTER COLUMN id SET DEFAULT nextval('pm_package_version_licenses_id_seq'::regclass);
@ -24058,6 +24078,9 @@ ALTER TABLE ONLY pm_affected_packages
ALTER TABLE ONLY pm_checkpoints
ADD CONSTRAINT pm_checkpoints_pkey PRIMARY KEY (id);
ALTER TABLE ONLY pm_epss
ADD CONSTRAINT pm_epss_pkey PRIMARY KEY (id);
ALTER TABLE ONLY pm_licenses
ADD CONSTRAINT pm_licenses_pkey PRIMARY KEY (id);
@ -28934,6 +28957,8 @@ CREATE INDEX index_pm_affected_packages_on_pm_advisory_id ON pm_affected_package
CREATE INDEX index_pm_affected_packages_on_purl_type_and_package_name ON pm_affected_packages USING btree (purl_type, package_name);
CREATE UNIQUE INDEX index_pm_epss_on_cve ON pm_epss USING btree (cve);
CREATE INDEX index_pm_package_version_licenses_on_pm_license_id ON pm_package_version_licenses USING btree (pm_license_id);
CREATE INDEX index_pm_package_version_licenses_on_pm_package_version_id ON pm_package_version_licenses USING btree (pm_package_version_id);

View File

@ -480,6 +480,18 @@ because it only deletes untagged images.
Implement cleanup policies to remove unneeded tags, which eventually causes images
to be removed through garbage collection and storage space being recovered.
## Backup with metadata database
When the metadata database is enabled, backups must capture both the object storage
used by the registry, as before, but also the database. Backups of object storage
and the database should be coordinated to capture the state of the registry as close as possible
to each other. To restore the registry, you must apply both backups together.
## Downgrade a registry
To downgrade the registry to a previous version after the migration is complete,
you must restore to a backup of the desired version in order to downgrade.
## Troubleshooting
### `there are pending database migrations` error

View File

@ -1087,6 +1087,20 @@ four standard [pagination arguments](#pagination-arguments):
| <a id="querysnippetstype"></a>`type` | [`TypeEnum`](#typeenum) | Type of snippet. |
| <a id="querysnippetsvisibility"></a>`visibility` | [`VisibilityScopesEnum`](#visibilityscopesenum) | Visibility of the snippet. |
### `Query.standardRoles`
Standard roles available for the instance, available only for self-managed.
DETAILS:
**Introduced** in GitLab 17.3.
**Status**: Experiment.
Returns [`StandardRoleConnection`](#standardroleconnection).
This field returns a [connection](#connections). It accepts the
four standard [pagination arguments](#pagination-arguments):
`before: String`, `after: String`, `first: Int`, and `last: Int`.
### `Query.subscriptionFutureEntries`
Fields related to entries in future subscriptions.
@ -15548,6 +15562,29 @@ The edge type for [`SnippetRepositoryRegistry`](#snippetrepositoryregistry).
| <a id="snippetrepositoryregistryedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
| <a id="snippetrepositoryregistryedgenode"></a>`node` | [`SnippetRepositoryRegistry`](#snippetrepositoryregistry) | The item at the end of the edge. |
#### `StandardRoleConnection`
The connection type for [`StandardRole`](#standardrole).
##### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="standardroleconnectionedges"></a>`edges` | [`[StandardRoleEdge]`](#standardroleedge) | A list of edges. |
| <a id="standardroleconnectionnodes"></a>`nodes` | [`[StandardRole]`](#standardrole) | A list of nodes. |
| <a id="standardroleconnectionpageinfo"></a>`pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. |
#### `StandardRoleEdge`
The edge type for [`StandardRole`](#standardrole).
##### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="standardroleedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
| <a id="standardroleedgenode"></a>`node` | [`StandardRole`](#standardrole) | The item at the end of the edge. |
#### `SubmoduleConnection`
The connection type for [`Submodule`](#submodule).
@ -16599,6 +16636,7 @@ four standard [pagination arguments](#pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="addonuserassignedmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. Available only when the feature flag `mr_approved_filter` is enabled. |
| <a id="addonuserassignedmergerequestsapprovedby"></a>`approvedBy` | [`[String!]`](#string) | Usernames of the approvers. |
| <a id="addonuserassignedmergerequestsauthorusername"></a>`authorUsername` | [`String`](#string) | Username of the author. |
| <a id="addonuserassignedmergerequestscreatedafter"></a>`createdAfter` | [`Time`](#time) | Merge requests created after the timestamp. |
| <a id="addonuserassignedmergerequestscreatedbefore"></a>`createdBefore` | [`Time`](#time) | Merge requests created before the timestamp. |
@ -16612,11 +16650,14 @@ four standard [pagination arguments](#pagination-arguments):
| <a id="addonuserassignedmergerequestslabels"></a>`labels` **{warning-solid}** | [`[String!]`](#string) | **Deprecated** in GitLab 17.1. Use `labelName`. |
| <a id="addonuserassignedmergerequestsmergedafter"></a>`mergedAfter` | [`Time`](#time) | Merge requests merged after the date. |
| <a id="addonuserassignedmergerequestsmergedbefore"></a>`mergedBefore` | [`Time`](#time) | Merge requests merged before the date. |
| <a id="addonuserassignedmergerequestsmergedby"></a>`mergedBy` | [`String`](#string) | Username of the merger. |
| <a id="addonuserassignedmergerequestsmilestonetitle"></a>`milestoneTitle` | [`String`](#string) | Title of the milestone. Incompatible with milestoneWildcardId. |
| <a id="addonuserassignedmergerequestsmilestonewildcardid"></a>`milestoneWildcardId` | [`MilestoneWildcardId`](#milestonewildcardid) | Filter issues by milestone ID wildcard. Incompatible with milestoneTitle. |
| <a id="addonuserassignedmergerequestsmyreactionemoji"></a>`myReactionEmoji` | [`String`](#string) | Filter by your reaction emoji. |
| <a id="addonuserassignedmergerequestsnot"></a>`not` | [`MergeRequestsResolverNegatedParams`](#mergerequestsresolvernegatedparams) | List of negated arguments. Warning: this argument is experimental and a subject to change in future. |
| <a id="addonuserassignedmergerequestsprojectid"></a>`projectId` | [`ProjectID`](#projectid) | The global ID of the project the authored merge requests should be in. Incompatible with projectPath. |
| <a id="addonuserassignedmergerequestsprojectpath"></a>`projectPath` | [`String`](#string) | The full-path of the project the authored merge requests should be in. Incompatible with projectId. |
| <a id="addonuserassignedmergerequestsreleasetag"></a>`releaseTag` | [`String`](#string) | Filter by release tag. |
| <a id="addonuserassignedmergerequestsreviewstate"></a>`reviewState` **{warning-solid}** | [`MergeRequestReviewState`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer state of the merge request. |
| <a id="addonuserassignedmergerequestsreviewstates"></a>`reviewStates` **{warning-solid}** | [`[MergeRequestReviewState!]`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer states of the merge request. |
| <a id="addonuserassignedmergerequestsreviewerusername"></a>`reviewerUsername` | [`String`](#string) | Username of the reviewer. |
@ -16643,6 +16684,7 @@ four standard [pagination arguments](#pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="addonuserauthoredmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. Available only when the feature flag `mr_approved_filter` is enabled. |
| <a id="addonuserauthoredmergerequestsapprovedby"></a>`approvedBy` | [`[String!]`](#string) | Usernames of the approvers. |
| <a id="addonuserauthoredmergerequestsassigneeusername"></a>`assigneeUsername` | [`String`](#string) | Username of the assignee. |
| <a id="addonuserauthoredmergerequestsassigneewildcardid"></a>`assigneeWildcardId` | [`AssigneeWildcardId`](#assigneewildcardid) | Filter by assignee presence. Incompatible with assigneeUsernames and assigneeUsername. |
| <a id="addonuserauthoredmergerequestscreatedafter"></a>`createdAfter` | [`Time`](#time) | Merge requests created after the timestamp. |
@ -16657,11 +16699,14 @@ four standard [pagination arguments](#pagination-arguments):
| <a id="addonuserauthoredmergerequestslabels"></a>`labels` **{warning-solid}** | [`[String!]`](#string) | **Deprecated** in GitLab 17.1. Use `labelName`. |
| <a id="addonuserauthoredmergerequestsmergedafter"></a>`mergedAfter` | [`Time`](#time) | Merge requests merged after the date. |
| <a id="addonuserauthoredmergerequestsmergedbefore"></a>`mergedBefore` | [`Time`](#time) | Merge requests merged before the date. |
| <a id="addonuserauthoredmergerequestsmergedby"></a>`mergedBy` | [`String`](#string) | Username of the merger. |
| <a id="addonuserauthoredmergerequestsmilestonetitle"></a>`milestoneTitle` | [`String`](#string) | Title of the milestone. Incompatible with milestoneWildcardId. |
| <a id="addonuserauthoredmergerequestsmilestonewildcardid"></a>`milestoneWildcardId` | [`MilestoneWildcardId`](#milestonewildcardid) | Filter issues by milestone ID wildcard. Incompatible with milestoneTitle. |
| <a id="addonuserauthoredmergerequestsmyreactionemoji"></a>`myReactionEmoji` | [`String`](#string) | Filter by your reaction emoji. |
| <a id="addonuserauthoredmergerequestsnot"></a>`not` | [`MergeRequestsResolverNegatedParams`](#mergerequestsresolvernegatedparams) | List of negated arguments. Warning: this argument is experimental and a subject to change in future. |
| <a id="addonuserauthoredmergerequestsprojectid"></a>`projectId` | [`ProjectID`](#projectid) | The global ID of the project the authored merge requests should be in. Incompatible with projectPath. |
| <a id="addonuserauthoredmergerequestsprojectpath"></a>`projectPath` | [`String`](#string) | The full-path of the project the authored merge requests should be in. Incompatible with projectId. |
| <a id="addonuserauthoredmergerequestsreleasetag"></a>`releaseTag` | [`String`](#string) | Filter by release tag. |
| <a id="addonuserauthoredmergerequestsreviewstate"></a>`reviewState` **{warning-solid}** | [`MergeRequestReviewState`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer state of the merge request. |
| <a id="addonuserauthoredmergerequestsreviewstates"></a>`reviewStates` **{warning-solid}** | [`[MergeRequestReviewState!]`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer states of the merge request. |
| <a id="addonuserauthoredmergerequestsreviewerusername"></a>`reviewerUsername` | [`String`](#string) | Username of the reviewer. |
@ -16741,6 +16786,7 @@ four standard [pagination arguments](#pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="addonuserreviewrequestedmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. Available only when the feature flag `mr_approved_filter` is enabled. |
| <a id="addonuserreviewrequestedmergerequestsapprovedby"></a>`approvedBy` | [`[String!]`](#string) | Usernames of the approvers. |
| <a id="addonuserreviewrequestedmergerequestsassigneeusername"></a>`assigneeUsername` | [`String`](#string) | Username of the assignee. |
| <a id="addonuserreviewrequestedmergerequestsassigneewildcardid"></a>`assigneeWildcardId` | [`AssigneeWildcardId`](#assigneewildcardid) | Filter by assignee presence. Incompatible with assigneeUsernames and assigneeUsername. |
| <a id="addonuserreviewrequestedmergerequestsauthorusername"></a>`authorUsername` | [`String`](#string) | Username of the author. |
@ -16756,11 +16802,14 @@ four standard [pagination arguments](#pagination-arguments):
| <a id="addonuserreviewrequestedmergerequestslabels"></a>`labels` **{warning-solid}** | [`[String!]`](#string) | **Deprecated** in GitLab 17.1. Use `labelName`. |
| <a id="addonuserreviewrequestedmergerequestsmergedafter"></a>`mergedAfter` | [`Time`](#time) | Merge requests merged after the date. |
| <a id="addonuserreviewrequestedmergerequestsmergedbefore"></a>`mergedBefore` | [`Time`](#time) | Merge requests merged before the date. |
| <a id="addonuserreviewrequestedmergerequestsmergedby"></a>`mergedBy` | [`String`](#string) | Username of the merger. |
| <a id="addonuserreviewrequestedmergerequestsmilestonetitle"></a>`milestoneTitle` | [`String`](#string) | Title of the milestone. Incompatible with milestoneWildcardId. |
| <a id="addonuserreviewrequestedmergerequestsmilestonewildcardid"></a>`milestoneWildcardId` | [`MilestoneWildcardId`](#milestonewildcardid) | Filter issues by milestone ID wildcard. Incompatible with milestoneTitle. |
| <a id="addonuserreviewrequestedmergerequestsmyreactionemoji"></a>`myReactionEmoji` | [`String`](#string) | Filter by your reaction emoji. |
| <a id="addonuserreviewrequestedmergerequestsnot"></a>`not` | [`MergeRequestsResolverNegatedParams`](#mergerequestsresolvernegatedparams) | List of negated arguments. Warning: this argument is experimental and a subject to change in future. |
| <a id="addonuserreviewrequestedmergerequestsprojectid"></a>`projectId` | [`ProjectID`](#projectid) | The global ID of the project the authored merge requests should be in. Incompatible with projectPath. |
| <a id="addonuserreviewrequestedmergerequestsprojectpath"></a>`projectPath` | [`String`](#string) | The full-path of the project the authored merge requests should be in. Incompatible with projectId. |
| <a id="addonuserreviewrequestedmergerequestsreleasetag"></a>`releaseTag` | [`String`](#string) | Filter by release tag. |
| <a id="addonuserreviewrequestedmergerequestsreviewstate"></a>`reviewState` **{warning-solid}** | [`MergeRequestReviewState`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer state of the merge request. |
| <a id="addonuserreviewrequestedmergerequestsreviewstates"></a>`reviewStates` **{warning-solid}** | [`[MergeRequestReviewState!]`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer states of the merge request. |
| <a id="addonuserreviewrequestedmergerequestssort"></a>`sort` | [`MergeRequestSort`](#mergerequestsort) | Sort merge requests by the criteria. |
@ -17437,6 +17486,7 @@ four standard [pagination arguments](#pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="autocompleteduserassignedmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. Available only when the feature flag `mr_approved_filter` is enabled. |
| <a id="autocompleteduserassignedmergerequestsapprovedby"></a>`approvedBy` | [`[String!]`](#string) | Usernames of the approvers. |
| <a id="autocompleteduserassignedmergerequestsauthorusername"></a>`authorUsername` | [`String`](#string) | Username of the author. |
| <a id="autocompleteduserassignedmergerequestscreatedafter"></a>`createdAfter` | [`Time`](#time) | Merge requests created after the timestamp. |
| <a id="autocompleteduserassignedmergerequestscreatedbefore"></a>`createdBefore` | [`Time`](#time) | Merge requests created before the timestamp. |
@ -17450,11 +17500,14 @@ four standard [pagination arguments](#pagination-arguments):
| <a id="autocompleteduserassignedmergerequestslabels"></a>`labels` **{warning-solid}** | [`[String!]`](#string) | **Deprecated** in GitLab 17.1. Use `labelName`. |
| <a id="autocompleteduserassignedmergerequestsmergedafter"></a>`mergedAfter` | [`Time`](#time) | Merge requests merged after the date. |
| <a id="autocompleteduserassignedmergerequestsmergedbefore"></a>`mergedBefore` | [`Time`](#time) | Merge requests merged before the date. |
| <a id="autocompleteduserassignedmergerequestsmergedby"></a>`mergedBy` | [`String`](#string) | Username of the merger. |
| <a id="autocompleteduserassignedmergerequestsmilestonetitle"></a>`milestoneTitle` | [`String`](#string) | Title of the milestone. Incompatible with milestoneWildcardId. |
| <a id="autocompleteduserassignedmergerequestsmilestonewildcardid"></a>`milestoneWildcardId` | [`MilestoneWildcardId`](#milestonewildcardid) | Filter issues by milestone ID wildcard. Incompatible with milestoneTitle. |
| <a id="autocompleteduserassignedmergerequestsmyreactionemoji"></a>`myReactionEmoji` | [`String`](#string) | Filter by your reaction emoji. |
| <a id="autocompleteduserassignedmergerequestsnot"></a>`not` | [`MergeRequestsResolverNegatedParams`](#mergerequestsresolvernegatedparams) | List of negated arguments. Warning: this argument is experimental and a subject to change in future. |
| <a id="autocompleteduserassignedmergerequestsprojectid"></a>`projectId` | [`ProjectID`](#projectid) | The global ID of the project the authored merge requests should be in. Incompatible with projectPath. |
| <a id="autocompleteduserassignedmergerequestsprojectpath"></a>`projectPath` | [`String`](#string) | The full-path of the project the authored merge requests should be in. Incompatible with projectId. |
| <a id="autocompleteduserassignedmergerequestsreleasetag"></a>`releaseTag` | [`String`](#string) | Filter by release tag. |
| <a id="autocompleteduserassignedmergerequestsreviewstate"></a>`reviewState` **{warning-solid}** | [`MergeRequestReviewState`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer state of the merge request. |
| <a id="autocompleteduserassignedmergerequestsreviewstates"></a>`reviewStates` **{warning-solid}** | [`[MergeRequestReviewState!]`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer states of the merge request. |
| <a id="autocompleteduserassignedmergerequestsreviewerusername"></a>`reviewerUsername` | [`String`](#string) | Username of the reviewer. |
@ -17481,6 +17534,7 @@ four standard [pagination arguments](#pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="autocompleteduserauthoredmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. Available only when the feature flag `mr_approved_filter` is enabled. |
| <a id="autocompleteduserauthoredmergerequestsapprovedby"></a>`approvedBy` | [`[String!]`](#string) | Usernames of the approvers. |
| <a id="autocompleteduserauthoredmergerequestsassigneeusername"></a>`assigneeUsername` | [`String`](#string) | Username of the assignee. |
| <a id="autocompleteduserauthoredmergerequestsassigneewildcardid"></a>`assigneeWildcardId` | [`AssigneeWildcardId`](#assigneewildcardid) | Filter by assignee presence. Incompatible with assigneeUsernames and assigneeUsername. |
| <a id="autocompleteduserauthoredmergerequestscreatedafter"></a>`createdAfter` | [`Time`](#time) | Merge requests created after the timestamp. |
@ -17495,11 +17549,14 @@ four standard [pagination arguments](#pagination-arguments):
| <a id="autocompleteduserauthoredmergerequestslabels"></a>`labels` **{warning-solid}** | [`[String!]`](#string) | **Deprecated** in GitLab 17.1. Use `labelName`. |
| <a id="autocompleteduserauthoredmergerequestsmergedafter"></a>`mergedAfter` | [`Time`](#time) | Merge requests merged after the date. |
| <a id="autocompleteduserauthoredmergerequestsmergedbefore"></a>`mergedBefore` | [`Time`](#time) | Merge requests merged before the date. |
| <a id="autocompleteduserauthoredmergerequestsmergedby"></a>`mergedBy` | [`String`](#string) | Username of the merger. |
| <a id="autocompleteduserauthoredmergerequestsmilestonetitle"></a>`milestoneTitle` | [`String`](#string) | Title of the milestone. Incompatible with milestoneWildcardId. |
| <a id="autocompleteduserauthoredmergerequestsmilestonewildcardid"></a>`milestoneWildcardId` | [`MilestoneWildcardId`](#milestonewildcardid) | Filter issues by milestone ID wildcard. Incompatible with milestoneTitle. |
| <a id="autocompleteduserauthoredmergerequestsmyreactionemoji"></a>`myReactionEmoji` | [`String`](#string) | Filter by your reaction emoji. |
| <a id="autocompleteduserauthoredmergerequestsnot"></a>`not` | [`MergeRequestsResolverNegatedParams`](#mergerequestsresolvernegatedparams) | List of negated arguments. Warning: this argument is experimental and a subject to change in future. |
| <a id="autocompleteduserauthoredmergerequestsprojectid"></a>`projectId` | [`ProjectID`](#projectid) | The global ID of the project the authored merge requests should be in. Incompatible with projectPath. |
| <a id="autocompleteduserauthoredmergerequestsprojectpath"></a>`projectPath` | [`String`](#string) | The full-path of the project the authored merge requests should be in. Incompatible with projectId. |
| <a id="autocompleteduserauthoredmergerequestsreleasetag"></a>`releaseTag` | [`String`](#string) | Filter by release tag. |
| <a id="autocompleteduserauthoredmergerequestsreviewstate"></a>`reviewState` **{warning-solid}** | [`MergeRequestReviewState`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer state of the merge request. |
| <a id="autocompleteduserauthoredmergerequestsreviewstates"></a>`reviewStates` **{warning-solid}** | [`[MergeRequestReviewState!]`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer states of the merge request. |
| <a id="autocompleteduserauthoredmergerequestsreviewerusername"></a>`reviewerUsername` | [`String`](#string) | Username of the reviewer. |
@ -17591,6 +17648,7 @@ four standard [pagination arguments](#pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="autocompleteduserreviewrequestedmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. Available only when the feature flag `mr_approved_filter` is enabled. |
| <a id="autocompleteduserreviewrequestedmergerequestsapprovedby"></a>`approvedBy` | [`[String!]`](#string) | Usernames of the approvers. |
| <a id="autocompleteduserreviewrequestedmergerequestsassigneeusername"></a>`assigneeUsername` | [`String`](#string) | Username of the assignee. |
| <a id="autocompleteduserreviewrequestedmergerequestsassigneewildcardid"></a>`assigneeWildcardId` | [`AssigneeWildcardId`](#assigneewildcardid) | Filter by assignee presence. Incompatible with assigneeUsernames and assigneeUsername. |
| <a id="autocompleteduserreviewrequestedmergerequestsauthorusername"></a>`authorUsername` | [`String`](#string) | Username of the author. |
@ -17606,11 +17664,14 @@ four standard [pagination arguments](#pagination-arguments):
| <a id="autocompleteduserreviewrequestedmergerequestslabels"></a>`labels` **{warning-solid}** | [`[String!]`](#string) | **Deprecated** in GitLab 17.1. Use `labelName`. |
| <a id="autocompleteduserreviewrequestedmergerequestsmergedafter"></a>`mergedAfter` | [`Time`](#time) | Merge requests merged after the date. |
| <a id="autocompleteduserreviewrequestedmergerequestsmergedbefore"></a>`mergedBefore` | [`Time`](#time) | Merge requests merged before the date. |
| <a id="autocompleteduserreviewrequestedmergerequestsmergedby"></a>`mergedBy` | [`String`](#string) | Username of the merger. |
| <a id="autocompleteduserreviewrequestedmergerequestsmilestonetitle"></a>`milestoneTitle` | [`String`](#string) | Title of the milestone. Incompatible with milestoneWildcardId. |
| <a id="autocompleteduserreviewrequestedmergerequestsmilestonewildcardid"></a>`milestoneWildcardId` | [`MilestoneWildcardId`](#milestonewildcardid) | Filter issues by milestone ID wildcard. Incompatible with milestoneTitle. |
| <a id="autocompleteduserreviewrequestedmergerequestsmyreactionemoji"></a>`myReactionEmoji` | [`String`](#string) | Filter by your reaction emoji. |
| <a id="autocompleteduserreviewrequestedmergerequestsnot"></a>`not` | [`MergeRequestsResolverNegatedParams`](#mergerequestsresolvernegatedparams) | List of negated arguments. Warning: this argument is experimental and a subject to change in future. |
| <a id="autocompleteduserreviewrequestedmergerequestsprojectid"></a>`projectId` | [`ProjectID`](#projectid) | The global ID of the project the authored merge requests should be in. Incompatible with projectPath. |
| <a id="autocompleteduserreviewrequestedmergerequestsprojectpath"></a>`projectPath` | [`String`](#string) | The full-path of the project the authored merge requests should be in. Incompatible with projectId. |
| <a id="autocompleteduserreviewrequestedmergerequestsreleasetag"></a>`releaseTag` | [`String`](#string) | Filter by release tag. |
| <a id="autocompleteduserreviewrequestedmergerequestsreviewstate"></a>`reviewState` **{warning-solid}** | [`MergeRequestReviewState`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer state of the merge request. |
| <a id="autocompleteduserreviewrequestedmergerequestsreviewstates"></a>`reviewStates` **{warning-solid}** | [`[MergeRequestReviewState!]`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer states of the merge request. |
| <a id="autocompleteduserreviewrequestedmergerequestssort"></a>`sort` | [`MergeRequestSort`](#mergerequestsort) | Sort merge requests by the criteria. |
@ -19713,6 +19774,7 @@ four standard [pagination arguments](#pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="currentuserassignedmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. Available only when the feature flag `mr_approved_filter` is enabled. |
| <a id="currentuserassignedmergerequestsapprovedby"></a>`approvedBy` | [`[String!]`](#string) | Usernames of the approvers. |
| <a id="currentuserassignedmergerequestsauthorusername"></a>`authorUsername` | [`String`](#string) | Username of the author. |
| <a id="currentuserassignedmergerequestscreatedafter"></a>`createdAfter` | [`Time`](#time) | Merge requests created after the timestamp. |
| <a id="currentuserassignedmergerequestscreatedbefore"></a>`createdBefore` | [`Time`](#time) | Merge requests created before the timestamp. |
@ -19726,11 +19788,14 @@ four standard [pagination arguments](#pagination-arguments):
| <a id="currentuserassignedmergerequestslabels"></a>`labels` **{warning-solid}** | [`[String!]`](#string) | **Deprecated** in GitLab 17.1. Use `labelName`. |
| <a id="currentuserassignedmergerequestsmergedafter"></a>`mergedAfter` | [`Time`](#time) | Merge requests merged after the date. |
| <a id="currentuserassignedmergerequestsmergedbefore"></a>`mergedBefore` | [`Time`](#time) | Merge requests merged before the date. |
| <a id="currentuserassignedmergerequestsmergedby"></a>`mergedBy` | [`String`](#string) | Username of the merger. |
| <a id="currentuserassignedmergerequestsmilestonetitle"></a>`milestoneTitle` | [`String`](#string) | Title of the milestone. Incompatible with milestoneWildcardId. |
| <a id="currentuserassignedmergerequestsmilestonewildcardid"></a>`milestoneWildcardId` | [`MilestoneWildcardId`](#milestonewildcardid) | Filter issues by milestone ID wildcard. Incompatible with milestoneTitle. |
| <a id="currentuserassignedmergerequestsmyreactionemoji"></a>`myReactionEmoji` | [`String`](#string) | Filter by your reaction emoji. |
| <a id="currentuserassignedmergerequestsnot"></a>`not` | [`MergeRequestsResolverNegatedParams`](#mergerequestsresolvernegatedparams) | List of negated arguments. Warning: this argument is experimental and a subject to change in future. |
| <a id="currentuserassignedmergerequestsprojectid"></a>`projectId` | [`ProjectID`](#projectid) | The global ID of the project the authored merge requests should be in. Incompatible with projectPath. |
| <a id="currentuserassignedmergerequestsprojectpath"></a>`projectPath` | [`String`](#string) | The full-path of the project the authored merge requests should be in. Incompatible with projectId. |
| <a id="currentuserassignedmergerequestsreleasetag"></a>`releaseTag` | [`String`](#string) | Filter by release tag. |
| <a id="currentuserassignedmergerequestsreviewstate"></a>`reviewState` **{warning-solid}** | [`MergeRequestReviewState`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer state of the merge request. |
| <a id="currentuserassignedmergerequestsreviewstates"></a>`reviewStates` **{warning-solid}** | [`[MergeRequestReviewState!]`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer states of the merge request. |
| <a id="currentuserassignedmergerequestsreviewerusername"></a>`reviewerUsername` | [`String`](#string) | Username of the reviewer. |
@ -19757,6 +19822,7 @@ four standard [pagination arguments](#pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="currentuserauthoredmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. Available only when the feature flag `mr_approved_filter` is enabled. |
| <a id="currentuserauthoredmergerequestsapprovedby"></a>`approvedBy` | [`[String!]`](#string) | Usernames of the approvers. |
| <a id="currentuserauthoredmergerequestsassigneeusername"></a>`assigneeUsername` | [`String`](#string) | Username of the assignee. |
| <a id="currentuserauthoredmergerequestsassigneewildcardid"></a>`assigneeWildcardId` | [`AssigneeWildcardId`](#assigneewildcardid) | Filter by assignee presence. Incompatible with assigneeUsernames and assigneeUsername. |
| <a id="currentuserauthoredmergerequestscreatedafter"></a>`createdAfter` | [`Time`](#time) | Merge requests created after the timestamp. |
@ -19771,11 +19837,14 @@ four standard [pagination arguments](#pagination-arguments):
| <a id="currentuserauthoredmergerequestslabels"></a>`labels` **{warning-solid}** | [`[String!]`](#string) | **Deprecated** in GitLab 17.1. Use `labelName`. |
| <a id="currentuserauthoredmergerequestsmergedafter"></a>`mergedAfter` | [`Time`](#time) | Merge requests merged after the date. |
| <a id="currentuserauthoredmergerequestsmergedbefore"></a>`mergedBefore` | [`Time`](#time) | Merge requests merged before the date. |
| <a id="currentuserauthoredmergerequestsmergedby"></a>`mergedBy` | [`String`](#string) | Username of the merger. |
| <a id="currentuserauthoredmergerequestsmilestonetitle"></a>`milestoneTitle` | [`String`](#string) | Title of the milestone. Incompatible with milestoneWildcardId. |
| <a id="currentuserauthoredmergerequestsmilestonewildcardid"></a>`milestoneWildcardId` | [`MilestoneWildcardId`](#milestonewildcardid) | Filter issues by milestone ID wildcard. Incompatible with milestoneTitle. |
| <a id="currentuserauthoredmergerequestsmyreactionemoji"></a>`myReactionEmoji` | [`String`](#string) | Filter by your reaction emoji. |
| <a id="currentuserauthoredmergerequestsnot"></a>`not` | [`MergeRequestsResolverNegatedParams`](#mergerequestsresolvernegatedparams) | List of negated arguments. Warning: this argument is experimental and a subject to change in future. |
| <a id="currentuserauthoredmergerequestsprojectid"></a>`projectId` | [`ProjectID`](#projectid) | The global ID of the project the authored merge requests should be in. Incompatible with projectPath. |
| <a id="currentuserauthoredmergerequestsprojectpath"></a>`projectPath` | [`String`](#string) | The full-path of the project the authored merge requests should be in. Incompatible with projectId. |
| <a id="currentuserauthoredmergerequestsreleasetag"></a>`releaseTag` | [`String`](#string) | Filter by release tag. |
| <a id="currentuserauthoredmergerequestsreviewstate"></a>`reviewState` **{warning-solid}** | [`MergeRequestReviewState`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer state of the merge request. |
| <a id="currentuserauthoredmergerequestsreviewstates"></a>`reviewStates` **{warning-solid}** | [`[MergeRequestReviewState!]`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer states of the merge request. |
| <a id="currentuserauthoredmergerequestsreviewerusername"></a>`reviewerUsername` | [`String`](#string) | Username of the reviewer. |
@ -19855,6 +19924,7 @@ four standard [pagination arguments](#pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="currentuserreviewrequestedmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. Available only when the feature flag `mr_approved_filter` is enabled. |
| <a id="currentuserreviewrequestedmergerequestsapprovedby"></a>`approvedBy` | [`[String!]`](#string) | Usernames of the approvers. |
| <a id="currentuserreviewrequestedmergerequestsassigneeusername"></a>`assigneeUsername` | [`String`](#string) | Username of the assignee. |
| <a id="currentuserreviewrequestedmergerequestsassigneewildcardid"></a>`assigneeWildcardId` | [`AssigneeWildcardId`](#assigneewildcardid) | Filter by assignee presence. Incompatible with assigneeUsernames and assigneeUsername. |
| <a id="currentuserreviewrequestedmergerequestsauthorusername"></a>`authorUsername` | [`String`](#string) | Username of the author. |
@ -19870,11 +19940,14 @@ four standard [pagination arguments](#pagination-arguments):
| <a id="currentuserreviewrequestedmergerequestslabels"></a>`labels` **{warning-solid}** | [`[String!]`](#string) | **Deprecated** in GitLab 17.1. Use `labelName`. |
| <a id="currentuserreviewrequestedmergerequestsmergedafter"></a>`mergedAfter` | [`Time`](#time) | Merge requests merged after the date. |
| <a id="currentuserreviewrequestedmergerequestsmergedbefore"></a>`mergedBefore` | [`Time`](#time) | Merge requests merged before the date. |
| <a id="currentuserreviewrequestedmergerequestsmergedby"></a>`mergedBy` | [`String`](#string) | Username of the merger. |
| <a id="currentuserreviewrequestedmergerequestsmilestonetitle"></a>`milestoneTitle` | [`String`](#string) | Title of the milestone. Incompatible with milestoneWildcardId. |
| <a id="currentuserreviewrequestedmergerequestsmilestonewildcardid"></a>`milestoneWildcardId` | [`MilestoneWildcardId`](#milestonewildcardid) | Filter issues by milestone ID wildcard. Incompatible with milestoneTitle. |
| <a id="currentuserreviewrequestedmergerequestsmyreactionemoji"></a>`myReactionEmoji` | [`String`](#string) | Filter by your reaction emoji. |
| <a id="currentuserreviewrequestedmergerequestsnot"></a>`not` | [`MergeRequestsResolverNegatedParams`](#mergerequestsresolvernegatedparams) | List of negated arguments. Warning: this argument is experimental and a subject to change in future. |
| <a id="currentuserreviewrequestedmergerequestsprojectid"></a>`projectId` | [`ProjectID`](#projectid) | The global ID of the project the authored merge requests should be in. Incompatible with projectPath. |
| <a id="currentuserreviewrequestedmergerequestsprojectpath"></a>`projectPath` | [`String`](#string) | The full-path of the project the authored merge requests should be in. Incompatible with projectId. |
| <a id="currentuserreviewrequestedmergerequestsreleasetag"></a>`releaseTag` | [`String`](#string) | Filter by release tag. |
| <a id="currentuserreviewrequestedmergerequestsreviewstate"></a>`reviewState` **{warning-solid}** | [`MergeRequestReviewState`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer state of the merge request. |
| <a id="currentuserreviewrequestedmergerequestsreviewstates"></a>`reviewStates` **{warning-solid}** | [`[MergeRequestReviewState!]`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer states of the merge request. |
| <a id="currentuserreviewrequestedmergerequestssort"></a>`sort` | [`MergeRequestSort`](#mergerequestsort) | Sort merge requests by the criteria. |
@ -23140,6 +23213,7 @@ four standard [pagination arguments](#pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="groupmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. Available only when the feature flag `mr_approved_filter` is enabled. |
| <a id="groupmergerequestsapprovedby"></a>`approvedBy` | [`[String!]`](#string) | Usernames of the approvers. |
| <a id="groupmergerequestsassigneeusername"></a>`assigneeUsername` | [`String`](#string) | Username of the assignee. |
| <a id="groupmergerequestsassigneewildcardid"></a>`assigneeWildcardId` | [`AssigneeWildcardId`](#assigneewildcardid) | Filter by assignee presence. Incompatible with assigneeUsernames and assigneeUsername. |
| <a id="groupmergerequestsauthorusername"></a>`authorUsername` | [`String`](#string) | Username of the author. |
@ -23156,9 +23230,12 @@ four standard [pagination arguments](#pagination-arguments):
| <a id="groupmergerequestslabels"></a>`labels` **{warning-solid}** | [`[String!]`](#string) | **Deprecated** in GitLab 17.1. Use `labelName`. |
| <a id="groupmergerequestsmergedafter"></a>`mergedAfter` | [`Time`](#time) | Merge requests merged after the date. |
| <a id="groupmergerequestsmergedbefore"></a>`mergedBefore` | [`Time`](#time) | Merge requests merged before the date. |
| <a id="groupmergerequestsmergedby"></a>`mergedBy` | [`String`](#string) | Username of the merger. |
| <a id="groupmergerequestsmilestonetitle"></a>`milestoneTitle` | [`String`](#string) | Title of the milestone. Incompatible with milestoneWildcardId. |
| <a id="groupmergerequestsmilestonewildcardid"></a>`milestoneWildcardId` | [`MilestoneWildcardId`](#milestonewildcardid) | Filter issues by milestone ID wildcard. Incompatible with milestoneTitle. |
| <a id="groupmergerequestsmyreactionemoji"></a>`myReactionEmoji` | [`String`](#string) | Filter by your reaction emoji. |
| <a id="groupmergerequestsnot"></a>`not` | [`MergeRequestsResolverNegatedParams`](#mergerequestsresolvernegatedparams) | List of negated arguments. Warning: this argument is experimental and a subject to change in future. |
| <a id="groupmergerequestsreleasetag"></a>`releaseTag` | [`String`](#string) | Filter by release tag. |
| <a id="groupmergerequestsreviewstate"></a>`reviewState` **{warning-solid}** | [`MergeRequestReviewState`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer state of the merge request. |
| <a id="groupmergerequestsreviewstates"></a>`reviewStates` **{warning-solid}** | [`[MergeRequestReviewState!]`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer states of the merge request. |
| <a id="groupmergerequestssort"></a>`sort` | [`MergeRequestSort`](#mergerequestsort) | Sort merge requests by the criteria. |
@ -25188,6 +25265,7 @@ four standard [pagination arguments](#pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mergerequestassigneeassignedmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. Available only when the feature flag `mr_approved_filter` is enabled. |
| <a id="mergerequestassigneeassignedmergerequestsapprovedby"></a>`approvedBy` | [`[String!]`](#string) | Usernames of the approvers. |
| <a id="mergerequestassigneeassignedmergerequestsauthorusername"></a>`authorUsername` | [`String`](#string) | Username of the author. |
| <a id="mergerequestassigneeassignedmergerequestscreatedafter"></a>`createdAfter` | [`Time`](#time) | Merge requests created after the timestamp. |
| <a id="mergerequestassigneeassignedmergerequestscreatedbefore"></a>`createdBefore` | [`Time`](#time) | Merge requests created before the timestamp. |
@ -25201,11 +25279,14 @@ four standard [pagination arguments](#pagination-arguments):
| <a id="mergerequestassigneeassignedmergerequestslabels"></a>`labels` **{warning-solid}** | [`[String!]`](#string) | **Deprecated** in GitLab 17.1. Use `labelName`. |
| <a id="mergerequestassigneeassignedmergerequestsmergedafter"></a>`mergedAfter` | [`Time`](#time) | Merge requests merged after the date. |
| <a id="mergerequestassigneeassignedmergerequestsmergedbefore"></a>`mergedBefore` | [`Time`](#time) | Merge requests merged before the date. |
| <a id="mergerequestassigneeassignedmergerequestsmergedby"></a>`mergedBy` | [`String`](#string) | Username of the merger. |
| <a id="mergerequestassigneeassignedmergerequestsmilestonetitle"></a>`milestoneTitle` | [`String`](#string) | Title of the milestone. Incompatible with milestoneWildcardId. |
| <a id="mergerequestassigneeassignedmergerequestsmilestonewildcardid"></a>`milestoneWildcardId` | [`MilestoneWildcardId`](#milestonewildcardid) | Filter issues by milestone ID wildcard. Incompatible with milestoneTitle. |
| <a id="mergerequestassigneeassignedmergerequestsmyreactionemoji"></a>`myReactionEmoji` | [`String`](#string) | Filter by your reaction emoji. |
| <a id="mergerequestassigneeassignedmergerequestsnot"></a>`not` | [`MergeRequestsResolverNegatedParams`](#mergerequestsresolvernegatedparams) | List of negated arguments. Warning: this argument is experimental and a subject to change in future. |
| <a id="mergerequestassigneeassignedmergerequestsprojectid"></a>`projectId` | [`ProjectID`](#projectid) | The global ID of the project the authored merge requests should be in. Incompatible with projectPath. |
| <a id="mergerequestassigneeassignedmergerequestsprojectpath"></a>`projectPath` | [`String`](#string) | The full-path of the project the authored merge requests should be in. Incompatible with projectId. |
| <a id="mergerequestassigneeassignedmergerequestsreleasetag"></a>`releaseTag` | [`String`](#string) | Filter by release tag. |
| <a id="mergerequestassigneeassignedmergerequestsreviewstate"></a>`reviewState` **{warning-solid}** | [`MergeRequestReviewState`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer state of the merge request. |
| <a id="mergerequestassigneeassignedmergerequestsreviewstates"></a>`reviewStates` **{warning-solid}** | [`[MergeRequestReviewState!]`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer states of the merge request. |
| <a id="mergerequestassigneeassignedmergerequestsreviewerusername"></a>`reviewerUsername` | [`String`](#string) | Username of the reviewer. |
@ -25232,6 +25313,7 @@ four standard [pagination arguments](#pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mergerequestassigneeauthoredmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. Available only when the feature flag `mr_approved_filter` is enabled. |
| <a id="mergerequestassigneeauthoredmergerequestsapprovedby"></a>`approvedBy` | [`[String!]`](#string) | Usernames of the approvers. |
| <a id="mergerequestassigneeauthoredmergerequestsassigneeusername"></a>`assigneeUsername` | [`String`](#string) | Username of the assignee. |
| <a id="mergerequestassigneeauthoredmergerequestsassigneewildcardid"></a>`assigneeWildcardId` | [`AssigneeWildcardId`](#assigneewildcardid) | Filter by assignee presence. Incompatible with assigneeUsernames and assigneeUsername. |
| <a id="mergerequestassigneeauthoredmergerequestscreatedafter"></a>`createdAfter` | [`Time`](#time) | Merge requests created after the timestamp. |
@ -25246,11 +25328,14 @@ four standard [pagination arguments](#pagination-arguments):
| <a id="mergerequestassigneeauthoredmergerequestslabels"></a>`labels` **{warning-solid}** | [`[String!]`](#string) | **Deprecated** in GitLab 17.1. Use `labelName`. |
| <a id="mergerequestassigneeauthoredmergerequestsmergedafter"></a>`mergedAfter` | [`Time`](#time) | Merge requests merged after the date. |
| <a id="mergerequestassigneeauthoredmergerequestsmergedbefore"></a>`mergedBefore` | [`Time`](#time) | Merge requests merged before the date. |
| <a id="mergerequestassigneeauthoredmergerequestsmergedby"></a>`mergedBy` | [`String`](#string) | Username of the merger. |
| <a id="mergerequestassigneeauthoredmergerequestsmilestonetitle"></a>`milestoneTitle` | [`String`](#string) | Title of the milestone. Incompatible with milestoneWildcardId. |
| <a id="mergerequestassigneeauthoredmergerequestsmilestonewildcardid"></a>`milestoneWildcardId` | [`MilestoneWildcardId`](#milestonewildcardid) | Filter issues by milestone ID wildcard. Incompatible with milestoneTitle. |
| <a id="mergerequestassigneeauthoredmergerequestsmyreactionemoji"></a>`myReactionEmoji` | [`String`](#string) | Filter by your reaction emoji. |
| <a id="mergerequestassigneeauthoredmergerequestsnot"></a>`not` | [`MergeRequestsResolverNegatedParams`](#mergerequestsresolvernegatedparams) | List of negated arguments. Warning: this argument is experimental and a subject to change in future. |
| <a id="mergerequestassigneeauthoredmergerequestsprojectid"></a>`projectId` | [`ProjectID`](#projectid) | The global ID of the project the authored merge requests should be in. Incompatible with projectPath. |
| <a id="mergerequestassigneeauthoredmergerequestsprojectpath"></a>`projectPath` | [`String`](#string) | The full-path of the project the authored merge requests should be in. Incompatible with projectId. |
| <a id="mergerequestassigneeauthoredmergerequestsreleasetag"></a>`releaseTag` | [`String`](#string) | Filter by release tag. |
| <a id="mergerequestassigneeauthoredmergerequestsreviewstate"></a>`reviewState` **{warning-solid}** | [`MergeRequestReviewState`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer state of the merge request. |
| <a id="mergerequestassigneeauthoredmergerequestsreviewstates"></a>`reviewStates` **{warning-solid}** | [`[MergeRequestReviewState!]`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer states of the merge request. |
| <a id="mergerequestassigneeauthoredmergerequestsreviewerusername"></a>`reviewerUsername` | [`String`](#string) | Username of the reviewer. |
@ -25330,6 +25415,7 @@ four standard [pagination arguments](#pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mergerequestassigneereviewrequestedmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. Available only when the feature flag `mr_approved_filter` is enabled. |
| <a id="mergerequestassigneereviewrequestedmergerequestsapprovedby"></a>`approvedBy` | [`[String!]`](#string) | Usernames of the approvers. |
| <a id="mergerequestassigneereviewrequestedmergerequestsassigneeusername"></a>`assigneeUsername` | [`String`](#string) | Username of the assignee. |
| <a id="mergerequestassigneereviewrequestedmergerequestsassigneewildcardid"></a>`assigneeWildcardId` | [`AssigneeWildcardId`](#assigneewildcardid) | Filter by assignee presence. Incompatible with assigneeUsernames and assigneeUsername. |
| <a id="mergerequestassigneereviewrequestedmergerequestsauthorusername"></a>`authorUsername` | [`String`](#string) | Username of the author. |
@ -25345,11 +25431,14 @@ four standard [pagination arguments](#pagination-arguments):
| <a id="mergerequestassigneereviewrequestedmergerequestslabels"></a>`labels` **{warning-solid}** | [`[String!]`](#string) | **Deprecated** in GitLab 17.1. Use `labelName`. |
| <a id="mergerequestassigneereviewrequestedmergerequestsmergedafter"></a>`mergedAfter` | [`Time`](#time) | Merge requests merged after the date. |
| <a id="mergerequestassigneereviewrequestedmergerequestsmergedbefore"></a>`mergedBefore` | [`Time`](#time) | Merge requests merged before the date. |
| <a id="mergerequestassigneereviewrequestedmergerequestsmergedby"></a>`mergedBy` | [`String`](#string) | Username of the merger. |
| <a id="mergerequestassigneereviewrequestedmergerequestsmilestonetitle"></a>`milestoneTitle` | [`String`](#string) | Title of the milestone. Incompatible with milestoneWildcardId. |
| <a id="mergerequestassigneereviewrequestedmergerequestsmilestonewildcardid"></a>`milestoneWildcardId` | [`MilestoneWildcardId`](#milestonewildcardid) | Filter issues by milestone ID wildcard. Incompatible with milestoneTitle. |
| <a id="mergerequestassigneereviewrequestedmergerequestsmyreactionemoji"></a>`myReactionEmoji` | [`String`](#string) | Filter by your reaction emoji. |
| <a id="mergerequestassigneereviewrequestedmergerequestsnot"></a>`not` | [`MergeRequestsResolverNegatedParams`](#mergerequestsresolvernegatedparams) | List of negated arguments. Warning: this argument is experimental and a subject to change in future. |
| <a id="mergerequestassigneereviewrequestedmergerequestsprojectid"></a>`projectId` | [`ProjectID`](#projectid) | The global ID of the project the authored merge requests should be in. Incompatible with projectPath. |
| <a id="mergerequestassigneereviewrequestedmergerequestsprojectpath"></a>`projectPath` | [`String`](#string) | The full-path of the project the authored merge requests should be in. Incompatible with projectId. |
| <a id="mergerequestassigneereviewrequestedmergerequestsreleasetag"></a>`releaseTag` | [`String`](#string) | Filter by release tag. |
| <a id="mergerequestassigneereviewrequestedmergerequestsreviewstate"></a>`reviewState` **{warning-solid}** | [`MergeRequestReviewState`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer state of the merge request. |
| <a id="mergerequestassigneereviewrequestedmergerequestsreviewstates"></a>`reviewStates` **{warning-solid}** | [`[MergeRequestReviewState!]`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer states of the merge request. |
| <a id="mergerequestassigneereviewrequestedmergerequestssort"></a>`sort` | [`MergeRequestSort`](#mergerequestsort) | Sort merge requests by the criteria. |
@ -25555,6 +25644,7 @@ four standard [pagination arguments](#pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mergerequestauthorassignedmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. Available only when the feature flag `mr_approved_filter` is enabled. |
| <a id="mergerequestauthorassignedmergerequestsapprovedby"></a>`approvedBy` | [`[String!]`](#string) | Usernames of the approvers. |
| <a id="mergerequestauthorassignedmergerequestsauthorusername"></a>`authorUsername` | [`String`](#string) | Username of the author. |
| <a id="mergerequestauthorassignedmergerequestscreatedafter"></a>`createdAfter` | [`Time`](#time) | Merge requests created after the timestamp. |
| <a id="mergerequestauthorassignedmergerequestscreatedbefore"></a>`createdBefore` | [`Time`](#time) | Merge requests created before the timestamp. |
@ -25568,11 +25658,14 @@ four standard [pagination arguments](#pagination-arguments):
| <a id="mergerequestauthorassignedmergerequestslabels"></a>`labels` **{warning-solid}** | [`[String!]`](#string) | **Deprecated** in GitLab 17.1. Use `labelName`. |
| <a id="mergerequestauthorassignedmergerequestsmergedafter"></a>`mergedAfter` | [`Time`](#time) | Merge requests merged after the date. |
| <a id="mergerequestauthorassignedmergerequestsmergedbefore"></a>`mergedBefore` | [`Time`](#time) | Merge requests merged before the date. |
| <a id="mergerequestauthorassignedmergerequestsmergedby"></a>`mergedBy` | [`String`](#string) | Username of the merger. |
| <a id="mergerequestauthorassignedmergerequestsmilestonetitle"></a>`milestoneTitle` | [`String`](#string) | Title of the milestone. Incompatible with milestoneWildcardId. |
| <a id="mergerequestauthorassignedmergerequestsmilestonewildcardid"></a>`milestoneWildcardId` | [`MilestoneWildcardId`](#milestonewildcardid) | Filter issues by milestone ID wildcard. Incompatible with milestoneTitle. |
| <a id="mergerequestauthorassignedmergerequestsmyreactionemoji"></a>`myReactionEmoji` | [`String`](#string) | Filter by your reaction emoji. |
| <a id="mergerequestauthorassignedmergerequestsnot"></a>`not` | [`MergeRequestsResolverNegatedParams`](#mergerequestsresolvernegatedparams) | List of negated arguments. Warning: this argument is experimental and a subject to change in future. |
| <a id="mergerequestauthorassignedmergerequestsprojectid"></a>`projectId` | [`ProjectID`](#projectid) | The global ID of the project the authored merge requests should be in. Incompatible with projectPath. |
| <a id="mergerequestauthorassignedmergerequestsprojectpath"></a>`projectPath` | [`String`](#string) | The full-path of the project the authored merge requests should be in. Incompatible with projectId. |
| <a id="mergerequestauthorassignedmergerequestsreleasetag"></a>`releaseTag` | [`String`](#string) | Filter by release tag. |
| <a id="mergerequestauthorassignedmergerequestsreviewstate"></a>`reviewState` **{warning-solid}** | [`MergeRequestReviewState`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer state of the merge request. |
| <a id="mergerequestauthorassignedmergerequestsreviewstates"></a>`reviewStates` **{warning-solid}** | [`[MergeRequestReviewState!]`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer states of the merge request. |
| <a id="mergerequestauthorassignedmergerequestsreviewerusername"></a>`reviewerUsername` | [`String`](#string) | Username of the reviewer. |
@ -25599,6 +25692,7 @@ four standard [pagination arguments](#pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mergerequestauthorauthoredmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. Available only when the feature flag `mr_approved_filter` is enabled. |
| <a id="mergerequestauthorauthoredmergerequestsapprovedby"></a>`approvedBy` | [`[String!]`](#string) | Usernames of the approvers. |
| <a id="mergerequestauthorauthoredmergerequestsassigneeusername"></a>`assigneeUsername` | [`String`](#string) | Username of the assignee. |
| <a id="mergerequestauthorauthoredmergerequestsassigneewildcardid"></a>`assigneeWildcardId` | [`AssigneeWildcardId`](#assigneewildcardid) | Filter by assignee presence. Incompatible with assigneeUsernames and assigneeUsername. |
| <a id="mergerequestauthorauthoredmergerequestscreatedafter"></a>`createdAfter` | [`Time`](#time) | Merge requests created after the timestamp. |
@ -25613,11 +25707,14 @@ four standard [pagination arguments](#pagination-arguments):
| <a id="mergerequestauthorauthoredmergerequestslabels"></a>`labels` **{warning-solid}** | [`[String!]`](#string) | **Deprecated** in GitLab 17.1. Use `labelName`. |
| <a id="mergerequestauthorauthoredmergerequestsmergedafter"></a>`mergedAfter` | [`Time`](#time) | Merge requests merged after the date. |
| <a id="mergerequestauthorauthoredmergerequestsmergedbefore"></a>`mergedBefore` | [`Time`](#time) | Merge requests merged before the date. |
| <a id="mergerequestauthorauthoredmergerequestsmergedby"></a>`mergedBy` | [`String`](#string) | Username of the merger. |
| <a id="mergerequestauthorauthoredmergerequestsmilestonetitle"></a>`milestoneTitle` | [`String`](#string) | Title of the milestone. Incompatible with milestoneWildcardId. |
| <a id="mergerequestauthorauthoredmergerequestsmilestonewildcardid"></a>`milestoneWildcardId` | [`MilestoneWildcardId`](#milestonewildcardid) | Filter issues by milestone ID wildcard. Incompatible with milestoneTitle. |
| <a id="mergerequestauthorauthoredmergerequestsmyreactionemoji"></a>`myReactionEmoji` | [`String`](#string) | Filter by your reaction emoji. |
| <a id="mergerequestauthorauthoredmergerequestsnot"></a>`not` | [`MergeRequestsResolverNegatedParams`](#mergerequestsresolvernegatedparams) | List of negated arguments. Warning: this argument is experimental and a subject to change in future. |
| <a id="mergerequestauthorauthoredmergerequestsprojectid"></a>`projectId` | [`ProjectID`](#projectid) | The global ID of the project the authored merge requests should be in. Incompatible with projectPath. |
| <a id="mergerequestauthorauthoredmergerequestsprojectpath"></a>`projectPath` | [`String`](#string) | The full-path of the project the authored merge requests should be in. Incompatible with projectId. |
| <a id="mergerequestauthorauthoredmergerequestsreleasetag"></a>`releaseTag` | [`String`](#string) | Filter by release tag. |
| <a id="mergerequestauthorauthoredmergerequestsreviewstate"></a>`reviewState` **{warning-solid}** | [`MergeRequestReviewState`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer state of the merge request. |
| <a id="mergerequestauthorauthoredmergerequestsreviewstates"></a>`reviewStates` **{warning-solid}** | [`[MergeRequestReviewState!]`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer states of the merge request. |
| <a id="mergerequestauthorauthoredmergerequestsreviewerusername"></a>`reviewerUsername` | [`String`](#string) | Username of the reviewer. |
@ -25697,6 +25794,7 @@ four standard [pagination arguments](#pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mergerequestauthorreviewrequestedmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. Available only when the feature flag `mr_approved_filter` is enabled. |
| <a id="mergerequestauthorreviewrequestedmergerequestsapprovedby"></a>`approvedBy` | [`[String!]`](#string) | Usernames of the approvers. |
| <a id="mergerequestauthorreviewrequestedmergerequestsassigneeusername"></a>`assigneeUsername` | [`String`](#string) | Username of the assignee. |
| <a id="mergerequestauthorreviewrequestedmergerequestsassigneewildcardid"></a>`assigneeWildcardId` | [`AssigneeWildcardId`](#assigneewildcardid) | Filter by assignee presence. Incompatible with assigneeUsernames and assigneeUsername. |
| <a id="mergerequestauthorreviewrequestedmergerequestsauthorusername"></a>`authorUsername` | [`String`](#string) | Username of the author. |
@ -25712,11 +25810,14 @@ four standard [pagination arguments](#pagination-arguments):
| <a id="mergerequestauthorreviewrequestedmergerequestslabels"></a>`labels` **{warning-solid}** | [`[String!]`](#string) | **Deprecated** in GitLab 17.1. Use `labelName`. |
| <a id="mergerequestauthorreviewrequestedmergerequestsmergedafter"></a>`mergedAfter` | [`Time`](#time) | Merge requests merged after the date. |
| <a id="mergerequestauthorreviewrequestedmergerequestsmergedbefore"></a>`mergedBefore` | [`Time`](#time) | Merge requests merged before the date. |
| <a id="mergerequestauthorreviewrequestedmergerequestsmergedby"></a>`mergedBy` | [`String`](#string) | Username of the merger. |
| <a id="mergerequestauthorreviewrequestedmergerequestsmilestonetitle"></a>`milestoneTitle` | [`String`](#string) | Title of the milestone. Incompatible with milestoneWildcardId. |
| <a id="mergerequestauthorreviewrequestedmergerequestsmilestonewildcardid"></a>`milestoneWildcardId` | [`MilestoneWildcardId`](#milestonewildcardid) | Filter issues by milestone ID wildcard. Incompatible with milestoneTitle. |
| <a id="mergerequestauthorreviewrequestedmergerequestsmyreactionemoji"></a>`myReactionEmoji` | [`String`](#string) | Filter by your reaction emoji. |
| <a id="mergerequestauthorreviewrequestedmergerequestsnot"></a>`not` | [`MergeRequestsResolverNegatedParams`](#mergerequestsresolvernegatedparams) | List of negated arguments. Warning: this argument is experimental and a subject to change in future. |
| <a id="mergerequestauthorreviewrequestedmergerequestsprojectid"></a>`projectId` | [`ProjectID`](#projectid) | The global ID of the project the authored merge requests should be in. Incompatible with projectPath. |
| <a id="mergerequestauthorreviewrequestedmergerequestsprojectpath"></a>`projectPath` | [`String`](#string) | The full-path of the project the authored merge requests should be in. Incompatible with projectId. |
| <a id="mergerequestauthorreviewrequestedmergerequestsreleasetag"></a>`releaseTag` | [`String`](#string) | Filter by release tag. |
| <a id="mergerequestauthorreviewrequestedmergerequestsreviewstate"></a>`reviewState` **{warning-solid}** | [`MergeRequestReviewState`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer state of the merge request. |
| <a id="mergerequestauthorreviewrequestedmergerequestsreviewstates"></a>`reviewStates` **{warning-solid}** | [`[MergeRequestReviewState!]`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer states of the merge request. |
| <a id="mergerequestauthorreviewrequestedmergerequestssort"></a>`sort` | [`MergeRequestSort`](#mergerequestsort) | Sort merge requests by the criteria. |
@ -25968,6 +26069,7 @@ four standard [pagination arguments](#pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mergerequestparticipantassignedmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. Available only when the feature flag `mr_approved_filter` is enabled. |
| <a id="mergerequestparticipantassignedmergerequestsapprovedby"></a>`approvedBy` | [`[String!]`](#string) | Usernames of the approvers. |
| <a id="mergerequestparticipantassignedmergerequestsauthorusername"></a>`authorUsername` | [`String`](#string) | Username of the author. |
| <a id="mergerequestparticipantassignedmergerequestscreatedafter"></a>`createdAfter` | [`Time`](#time) | Merge requests created after the timestamp. |
| <a id="mergerequestparticipantassignedmergerequestscreatedbefore"></a>`createdBefore` | [`Time`](#time) | Merge requests created before the timestamp. |
@ -25981,11 +26083,14 @@ four standard [pagination arguments](#pagination-arguments):
| <a id="mergerequestparticipantassignedmergerequestslabels"></a>`labels` **{warning-solid}** | [`[String!]`](#string) | **Deprecated** in GitLab 17.1. Use `labelName`. |
| <a id="mergerequestparticipantassignedmergerequestsmergedafter"></a>`mergedAfter` | [`Time`](#time) | Merge requests merged after the date. |
| <a id="mergerequestparticipantassignedmergerequestsmergedbefore"></a>`mergedBefore` | [`Time`](#time) | Merge requests merged before the date. |
| <a id="mergerequestparticipantassignedmergerequestsmergedby"></a>`mergedBy` | [`String`](#string) | Username of the merger. |
| <a id="mergerequestparticipantassignedmergerequestsmilestonetitle"></a>`milestoneTitle` | [`String`](#string) | Title of the milestone. Incompatible with milestoneWildcardId. |
| <a id="mergerequestparticipantassignedmergerequestsmilestonewildcardid"></a>`milestoneWildcardId` | [`MilestoneWildcardId`](#milestonewildcardid) | Filter issues by milestone ID wildcard. Incompatible with milestoneTitle. |
| <a id="mergerequestparticipantassignedmergerequestsmyreactionemoji"></a>`myReactionEmoji` | [`String`](#string) | Filter by your reaction emoji. |
| <a id="mergerequestparticipantassignedmergerequestsnot"></a>`not` | [`MergeRequestsResolverNegatedParams`](#mergerequestsresolvernegatedparams) | List of negated arguments. Warning: this argument is experimental and a subject to change in future. |
| <a id="mergerequestparticipantassignedmergerequestsprojectid"></a>`projectId` | [`ProjectID`](#projectid) | The global ID of the project the authored merge requests should be in. Incompatible with projectPath. |
| <a id="mergerequestparticipantassignedmergerequestsprojectpath"></a>`projectPath` | [`String`](#string) | The full-path of the project the authored merge requests should be in. Incompatible with projectId. |
| <a id="mergerequestparticipantassignedmergerequestsreleasetag"></a>`releaseTag` | [`String`](#string) | Filter by release tag. |
| <a id="mergerequestparticipantassignedmergerequestsreviewstate"></a>`reviewState` **{warning-solid}** | [`MergeRequestReviewState`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer state of the merge request. |
| <a id="mergerequestparticipantassignedmergerequestsreviewstates"></a>`reviewStates` **{warning-solid}** | [`[MergeRequestReviewState!]`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer states of the merge request. |
| <a id="mergerequestparticipantassignedmergerequestsreviewerusername"></a>`reviewerUsername` | [`String`](#string) | Username of the reviewer. |
@ -26012,6 +26117,7 @@ four standard [pagination arguments](#pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mergerequestparticipantauthoredmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. Available only when the feature flag `mr_approved_filter` is enabled. |
| <a id="mergerequestparticipantauthoredmergerequestsapprovedby"></a>`approvedBy` | [`[String!]`](#string) | Usernames of the approvers. |
| <a id="mergerequestparticipantauthoredmergerequestsassigneeusername"></a>`assigneeUsername` | [`String`](#string) | Username of the assignee. |
| <a id="mergerequestparticipantauthoredmergerequestsassigneewildcardid"></a>`assigneeWildcardId` | [`AssigneeWildcardId`](#assigneewildcardid) | Filter by assignee presence. Incompatible with assigneeUsernames and assigneeUsername. |
| <a id="mergerequestparticipantauthoredmergerequestscreatedafter"></a>`createdAfter` | [`Time`](#time) | Merge requests created after the timestamp. |
@ -26026,11 +26132,14 @@ four standard [pagination arguments](#pagination-arguments):
| <a id="mergerequestparticipantauthoredmergerequestslabels"></a>`labels` **{warning-solid}** | [`[String!]`](#string) | **Deprecated** in GitLab 17.1. Use `labelName`. |
| <a id="mergerequestparticipantauthoredmergerequestsmergedafter"></a>`mergedAfter` | [`Time`](#time) | Merge requests merged after the date. |
| <a id="mergerequestparticipantauthoredmergerequestsmergedbefore"></a>`mergedBefore` | [`Time`](#time) | Merge requests merged before the date. |
| <a id="mergerequestparticipantauthoredmergerequestsmergedby"></a>`mergedBy` | [`String`](#string) | Username of the merger. |
| <a id="mergerequestparticipantauthoredmergerequestsmilestonetitle"></a>`milestoneTitle` | [`String`](#string) | Title of the milestone. Incompatible with milestoneWildcardId. |
| <a id="mergerequestparticipantauthoredmergerequestsmilestonewildcardid"></a>`milestoneWildcardId` | [`MilestoneWildcardId`](#milestonewildcardid) | Filter issues by milestone ID wildcard. Incompatible with milestoneTitle. |
| <a id="mergerequestparticipantauthoredmergerequestsmyreactionemoji"></a>`myReactionEmoji` | [`String`](#string) | Filter by your reaction emoji. |
| <a id="mergerequestparticipantauthoredmergerequestsnot"></a>`not` | [`MergeRequestsResolverNegatedParams`](#mergerequestsresolvernegatedparams) | List of negated arguments. Warning: this argument is experimental and a subject to change in future. |
| <a id="mergerequestparticipantauthoredmergerequestsprojectid"></a>`projectId` | [`ProjectID`](#projectid) | The global ID of the project the authored merge requests should be in. Incompatible with projectPath. |
| <a id="mergerequestparticipantauthoredmergerequestsprojectpath"></a>`projectPath` | [`String`](#string) | The full-path of the project the authored merge requests should be in. Incompatible with projectId. |
| <a id="mergerequestparticipantauthoredmergerequestsreleasetag"></a>`releaseTag` | [`String`](#string) | Filter by release tag. |
| <a id="mergerequestparticipantauthoredmergerequestsreviewstate"></a>`reviewState` **{warning-solid}** | [`MergeRequestReviewState`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer state of the merge request. |
| <a id="mergerequestparticipantauthoredmergerequestsreviewstates"></a>`reviewStates` **{warning-solid}** | [`[MergeRequestReviewState!]`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer states of the merge request. |
| <a id="mergerequestparticipantauthoredmergerequestsreviewerusername"></a>`reviewerUsername` | [`String`](#string) | Username of the reviewer. |
@ -26110,6 +26219,7 @@ four standard [pagination arguments](#pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mergerequestparticipantreviewrequestedmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. Available only when the feature flag `mr_approved_filter` is enabled. |
| <a id="mergerequestparticipantreviewrequestedmergerequestsapprovedby"></a>`approvedBy` | [`[String!]`](#string) | Usernames of the approvers. |
| <a id="mergerequestparticipantreviewrequestedmergerequestsassigneeusername"></a>`assigneeUsername` | [`String`](#string) | Username of the assignee. |
| <a id="mergerequestparticipantreviewrequestedmergerequestsassigneewildcardid"></a>`assigneeWildcardId` | [`AssigneeWildcardId`](#assigneewildcardid) | Filter by assignee presence. Incompatible with assigneeUsernames and assigneeUsername. |
| <a id="mergerequestparticipantreviewrequestedmergerequestsauthorusername"></a>`authorUsername` | [`String`](#string) | Username of the author. |
@ -26125,11 +26235,14 @@ four standard [pagination arguments](#pagination-arguments):
| <a id="mergerequestparticipantreviewrequestedmergerequestslabels"></a>`labels` **{warning-solid}** | [`[String!]`](#string) | **Deprecated** in GitLab 17.1. Use `labelName`. |
| <a id="mergerequestparticipantreviewrequestedmergerequestsmergedafter"></a>`mergedAfter` | [`Time`](#time) | Merge requests merged after the date. |
| <a id="mergerequestparticipantreviewrequestedmergerequestsmergedbefore"></a>`mergedBefore` | [`Time`](#time) | Merge requests merged before the date. |
| <a id="mergerequestparticipantreviewrequestedmergerequestsmergedby"></a>`mergedBy` | [`String`](#string) | Username of the merger. |
| <a id="mergerequestparticipantreviewrequestedmergerequestsmilestonetitle"></a>`milestoneTitle` | [`String`](#string) | Title of the milestone. Incompatible with milestoneWildcardId. |
| <a id="mergerequestparticipantreviewrequestedmergerequestsmilestonewildcardid"></a>`milestoneWildcardId` | [`MilestoneWildcardId`](#milestonewildcardid) | Filter issues by milestone ID wildcard. Incompatible with milestoneTitle. |
| <a id="mergerequestparticipantreviewrequestedmergerequestsmyreactionemoji"></a>`myReactionEmoji` | [`String`](#string) | Filter by your reaction emoji. |
| <a id="mergerequestparticipantreviewrequestedmergerequestsnot"></a>`not` | [`MergeRequestsResolverNegatedParams`](#mergerequestsresolvernegatedparams) | List of negated arguments. Warning: this argument is experimental and a subject to change in future. |
| <a id="mergerequestparticipantreviewrequestedmergerequestsprojectid"></a>`projectId` | [`ProjectID`](#projectid) | The global ID of the project the authored merge requests should be in. Incompatible with projectPath. |
| <a id="mergerequestparticipantreviewrequestedmergerequestsprojectpath"></a>`projectPath` | [`String`](#string) | The full-path of the project the authored merge requests should be in. Incompatible with projectId. |
| <a id="mergerequestparticipantreviewrequestedmergerequestsreleasetag"></a>`releaseTag` | [`String`](#string) | Filter by release tag. |
| <a id="mergerequestparticipantreviewrequestedmergerequestsreviewstate"></a>`reviewState` **{warning-solid}** | [`MergeRequestReviewState`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer state of the merge request. |
| <a id="mergerequestparticipantreviewrequestedmergerequestsreviewstates"></a>`reviewStates` **{warning-solid}** | [`[MergeRequestReviewState!]`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer states of the merge request. |
| <a id="mergerequestparticipantreviewrequestedmergerequestssort"></a>`sort` | [`MergeRequestSort`](#mergerequestsort) | Sort merge requests by the criteria. |
@ -26354,6 +26467,7 @@ four standard [pagination arguments](#pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mergerequestreviewerassignedmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. Available only when the feature flag `mr_approved_filter` is enabled. |
| <a id="mergerequestreviewerassignedmergerequestsapprovedby"></a>`approvedBy` | [`[String!]`](#string) | Usernames of the approvers. |
| <a id="mergerequestreviewerassignedmergerequestsauthorusername"></a>`authorUsername` | [`String`](#string) | Username of the author. |
| <a id="mergerequestreviewerassignedmergerequestscreatedafter"></a>`createdAfter` | [`Time`](#time) | Merge requests created after the timestamp. |
| <a id="mergerequestreviewerassignedmergerequestscreatedbefore"></a>`createdBefore` | [`Time`](#time) | Merge requests created before the timestamp. |
@ -26367,11 +26481,14 @@ four standard [pagination arguments](#pagination-arguments):
| <a id="mergerequestreviewerassignedmergerequestslabels"></a>`labels` **{warning-solid}** | [`[String!]`](#string) | **Deprecated** in GitLab 17.1. Use `labelName`. |
| <a id="mergerequestreviewerassignedmergerequestsmergedafter"></a>`mergedAfter` | [`Time`](#time) | Merge requests merged after the date. |
| <a id="mergerequestreviewerassignedmergerequestsmergedbefore"></a>`mergedBefore` | [`Time`](#time) | Merge requests merged before the date. |
| <a id="mergerequestreviewerassignedmergerequestsmergedby"></a>`mergedBy` | [`String`](#string) | Username of the merger. |
| <a id="mergerequestreviewerassignedmergerequestsmilestonetitle"></a>`milestoneTitle` | [`String`](#string) | Title of the milestone. Incompatible with milestoneWildcardId. |
| <a id="mergerequestreviewerassignedmergerequestsmilestonewildcardid"></a>`milestoneWildcardId` | [`MilestoneWildcardId`](#milestonewildcardid) | Filter issues by milestone ID wildcard. Incompatible with milestoneTitle. |
| <a id="mergerequestreviewerassignedmergerequestsmyreactionemoji"></a>`myReactionEmoji` | [`String`](#string) | Filter by your reaction emoji. |
| <a id="mergerequestreviewerassignedmergerequestsnot"></a>`not` | [`MergeRequestsResolverNegatedParams`](#mergerequestsresolvernegatedparams) | List of negated arguments. Warning: this argument is experimental and a subject to change in future. |
| <a id="mergerequestreviewerassignedmergerequestsprojectid"></a>`projectId` | [`ProjectID`](#projectid) | The global ID of the project the authored merge requests should be in. Incompatible with projectPath. |
| <a id="mergerequestreviewerassignedmergerequestsprojectpath"></a>`projectPath` | [`String`](#string) | The full-path of the project the authored merge requests should be in. Incompatible with projectId. |
| <a id="mergerequestreviewerassignedmergerequestsreleasetag"></a>`releaseTag` | [`String`](#string) | Filter by release tag. |
| <a id="mergerequestreviewerassignedmergerequestsreviewstate"></a>`reviewState` **{warning-solid}** | [`MergeRequestReviewState`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer state of the merge request. |
| <a id="mergerequestreviewerassignedmergerequestsreviewstates"></a>`reviewStates` **{warning-solid}** | [`[MergeRequestReviewState!]`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer states of the merge request. |
| <a id="mergerequestreviewerassignedmergerequestsreviewerusername"></a>`reviewerUsername` | [`String`](#string) | Username of the reviewer. |
@ -26398,6 +26515,7 @@ four standard [pagination arguments](#pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mergerequestreviewerauthoredmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. Available only when the feature flag `mr_approved_filter` is enabled. |
| <a id="mergerequestreviewerauthoredmergerequestsapprovedby"></a>`approvedBy` | [`[String!]`](#string) | Usernames of the approvers. |
| <a id="mergerequestreviewerauthoredmergerequestsassigneeusername"></a>`assigneeUsername` | [`String`](#string) | Username of the assignee. |
| <a id="mergerequestreviewerauthoredmergerequestsassigneewildcardid"></a>`assigneeWildcardId` | [`AssigneeWildcardId`](#assigneewildcardid) | Filter by assignee presence. Incompatible with assigneeUsernames and assigneeUsername. |
| <a id="mergerequestreviewerauthoredmergerequestscreatedafter"></a>`createdAfter` | [`Time`](#time) | Merge requests created after the timestamp. |
@ -26412,11 +26530,14 @@ four standard [pagination arguments](#pagination-arguments):
| <a id="mergerequestreviewerauthoredmergerequestslabels"></a>`labels` **{warning-solid}** | [`[String!]`](#string) | **Deprecated** in GitLab 17.1. Use `labelName`. |
| <a id="mergerequestreviewerauthoredmergerequestsmergedafter"></a>`mergedAfter` | [`Time`](#time) | Merge requests merged after the date. |
| <a id="mergerequestreviewerauthoredmergerequestsmergedbefore"></a>`mergedBefore` | [`Time`](#time) | Merge requests merged before the date. |
| <a id="mergerequestreviewerauthoredmergerequestsmergedby"></a>`mergedBy` | [`String`](#string) | Username of the merger. |
| <a id="mergerequestreviewerauthoredmergerequestsmilestonetitle"></a>`milestoneTitle` | [`String`](#string) | Title of the milestone. Incompatible with milestoneWildcardId. |
| <a id="mergerequestreviewerauthoredmergerequestsmilestonewildcardid"></a>`milestoneWildcardId` | [`MilestoneWildcardId`](#milestonewildcardid) | Filter issues by milestone ID wildcard. Incompatible with milestoneTitle. |
| <a id="mergerequestreviewerauthoredmergerequestsmyreactionemoji"></a>`myReactionEmoji` | [`String`](#string) | Filter by your reaction emoji. |
| <a id="mergerequestreviewerauthoredmergerequestsnot"></a>`not` | [`MergeRequestsResolverNegatedParams`](#mergerequestsresolvernegatedparams) | List of negated arguments. Warning: this argument is experimental and a subject to change in future. |
| <a id="mergerequestreviewerauthoredmergerequestsprojectid"></a>`projectId` | [`ProjectID`](#projectid) | The global ID of the project the authored merge requests should be in. Incompatible with projectPath. |
| <a id="mergerequestreviewerauthoredmergerequestsprojectpath"></a>`projectPath` | [`String`](#string) | The full-path of the project the authored merge requests should be in. Incompatible with projectId. |
| <a id="mergerequestreviewerauthoredmergerequestsreleasetag"></a>`releaseTag` | [`String`](#string) | Filter by release tag. |
| <a id="mergerequestreviewerauthoredmergerequestsreviewstate"></a>`reviewState` **{warning-solid}** | [`MergeRequestReviewState`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer state of the merge request. |
| <a id="mergerequestreviewerauthoredmergerequestsreviewstates"></a>`reviewStates` **{warning-solid}** | [`[MergeRequestReviewState!]`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer states of the merge request. |
| <a id="mergerequestreviewerauthoredmergerequestsreviewerusername"></a>`reviewerUsername` | [`String`](#string) | Username of the reviewer. |
@ -26496,6 +26617,7 @@ four standard [pagination arguments](#pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mergerequestreviewerreviewrequestedmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. Available only when the feature flag `mr_approved_filter` is enabled. |
| <a id="mergerequestreviewerreviewrequestedmergerequestsapprovedby"></a>`approvedBy` | [`[String!]`](#string) | Usernames of the approvers. |
| <a id="mergerequestreviewerreviewrequestedmergerequestsassigneeusername"></a>`assigneeUsername` | [`String`](#string) | Username of the assignee. |
| <a id="mergerequestreviewerreviewrequestedmergerequestsassigneewildcardid"></a>`assigneeWildcardId` | [`AssigneeWildcardId`](#assigneewildcardid) | Filter by assignee presence. Incompatible with assigneeUsernames and assigneeUsername. |
| <a id="mergerequestreviewerreviewrequestedmergerequestsauthorusername"></a>`authorUsername` | [`String`](#string) | Username of the author. |
@ -26511,11 +26633,14 @@ four standard [pagination arguments](#pagination-arguments):
| <a id="mergerequestreviewerreviewrequestedmergerequestslabels"></a>`labels` **{warning-solid}** | [`[String!]`](#string) | **Deprecated** in GitLab 17.1. Use `labelName`. |
| <a id="mergerequestreviewerreviewrequestedmergerequestsmergedafter"></a>`mergedAfter` | [`Time`](#time) | Merge requests merged after the date. |
| <a id="mergerequestreviewerreviewrequestedmergerequestsmergedbefore"></a>`mergedBefore` | [`Time`](#time) | Merge requests merged before the date. |
| <a id="mergerequestreviewerreviewrequestedmergerequestsmergedby"></a>`mergedBy` | [`String`](#string) | Username of the merger. |
| <a id="mergerequestreviewerreviewrequestedmergerequestsmilestonetitle"></a>`milestoneTitle` | [`String`](#string) | Title of the milestone. Incompatible with milestoneWildcardId. |
| <a id="mergerequestreviewerreviewrequestedmergerequestsmilestonewildcardid"></a>`milestoneWildcardId` | [`MilestoneWildcardId`](#milestonewildcardid) | Filter issues by milestone ID wildcard. Incompatible with milestoneTitle. |
| <a id="mergerequestreviewerreviewrequestedmergerequestsmyreactionemoji"></a>`myReactionEmoji` | [`String`](#string) | Filter by your reaction emoji. |
| <a id="mergerequestreviewerreviewrequestedmergerequestsnot"></a>`not` | [`MergeRequestsResolverNegatedParams`](#mergerequestsresolvernegatedparams) | List of negated arguments. Warning: this argument is experimental and a subject to change in future. |
| <a id="mergerequestreviewerreviewrequestedmergerequestsprojectid"></a>`projectId` | [`ProjectID`](#projectid) | The global ID of the project the authored merge requests should be in. Incompatible with projectPath. |
| <a id="mergerequestreviewerreviewrequestedmergerequestsprojectpath"></a>`projectPath` | [`String`](#string) | The full-path of the project the authored merge requests should be in. Incompatible with projectId. |
| <a id="mergerequestreviewerreviewrequestedmergerequestsreleasetag"></a>`releaseTag` | [`String`](#string) | Filter by release tag. |
| <a id="mergerequestreviewerreviewrequestedmergerequestsreviewstate"></a>`reviewState` **{warning-solid}** | [`MergeRequestReviewState`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer state of the merge request. |
| <a id="mergerequestreviewerreviewrequestedmergerequestsreviewstates"></a>`reviewStates` **{warning-solid}** | [`[MergeRequestReviewState!]`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer states of the merge request. |
| <a id="mergerequestreviewerreviewrequestedmergerequestssort"></a>`sort` | [`MergeRequestSort`](#mergerequestsort) | Sort merge requests by the criteria. |
@ -29553,6 +29678,7 @@ four standard [pagination arguments](#pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="projectmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. Available only when the feature flag `mr_approved_filter` is enabled. |
| <a id="projectmergerequestsapprovedby"></a>`approvedBy` | [`[String!]`](#string) | Usernames of the approvers. |
| <a id="projectmergerequestsassigneeusername"></a>`assigneeUsername` | [`String`](#string) | Username of the assignee. |
| <a id="projectmergerequestsassigneewildcardid"></a>`assigneeWildcardId` | [`AssigneeWildcardId`](#assigneewildcardid) | Filter by assignee presence. Incompatible with assigneeUsernames and assigneeUsername. |
| <a id="projectmergerequestsauthorusername"></a>`authorUsername` | [`String`](#string) | Username of the author. |
@ -29567,9 +29693,12 @@ four standard [pagination arguments](#pagination-arguments):
| <a id="projectmergerequestslabels"></a>`labels` **{warning-solid}** | [`[String!]`](#string) | **Deprecated** in GitLab 17.1. Use `labelName`. |
| <a id="projectmergerequestsmergedafter"></a>`mergedAfter` | [`Time`](#time) | Merge requests merged after the date. |
| <a id="projectmergerequestsmergedbefore"></a>`mergedBefore` | [`Time`](#time) | Merge requests merged before the date. |
| <a id="projectmergerequestsmergedby"></a>`mergedBy` | [`String`](#string) | Username of the merger. |
| <a id="projectmergerequestsmilestonetitle"></a>`milestoneTitle` | [`String`](#string) | Title of the milestone. Incompatible with milestoneWildcardId. |
| <a id="projectmergerequestsmilestonewildcardid"></a>`milestoneWildcardId` | [`MilestoneWildcardId`](#milestonewildcardid) | Filter issues by milestone ID wildcard. Incompatible with milestoneTitle. |
| <a id="projectmergerequestsmyreactionemoji"></a>`myReactionEmoji` | [`String`](#string) | Filter by your reaction emoji. |
| <a id="projectmergerequestsnot"></a>`not` | [`MergeRequestsResolverNegatedParams`](#mergerequestsresolvernegatedparams) | List of negated arguments. Warning: this argument is experimental and a subject to change in future. |
| <a id="projectmergerequestsreleasetag"></a>`releaseTag` | [`String`](#string) | Filter by release tag. |
| <a id="projectmergerequestsreviewstate"></a>`reviewState` **{warning-solid}** | [`MergeRequestReviewState`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer state of the merge request. |
| <a id="projectmergerequestsreviewstates"></a>`reviewStates` **{warning-solid}** | [`[MergeRequestReviewState!]`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer states of the merge request. |
| <a id="projectmergerequestsreviewerusername"></a>`reviewerUsername` | [`String`](#string) | Username of the reviewer. |
@ -31854,6 +31983,18 @@ SSH signature for a signed commit.
| <a id="sshsignatureuser"></a>`user` | [`UserCore`](#usercore) | User associated with the key. |
| <a id="sshsignatureverificationstatus"></a>`verificationStatus` | [`VerificationStatus`](#verificationstatus) | Indicates verification status of the associated key or certificate. |
### `StandardRole`
Represents a standard role.
#### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="standardroleaccesslevel"></a>`accessLevel` | [`Int!`](#int) | Access level as a number. |
| <a id="standardrolememberscount"></a>`membersCount` **{warning-solid}** | [`Int!`](#int) | **Introduced** in GitLab 17.3. **Status**: Experiment. Total number of members with the standard role. |
| <a id="standardrolename"></a>`name` | [`String!`](#string) | Access level as a string. |
### `StandardsAdherenceChecksStatus`
Progress of standards adherence checks.
@ -32539,6 +32680,7 @@ four standard [pagination arguments](#pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="usercoreassignedmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. Available only when the feature flag `mr_approved_filter` is enabled. |
| <a id="usercoreassignedmergerequestsapprovedby"></a>`approvedBy` | [`[String!]`](#string) | Usernames of the approvers. |
| <a id="usercoreassignedmergerequestsauthorusername"></a>`authorUsername` | [`String`](#string) | Username of the author. |
| <a id="usercoreassignedmergerequestscreatedafter"></a>`createdAfter` | [`Time`](#time) | Merge requests created after the timestamp. |
| <a id="usercoreassignedmergerequestscreatedbefore"></a>`createdBefore` | [`Time`](#time) | Merge requests created before the timestamp. |
@ -32552,11 +32694,14 @@ four standard [pagination arguments](#pagination-arguments):
| <a id="usercoreassignedmergerequestslabels"></a>`labels` **{warning-solid}** | [`[String!]`](#string) | **Deprecated** in GitLab 17.1. Use `labelName`. |
| <a id="usercoreassignedmergerequestsmergedafter"></a>`mergedAfter` | [`Time`](#time) | Merge requests merged after the date. |
| <a id="usercoreassignedmergerequestsmergedbefore"></a>`mergedBefore` | [`Time`](#time) | Merge requests merged before the date. |
| <a id="usercoreassignedmergerequestsmergedby"></a>`mergedBy` | [`String`](#string) | Username of the merger. |
| <a id="usercoreassignedmergerequestsmilestonetitle"></a>`milestoneTitle` | [`String`](#string) | Title of the milestone. Incompatible with milestoneWildcardId. |
| <a id="usercoreassignedmergerequestsmilestonewildcardid"></a>`milestoneWildcardId` | [`MilestoneWildcardId`](#milestonewildcardid) | Filter issues by milestone ID wildcard. Incompatible with milestoneTitle. |
| <a id="usercoreassignedmergerequestsmyreactionemoji"></a>`myReactionEmoji` | [`String`](#string) | Filter by your reaction emoji. |
| <a id="usercoreassignedmergerequestsnot"></a>`not` | [`MergeRequestsResolverNegatedParams`](#mergerequestsresolvernegatedparams) | List of negated arguments. Warning: this argument is experimental and a subject to change in future. |
| <a id="usercoreassignedmergerequestsprojectid"></a>`projectId` | [`ProjectID`](#projectid) | The global ID of the project the authored merge requests should be in. Incompatible with projectPath. |
| <a id="usercoreassignedmergerequestsprojectpath"></a>`projectPath` | [`String`](#string) | The full-path of the project the authored merge requests should be in. Incompatible with projectId. |
| <a id="usercoreassignedmergerequestsreleasetag"></a>`releaseTag` | [`String`](#string) | Filter by release tag. |
| <a id="usercoreassignedmergerequestsreviewstate"></a>`reviewState` **{warning-solid}** | [`MergeRequestReviewState`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer state of the merge request. |
| <a id="usercoreassignedmergerequestsreviewstates"></a>`reviewStates` **{warning-solid}** | [`[MergeRequestReviewState!]`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer states of the merge request. |
| <a id="usercoreassignedmergerequestsreviewerusername"></a>`reviewerUsername` | [`String`](#string) | Username of the reviewer. |
@ -32583,6 +32728,7 @@ four standard [pagination arguments](#pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="usercoreauthoredmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. Available only when the feature flag `mr_approved_filter` is enabled. |
| <a id="usercoreauthoredmergerequestsapprovedby"></a>`approvedBy` | [`[String!]`](#string) | Usernames of the approvers. |
| <a id="usercoreauthoredmergerequestsassigneeusername"></a>`assigneeUsername` | [`String`](#string) | Username of the assignee. |
| <a id="usercoreauthoredmergerequestsassigneewildcardid"></a>`assigneeWildcardId` | [`AssigneeWildcardId`](#assigneewildcardid) | Filter by assignee presence. Incompatible with assigneeUsernames and assigneeUsername. |
| <a id="usercoreauthoredmergerequestscreatedafter"></a>`createdAfter` | [`Time`](#time) | Merge requests created after the timestamp. |
@ -32597,11 +32743,14 @@ four standard [pagination arguments](#pagination-arguments):
| <a id="usercoreauthoredmergerequestslabels"></a>`labels` **{warning-solid}** | [`[String!]`](#string) | **Deprecated** in GitLab 17.1. Use `labelName`. |
| <a id="usercoreauthoredmergerequestsmergedafter"></a>`mergedAfter` | [`Time`](#time) | Merge requests merged after the date. |
| <a id="usercoreauthoredmergerequestsmergedbefore"></a>`mergedBefore` | [`Time`](#time) | Merge requests merged before the date. |
| <a id="usercoreauthoredmergerequestsmergedby"></a>`mergedBy` | [`String`](#string) | Username of the merger. |
| <a id="usercoreauthoredmergerequestsmilestonetitle"></a>`milestoneTitle` | [`String`](#string) | Title of the milestone. Incompatible with milestoneWildcardId. |
| <a id="usercoreauthoredmergerequestsmilestonewildcardid"></a>`milestoneWildcardId` | [`MilestoneWildcardId`](#milestonewildcardid) | Filter issues by milestone ID wildcard. Incompatible with milestoneTitle. |
| <a id="usercoreauthoredmergerequestsmyreactionemoji"></a>`myReactionEmoji` | [`String`](#string) | Filter by your reaction emoji. |
| <a id="usercoreauthoredmergerequestsnot"></a>`not` | [`MergeRequestsResolverNegatedParams`](#mergerequestsresolvernegatedparams) | List of negated arguments. Warning: this argument is experimental and a subject to change in future. |
| <a id="usercoreauthoredmergerequestsprojectid"></a>`projectId` | [`ProjectID`](#projectid) | The global ID of the project the authored merge requests should be in. Incompatible with projectPath. |
| <a id="usercoreauthoredmergerequestsprojectpath"></a>`projectPath` | [`String`](#string) | The full-path of the project the authored merge requests should be in. Incompatible with projectId. |
| <a id="usercoreauthoredmergerequestsreleasetag"></a>`releaseTag` | [`String`](#string) | Filter by release tag. |
| <a id="usercoreauthoredmergerequestsreviewstate"></a>`reviewState` **{warning-solid}** | [`MergeRequestReviewState`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer state of the merge request. |
| <a id="usercoreauthoredmergerequestsreviewstates"></a>`reviewStates` **{warning-solid}** | [`[MergeRequestReviewState!]`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer states of the merge request. |
| <a id="usercoreauthoredmergerequestsreviewerusername"></a>`reviewerUsername` | [`String`](#string) | Username of the reviewer. |
@ -32681,6 +32830,7 @@ four standard [pagination arguments](#pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="usercorereviewrequestedmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. Available only when the feature flag `mr_approved_filter` is enabled. |
| <a id="usercorereviewrequestedmergerequestsapprovedby"></a>`approvedBy` | [`[String!]`](#string) | Usernames of the approvers. |
| <a id="usercorereviewrequestedmergerequestsassigneeusername"></a>`assigneeUsername` | [`String`](#string) | Username of the assignee. |
| <a id="usercorereviewrequestedmergerequestsassigneewildcardid"></a>`assigneeWildcardId` | [`AssigneeWildcardId`](#assigneewildcardid) | Filter by assignee presence. Incompatible with assigneeUsernames and assigneeUsername. |
| <a id="usercorereviewrequestedmergerequestsauthorusername"></a>`authorUsername` | [`String`](#string) | Username of the author. |
@ -32696,11 +32846,14 @@ four standard [pagination arguments](#pagination-arguments):
| <a id="usercorereviewrequestedmergerequestslabels"></a>`labels` **{warning-solid}** | [`[String!]`](#string) | **Deprecated** in GitLab 17.1. Use `labelName`. |
| <a id="usercorereviewrequestedmergerequestsmergedafter"></a>`mergedAfter` | [`Time`](#time) | Merge requests merged after the date. |
| <a id="usercorereviewrequestedmergerequestsmergedbefore"></a>`mergedBefore` | [`Time`](#time) | Merge requests merged before the date. |
| <a id="usercorereviewrequestedmergerequestsmergedby"></a>`mergedBy` | [`String`](#string) | Username of the merger. |
| <a id="usercorereviewrequestedmergerequestsmilestonetitle"></a>`milestoneTitle` | [`String`](#string) | Title of the milestone. Incompatible with milestoneWildcardId. |
| <a id="usercorereviewrequestedmergerequestsmilestonewildcardid"></a>`milestoneWildcardId` | [`MilestoneWildcardId`](#milestonewildcardid) | Filter issues by milestone ID wildcard. Incompatible with milestoneTitle. |
| <a id="usercorereviewrequestedmergerequestsmyreactionemoji"></a>`myReactionEmoji` | [`String`](#string) | Filter by your reaction emoji. |
| <a id="usercorereviewrequestedmergerequestsnot"></a>`not` | [`MergeRequestsResolverNegatedParams`](#mergerequestsresolvernegatedparams) | List of negated arguments. Warning: this argument is experimental and a subject to change in future. |
| <a id="usercorereviewrequestedmergerequestsprojectid"></a>`projectId` | [`ProjectID`](#projectid) | The global ID of the project the authored merge requests should be in. Incompatible with projectPath. |
| <a id="usercorereviewrequestedmergerequestsprojectpath"></a>`projectPath` | [`String`](#string) | The full-path of the project the authored merge requests should be in. Incompatible with projectId. |
| <a id="usercorereviewrequestedmergerequestsreleasetag"></a>`releaseTag` | [`String`](#string) | Filter by release tag. |
| <a id="usercorereviewrequestedmergerequestsreviewstate"></a>`reviewState` **{warning-solid}** | [`MergeRequestReviewState`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer state of the merge request. |
| <a id="usercorereviewrequestedmergerequestsreviewstates"></a>`reviewStates` **{warning-solid}** | [`[MergeRequestReviewState!]`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer states of the merge request. |
| <a id="usercorereviewrequestedmergerequestssort"></a>`sort` | [`MergeRequestSort`](#mergerequestsort) | Sort merge requests by the criteria. |
@ -35868,6 +36021,7 @@ Iteration ID wildcard values.
| <a id="jobartifactfiletypedast"></a>`DAST` | DAST job artifact file type. |
| <a id="jobartifactfiletypedependency_scanning"></a>`DEPENDENCY_SCANNING` | DEPENDENCY SCANNING job artifact file type. |
| <a id="jobartifactfiletypedotenv"></a>`DOTENV` | DOTENV job artifact file type. |
| <a id="jobartifactfiletypejacoco"></a>`JACOCO` | JACOCO job artifact file type. |
| <a id="jobartifactfiletypejunit"></a>`JUNIT` | JUNIT job artifact file type. |
| <a id="jobartifactfiletypelicense_scanning"></a>`LICENSE_SCANNING` | LICENSE SCANNING job artifact file type. |
| <a id="jobartifactfiletypeload_performance"></a>`LOAD_PERFORMANCE` | LOAD PERFORMANCE job artifact file type. |
@ -39224,6 +39378,7 @@ four standard [pagination arguments](#pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="userassignedmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. Available only when the feature flag `mr_approved_filter` is enabled. |
| <a id="userassignedmergerequestsapprovedby"></a>`approvedBy` | [`[String!]`](#string) | Usernames of the approvers. |
| <a id="userassignedmergerequestsauthorusername"></a>`authorUsername` | [`String`](#string) | Username of the author. |
| <a id="userassignedmergerequestscreatedafter"></a>`createdAfter` | [`Time`](#time) | Merge requests created after the timestamp. |
| <a id="userassignedmergerequestscreatedbefore"></a>`createdBefore` | [`Time`](#time) | Merge requests created before the timestamp. |
@ -39237,11 +39392,14 @@ four standard [pagination arguments](#pagination-arguments):
| <a id="userassignedmergerequestslabels"></a>`labels` **{warning-solid}** | [`[String!]`](#string) | **Deprecated** in GitLab 17.1. Use `labelName`. |
| <a id="userassignedmergerequestsmergedafter"></a>`mergedAfter` | [`Time`](#time) | Merge requests merged after the date. |
| <a id="userassignedmergerequestsmergedbefore"></a>`mergedBefore` | [`Time`](#time) | Merge requests merged before the date. |
| <a id="userassignedmergerequestsmergedby"></a>`mergedBy` | [`String`](#string) | Username of the merger. |
| <a id="userassignedmergerequestsmilestonetitle"></a>`milestoneTitle` | [`String`](#string) | Title of the milestone. Incompatible with milestoneWildcardId. |
| <a id="userassignedmergerequestsmilestonewildcardid"></a>`milestoneWildcardId` | [`MilestoneWildcardId`](#milestonewildcardid) | Filter issues by milestone ID wildcard. Incompatible with milestoneTitle. |
| <a id="userassignedmergerequestsmyreactionemoji"></a>`myReactionEmoji` | [`String`](#string) | Filter by your reaction emoji. |
| <a id="userassignedmergerequestsnot"></a>`not` | [`MergeRequestsResolverNegatedParams`](#mergerequestsresolvernegatedparams) | List of negated arguments. Warning: this argument is experimental and a subject to change in future. |
| <a id="userassignedmergerequestsprojectid"></a>`projectId` | [`ProjectID`](#projectid) | The global ID of the project the authored merge requests should be in. Incompatible with projectPath. |
| <a id="userassignedmergerequestsprojectpath"></a>`projectPath` | [`String`](#string) | The full-path of the project the authored merge requests should be in. Incompatible with projectId. |
| <a id="userassignedmergerequestsreleasetag"></a>`releaseTag` | [`String`](#string) | Filter by release tag. |
| <a id="userassignedmergerequestsreviewstate"></a>`reviewState` **{warning-solid}** | [`MergeRequestReviewState`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer state of the merge request. |
| <a id="userassignedmergerequestsreviewstates"></a>`reviewStates` **{warning-solid}** | [`[MergeRequestReviewState!]`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer states of the merge request. |
| <a id="userassignedmergerequestsreviewerusername"></a>`reviewerUsername` | [`String`](#string) | Username of the reviewer. |
@ -39268,6 +39426,7 @@ four standard [pagination arguments](#pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="userauthoredmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. Available only when the feature flag `mr_approved_filter` is enabled. |
| <a id="userauthoredmergerequestsapprovedby"></a>`approvedBy` | [`[String!]`](#string) | Usernames of the approvers. |
| <a id="userauthoredmergerequestsassigneeusername"></a>`assigneeUsername` | [`String`](#string) | Username of the assignee. |
| <a id="userauthoredmergerequestsassigneewildcardid"></a>`assigneeWildcardId` | [`AssigneeWildcardId`](#assigneewildcardid) | Filter by assignee presence. Incompatible with assigneeUsernames and assigneeUsername. |
| <a id="userauthoredmergerequestscreatedafter"></a>`createdAfter` | [`Time`](#time) | Merge requests created after the timestamp. |
@ -39282,11 +39441,14 @@ four standard [pagination arguments](#pagination-arguments):
| <a id="userauthoredmergerequestslabels"></a>`labels` **{warning-solid}** | [`[String!]`](#string) | **Deprecated** in GitLab 17.1. Use `labelName`. |
| <a id="userauthoredmergerequestsmergedafter"></a>`mergedAfter` | [`Time`](#time) | Merge requests merged after the date. |
| <a id="userauthoredmergerequestsmergedbefore"></a>`mergedBefore` | [`Time`](#time) | Merge requests merged before the date. |
| <a id="userauthoredmergerequestsmergedby"></a>`mergedBy` | [`String`](#string) | Username of the merger. |
| <a id="userauthoredmergerequestsmilestonetitle"></a>`milestoneTitle` | [`String`](#string) | Title of the milestone. Incompatible with milestoneWildcardId. |
| <a id="userauthoredmergerequestsmilestonewildcardid"></a>`milestoneWildcardId` | [`MilestoneWildcardId`](#milestonewildcardid) | Filter issues by milestone ID wildcard. Incompatible with milestoneTitle. |
| <a id="userauthoredmergerequestsmyreactionemoji"></a>`myReactionEmoji` | [`String`](#string) | Filter by your reaction emoji. |
| <a id="userauthoredmergerequestsnot"></a>`not` | [`MergeRequestsResolverNegatedParams`](#mergerequestsresolvernegatedparams) | List of negated arguments. Warning: this argument is experimental and a subject to change in future. |
| <a id="userauthoredmergerequestsprojectid"></a>`projectId` | [`ProjectID`](#projectid) | The global ID of the project the authored merge requests should be in. Incompatible with projectPath. |
| <a id="userauthoredmergerequestsprojectpath"></a>`projectPath` | [`String`](#string) | The full-path of the project the authored merge requests should be in. Incompatible with projectId. |
| <a id="userauthoredmergerequestsreleasetag"></a>`releaseTag` | [`String`](#string) | Filter by release tag. |
| <a id="userauthoredmergerequestsreviewstate"></a>`reviewState` **{warning-solid}** | [`MergeRequestReviewState`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer state of the merge request. |
| <a id="userauthoredmergerequestsreviewstates"></a>`reviewStates` **{warning-solid}** | [`[MergeRequestReviewState!]`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer states of the merge request. |
| <a id="userauthoredmergerequestsreviewerusername"></a>`reviewerUsername` | [`String`](#string) | Username of the reviewer. |
@ -39366,6 +39528,7 @@ four standard [pagination arguments](#pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="userreviewrequestedmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. Available only when the feature flag `mr_approved_filter` is enabled. |
| <a id="userreviewrequestedmergerequestsapprovedby"></a>`approvedBy` | [`[String!]`](#string) | Usernames of the approvers. |
| <a id="userreviewrequestedmergerequestsassigneeusername"></a>`assigneeUsername` | [`String`](#string) | Username of the assignee. |
| <a id="userreviewrequestedmergerequestsassigneewildcardid"></a>`assigneeWildcardId` | [`AssigneeWildcardId`](#assigneewildcardid) | Filter by assignee presence. Incompatible with assigneeUsernames and assigneeUsername. |
| <a id="userreviewrequestedmergerequestsauthorusername"></a>`authorUsername` | [`String`](#string) | Username of the author. |
@ -39381,11 +39544,14 @@ four standard [pagination arguments](#pagination-arguments):
| <a id="userreviewrequestedmergerequestslabels"></a>`labels` **{warning-solid}** | [`[String!]`](#string) | **Deprecated** in GitLab 17.1. Use `labelName`. |
| <a id="userreviewrequestedmergerequestsmergedafter"></a>`mergedAfter` | [`Time`](#time) | Merge requests merged after the date. |
| <a id="userreviewrequestedmergerequestsmergedbefore"></a>`mergedBefore` | [`Time`](#time) | Merge requests merged before the date. |
| <a id="userreviewrequestedmergerequestsmergedby"></a>`mergedBy` | [`String`](#string) | Username of the merger. |
| <a id="userreviewrequestedmergerequestsmilestonetitle"></a>`milestoneTitle` | [`String`](#string) | Title of the milestone. Incompatible with milestoneWildcardId. |
| <a id="userreviewrequestedmergerequestsmilestonewildcardid"></a>`milestoneWildcardId` | [`MilestoneWildcardId`](#milestonewildcardid) | Filter issues by milestone ID wildcard. Incompatible with milestoneTitle. |
| <a id="userreviewrequestedmergerequestsmyreactionemoji"></a>`myReactionEmoji` | [`String`](#string) | Filter by your reaction emoji. |
| <a id="userreviewrequestedmergerequestsnot"></a>`not` | [`MergeRequestsResolverNegatedParams`](#mergerequestsresolvernegatedparams) | List of negated arguments. Warning: this argument is experimental and a subject to change in future. |
| <a id="userreviewrequestedmergerequestsprojectid"></a>`projectId` | [`ProjectID`](#projectid) | The global ID of the project the authored merge requests should be in. Incompatible with projectPath. |
| <a id="userreviewrequestedmergerequestsprojectpath"></a>`projectPath` | [`String`](#string) | The full-path of the project the authored merge requests should be in. Incompatible with projectId. |
| <a id="userreviewrequestedmergerequestsreleasetag"></a>`releaseTag` | [`String`](#string) | Filter by release tag. |
| <a id="userreviewrequestedmergerequestsreviewstate"></a>`reviewState` **{warning-solid}** | [`MergeRequestReviewState`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer state of the merge request. |
| <a id="userreviewrequestedmergerequestsreviewstates"></a>`reviewStates` **{warning-solid}** | [`[MergeRequestReviewState!]`](#mergerequestreviewstate) | **Introduced** in GitLab 17.0. **Status**: Experiment. Reviewer states of the merge request. |
| <a id="userreviewrequestedmergerequestssort"></a>`sort` | [`MergeRequestSort`](#mergerequestsort) | Sort merge requests by the criteria. |
@ -39977,10 +40143,13 @@ Defines which user roles, users, or groups can merge into a protected branch.
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mergerequestsresolvernegatedparamsapprovedby"></a>`approvedBy` | [`[String!]`](#string) | Usernames of approvers to exclude. |
| <a id="mergerequestsresolvernegatedparamsassigneeusernames"></a>`assigneeUsernames` | [`[String!]`](#string) | Usernames of the assignee to exclude. |
| <a id="mergerequestsresolvernegatedparamslabels"></a>`labels` | [`[String!]`](#string) | Array of label names. All resolved merge requests will not have these labels. |
| <a id="mergerequestsresolvernegatedparamsmilestonetitle"></a>`milestoneTitle` | [`String`](#string) | Title of the milestone. |
| <a id="mergerequestsresolvernegatedparamsreviewerusername"></a>`reviewerUsername` | [`String`](#string) | Username of the reviewer. |
| <a id="mergerequestsresolvernegatedparamsmilestonetitle"></a>`milestoneTitle` | [`String`](#string) | Title of the milestone to exclude. |
| <a id="mergerequestsresolvernegatedparamsmyreactionemoji"></a>`myReactionEmoji` | [`String`](#string) | Filter by reaction emoji to exclude. |
| <a id="mergerequestsresolvernegatedparamsreleasetag"></a>`releaseTag` | [`String`](#string) | Filter by release tag to exclude. |
| <a id="mergerequestsresolvernegatedparamsreviewerusername"></a>`reviewerUsername` | [`String`](#string) | Username of the reviewer to exclude. |
### `MonthSelectionInput`

View File

@ -36,6 +36,9 @@ that have the functionality you need in the [CI/CD Catalog](#cicd-catalog).
For an introduction and hands-on examples, see [Efficient DevSecOps workflows with reusable CI/CD components](https://www.youtube.com/watch?v=-yvfSFKAgbA).
<!-- Video published on 2024-01-22. DRI: Developer Relations, https://gitlab.com/groups/gitlab-com/marketing/developer-relations/-/epics/399 -->
For common questions and additional support, see the [FAQ: GitLab CI/CD Catalog](https://about.gitlab.com/blog/2024/08/01/faq-gitlab-ci-cd-catalog/)
blog post.
## Component project
> - The maximum number of components per project [changed](https://gitlab.com/gitlab-org/gitlab/-/issues/436565) from 10 to 30 in GitLab 16.9.

View File

@ -30,8 +30,10 @@ Maintainer role.
Prerequisites:
- When granting the **Allowed to deploy** permission to a group or subgroup, the user configuring the protected environment must be a **direct member** of the group or subgroup to be added. Otherwise, the group or subgroup does not show up in the dropdown list. For more information see [issue #345140](https://gitlab.com/gitlab-org/gitlab/-/issues/345140).
- When granting **Allowed to deploy** permissions to a group or project by using the settings UI, only direct members of the group or project receive these permissions. To grant these permissions to inherited members also, [use the API](../../api/protected_environments.md#group-inheritance-types). For more information see [issue #422392](https://gitlab.com/gitlab-org/gitlab/-/issues/422392).
- When granting the **Allowed to deploy** permission to an approver group, the user configuring the protected environment must be a **direct member** of the approver group to be added. Otherwise, the group or subgroup does not show up in the dropdown list. For more information see [issue #345140](https://gitlab.com/gitlab-org/gitlab/-/issues/345140).
- When granting **Approvers** permissions to an approver group or project, by default only direct members of the approver group or project receive these permissions. To also grant these permissions to inherited members of the approver group or project:
- Select the **Enable group inheritance** checkbox.
- [Use the API](../../api/protected_environments.md#group-inheritance-types).
To protect an environment:

View File

@ -98,6 +98,8 @@ For example, the `[redis]` section in the configuration file could contain:
[redis]
URL = "unix:///var/run/gitlab/redis.sock"
Password = "my_awesome_password"
Sentinel = [ "tcp://sentinel1:23456", "tcp://sentinel2:23456" ]
SentinelMaster = "mymaster"
```
- `URL` - A string in the format `unix://path/to/redis.sock` or `tcp://host:port`.
@ -160,28 +162,6 @@ addr = "localhost:9229"
max_version = "tls1.3"
```
## Sentinel support
```plaintext
[redis]
Sentinel = [ "tcp://sentinel1:23456", "tcp://sentinel2:23456" ]
SentinelMaster = "mymaster"
```
## Sentinel TLS support
```plaintext
[redis]
Sentinel = [ "tcp://sentinel1:23456", "tcp://sentinel2:23456" ]
SentinelMaster = "mymaster"
[Sentinel.tls]
certificate = "/path/to/certificate"
key = "/path/to/private/key"
ca_certificate = "/path/to/ca_certificate" # optional
min_version = "tls1.2" # optional
max_version = "tls1.3" # optional
```
## Interaction of `authBackend` and `authSocket`
The interaction between `authBackend` and `authSocket` can be confusing.

View File

@ -65,6 +65,49 @@ A user is not counted as a billable user if:
The amount of **Billable users** is reported once a day in the **Admin** area.
#### Check daily and historical billable users
Prerequisites:
- You must be an administrator.
You can get a list of daily and historical billable users in your GitLab instance:
1. [Start a Rails console session](../../administration/operations/rails_console.md#starting-a-rails-console-session).
1. Count the number of users in the instance:
```ruby
User.billable.count
```
1. Get the historical maximum number of users on the instance from the past year:
```ruby
::HistoricalData.max_historical_user_count(from: 1.year.ago.beginning_of_day, to: Time.current.end_of_day)
```
#### Update daily and hitorical billable users
Prerequisites:
- You must be an administrator.
You can trigger a manual update of the daily and historical billable users in your GitLab instance.
1. [Start a Rails console session](../../administration/operations/rails_console.md#starting-a-rails-console-session).
1. Force an update of the daily billable users:
```ruby
identifier = Analytics::UsageTrends::Measurement.identifiers[:billable_users]
::Analytics::UsageTrends::CounterJobWorker.new.perform(identifier, User.minimum(:id), User.maximum(:id), Time.zone.now)
```
1. Force an update of the historical max billable users:
```ruby
::HistoricalDataWorker.new.perform
```
### Maximum users
The number of _maximum users_ reflects the highest peak of billable users for the current license period.
@ -505,38 +548,3 @@ You might get the error `Attempt_Exceed_Limitation - Attempt exceed the limitati
This issue occurs when the credit card form is re-submitted too quickly within a specific time frame (three submissions within one minute or six submissions within one hour).
To resolve this issue, wait a few minutes and try the purchase process again.
### Check daily and historical billable users
Administrators can get a list of daily and historical billable users in your GitLab instance.
1. [Start a Rails console session](../../administration/operations/rails_console.md#starting-a-rails-console-session).
1. Count the number of users in the instance:
```ruby
User.billable.count
```
1. Get the historical maximum number of users on the instance from the past year:
```ruby
::HistoricalData.max_historical_user_count(from: 1.year.ago.beginning_of_day, to: Time.current.end_of_day)
```
### Update daily billable and historical users
Administrators can trigger a manual update of the daily and historical billable users in your GitLab instance.
1. [Start a Rails console session](../../administration/operations/rails_console.md#starting-a-rails-console-session).
1. Force an update of the daily billable users:
```ruby
identifier = Analytics::UsageTrends::Measurement.identifiers[:billable_users]
::Analytics::UsageTrends::CounterJobWorker.new.perform(identifier, User.minimum(:id), User.maximum(:id), Time.zone.now)
```
1. Force an update of the historical max billable users:
```ruby
::HistoricalDataWorker.new.perform
```

View File

@ -295,12 +295,13 @@ To create a thread:
> - Resolvable threads for issues [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/31114) in GitLab 16.3 [with a flag](../../administration/feature_flags.md) named `resolvable_issue_threads`. Disabled by default.
> - Resolvable threads for issues [enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/31114) in GitLab 16.4.
> - Resolvable threads for issues [generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/31114) in GitLab 16.7. Feature flag `resolvable_issue_threads` removed.
> - Resolvable threads for tasks, objectives, and key results [generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/458818) in GitLab 17.3.
You can resolve a thread when you want to finish a conversation.
Prerequisites:
- You must be in an issue or merge request.
- You must be in an issue, task, objective, key result, or merge request.
- You must have at least the Developer role or be the author of the issue or merge request.
To resolve a thread:

View File

@ -60,11 +60,12 @@ In the GitLab UI, GitLab Duo Chat knows about these areas:
In the IDEs, GitLab Duo Chat knows about these areas:
| Area | How to ask Chat |
|---------|------------------|
| Selected lines in the editor | With the lines selected, ask about `this code` or `this file`. Chat is not aware of the file; you must select the lines you want to ask about. |
| Epics | Ask about the URL. |
| Issues | Ask about the URL. |
| Area | How to ask Chat |
|-------------------------------|-----------------------|
| Selected lines in the editor | With the lines selected, ask about `this code` or `this file`. Chat is not aware of the file; you must select the lines you want to ask about. |
| Epics | Ask about the URL. |
| Issues | Ask about the URL. |
| Open files | Start working in a file, making sure that you have opened the files you want as used as context. For details, see [open tabs as context](../project/repository/code_suggestions/index.md#open-tabs-as-context). |
In addition, in the IDEs, when you use any of the slash commands,
like `/explain`, `/refactor`, `/fix`, or `/tests,` Duo Chat has access to the

View File

@ -104,11 +104,9 @@ you might write something like:
AI is non-deterministic, so you may not get the same suggestion every time with the same input.
To generate quality code, write clear, descriptive, specific tasks.
### Best practice examples
For use cases and best practices, follow the [GitLab Duo examples documentation](../../../gitlab_duo_examples.md).
#### Use open tabs as context
## Open tabs as context
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/464767) in GitLab 17.2 [with a flag](../../../../administration/feature_flags.md) named `advanced_context_resolver`. Disabled by default.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/462750) in GitLab 17.2 [with a flag](../../../../administration/feature_flags.md) named `code_suggestions_context`. Disabled by default.
@ -120,30 +118,54 @@ FLAG:
The availability of this feature is controlled by a feature flag.
For more information, see the history.
For better results from GitLab Duo Code Suggestions, ensure that Open Tabs Context is enabled in your IDE settings.
This feature uses the contents of the files currently open in your IDE to get more
accurate and relevant results from Code Suggestions. Like prompt engineering, these files
To get more accurate and relevant results from Code Suggestions and Code Generation, you can use
the contents of the files open in tabs in your IDE. Similar to prompt engineering, these files
give GitLab Duo more information about the standards and practices in your code project.
To get the most benefit from using your open tabs as context, open the files relevant to the code
you want to create, including configuration files. When you start work in a new file,
Code Suggestions offers you suggestions in the new file.
### Enable open tabs as context
Prerequisites:
- Requires GitLab 17.2 and later. Earlier GitLab versions that support Code Suggestions
cannot weight the content of open tabs more heavily than other files in your project.
- Requires a [supported code language](#advanced-context-supported-languages).
- GitLab Duo Code Suggestions must be enabled for your project.
- For GitLab self-managed instances, the `code_suggestions_context`and the
`advanced_context_resolver` [feature flags](../../../feature_flags.md) must be enabled.
- Use a supported code language:
- Code Completion: All configured languages.
- Code Generation: Go, Java, JavaScript, Kotlin, Python, Ruby, Rust, TypeScript (`.ts` and `.tsx` files),
Vue, and YAML.
1. Open the files you want to provide for context. Advanced Context uses the most recently
opened or changed files for context. If you dont want a file sent as additional context, close it.
1. To fine-tune your Code Generation results, add code comments to your file that explain
what you want to build. Code Generation treats your code comments like chat. Your code comments
update the `user_instruction`, and then improve the next results you receive.
::Tabs
As you work, GitLab Duo provides code suggestions that use your other open files
(within [truncation limits](#truncation-of-file-content))
as extra context.
:::TabTitle Visual Studio Code
1. Install the [GitLab Workflow extension version 4.14.2 or later](https://marketplace.visualstudio.com/items?itemName=GitLab.gitlab-workflow)
from the Visual Studio Marketplace.
1. Configure the [extension settings](https://gitlab.com/gitlab-org/gitlab-vscode-extension#extension-settings).
1. Enable the feature by turning on the `gitlab.aiAssistedCodeSuggestions.enabledSupportedLanguages` setting.
:::TabTitle JetBrains IDEs
For installation instructions for JetBrains IDEs, see the
[GitLab JetBrains Plugin documentation](https://gitlab.com/gitlab-org/editor-extensions/gitlab-jetbrains-plugin#toggle-sending-open-tabs-as-context).
::EndTabs
### Use open tabs as context
Open the files you want to provide for context:
- Open tabs uses the most recently opened or changed files.
- If you do not want a file used as additional context, close that file.
When you start working in a file, GitLab Duo uses your open files
as extra context, within [truncation limits](#truncation-of-file-content).
You can adjust your Code Generation results by adding code comments to your file
that explain what you want to build. Code Generation treats your code comments
like chat. Your code comments update the `user_instruction`, and then improve
the next results you receive.
### Related topics
To learn about the code that builds the prompt, see these files:
@ -151,19 +173,11 @@ To learn about the code that builds the prompt, see these files:
[`ee/lib/api/code_suggestions.rb`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/lib/api/code_suggestions.rb#L76)
in the `gitlab` repository.
- **Code Completion**:
[`ai_gateway/code_suggestions/processing/completions.py`](https://gitlab.com/gitlab-org/modelops/applied-ml/code-suggestions/ai-assist/-/blob/fcb3f485a8f047a86a8166aad81f93b6d82106a7/ai_gateway/code_suggestions/processing/completions.py#L273)
in the `modelops` repository.
[`ai_gateway/code_suggestions/processing/completions.py`](https://gitlab.com/gitlab-org/modelops/applied-ml/code-suggestions/ai-assist/-/blob/fcb3f485a8f047a86a8166aad81f93b6d82106a7/ai_gateway/code_suggestions/processing/completions.py#L273) in the `modelops` repository.
We'd love your feedback about the Advanced Context feature in
You can provide feedback about this feature in
[issue 258](https://gitlab.com/gitlab-org/editor-extensions/gitlab-lsp/-/issues/258).
### Advanced Context supported languages
The Advanced Context feature supports these languages:
- Code Completion: all configured languages.
- Code Generation: Go, Java, JavaScript, Kotlin, Python, Ruby, Rust, TypeScript (`.ts` and `.tsx` files), Vue, and YAML.
## Response time
Code Suggestions is powered by a generative AI model.

View File

@ -70,57 +70,6 @@ plugin support. Refer to the JetBrains documentation for specifics on your IDE.
For languages not listed in the table, Code Suggestions might not function as expected.
## Use open tabs as context
> - [Introduced](https://gitlab.com/gitlab-org/editor-extensions/gitlab-lsp/-/issues/206) in GitLab 17.2.
To enhance the accuracy and relevance of GitLab Duo Code Suggestions, enable the use of
open tabs as context in your IDE settings. This feature uses the contents of files most recently
opened or changed in your IDE to provide more tailored code suggestions, within certain truncation limits.
This extra context gives you:
- More accurate and relevant code suggestions
- Better alignment with your project's standards and practices
- Improved context for new file creation
Open tabs as context supports these languages:
- Code Completion: All configured languages.
- Code Generation: Go, Java, JavaScript, Kotlin, Python, Ruby, Rust, TypeScript (`.ts` and `.tsx` files),
Vue, and YAML.
## Enable open tabs as context
Prerequisites:
- Requires GitLab 17.1 or later.
- For GitLab self-managed instances, enable the `code_suggestions_context`and the
`advanced_context_resolver` [feature flags](../../../feature_flags.md).
- GitLab Duo Code Suggestions enabled for your project
- For Visual Studio Code, requires the GitLab Workflow extension, version 4.14.2 or later.
::Tabs
:::TabTitle Visual Studio Code
1. Install the [GitLab Workflow extension](https://marketplace.visualstudio.com/items?itemName=GitLab.gitlab-workflow)
from the Visual Studio Marketplace.
1. Configure the extension following the
[setup instructions](https://gitlab.com/gitlab-org/gitlab-vscode-extension#extension-settings).
1. Enable the feature by toggling the `gitlab.aiAssistedCodeSuggestions.enabledSupportedLanguages` setting.
:::TabTitle JetBrains IDEs
For installation instructions for JetBrains IDEs, see the
[GitLab JetBrains Plugin documentation](https://gitlab.com/gitlab-org/editor-extensions/gitlab-jetbrains-plugin#toggle-sending-open-tabs-as-context).
::EndTabs
When you're ready to start coding:
1. Open relevant files, including configuration files, to provide better context.
1. Close any files you don't want to be used as context.
## View multiple code suggestions
> - [Introduced](https://gitlab.com/gitlab-org/gitlab-vscode-extension/-/issues/1325) in GitLab 17.1.

View File

@ -612,3 +612,30 @@ Prerequisites:
ellipsis (**{ellipsis_v}**) and then select **Remove**.
Due to the bi-directional relationship, the relationship no longer appears in either item.
### Add a merge request and automatically close tasks
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/440851) in GitLab 17.3.
You can set a task to close when a merge request merges.
Prerequisites:
- You must have at least a Developer role for the project containing the merge request.
- You must have at least a Reporter role for the project containing the task.
1. Edit your merge request.
1. In the **Description** box, find and add the task.
- Use the [closing pattern](project/issues/managing_issues.md#closing-issues-automatically) that you would for adding a merge request to an issue.
- If your task is in the same project as your merge request, you can search for your task by typing <kbd>#</kbd> followed by the task's ID or title.
- If your task is in a different project, with a task open, copy the URL from the browser or
copy the task's reference by selecting the vertical ellipsis (**{ellipsis_v}**) in the upper-right corner, then **Copy Reference**.
The merge requests are now visible on the right sidebar, in the **Development** section.
You must use the exact closing pattern to add the merge request to the task. Other text will not work.
If [automatic issue closing](project/issues/managing_issues.md#disable-automatic-issue-closing) is enabled in your project settings, the task will be automatically closed when either:
- The added merge request is merged.
- A commit referencing a task with the closing pattern is committed to your project's default branch.

View File

@ -11,13 +11,15 @@ module Banzai
#
# Extends HTML::Pipeline::SanitizationFilter with common rules.
class BaseSanitizationFilter < HTML::Pipeline::SanitizationFilter
include Concerns::TimeoutFilterHandler
prepend Concerns::TimeoutFilterHandler
include Gitlab::Utils::StrongMemoize
extend Gitlab::Utils::SanitizeNodeLink
RENDER_TIMEOUT = 5.seconds
UNSAFE_PROTOCOLS = %w[data javascript vbscript].freeze
def call_with_timeout
def call
Sanitize.clean_node!(doc, allowlist)
end

View File

@ -6,7 +6,7 @@
# issue: https://gitlab.com/gitlab-org/gitlab/-/issues/454601
module Banzai
module Filter
class BlockquoteFenceLegacyFilter < TimeoutTextPipelineFilter
class BlockquoteFenceLegacyFilter < HTML::Pipeline::TextFilter
MARKDOWN_CODE_BLOCK_REGEX = %r{
(?<code>
# Code blocks:
@ -74,7 +74,7 @@ module Banzai
super text, context, result
end
def call_with_timeout
def call
return @text if MarkdownFilter.glfm_markdown?(context)
@text.gsub(REGEX) do

View File

@ -32,29 +32,30 @@ module Banzai
HTML
def call
return call_with_timeout if Gitlab::RenderTimeout.banzai_timeout_disabled?
return super if Gitlab::RenderTimeout.banzai_timeout_disabled?
Gitlab::RenderTimeout.timeout(foreground: render_timeout, background: render_timeout) { call_with_timeout }
Gitlab::RenderTimeout.timeout(foreground: render_timeout, background: render_timeout) { super }
rescue Timeout::Error => e
class_name = self.class.name.demodulize
Gitlab::ErrorTracking.track_exception(e, project_id: context[:project]&.id, class_name: class_name)
Gitlab::ErrorTracking.track_exception(e, project_id: context[:project]&.id, group_id: context[:group]&.id,
class_name: class_name)
# we've timed out, but some work may have already been completed,
# so return what we can
returned_timeout_value
end
def call_with_timeout
raise NotImplementedError
end
private
def render_timeout
return super if defined?(super)
RENDER_TIMEOUT
end
def returned_timeout_value
return super if defined?(super)
if is_a?(HTML::Pipeline::TextFilter)
text
else

View File

@ -3,13 +3,13 @@
module Banzai
module Filter
class CustomEmojiFilter < HTML::Pipeline::Filter
include Concerns::TimeoutFilterHandler
prepend Concerns::TimeoutFilterHandler
prepend Concerns::PipelineTimingCheck
include Gitlab::Utils::StrongMemoize
IGNORED_ANCESTOR_TAGS = %w[pre code tt].to_set
def call_with_timeout
def call
return doc unless resource_parent
doc.xpath('descendant-or-self::text()').each do |node|

View File

@ -7,12 +7,12 @@ module Banzai
#
# Based on HTML::Pipeline::EmojiFilter
class EmojiFilter < HTML::Pipeline::Filter
include Concerns::TimeoutFilterHandler
prepend Concerns::TimeoutFilterHandler
prepend Concerns::PipelineTimingCheck
IGNORED_ANCESTOR_TAGS = %w[pre code tt].to_set
def call_with_timeout
def call
@emoji_count = 0
doc.xpath('descendant-or-self::text()').each do |node|

View File

@ -4,14 +4,14 @@ module Banzai
module Filter
# HTML Filter to modify the attributes of external links
class ExternalLinkFilter < HTML::Pipeline::Filter
include Concerns::TimeoutFilterHandler
prepend Concerns::TimeoutFilterHandler
prepend Concerns::PipelineTimingCheck
SCHEMES = ['http', 'https', nil].freeze
RTLO = "\u202E"
ENCODED_RTLO = '%E2%80%AE'
def call_with_timeout
def call
links.each do |node|
# URI.parse does stricter checking on the url than Addressable,
# such as on `mailto:` links. Since we've been using it, do an

View File

@ -7,6 +7,7 @@ module Banzai
# similar functionality in reference filtering.
class AbstractReferenceFilter < ReferenceFilter
include CrossProjectReference
prepend Concerns::TimeoutFilterHandler
prepend Concerns::PipelineTimingCheck
RENDER_TIMEOUT = 2.seconds
@ -122,64 +123,53 @@ module Banzai
def call
return doc unless project || group || user
# protect against certain reference_patterns that are difficult to optimize
# against malicious input, such as Commit.reference_pattern
Gitlab::RenderTimeout.timeout(foreground: RENDER_TIMEOUT, background: RENDER_TIMEOUT) do
reference_cache.load_reference_cache(nodes) if respond_to?(:parent_records) && nodes.present?
reference_cache.load_reference_cache(nodes) if respond_to?(:parent_records) && nodes.present?
ref_pattern = object_reference_pattern
link_pattern = object_class.link_reference_pattern
ref_pattern = object_reference_pattern
link_pattern = object_class.link_reference_pattern
# Compile often used regexps only once outside of the loop
ref_pattern_anchor = /\A#{ref_pattern}\z/
link_pattern_start = /\A#{link_pattern}/
link_pattern_anchor = /\A#{link_pattern}\z/
# Compile often used regexps only once outside of the loop
ref_pattern_anchor = /\A#{ref_pattern}\z/
link_pattern_start = /\A#{link_pattern}/
link_pattern_anchor = /\A#{link_pattern}\z/
nodes.each_with_index do |node, index|
if text_node?(node) && ref_pattern
replace_text_when_pattern_matches(node, index, ref_pattern) do |content|
object_link_filter(content, ref_pattern)
nodes.each_with_index do |node, index|
if text_node?(node) && ref_pattern
replace_text_when_pattern_matches(node, index, ref_pattern) do |content|
object_link_filter(content, ref_pattern)
end
elsif element_node?(node)
yield_valid_link(node) do |link, inner_html|
if ref_pattern && link =~ ref_pattern_anchor
replace_link_node_with_href(node, index, link) do
object_link_filter(link, ref_pattern_anchor, link_content: inner_html)
end
next
end
elsif element_node?(node)
yield_valid_link(node) do |link, inner_html|
if ref_pattern && link =~ ref_pattern_anchor
replace_link_node_with_href(node, index, link) do
object_link_filter(link, ref_pattern_anchor, link_content: inner_html)
end
next unless link_pattern
next
if link == inner_html && inner_html =~ link_pattern_start
replace_link_node_with_text(node, index) do
object_link_filter(inner_html, link_pattern_start, link_reference: true)
end
next unless link_pattern
next
end
if link == inner_html && inner_html =~ link_pattern_start
replace_link_node_with_text(node, index) do
object_link_filter(inner_html, link_pattern_start, link_reference: true)
end
next
if link =~ link_pattern_anchor
replace_link_node_with_href(node, index, link) do
object_link_filter(link, link_pattern_anchor, link_content: inner_html, link_reference: true)
end
if link =~ link_pattern_anchor
replace_link_node_with_href(node, index, link) do
object_link_filter(link, link_pattern_anchor, link_content: inner_html, link_reference: true)
end
next
end
next
end
end
end
end
doc
rescue Timeout::Error => e
class_name = self.class.name.demodulize
Gitlab::ErrorTracking.track_exception(e, project_id: context[:project]&.id, class_name: class_name)
# we've timed out, but some work may have already been completed,
# so go ahead and return the document
doc
end

View File

@ -9,7 +9,8 @@ module Banzai
module Filter
# HTML Filter to highlight fenced code blocks
#
class SyntaxHighlightFilter < TimeoutHtmlPipelineFilter
class SyntaxHighlightFilter < HTML::Pipeline::Filter
prepend Concerns::TimeoutFilterHandler
prepend Concerns::PipelineTimingCheck
include Concerns::OutputSafety
@ -18,7 +19,7 @@ module Banzai
CSS = 'pre:not([data-kroki-style]) > code:only-child'
XPATH = Gitlab::Utils::Nokogiri.css_to_xpath(CSS).freeze
def call_with_timeout
def call
doc.xpath(XPATH).each do |node|
highlight_node(node)
end

View File

@ -1,31 +0,0 @@
# frozen_string_literal: true
module Banzai
module Filter
# HTML Filter that wraps a filter in a Gitlab::RenderTimeout.
# This way partial results can be returned, and the entire pipeline
# is not killed.
#
# This should not be used for any filter that must be allowed to complete,
# like a `ReferenceRedactorFilter`
#
class TimeoutHtmlPipelineFilter < HTML::Pipeline::Filter
RENDER_TIMEOUT = 10.seconds
def call
Gitlab::RenderTimeout.timeout(foreground: RENDER_TIMEOUT, background: RENDER_TIMEOUT) { call_with_timeout }
rescue Timeout::Error => e
class_name = self.class.name.demodulize
Gitlab::ErrorTracking.track_exception(e, project_id: context[:project]&.id, class_name: class_name)
# we've timed out, but some work may have already been completed,
# so go ahead and return the document
doc
end
def call_with_timeout
raise NotImplementedError
end
end
end
end

View File

@ -1,31 +0,0 @@
# frozen_string_literal: true
module Banzai
module Filter
# Text Filter that wraps a filter in a Gitlab::RenderTimeout.
# This way partial results can be returned, and the entire pipeline
# is not killed.
#
# This should not be used for any filter that must be allowed to complete,
# like a `ReferenceRedactorFilter`
#
class TimeoutTextPipelineFilter < HTML::Pipeline::TextFilter
RENDER_TIMEOUT = 10.seconds
def call
Gitlab::RenderTimeout.timeout(foreground: RENDER_TIMEOUT, background: RENDER_TIMEOUT) { call_with_timeout }
rescue Timeout::Error => e
class_name = self.class.name.demodulize
Gitlab::ErrorTracking.track_exception(e, project_id: context[:project]&.id, class_name: class_name)
# we've timed out, but some work may have already been completed,
# so go ahead and return the text
@text
end
def call_with_timeout
raise NotImplementedError
end
end
end
end

View File

@ -10,7 +10,7 @@ module Gitlab
include ::Gitlab::Config::Entry::Attributable
ALLOWED_KEYS = %i[coverage_format path].freeze
SUPPORTED_COVERAGE = %w[cobertura].freeze
SUPPORTED_COVERAGE = %w[cobertura jacoco].freeze
attributes ALLOWED_KEYS

View File

@ -11,6 +11,7 @@ module Gitlab
cobertura: ::Gitlab::Ci::Parsers::Coverage::Cobertura,
terraform: ::Gitlab::Ci::Parsers::Terraform::Tfplan,
accessibility: ::Gitlab::Ci::Parsers::Accessibility::Pa11y,
jacoco: ::Gitlab::Ci::Parsers::Coverage::Jacoco,
codequality: ::Gitlab::Ci::Parsers::Codequality::CodeClimate,
sast: ::Gitlab::Ci::Parsers::Security::Sast,
secret_detection: ::Gitlab::Ci::Parsers::Security::SecretDetection,

View File

@ -8,7 +8,7 @@ module Gitlab
InvalidXMLError = Class.new(Gitlab::Ci::Parsers::ParserError)
InvalidLineInformationError = Class.new(Gitlab::Ci::Parsers::ParserError)
def parse!(xml_data, coverage_report, project_path: nil, worktree_paths: nil)
def parse!(xml_data, coverage_report, project_path: nil, worktree_paths: nil, **_kwargs)
Nokogiri::XML::SAX::Parser.new(Documents::CoberturaDocument.new(coverage_report, project_path, worktree_paths)).parse(xml_data)
end
end

View File

@ -0,0 +1,78 @@
# frozen_string_literal: true
module Gitlab
module Ci
module Parsers
module Coverage
module Documents
class JacocoDocument < Nokogiri::XML::SAX::Document
PATH_TAGS = %w[group package sourcefile].freeze
def initialize(coverage_report, merge_request_file_paths)
@coverage_report = coverage_report
@merge_request_file_paths = merge_request_file_paths
@current_path_array = []
end
def error(error)
raise Jacoco::InvalidXMLError, "XML parsing failed with error: #{error}"
end
def start_element(node_name, attrs = [])
return unless node_name
node_attrs = attrs.to_h
if PATH_TAGS.include?(node_name) && node_attrs["name"].present?
current_path_array << unixify(node_attrs["name"])
elsif node_name == 'line'
parse_line(node_attrs)
end
end
def end_element(node_name)
# remove the element from the current path, as if leaving the current directory
return unless PATH_TAGS.include?(node_name)
current_path_array.pop
end
private
attr_accessor :coverage_report, :merge_request_file_paths,
:current_path_array
def parse_line(node_attrs)
coverage_data = { node_attrs.fetch('nr').to_i => node_attrs.fetch('ci').to_i }
coverage_report.add_file(matched_full_path, coverage_data)
rescue KeyError
raise Jacoco::InvalidLineInformationError, "Line information had invalid attributes"
end
def current_path
File.join(current_path_array)
end
# Jacoco reports only provide the relative path
# so we need to match the files against the ones changed on the MR
# and provide the full path in our reports
def matched_full_path
matched_path = merge_request_file_paths.find do |full_path|
full_path.include?(current_path)
end
Gitlab::AppLogger.info(message: "Missing merge request changes for #{current_path}") unless matched_path
matched_path
end
def unixify(path)
path.tr('\\', '/')
end
end
end
end
end
end
end

View File

@ -0,0 +1,24 @@
# frozen_string_literal: true
module Gitlab
module Ci
module Parsers
module Coverage
class Jacoco
InvalidXMLError = Class.new(Gitlab::Ci::Parsers::ParserError)
FeatureDisabledError = Class.new(Gitlab::Ci::Parsers::ParserError)
InvalidLineInformationError = Class.new(Gitlab::Ci::Parsers::ParserError)
def parse!(xml_data, coverage_report, project:, merge_request_paths:, **_kwargs)
unless Feature.enabled?(:jacoco_coverage_reports, project)
raise FeatureDisabledError, "Feature jacoco_coverage_reports is disabled for project #{project.full_name}"
end
Nokogiri::XML::SAX::Parser.new(Documents::JacocoDocument.new(coverage_report,
merge_request_paths)).parse(xml_data)
end
end
end
end
end
end

View File

@ -18,6 +18,8 @@ module Gitlab
# we are only interested in the coverage report from the root pipeline.
return coverage_report if @pipeline.child?
return coverage_report if merge_request_file_paths.empty?
coverage_report.tap do |coverage_report|
report_builds.find_each do |build|
build.each_report(::Ci::JobArtifact.file_types_for_report(:coverage)) do |file_type, blob|
@ -25,7 +27,9 @@ module Gitlab
blob,
coverage_report,
project_path: @pipeline.project.full_path,
worktree_paths: @pipeline.all_worktree_paths
worktree_paths: @pipeline.all_worktree_paths,
merge_request_paths: merge_request_file_paths,
project: @pipeline.project
)
end
end
@ -37,6 +41,17 @@ module Gitlab
def report_builds
@pipeline.latest_report_builds_in_self_and_project_descendants(::Ci::JobArtifact.of_report_type(:coverage))
end
def merge_request_file_paths
merge_request_paths = Set.new
@pipeline.merge_requests_as_head_pipeline.each do |merge_request|
merge_request_paths += merge_request.modified_paths
end
merge_request_paths
end
strong_memoize_attr :merge_request_file_paths
end
end
end

View File

@ -30,7 +30,8 @@ module QA
:import,
:import_status,
:import_error,
:description
:description,
:created_at
attribute :group do
Group.fabricate! do |group|
@ -577,7 +578,8 @@ module QA
:snippets_enabled,
:shared_runners_enabled,
:request_access_enabled,
:avatar_url
:avatar_url,
:created_at
)
end

View File

@ -39,7 +39,7 @@ module QA
toggle_local_requests(false)
end
it 'integrates and displays build status for MR pipeline in GitLab',
it 'integrates and displays build status for MR pipeline in GitLab', :blocking,
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347788' do
setup_project_integration

View File

@ -226,6 +226,16 @@ FactoryBot.define do
end
end
trait :jacoco do
file_type { :jacoco }
file_format { :gzip }
after(:build) do |artifact, evaluator|
artifact.file = fixture_file_upload(
Rails.root.join('spec/fixtures/jacoco/coverage.xml.gz'), 'application/x-gzip')
end
end
trait :terraform do
file_type { :terraform }
file_format { :raw }

View File

@ -0,0 +1,73 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!DOCTYPE report PUBLIC "-//JACOCO//DTD Report 1.1//EN" "report.dtd">
<report name="gitlab-jacoco-coverage-test">
<sessioninfo id="runner--azerasq-project-36665609-concurrent-0-54d28570" start="1654178605407" dump="1654178652125" />
<package name="org/acme">
<class name="org/acme/ExampleResource" sourcefilename="ExampleResource.java">
<method name="&lt;init&gt;" desc="()V" line="9">
<counter type="INSTRUCTION" missed="0" covered="3" />
<counter type="LINE" missed="0" covered="1" />
<counter type="COMPLEXITY" missed="0" covered="1" />
<counter type="METHOD" missed="0" covered="1" />
</method>
<method name="hello" desc="()Ljava/lang/String;" line="14">
<counter type="INSTRUCTION" missed="0" covered="2" />
<counter type="LINE" missed="0" covered="1" />
<counter type="COMPLEXITY" missed="0" covered="1" />
<counter type="METHOD" missed="0" covered="1" />
</method>
<counter type="INSTRUCTION" missed="0" covered="5" />
<counter type="LINE" missed="0" covered="2" />
<counter type="COMPLEXITY" missed="0" covered="2" />
<counter type="METHOD" missed="0" covered="2" />
<counter type="CLASS" missed="0" covered="1" />
</class>
<class name="org/acme/AnotherResource" sourcefilename="AnotherResource.java">
<method name="&lt;init&gt;" desc="()V" line="9">
<counter type="INSTRUCTION" missed="3" covered="0" />
<counter type="LINE" missed="1" covered="0" />
<counter type="COMPLEXITY" missed="1" covered="0" />
</counter type="METHOD" missed="1" covered="0" />
</method>
<method name="coucou" desc="()Ljava/lang/String;" line="14">
<counter type="INSTRUCTION" missed="2" covered="0" />
<counter type="LINE" missed="1" covered="0" />
<counter type="COMPLEXITY" missed="1" covered="0" />
<counter type="METHOD" missed="1" covered="0" />
</method>
<counter type="INSTRUCTION" missed="5" covered="0" />
<counter type="LINE" missed="2" covered="0" />
<counter type="COMPLEXITY" missed="2" covered="0" />
<counter type="METHOD" missed="2" covered="0" />
<counter type="CLASS" missed="1" covered="0" />
</class>
<sourcefile name="AnotherResource.java">
<line nr="9" mi="3" ci="0" mb="0" cb="0" />
<line nr="14" mi="2" ci="0" mb="0" cb="0" />
<counter type="INSTRUCTION" missed="5" covered="0" />
<counter type="LINE" missed="2" covered="0" />
<counter type="COMPLEXITY" missed="2" covered="0" />
<counter type="METHOD" missed="2" covered="0" />
<counter type="CLASS" missed="1" covered="0" />
</sourcefile>
<sourcefile name="ExampleResource.java">
<line mi="0" mb="0" cb="0" />
<lad nr="14" mi="0" mb="0" cb="0" />
<counter type="INSTRUCTION" missed="0" covered="5" />
<counter type="LINE" missed="0" covered="2" />
<counter type="COMPLEXITY" missed="0" covered="2" />
<counter type="METHOD" missed="0" covered="2" />
<counter type="CLASS" missed="0" covered="1" />
</sourcefile>
<counter type="INSTRUCTION" missed="5" covered="5" />
<counter type="LINE" missed="2" covered="2" />
<counter type="COMPLEXITY" missed="2" covered="2" />
<counter type="METHOD" missed="2" covered="2" />
<counter type="CLASS" missed="1" covered="1" />
</package>
<counter type="INSTRUCTION" missed="5" covered="5" />
<counter type="LINE" missed="2" covered="2" />
<counter type="COMPLEXITY" missed="2" covered="2" />
<counter type="METHOD" missed="2" covered="2" />
<counter type="CLASS" missed="1" covered="1" />
</report>

View File

@ -0,0 +1,73 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!DOCTYPE report PUBLIC "-//JACOCO//DTD Report 1.1//EN" "report.dtd">
<report name="gitlab-jacoco-coverage-test">
<sessioninfo id="runner--azerasq-project-36665609-concurrent-0-54d28570" start="1654178605407" dump="1654178652125" />
<package name="org/acme">
<class name="org/acme/ExampleResource" sourcefilename="ExampleResource.java">
<method name="&lt;init&gt;" desc="()V" line="9">
<counter type="INSTRUCTION" missed="0" covered="3" />
<counter type="LINE" missed="0" covered="1" />
<counter type="COMPLEXITY" missed="0" covered="1" />
<counter type="METHOD" missed="0" covered="1" />
</method>
<method name="hello" desc="()Ljava/lang/String;" line="14">
<counter type="INSTRUCTION" missed="0" covered="2" />
<counter type="LINE" missed="0" covered="1" />
<counter type="COMPLEXITY" missed="0" covered="1" />
<counter type="METHOD" missed="0" covered="1" />
</method>
<counter type="INSTRUCTION" missed="0" covered="5" />
<counter type="LINE" missed="0" covered="2" />
<counter type="COMPLEXITY" missed="0" covered="2" />
<counter type="METHOD" missed="0" covered="2" />
<counter type="CLASS" missed="0" covered="1" />
</class>
<class name="org/acme/AnotherResource" sourcefilename="AnotherResource.java">
<method name="&lt;init&gt;" desc="()V" line="9">
<counter type="INSTRUCTION" missed="3" covered="0" />
<counter type="LINE" missed="1" covered="0" />
<counter type="COMPLEXITY" missed="1" covered="0" />
<counter type="METHOD" missed="1" covered="0" />
</method>
<method name="coucou" desc="()Ljava/lang/String;" line="14">
<counter type="INSTRUCTION" missed="2" covered="0" />
<counter type="LINE" missed="1" covered="0" />
<counter type="COMPLEXITY" missed="1" covered="0" />
<counter type="METHOD" missed="1" covered="0" />
</method>
<counter type="INSTRUCTION" missed="5" covered="0" />
<counter type="LINE" missed="2" covered="0" />
<counter type="COMPLEXITY" missed="2" covered="0" />
<counter type="METHOD" missed="2" covered="0" />
<counter type="CLASS" missed="1" covered="0" />
</class>
<sourcefile name="AnotherResource.java">
<line nr="9" mi="3" ci="0" mb="0" cb="0" />
<line nr="14" mi="2" ci="0" mb="0" cb="0" />
<counter type="INSTRUCTION" missed="5" covered="0" />
<counter type="LINE" missed="2" covered="0" />
<counter type="COMPLEXITY" missed="2" covered="0" />
<counter type="METHOD" missed="2" covered="0" />
<counter type="CLASS" missed="1" covered="0" />
</sourcefile>
<sourcefile name="ExampleResource.java">
<line mi="0" mb="0" cb="0" />
<line nr="14" mi="0" mb="0" cb="0" />
<counter type="INSTRUCTION" missed="0" covered="5" />
<counter type="LINE" missed="0" covered="2" />
<counter type="COMPLEXITY" missed="0" covered="2" />
<counter type="METHOD" missed="0" covered="2" />
<counter type="CLASS" missed="0" covered="1" />
</sourcefile>
<counter type="INSTRUCTION" missed="5" covered="5" />
<counter type="LINE" missed="2" covered="2" />
<counter type="COMPLEXITY" missed="2" covered="2" />
<counter type="METHOD" missed="2" covered="2" />
<counter type="CLASS" missed="1" covered="1" />
</package>
<counter type="INSTRUCTION" missed="5" covered="5" />
<counter type="LINE" missed="2" covered="2" />
<counter type="COMPLEXITY" missed="2" covered="2" />
<counter type="METHOD" missed="2" covered="2" />
<counter type="CLASS" missed="1" covered="1" />
</report>

73
spec/fixtures/jacoco/coverage.xml vendored Normal file
View File

@ -0,0 +1,73 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!DOCTYPE report PUBLIC "-//JACOCO//DTD Report 1.1//EN" "report.dtd">
<report name="gitlab-jacoco-coverage-test">
<sessioninfo id="runner--azerasq-project-36665609-concurrent-0-54d28570" start="1654178605407" dump="1654178652125" />
<package name="org/acme">
<class name="org/acme/ExampleResource" sourcefilename="ExampleResource.java">
<method name="&lt;init&gt;" desc="()V" line="9">
<counter type="INSTRUCTION" missed="0" covered="3" />
<counter type="LINE" missed="0" covered="1" />
<counter type="COMPLEXITY" missed="0" covered="1" />
<counter type="METHOD" missed="0" covered="1" />
</method>
<method name="hello" desc="()Ljava/lang/String;" line="14">
<counter type="INSTRUCTION" missed="0" covered="2" />
<counter type="LINE" missed="0" covered="1" />
<counter type="COMPLEXITY" missed="0" covered="1" />
<counter type="METHOD" missed="0" covered="1" />
</method>
<counter type="INSTRUCTION" missed="0" covered="5" />
<counter type="LINE" missed="0" covered="2" />
<counter type="COMPLEXITY" missed="0" covered="2" />
<counter type="METHOD" missed="0" covered="2" />
<counter type="CLASS" missed="0" covered="1" />
</class>
<class name="org/acme/AnotherResource" sourcefilename="AnotherResource.java">
<method name="&lt;init&gt;" desc="()V" line="9">
<counter type="INSTRUCTION" missed="3" covered="0" />
<counter type="LINE" missed="1" covered="0" />
<counter type="COMPLEXITY" missed="1" covered="0" />
<counter type="METHOD" missed="1" covered="0" />
</method>
<method name="coucou" desc="()Ljava/lang/String;" line="14">
<counter type="INSTRUCTION" missed="2" covered="0" />
<counter type="LINE" missed="1" covered="0" />
<counter type="COMPLEXITY" missed="1" covered="0" />
<counter type="METHOD" missed="1" covered="0" />
</method>
<counter type="INSTRUCTION" missed="5" covered="0" />
<counter type="LINE" missed="2" covered="0" />
<counter type="COMPLEXITY" missed="2" covered="0" />
<counter type="METHOD" missed="2" covered="0" />
<counter type="CLASS" missed="1" covered="0" />
</class>
<sourcefile name="AnotherResource.java">
<line nr="9" mi="3" ci="0" mb="0" cb="0" />
<line nr="14" mi="2" ci="0" mb="0" cb="0" />
<counter type="INSTRUCTION" missed="5" covered="0" />
<counter type="LINE" missed="2" covered="0" />
<counter type="COMPLEXITY" missed="2" covered="0" />
<counter type="METHOD" missed="2" covered="0" />
<counter type="CLASS" missed="1" covered="0" />
</sourcefile>
<sourcefile name="ExampleResource.java">
<line nr="9" mi="0" ci="3" mb="0" cb="0" />
<line nr="14" mi="0" ci="2" mb="0" cb="0" />
<counter type="INSTRUCTION" missed="0" covered="5" />
<counter type="LINE" missed="0" covered="2" />
<counter type="COMPLEXITY" missed="0" covered="2" />
<counter type="METHOD" missed="0" covered="2" />
<counter type="CLASS" missed="0" covered="1" />
</sourcefile>
<counter type="INSTRUCTION" missed="5" covered="5" />
<counter type="LINE" missed="2" covered="2" />
<counter type="COMPLEXITY" missed="2" covered="2" />
<counter type="METHOD" missed="2" covered="2" />
<counter type="CLASS" missed="1" covered="1" />
</package>
<counter type="INSTRUCTION" missed="5" covered="5" />
<counter type="LINE" missed="2" covered="2" />
<counter type="COMPLEXITY" missed="2" covered="2" />
<counter type="METHOD" missed="2" covered="2" />
<counter type="CLASS" missed="1" covered="1" />
</report>

BIN
spec/fixtures/jacoco/coverage.xml.gz vendored Normal file

Binary file not shown.

View File

@ -3,23 +3,20 @@ import Vue, { nextTick } from 'vue';
import Vuex from 'vuex';
import VueApollo from 'vue-apollo';
import { GlTab, GlTabs, GlModal } from '@gitlab/ui';
import { createAlert } from '~/alert';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import setWindowLocation from 'helpers/set_window_location_helper';
import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { stubComponent, RENDER_ALL_SLOTS_TEMPLATE } from 'helpers/stub_component';
import PlaceholdersTabApp from '~/members/placeholders/components/app.vue';
import PlaceholdersTable from '~/members/placeholders/components/placeholders_table.vue';
import CsvUploadModal from '~/members/placeholders/components/csv_upload_modal.vue';
import importSourceUsersQuery from '~/members/placeholders/graphql/queries/import_source_users.query.graphql';
import { MEMBERS_TAB_TYPES } from '~/members/constants';
import setWindowLocation from 'helpers/set_window_location_helper';
import {
mockSourceUsersQueryResponse,
mockSourceUsersFailedStatusResponse,
mockSourceUsers,
pagination,
} from '../mock_data';
PLACEHOLDER_STATUS_FAILED,
QUERY_PARAM_FAILED,
PLACEHOLDER_USER_STATUS,
} from '~/import_entities/import_groups/constants';
import { mockSourceUsersQueryResponse, mockSourceUsers, pagination } from '../mock_data';
Vue.use(Vuex);
Vue.use(VueApollo);
@ -30,15 +27,16 @@ describe('PlaceholdersTabApp', () => {
let store;
let mockApollo;
const mockGroup = {
path: 'imported-group',
name: 'Imported group',
};
const sourceUsersQueryHandler = jest.fn().mockResolvedValue(mockSourceUsersQueryResponse());
const $toast = {
show: jest.fn(),
};
const mockGroup = {
path: 'imported-group',
name: 'Imported group',
};
const createComponent = ({
queryHandler = sourceUsersQueryHandler,
mountFn = shallowMountExtended,
@ -60,8 +58,8 @@ describe('PlaceholdersTabApp', () => {
apolloProvider: mockApollo,
store,
provide: {
group: mockGroup,
reassignmentCsvDownloadPath: 'foo/bar',
group: mockGroup,
},
mocks: { $toast },
stubs: {
@ -78,7 +76,8 @@ describe('PlaceholdersTabApp', () => {
const findTabs = () => wrapper.findComponent(GlTabs);
const findTabAt = (index) => wrapper.findAllComponents(GlTab).at(index);
const findPlaceholdersTable = () => wrapper.findComponent(PlaceholdersTable);
const findUnassignedTable = () => wrapper.findByTestId('placeholders-table-unassigned');
const findReassignedTable = () => wrapper.findByTestId('placeholders-table-reassigned');
const findReassignCsvButton = () => wrapper.findByTestId('reassign-csv-button');
const findCsvModal = () => wrapper.findComponent(CsvUploadModal);
@ -105,7 +104,7 @@ describe('PlaceholdersTabApp', () => {
createComponent();
await nextTick();
findPlaceholdersTable().vm.$emit('confirm', mockSourceUser);
findUnassignedTable().vm.$emit('confirm', mockSourceUser);
await nextTick();
});
@ -123,152 +122,40 @@ describe('PlaceholdersTabApp', () => {
});
});
describe('when sourceUsers query is loading', () => {
it('renders placeholders table as loading', () => {
describe('passes the correct queryStatuses to PlaceholdersTable', () => {
it('awaiting Reassignment - when the url includes the query param failed', () => {
setWindowLocation(`?status=${QUERY_PARAM_FAILED}`);
createComponent();
expect(findPlaceholdersTable().props('isLoading')).toBe(true);
});
});
describe('when sourceUsers query fails', () => {
beforeEach(async () => {
const sourceUsersFailedQueryHandler = jest.fn().mockRejectedValue(new Error('GraphQL error'));
createComponent({
queryHandler: sourceUsersFailedQueryHandler,
});
await waitForPromises();
});
it('creates an alert', () => {
expect(createAlert).toHaveBeenCalledWith({
message: 'There was a problem fetching placeholder users.',
const placeholdersTable = findUnassignedTable();
expect(placeholdersTable.props()).toMatchObject({
queryStatuses: [PLACEHOLDER_STATUS_FAILED],
});
});
});
describe('when sourceUsers query succeeds', () => {
beforeEach(async () => {
it('awaiting Reassignment - when the url does not include query param', () => {
createComponent();
await waitForPromises();
});
it('fetches sourceUsers', () => {
expect(sourceUsersQueryHandler).toHaveBeenCalledTimes(1);
expect(sourceUsersQueryHandler).toHaveBeenCalledWith({
after: null,
before: null,
fullPath: mockGroup.path,
first: 20,
statuses: [],
const placeholdersTable = findUnassignedTable();
expect(placeholdersTable.props()).toMatchObject({
queryStatuses: PLACEHOLDER_USER_STATUS.UNASSIGNED,
});
});
it('renders placeholders table', () => {
const sourceUsers = mockSourceUsersQueryResponse().data.namespace.importSourceUsers;
it('reassigned', () => {
createComponent();
expect(findPlaceholdersTable().props()).toMatchObject({
isLoading: false,
items: sourceUsers.nodes,
pageInfo: sourceUsers.pageInfo,
});
});
});
describe('when sourceUsers query succeeds and has pagination', () => {
const sourceUsersPaginatedQueryHandler = jest.fn();
const mockPageInfo = {
endCursor: 'end834',
hasNextPage: true,
hasPreviousPage: true,
startCursor: 'start971',
};
beforeEach(async () => {
sourceUsersPaginatedQueryHandler
.mockResolvedValueOnce(mockSourceUsersQueryResponse({ pageInfo: mockPageInfo }))
.mockResolvedValueOnce(mockSourceUsersQueryResponse());
createComponent({
queryHandler: sourceUsersPaginatedQueryHandler,
});
await waitForPromises();
});
describe('when "prev" event is emitted', () => {
beforeEach(() => {
findPlaceholdersTable().vm.$emit('prev');
});
it('fetches sourceUsers with previous results', () => {
expect(sourceUsersPaginatedQueryHandler).toHaveBeenCalledTimes(2);
expect(sourceUsersPaginatedQueryHandler).toHaveBeenCalledWith(
expect.objectContaining({
after: null,
before: mockPageInfo.startCursor,
last: 20,
}),
);
});
});
describe('when "next" event is emitted', () => {
beforeEach(() => {
findPlaceholdersTable().vm.$emit('next');
});
it('fetches sourceUsers with next results', () => {
expect(sourceUsersPaginatedQueryHandler).toHaveBeenCalledTimes(2);
expect(sourceUsersPaginatedQueryHandler).toHaveBeenCalledWith(
expect.objectContaining({
after: mockPageInfo.endCursor,
before: null,
first: 20,
}),
);
});
});
});
describe('correctly filters users', () => {
const sourceUsersFailureQueryHandler = jest
.fn()
.mockResolvedValue(mockSourceUsersFailedStatusResponse);
beforeEach(async () => {
setWindowLocation('?status=failed');
createComponent({ queryHandler: sourceUsersFailureQueryHandler });
await waitForPromises();
});
it('when the url includes the query param failed', () => {
const sourceUsersWithFailedStatus =
mockSourceUsersFailedStatusResponse.data.namespace.importSourceUsers;
const tableProps = findPlaceholdersTable().props();
expect(findPlaceholdersTable().props()).toMatchObject({
isLoading: false,
items: sourceUsersWithFailedStatus.nodes,
pageInfo: sourceUsersWithFailedStatus.pageInfo,
});
expect(tableProps.items.length).toBe(1);
expect(tableProps.items[0].status).toBe('FAILED');
expect(sourceUsersFailureQueryHandler).toHaveBeenCalledTimes(1);
expect(sourceUsersFailureQueryHandler).toHaveBeenCalledWith({
after: null,
before: null,
fullPath: mockGroup.path,
first: 20,
statuses: ['FAILED'],
const placeholdersTable = findReassignedTable();
expect(placeholdersTable.props()).toMatchObject({
reassigned: true,
queryStatuses: PLACEHOLDER_USER_STATUS.REASSIGNED,
});
});
});
describe('reassign CSV button', () => {
it('renders the button and the modal', () => {
createComponent();
createComponent({ mountFn: mountExtended });
expect(findReassignCsvButton().exists()).toBe(true);
expect(findCsvModal().exists()).toBe(true);
@ -276,7 +163,6 @@ describe('PlaceholdersTabApp', () => {
it('shows modal when button is clicked', async () => {
createComponent({ mountFn: mountExtended });
findReassignCsvButton().trigger('click');
await nextTick();

View File

@ -1,27 +1,58 @@
import Vue from 'vue';
import Vue, { nextTick } from 'vue';
// eslint-disable-next-line no-restricted-imports
import Vuex from 'vuex';
import VueApollo from 'vue-apollo';
import { mount, shallowMount } from '@vue/test-utils';
import { GlAvatarLabeled, GlBadge, GlKeysetPagination, GlLoadingIcon, GlTable } from '@gitlab/ui';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import createMockApollo from 'helpers/mock_apollo_helper';
import { stubComponent } from 'helpers/stub_component';
import PlaceholdersTable from '~/members/placeholders/components/placeholders_table.vue';
import PlaceholderActions from '~/members/placeholders/components/placeholder_actions.vue';
import { mockSourceUsers } from '../mock_data';
import { createAlert } from '~/alert';
import waitForPromises from 'helpers/wait_for_promises';
import setWindowLocation from 'helpers/set_window_location_helper';
import {
PLACEHOLDER_STATUS_FAILED,
QUERY_PARAM_FAILED,
PLACEHOLDER_USER_STATUS,
} from '~/import_entities/import_groups/constants';
import importSourceUsersQuery from '~/members/placeholders/graphql/queries/import_source_users.query.graphql';
import { mockSourceUsersQueryResponse, mockSourceUsers } from '../mock_data';
Vue.use(Vuex);
Vue.use(VueApollo);
jest.mock('~/alert');
describe('PlaceholdersTable', () => {
let wrapper;
let mockApollo;
const defaultProps = {
isLoading: false,
items: mockSourceUsers,
const mockGroup = {
path: 'imported-group',
name: 'Imported group',
};
const createComponent = ({ mountFn = shallowMount, props = {} } = {}) => {
mockApollo = createMockApollo();
const defaultProps = {
queryStatuses: PLACEHOLDER_USER_STATUS.UNASSIGNED,
reassigned: false,
};
const sourceUsersQueryHandler = jest.fn().mockResolvedValue(mockSourceUsersQueryResponse());
const $toast = {
show: jest.fn(),
};
const createComponent = ({
mountFn = shallowMount,
queryHandler = sourceUsersQueryHandler,
props = {},
options = {},
} = {}) => {
mockApollo = createMockApollo([[importSourceUsersQuery, queryHandler]]);
wrapper = mountFn(PlaceholdersTable, {
apolloProvider: mockApollo,
@ -29,9 +60,14 @@ describe('PlaceholdersTable', () => {
...defaultProps,
...props,
},
provide: {
group: mockGroup,
},
mocks: { $toast },
directives: {
GlTooltip: createMockDirective('gl-tooltip'),
},
...options,
});
};
@ -44,111 +80,135 @@ describe('PlaceholdersTable', () => {
.props('fields')
.map((f) => f.label);
it('renders table', () => {
createComponent({ mountFn: mount });
expect(findTable().exists()).toBe(true);
expect(findTableRows().length).toBe(mockSourceUsers.length);
expect(findTableFields()).toEqual([
'Placeholder user',
'Source',
'Reassignment status',
'Reassign placeholder to',
]);
});
it('renders loading icon when table is loading', () => {
createComponent({
props: { isLoading: true },
});
expect(findLoadingIcon().exists()).toBe(true);
});
it('renders avatar for placeholder user', () => {
createComponent({ mountFn: mount });
const avatar = findTableRows().at(0).findComponent(GlAvatarLabeled);
const { placeholderUser } = mockSourceUsers[0];
expect(avatar.props()).toMatchObject({
label: placeholderUser.name,
subLabel: `@${placeholderUser.username}`,
});
expect(avatar.attributes('src')).toBe(placeholderUser.avatarUrl);
});
it('renders source info', () => {
createComponent({ mountFn: mount });
expect(findTableRows().at(0).text()).toContain(mockSourceUsers[0].sourceHostname);
expect(findTableRows().at(0).text()).toContain(mockSourceUsers[0].sourceUsername);
});
it('renders status badge with tooltip', () => {
createComponent({ mountFn: mount });
const firstRow = findTableRows().at(0);
const badge = firstRow.findComponent(GlBadge);
const badgeTooltip = getBinding(badge.element, 'gl-tooltip');
expect(badge.text()).toBe('Not started');
expect(badgeTooltip.value).toBe('Reassignment has not started.');
});
it('renders actions when item is not reassigned', () => {
createComponent({ mountFn: mount });
const firstRow = findTableRows().at(0);
const actions = firstRow.findComponent(PlaceholderActions);
expect(actions.props('sourceUser')).toEqual(mockSourceUsers[0]);
});
it('renders avatar for placeholderUser when item status is KEEP_AS_PLACEHOLDER', () => {
createComponent({ mountFn: mount });
const reassignedItemRow = findTableRows().at(5);
const actionsAvatar = reassignedItemRow.findAllComponents(GlAvatarLabeled).at(1);
const { placeholderUser } = mockSourceUsers[5];
expect(actionsAvatar.props()).toMatchObject({
label: placeholderUser.name,
subLabel: `@${placeholderUser.username}`,
describe('when sourceUsers query is loading', () => {
it('renders table as loading', () => {
createComponent();
expect(findLoadingIcon().exists()).toBe(true);
});
});
it('renders avatar for reassignToUser when item status is COMPLETED', () => {
createComponent({ mountFn: mount });
describe('when sourceUsers query fails', () => {
beforeEach(async () => {
const sourceUsersFailedQueryHandler = jest.fn().mockRejectedValue(new Error('GraphQL error'));
const reassignedItemRow = findTableRows().at(6);
const actionsAvatar = reassignedItemRow.findAllComponents(GlAvatarLabeled).at(1);
const { reassignToUser } = mockSourceUsers[6];
expect(actionsAvatar.props()).toMatchObject({
label: reassignToUser.name,
subLabel: `@${reassignToUser.username}`,
});
});
describe('when is "Re-assigned" table variant', () => {
beforeEach(() => {
createComponent({
props: {
reassigned: true,
},
queryHandler: sourceUsersFailedQueryHandler,
});
await waitForPromises();
});
it('creates an alert', () => {
expect(createAlert).toHaveBeenCalledWith({
message: 'There was a problem fetching placeholder users.',
});
});
});
describe('when sourceUsers query succeeds', () => {
beforeEach(async () => {
createComponent({
mountFn: mount,
});
await waitForPromises();
});
it('fetches sourceUsers', () => {
expect(sourceUsersQueryHandler).toHaveBeenCalledTimes(1);
expect(sourceUsersQueryHandler).toHaveBeenCalledWith({
after: null,
before: null,
fullPath: mockGroup.path,
first: 20,
statuses: PLACEHOLDER_USER_STATUS.UNASSIGNED,
});
});
it('renders table', () => {
expect(findTable().exists()).toBe(true);
it('renders table', async () => {
await waitForPromises();
expect(findLoadingIcon().exists()).toBe(false);
expect(findTableRows()).toHaveLength(mockSourceUsers.length);
expect(findTableFields()).toEqual([
'Placeholder user',
'Source',
'Reassignment status',
'Reassigned to',
'Reassign placeholder to',
]);
});
it('renders avatar for placeholder user', async () => {
await waitForPromises();
const avatar = findTableRows().at(0).findComponent(GlAvatarLabeled);
const { placeholderUser } = mockSourceUsers[0];
expect(avatar.props()).toMatchObject({
label: placeholderUser.name,
subLabel: `@${placeholderUser.username}`,
});
expect(avatar.attributes('src')).toBe(placeholderUser.avatarUrl);
});
it('renders source info', async () => {
await waitForPromises();
expect(findTableRows().at(0).text()).toContain(mockSourceUsers[0].sourceHostname);
expect(findTableRows().at(0).text()).toContain(mockSourceUsers[0].sourceUsername);
});
it('renders status badge with tooltip', async () => {
await waitForPromises();
const firstRow = findTableRows().at(0);
const badge = firstRow.findComponent(GlBadge);
const badgeTooltip = getBinding(badge.element, 'gl-tooltip');
expect(badge.text()).toBe('Not started');
expect(badgeTooltip.value).toBe('Reassignment has not started.');
});
it('renders avatar for placeholderUser when item status is KEEP_AS_PLACEHOLDER', async () => {
await waitForPromises();
const reassignedItemRow = findTableRows().at(5);
const actionsAvatar = reassignedItemRow.findAllComponents(GlAvatarLabeled).at(1);
const { placeholderUser } = mockSourceUsers[5];
expect(actionsAvatar.props()).toMatchObject({
label: placeholderUser.name,
subLabel: `@${placeholderUser.username}`,
});
});
it('renders actions when item is not reassigned', async () => {
await waitForPromises();
const firstRow = findTableRows().at(0);
const actions = firstRow.findComponent(PlaceholderActions);
expect(actions.props('sourceUser')).toEqual(mockSourceUsers[0]);
});
it('renders avatar for reassignToUser when item status is COMPLETED', async () => {
await waitForPromises();
const reassignedItemRow = findTableRows().at(6);
const actionsAvatar = reassignedItemRow.findAllComponents(GlAvatarLabeled).at(1);
const { reassignToUser } = mockSourceUsers[6];
expect(actionsAvatar.props()).toMatchObject({
label: reassignToUser.name,
subLabel: `@${reassignToUser.username}`,
});
});
it('table actions emit "confirm" event with item', () => {
const actions = findTableRows().at(2).findComponent(PlaceholderActions);
actions.vm.$emit('confirm');
expect(wrapper.emitted('confirm')[0]).toEqual([mockSourceUsers[2]]);
});
});
describe('pagination', () => {
@ -161,63 +221,149 @@ describe('PlaceholdersTable', () => {
`(
'when hasNextPage=$hasNextPage and hasPreviousPage=$hasPreviousPage',
({ hasNextPage, hasPreviousPage, expectPagination }) => {
beforeEach(() => {
createComponent({
props: {
beforeEach(async () => {
const customHandler = jest.fn().mockResolvedValue(
mockSourceUsersQueryResponse({
pageInfo: {
hasNextPage,
hasPreviousPage,
},
},
}),
);
createComponent({
queryHandler: customHandler,
});
await nextTick();
});
it(`${expectPagination ? 'renders' : 'does not render'} pagination`, () => {
expect(findPagination().exists()).toBe(expectPagination);
});
},
);
it('emits "prev" event', () => {
createComponent({
props: {
pageInfo: {
hasPreviousPage: true,
},
},
describe('buttons', () => {
const mockPageInfo = {
endCursor: 'end834',
hasNextPage: true,
hasPreviousPage: true,
startCursor: 'start971',
};
const customHandler = jest.fn().mockResolvedValue(
mockSourceUsersQueryResponse({
pageInfo: mockPageInfo,
}),
);
beforeEach(async () => {
createComponent({
mountFn: mount,
queryHandler: customHandler,
});
await waitForPromises();
});
findPagination().vm.$emit('prev');
expect(wrapper.emitted('prev')[0]).toEqual([]);
});
it('emits "next" event', () => {
createComponent({
props: {
pageInfo: {
hasNextPage: true,
},
},
it('requests the next page on "prev" click with the correct data', async () => {
const paginated = findPagination();
await paginated.vm.$emit('prev');
expect(customHandler).toHaveBeenCalledTimes(2);
expect(customHandler).toHaveBeenCalledWith(
expect.objectContaining({
after: null,
before: mockPageInfo.startCursor,
last: 20,
}),
);
});
findPagination().vm.$emit('next');
expect(wrapper.emitted('next')[0]).toEqual([]);
it('requests the next page on "next" click the correct data', async () => {
const paginated = findPagination();
await paginated.vm.$emit('next');
expect(customHandler).toHaveBeenCalledTimes(2);
expect(customHandler).toHaveBeenCalledWith(
expect.objectContaining({
after: mockPageInfo.endCursor,
before: null,
first: 20,
}),
);
});
});
});
describe('actions events', () => {
beforeEach(() => {
createComponent({ mountFn: mount });
describe('correctly filters users with failed status', () => {
const sourceUsersFailureQueryHandler = jest
.fn()
.mockResolvedValue(mockSourceUsersQueryResponse({ nodes: [mockSourceUsers[4]] }));
beforeEach(async () => {
setWindowLocation(`?status=${QUERY_PARAM_FAILED}`);
await waitForPromises();
createComponent({
mountFn: shallowMount,
queryHandler: sourceUsersFailureQueryHandler,
props: { queryStatuses: [PLACEHOLDER_STATUS_FAILED] },
options: {
stubs: {
GlTable: stubComponent(GlTable, {
props: ['fields', 'items', 'busy'],
}),
},
},
});
await waitForPromises();
});
it('emits "confirm" event with item', () => {
const actions = findTableRows().at(2).findComponent(PlaceholderActions);
it('when the url includes the query param failed', () => {
expect(findTable().props('items')).toHaveLength(1);
expect(findTable().props('items')[0].status).toBe(PLACEHOLDER_STATUS_FAILED);
expect(sourceUsersFailureQueryHandler).toHaveBeenCalledTimes(1);
expect(sourceUsersFailureQueryHandler).toHaveBeenCalledWith({
after: null,
before: null,
fullPath: mockGroup.path,
first: 20,
statuses: [PLACEHOLDER_STATUS_FAILED],
});
});
});
actions.vm.$emit('confirm');
describe('when is "Re-assigned" table variant', () => {
const reassignedQueryHandler = jest
.fn()
.mockResolvedValue(
mockSourceUsersQueryResponse({ nodes: [mockSourceUsers[5], mockSourceUsers[6]] }),
);
expect(wrapper.emitted('confirm')[0]).toEqual([mockSourceUsers[2]]);
beforeEach(async () => {
createComponent({
mountFn: shallowMount,
queryHandler: reassignedQueryHandler,
props: { reassigned: true, queryStatus: PLACEHOLDER_USER_STATUS.REASSIGNED },
options: {
stubs: {
GlTable: stubComponent(GlTable, {
props: ['fields', 'items', 'busy'],
}),
},
},
});
await waitForPromises();
});
it('renders table', () => {
expect(findTable().exists()).toBe(true);
expect(findTableFields()).toEqual([
'Placeholder user',
'Source',
'Reassignment status',
'Reassigned to',
]);
});
it('only displays items that have been already assigned', () => {
expect(findTable().props('items')).toEqual([mockSourceUsers[5], mockSourceUsers[6]]);
});
});
});

View File

@ -63,14 +63,14 @@ export const mockSourceUsers = [
}),
];
export const mockSourceUsersQueryResponse = ({ pageInfo = {} } = {}) => ({
export const mockSourceUsersQueryResponse = ({ nodes = mockSourceUsers, pageInfo = {} } = {}) => ({
data: {
namespace: {
__typename: 'Namespace',
id: 'gid://gitlab/Group/1',
importSourceUsers: {
__typename: 'ImportSourceUserConnection',
nodes: mockSourceUsers,
nodes,
pageInfo: {
__typename: 'PageInfo',
hasNextPage: false,
@ -84,26 +84,6 @@ export const mockSourceUsersQueryResponse = ({ pageInfo = {} } = {}) => ({
},
});
export const mockSourceUsersFailedStatusResponse = {
data: {
namespace: {
__typename: 'Namespace',
id: 'gid://gitlab/Group/1',
importSourceUsers: {
__typename: 'ImportSourceUserConnection',
nodes: [mockSourceUsers[4]],
pageInfo: {
__typename: 'PageInfo',
hasNextPage: false,
hasPreviousPage: false,
startCursor: '',
endCursor: '',
},
},
},
},
};
export const mockReassignMutationResponse = {
data: {
importSourceUserReassign: {

View File

@ -1,6 +1,6 @@
import { GlSprintf, GlSkeletonLoader, GlButton } from '@gitlab/ui';
import { GlSprintf, GlSkeletonLoader, GlButton, GlBadge } from '@gitlab/ui';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { createMockDirective } from 'helpers/vue_mock_directive';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import { mockTracking } from 'helpers/tracking_helper';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import DeleteButton from '~/packages_and_registries/container_registry/explorer/components/delete_button.vue';
@ -34,20 +34,23 @@ describe('Image List Row', () => {
const findListItemComponent = () => wrapper.findComponent(ListItem);
const findShowFullPathButton = () => wrapper.findComponent(GlButton);
const findPublishMessage = () => wrapper.findComponent(PublishMessage);
const findProtectedBadge = () => wrapper.findComponent(GlBadge);
const mountComponent = ({ props = {}, config = {} } = {}) => {
const mountComponent = ({ props = {}, config = {}, provide = {} } = {}) => {
wrapper = shallowMountExtended(Component, {
stubs: {
RouterLink,
ListItem,
GlButton,
GlSprintf,
GlBadge,
},
propsData: {
item,
...props,
},
provide: {
...provide,
config: {
...config,
},
@ -270,4 +273,54 @@ describe('Image List Row', () => {
});
});
});
describe('badge "protected"', () => {
const mountComponentForProtectedBadge = ({
itemProtectionRuleExists = true,
glFeaturesContainerRegistryProtectedContainers = true,
} = {}) => {
return mountComponent({
props: { item: { ...item, protectionRuleExists: itemProtectionRuleExists } },
provide: {
glFeatures: {
containerRegistryProtectedContainers: glFeaturesContainerRegistryProtectedContainers,
},
},
});
};
describe('when image has new badge', () => {
beforeEach(() => {
mountComponentForProtectedBadge();
});
it('shows badge', () => {
expect(findProtectedBadge().text()).toBe('protected');
});
it('binds tooltip directive', () => {
const ProtectedBadgeTooltipBinding = getBinding(findProtectedBadge().element, 'gl-tooltip');
expect(ProtectedBadgeTooltipBinding).toBeDefined();
expect(findProtectedBadge().attributes('title')).toMatch(
'A protection rule exists for this container repository.',
);
});
});
describe('when image does not have new badge', () => {
it('does not show badge', () => {
mountComponentForProtectedBadge({ itemProtectionRuleExists: false });
expect(findProtectedBadge().exists()).toBe(false);
});
});
describe('when feature flag "containerRegistryProtectedContainers" disabled', () => {
it('does not show badge', () => {
mountComponentForProtectedBadge({ glFeaturesContainerRegistryProtectedContainers: false });
expect(findProtectedBadge().exists()).toBe(false);
});
});
});
});

View File

@ -22,6 +22,7 @@ export const imagesListResponse = [
path: 'GITLAB-TEST',
webUrl: 'http://localhost:3000/gitlab-org/gitlab-test',
},
protectionRuleExists: false,
...userPermissionsData,
},
{
@ -41,6 +42,7 @@ export const imagesListResponse = [
path: 'GITLAB-TEST',
webUrl: 'http://localhost:3000/gitlab-org/gitlab-test',
},
protectionRuleExists: false,
...userPermissionsData,
},
];

View File

@ -286,4 +286,6 @@ export const allowedToMergeDrawerProps = {
export const editRuleData = [{ accessLevel: 60 }, { accessLevel: 40 }, { accessLevel: 30 }];
export const editRuleDataNoAccessLevels = [];
export const editRuleDataNoOne = [{ accessLevel: 0 }];

View File

@ -9,9 +9,12 @@ import { protectionRowPropsMock } from './mock_data';
describe('Branch rule protection row', () => {
let wrapper;
const createComponent = () => {
const createComponent = ({ propsData = {} } = {}) => {
wrapper = shallowMountExtended(ProtectionRow, {
propsData: protectionRowPropsMock,
propsData: {
...protectionRowPropsMock,
...propsData,
},
stubs: { GlAvatarsInline },
});
};
@ -23,6 +26,7 @@ describe('Branch rule protection row', () => {
const findAvatarLinks = () => wrapper.findAllComponents(GlAvatarLink);
const findAvatars = () => wrapper.findAllComponents(GlAvatar);
const findAccessLevels = () => wrapper.findAllByTestId('access-level');
const findSharedSecretBadge = () => wrapper.findByTestId('shared-secret');
const findStatusChecksUrl = () => wrapper.findByText(protectionRowPropsMock.statusCheckUrl);
it('renders a title', () => {
@ -35,6 +39,7 @@ describe('Branch rule protection row', () => {
...protectionRowPropsMock.groups,
]);
expect(findAvatarsInline().props('badgeSrOnlyText')).toBe('1 additional user');
expect(findSharedSecretBadge().exists()).toBe(false);
});
it('renders avatar-link components', () => {
@ -63,4 +68,14 @@ describe('Branch rule protection row', () => {
it('renders status checks URL', () => {
expect(findStatusChecksUrl().exists()).toBe(true);
});
it('renders status checks hmac enabled badge', () => {
createComponent({
propsData: {
hmac: true,
},
});
expect(findSharedSecretBadge().exists()).toBe(true);
});
});

View File

@ -1,3 +1,4 @@
import { nextTick } from 'vue';
import { GlDrawer, GlFormCheckbox } from '@gitlab/ui';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { getContentWrapperHeight } from '~/lib/utils/dom_utils';
@ -6,6 +7,7 @@ import RuleDrawer from '~/projects/settings/branch_rules/components/view/rule_dr
import {
allowedToMergeDrawerProps,
editRuleData,
editRuleDataNoAccessLevels,
editRuleDataNoOne,
} from 'ee_else_ce_jest/projects/settings/branch_rules/components/view/mock_data';
@ -21,6 +23,10 @@ describe('Edit Rule Drawer', () => {
const findHeader = () => wrapper.find('h2');
const findSaveButton = () => wrapper.findByTestId('save-allowed-to-merge');
const findCheckboxes = () => wrapper.findAllComponents(GlFormCheckbox);
const findAdministratorsCheckbox = () => findCheckboxes().at(0);
const findMaintainersCheckbox = () => findCheckboxes().at(1);
const findDevelopersAndMaintainersCheckbox = () => findCheckboxes().at(2);
const findNoOneCheckbox = () => findCheckboxes().at(3);
const createComponent = (props = allowedToMergeDrawerProps) => {
wrapper = shallowMountExtended(RuleDrawer, {
@ -64,27 +70,61 @@ describe('Edit Rule Drawer', () => {
});
it('renders checkboxes with expected text', () => {
expect(findCheckboxes().length).toBe(3);
expect(findCheckboxes().at(0).text()).toBe('Administrators');
expect(findCheckboxes().at(1).text()).toBe('Maintainers');
expect(findCheckboxes().at(2).text()).toBe('Developers and Maintainers');
expect(findCheckboxes().length).toBe(4);
expect(findAdministratorsCheckbox().text()).toBe('Administrators');
expect(findMaintainersCheckbox().text()).toBe('Maintainers');
expect(findDevelopersAndMaintainersCheckbox().text()).toBe('Developers and Maintainers');
expect(findNoOneCheckbox().text()).toBe('No one');
});
it('emits expected data', () => {
findCheckboxes().at(0).vm.$emit('input', true);
findCheckboxes().at(1).vm.$emit('input', true);
findCheckboxes().at(2).vm.$emit('input', true);
findAdministratorsCheckbox().vm.$emit('input', true);
findMaintainersCheckbox().vm.$emit('input', true);
findDevelopersAndMaintainersCheckbox().vm.$emit('input', true);
findSaveButton().vm.$emit('click');
expect(wrapper.emitted('editRule')).toHaveLength(1);
expect(wrapper.emitted('editRule')[0][0]).toEqual(editRuleData);
});
it('when all roles unchecked it sends `No one` as a role', () => {
findCheckboxes().at(0).vm.$emit('input', false);
findCheckboxes().at(1).vm.$emit('input', false);
findCheckboxes().at(2).vm.$emit('input', false);
it('when `No one` is selected, it sets other access level checkboxes to false', async () => {
createComponent({ ...allowedToMergeDrawerProps, roles: [30, 40, 60], isOpen: true });
findNoOneCheckbox().vm.$emit('input', true);
await nextTick();
expect(findAdministratorsCheckbox().attributes('checked')).toBeUndefined();
expect(findMaintainersCheckbox().attributes('checked')).toBeUndefined();
expect(findDevelopersAndMaintainersCheckbox().attributes('checked')).toBeUndefined();
expect(findNoOneCheckbox().attributes('checked')).toBe('true');
});
it('when `No one` is initially selected, selecting another role unchecks `No one', async () => {
createComponent({ ...allowedToMergeDrawerProps, roles: [0], isOpen: true });
findAdministratorsCheckbox().vm.$emit('input', true);
await nextTick();
expect(findNoOneCheckbox().attributes('checked')).toBeUndefined();
expect(findAdministratorsCheckbox().attributes('checked')).toBe('true');
});
it('when all roles are checked it sends `No one` as a role', () => {
findAdministratorsCheckbox().vm.$emit('input', true);
findMaintainersCheckbox().vm.$emit('input', true);
findDevelopersAndMaintainersCheckbox().vm.$emit('input', true);
findNoOneCheckbox().vm.$emit('input', true);
findSaveButton().vm.$emit('click');
expect(wrapper.emitted('editRule')).toHaveLength(1);
expect(wrapper.emitted('editRule')[0][0]).toEqual(editRuleDataNoOne);
});
it('when all roles are unchecked it does not send any role', () => {
findAdministratorsCheckbox().vm.$emit('input', false);
findMaintainersCheckbox().vm.$emit('input', false);
findDevelopersAndMaintainersCheckbox().vm.$emit('input', false);
findNoOneCheckbox().vm.$emit('input', false);
findSaveButton().vm.$emit('click');
expect(wrapper.emitted('editRule')[0][0]).toEqual(editRuleDataNoAccessLevels);
});
});

View File

@ -176,7 +176,13 @@ describe('MrWidgetOptions', () => {
${'shaMismatch'} | ${'ShaMismatch'} | ${ShaMismatch}
`('should translate $state into $componentName component', async ({ state, component }) => {
await createComponent();
Vue.set(wrapper.vm.mr, 'state', state);
wrapper.vm.mr = {
...wrapper.vm.mr,
setGraphqlData: jest.fn(),
state,
};
await nextTick();
expect(wrapper.findComponent(component).exists()).toBe(true);
});
@ -249,7 +255,12 @@ describe('MrWidgetOptions', () => {
},
});
await nextTick();
Vue.set(wrapper.vm.mr, 'mergePipelinesEnabled', true);
wrapper.vm.mt = {
...wrapper.vm.mr,
setGraphqlData: jest.fn(),
mergePipelinesEnabled: true,
};
await nextTick();
expect(findMergePipelineForkAlert().exists()).toBe(false);
});
@ -273,7 +284,13 @@ describe('MrWidgetOptions', () => {
},
});
await nextTick();
Vue.set(wrapper.vm.mr, 'mergePipelinesEnabled', true);
wrapper.vm.mr = {
...wrapper.vm.mr,
setGraphqlData: jest.fn(),
mergePipelinesEnabled: true,
};
await nextTick();
expect(findMergePipelineForkAlert().exists()).toBe(true);
});

View File

@ -20,6 +20,8 @@ import {
I18N_WORK_ITEM_CONFIDENTIALITY_CHECKBOX_TOOLTIP,
SEARCH_DEBOUNCE,
WORK_ITEM_TYPE_ENUM_EPIC,
MAX_WORK_ITEMS,
I18N_MAX_WORK_ITEMS_ERROR_MESSAGE,
} from '~/work_items/constants';
import projectWorkItemsQuery from '~/work_items/graphql/project_work_items.query.graphql';
import namespaceWorkItemTypesQuery from '~/work_items/graphql/namespace_work_item_types.query.graphql';
@ -32,6 +34,7 @@ import {
updateWorkItemMutationResponse,
mockIterationWidgetResponse,
namespaceProjectsList,
generateWorkItemsListWithId,
} from '../../mock_data';
Vue.use(VueApollo);
@ -127,6 +130,7 @@ describe('WorkItemLinksForm', () => {
const findTooltip = () => wrapper.findComponent(GlTooltip);
const findAddChildButton = () => wrapper.findByTestId('add-child-button');
const findValidationElement = () => wrapper.findByTestId('work-items-invalid');
const findWorkItemLimitValidationMessage = () => wrapper.findByTestId('work-items-limit-error');
const findErrorMessageElement = () => wrapper.findByTestId('work-items-error');
const findProjectSelector = () => wrapper.findComponent(WorkItemProjectsListbox);
@ -465,6 +469,17 @@ describe('WorkItemLinksForm', () => {
);
});
it('disables button ans shows validation error when more than 10 work items are selected', async () => {
await selectAvailableWorkItemTokens(generateWorkItemsListWithId(MAX_WORK_ITEMS + 1));
expect(findWorkItemTokenInput().props('areWorkItemsToAddValid')).toBe(false);
expect(findAddChildButton().attributes('disabled')).toBe('true');
expect(findWorkItemLimitValidationMessage().exists()).toBe(true);
expect(findWorkItemLimitValidationMessage().text()).toContain(
I18N_MAX_WORK_ITEMS_ERROR_MESSAGE,
);
});
it('clears form error when token input is updated', async () => {
await createComponent({ formType: FORM_TYPES.add, updateMutation: updateMutationRejection });
await selectAvailableWorkItemTokens();

View File

@ -5,6 +5,7 @@ require 'spec_helper'
RSpec.describe Resolvers::MergeRequestsResolver, feature_category: :code_review_workflow do
include GraphqlHelpers
include SortingHelper
include MrResolverHelpers
let_it_be(:project) { create(:project, :repository) }
let_it_be(:other_project) { create(:project, :repository) }
@ -240,6 +241,107 @@ RSpec.describe Resolvers::MergeRequestsResolver, feature_category: :code_review_
end
end
context 'with merged_by argument' do
before_all do
merge_request_1.metrics.update!(merged_by: other_user)
end
context "for matching arguments" do
it 'returns merge requests merged by user' do
result = resolve_mr(project, merged_by: other_user.username)
expect(result).to contain_exactly(merge_request_1)
end
it 'does not return anything' do
result = resolve_mr(project, merged_by: "cool_guy_123")
expect(result).to be_empty
end
end
end
context 'with release argument' do
let_it_be(:release_in_project) { create(:release, :with_milestones, project: merge_request_1.project) }
let_it_be(:milestone) { release_in_project.milestones.last }
before_all do
merge_request_1.update!(milestone: milestone)
end
it 'returns merge requests in release' do
result = resolve_mr(project, release_tag: release_in_project.name)
expect(result).to contain_exactly(merge_request_1)
end
it 'does not return anything' do
result = resolve_mr(project, release_tag: "8675309.0")
expect(result).to be_empty
end
it 'filters out merge requests with given milestone title' do
result = resolve_mr(project, not: { release_tag: release_in_project.name })
expect(result).not_to include(merge_request_1)
end
end
context 'with approved_by argument' do
let(:username) { other_user.username }
before_all do
merge_request_1.approvals.create!(user: other_user)
end
it 'returns merge requests approved by user' do
result = resolve_mr(project, approved_by: [username])
expect(result).to contain_exactly(merge_request_1)
end
it 'does not return anything' do
result = resolve_mr(project, approved_by: ["cool_guy_123"])
expect(result).to be_empty
end
context 'with negated approved by argument' do
it 'filters out merge requests with given approved user' do
result = resolve_mr(project, not: { approved_by: [username] })
expect(result).not_to include(merge_request_1)
end
end
end
context 'with my_reaction_emoji argument' do
before_all do
merge_request_1.award_emoji.create!(name: "poop", user: current_user)
end
it 'returns merge requests with a reaction emoji set by user' do
result = resolve_mr(project, my_reaction_emoji: "poop")
expect(result).to contain_exactly(merge_request_1)
end
it 'does not return anything' do
result = resolve_mr(project, my_reaction_emoji: "thumbsup")
expect(result).to be_empty
end
context 'with negated my_reaction_emoji argument' do
it 'filters out merge requests with given reaction emoji' do
result = resolve_mr(project, not: { my_reaction_emoji: "poop" })
expect(result).not_to include(merge_request_1)
end
end
end
context 'when filtering by the merge request deployments' do
let_it_be(:gstg) { create(:environment, project: project, name: 'gstg') }
let_it_be(:gprd) { create(:environment, project: project, name: 'gprd') }
@ -501,8 +603,4 @@ RSpec.describe Resolvers::MergeRequestsResolver, feature_category: :code_review_
def resolve_mr_single(project, iid)
resolve_mr(project, resolver: described_class.single, iid: iid.to_s)
end
def resolve_mr(project, resolver: described_class, user: current_user, **args)
resolve(resolver, obj: project, args: args, ctx: { current_user: user }, arg_style: :internal)
end
end

View File

@ -356,6 +356,10 @@ RSpec.describe GitlabSchema.types['Project'], feature_category: :groups_and_proj
:updated_after,
:updated_before,
:author_username,
:approved_by,
:my_reaction_emoji,
:merged_by,
:release_tag,
:assignee_username,
:assignee_wildcard_id,
:reviewer_username,

View File

@ -333,6 +333,7 @@ RSpec.describe MergeRequestsHelper, feature_category: :code_review_workflow do
it 'returns the correct data' do
expected_data = {
autocomplete_award_emojis_path: autocomplete_award_emojis_path,
full_path: project.full_path,
is_public_visibility_restricted: 'false',
is_signed_in: 'true',

View File

@ -37,8 +37,4 @@ RSpec.describe Banzai::Filter::BlockquoteFenceLegacyFilter, feature_category: :t
end.not_to raise_error
end
end
it_behaves_like 'text filter timeout' do
let(:text) { ">>>\ntest\n>>>" }
end
end

View File

@ -214,5 +214,6 @@ RSpec.describe Banzai::Filter::ExternalLinkFilter, feature_category: :team_plann
it_behaves_like 'a filter timeout' do
let(:text) { 'text' }
let(:expected_result) { described_class::COMPLEX_MARKDOWN_MESSAGE }
let(:expected_timeout) { described_class::SANITIZATION_RENDER_TIMEOUT }
end
end

View File

@ -3,16 +3,18 @@
require 'spec_helper'
RSpec.describe Banzai::Filter::References::AbstractReferenceFilter, feature_category: :team_planning do
include FilterSpecHelper
let_it_be(:project) { create(:project) }
let_it_be(:issue) { create(:issue, project: project) }
let_it_be(:doc) { Nokogiri::HTML.fragment('') }
let_it_be(:filter) { described_class.new(doc, project: project) }
let_it_be(:filter_instance) { described_class.new(doc, project: project) }
describe '#data_attributes_for' do
it 'is not an XSS vector' do
allow(described_class).to receive(:object_class).and_return(Issue)
data_attributes = filter.data_attributes_for('xss &lt;img onerror=alert(1) src=x&gt;', project, issue, link_content: true)
data_attributes = filter_instance.data_attributes_for('xss &lt;img onerror=alert(1) src=x&gt;', project, issue, link_content: true)
expect(data_attributes[:original]).to eq('xss &amp;lt;img onerror=alert(1) src=x&amp;gt;')
end
@ -22,29 +24,32 @@ RSpec.describe Banzai::Filter::References::AbstractReferenceFilter, feature_cate
allow(described_class).to receive(:object_class).and_return(Issue)
expect(Gitlab::RenderTimeout).to receive(:timeout).and_call_original
filter.call
filter(doc)
end
it 'uses gsub_with_limit' do
allow(described_class).to receive(:object_class).and_return(Issue)
expect(Gitlab::Utils::Gsub).to receive(:gsub_with_limit).with(anything, anything, limit: Banzai::Filter::FILTER_ITEM_LIMIT).and_call_original
filter.references_in('text')
filter_instance.references_in('text')
end
context 'abstract methods' do
describe '#find_object' do
it 'raises NotImplementedError' do
expect { filter.find_object(nil, nil) }.to raise_error(NotImplementedError)
expect { filter_instance.find_object(nil, nil) }.to raise_error(NotImplementedError)
end
end
describe '#url_for_object' do
it 'raises NotImplementedError' do
expect { filter.url_for_object(nil, nil) }.to raise_error(NotImplementedError)
expect { filter_instance.url_for_object(nil, nil) }.to raise_error(NotImplementedError)
end
end
end
it_behaves_like 'pipeline timing check', context: { project: nil }
it_behaves_like 'a filter timeout' do
let(:text) { 'text' }
end
end

View File

@ -227,5 +227,6 @@ RSpec.describe Banzai::Filter::SanitizationFilter, feature_category: :team_plann
it_behaves_like 'a filter timeout' do
let(:text) { 'text' }
let(:expected_result) { described_class::COMPLEX_MARKDOWN_MESSAGE }
let(:expected_timeout) { described_class::SANITIZATION_RENDER_TIMEOUT }
end
end

View File

@ -147,7 +147,7 @@ RSpec.describe Banzai::Filter::SyntaxHighlightFilter, feature_category: :team_pl
include_examples "XSS prevention", "ruby"
end
it_behaves_like "html filter timeout" do
it_behaves_like 'a filter timeout' do
let(:text) { '<pre data-canonical-lang="ruby"><code>def fun end</code></pre>' }
end

View File

@ -1,15 +0,0 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Banzai::Filter::TimeoutHtmlPipelineFilter, feature_category: :team_planning do
include FilterSpecHelper
it_behaves_like 'html filter timeout' do
let(:text) { '<p>some text</p>' }
end
it 'raises NotImplementedError' do
expect { filter('test') }.to raise_error NotImplementedError
end
end

View File

@ -1,15 +0,0 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Banzai::Filter::TimeoutTextPipelineFilter, feature_category: :team_planning do
include FilterSpecHelper
it_behaves_like 'text filter timeout' do
let(:text) { '<p>some text</p>' }
end
it 'raises NotImplementedError' do
expect { filter('test') }.to raise_error NotImplementedError
end
end

View File

@ -25,13 +25,21 @@ RSpec.describe Gitlab::Ci::Config::Entry::Reports::CoverageReport, feature_categ
end
context 'with unsupported coverage format' do
let(:config) { { coverage_format: 'jacoco', path: 'jacoco.xml' } }
let(:config) { { coverage_format: 'anotherformat', path: 'anotherformat.xml' } }
it { expect(entry).not_to be_valid }
it { expect(entry.errors).to include(/format must be one of supported formats/) }
end
context 'with jacoco coverage format' do
let(:config) { { coverage_format: 'jacoco', path: 'jacoco.xml' } }
it { expect(entry).to be_valid }
it { expect(entry.value).to eq(config) }
end
context 'without coverage format' do
let(:config) { { path: 'cobertura-coverage.xml' } }

View File

@ -0,0 +1,57 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::Ci::Parsers::Coverage::Documents::JacocoDocument,
feature_category: :code_testing do
subject(:parse_report) do
Nokogiri::XML::SAX::Parser.new(described_class.new(coverage_report,
modified_files)).parse(xml)
end
describe '#parse!' do
let(:coverage_report) { Gitlab::Ci::Reports::CoverageReport.new }
let(:modified_files) { %w[src/main/org/acme/AnotherResource.java src/main/org/acme/ExampleResource.java] }
let(:project_path) { 'root/someproject' }
let(:xml) { fixture_file_upload(Rails.root.join('spec/fixtures/jacoco/coverage.xml'), 'text/xml') }
it 'parses the file' do
parse_report
expect(coverage_report.files).to match({
"src/main/org/acme/AnotherResource.java" => { 9 => 0, 14 => 0 },
"src/main/org/acme/ExampleResource.java" => { 9 => 3, 14 => 2 }
})
end
context 'when the report format is invalid' do
context 'when the xml syntax is invalid' do
let(:xml) do
fixture_file_upload(Rails.root.join('spec/fixtures/jacoco/coverage-invalid-format.xml'), 'text/xml')
end
it 'returns an error' do
expect { parse_report }.to raise_error(Gitlab::Ci::Parsers::Coverage::Jacoco::InvalidXMLError)
end
end
context 'when the line does not contain the required info' do
let(:xml) { fixture_file_upload(Rails.root.join('spec/fixtures/jacoco/coverage-no-line-info.xml'), 'text/xml') }
it 'returns an error' do
expect { parse_report }.to raise_error(Gitlab::Ci::Parsers::Coverage::Jacoco::InvalidLineInformationError)
end
end
end
context 'when the merge request paths do not exist' do
let(:modified_files) { %w[src/test/org/acme/ExampleResource.java] }
it 'returns an error' do
expect(Gitlab::AppLogger).to receive(:info).twice
parse_report
end
end
end
end

View File

@ -0,0 +1,41 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::Ci::Parsers::Coverage::Jacoco, feature_category: :code_testing do
let_it_be(:project) { create(:project, :repository) }
let(:xml_data) { double }
let(:coverage_report) { double }
let(:paths) { double }
let(:merge_request_paths) { double }
subject(:parse_report) do
described_class.new.parse!(xml_data,
coverage_report,
project: project,
worktree_paths: paths,
merge_request_paths: merge_request_paths)
end
before do
allow_next_instance_of(Nokogiri::XML::SAX::Parser) do |document|
allow(document).to receive(:parse)
end
end
it 'uses Jacoco parser' do
expect(Gitlab::Ci::Parsers::Coverage::Documents::JacocoDocument).to receive(:new)
parse_report
end
context 'when the feature flag is disabled' do
before do
stub_feature_flags(jacoco_coverage_reports: false)
end
it 'returns an error' do
expect { parse_report }.to raise_error(described_class::FeatureDisabledError)
end
end
end

View File

@ -22,6 +22,14 @@ RSpec.describe Gitlab::Ci::Parsers do
end
end
context 'when file_type is jacoco' do
let(:file_type) { 'jacoco' }
it 'fabricates the class' do
is_expected.to be_a(described_class::Coverage::Jacoco)
end
end
context 'when file_type is accessibility' do
let(:file_type) { 'accessibility' }

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