Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2024-10-01 09:11:55 +00:00
parent d7be15963e
commit cd3fcd1c22
63 changed files with 1450 additions and 680 deletions

View File

@ -14,24 +14,12 @@ Layout/LineEndStringConcatenationIndentation:
- 'app/graphql/mutations/concerns/mutations/validate_time_estimate.rb'
- 'app/graphql/mutations/container_registry/protection/rule/create.rb'
- 'app/graphql/mutations/container_registry/protection/rule/delete.rb'
- 'app/graphql/mutations/container_registry/protection/rule/update.rb'
- 'app/graphql/mutations/design_management/upload.rb'
- 'app/graphql/mutations/issues/bulk_update.rb'
- 'app/graphql/mutations/issues/update.rb'
- 'app/graphql/mutations/members/projects/bulk_update.rb'
- 'app/graphql/mutations/merge_requests/update.rb'
- 'app/graphql/resolvers/ci/config_resolver.rb'
- 'app/graphql/resolvers/ci/runners_resolver.rb'
- 'app/graphql/resolvers/ci/template_resolver.rb'
- 'app/graphql/resolvers/concerns/project_search_arguments.rb'
- 'app/graphql/resolvers/design_management/designs_resolver.rb'
- 'app/graphql/resolvers/groups_resolver.rb'
- 'app/graphql/types/ci/detailed_status_type.rb'
- 'app/graphql/types/ci/job_token_scope/direction_enum.rb'
- 'app/graphql/types/ci/job_token_scope_type.rb'
- 'app/graphql/types/ci/job_trace_type.rb'
- 'app/graphql/types/ci/job_type.rb'
- 'app/graphql/types/ci/runner_membership_filter_enum.rb'
- 'app/graphql/types/ci/runner_type.rb'
- 'app/graphql/types/commit_type.rb'
- 'app/graphql/types/container_registry/protection/rule_type.rb'

View File

@ -1 +1 @@
faa2e2cf138777ba493edc43a01cc905d83d99be
7207df70c6dcd76de3ef92993b57b33c7ab5eb8a

View File

@ -10,6 +10,7 @@ const PROJECT_IMPORT_MEMBERS_PATH = '/api/:version/projects/:id/import_project_m
const PROJECT_REPOSITORY_SIZE_PATH = '/api/:version/projects/:id/repository_size';
const PROJECT_TRANSFER_LOCATIONS_PATH = 'api/:version/projects/:id/transfer_locations';
const PROJECT_SHARE_LOCATIONS_PATH = 'api/:version/projects/:id/share_locations';
const PROJECT_UPLOADS_PATH = '/api/:version/projects/:id/uploads';
export function getProjects(query, options, callback = () => {}) {
const url = buildApiUrl(PROJECTS_PATH);
@ -91,3 +92,30 @@ export const getProjectShareLocations = (projectId, params = {}, axiosOptions =
return axios.get(url, { params: { ...defaultParams, ...params }, ...axiosOptions });
};
/**
* Uploads an image to a project and returns the share URL.
*
* @param {Object} options - The options for uploading the image.
* @param {string} options.filename - The name of the file to be uploaded.
* @param {Blob} options.blobData - The blob data of the image to be uploaded.
* @param {string} options.projectId - The ID of the project.
* @returns {Promise<string>} The share URL of the uploaded image
*/
export async function uploadImageToProject({ filename, blobData, projectId }) {
const url = buildApiUrl(PROJECT_UPLOADS_PATH).replace(':id', projectId);
const formData = new FormData();
formData.append('file', blobData, filename);
const result = await axios.post(url, formData, {
headers: { 'Content-Type': 'multipart/form-data' },
});
if (!result.data?.full_path) {
return Promise.reject(new Error(`Image failed to upload`));
}
return new URL(result.data.full_path, document.baseURI).href;
}

View File

@ -1,3 +1,4 @@
import { domToBlob } from 'modern-screenshot';
import vector from './vector';
import { readFileAsDataURL } from './file_utility';
@ -64,3 +65,7 @@ export const getRetinaDimensions = async (pngFile) => {
return null;
}
};
export function domElementToBlob(domElement) {
return domToBlob(domElement);
}

View File

@ -16,7 +16,7 @@ import RichTimestampTooltip from '~/vue_shared/components/rich_timestamp_tooltip
import WorkItemLinkChildMetadata from 'ee_else_ce/work_items/components/shared/work_item_link_child_metadata.vue';
import WorkItemTypeIcon from '../work_item_type_icon.vue';
import WorkItemStateBadge from '../work_item_state_badge.vue';
import { findLinkedItemsWidget } from '../../utils';
import { findLinkedItemsWidget, getDisplayReference } from '../../utils';
import { STATE_OPEN, WIDGET_TYPE_ASSIGNEES, WIDGET_TYPE_LABELS } from '../../constants';
import WorkItemRelationshipIcons from './work_item_relationship_icons.vue';
@ -54,16 +54,15 @@ export default {
type: Boolean,
required: true,
},
workItemFullPath: {
type: String,
required: true,
},
showLabels: {
type: Boolean,
required: false,
default: true,
},
workItemFullPath: {
type: String,
required: false,
default: '',
},
showWeight: {
type: Boolean,
required: false,
@ -103,6 +102,15 @@ export default {
childItemType() {
return this.childItem.workItemType.name;
},
childItemIid() {
return this.childItem.iid;
},
childItemWebUrl() {
return this.childItem.webUrl;
},
childItemFullPath() {
return this.childItem.namespace?.fullPath;
},
stateTimestamp() {
return this.isChildItemOpen ? this.childItem.createdAt : this.childItem.closedAt;
},
@ -116,12 +124,7 @@ export default {
return this.showLabels && this.labels.length;
},
displayReference() {
// The reference is replaced by work item fullpath in case the project and group are same.
// e.g., gitlab-org/gitlab-test#45 will be shown as #45
if (new RegExp(`${this.workItemFullPath}#`, 'g').test(this.childItem.reference)) {
return this.childItem.reference.replace(new RegExp(`${this.workItemFullPath}`, 'g'), '');
}
return this.childItem.reference;
return getDisplayReference(this.workItemFullPath, this.childItem.reference);
},
linkedChildWorkItems() {
return findLinkedItemsWidget(this.childItem).linkedItems?.nodes || [];
@ -190,6 +193,9 @@ export default {
v-if="isChildItemOpen && linkedChildWorkItems.length"
:work-item-type="childItemType"
:linked-work-items="linkedChildWorkItems"
:work-item-full-path="childItemFullPath"
:work-item-iid="childItemIid"
:work-item-web-url="childItemWebUrl"
/>
<span
:id="`statusIcon-${childItem.id}`"

View File

@ -1,14 +1,15 @@
<script>
import { GlIcon, GlTooltipDirective } from '@gitlab/ui';
import { GlIcon } from '@gitlab/ui';
import { n__, sprintf } from '~/locale';
import { LINKED_CATEGORIES_MAP, sprintfWorkItem } from '../../constants';
import workItemLinkedItemsQuery from '../../graphql/work_item_linked_items.query.graphql';
import { findLinkedItemsWidget } from '../../utils';
import WorkItemRelationshipPopover from './work_item_relationship_popover.vue';
export default {
components: {
GlIcon,
},
directives: {
GlTooltip: GlTooltipDirective,
WorkItemRelationshipPopover,
},
props: {
linkedWorkItems: {
@ -19,6 +20,46 @@ export default {
type: String,
required: true,
},
workItemWebUrl: {
type: String,
required: true,
},
workItemFullPath: {
type: String,
required: true,
},
workItemIid: {
type: String,
required: true,
},
},
apollo: {
childItemLinkedItems: {
skip() {
return this.skipQuery;
},
query() {
return workItemLinkedItemsQuery;
},
variables() {
return {
fullPath: this.workItemFullPath,
iid: this.workItemIid,
};
},
update({ workspace }) {
if (!workspace?.workItem) return [];
this.skipQuery = true;
return findLinkedItemsWidget(workspace.workItem).linkedItems?.nodes || [];
},
},
},
data() {
return {
skipQuery: true,
childItemLinkedItems: [],
};
},
computed: {
itemsBlockedBy() {
@ -31,6 +72,12 @@ export default {
return item.linkType === LINKED_CATEGORIES_MAP.BLOCKS;
});
},
itemsBlockedByIconId() {
return `relationship-blocked-by-icon-${this.workItemIid}`;
},
itemsBlocksIconId() {
return `relationship-blocks-icon-${this.workItemIid}`;
},
blockedByLabel() {
const message = sprintf(
n__(
@ -53,33 +100,74 @@ export default {
);
return sprintfWorkItem(message, this.workItemType);
},
isLoading() {
return this.$apollo.queries.childItemLinkedItems.loading;
},
childBlockedByItems() {
return this.childItemLinkedItems.filter((item) => {
return item.linkType === LINKED_CATEGORIES_MAP.IS_BLOCKED_BY;
});
},
childBlocksItems() {
return this.childItemLinkedItems.filter((item) => {
return item.linkType === LINKED_CATEGORIES_MAP.BLOCKS;
});
},
},
methods: {
handleMouseEnter() {
this.skipQuery = false;
},
},
};
</script>
<template>
<span class="gl-flex gl-gap-3">
<span
v-if="itemsBlockedBy.length"
v-gl-tooltip
:title="blockedByLabel"
:aria-label="blockedByLabel"
class="gl-text-sm gl-text-secondary"
data-testid="relationship-blocked-by-icon"
>
<gl-icon name="entity-blocked" class="gl-text-red-500" />
{{ itemsBlockedBy.length }}
</span>
<span
v-if="itemsBlocks.length"
v-gl-tooltip
:title="blocksLabel"
:aria-label="blocksLabel"
class="gl-text-sm gl-text-secondary"
data-testid="relationship-blocks-icon"
>
<gl-icon name="entity-blocking" class="gl-text-orange-500" />
{{ itemsBlocks.length }}
</span>
<template v-if="itemsBlockedBy.length > 0">
<span
:id="itemsBlockedByIconId"
:aria-label="blockedByLabel"
tabIndex="0"
class="gl-cursor-pointer gl-text-sm gl-text-secondary"
data-testid="relationship-blocked-by-icon"
@mouseenter="handleMouseEnter"
>
<gl-icon name="entity-blocked" class="gl-text-red-500" />
{{ itemsBlockedBy.length }}
</span>
<work-item-relationship-popover
:target="itemsBlockedByIconId"
:title="s__('WorkItem|Blocked by')"
:loading="isLoading"
:linked-work-items="childBlockedByItems"
:work-item-full-path="workItemFullPath"
:work-item-web-url="workItemWebUrl"
:work-item-type="workItemType"
/>
</template>
<template v-if="itemsBlocks.length > 0">
<span
:id="itemsBlocksIconId"
:aria-label="blocksLabel"
tabIndex="0"
class="gl-cursor-pointer gl-text-sm gl-text-secondary"
data-testid="relationship-blocks-icon"
@mouseenter="handleMouseEnter"
>
<gl-icon name="entity-blocking" class="gl-text-orange-500" />
{{ itemsBlocks.length }}
</span>
<work-item-relationship-popover
:target="itemsBlocksIconId"
:title="s__('WorkItem|Blocking')"
:loading="isLoading"
:linked-work-items="childBlocksItems"
:work-item-full-path="workItemFullPath"
:work-item-web-url="workItemWebUrl"
:work-item-type="workItemType"
/>
</template>
</span>
</template>

View File

@ -0,0 +1,123 @@
<script>
import { GlPopover, GlLoadingIcon, GlTooltipDirective, GlLink } from '@gitlab/ui';
import { n__ } from '~/locale';
import { WORK_ITEM_TYPE_VALUE_ISSUE } from '~/work_items/constants';
import WorkItemRelationshipPopoverMetadata from 'ee_else_ce/work_items/components/shared/work_item_relationship_popover_metadata.vue';
import WorkItemTypeIcon from '../work_item_type_icon.vue';
const defaultDisplayLimit = 3;
export default {
components: {
GlPopover,
GlLoadingIcon,
GlLink,
WorkItemTypeIcon,
WorkItemRelationshipPopoverMetadata,
},
directives: {
GlTooltip: GlTooltipDirective,
},
props: {
linkedWorkItems: {
type: Array,
required: true,
},
title: {
type: String,
required: true,
},
target: {
type: String,
required: true,
},
workItemFullPath: {
type: String,
required: true,
},
workItemType: {
type: String,
required: true,
},
workItemWebUrl: {
type: String,
required: true,
},
loading: {
type: Boolean,
default: false,
required: false,
},
},
defaultDisplayLimit: 3,
computed: {
atLinkedItemsDisplayLimit() {
return this.linkedWorkItems.length > defaultDisplayLimit;
},
displayedIssuablesCount() {
return this.atLinkedItemsDisplayLimit
? this.linkedWorkItems.length - defaultDisplayLimit
: this.linkedWorkItems.length;
},
moreItemsText() {
return n__('WorkItem|+%d more item', 'WorkItem|+%d more items', this.displayedIssuablesCount);
},
linkedItemsToDisplay() {
return this.linkedWorkItems.slice(0, defaultDisplayLimit);
},
moreItemsLink() {
return `${this.workItemWebUrl}#${this.workItemType === WORK_ITEM_TYPE_VALUE_ISSUE ? 'related-issues' : 'linkeditems'}`;
},
},
};
</script>
<template>
<gl-popover
:target="target"
placement="top"
triggers="hover focus"
:css-classes="['gl-max-w-sm']"
>
<template #title>
<span class="gl-text-sm gl-text-secondary">{{ title }}</span>
</template>
<gl-loading-icon v-if="loading" size="sm" />
<template v-else>
<ul
class="gl-mb-0 gl-flex gl-list-none gl-flex-col gl-gap-3 gl-p-0"
:class="{ 'gl-mb-3': atLinkedItemsDisplayLimit }"
>
<li v-for="{ workItem } in linkedItemsToDisplay" :key="workItem.id">
<work-item-type-icon
:show-tooltip-on-hover="true"
class="gl-mr-1 gl-cursor-help"
color-class="gl-text-secondary"
:work-item-type="workItem.workItemType.name"
/>
<gl-link
:href="workItem.webUrl"
class="gl-link gl-hyphens-auto gl-break-words gl-text-base gl-font-semibold gl-text-primary hover:gl-text-gray-900"
@click.exact="$emit('click', $event)"
@mouseover="$emit('mouseover')"
@mouseout="$emit('mouseout')"
>
{{ workItem.title }}
</gl-link>
<work-item-relationship-popover-metadata
:work-item="workItem"
:work-item-full-path="workItemFullPath"
/>
</li>
</ul>
<gl-link
v-if="atLinkedItemsDisplayLimit"
data-testid="more-related-items-link"
:href="moreItemsLink"
class="gl-mt-3 gl-text-sm !gl-text-blue-500"
>{{ moreItemsText }}</gl-link
>
</template>
</gl-popover>
</template>

View File

@ -0,0 +1,84 @@
<script>
import { GlTooltipDirective, GlAvatarsInline, GlAvatar, GlAvatarLink } from '@gitlab/ui';
import ItemMilestone from '~/issuable/components/issue_milestone.vue';
import { s__, sprintf } from '~/locale';
import { WIDGET_TYPE_MILESTONE, WIDGET_TYPE_ASSIGNEES } from '~/work_items/constants';
import { findWidget } from '~/issues/list/utils';
import { getDisplayReference } from '../../utils';
export default {
name: 'WorkItemRelationshipPopoverMetadata',
components: {
ItemMilestone,
GlAvatar,
GlAvatarLink,
GlAvatarsInline,
},
directives: {
GlTooltip: GlTooltipDirective,
},
props: {
workItem: {
type: Object,
required: true,
},
workItemFullPath: {
type: String,
required: true,
},
},
assigneesDisplayLimit: 3,
computed: {
workItemAssignees() {
return findWidget(WIDGET_TYPE_ASSIGNEES, this.workItem)?.assignees?.nodes || [];
},
workItemMilestone() {
return findWidget(WIDGET_TYPE_MILESTONE, this.workItem)?.milestone;
},
fullReference() {
return getDisplayReference(this.workItemFullPath, this.workItem.reference);
},
directNamespaceReference() {
return this.fullReference.split('/').slice(-1)[0];
},
assigneesCollapsedTooltip() {
if (this.workItemAssignees.length > this.$options.assigneesDisplayLimit) {
return sprintf(s__('WorkItem|%{count} more assignees'), {
count: this.workItemAssignees.length - this.$options.assigneesDisplayLimit,
});
}
return '';
},
},
};
</script>
<template>
<div
class="shrink-0 gl-mt-1 gl-flex gl-w-fit gl-flex-wrap gl-items-center gl-gap-x-3 gl-gap-y-2 gl-text-sm gl-text-secondary"
>
<span v-gl-tooltip :title="fullReference">{{ directNamespaceReference }}</span>
<slot name="weight-metadata"></slot>
<item-milestone
v-if="workItemMilestone"
:milestone="workItemMilestone"
class="gl-flex gl-max-w-15 !gl-cursor-help gl-items-center gl-gap-2 gl-leading-normal !gl-no-underline"
/>
<slot name="additional-metadata"></slot>
<gl-avatars-inline
v-if="workItemAssignees.length"
collapsed
:avatars="workItemAssignees"
:max-visible="$options.assigneesDisplayLimit"
:avatar-size="16"
badge-tooltip-prop="name"
:badge-sr-only-text="assigneesCollapsedTooltip"
>
<template #avatar="{ avatar }">
<gl-avatar-link v-gl-tooltip :href="avatar.webUrl" :title="avatar.name">
<gl-avatar :alt="avatar.name" :src="avatar.avatarUrl" :size="16" />
</gl-avatar-link>
</template>
</gl-avatars-inline>
</div>
</template>

View File

@ -13,6 +13,10 @@ fragment WorkItemLinkedItemsFragment on WorkItem {
id
iid
confidential
namespace {
id
fullPath
}
workItemType {
id
name

View File

@ -153,6 +153,15 @@ export const markdownPreviewPath = ({ fullPath, iid, isGroup = false }) => {
return `${domain}/${basePath}/-/preview_markdown?target_type=WorkItem&target_id=${iid}`;
};
export const getDisplayReference = (workItemFullPath, workitemReference) => {
// The reference is replaced by work item fullpath in case the project and group are same.
// e.g., gitlab-org/gitlab-test#45 will be shown as #45
if (new RegExp(`${workItemFullPath}#`, 'g').test(workitemReference)) {
return workitemReference.replace(new RegExp(`${workItemFullPath}`, 'g'), '');
}
return workitemReference;
};
export const isReference = (input) => {
/**
* The regular expression checks if the `value` is

View File

@ -22,11 +22,6 @@
.title {
margin-bottom: 2px;
}
.icon-merge-request-unmerged {
height: 13px;
margin-bottom: 3px;
}
}
}
@ -34,15 +29,3 @@
opacity: 0.3;
pointer-events: none;
}
.work-item-labels {
// stylelint-disable-next-line gitlab/no-gl-class
.gl-token {
padding-left: $gl-spacing-scale-1;
}
// stylelint-disable-next-line gitlab/no-gl-class
.gl-token-close {
display: none;
}
}

View File

@ -82,11 +82,6 @@
background-color: mix($gray-50, $orange-50, 75%) !important;
}
.gl-dark .issue-sticky-header-text .badge-muted {
background-color: var(--gray-100);
color: var(--gray-700);
}
.gl-dark {
.gl-filtered-search-suggestion-active {
background-color: $gray-100;

View File

@ -7,8 +7,8 @@ module Mutations
class Update < ::Mutations::BaseMutation
graphql_name 'UpdateContainerRegistryProtectionRule'
description 'Updates a container registry protection rule to restrict access to project containers. ' \
'You can prevent users without certain roles from altering containers. ' \
'Available only when feature flag `container_registry_protected_containers` is enabled.'
'You can prevent users without certain roles from altering containers. ' \
'Available only when feature flag `container_registry_protected_containers` is enabled.'
authorize :admin_container_image

View File

@ -18,7 +18,7 @@ module Mutations
field :skipped_designs, [Types::DesignManagement::DesignType],
null: false,
description: "Any designs that were skipped from the upload due to there " \
"being no change to their content since their last version"
"being no change to their content since their last version"
def resolve(project_path:, iid:, files:)
issue = authorized_find!(project_path: project_path, iid: iid)

View File

@ -10,23 +10,23 @@ module Mutations
MAX_ISSUES = 100
description 'Allows updating several properties for a set of issues. ' \
'Does nothing if the `bulk_update_issues_mutation` feature flag is disabled.'
'Does nothing if the `bulk_update_issues_mutation` feature flag is disabled.'
argument :parent_id, ::Types::GlobalIDType[::IssueParent],
required: true,
description: 'Global ID of the parent to which the bulk update will be scoped. ' \
'The parent can be a project. The parent can also be a group (Premium and Ultimate only). ' \
'Example `IssueParentID` are `"gid://gitlab/Project/1"` and `"gid://gitlab/Group/1"`.'
'The parent can be a project. The parent can also be a group (Premium and Ultimate only). ' \
'Example `IssueParentID` are `"gid://gitlab/Project/1"` and `"gid://gitlab/Group/1"`.'
argument :ids, [::Types::GlobalIDType[::Issue]],
required: true,
description: 'Global ID array of the issues that will be updated. ' \
"IDs that the user can\'t update will be ignored. A max of #{MAX_ISSUES} can be provided."
"IDs that the user can\'t update will be ignored. A max of #{MAX_ISSUES} can be provided."
argument :assignee_ids, [::Types::GlobalIDType[::User]],
required: false,
description: 'Global ID array of the users that will be assigned to the given issues. ' \
'Existing assignees will be replaced with the ones on this list.'
'Existing assignees will be replaced with the ones on this list.'
argument :milestone_id, ::Types::GlobalIDType[::Milestone],
required: false,

View File

@ -35,7 +35,7 @@ module Mutations
argument :time_estimate, GraphQL::Types::String,
required: false,
description: 'Estimated time to complete the issue. ' \
'Use `null` or `0` to remove the current estimate.'
'Use `null` or `0` to remove the current estimate.'
def resolve(project_path:, iid:, **args)
issue = authorized_find!(project_path: project_path, iid: iid)

View File

@ -6,7 +6,7 @@ module Mutations
class BulkUpdate < BulkUpdateBase
graphql_name 'ProjectMemberBulkUpdate'
description 'Updates multiple members of a project. ' \
'To use this mutation, you must have at least the Maintainer role.'
'To use this mutation, you must have at least the Maintainer role.'
authorize :admin_project_member

View File

@ -29,7 +29,7 @@ module Mutations
argument :time_estimate, GraphQL::Types::String,
required: false,
description: 'Estimated time to complete the merge request. ' \
'Use `null` or `0` to remove the current estimate.'
'Use `null` or `0` to remove the current estimate.'
def resolve(project_path:, iid:, **args)
merge_request = authorized_find!(project_path: project_path, iid: iid)

View File

@ -28,7 +28,7 @@ module Types
description: 'Icon of the status.',
deprecated: {
reason: 'The `icon` attribute is deprecated. Use `name` to ' \
'identify the status to display instead',
'identify the status to display instead',
milestone: '16.4'
}
field :id, GraphQL::Types::String, null: false,

View File

@ -14,7 +14,7 @@ module Types
value 'INBOUND',
value: :inbound,
description: 'Target projects in the inbound allowlist can access the scope project ' \
'through their job tokens.'
'through their job tokens.'
end
end
end

View File

@ -27,30 +27,30 @@ module Types
Types::ProjectType.connection_type,
null: false,
description: "Allowlist of projects that can access the current project " \
"by authenticating with a CI/CD job token.",
"by authenticating with a CI/CD job token.",
method: :inbound_projects
field :groups_allowlist,
Types::GroupType.connection_type,
null: false,
description: "Allowlist of groups that can access the current project " \
"by authenticating with a CI/CD job token.",
"by authenticating with a CI/CD job token.",
method: :groups
field :inbound_allowlist_count,
GraphQL::Types::Int,
null: false,
description: "Count of projects that can access the current project " \
"by authenticating with a CI/CD job token. " \
"The count does not include nested projects.",
"by authenticating with a CI/CD job token. " \
"The count does not include nested projects.",
method: :inbound_projects_count
field :groups_allowlist_count,
GraphQL::Types::Int,
null: false,
description: "Count of groups that can access the current project " \
"by authenticating with a CI/CD job token. " \
"The count does not include subgroups.",
"by authenticating with a CI/CD job token. " \
"The count does not include subgroups.",
method: :groups_count
end
end

View File

@ -11,8 +11,8 @@ module Types
field :html_summary, GraphQL::Types::String, null: false,
alpha: { milestone: '15.11' },
description: 'HTML summary that contains the tail lines of the trace. ' \
"Returns at most #{MAX_SIZE_KB}KB of raw bytes from the trace. " \
'The returned string might start with an unexpected invalid UTF-8 code point due to truncation.' do
"Returns at most #{MAX_SIZE_KB}KB of raw bytes from the trace. " \
'The returned string might start with an unexpected invalid UTF-8 code point due to truncation.' do
argument :last_lines, Integer,
required: false, default_value: 10,
description: 'Number of tail lines to return, up to a maximum of 100 lines.'

View File

@ -93,7 +93,7 @@ module Types
field :previous_stage_jobs_or_needs, Types::Ci::JobNeedUnion.connection_type,
null: true,
description: 'Jobs that must complete before the job runs. Returns `BuildNeed`, ' \
'which is the needed jobs if the job uses the `needs` keyword, or the previous stage jobs otherwise.',
'which is the needed jobs if the job uses the `needs` keyword, or the previous stage jobs otherwise.',
deprecated: { reason: 'Replaced by previousStageJobs and needs fields', milestone: '16.4' }
field :ref_name, GraphQL::Types::String, null: true,
description: 'Ref name of the job.'

View File

@ -18,7 +18,7 @@ module Types
value 'ALL_AVAILABLE',
description:
"Include all runners. This list includes runners for all projects in the group " \
"and subgroups, as well as for the parent groups and instance.",
"and subgroups, as well as for the parent groups and instance.",
value: :all_available,
alpha: { milestone: '15.5' }
end

View File

@ -33,6 +33,20 @@ module AuthHelper
Gitlab::Auth.omniauth_enabled?
end
def enabled_button_based_providers_for_signup
if Gitlab.config.omniauth.allow_single_sign_on.is_a?(Array)
enabled_button_based_providers & Gitlab.config.omniauth.allow_single_sign_on
elsif Gitlab.config.omniauth.allow_single_sign_on
enabled_button_based_providers
else
[]
end
end
def signup_button_based_providers_enabled?
omniauth_enabled? && enabled_button_based_providers_for_signup.any?
end
def provider_has_custom_icon?(name)
icon_for_provider(name.to_s)
end

View File

@ -14,7 +14,7 @@ module Groups::GroupMembersHelper
banned:,
include_relations:,
search:,
pending_members:,
pending_members_count:,
placeholder_users:
)
{

View File

@ -19,7 +19,7 @@ module Projects::ProjectMembersHelper
private
def project_members_app_data(
project, members:, invited:, access_requests:, include_relations:, search:, pending_members:) # rubocop:disable Lint/UnusedMethodArgument -- Argument used in EE
project, members:, invited:, access_requests:, include_relations:, search:, pending_members_count:) # rubocop:disable Lint/UnusedMethodArgument -- Argument used in EE
{
user: project_members_list_data(project, members, { param_name: :page, params: { search_groups: nil } }),
group: project_group_links_list_data(project, include_relations, search),

View File

@ -1297,13 +1297,21 @@ class User < ApplicationRecord
direct_groups_cte = Gitlab::SQL::CTE.new(:direct_groups, groups)
direct_groups_cte_alias = direct_groups_cte.table.alias(Group.table_name)
groups_from_authorized_projects = Group.id_in(authorized_projects.select(:namespace_id))
groups_from_shares = Group.joins(:shared_with_group_links)
.where(group_group_links: { shared_with_group_id: Group.from(direct_groups_cte_alias) })
if Feature.enabled?(:fix_user_authorized_groups, self)
groups_from_authorized_projects = groups_from_authorized_projects.self_and_ancestors
groups_from_shares = groups_from_shares.self_and_descendants
end
Group
.with(direct_groups_cte.to_arel)
.from_union([
Group.from(direct_groups_cte_alias).self_and_descendants,
Group.id_in(authorized_projects.select(:namespace_id)),
Group.joins(:shared_with_group_links)
.where(group_group_links: { shared_with_group_id: Group.from(direct_groups_cte_alias) })
groups_from_authorized_projects,
groups_from_shares
])
end
end

View File

@ -13,12 +13,12 @@
url: registration_path(resource_name, ::Onboarding::Status.registration_path_params(params: params)),
button_text: _('Continue')
- if omniauth_enabled? && button_based_providers_enabled?
- if signup_button_based_providers_enabled?
.gl-text-center.gl-pt-5
%label.gl-font-normal
= _('Continue with:')
.gl-flex.gl-flex-col.gl-gap-3
- enabled_button_based_providers.each do |provider|
- enabled_button_based_providers_for_signup.each do |provider|
= render 'devise/shared/omniauth_provider_button',
href: omniauth_authorize_path(:user, provider, ::Onboarding::Status.registration_path_params(params: params)),
provider: provider,

View File

@ -32,7 +32,7 @@
banned: @banned || [],
include_relations: @include_relations,
search: params[:search_groups],
pending_members: @pending_promotion_members,
pending_members_count: @pending_promotion_members_count,
placeholder_users: @placeholder_users_count
).to_json } }
= gl_loading_icon(css_class: 'gl-my-5', size: 'md')

View File

@ -46,5 +46,5 @@
access_requests: @requesters,
include_relations: @include_relations,
search: params[:search_groups],
pending_members: @pending_promotion_members) } }
pending_members_count: @pending_promotion_members_count) } }
= gl_loading_icon(css_class: 'gl-my-5', size: 'md')

View File

@ -0,0 +1,9 @@
---
name: fix_user_authorized_groups
feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/482866
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/165276
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/483175
milestone: '17.5'
group: group::project management
type: gitlab_com_derisk
default_enabled: false

View File

@ -179,7 +179,7 @@ The following data is included in the export:
- Type
- Path
- Access level ([Project](../user/permissions.md#project-members-permissions) and [Group](../user/permissions.md#group-members-permissions))
- Date of last activity. For a list of activities that populate this column, see the [Users API documentation](../api/users.md#get-a-list-of-a-users-activity).
- Date of last activity. For a list of activities that populate this column, see the [Users API documentation](../api/users.md#list-a-users-activity).
Only the first 100,000 user accounts are exported.

View File

@ -141,7 +141,7 @@ Parameters:
| `user_id` | integer | yes | The ID of a service account user. |
| `name` | string | yes | The name of the personal access token. |
| `scopes` | array | yes | Array of scopes of the personal access token. See [personal access token scopes](../user/profile/personal_access_tokens.md#personal-access-token-scopes) for possible values. |
| `expires_at` | date | no | The personal access token expiry date. When left blank, the token follows the [standard rule of expiry for personal access tokens](../user/profile/personal_access_tokens.md#access-token-expiration). |
| `expires_at` | date | no | The personal access token expiry date. When left blank, the token follows the [standard rule of expiry for personal access tokens](../user/profile/personal_access_tokens.md#access-token-expiration). To specify no expiration date, set this value to `null`. |
Example request:

View File

@ -73,6 +73,24 @@ When there was any error sending the email:
}
```
NOTE:
When the ability to **Manage Non-Billable Promotions** is enabled, the newly invited member will be pending administrator approval if the role is billable. To enable **Manage Non-Billable Promotions**:
1. Enable `enable_member_promotion_management` Application Setting
1. Enable `member_promotion_management` Feature Flag
Example response:
```json
{
"queued_users": {
"username_1": "Request queued for administrator approval."
},
"status": "success"
}
```
## List all invitations pending for a group or project
Gets a list of invited group or project members viewable by the authenticated user.

View File

@ -626,6 +626,49 @@ Example response:
}
```
NOTE:
When the ability to **Manage Non-Billable Promotions** is enabled, the newly added member will be pending administrator approval if the role is billable. To enable **Manage Non-Billable Promotions**:
1. Enable `enable_member_promotion_management` Application Setting
1. Enable `member_promotion_management` Feature Flag
Example of queueing a single user:
```shell
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" \
--data "user_id=1&access_level=30" "https://gitlab.example.com/api/v4/groups/:id/members"
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" \
--data "user_id=1&access_level=30" "https://gitlab.example.com/api/v4/projects/:id/members"
```
```json
{
"message":{
"username_1":"Request queued for administrator approval."
}
}
```
Example of queueing multiple users:
```shell
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" \
--data "user_id=1,2&access_level=30" "https://gitlab.example.com/api/v4/groups/:id/members"
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" \
--data "user_id=1,2&access_level=30" "https://gitlab.example.com/api/v4/projects/:id/members"
```
```json
{
"queued_users": {
"username_1": "Request queued for administrator approval.",
"username_2": "Request queued for administrator approval."
},
"status": "success"
}
```
## Edit a member of a group or project
Updates a member of a group or project.
@ -674,6 +717,23 @@ Example response:
}
```
NOTE:
When the ability to **Manage Non-Billable Promotions** is enabled, if the role is changed to a billable one, the request will be sent to administrator approval. To enable **Manage Non-Billable Promotions**:
1. Enable `enable_member_promotion_management` Application Setting
1. Enable `member_promotion_management` Feature Flag
Example response:
```json
{
"message":{
"username_1":"Request queued for administrator approval."
}
}
```
### Set override flag for a member of a group
By default, the access level of LDAP group members is set to the value specified

View File

@ -547,196 +547,7 @@ You can include the user's [custom attributes](custom_attributes.md) in the resp
GET /users/:id?with_custom_attributes=true
```
## Create a user
DETAILS:
**Tier:** Free, Premium, Ultimate
**Offering:** Self-managed, GitLab Dedicated
> - Ability to create an auditor user was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/366404) in GitLab 15.3.
Create a user.
Prerequisites:
- You must be an administrator.
When you create a user, you must specify at least one of the following:
- `password`
- `reset_password`
- `force_random_password`
If `reset_password` and `force_random_password` are both `false`, then `password` is required.
`force_random_password` and `reset_password` take priority over `password`. Also, `reset_password` and
`force_random_password` can be used together.
NOTE:
`private_profile` defaults to the value of the
[Set profiles of new users to private by default](../administration/settings/account_and_limit_settings.md#set-profiles-of-new-users-to-private-by-default) setting.
`bio` defaults to `""` instead of `null`.
```plaintext
POST /users
```
Supported attributes:
| Attribute | Required | Description |
|:-------------------------------------|:---------|:------------|
| `admin` | No | User is an administrator. Valid values are `true` or `false`. Defaults to false. |
| `auditor` | No | User is an auditor. Valid values are `true` or `false`. Defaults to false. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/366404) in GitLab 15.3. Premium and Ultimate only. |
| `avatar` | No | Image file for user's avatar |
| `bio` | No | User's biography |
| `can_create_group` | No | User can create top-level groups - true or false |
| `color_scheme_id` | No | User's color scheme for the file viewer (for more information, see the [user preference documentation](../user/profile/preferences.md#change-the-syntax-highlighting-theme)) |
| `commit_email` | No | User's commit email address |
| `email` | Yes | Email |
| `extern_uid` | No | External UID |
| `external` | No | Flags the user as external - true or false (default) |
| `extra_shared_runners_minutes_limit` | No | Can be set by administrators only. Additional compute minutes for this user. Premium and Ultimate only. |
| `force_random_password` | No | Set user password to a random value - true or false (default) |
| `group_id_for_saml` | No | ID of group where SAML has been configured |
| `linkedin` | No | LinkedIn |
| `location` | No | User's location |
| `name` | Yes | Name |
| `note` | No | Administrator notes for this user |
| `organization` | No | Organization name |
| `password` | No | Password |
| `private_profile` | No | User's profile is private - true or false. The default value is determined by [this](../administration/settings/account_and_limit_settings.md#set-profiles-of-new-users-to-private-by-default) setting. |
| `projects_limit` | No | Number of projects user can create |
| `pronouns` | No | User's pronouns |
| `provider` | No | External provider name |
| `public_email` | No | User's public email address |
| `reset_password` | No | Send user password reset link - true or false(default) |
| `shared_runners_minutes_limit` | No | Can be set by administrators only. Maximum number of monthly compute minutes for this user. Can be `nil` (default; inherit system default), `0` (unlimited), or `> 0`. Premium and Ultimate only. |
| `skip_confirmation` | No | Skip confirmation - true or false (default) |
| `skype` | No | Skype ID |
| `theme_id` | No | GitLab theme for the user (for more information, see the [user preference documentation](../user/profile/preferences.md#change-the-color-theme) for more information) |
| `twitter` | No | X (formerly Twitter) account |
| `discord` | No | Discord account |
| `username` | Yes | Username |
| `view_diffs_file_by_file` | No | Flag indicating the user sees only one file diff per page |
| `website_url` | No | Website URL |
## Modify a user
DETAILS:
**Tier:** Free, Premium, Ultimate
**Offering:** Self-managed, GitLab Dedicated
> - Ability to modify an auditor user was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/366404) in GitLab 15.3.
Modify an existing user.
Prerequisites:
- You must be an administrator.
The `email` field is the user's primary email address. You can only change this field to an already-added secondary
email address for that user. To add more email addresses to the same user, use the [add email endpoint](user_email_addresses.md#add-an-email-address).
```plaintext
PUT /users/:id
```
Supported attributes:
| Attribute | Required | Description |
|:-------------------------------------|:---------|:------------|
| `admin` | No | User is an administrator. Valid values are `true` or `false`. Defaults to false. |
| `auditor` | No | User is an auditor. Valid values are `true` or `false`. Defaults to false. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/366404) in GitLab 15.3.(default) Premium and Ultimate only. |
| `avatar` | No | Image file for user's avatar |
| `bio` | No | User's biography |
| `can_create_group` | No | User can create groups - true or false |
| `color_scheme_id` | No | User's color scheme for the file viewer (for more information, see the [user preference documentation](../user/profile/preferences.md#change-the-syntax-highlighting-theme) for more information) |
| `commit_email` | No | User's commit email. Set to `_private` to use the private commit email. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/375148) in GitLab 15.5. |
| `email` | No | Email |
| `extern_uid` | No | External UID |
| `external` | No | Flags the user as external - true or false (default) |
| `extra_shared_runners_minutes_limit` | No | Can be set by administrators only. Additional compute minutes for this user. Premium and Ultimate only. |
| `group_id_for_saml` | No | ID of group where SAML has been configured |
| `id` | Yes | ID of the user |
| `linkedin` | No | LinkedIn |
| `location` | No | User's location |
| `name` | No | Name |
| `note` | No | Administration notes for this user |
| `organization` | No | Organization name |
| `password` | No | Password |
| `private_profile` | No | User's profile is private - true or false. |
| `projects_limit` | No | Limit projects each user can create |
| `pronouns` | No | Pronouns |
| `provider` | No | External provider name |
| `public_email` | No | Public email of the user (must be already verified) |
| `shared_runners_minutes_limit` | No | Can be set by administrators only. Maximum number of monthly compute minutes for this user. Can be `nil` (default; inherit system default), `0` (unlimited) or `> 0`. Premium and Ultimate only. |
| `skip_reconfirmation` | No | Skip reconfirmation - true or false (default) |
| `skype` | No | Skype ID |
| `theme_id` | No | GitLab theme for the user (for more information, see the [user preference documentation](../user/profile/preferences.md#change-the-color-theme) for more information) |
| `twitter` | No | X (formerly Twitter) account |
| `discord` | No | Discord account |
| `username` | No | Username |
| `view_diffs_file_by_file` | No | Flag indicating the user sees only one file diff per page |
| `website_url` | No | Website URL |
If you update a user's password, they are forced to change it when they next sign in.
Returns a `404` error, even in cases where a `409` (Conflict) would be more appropriate.
For example, when renaming the email address to an existing one.
## Delete authentication identity from a user
DETAILS:
**Tier:** Free, Premium, Ultimate
**Offering:** Self-managed, GitLab Dedicated
Delete a user's authentication identity using the provider name associated with that identity.
Prerequisites:
- You must be an administrator.
```plaintext
DELETE /users/:id/identities/:provider
```
Supported attributes:
| Attribute | Type | Required | Description |
|:-----------|:--------|:---------|:------------|
| `id` | integer | yes | ID of a user |
| `provider` | string | yes | External provider name |
## Delete a user
DETAILS:
**Tier:** Free, Premium, Ultimate
**Offering:** Self-managed, GitLab Dedicated
Delete a user.
Prerequisites:
- You must be an administrator.
Returns:
- `204 No Content` status code if the operation was successful.
- `404` if the resource was not found.
- `409` if the user cannot be soft deleted.
```plaintext
DELETE /users/:id
```
Supported attributes:
| Attribute | Type | Required | Description |
|:--------------|:--------|:---------|:------------|
| `id` | integer | yes | ID of a user |
| `hard_delete` | boolean | no | If true, contributions that would usually be [moved to Ghost User](../user/profile/account/delete_account.md#associated-records) are deleted instead, as well as groups owned solely by this user. |
## List the current user
## Get the current user
Get the current user.
@ -879,6 +690,172 @@ parameters:
- `provisioned_by_group_id`
- `using_license_seat`
## Create a user
DETAILS:
**Tier:** Free, Premium, Ultimate
**Offering:** Self-managed, GitLab Dedicated
> - Ability to create an auditor user was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/366404) in GitLab 15.3.
Create a user.
Prerequisites:
- You must be an administrator.
When you create a user, you must specify at least one of the following:
- `password`
- `reset_password`
- `force_random_password`
If `reset_password` and `force_random_password` are both `false`, then `password` is required.
`force_random_password` and `reset_password` take priority over `password`. Also, `reset_password` and
`force_random_password` can be used together.
NOTE:
`private_profile` defaults to the value of the
[Set profiles of new users to private by default](../administration/settings/account_and_limit_settings.md#set-profiles-of-new-users-to-private-by-default) setting.
`bio` defaults to `""` instead of `null`.
```plaintext
POST /users
```
Supported attributes:
| Attribute | Required | Description |
|:-------------------------------------|:---------|:------------|
| `admin` | No | User is an administrator. Valid values are `true` or `false`. Defaults to false. |
| `auditor` | No | User is an auditor. Valid values are `true` or `false`. Defaults to false. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/366404) in GitLab 15.3. Premium and Ultimate only. |
| `avatar` | No | Image file for user's avatar |
| `bio` | No | User's biography |
| `can_create_group` | No | User can create top-level groups - true or false |
| `color_scheme_id` | No | User's color scheme for the file viewer (for more information, see the [user preference documentation](../user/profile/preferences.md#change-the-syntax-highlighting-theme)) |
| `commit_email` | No | User's commit email address |
| `email` | Yes | Email |
| `extern_uid` | No | External UID |
| `external` | No | Flags the user as external - true or false (default) |
| `extra_shared_runners_minutes_limit` | No | Can be set by administrators only. Additional compute minutes for this user. Premium and Ultimate only. |
| `force_random_password` | No | Set user password to a random value - true or false (default) |
| `group_id_for_saml` | No | ID of group where SAML has been configured |
| `linkedin` | No | LinkedIn |
| `location` | No | User's location |
| `name` | Yes | Name |
| `note` | No | Administrator notes for this user |
| `organization` | No | Organization name |
| `password` | No | Password |
| `private_profile` | No | User's profile is private - true or false. The default value is determined by [a setting](../administration/settings/account_and_limit_settings.md#set-profiles-of-new-users-to-private-by-default). |
| `projects_limit` | No | Number of projects user can create |
| `pronouns` | No | User's pronouns |
| `provider` | No | External provider name |
| `public_email` | No | User's public email address |
| `reset_password` | No | Send user password reset link - true or false(default) |
| `shared_runners_minutes_limit` | No | Can be set by administrators only. Maximum number of monthly compute minutes for this user. Can be `nil` (default; inherit system default), `0` (unlimited), or `> 0`. Premium and Ultimate only. |
| `skip_confirmation` | No | Skip confirmation - true or false (default) |
| `skype` | No | Skype ID |
| `theme_id` | No | GitLab theme for the user (for more information, see the [user preference documentation](../user/profile/preferences.md#change-the-color-theme) for more information) |
| `twitter` | No | X (formerly Twitter) account |
| `discord` | No | Discord account |
| `username` | Yes | Username |
| `view_diffs_file_by_file` | No | Flag indicating the user sees only one file diff per page |
| `website_url` | No | Website URL |
## Modify a user
DETAILS:
**Tier:** Free, Premium, Ultimate
**Offering:** Self-managed, GitLab Dedicated
> - Ability to modify an auditor user was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/366404) in GitLab 15.3.
Modify an existing user.
Prerequisites:
- You must be an administrator.
The `email` field is the user's primary email address. You can only change this field to an already-added secondary
email address for that user. To add more email addresses to the same user, use the [add email endpoint](user_email_addresses.md#add-an-email-address).
```plaintext
PUT /users/:id
```
Supported attributes:
| Attribute | Required | Description |
|:-------------------------------------|:---------|:------------|
| `admin` | No | User is an administrator. Valid values are `true` or `false`. Defaults to false. |
| `auditor` | No | User is an auditor. Valid values are `true` or `false`. Defaults to false. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/366404) in GitLab 15.3.(default) Premium and Ultimate only. |
| `avatar` | No | Image file for user's avatar |
| `bio` | No | User's biography |
| `can_create_group` | No | User can create groups - true or false |
| `color_scheme_id` | No | User's color scheme for the file viewer (for more information, see the [user preference documentation](../user/profile/preferences.md#change-the-syntax-highlighting-theme) for more information) |
| `commit_email` | No | User's commit email. Set to `_private` to use the private commit email. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/375148) in GitLab 15.5. |
| `email` | No | Email |
| `extern_uid` | No | External UID |
| `external` | No | Flags the user as external - true or false (default) |
| `extra_shared_runners_minutes_limit` | No | Can be set by administrators only. Additional compute minutes for this user. Premium and Ultimate only. |
| `group_id_for_saml` | No | ID of group where SAML has been configured |
| `id` | Yes | ID of the user |
| `linkedin` | No | LinkedIn |
| `location` | No | User's location |
| `name` | No | Name |
| `note` | No | Administration notes for this user |
| `organization` | No | Organization name |
| `password` | No | Password |
| `private_profile` | No | User's profile is private - true or false. |
| `projects_limit` | No | Limit projects each user can create |
| `pronouns` | No | Pronouns |
| `provider` | No | External provider name |
| `public_email` | No | Public email of the user (must be already verified) |
| `shared_runners_minutes_limit` | No | Can be set by administrators only. Maximum number of monthly compute minutes for this user. Can be `nil` (default; inherit system default), `0` (unlimited) or `> 0`. Premium and Ultimate only. |
| `skip_reconfirmation` | No | Skip reconfirmation - true or false (default) |
| `skype` | No | Skype ID |
| `theme_id` | No | GitLab theme for the user (for more information, see the [user preference documentation](../user/profile/preferences.md#change-the-color-theme) for more information) |
| `twitter` | No | X (formerly Twitter) account |
| `discord` | No | Discord account |
| `username` | No | Username |
| `view_diffs_file_by_file` | No | Flag indicating the user sees only one file diff per page |
| `website_url` | No | Website URL |
If you update a user's password, they are forced to change it when they next sign in.
Returns a `404` error, even in cases where a `409` (Conflict) would be more appropriate.
For example, when renaming the email address to an existing one.
## Delete a user
DETAILS:
**Tier:** Free, Premium, Ultimate
**Offering:** Self-managed, GitLab Dedicated
Delete a user.
Prerequisites:
- You must be an administrator.
Returns:
- `204 No Content` status code if the operation was successful.
- `404` if the resource was not found.
- `409` if the user cannot be soft deleted.
```plaintext
DELETE /users/:id
```
Supported attributes:
| Attribute | Type | Required | Description |
|:--------------|:--------|:---------|:------------|
| `id` | integer | yes | ID of a user |
| `hard_delete` | boolean | no | If true, contributions that would usually be [moved to Ghost User](../user/profile/account/delete_account.md#associated-records) are deleted instead, and also groups owned solely by this user. |
## Get your user status
Get your user status.
@ -1039,6 +1016,52 @@ Supported attributes:
| `show_whitespace_in_diffs` | Yes | Flag indicating the user sees whitespace changes in diffs. |
| `pass_user_identities_to_ci_jwt` | Yes | Flag indicating the user passes their external identities as CI information. This attribute does not contain enough information to identify or authorize the user in an external system. The attribute is internal to GitLab, and must not be passed to third-party services. For more information and examples, see [Token Payload](../ci/secrets/id_token_authentication.md#token-payload). |
## Upload an avatar for yourself
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/148130) in GitLab 17.0.
Upload an avatar for yourself.
Prerequisites:
- You must be authenticated.
```plaintext
PUT /user/avatar
```
Supported attributes:
| Attribute | Type | Required | Description |
|:----------|:-------|:---------|:------------|
| `avatar` | string | Yes | The file to be uploaded. The ideal image size is 192 x 192 pixels. The maximum file size allowed is 200 KiB. |
To upload an avatar from your file system, use the `--form` argument. This causes
cURL to post data using the header `Content-Type: multipart/form-data`. The
`file=` parameter must point to an image file on your file system and be
preceded by `@`. For example:
Example request:
```shell
curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" \
--form "avatar=@avatar.png" \
--url "https://gitlab.example.com/api/v4/user/avatar"
```
Example response:
```json
{
"avatar_url": "http://gdk.test:3000/uploads/-/system/user/avatar/76/avatar.png",
}
```
Returns:
- `200` if successful.
- `400 Bad Request` for file sizes greater than 200 KiB.
## Get a count of your assigned issues, merge requests, and reviews
Get a count of your assigned issues, merge requests, and reviews.
@ -1111,7 +1134,7 @@ Example response:
}
```
## Get a list of a user's activity
## List a user's activity
DETAILS:
**Tier:** Free, Premium, Ultimate
@ -1174,7 +1197,7 @@ Example response:
`last_activity_at` is deprecated. Use `last_activity_on` instead.
## Get a list of projects and groups that a user is a member of
## List projects and groups that a user is a member of
DETAILS:
**Tier:** Free, Premium, Ultimate
@ -1327,48 +1350,25 @@ Example response:
}
```
## Upload an avatar for yourself
## Delete authentication identity from a user
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/148130) in GitLab 17.0.
DETAILS:
**Tier:** Free, Premium, Ultimate
**Offering:** Self-managed, GitLab Dedicated
Upload an avatar for yourself.
Delete a user's authentication identity using the provider name associated with that identity.
Prerequisites:
- You must be authenticated.
- You must be an administrator.
```plaintext
PUT /user/avatar
DELETE /users/:id/identities/:provider
```
Supported attributes:
| Attribute | Type | Required | Description |
|:----------|:-------|:---------|:------------|
| `avatar` | string | Yes | The file to be uploaded. The ideal image size is 192 x 192 pixels. The maximum file size allowed is 200 KiB. |
To upload an avatar from your file system, use the `--form` argument. This causes
cURL to post data using the header `Content-Type: multipart/form-data`. The
`file=` parameter must point to an image file on your file system and be
preceded by `@`. For example:
Example request:
```shell
curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" \
--form "avatar=@avatar.png" \
--url "https://gitlab.example.com/api/v4/user/avatar"
```
Example response:
```json
{
"avatar_url": "http://gdk.test:3000/uploads/-/system/user/avatar/76/avatar.png",
}
```
Returns:
- `200` if successful.
- `400 Bad Request` for file sizes greater than 200 KiB.
| Attribute | Type | Required | Description |
|:-----------|:--------|:---------|:------------|
| `id` | integer | yes | ID of a user |
| `provider` | string | yes | External provider name |

View File

@ -189,8 +189,8 @@ you use to provision and register new values.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/30942) in GitLab 15.3 [with a flag](../../administration/feature_flags.md) named `enforce_runner_token_expires_at`. Disabled by default.
> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/377902) in GitLab 15.5. Feature flag `enforce_runner_token_expires_at` removed.
Each runner has an [runner authentication token](../../api/runners.md#registration-and-authentication-tokens)
to connect with the GitLab instance.
Each runner uses a [runner authentication token](../../api/runners.md#registration-and-authentication-tokens)
to connect to and authenticate with a GitLab instance.
To help prevent the token from being compromised, you can have the
token rotate automatically at specified intervals. When the tokens are rotated,

View File

@ -357,14 +357,16 @@ in the relevant projects:
- <https://gitlab.com/gitlab-org/charts/gitlab/-/blob/master/.gitlab-ci.yml>
- <https://gitlab.com/gitlab-org/cloud-native/gitlab-operator/-/blob/master/.gitlab-ci.yml>
We also run some documentation tests in the:
We also run some documentation tests in these projects:
- GitLab CLI project: <https://gitlab.com/gitlab-org/cli/-/blob/main/.gitlab-ci.yml>
- GitLab Development Kit project:
<https://gitlab.com/gitlab-org/gitlab-development-kit/-/blob/main/.gitlab/ci/test.gitlab-ci.yml>.
- Gitaly project: <https://gitlab.com/gitlab-org/gitaly/-/blob/master/.gitlab-ci.yml>.
- GitLab CLI: <https://gitlab.com/gitlab-org/cli/-/blob/main/.gitlab-ci.yml>
- GitLab Development Kit:
<https://gitlab.com/gitlab-org/gitlab-development-kit/-/blob/main/.gitlab/ci/test.gitlab-ci.yml>
- Gitaly: <https://gitlab.com/gitlab-org/gitaly/-/blob/master/.gitlab-ci.yml>
- GitLab Duo Plugin for JetBrains: <https://gitlab.com/gitlab-org/editor-extensions/gitlab-jetbrains-plugin/-/blob/main/.gitlab-ci.yml>
- GitLab Workflow extension for VS Code project: <https://gitlab.com/gitlab-org/gitlab-vscode-extension/-/blob/main/.gitlab-ci.yml>.
- GitLab Plugin for Neovim project: <https://gitlab.com/gitlab-org/editor-extensions/gitlab.vim/-/blob/main/.gitlab-ci.yml>.
- GitLab Language Server project: <https://gitlab.com/gitlab-org/editor-extensions/gitlab-lsp/-/blob/main/.gitlab-ci.yml>.
- GitLab Extension for Visual Studio project: <https://gitlab.com/gitlab-org/editor-extensions/gitlab-visual-studio-extension/-/blob/main/.gitlab-ci.yml>.
- GitLab Workflow extension for VS Code: <https://gitlab.com/gitlab-org/gitlab-vscode-extension/-/blob/main/.gitlab-ci.yml>
- GitLab Plugin for Neovim: <https://gitlab.com/gitlab-org/editor-extensions/gitlab.vim/-/blob/main/.gitlab-ci.yml>
- GitLab Language Server: <https://gitlab.com/gitlab-org/editor-extensions/gitlab-lsp/-/blob/main/.gitlab-ci.yml>
- GitLab Extension for Visual Studio: <https://gitlab.com/gitlab-org/editor-extensions/gitlab-visual-studio-extension/-/blob/main/.gitlab-ci.yml>
- AI Gateway: <https://gitlab.com/gitlab-org/modelops/applied-ml/code-suggestions/ai-assist/-/blob/main/.gitlab/ci/lint.gitlab-ci.yml>
- Prompt Library: <https://gitlab.com/gitlab-org/modelops/ai-model-validation-and-research/ai-evaluation/prompt-library/-/blob/main/.gitlab-ci.yml>

View File

@ -30,7 +30,7 @@ can be used for inter-process communication in cases where [PostgreSQL](sql.md)
is less appropriate. For example, transient state or data that is written much
more often than it is read.
If [Geo](geo.md) is enabled, each Geo node gets its own, independent Redis
If [Geo](geo.md) is enabled, each Geo site gets its own, independent Redis
database.
We have [development documentation on adding a new Redis instance](redis/new_redis_instance.md).

View File

@ -50,7 +50,8 @@ You can use GitLab Flavored Markdown in the following areas:
You can also use other rich text files in GitLab. You might have to install a dependency
to do so. For more information, see the [`gitlab-markup` gem project](https://gitlab.com/gitlab-org/gitlab-markup).
Support for improvements to Markdown preview when using GitLab Flavored Markdown in the Web IDE is proposed in [issue 645](https://gitlab.com/gitlab-org/gitlab-vscode-extension/-/issues/645).
Support for GitLab Flavored Markdown preview in the Web IDE is proposed in
[issue 645](https://gitlab.com/gitlab-org/gitlab-vscode-extension/-/issues/645).
### Differences between GitLab Flavored Markdown and standard Markdown

View File

@ -37,17 +37,13 @@ When a branch is protected, the default behavior enforces these restrictions on
|:-------------------------|:----------------------------------------|
| Protect a branch | At least the Maintainer role. |
| Push to the branch | Anyone with **Allowed** permission. (1) |
| Force push to the branch | No one. (3) |
| Force push to the branch | No one. |
| Delete the branch | No one. (2) |
1. Users with the Developer role can create a project in a group, but might not be allowed to
initially push to the [default branch](default.md).
1. No one can delete a protected branch using Git commands, however, users with at least Maintainer
role can [delete a protected branch from the UI or API](#delete-a-protected-branch).
1. If the `group_protected_branches` feature flag is enabled _and_ the same branch is
protected at both the group and project levels, force push settings configured
for that branch at the project level are ignored. All other protections continue
to use project level settings.
You can implement a [merge request approval policy](../../../application_security/policies/merge_request_approval_policies.md#approval_settings)
to prevent protected branches being unprotected or deleted.
@ -136,10 +132,7 @@ To make it available, an administrator can
named `group_protected_branches`. On GitLab.com and GitLab Dedicated, this feature is not available.
Group owners can create protected branches for a group. These settings are inherited
by all projects in the group and can't be overridden by project settings. If a
specific branch is configured with **Allowed to force push** settings at both the
group and project levels, the **Allowed to force push** setting at the _project_ level
is ignored in favor of the group level setting.
by all projects in the group and can't be overridden by project settings.
Prerequisites:
@ -310,11 +303,6 @@ As the most permissive option determines the behavior, the resulting permissions
and controls branch behavior as a result. Even though the branch also matched `v1.x` and `v*`
(which each have stricter permissions), any user that can push to this branch can also force push.
NOTE:
Force push settings for a branch at the project level are overridden by group level settings
if the `group_protected_branches` feature flag is enabled and a group owner has set
[group level protection for the same branch](#for-all-projects-in-a-group).
## Require Code Owner approval on a protected branch
DETAILS:

View File

@ -25,7 +25,8 @@ For a more basic implementation, see [Web Editor](../repository/web_editor.md).
To pair the Web IDE with a remote development environment, see [Remote development](../remote_development/index.md).
Support for improvements to Markdown preview when using GitLab Flavored Markdown in the Web IDE is proposed in [issue 645](https://gitlab.com/gitlab-org/gitlab-vscode-extension/-/issues/645).
Support for [GitLab Flavored Markdown](../../markdown.md) preview in the Web IDE is proposed in
[issue 645](https://gitlab.com/gitlab-org/gitlab-vscode-extension/-/issues/645).
## Open the Web IDE

View File

@ -577,8 +577,8 @@ module API
render_api_error!('201 Created', 201)
end
def accepted!
render_api_error!('202 Accepted', 202)
def accepted!(message = '202 Accepted')
render_api_error!(message, 202)
end
def render_validation_error!(models, status = 400)

View File

@ -105,12 +105,16 @@ module API
member = instance.single_member
render_validation_error!(member) if member&.invalid?
# if errors occurred besides model validations or authorization failures,
# render those appropriately
if result[:status] == :error
render_structured_api_error!(result, :bad_request)
present_add_single_member_response(result, member)
end
def present_put_membership_response(result)
updated_member = result[:members].first
if result[:status] == :success
present_members updated_member
else
present_members(member)
render_validation_error!(updated_member)
end
end
@ -134,6 +138,16 @@ module API
def member_already_exists?(source, user_id)
source.members.exists?(user_id: user_id) # rubocop: disable CodeReuse/ActiveRecord
end
def present_add_single_member_response(result, member)
# if errors occurred besides model validations or authorization failures,
# render those appropriately
if result[:status] == :error
render_structured_api_error!(result, :bad_request)
else
present_members(member)
end
end
end
end
end

View File

@ -152,13 +152,7 @@ module API
.new(current_user, declared_params(include_missing: false))
.execute(member)
updated_member = result[:members].first
if result[:status] == :success
present_members updated_member
else
render_validation_error!(updated_member)
end
present_put_membership_response(result)
end
# rubocop: enable CodeReuse/ActiveRecord

View File

@ -37282,6 +37282,9 @@ msgstr ""
msgid "ObservabilityMetrics|Error: Failed to load metrics details. Try reloading the page."
msgstr ""
msgid "ObservabilityMetrics|Error: Unable to create metric snapshot image."
msgstr ""
msgid "ObservabilityMetrics|Failed to load metrics."
msgstr ""
@ -62002,6 +62005,11 @@ msgid_plural "WorkItem|%{workItemType} is blocked by %{itemCount} items"
msgstr[0] ""
msgstr[1] ""
msgid "WorkItem|+%d more item"
msgid_plural "WorkItem|+%d more items"
msgstr[0] ""
msgstr[1] ""
msgid "WorkItem|A non-confidential %{workItemType} cannot be assigned to a confidential parent %{parentWorkItemType}."
msgstr ""

View File

@ -184,6 +184,7 @@
"mermaid": "10.7.0",
"micromatch": "^4.0.5",
"minimatch": "^3.0.4",
"modern-screenshot": "^4.4.39",
"monaco-editor": "^0.30.1",
"monaco-editor-webpack-plugin": "^6.0.0",
"monaco-yaml": "4.0.0",

View File

@ -1,258 +1,251 @@
{
"qa/specs/features/api/10_govern/group_access_token_spec.rb": 12.397871947000112,
"qa/specs/features/api/10_govern/project_access_token_spec.rb": 37.23903082000004,
"qa/specs/features/api/1_manage/migration/gitlab_migration_project_spec.rb": 121.145597555,
"qa/specs/features/api/1_manage/rate_limits_spec.rb": 2.453305433999958,
"qa/specs/features/api/2_plan/closes_issue_via_pushing_a_commit_spec.rb": 7.209470354000132,
"qa/specs/features/api/3_create/merge_request/push_options_labels_spec.rb": 10.633708354999953,
"qa/specs/features/api/3_create/merge_request/push_options_mwps_spec.rb": 9.515109185000028,
"qa/specs/features/api/3_create/merge_request/push_options_remove_source_branch_spec.rb": 12.95933420700021,
"qa/specs/features/api/3_create/merge_request/push_options_target_branch_spec.rb": 10.712993371000266,
"qa/specs/features/api/3_create/merge_request/push_options_title_description_spec.rb": 22.123816485999896,
"qa/specs/features/api/3_create/repository/add_list_delete_branches_spec.rb": 5.575647242000059,
"qa/specs/features/api/3_create/repository/commit_to_templated_project_spec.rb": 8.450835704999918,
"qa/specs/features/api/3_create/repository/default_branch_name_setting_spec.rb": 6.0398892079997495,
"qa/specs/features/api/3_create/repository/files_spec.rb": 2.84329607199993,
"qa/specs/features/api/3_create/repository/project_archive_compare_spec.rb": 5.720794561000048,
"qa/specs/features/api/3_create/repository/push_postreceive_idempotent_spec.rb": 8.671697718000132,
"qa/specs/features/api/3_create/repository/storage_size_spec.rb": 14.04211848500006,
"qa/specs/features/api/3_create/repository/tag_revision_trigger_prereceive_hook_spec.rb": 2.0491826810000475,
"qa/specs/features/api/4_verify/api_variable_inheritance_with_forward_pipeline_variables_spec.rb": 56.58822126100017,
"qa/specs/features/api/4_verify/cancel_pipeline_when_block_user_spec.rb": 5.542681564000077,
"qa/specs/features/api/4_verify/file_variable_spec.rb": 29.22528023399991,
"qa/specs/features/api/4_verify/job_downloads_artifacts_spec.rb": 15.794122663999588,
"qa/specs/features/api/9_data_stores/user_inherited_access_spec.rb": 70.58858790399995,
"qa/specs/features/api/9_data_stores/users_spec.rb": 0.4996049840001433,
"qa/specs/features/browser_ui/10_govern/group/group_access_token_spec.rb": 10.296608160999995,
"qa/specs/features/browser_ui/10_govern/login/2fa_recovery_spec.rb": 49.564313320999986,
"qa/specs/features/browser_ui/10_govern/login/2fa_ssh_recovery_spec.rb": 31.97967125299965,
"qa/specs/features/browser_ui/10_govern/login/log_in_spec.rb": 8.875357668999982,
"qa/specs/features/browser_ui/10_govern/login/log_in_with_2fa_spec.rb": 68.2847945389999,
"qa/specs/features/browser_ui/10_govern/login/login_via_oauth_and_oidc_with_gitlab_as_idp_spec.rb": 431.209770424,
"qa/specs/features/browser_ui/10_govern/login/register_spec.rb": 181.24613914499992,
"qa/specs/features/browser_ui/10_govern/project/project_access_token_spec.rb": 12.759093617999952,
"qa/specs/features/browser_ui/10_govern/user/impersonation_token_spec.rb": 29.862426868000057,
"qa/specs/features/browser_ui/10_govern/user/user_access_termination_spec.rb": 36.48008158399989,
"qa/specs/features/browser_ui/14_analytics/performance_bar_spec.rb": 18.323326968999936,
"qa/specs/features/browser_ui/14_analytics/service_ping_default_enabled_spec.rb": 9.91786422899986,
"qa/specs/features/browser_ui/1_manage/integrations/jenkins/jenkins_build_status_spec.rb": 62.74245996399986,
"qa/specs/features/browser_ui/2_plan/design_management/add_design_content_spec.rb": 12.972298938999984,
"qa/specs/features/browser_ui/2_plan/design_management/archive_design_content_spec.rb": 21.18130115100007,
"qa/specs/features/browser_ui/2_plan/design_management/modify_design_content_spec.rb": 12.365103047000048,
"qa/specs/features/browser_ui/2_plan/issue/check_mentions_for_xss_spec.rb": 12.350918417000003,
"qa/specs/features/browser_ui/2_plan/issue/collapse_comments_in_discussions_spec.rb": 16.988709157000017,
"qa/specs/features/browser_ui/2_plan/issue/comment_issue_spec.rb": 13.298123846999943,
"qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb": 37.74972280200018,
"qa/specs/features/browser_ui/2_plan/issue/custom_issue_template_spec.rb": 18.49045557999989,
"qa/specs/features/browser_ui/2_plan/issue/export_as_csv_spec.rb": 11.60536830400008,
"qa/specs/features/browser_ui/2_plan/issue/filter_issue_comments_spec.rb": 16.35631897600001,
"qa/specs/features/browser_ui/2_plan/issue/issue_suggestions_spec.rb": 12.273179357999993,
"qa/specs/features/browser_ui/2_plan/issue/mentions_spec.rb": 12.95962527399979,
"qa/specs/features/browser_ui/2_plan/issue/real_time_assignee_spec.rb": 12.479864686999917,
"qa/specs/features/browser_ui/2_plan/issue_boards/focus_mode_spec.rb": 10.416517890000023,
"qa/specs/features/browser_ui/2_plan/milestone/assign_milestone_spec.rb": 55.117152813000075,
"qa/specs/features/browser_ui/2_plan/milestone/create_group_milestone_spec.rb": 14.865196981999816,
"qa/specs/features/browser_ui/2_plan/milestone/create_project_milestone_spec.rb": 17.427250706999985,
"qa/specs/features/browser_ui/2_plan/project_wiki/project_based_content_creation_spec.rb": 56.926687345000005,
"qa/specs/features/browser_ui/2_plan/project_wiki/project_based_content_manipulation_spec.rb": 34.26779686000009,
"qa/specs/features/browser_ui/2_plan/project_wiki/project_based_directory_management_spec.rb": 13.058623059999718,
"qa/specs/features/browser_ui/2_plan/project_wiki/project_based_file_upload_spec.rb": 17.17543610699977,
"qa/specs/features/browser_ui/2_plan/project_wiki/project_based_list_spec.rb": 35.62580278899986,
"qa/specs/features/browser_ui/2_plan/project_wiki/project_based_page_deletion_spec.rb": 33.17074543900003,
"qa/specs/features/browser_ui/2_plan/related_issues/related_issues_spec.rb": 11.858483000999968,
"qa/specs/features/browser_ui/2_plan/transient/comment_on_discussion_spec.rb": 96.11224141399998,
"qa/specs/features/browser_ui/3_create/merge_request/cherry_pick/cherry_pick_a_merge_spec.rb": 23.108933895000064,
"qa/specs/features/browser_ui/3_create/merge_request/cherry_pick/cherry_pick_commit_spec.rb": 14.581709606999993,
"qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_spec.rb": 52.01036585300017,
"qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_via_template_spec.rb": 15.210137743000018,
"qa/specs/features/browser_ui/3_create/merge_request/merge_merge_request_from_fork_spec.rb": 27.128310960999897,
"qa/specs/features/browser_ui/3_create/merge_request/rebase_merge_request_spec.rb": 29.26279021299979,
"qa/specs/features/browser_ui/3_create/merge_request/revert/revert_commit_spec.rb": 18.322653746000015,
"qa/specs/features/browser_ui/3_create/merge_request/revert/reverting_merge_request_spec.rb": 19.307837559999825,
"qa/specs/features/browser_ui/3_create/merge_request/squash_merge_request_spec.rb": 18.26698207300001,
"qa/specs/features/browser_ui/3_create/merge_request/suggestions/batch_suggestion_spec.rb": 37.257067328000176,
"qa/specs/features/browser_ui/3_create/merge_request/suggestions/custom_commit_suggestion_spec.rb": 28.395653977000165,
"qa/specs/features/browser_ui/3_create/merge_request/view_merge_request_diff_patch_spec.rb": 26.92004345800001,
"qa/specs/features/browser_ui/3_create/repository/add_file_template_spec.rb": 58.52073852400008,
"qa/specs/features/browser_ui/3_create/repository/add_new_branch_rule_spec.rb": 17.781753611999875,
"qa/specs/features/browser_ui/3_create/repository/branch_with_unusual_name_spec.rb": 12.242755597000041,
"qa/specs/features/browser_ui/3_create/repository/clone_spec.rb": 9.960431046000167,
"qa/specs/features/browser_ui/3_create/repository/file/create_file_via_web_spec.rb": 15.371727186000044,
"qa/specs/features/browser_ui/3_create/repository/file/delete_file_via_web_spec.rb": 12.087864284999796,
"qa/specs/features/browser_ui/3_create/repository/file/edit_file_via_web_spec.rb": 12.127680071999976,
"qa/specs/features/browser_ui/3_create/repository/file/file_with_unusual_name_spec.rb": 13.449512228999993,
"qa/specs/features/browser_ui/3_create/repository/license_detection_spec.rb": 29.89524966800002,
"qa/specs/features/browser_ui/3_create/repository/protected_tags_spec.rb": 82.36627285899999,
"qa/specs/features/browser_ui/3_create/repository/protocol_v2_push_http_spec.rb": 14.41380467099998,
"qa/specs/features/browser_ui/3_create/repository/protocol_v2_push_ssh_spec.rb": 14.242686575000107,
"qa/specs/features/browser_ui/3_create/repository/push_http_private_token_spec.rb": 12.413497467999605,
"qa/specs/features/browser_ui/3_create/repository/push_mirroring_lfs_over_http_spec.rb": 51.00565575399992,
"qa/specs/features/browser_ui/3_create/repository/push_mirroring_over_http_spec.rb": 24.197618695000074,
"qa/specs/features/browser_ui/3_create/repository/push_over_http_file_size_spec.rb": 40.23107726799981,
"qa/specs/features/browser_ui/3_create/repository/push_over_http_spec.rb": 11.946123556999964,
"qa/specs/features/browser_ui/3_create/repository/push_over_ssh_spec.rb": 24.566063014000065,
"qa/specs/features/browser_ui/3_create/repository/push_protected_branch_spec.rb": 10.99895531600032,
"qa/specs/features/browser_ui/3_create/repository/push_to_canary_gitaly_spec.rb": 19.954812592000053,
"qa/specs/features/browser_ui/3_create/repository/ssh_key_support_create_spec.rb": 11.979494855999747,
"qa/specs/features/browser_ui/3_create/repository/ssh_key_support_delete_spec.rb": 13.269448764000003,
"qa/specs/features/browser_ui/3_create/repository/user_views_commit_diff_patch_spec.rb": 22.301814552999986,
"qa/specs/features/browser_ui/3_create/snippet/add_comment_to_snippet_spec.rb": 35.360918446999904,
"qa/specs/features/browser_ui/3_create/snippet/add_file_to_snippet_spec.rb": 25.735420180000006,
"qa/specs/features/browser_ui/3_create/snippet/clone_push_pull_personal_snippet_spec.rb": 32.776856023999926,
"qa/specs/features/browser_ui/3_create/snippet/clone_push_pull_project_snippet_spec.rb": 47.560282256999926,
"qa/specs/features/browser_ui/3_create/snippet/copy_snippet_file_contents_spec.rb": 26.71346316800009,
"qa/specs/features/browser_ui/3_create/snippet/create_personal_snippet_spec.rb": 9.19937098000014,
"qa/specs/features/browser_ui/3_create/snippet/create_personal_snippet_with_multiple_files_spec.rb": 8.94432519999998,
"qa/specs/features/browser_ui/3_create/snippet/create_project_snippet_spec.rb": 15.440743931000043,
"qa/specs/features/browser_ui/3_create/snippet/create_project_snippet_with_multiple_files_spec.rb": 20.027893337000023,
"qa/specs/features/browser_ui/3_create/snippet/delete_file_from_snippet_spec.rb": 22.887218332999964,
"qa/specs/features/browser_ui/3_create/snippet/share_snippet_spec.rb": 19.402230539000016,
"qa/specs/features/browser_ui/3_create/snippet/snippet_index_page_spec.rb": 53.591218443000116,
"qa/specs/features/browser_ui/3_create/source_editor/source_editor_toolbar_spec.rb": 20.280463688000054,
"qa/specs/features/browser_ui/3_create/web_ide/add_first_file_in_web_ide_spec.rb": 41.50735434999979,
"qa/specs/features/browser_ui/3_create/web_ide/add_new_directory_in_web_ide_spec.rb": 61.49260960100037,
"qa/specs/features/browser_ui/3_create/web_ide/closing_web_ide_with_unsaved_changes_spec.rb": 17.63215369400018,
"qa/specs/features/browser_ui/3_create/web_ide/upload_new_file_in_web_ide_spec.rb": 145.06106596300015,
"qa/specs/features/browser_ui/4_verify/ci_components_catalog/ci_catalog_sorting_spec.rb": 70.48372362600003,
"qa/specs/features/browser_ui/4_verify/ci_components_catalog/run_component_in_project_pipeline_spec.rb": 38.94410077600014,
"qa/specs/features/browser_ui/4_verify/ci_job_artifacts/expose_job_artifacts_in_mr_spec.rb": 22.367475329999934,
"qa/specs/features/browser_ui/4_verify/ci_job_artifacts/job_artifacts_access_keyword_spec.rb": 119.9387103099998,
"qa/specs/features/browser_ui/4_verify/ci_job_artifacts/unlocking_job_artifacts_across_pipelines_spec.rb": 184.36148940700002,
"qa/specs/features/browser_ui/4_verify/ci_project_artifacts/user_can_bulk_delete_artifacts_spec.rb": 37.10709434699993,
"qa/specs/features/browser_ui/4_verify/ci_variable/custom_variable_spec.rb": 33.05014461699989,
"qa/specs/features/browser_ui/4_verify/ci_variable/pipeline_with_protected_variable_spec.rb": 55.08954772700008,
"qa/specs/features/browser_ui/4_verify/ci_variable/prefill_variables_spec.rb": 28.18033253600015,
"qa/specs/features/browser_ui/4_verify/ci_variable/raw_variables_defined_in_yaml_spec.rb": 16.35037038099972,
"qa/specs/features/browser_ui/4_verify/ci_variable/ui_variable_inheritable_when_forward_pipeline_variables_true_spec.rb": 46.55407898899966,
"qa/specs/features/browser_ui/4_verify/pipeline/include_local_config_file_paths_with_wildcard_spec.rb": 12.40527249600018,
"qa/specs/features/browser_ui/4_verify/pipeline/include_multiple_files_from_a_project_spec.rb": 31.567785722000053,
"qa/specs/features/browser_ui/4_verify/pipeline/include_multiple_files_from_multiple_projects_spec.rb": 32.14873077800007,
"qa/specs/features/browser_ui/4_verify/pipeline/parent_child_pipelines_independent_relationship_spec.rb": 159.25057481,
"qa/specs/features/browser_ui/4_verify/pipeline/pass_dotenv_variables_to_downstream_via_bridge_spec.rb": 30.228817518999904,
"qa/specs/features/browser_ui/4_verify/pipeline/pipeline_with_image_pull_policy_spec.rb": 62.828434690999984,
"qa/specs/features/browser_ui/4_verify/pipeline/run_pipeline_via_web_only_spec.rb": 20.732332309999947,
"qa/specs/features/browser_ui/4_verify/pipeline/run_pipeline_with_manual_jobs_spec.rb": 43.38380465799992,
"qa/specs/features/browser_ui/4_verify/pipeline/trigger_child_pipeline_with_manual_spec.rb": 36.93094494899992,
"qa/specs/features/browser_ui/4_verify/pipeline/trigger_matrix_spec.rb": 27.6984514830001,
"qa/specs/features/browser_ui/4_verify/pipeline/update_ci_file_with_pipeline_editor_spec.rb": 17.473935009999877,
"qa/specs/features/browser_ui/4_verify/runner/fleet_management/group_runner_counts_spec.rb": 11.281532321999748,
"qa/specs/features/browser_ui/4_verify/runner/fleet_management/group_runner_status_counts_spec.rb": 14.362288008000178,
"qa/specs/features/browser_ui/4_verify/runner/register_group_runner_spec.rb": 11.812493389999872,
"qa/specs/features/browser_ui/4_verify/runner/register_runner_spec.rb": 12.41056197099988,
"qa/specs/features/browser_ui/4_verify/testing/endpoint_coverage_spec.rb": 23.068139760000122,
"qa/specs/features/browser_ui/5_package/container_registry/saas/container_registry_spec.rb": 181.211141692,
"qa/specs/features/browser_ui/5_package/package_registry/composer_registry_spec.rb": 29.54853552399993,
"qa/specs/features/browser_ui/5_package/package_registry/conan_repository_spec.rb": 49.92920795300006,
"qa/specs/features/browser_ui/5_package/package_registry/generic_repository_spec.rb": 133.64515306499993,
"qa/specs/features/browser_ui/5_package/package_registry/helm_registry_spec.rb": 155.8863834660001,
"qa/specs/features/browser_ui/5_package/package_registry/maven/maven_group_level_spec.rb": 328.023568094,
"qa/specs/features/browser_ui/5_package/package_registry/maven/maven_project_level_spec.rb": 138.53979677400002,
"qa/specs/features/browser_ui/5_package/package_registry/maven_gradle_repository_spec.rb": 140.927264165,
"qa/specs/features/browser_ui/5_package/package_registry/npm/npm_group_level_spec.rb": 169.96996041800003,
"qa/specs/features/browser_ui/5_package/package_registry/npm/npm_instance_level_spec.rb": 248.15001537699993,
"qa/specs/features/browser_ui/5_package/package_registry/pypi_repository_spec.rb": 51.85050848599985,
"qa/specs/features/browser_ui/6_release/deploy_key/add_deploy_key_spec.rb": 14.327700026999992,
"qa/specs/features/browser_ui/6_release/deploy_key/clone_using_deploy_key_spec.rb": 138.50435548600012,
"qa/specs/features/browser_ui/6_release/deploy_token/add_deploy_token_spec.rb": 7.851582360000066,
"qa/specs/features/browser_ui/8_monitor/alert_management/alert_settings_create_new_alerts_spec.rb": 23.870582943000045,
"qa/specs/features/browser_ui/8_monitor/alert_management/automatically_creates_incident_for_alert_spec.rb": 33.497799258999976,
"qa/specs/features/browser_ui/8_monitor/alert_management/create_alert_using_authorization_key_spec.rb": 33.665825194000035,
"qa/specs/features/browser_ui/8_monitor/alert_management/recovery_alert_resolves_correct_alert_spec.rb": 16.428518147000204,
"qa/specs/features/browser_ui/9_data_stores/group/group_member_access_request_spec.rb": 57.3846946189999,
"qa/specs/features/browser_ui/9_data_stores/group/transfer_project_spec.rb": 20.150782878999962,
"qa/specs/features/browser_ui/9_data_stores/project/add_project_member_spec.rb": 12.842779954999969,
"qa/specs/features/browser_ui/9_data_stores/project/create_project_badge_spec.rb": 18.237045063000096,
"qa/specs/features/browser_ui/9_data_stores/project/create_project_spec.rb": 18.170617833999813,
"qa/specs/features/browser_ui/9_data_stores/project/dashboard_images_spec.rb": 14.379097446999822,
"qa/specs/features/browser_ui/9_data_stores/project/invite_group_to_project_spec.rb": 49.47658440600003,
"qa/specs/features/browser_ui/9_data_stores/project/project_owner_permissions_spec.rb": 48.54146214100001,
"qa/specs/features/browser_ui/9_data_stores/project/view_project_activity_spec.rb": 14.59204661900003,
"qa/specs/features/browser_ui/9_data_stores/user/follow_user_activity_spec.rb": 18.60214837700005,
"qa/specs/features/browser_ui/9_data_stores/user/parent_group_access_termination_spec.rb": 23.704223850000062,
"qa/specs/features/browser_ui/9_data_stores/user/user_inherited_access_spec.rb": 24.50105342100005,
"qa/specs/features/ee/api/10_govern/compliance_pipeline_spec.rb": 18.616757694999933,
"qa/specs/features/ee/api/10_govern/instance_audit_event_streaming_spec.rb": 13.494274295000196,
"qa/specs/features/ee/api/10_govern/user/minimal_access_user_spec.rb": 46.14057161200003,
"qa/specs/features/ee/api/2_plan/epics_milestone_dates_spec.rb": 18.077241108000067,
"qa/specs/features/ee/api/3_create/code_suggestions_spec.rb": 6.717857566000021,
"qa/specs/features/ee/browser_ui/10_govern/change_vulnerability_status_spec.rb": 62.65099704199997,
"qa/specs/features/ee/browser_ui/10_govern/create_merge_request_with_secure_spec.rb": 43.97230168299984,
"qa/specs/features/ee/browser_ui/10_govern/dismissed_vulnerabilities_in_security_widget_spec.rb": 41.14789498399978,
"qa/specs/features/ee/browser_ui/10_govern/export_vulnerability_report_spec.rb": 16.80834482299997,
"qa/specs/features/ee/browser_ui/10_govern/fix_vulnerability_workflow_spec.rb": 80.20809595699984,
"qa/specs/features/ee/browser_ui/10_govern/group/group_audit_event_streaming_spec.rb": 26.22414726199986,
"qa/specs/features/ee/browser_ui/10_govern/group/group_audit_logs_1_spec.rb": 105.71841908799979,
"qa/specs/features/ee/browser_ui/10_govern/group/restrict_by_ip_address_spec.rb": 221.70173438400002,
"qa/specs/features/ee/browser_ui/10_govern/instance/instance_audit_logs_spec.rb": 120.52202147899993,
"qa/specs/features/ee/browser_ui/10_govern/policies_list_spec.rb": 22.321339837000096,
"qa/specs/features/ee/browser_ui/10_govern/project/project_audit_logs_spec.rb": 130.7218652890001,
"qa/specs/features/ee/browser_ui/10_govern/project_security_dashboard_spec.rb": 31.217049610999993,
"qa/specs/features/ee/browser_ui/10_govern/scan_execution_policy_vulnerabilities_spec.rb": 65.474416916,
"qa/specs/features/ee/browser_ui/10_govern/scan_result_policy_vulnerabilities_spec.rb": 52.58500605400002,
"qa/specs/features/ee/browser_ui/10_govern/security_reports_spec.rb": 148.30917081100006,
"qa/specs/features/ee/browser_ui/10_govern/user/minimal_access_user_spec.rb": 11.88923071399995,
"qa/specs/features/ee/browser_ui/10_govern/vulnerability_management_spec.rb": 173.51753275700003,
"qa/specs/features/ee/browser_ui/10_govern/vulnerability_security_training_spec.rb": 93.80908392499987,
"qa/specs/features/ee/browser_ui/11_fulfillment/license/license_spec.rb": 7.375643481000225,
"qa/specs/features/ee/browser_ui/11_fulfillment/purchase/overage_modal_spec.rb": 360.2599755880001,
"qa/specs/features/ee/browser_ui/11_fulfillment/purchase/purchase_ci_spec.rb": 232.047008001,
"qa/specs/features/ee/browser_ui/11_fulfillment/purchase/upgrade_group_spec.rb": 121.72472706700046,
"qa/specs/features/ee/browser_ui/11_fulfillment/saas_user_limit_experience_spec.rb": 164.46296615700066,
"qa/specs/features/ee/browser_ui/11_fulfillment/utilization/free_namespace_storage_spec.rb": 332.41206052300004,
"qa/specs/features/ee/browser_ui/11_fulfillment/utilization/saas_user_caps_spec.rb": 39.50882987800014,
"qa/specs/features/ee/browser_ui/11_fulfillment/utilization/usage_quotas_seats_spec.rb": 111.24074988800021,
"qa/specs/features/ee/browser_ui/11_fulfillment/utilization/user_registration_billing_spec.rb": 15.692323979999856,
"qa/specs/features/ee/browser_ui/13_secure/enable_advanced_sast_spec.rb": 75.51378988199997,
"qa/specs/features/ee/browser_ui/13_secure/enable_scanning_from_configuration_spec.rb": 83.86855627799969,
"qa/specs/features/ee/browser_ui/13_secure/on_demand_dast_spec.rb": 85.12023525199993,
"qa/specs/features/ee/browser_ui/2_plan/analytics/contribution_analytics_spec.rb": 26.270618488999844,
"qa/specs/features/ee/browser_ui/2_plan/analytics/mr_analytics_spec.rb": 22.40183240800002,
"qa/specs/features/ee/browser_ui/2_plan/analytics/value_stream_analytics_spec.rb": 21.887673334000056,
"qa/specs/features/ee/browser_ui/2_plan/burndown_chart/burndown_chart_spec.rb": 10.862288717999945,
"qa/specs/features/ee/browser_ui/2_plan/custom_email/custom_email_spec.rb": 11.189939669000069,
"qa/specs/features/ee/browser_ui/2_plan/epic/epics_management_spec.rb": 146.42032209499985,
"qa/specs/features/ee/browser_ui/2_plan/epic/promote_issue_to_epic_spec.rb": 15.018310149000172,
"qa/specs/features/ee/browser_ui/2_plan/group_wiki/create_group_wiki_page_spec.rb": 24.6155365489999,
"qa/specs/features/ee/browser_ui/2_plan/group_wiki/delete_group_wiki_page_spec.rb": 10.632227265999973,
"qa/specs/features/ee/browser_ui/2_plan/group_wiki/file_upload_group_wiki_page_spec.rb": 18.554999136999868,
"qa/specs/features/ee/browser_ui/2_plan/insights/default_insights_spec.rb": 19.554992973999788,
"qa/specs/features/ee/browser_ui/2_plan/issue/default_issue_template_spec.rb": 18.905201614999896,
"qa/specs/features/ee/browser_ui/2_plan/issue_boards/configurable_issue_board_spec.rb": 9.612566635999997,
"qa/specs/features/ee/browser_ui/2_plan/issue_boards/configure_issue_board_by_label_spec.rb": 16.21545620400002,
"qa/specs/features/ee/browser_ui/2_plan/issue_boards/create_group_issue_board_spec.rb": 9.770967304000123,
"qa/specs/features/ee/browser_ui/2_plan/issue_boards/group_issue_boards_spec.rb": 10.276463024999885,
"qa/specs/features/ee/browser_ui/2_plan/issue_boards/project_issue_boards_spec.rb": 33.215317630999834,
"qa/specs/features/ee/browser_ui/2_plan/issue_boards/read_only_board_configuration_spec.rb": 21.664296121000007,
"qa/specs/features/ee/browser_ui/2_plan/issue_boards/sum_of_issues_weights_spec.rb": 12.10210814800007,
"qa/specs/features/ee/browser_ui/2_plan/issues_analytics/issues_analytics_spec.rb": 17.60076914399997,
"qa/specs/features/ee/browser_ui/2_plan/issues_weight/issue_weight_visualization_spec.rb": 11.882972971000072,
"qa/specs/features/ee/browser_ui/2_plan/iterations/assign_group_iteration_spec.rb": 14.219959568999911,
"qa/specs/features/ee/browser_ui/2_plan/iterations/create_group_iteration_spec.rb": 23.512710422999817,
"qa/specs/features/ee/browser_ui/2_plan/multiple_assignees_for_issues/four_assignees_spec.rb": 11.789255166999965,
"qa/specs/features/ee/browser_ui/2_plan/multiple_assignees_for_issues/more_than_four_assignees_spec.rb": 34.729818802999944,
"qa/specs/features/ee/browser_ui/2_plan/scoped_labels/editing_scoped_labels_spec.rb": 11.174618635999991,
"qa/specs/features/ee/browser_ui/3_create/merge_request/add_batch_comments_in_merge_request_spec.rb": 56.259445724000216,
"qa/specs/features/ee/browser_ui/3_create/merge_request/approval_rules_spec.rb": 81.74281149999979,
"qa/specs/features/ee/browser_ui/3_create/merge_request/default_merge_request_template_spec.rb": 17.38010672700011,
"qa/specs/features/ee/browser_ui/3_create/repository/assign_code_owners_spec.rb": 32.98471905699989,
"qa/specs/features/ee/browser_ui/3_create/repository/code_owners_spec.rb": 12.166596606999974,
"qa/specs/features/ee/browser_ui/3_create/repository/code_owners_with_protected_branch_and_squashed_commits_spec.rb": 20.807681555000045,
"qa/specs/features/ee/browser_ui/3_create/repository/file_locking_spec.rb": 157.3566193449999,
"qa/specs/features/ee/browser_ui/3_create/repository/group_file_template_spec.rb": 90.37105526800008,
"qa/specs/features/ee/browser_ui/3_create/repository/merge_with_code_owner_in_root_group_spec.rb": 80.31416042700016,
"qa/specs/features/ee/browser_ui/3_create/repository/merge_with_code_owner_in_subgroup_spec.rb": 116.34840886400025,
"qa/specs/features/ee/browser_ui/3_create/repository/project_templates_spec.rb": 54.955738060000044,
"qa/specs/features/ee/browser_ui/3_create/repository/pull_mirroring_over_http_spec.rb": 25.12295135799991,
"qa/specs/features/ee/browser_ui/3_create/repository/pull_mirroring_over_ssh_with_key_spec.rb": 31.673243391999904,
"qa/specs/features/ee/browser_ui/3_create/repository/push_rules_spec.rb": 226.8815248159999,
"qa/specs/features/ee/browser_ui/3_create/repository/restrict_push_protected_branch_spec.rb": 217.52391698899999,
"qa/specs/features/ee/browser_ui/3_create/web_ide/code_suggestions_in_web_ide_spec.rb": 69.76164416599204,
"qa/specs/features/ee/browser_ui/4_verify/multi-project_pipelines_spec.rb": 16.685150342999805,
"qa/specs/features/ee/browser_ui/4_verify/parent_child_pipelines_dependent_relationship_spec.rb": 59.09543425900006,
"qa/specs/features/ee/browser_ui/4_verify/pipeline_subscription_with_group_owned_project_spec.rb": 38.168540809000206,
"qa/specs/features/ee/browser_ui/4_verify/pipelines_for_merged_results_and_merge_trains_spec.rb": 72.239648666,
"qa/specs/features/ee/browser_ui/4_verify/transient/merge_trains_transient_bug_spec.rb": 222.49861122300013,
"qa/specs/features/ee/browser_ui/8_monitor/incident_management/incident_quick_action_spec.rb": 11.709183800999995,
"qa/specs/features/ee/browser_ui/9_data_stores/group/prevent_forking_outside_group_spec.rb": 31.651073860999986,
"qa/specs/features/ee/browser_ui/9_data_stores/group/share_group_with_group_spec.rb": 25.22892628600016
"qa/specs/features/api/10_govern/group_access_token_spec.rb": 22.368781745999968,
"qa/specs/features/api/10_govern/project_access_token_spec.rb": 23.633304253000006,
"qa/specs/features/api/1_manage/rate_limits_spec.rb": 3.1467832400003317,
"qa/specs/features/api/2_plan/closes_issue_via_pushing_a_commit_spec.rb": 7.066938178999862,
"qa/specs/features/api/3_create/merge_request/push_options_labels_spec.rb": 8.327959042000202,
"qa/specs/features/api/3_create/merge_request/push_options_mwps_spec.rb": 8.461132950999854,
"qa/specs/features/api/3_create/merge_request/push_options_remove_source_branch_spec.rb": 26.816687255000033,
"qa/specs/features/api/3_create/merge_request/push_options_target_branch_spec.rb": 8.936014013000204,
"qa/specs/features/api/3_create/merge_request/push_options_title_description_spec.rb": 22.04809043399996,
"qa/specs/features/api/3_create/merge_request/view_merge_requests_spec.rb": 0.07425793599986719,
"qa/specs/features/api/3_create/repository/add_list_delete_branches_spec.rb": 5.418077632999939,
"qa/specs/features/api/3_create/repository/commit_to_templated_project_spec.rb": 9.446346610999626,
"qa/specs/features/api/3_create/repository/default_branch_name_setting_spec.rb": 8.764005738999913,
"qa/specs/features/api/3_create/repository/files_spec.rb": 4.811035699000058,
"qa/specs/features/api/3_create/repository/project_archive_compare_spec.rb": 4.926575522999883,
"qa/specs/features/api/3_create/repository/push_postreceive_idempotent_spec.rb": 6.722170169000037,
"qa/specs/features/api/3_create/repository/storage_size_spec.rb": 15.720025386000088,
"qa/specs/features/api/3_create/repository/tag_revision_trigger_prereceive_hook_spec.rb": 2.1978715340001145,
"qa/specs/features/api/4_verify/api_variable_inheritance_with_forward_pipeline_variables_spec.rb": 45.16411672999993,
"qa/specs/features/api/4_verify/cancel_pipeline_when_block_user_spec.rb": 10.504823287000363,
"qa/specs/features/api/4_verify/file_variable_spec.rb": 34.60797590999982,
"qa/specs/features/api/4_verify/job_downloads_artifacts_spec.rb": 25.90519738099988,
"qa/specs/features/api/9_data_stores/user_inherited_access_spec.rb": 72.58973470299998,
"qa/specs/features/api/9_data_stores/users_spec.rb": 0.46943177399998604,
"qa/specs/features/browser_ui/10_govern/group/group_access_token_spec.rb": 10.867392854000173,
"qa/specs/features/browser_ui/10_govern/login/2fa_recovery_spec.rb": 44.48518719200001,
"qa/specs/features/browser_ui/10_govern/login/2fa_ssh_recovery_spec.rb": 45.29727074599987,
"qa/specs/features/browser_ui/10_govern/login/log_in_spec.rb": 9.24467735899998,
"qa/specs/features/browser_ui/10_govern/login/log_in_with_2fa_spec.rb": 71.21219507099977,
"qa/specs/features/browser_ui/10_govern/login/login_via_oauth_and_oidc_with_gitlab_as_idp_spec.rb": 434.290598865,
"qa/specs/features/browser_ui/10_govern/login/register_spec.rb": 167.21751289999997,
"qa/specs/features/browser_ui/10_govern/project/project_access_token_spec.rb": 15.002181600999847,
"qa/specs/features/browser_ui/10_govern/user/impersonation_token_spec.rb": 34.3730335500004,
"qa/specs/features/browser_ui/10_govern/user/user_access_termination_spec.rb": 42.11820167299993,
"qa/specs/features/browser_ui/14_analytics/performance_bar_spec.rb": 18.42159530700019,
"qa/specs/features/browser_ui/14_analytics/service_ping_default_enabled_spec.rb": 12.865294517000166,
"qa/specs/features/browser_ui/1_manage/integrations/jenkins/jenkins_build_status_spec.rb": 64.23631289100013,
"qa/specs/features/browser_ui/2_plan/design_management/add_design_content_spec.rb": 13.557514046000051,
"qa/specs/features/browser_ui/2_plan/design_management/archive_design_content_spec.rb": 15.577577431000009,
"qa/specs/features/browser_ui/2_plan/design_management/modify_design_content_spec.rb": 16.93965877000005,
"qa/specs/features/browser_ui/2_plan/issue/check_mentions_for_xss_spec.rb": 15.712710897999841,
"qa/specs/features/browser_ui/2_plan/issue/collapse_comments_in_discussions_spec.rb": 11.492959395999605,
"qa/specs/features/browser_ui/2_plan/issue/comment_issue_spec.rb": 14.383327321999786,
"qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb": 47.38104187599993,
"qa/specs/features/browser_ui/2_plan/issue/custom_issue_template_spec.rb": 18.069448444000045,
"qa/specs/features/browser_ui/2_plan/issue/export_as_csv_spec.rb": 20.876328290999936,
"qa/specs/features/browser_ui/2_plan/issue/filter_issue_comments_spec.rb": 21.686897792999844,
"qa/specs/features/browser_ui/2_plan/issue/issue_suggestions_spec.rb": 17.499067247999847,
"qa/specs/features/browser_ui/2_plan/issue/mentions_spec.rb": 20.052594967999994,
"qa/specs/features/browser_ui/2_plan/issue/real_time_assignee_spec.rb": 15.281954894000137,
"qa/specs/features/browser_ui/2_plan/issue_boards/focus_mode_spec.rb": 9.612242246999813,
"qa/specs/features/browser_ui/2_plan/milestone/assign_milestone_spec.rb": 58.40833293900005,
"qa/specs/features/browser_ui/2_plan/milestone/create_group_milestone_spec.rb": 12.194349004999822,
"qa/specs/features/browser_ui/2_plan/milestone/create_project_milestone_spec.rb": 16.66858077699999,
"qa/specs/features/browser_ui/2_plan/project_wiki/project_based_content_creation_spec.rb": 57.8606801320002,
"qa/specs/features/browser_ui/2_plan/project_wiki/project_based_content_manipulation_spec.rb": 36.7572706560004,
"qa/specs/features/browser_ui/2_plan/project_wiki/project_based_directory_management_spec.rb": 13.130093501000374,
"qa/specs/features/browser_ui/2_plan/project_wiki/project_based_file_upload_spec.rb": 26.96827703400004,
"qa/specs/features/browser_ui/2_plan/project_wiki/project_based_list_spec.rb": 47.06445215099984,
"qa/specs/features/browser_ui/2_plan/project_wiki/project_based_page_deletion_spec.rb": 32.69071444200017,
"qa/specs/features/browser_ui/2_plan/related_issues/related_issues_spec.rb": 12.757383355999991,
"qa/specs/features/browser_ui/2_plan/transient/comment_on_discussion_spec.rb": 94.82951411399995,
"qa/specs/features/browser_ui/3_create/merge_request/cherry_pick/cherry_pick_a_merge_spec.rb": 28.79146358800017,
"qa/specs/features/browser_ui/3_create/merge_request/cherry_pick/cherry_pick_commit_spec.rb": 15.203331360999982,
"qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_spec.rb": 34.60106437700006,
"qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_via_template_spec.rb": 16.876695956000276,
"qa/specs/features/browser_ui/3_create/merge_request/merge_merge_request_from_fork_spec.rb": 20.24183390600001,
"qa/specs/features/browser_ui/3_create/merge_request/rebase_merge_request_spec.rb": 39.35212773400008,
"qa/specs/features/browser_ui/3_create/merge_request/revert/revert_commit_spec.rb": 16.664726423000047,
"qa/specs/features/browser_ui/3_create/merge_request/revert/reverting_merge_request_spec.rb": 29.294655512999725,
"qa/specs/features/browser_ui/3_create/merge_request/squash_merge_request_spec.rb": 29.818330108000055,
"qa/specs/features/browser_ui/3_create/merge_request/suggestions/batch_suggestion_spec.rb": 49.977204337999865,
"qa/specs/features/browser_ui/3_create/merge_request/suggestions/custom_commit_suggestion_spec.rb": 74.05581426499998,
"qa/specs/features/browser_ui/3_create/merge_request/view_merge_request_diff_patch_spec.rb": 25.886177607000036,
"qa/specs/features/browser_ui/3_create/repository/add_file_template_spec.rb": 58.32857243300032,
"qa/specs/features/browser_ui/3_create/repository/add_new_branch_rule_spec.rb": 19.121554731999822,
"qa/specs/features/browser_ui/3_create/repository/branch_with_unusual_name_spec.rb": 12.009725652999805,
"qa/specs/features/browser_ui/3_create/repository/clone_spec.rb": 14.347447782000017,
"qa/specs/features/browser_ui/3_create/repository/file/create_file_via_web_spec.rb": 16.534865420999722,
"qa/specs/features/browser_ui/3_create/repository/file/delete_file_via_web_spec.rb": 13.119983175000016,
"qa/specs/features/browser_ui/3_create/repository/file/edit_file_via_web_spec.rb": 15.378666402999897,
"qa/specs/features/browser_ui/3_create/repository/file/file_with_unusual_name_spec.rb": 15.938765588000024,
"qa/specs/features/browser_ui/3_create/repository/license_detection_spec.rb": 21.63542792399994,
"qa/specs/features/browser_ui/3_create/repository/protected_tags_spec.rb": 79.99040074799996,
"qa/specs/features/browser_ui/3_create/repository/protocol_v2_push_http_spec.rb": 12.59656118699968,
"qa/specs/features/browser_ui/3_create/repository/protocol_v2_push_ssh_spec.rb": 14.377605238999877,
"qa/specs/features/browser_ui/3_create/repository/push_http_private_token_spec.rb": 12.259645183999965,
"qa/specs/features/browser_ui/3_create/repository/push_mirroring_lfs_over_http_spec.rb": 61.57848500299997,
"qa/specs/features/browser_ui/3_create/repository/push_mirroring_over_http_spec.rb": 58.59291245999975,
"qa/specs/features/browser_ui/3_create/repository/push_over_http_file_size_spec.rb": 40.70022904899997,
"qa/specs/features/browser_ui/3_create/repository/push_over_http_spec.rb": 12.597955936999824,
"qa/specs/features/browser_ui/3_create/repository/push_over_ssh_spec.rb": 23.335798235999846,
"qa/specs/features/browser_ui/3_create/repository/push_protected_branch_spec.rb": 11.16296970899998,
"qa/specs/features/browser_ui/3_create/repository/push_to_canary_gitaly_spec.rb": 19.33630398599996,
"qa/specs/features/browser_ui/3_create/repository/ssh_key_support_create_spec.rb": 15.139340509000021,
"qa/specs/features/browser_ui/3_create/repository/ssh_key_support_delete_spec.rb": 15.598802374000115,
"qa/specs/features/browser_ui/3_create/repository/user_views_commit_diff_patch_spec.rb": 33.16634144599993,
"qa/specs/features/browser_ui/3_create/snippet/add_comment_to_snippet_spec.rb": 43.07075570100005,
"qa/specs/features/browser_ui/3_create/snippet/add_file_to_snippet_spec.rb": 32.04896657299969,
"qa/specs/features/browser_ui/3_create/snippet/clone_push_pull_personal_snippet_spec.rb": 44.12173341700009,
"qa/specs/features/browser_ui/3_create/snippet/clone_push_pull_project_snippet_spec.rb": 45.1201057369999,
"qa/specs/features/browser_ui/3_create/snippet/copy_snippet_file_contents_spec.rb": 35.046242132000316,
"qa/specs/features/browser_ui/3_create/snippet/create_personal_snippet_spec.rb": 11.228186354000172,
"qa/specs/features/browser_ui/3_create/snippet/create_personal_snippet_with_multiple_files_spec.rb": 11.679584620000014,
"qa/specs/features/browser_ui/3_create/snippet/create_project_snippet_spec.rb": 17.142693512999813,
"qa/specs/features/browser_ui/3_create/snippet/create_project_snippet_with_multiple_files_spec.rb": 25.128736303000096,
"qa/specs/features/browser_ui/3_create/snippet/delete_file_from_snippet_spec.rb": 22.43362897299994,
"qa/specs/features/browser_ui/3_create/snippet/share_snippet_spec.rb": 20.63210230699997,
"qa/specs/features/browser_ui/3_create/snippet/snippet_index_page_spec.rb": 51.18759698200006,
"qa/specs/features/browser_ui/3_create/source_editor/source_editor_toolbar_spec.rb": 18.490141503999894,
"qa/specs/features/browser_ui/3_create/web_ide/add_first_file_in_web_ide_spec.rb": 47.41684779299976,
"qa/specs/features/browser_ui/3_create/web_ide/add_new_directory_in_web_ide_spec.rb": 55.95471532700003,
"qa/specs/features/browser_ui/3_create/web_ide/closing_web_ide_with_unsaved_changes_spec.rb": 17.89687930900027,
"qa/specs/features/browser_ui/3_create/web_ide/upload_new_file_in_web_ide_spec.rb": 127.97824422899998,
"qa/specs/features/browser_ui/4_verify/ci_components_catalog/ci_catalog_sorting_spec.rb": 92.95931840900016,
"qa/specs/features/browser_ui/4_verify/ci_components_catalog/run_component_in_project_pipeline_spec.rb": 35.63051462899966,
"qa/specs/features/browser_ui/4_verify/ci_job_artifacts/expose_job_artifacts_in_mr_spec.rb": 28.20214109099993,
"qa/specs/features/browser_ui/4_verify/ci_job_artifacts/job_artifacts_access_keyword_spec.rb": 110.66918478300022,
"qa/specs/features/browser_ui/4_verify/ci_job_artifacts/unlocking_job_artifacts_across_pipelines_spec.rb": 217.47925253999983,
"qa/specs/features/browser_ui/4_verify/ci_project_artifacts/user_can_bulk_delete_artifacts_spec.rb": 26.754828502000237,
"qa/specs/features/browser_ui/4_verify/ci_variable/custom_variable_spec.rb": 31.085558825000135,
"qa/specs/features/browser_ui/4_verify/ci_variable/pipeline_with_protected_variable_spec.rb": 44.06894120200013,
"qa/specs/features/browser_ui/4_verify/ci_variable/prefill_variables_spec.rb": 35.78982095099991,
"qa/specs/features/browser_ui/4_verify/ci_variable/raw_variables_defined_in_yaml_spec.rb": 29.708999760000097,
"qa/specs/features/browser_ui/4_verify/ci_variable/ui_variable_inheritable_when_forward_pipeline_variables_true_spec.rb": 50.36197774100037,
"qa/specs/features/browser_ui/4_verify/pipeline/include_local_config_file_paths_with_wildcard_spec.rb": 13.341353649999746,
"qa/specs/features/browser_ui/4_verify/pipeline/include_multiple_files_from_a_project_spec.rb": 42.411010002999774,
"qa/specs/features/browser_ui/4_verify/pipeline/include_multiple_files_from_multiple_projects_spec.rb": 29.5737167530001,
"qa/specs/features/browser_ui/4_verify/pipeline/parent_child_pipelines_independent_relationship_spec.rb": 48.13610776800033,
"qa/specs/features/browser_ui/4_verify/pipeline/pass_dotenv_variables_to_downstream_via_bridge_spec.rb": 28.524868175999927,
"qa/specs/features/browser_ui/4_verify/pipeline/pipeline_with_image_pull_policy_spec.rb": 106.57642176700028,
"qa/specs/features/browser_ui/4_verify/pipeline/run_pipeline_with_manual_jobs_spec.rb": 43.70788082299987,
"qa/specs/features/browser_ui/4_verify/pipeline/trigger_child_pipeline_with_manual_spec.rb": 36.24359708399993,
"qa/specs/features/browser_ui/4_verify/pipeline/trigger_matrix_spec.rb": 34.50332342399997,
"qa/specs/features/browser_ui/4_verify/pipeline/update_ci_file_with_pipeline_editor_spec.rb": 24.002371265999955,
"qa/specs/features/browser_ui/4_verify/runner/fleet_management/group_runner_counts_spec.rb": 10.757894206999936,
"qa/specs/features/browser_ui/4_verify/runner/fleet_management/group_runner_status_counts_spec.rb": 10.301866036000092,
"qa/specs/features/browser_ui/4_verify/runner/register_group_runner_spec.rb": 12.12438019199999,
"qa/specs/features/browser_ui/4_verify/runner/register_runner_spec.rb": 15.005740251000134,
"qa/specs/features/browser_ui/4_verify/testing/endpoint_coverage_spec.rb": 29.49941567299993,
"qa/specs/features/browser_ui/5_package/infrastructure_registry/terraform_module_registry_spec.rb": 51.479649964000146,
"qa/specs/features/browser_ui/5_package/package_registry/composer_registry_spec.rb": 27.352062939999996,
"qa/specs/features/browser_ui/5_package/package_registry/conan_repository_spec.rb": 81.84952514700012,
"qa/specs/features/browser_ui/5_package/package_registry/generic_repository_spec.rb": 28.553728266000235,
"qa/specs/features/browser_ui/5_package/package_registry/helm_registry_spec.rb": 168.17629702600016,
"qa/specs/features/browser_ui/5_package/package_registry/maven/maven_group_level_spec.rb": 371.8446552810001,
"qa/specs/features/browser_ui/5_package/package_registry/maven/maven_project_level_spec.rb": 147.34913712900016,
"qa/specs/features/browser_ui/5_package/package_registry/maven_gradle_repository_spec.rb": 143.3438839700002,
"qa/specs/features/browser_ui/5_package/package_registry/npm/npm_group_level_spec.rb": 212.5769153199999,
"qa/specs/features/browser_ui/5_package/package_registry/npm/npm_instance_level_spec.rb": 154.38543904599965,
"qa/specs/features/browser_ui/5_package/package_registry/pypi_repository_spec.rb": 65.49403680400019,
"qa/specs/features/browser_ui/6_release/deploy_key/add_deploy_key_spec.rb": 14.485062738000124,
"qa/specs/features/browser_ui/6_release/deploy_key/clone_using_deploy_key_spec.rb": 95.86104218500031,
"qa/specs/features/browser_ui/6_release/deploy_token/add_deploy_token_spec.rb": 7.291155398999763,
"qa/specs/features/browser_ui/8_monitor/alert_management/alert_settings_create_new_alerts_spec.rb": 28.596902782000143,
"qa/specs/features/browser_ui/8_monitor/alert_management/automatically_creates_incident_for_alert_spec.rb": 51.41727816599996,
"qa/specs/features/browser_ui/8_monitor/alert_management/create_alert_using_authorization_key_spec.rb": 30.579300772999886,
"qa/specs/features/browser_ui/8_monitor/alert_management/recovery_alert_resolves_correct_alert_spec.rb": 17.057656027999656,
"qa/specs/features/browser_ui/9_data_stores/group/group_member_access_request_spec.rb": 62.32897362400013,
"qa/specs/features/browser_ui/9_data_stores/group/transfer_project_spec.rb": 18.02293271999997,
"qa/specs/features/browser_ui/9_data_stores/project/add_project_member_spec.rb": 17.59251898699995,
"qa/specs/features/browser_ui/9_data_stores/project/create_project_badge_spec.rb": 15.446313674000066,
"qa/specs/features/browser_ui/9_data_stores/project/create_project_spec.rb": 18.019042763000016,
"qa/specs/features/browser_ui/9_data_stores/project/dashboard_images_spec.rb": 14.63526036400026,
"qa/specs/features/browser_ui/9_data_stores/project/invite_group_to_project_spec.rb": 50.74090813900011,
"qa/specs/features/browser_ui/9_data_stores/project/project_owner_permissions_spec.rb": 44.86465373500005,
"qa/specs/features/browser_ui/9_data_stores/project/view_project_activity_spec.rb": 10.57122799900003,
"qa/specs/features/browser_ui/9_data_stores/user/follow_user_activity_spec.rb": 17.56207801699975,
"qa/specs/features/browser_ui/9_data_stores/user/parent_group_access_termination_spec.rb": 27.12611723300006,
"qa/specs/features/browser_ui/9_data_stores/user/user_inherited_access_spec.rb": 22.777019481000025,
"qa/specs/features/ee/api/10_govern/compliance_pipeline_spec.rb": 9.899398154999744,
"qa/specs/features/ee/api/10_govern/instance_audit_event_streaming_spec.rb": 13.41729055199994,
"qa/specs/features/ee/api/10_govern/user/minimal_access_user_spec.rb": 52.863767513999846,
"qa/specs/features/ee/api/2_plan/epics_milestone_dates_spec.rb": 24.66561908299991,
"qa/specs/features/ee/api/3_create/code_suggestions_spec.rb": 9.734530240000026,
"qa/specs/features/ee/browser_ui/10_govern/change_vulnerability_status_spec.rb": 78.78103058800025,
"qa/specs/features/ee/browser_ui/10_govern/create_merge_request_with_secure_spec.rb": 41.02528116299982,
"qa/specs/features/ee/browser_ui/10_govern/dismissed_vulnerabilities_in_security_widget_spec.rb": 75.75522501800015,
"qa/specs/features/ee/browser_ui/10_govern/export_vulnerability_report_spec.rb": 21.53629811100018,
"qa/specs/features/ee/browser_ui/10_govern/fix_vulnerability_workflow_spec.rb": 87.46915877299989,
"qa/specs/features/ee/browser_ui/10_govern/group/group_audit_event_streaming_spec.rb": 19.81644356400011,
"qa/specs/features/ee/browser_ui/10_govern/group/group_audit_logs_1_spec.rb": 94.59999707999987,
"qa/specs/features/ee/browser_ui/10_govern/group/restrict_by_ip_address_spec.rb": 244.94209053500003,
"qa/specs/features/ee/browser_ui/10_govern/instance/instance_audit_logs_spec.rb": 149.11489667600017,
"qa/specs/features/ee/browser_ui/10_govern/policies_list_spec.rb": 23.17459256999996,
"qa/specs/features/ee/browser_ui/10_govern/project/project_audit_logs_spec.rb": 142.88678456800017,
"qa/specs/features/ee/browser_ui/10_govern/project_security_dashboard_spec.rb": 32.639712987000166,
"qa/specs/features/ee/browser_ui/10_govern/scan_execution_policy_vulnerabilities_spec.rb": 87.48531807299992,
"qa/specs/features/ee/browser_ui/10_govern/scan_result_policy_vulnerabilities_spec.rb": 100.16423248799993,
"qa/specs/features/ee/browser_ui/10_govern/security_reports_spec.rb": 219.48511522400008,
"qa/specs/features/ee/browser_ui/10_govern/user/minimal_access_user_spec.rb": 10.48683282300044,
"qa/specs/features/ee/browser_ui/10_govern/vulnerability_management_spec.rb": 223.67916750899985,
"qa/specs/features/ee/browser_ui/10_govern/vulnerability_security_training_spec.rb": 90.11761338999986,
"qa/specs/features/ee/browser_ui/11_fulfillment/license/license_spec.rb": 6.416189227000359,
"qa/specs/features/ee/browser_ui/11_fulfillment/utilization/user_registration_billing_spec.rb": 25.087748015999978,
"qa/specs/features/ee/browser_ui/13_secure/enable_advanced_sast_spec.rb": 98.2445041179999,
"qa/specs/features/ee/browser_ui/13_secure/enable_scanning_from_configuration_spec.rb": 50.96775453700002,
"qa/specs/features/ee/browser_ui/13_secure/on_demand_dast_spec.rb": 95.48979141200016,
"qa/specs/features/ee/browser_ui/2_plan/analytics/contribution_analytics_spec.rb": 31.527241697000136,
"qa/specs/features/ee/browser_ui/2_plan/analytics/mr_analytics_spec.rb": 25.38604634799981,
"qa/specs/features/ee/browser_ui/2_plan/analytics/value_stream_analytics_spec.rb": 23.01250367600005,
"qa/specs/features/ee/browser_ui/2_plan/burndown_chart/burndown_chart_spec.rb": 10.041722617999994,
"qa/specs/features/ee/browser_ui/2_plan/custom_email/custom_email_spec.rb": 12.056798871999945,
"qa/specs/features/ee/browser_ui/2_plan/epic/epics_management_spec.rb": 134.200256243,
"qa/specs/features/ee/browser_ui/2_plan/epic/promote_issue_to_epic_spec.rb": 28.479518154999823,
"qa/specs/features/ee/browser_ui/2_plan/epic/roadmap_spec.rb": 10.634338394000224,
"qa/specs/features/ee/browser_ui/2_plan/group_wiki/create_group_wiki_page_spec.rb": 29.492960455999764,
"qa/specs/features/ee/browser_ui/2_plan/group_wiki/delete_group_wiki_page_spec.rb": 9.413657116000195,
"qa/specs/features/ee/browser_ui/2_plan/group_wiki/file_upload_group_wiki_page_spec.rb": 14.95102097400013,
"qa/specs/features/ee/browser_ui/2_plan/insights/default_insights_spec.rb": 24.128866205000122,
"qa/specs/features/ee/browser_ui/2_plan/issue/default_issue_template_spec.rb": 15.553754882000248,
"qa/specs/features/ee/browser_ui/2_plan/issue_boards/configurable_issue_board_spec.rb": 11.234492763999697,
"qa/specs/features/ee/browser_ui/2_plan/issue_boards/configure_issue_board_by_label_spec.rb": 18.468924121000327,
"qa/specs/features/ee/browser_ui/2_plan/issue_boards/create_group_issue_board_spec.rb": 17.354496787000244,
"qa/specs/features/ee/browser_ui/2_plan/issue_boards/group_issue_boards_spec.rb": 18.92236214400009,
"qa/specs/features/ee/browser_ui/2_plan/issue_boards/project_issue_boards_spec.rb": 39.630014759000005,
"qa/specs/features/ee/browser_ui/2_plan/issue_boards/read_only_board_configuration_spec.rb": 24.101322554000035,
"qa/specs/features/ee/browser_ui/2_plan/issue_boards/sum_of_issues_weights_spec.rb": 12.440506615000004,
"qa/specs/features/ee/browser_ui/2_plan/issues_analytics/issues_analytics_spec.rb": 21.37253022599998,
"qa/specs/features/ee/browser_ui/2_plan/issues_weight/issue_weight_visualization_spec.rb": 12.460709697999846,
"qa/specs/features/ee/browser_ui/2_plan/iterations/assign_group_iteration_spec.rb": 13.901354654999977,
"qa/specs/features/ee/browser_ui/2_plan/iterations/create_group_iteration_spec.rb": 33.006181079000044,
"qa/specs/features/ee/browser_ui/2_plan/multiple_assignees_for_issues/four_assignees_spec.rb": 12.56144702499978,
"qa/specs/features/ee/browser_ui/2_plan/multiple_assignees_for_issues/more_than_four_assignees_spec.rb": 32.16122686400013,
"qa/specs/features/ee/browser_ui/2_plan/scoped_labels/editing_scoped_labels_spec.rb": 13.211152739000227,
"qa/specs/features/ee/browser_ui/3_create/merge_request/add_batch_comments_in_merge_request_spec.rb": 57.75658679099979,
"qa/specs/features/ee/browser_ui/3_create/merge_request/approval_rules_spec.rb": 96.94270416100017,
"qa/specs/features/ee/browser_ui/3_create/merge_request/default_merge_request_template_spec.rb": 33.12321659999998,
"qa/specs/features/ee/browser_ui/3_create/repository/assign_code_owners_spec.rb": 28.152587653999944,
"qa/specs/features/ee/browser_ui/3_create/repository/code_owners_spec.rb": 16.502650385000152,
"qa/specs/features/ee/browser_ui/3_create/repository/code_owners_with_protected_branch_and_squashed_commits_spec.rb": 25.722663802999932,
"qa/specs/features/ee/browser_ui/3_create/repository/file_locking_spec.rb": 200.75515444999974,
"qa/specs/features/ee/browser_ui/3_create/repository/group_file_template_spec.rb": 92.8232680189999,
"qa/specs/features/ee/browser_ui/3_create/repository/merge_with_code_owner_in_root_group_spec.rb": 81.4973934489999,
"qa/specs/features/ee/browser_ui/3_create/repository/merge_with_code_owner_in_subgroup_spec.rb": 141.39839299200003,
"qa/specs/features/ee/browser_ui/3_create/repository/project_templates_spec.rb": 72.26127357299993,
"qa/specs/features/ee/browser_ui/3_create/repository/pull_mirroring_over_http_spec.rb": 29.386763341999995,
"qa/specs/features/ee/browser_ui/3_create/repository/pull_mirroring_over_ssh_with_key_spec.rb": 45.32656895399987,
"qa/specs/features/ee/browser_ui/3_create/repository/push_rules_spec.rb": 244.24686534299963,
"qa/specs/features/ee/browser_ui/3_create/repository/restrict_push_protected_branch_spec.rb": 224.68295732599972,
"qa/specs/features/ee/browser_ui/3_create/web_ide/code_suggestions_in_web_ide_spec.rb": 70.40918833,
"qa/specs/features/ee/browser_ui/4_verify/multi-project_pipelines_spec.rb": 16.11996115000011,
"qa/specs/features/ee/browser_ui/4_verify/parent_child_pipelines_dependent_relationship_spec.rb": 46.88418564700032,
"qa/specs/features/ee/browser_ui/4_verify/pipeline_subscription_with_group_owned_project_spec.rb": 36.758229692000214,
"qa/specs/features/ee/browser_ui/4_verify/pipelines_for_merged_results_and_merge_trains_spec.rb": 79.00419656800022,
"qa/specs/features/ee/browser_ui/4_verify/transient/merge_trains_transient_bug_spec.rb": 102.89802900000018,
"qa/specs/features/ee/browser_ui/8_monitor/incident_management/incident_quick_action_spec.rb": 14.259584643000153,
"qa/specs/features/ee/browser_ui/9_data_stores/group/prevent_forking_outside_group_spec.rb": 38.22584831700033,
"qa/specs/features/ee/browser_ui/9_data_stores/group/share_group_with_group_spec.rb": 24.902903569000046
}

View File

@ -3,7 +3,7 @@
module QA
RSpec.describe 'Govern', :orchestrated, :mattermost, product_group: :authentication do
describe 'Mattermost login' do
it 'user logs into Mattermost using GitLab OAuth',
it 'user logs into Mattermost using GitLab OAuth', :blocking,
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347891' do
Flow::Login.sign_in

View File

@ -47,7 +47,7 @@ RSpec.describe 'Merge request > User sees diff', :js, feature_category: :code_re
visit "#{diffs_project_merge_request_path(project, merge_request)}##{line_code}"
end
it 'shows the linked line' do
it 'shows the linked line', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/496702' do
expect(page).to have_selector("[id='#{line_code}']", visible: true, obscured: false)
end
end

View File

@ -409,7 +409,7 @@ RSpec.describe GroupsFinder, feature_category: :groups_and_projects do
)
end
it "returns project's parent group if user is member of project" do
it "returns project's ancestor groups if user is member of project" do
project = create(:project, :private, namespace: private_sub_subgroup)
project.add_developer(user)
@ -419,7 +419,8 @@ RSpec.describe GroupsFinder, feature_category: :groups_and_projects do
public_subgroup2,
internal_sub_subgroup,
public_sub_subgroup,
private_sub_subgroup
private_sub_subgroup,
private_subgroup2
)
end

View File

@ -219,4 +219,89 @@ describe('~/api/projects_api.js', () => {
expect(mock.history.get[0].mockOption).toBe(axiosOptions.mockOption);
});
});
describe('uploadImageToProject', () => {
const mockProjectId = 123;
const mockFilename = 'test.jpg';
const mockBlobData = new Blob(['test']);
beforeEach(() => {
window.gon = { relative_url_root: '', api_version: 'v7' };
jest.spyOn(axios, 'post');
});
it('should upload an image and return the share URL', async () => {
const mockResponse = {
full_path: '/-/project/123/uploads/abcd/test.jpg',
};
mock.onPost().replyOnce(HTTP_STATUS_OK, mockResponse);
const result = await projectsApi.uploadImageToProject({
filename: mockFilename,
blobData: mockBlobData,
projectId: mockProjectId,
});
expect(axios.post).toHaveBeenCalledWith(
`/api/v7/projects/${mockProjectId}/uploads`,
expect.any(FormData),
expect.objectContaining({
headers: { 'Content-Type': 'multipart/form-data' },
}),
);
expect(result).toBe('http://test.host/-/project/123/uploads/abcd/test.jpg');
});
it('should throw an error if filename is missing', async () => {
await expect(
projectsApi.uploadImageToProject({
blobData: mockBlobData,
projectId: mockProjectId,
}),
).rejects.toThrow('Request failed with status code 404');
});
it('should throw an error if blobData is missing', async () => {
await expect(
projectsApi.uploadImageToProject({
filename: mockFilename,
projectId: mockProjectId,
}),
).rejects.toThrow("is not of type 'Blob'");
});
it('should throw an error if projectId is missing', async () => {
await expect(
projectsApi.uploadImageToProject({
filename: mockFilename,
blobData: mockBlobData,
}),
).rejects.toThrow('Request failed with status code 404');
});
it('should throw an error if the upload fails', async () => {
mock.onPost().replyOnce(500);
await expect(
projectsApi.uploadImageToProject({
filename: mockFilename,
blobData: mockBlobData,
projectId: mockProjectId,
}),
).rejects.toThrow('Request failed with status code 500');
});
it('should throw an error if the response does not have a link', async () => {
mock.onPost().replyOnce(HTTP_STATUS_OK, {});
await expect(
projectsApi.uploadImageToProject({
filename: mockFilename,
blobData: mockBlobData,
projectId: mockProjectId,
}),
).rejects.toThrow('Image failed to upload');
});
});
});

View File

@ -1,28 +1,49 @@
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import WorkItemRelationshipIcons from '~/work_items/components/shared/work_item_relationship_icons.vue';
import { LINKED_CATEGORIES_MAP } from '~/work_items/constants';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import { createMockDirective } from 'helpers/vue_mock_directive';
import workItemLinkedItemsQuery from '~/work_items/graphql/work_item_linked_items.query.graphql';
import { mockLinkedItems } from '../../mock_data';
import { mockLinkedItems, workItemLinkedItemsResponse } from '../../mock_data';
describe('WorkItemRelationshipIcons', () => {
Vue.use(VueApollo);
let wrapper;
const createComponent = () => {
const workItemLinkedItemsSuccessHandler = jest
.fn()
.mockResolvedValue(workItemLinkedItemsResponse);
const createComponent = async ({
workItemType = 'Task',
workItemLinkedItemsHandler = workItemLinkedItemsSuccessHandler,
} = {}) => {
const mockApollo = createMockApollo([[workItemLinkedItemsQuery, workItemLinkedItemsHandler]]);
wrapper = shallowMountExtended(WorkItemRelationshipIcons, {
apolloProvider: mockApollo,
directives: {
GlTooltip: createMockDirective('gl-tooltip'),
},
propsData: {
workItemType,
workItemIid: '1',
workItemFullPath: 'gitlab-org/gitlab-test',
workItemWebUrl: '/gitlab-org/gitlab-test/-/work_items/1',
linkedWorkItems: mockLinkedItems.linkedItems.nodes,
workItemType: 'Task',
},
});
await waitForPromises();
};
const findBlockedIcon = () => wrapper.findByTestId('relationship-blocked-by-icon');
const findBlockingIcon = () => wrapper.findByTestId('relationship-blocks-icon');
const findTooltip = (icon) => getBinding(icon.element, 'gl-tooltip');
const blockedItems = mockLinkedItems.linkedItems.nodes.filter(
(item) => item.linkType === LINKED_CATEGORIES_MAP.IS_BLOCKED_BY,
@ -64,12 +85,18 @@ describe('WorkItemRelationshipIcons', () => {
expect(findBlockingIcon().text()).toContain(blockedItems.length.toString());
});
it('renders tooltips with correct text', () => {
it('does not query child link items if the icons are not hovered', () => {
createComponent();
expect(findTooltip(findBlockingIcon())).toBeDefined();
expect(findTooltip(findBlockedIcon())).toBeDefined();
expect(findBlockedIcon().attributes('title')).toBe('Task is blocked by 1 item');
expect(findBlockingIcon().attributes('title')).toBe('Task blocks 1 item');
expect(workItemLinkedItemsSuccessHandler).not.toHaveBeenCalled();
});
it('triggers child link items query on hover', async () => {
createComponent();
await findBlockedIcon().trigger('mouseenter');
await waitForPromises();
expect(workItemLinkedItemsSuccessHandler).toHaveBeenCalled();
});
});

View File

@ -0,0 +1,60 @@
import { GlAvatarsInline } from '@gitlab/ui';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import ItemMilestone from '~/issuable/components/issue_milestone.vue';
import WorkItemPopoverMetadata from '~/work_items/components/shared/work_item_relationship_popover_metadata.vue';
import { workItemTask } from '../../mock_data';
describe('WorkItemPopoverMetadata', () => {
let wrapper;
const mockMilestone = workItemTask.widgets.find(
(widget) => widget.type === 'MILESTONE',
).milestone;
const mockAssignees = workItemTask.widgets.find((widget) => widget.type === 'ASSIGNEES').assignees
.nodes;
const createComponent = () => {
wrapper = shallowMountExtended(WorkItemPopoverMetadata, {
propsData: {
workItem: workItemTask,
workItemFullPath: 'gitlab-org/gitlab-test',
},
scopedSlots: {
'weight-metadata': `<div data-testid="weight-metadata-slot">Test weight metada</div>`,
'additional-metadata': `<div data-testid="additional-metadata-slot">Test metadata</div>`,
},
});
};
const findItemMilestone = () => wrapper.findComponent(ItemMilestone);
const findMetadataSlot = () => wrapper.findByTestId('additional-metadata-slot');
const findWeightMetadataSlot = () => wrapper.findByTestId('weight-metadata-slot');
const findAvatars = () => wrapper.findComponent(GlAvatarsInline);
beforeEach(() => {
createComponent();
});
it('renders scoped slot contents', () => {
expect(findWeightMetadataSlot().text()).toBe('Test weight metada');
expect(findMetadataSlot().text()).toBe('Test metadata');
});
it('renders work item milestone', () => {
expect(findItemMilestone().exists()).toBe(true);
expect(findItemMilestone().props('milestone')).toEqual(mockMilestone);
});
it('renders avatars for assignees', () => {
expect(findAvatars().exists()).toBe(true);
expect(findAvatars().props()).toMatchObject({
avatars: mockAssignees,
maxVisible: 3,
avatarSize: 16,
collapsed: true,
badgeSrOnlyText: '',
badgeTooltipProp: 'name',
badgeTooltipMaxChars: null,
});
});
});

View File

@ -0,0 +1,92 @@
import { GlPopover, GlLoadingIcon } from '@gitlab/ui';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { createMockDirective } from 'helpers/vue_mock_directive';
import WorkItemRelationshipPopover from '~/work_items/components/shared/work_item_relationship_popover.vue';
import { mockLinkedItems } from '../../mock_data';
describe('WorkItemRelationshipPopover', () => {
let wrapper;
const linkedItems = mockLinkedItems.linkedItems.nodes;
const linkedItemsAboveLimit = [
...mockLinkedItems.linkedItems.nodes,
{
linkId: 'gid://gitlab/WorkItems::RelatedWorkItemLink/11',
linkType: 'blocks',
workItem: {
id: 'gid://gitlab/WorkItem/648',
iid: '57',
confidential: true,
workItemType: {
id: 'gid://gitlab/WorkItems::Type/6',
name: 'Objective',
iconName: 'issue-type-objective',
__typename: 'WorkItemType',
},
namespace: {
id: 'gid://gitlab/Group/1',
fullPath: 'test-project-path',
__typename: 'Namespace',
},
reference: 'test-project-path#57',
title: 'Multilevel Objective 3',
state: 'OPEN',
createdAt: '2023-03-28T10:50:16Z',
closedAt: null,
webUrl: '/gitlab-org/gitlab-test/-/work_items/57',
widgets: [],
__typename: 'WorkItem',
},
__typename: 'LinkedWorkItemType',
},
];
const target = 'blocking-icon';
const workItemWebUrl = '/gitlab-org/gitlab-test/-/work_items/1';
const createComponent = ({ linkedWorkItems = linkedItems, loading = false } = {}) => {
wrapper = shallowMountExtended(WorkItemRelationshipPopover, {
directives: {
GlTooltip: createMockDirective('gl-tooltip'),
},
propsData: {
linkedWorkItems,
title: 'Blocking',
target,
workItemFullPath: 'gitlab-org/gitlab-test',
workItemWebUrl,
loading,
},
});
};
const findPopover = () => wrapper.findComponent(GlPopover);
const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
const findMoreRelatedItemsLink = () => wrapper.findByTestId('more-related-items-link');
beforeEach(() => {
createComponent();
});
it('displays relationship popover on hover and focus', () => {
expect(findPopover().exists()).toBe(true);
expect(findPopover().props('triggers')).toBe('hover focus');
expect(findPopover().props('target')).toBe(target);
});
it('displays loading icon if loading prop = true', () => {
createComponent({ loading: true });
expect(findLoadingIcon().exists()).toBe(true);
});
it('displays linked items within the popover', () => {
linkedItems.forEach((item) => {
expect(findPopover().text()).toContain(item.workItem.title);
});
});
it('truncates linked items if the default display limit of 3 is exceeded', () => {
createComponent({ linkedWorkItems: linkedItemsAboveLimit });
expect(findMoreRelatedItemsLink().exists()).toBe(true);
expect(findMoreRelatedItemsLink().attributes('href')).toBe(`${workItemWebUrl}#linkeditems`);
});
});

View File

@ -608,6 +608,11 @@ export const mockBlockingLinkedItem = {
iconName: 'issue-type-task',
__typename: 'WorkItemType',
},
namespace: {
id: 'gid://gitlab/Group/1',
fullPath: 'test-project-path',
__typename: 'Namespace',
},
reference: 'test-project-path#1',
title: 'Task 1201',
state: 'OPEN',
@ -642,6 +647,11 @@ export const mockBlockedByLinkedItem = {
iconName: 'issue-type-task',
__typename: 'WorkItemType',
},
namespace: {
id: 'gid://gitlab/Group/1',
fullPath: 'test-project-path',
__typename: 'Namespace',
},
reference: 'test-project-path#1',
title: 'Task 1201',
state: 'OPEN',
@ -666,6 +676,11 @@ export const mockBlockedByLinkedItem = {
iconName: 'issue-type-task',
__typename: 'WorkItemType',
},
namespace: {
id: 'gid://gitlab/Group/1',
fullPath: 'test-project-path',
__typename: 'Namespace',
},
reference: 'test-project-path#1',
title: 'Task 1202',
state: 'OPEN',
@ -700,6 +715,11 @@ export const mockLinkedItems = {
iconName: 'issue-type-task',
__typename: 'WorkItemType',
},
namespace: {
id: 'gid://gitlab/Group/1',
fullPath: 'test-project-path',
__typename: 'Namespace',
},
reference: 'test-project-path#83',
title: 'Task 1201',
state: 'OPEN',
@ -724,6 +744,11 @@ export const mockLinkedItems = {
iconName: 'issue-type-objective',
__typename: 'WorkItemType',
},
namespace: {
id: 'gid://gitlab/Group/2',
fullPath: 'test-project-path',
__typename: 'Namespace',
},
reference: 'test-project-path#55',
title: 'Multilevel Objective 1',
state: 'OPEN',
@ -748,6 +773,11 @@ export const mockLinkedItems = {
iconName: 'issue-type-objective',
__typename: 'WorkItemType',
},
namespace: {
id: 'gid://gitlab/Group/3',
fullPath: 'test-project-path',
__typename: 'Namespace',
},
reference: 'test-project-path#56',
title: 'Multilevel Objective 2',
state: 'OPEN',
@ -827,6 +857,11 @@ export const workItemSingleLinkedItemResponse = {
iconName: 'issue-type-task',
__typename: 'WorkItemType',
},
namespace: {
id: 'gid://gitlab/Group/1',
fullPath: 'test-project-path',
__typename: 'Namespace',
},
reference: 'test-project-path#1',
title: 'Task 1201',
state: 'OPEN',
@ -1782,6 +1817,7 @@ export const workItemTask = {
widgets: [
workItemObjectiveMetadataWidgets.ASSIGNEES,
workItemObjectiveMetadataWidgets.LINKED_ITEMS,
workItemObjectiveMetadataWidgets.MILESTONE,
{
type: 'HIERARCHY',
hasChildren: false,

View File

@ -5,6 +5,43 @@ require "spec_helper"
RSpec.describe AuthHelper, feature_category: :system_access do
include LoginHelpers
describe "#enabled_button_based_providers_for_signup" do
[[true, %w[github gitlab]],
[false, []],
[['github'], ['github']],
[[], []]].each do |(allow_single_sign_on, result)|
context "when allow_single_sign_on is #{allow_single_sign_on}" do
before do
allow(helper).to receive(:enabled_button_based_providers) { %w[github gitlab] }
stub_omniauth_config(allow_single_sign_on: allow_single_sign_on)
end
it "returns #{result}" do
expect(helper.enabled_button_based_providers_for_signup).to eq(result)
end
end
end
end
describe "#signup_button_based_providers_enabled?" do
[[true, true, true],
[true, ['github'], true],
[false, true, false],
[true, false, false],
[true, [], false]].each do |(omniauth_enable, allow_single_sign_on, result)|
context "when omniauth is #{omniauth_enable} and allow_single_sign_on is #{allow_single_sign_on}" do
before do
allow(Gitlab::Auth).to receive(:omniauth_enabled?).and_return(omniauth_enable)
stub_omniauth_config(allow_single_sign_on: allow_single_sign_on)
end
it "returns #{result}" do
expect(helper.signup_button_based_providers_enabled?).to eq(result)
end
end
end
end
describe "button_based_providers" do
it 'returns all enabled providers from devise' do
allow(helper).to receive(:auth_providers) { [:twitter, :github] }

View File

@ -36,7 +36,7 @@ RSpec.describe Groups::GroupMembersHelper, feature_category: :groups_and_project
banned: [],
include_relations: [:inherited, :direct],
search: nil,
pending_members: [],
pending_members_count: [],
placeholder_users: {
pagination: {
total_items: 3,
@ -121,7 +121,7 @@ RSpec.describe Groups::GroupMembersHelper, feature_category: :groups_and_project
banned: [],
include_relations: include_relations,
search: nil,
pending_members: [],
pending_members_count: [],
placeholder_users: {}
)
end

View File

@ -32,7 +32,7 @@ RSpec.describe Projects::ProjectMembersHelper, feature_category: :groups_and_pro
access_requests: present_members(access_requests),
include_relations: [:inherited, :direct],
search: nil,
pending_members: []
pending_members_count: []
)
)
end
@ -142,7 +142,7 @@ RSpec.describe Projects::ProjectMembersHelper, feature_category: :groups_and_pro
access_requests: present_members(access_requests),
include_relations: include_relations,
search: nil,
pending_members: []
pending_members_count: []
)
)
end

View File

@ -4920,7 +4920,8 @@ RSpec.describe User, feature_category: :user_profile do
let_it_be(:private_group) { create(:group) }
let_it_be(:child_group) { create(:group, parent: private_group) }
let_it_be(:project_group) { create(:group) }
let_it_be(:project_group_parent) { create(:group) }
let_it_be(:project_group) { create(:group, parent: project_group_parent) }
let_it_be(:project) { create(:project, group: project_group) }
before_all do
@ -4930,10 +4931,22 @@ RSpec.describe User, feature_category: :user_profile do
subject { user.authorized_groups }
it { is_expected.to contain_exactly private_group, child_group, project_group }
it { is_expected.to contain_exactly private_group, child_group, project_group, project_group_parent }
context 'when fix_user_authorized_groups is disabled' do
before do
stub_feature_flags(fix_user_authorized_groups: false)
end
it 'omits ancestor groups of projects' do
is_expected.to include project_group
is_expected.not_to include project_group_parent
end
end
context 'with shared memberships' do
let_it_be(:shared_group) { create(:group) }
let_it_be(:shared_group_descendant) { create(:group, parent: shared_group) }
let_it_be(:other_group) { create(:group) }
let_it_be(:shared_with_project_group) { create(:group) }
@ -4943,8 +4956,19 @@ RSpec.describe User, feature_category: :user_profile do
create(:group_group_link, shared_group: shared_with_project_group, shared_with_group: project_group)
end
it { is_expected.to include shared_group }
it { is_expected.to include shared_group, shared_group_descendant }
it { is_expected.not_to include other_group, shared_with_project_group }
context 'when fix_user_authorized_groups is disabled' do
before do
stub_feature_flags(fix_user_authorized_groups: false)
end
it 'omits subgroups of shared groups' do
is_expected.to include shared_group
is_expected.not_to include shared_group_descendant
end
end
end
context 'when a new column is added to namespaces table' do

View File

@ -94,6 +94,10 @@ RSpec.describe API::GroupMilestones, feature_category: :team_planning do
let(:user) { create(:user) }
before do
# When a group has a project, users that have access to the group will get access to ancestor groups
# See https://gitlab.com/groups/gitlab-org/-/epics/9424
group.projects.delete_all
group.add_guest(user)
end

View File

@ -10619,6 +10619,11 @@ mock-apollo-client@1.2.0:
resolved "https://registry.yarnpkg.com/mock-apollo-client/-/mock-apollo-client-1.2.0.tgz#72543df0d74577d29be1b34cecba8898c7e71451"
integrity sha512-zCVHv3p7zvUmen9zce9l965ZrI6rMbrm2/oqGaTerVYOaYskl/cVgTG/L7iIToTIpI7onk/f6tu8hxPXZdyy/g==
modern-screenshot@^4.4.39:
version "4.4.39"
resolved "https://registry.yarnpkg.com/modern-screenshot/-/modern-screenshot-4.4.39.tgz#4c8b7a9ecb899e68b6d4111abfa71043f326847a"
integrity sha512-p+I4yLZUDnoJMa5zoi+71nLQmoLQ6WRU4W8vZu1BZk2PlIYOz5mGnj9/7t2lGWKYeOr4zo6pajhY0/9TS5Zcdw==
monaco-editor-webpack-plugin@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/monaco-editor-webpack-plugin/-/monaco-editor-webpack-plugin-6.0.0.tgz#628956ce1851afa2a5f6c88d0ecbb24e9a444898"
@ -13130,16 +13135,7 @@ string-length@^4.0.1:
char-regex "^1.0.2"
strip-ansi "^6.0.0"
"string-width-cjs@npm:string-width@^4.2.0":
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
dependencies:
emoji-regex "^8.0.0"
is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.1"
"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
@ -13192,7 +13188,7 @@ string_decoder@^1.0.0, string_decoder@^1.1.1, string_decoder@~1.1.1:
dependencies:
safe-buffer "~5.1.0"
"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
@ -13206,13 +13202,6 @@ strip-ansi@^5.2.0:
dependencies:
ansi-regex "^4.1.0"
strip-ansi@^6.0.0, strip-ansi@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
dependencies:
ansi-regex "^5.0.1"
strip-ansi@^7.0.1, strip-ansi@^7.1.0:
version "7.1.0"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45"
@ -14904,7 +14893,7 @@ worker-loader@^3.0.8:
loader-utils "^2.0.0"
schema-utils "^3.0.0"
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
@ -14922,15 +14911,6 @@ wrap-ansi@^6.2.0:
string-width "^4.1.0"
strip-ansi "^6.0.0"
wrap-ansi@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
dependencies:
ansi-styles "^4.0.0"
string-width "^4.1.0"
strip-ansi "^6.0.0"
wrap-ansi@^8.1.0:
version "8.1.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"