Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2025-01-09 18:37:29 +00:00
parent 7f5c968c6e
commit 1cbefa896f
83 changed files with 984 additions and 368 deletions

View File

@ -646,10 +646,13 @@ lib/gitlab/checks/**
/doc/administration/reference_architectures/ @axil /doc/administration/reference_architectures/ @axil
/doc/administration/reply_by_email.md @lciutacu /doc/administration/reply_by_email.md @lciutacu
/doc/administration/reply_by_email_postfix_setup.md @axil /doc/administration/reply_by_email_postfix_setup.md @axil
/doc/administration/reporting/ @axil /doc/administration/reporting/ @idurham
/doc/administration/reporting/spamcheck.md @axil
/doc/administration/repository_checks.md @eread /doc/administration/repository_checks.md @eread
/doc/administration/repository_storage_paths.md @eread /doc/administration/repository_storage_paths.md @eread
/doc/administration/restart_gitlab.md @axil /doc/administration/restart_gitlab.md @axil
/doc/administration/review_abuse_reports.md @idurham
/doc/administration/review_spam_logs.md @idurham
/doc/administration/self_hosted_models/ @jglassman1 /doc/administration/self_hosted_models/ @jglassman1
/doc/administration/server_hooks.md @eread /doc/administration/server_hooks.md @eread
/doc/administration/settings/account_and_limit_settings.md @brendan777 /doc/administration/settings/account_and_limit_settings.md @brendan777
@ -965,6 +968,7 @@ lib/gitlab/checks/**
/doc/development/git_object_deduplication.md @proglottis @toon /doc/development/git_object_deduplication.md @proglottis @toon
/doc/development/gitaly.md @proglottis @toon /doc/development/gitaly.md @proglottis @toon
/doc/development/gitpod_internals.md @gl-dx/eng-prod /doc/development/gitpod_internals.md @gl-dx/eng-prod
/doc/development/identity_verification.md @gitlab-org/software-supply-chain-security/authorization/approvers
/doc/development/image_scaling.md @abdwdd @alexpooley /doc/development/image_scaling.md @abdwdd @alexpooley
/doc/development/internal_analytics/ @gitlab-org/analytics-section/product-analytics/engineers/frontend @gitlab-org/analytics-section/analytics-instrumentation/engineers /doc/development/internal_analytics/ @gitlab-org/analytics-section/product-analytics/engineers/frontend @gitlab-org/analytics-section/analytics-instrumentation/engineers
/doc/development/internal_analytics/product_analytics.md @gitlab-org/analytics-section/product-analytics/engineers/frontend /doc/development/internal_analytics/product_analytics.md @gitlab-org/analytics-section/product-analytics/engineers/frontend
@ -975,14 +979,15 @@ lib/gitlab/checks/**
/doc/development/observability/ @gitlab-org/analytics-section/product-analytics/engineers/frontend /doc/development/observability/ @gitlab-org/analytics-section/product-analytics/engineers/frontend
/doc/development/omnibus.md @gitlab-org/distribution /doc/development/omnibus.md @gitlab-org/distribution
/doc/development/organization/ @abdwdd @alexpooley /doc/development/organization/ @abdwdd @alexpooley
/doc/development/permissions.md @gitlab-org/govern/authorization/approvers /doc/development/permissions.md @gitlab-org/software-supply-chain-security/authorization/approvers
/doc/development/permissions/ @gitlab-org/govern/authorization/approvers /doc/development/permissions/ @gitlab-org/software-supply-chain-security/authorization/approvers
/doc/development/pipelines/ @gl-dx/eng-prod /doc/development/pipelines/ @gl-dx/eng-prod
/doc/development/policies.md @gitlab-org/govern/authentication/approvers /doc/development/policies.md @gitlab-org/software-supply-chain-security/authentication/approvers
/doc/development/prometheus_metrics.md @gitlab-org/analytics-section/product-analytics/engineers/frontend /doc/development/prometheus_metrics.md @gitlab-org/analytics-section/product-analytics/engineers/frontend
/doc/development/search/ @gitlab-org/search-team/migration-maintainers /doc/development/search/ @gitlab-org/search-team/migration-maintainers
/doc/development/sec/ @gitlab-org/secure/composition-analysis-be @gitlab-org/secure/static-analysis /doc/development/sec/ @gitlab-org/secure/composition-analysis-be @gitlab-org/secure/static-analysis
/doc/development/software_design.md @gl-dx/eng-prod /doc/development/software_design.md @gl-dx/eng-prod
/doc/development/spam_protection_and_captcha/ @gitlab-org/software-supply-chain-security/authorization/approvers
/doc/development/stage_group_observability/ @gitlab-org/analytics-section/product-analytics/engineers/frontend /doc/development/stage_group_observability/ @gitlab-org/analytics-section/product-analytics/engineers/frontend
/doc/development/tracing.md @gitlab-org/analytics-section/product-analytics/engineers/frontend /doc/development/tracing.md @gitlab-org/analytics-section/product-analytics/engineers/frontend
/doc/downgrade_ee_to_ce/ @axil /doc/downgrade_ee_to_ce/ @axil
@ -1077,8 +1082,8 @@ lib/gitlab/checks/**
/doc/user/compliance/license_approval_policies.md @rlehmann1 /doc/user/compliance/license_approval_policies.md @rlehmann1
/doc/user/compliance/license_scanning_of_cyclonedx_files/ @rdickenson /doc/user/compliance/license_scanning_of_cyclonedx_files/ @rdickenson
/doc/user/crm/ @msedlakjakubowski /doc/user/crm/ @msedlakjakubowski
/doc/user/custom_roles.md @rlehmann1 /doc/user/custom_roles.md @idurham
/doc/user/custom_roles/ @rlehmann1 /doc/user/custom_roles/ @idurham
/doc/user/discussions/ @aqualls /doc/user/discussions/ @aqualls
/doc/user/duo_amazon_q/ @sselhorn /doc/user/duo_amazon_q/ @sselhorn
/doc/user/duo_workflow/ @sselhorn /doc/user/duo_workflow/ @sselhorn
@ -1107,6 +1112,8 @@ lib/gitlab/checks/**
/doc/user/group/issues_analytics/ @lciutacu /doc/user/group/issues_analytics/ @lciutacu
/doc/user/group/iterations/ @msedlakjakubowski /doc/user/group/iterations/ @msedlakjakubowski
/doc/user/group/manage.md @emily.sahlani /doc/user/group/manage.md @emily.sahlani
/doc/user/group/moderate_users.md @idurham
/doc/user/group/reporting/ @idurham
/doc/user/group/repositories_analytics/ @lyspin /doc/user/group/repositories_analytics/ @lyspin
/doc/user/group/roadmap/ @msedlakjakubowski /doc/user/group/roadmap/ @msedlakjakubowski
/doc/user/group/saml_sso/ @idurham /doc/user/group/saml_sso/ @idurham
@ -1128,7 +1135,7 @@ lib/gitlab/checks/**
/doc/user/packages/container_registry/ @lyspin /doc/user/packages/container_registry/ @lyspin
/doc/user/packages/dependency_proxy/ @lyspin /doc/user/packages/dependency_proxy/ @lyspin
/doc/user/packages/harbor_container_registry/ @lyspin /doc/user/packages/harbor_container_registry/ @lyspin
/doc/user/permissions.md @rlehmann1 /doc/user/permissions.md @idurham
/doc/user/profile/account/ @idurham /doc/user/profile/account/ @idurham
/doc/user/profile/account/create_accounts.md @lciutacu /doc/user/profile/account/create_accounts.md @lciutacu
/doc/user/profile/achievements.md @emily.sahlani /doc/user/profile/achievements.md @emily.sahlani
@ -1204,6 +1211,7 @@ lib/gitlab/checks/**
/doc/user/project/wiki/ @msedlakjakubowski /doc/user/project/wiki/ @msedlakjakubowski
/doc/user/project/working_with_projects.md @emily.sahlani /doc/user/project/working_with_projects.md @emily.sahlani
/doc/user/public_access.md @emily.sahlani /doc/user/public_access.md @emily.sahlani
/doc/user/report_abuse.md @idurham
/doc/user/reserved_names.md @emily.sahlani /doc/user/reserved_names.md @emily.sahlani
/doc/user/rich_text_editor.md @msedlakjakubowski /doc/user/rich_text_editor.md @msedlakjakubowski
/doc/user/search/ @ashrafkhamis /doc/user/search/ @ashrafkhamis

View File

@ -1 +1 @@
f1a54081b5323ecbb0f360e8d479e7878a87138f 1ea2d19a4cd8e6f4bfdd3fbde0a82f8b129e9e40

View File

@ -66,14 +66,14 @@ export default {
<span class="gl-font-bold gl-text-subtle">{{ diffsCount }} {{ filesText }}</span> <span class="gl-font-bold gl-text-subtle">{{ diffsCount }} {{ filesText }}</span>
</div> </div>
<div <div
class="diff-stats-group gl-flex gl-items-center gl-text-green-600" class="diff-stats-group gl-flex gl-items-center gl-text-success"
:class="{ 'gl-font-bold': isCompareVersionsHeader }" :class="{ 'gl-font-bold': isCompareVersionsHeader }"
> >
<span>+</span> <span>+</span>
<span data-testid="js-file-addition-line">{{ addedLines }}</span> <span data-testid="js-file-addition-line">{{ addedLines }}</span>
</div> </div>
<div <div
class="diff-stats-group gl-flex gl-items-center gl-text-red-500" class="diff-stats-group gl-flex gl-items-center gl-text-danger"
:class="{ 'gl-font-bold': isCompareVersionsHeader }" :class="{ 'gl-font-bold': isCompareVersionsHeader }"
> >
<span></span> <span></span>

View File

@ -11,8 +11,8 @@ export default {
<template> <template>
<span class="file-row-stats"> <span class="file-row-stats">
<span data-testid="file-added-lines" class="gl-text-green-600"> +{{ file.addedLines }} </span> <span data-testid="file-added-lines" class="gl-text-success"> +{{ file.addedLines }} </span>
<span data-testid="file-removed-lines" class="gl-text-red-500"> -{{ file.removedLines }} </span> <span data-testid="file-removed-lines" class="gl-text-danger"> -{{ file.removedLines }} </span>
</span> </span>
</template> </template>

View File

@ -136,9 +136,9 @@ export function stats(file) {
valid = true; valid = true;
if (diff > 0) { if (diff > 0) {
classes = 'gl-text-green-600'; classes = 'gl-text-success';
} else if (diff < 0) { } else if (diff < 0) {
classes = 'gl-text-red-500'; classes = 'gl-text-danger';
} }
} }

View File

@ -95,13 +95,13 @@ export default (elements, issuablePopoverMount = handleIssuablePopoverMount) =>
const listenerAddedAttr = 'data-popover-listener-added'; const listenerAddedAttr = 'data-popover-listener-added';
elements.forEach((el) => { elements.forEach((el) => {
const { projectPath, groupPath, iid, referenceType, milestone, project } = el.dataset; const { projectPath, groupPath, iid, referenceType, milestone } = el.dataset;
let { namespacePath } = el.dataset; let { namespacePath } = el.dataset;
const title = el.dataset.mrTitle || el.title; const title = el.dataset.mrTitle || el.title;
const { innerText } = el; const { innerText } = el;
namespacePath = namespacePath || groupPath || projectPath; namespacePath = namespacePath || groupPath || projectPath;
const isIssuable = Boolean(namespacePath && title && iid); const isIssuable = Boolean(namespacePath && title && iid);
const isMilestone = Boolean(milestone && project); const isMilestone = Boolean(milestone);
if (!el.getAttribute(listenerAddedAttr) && referenceType && (isIssuable || isMilestone)) { if (!el.getAttribute(listenerAddedAttr) && referenceType && (isIssuable || isMilestone)) {
el.addEventListener('mouseenter', ({ target }) => { el.addEventListener('mouseenter', ({ target }) => {

View File

@ -46,13 +46,24 @@ export default {
axios axios
.post(this.reassignmentCsvPath, formData) .post(this.reassignmentCsvPath, formData)
.then(() => { .then((response) => {
// nothing to do here, modal already closes itself
})
.catch(() => {
createAlert({ createAlert({
message: s__('UserMapping|Something went wrong while uploading the CSV file.'), message: response.data.message,
variant: 'success',
}); });
})
.catch((error) => {
if (error.response.data?.message) {
const { message } = error.response.data;
createAlert({
message,
});
} else {
createAlert({
message: s__('UserMapping|Something went wrong while uploading the CSV file.'),
});
}
}); });
}, },
isValidFileType(file) { isValidFileType(file) {
@ -119,8 +130,8 @@ export default {
icon="download" icon="download"
data-testid="csv-download-button" data-testid="csv-download-button"
class="vertical-align-text-top" class="vertical-align-text-top"
>{{ s__('UserMapping|Download the prefilled CSV template.') }}</gl-button >{{ s__('UserMapping|Download the prefilled CSV template.') }}
> </gl-button>
</li> </li>
<li>{{ s__('UserMapping|Review and complete the CSV file.') }}</li> <li>{{ s__('UserMapping|Review and complete the CSV file.') }}</li>
<li>{{ s__('UserMapping|Upload the completed CSV file.') }}</li> <li>{{ s__('UserMapping|Upload the completed CSV file.') }}</li>

View File

@ -72,10 +72,11 @@ export default {
}, },
isMergeRequestBroken() { isMergeRequestBroken() {
return ( return (
this.mergeRequest.commitCount === 0 || this.mergeRequest.state === 'opened' &&
!this.mergeRequest.sourceBranchExists || (this.mergeRequest.commitCount === 0 ||
!this.mergeRequest.targetBranchExists || !this.mergeRequest.sourceBranchExists ||
this.mergeRequest.conflicts !this.mergeRequest.targetBranchExists ||
this.mergeRequest.conflicts)
); );
}, },
}, },
@ -177,6 +178,7 @@ export default {
name="warning-solid" name="warning-solid"
variant="subtle" variant="subtle"
class="gl-mt-1" class="gl-mt-1"
data-testid="mr-broken-badge"
/> />
<discussions-badge <discussions-badge
v-if="mergeRequest.resolvableDiscussionsCount" v-if="mergeRequest.resolvableDiscussionsCount"
@ -204,11 +206,11 @@ export default {
<gl-icon name="doc-code" /> <gl-icon name="doc-code" />
<span>{{ mergeRequest.diffStatsSummary.fileCount }}</span> <span>{{ mergeRequest.diffStatsSummary.fileCount }}</span>
</div> </div>
<div class="gl-flex gl-items-center gl-font-bold gl-text-green-600"> <div class="gl-flex gl-items-center gl-font-bold gl-text-success">
<span>+</span> <span>+</span>
<span>{{ mergeRequest.diffStatsSummary.additions }}</span> <span>{{ mergeRequest.diffStatsSummary.additions }}</span>
</div> </div>
<div class="gl-flex gl-items-center gl-font-bold gl-text-red-500"> <div class="gl-flex gl-items-center gl-font-bold gl-text-danger">
<span></span> <span></span>
<span>{{ mergeRequest.diffStatsSummary.deletions }}</span> <span>{{ mergeRequest.diffStatsSummary.deletions }}</span>
</div> </div>

View File

@ -9,6 +9,7 @@ fragment MergeRequestDashboardFragment on MergeRequest {
title title
webUrl webUrl
draft draft
state
author { author {
...User ...User
} }

View File

@ -32,7 +32,6 @@ export async function mountMergeRequestListsApp({
newMergeRequestPath, newMergeRequestPath,
showExportButton, showExportButton,
issuableType, issuableType,
issuableCount,
email, email,
exportCsvPath, exportCsvPath,
rssUrl, rssUrl,
@ -71,7 +70,6 @@ export async function mountMergeRequestListsApp({
newMergeRequestPath, newMergeRequestPath,
showExportButton: parseBoolean(showExportButton), showExportButton: parseBoolean(showExportButton),
issuableType, issuableType,
issuableCount: Number(issuableCount),
email, email,
exportCsvPath, exportCsvPath,
rssUrl, rssUrl,

View File

@ -6,6 +6,8 @@ import { s__, sprintf } from '~/locale';
import { nHoursAfter } from '~/lib/utils/datetime_utility'; import { nHoursAfter } from '~/lib/utils/datetime_utility';
import { reportToSentry } from '~/ci/utils'; import { reportToSentry } from '~/ci/utils';
import { localeDateFormat } from '~/lib/utils/datetime/locale_dateformat'; import { localeDateFormat } from '~/lib/utils/datetime/locale_dateformat';
import Tracking from '~/tracking';
import { INSTRUMENT_TODO_ITEM_CLICK } from '~/todos/constants';
import snoozeTodoMutation from './mutations/snooze_todo.mutation.graphql'; import snoozeTodoMutation from './mutations/snooze_todo.mutation.graphql';
import unSnoozeTodoMutation from './mutations/un_snooze_todo.mutation.graphql'; import unSnoozeTodoMutation from './mutations/un_snooze_todo.mutation.graphql';
@ -15,6 +17,7 @@ export default {
GlDisclosureDropdown, GlDisclosureDropdown,
GlTooltip, GlTooltip,
}, },
mixins: [Tracking.mixin()],
inject: ['currentTime'], inject: ['currentTime'],
props: { props: {
todo: { todo: {
@ -62,7 +65,12 @@ export default {
day: dateFormat(forAnHour, 'DDDD'), day: dateFormat(forAnHour, 'DDDD'),
time: toTimeString(forAnHour), time: toTimeString(forAnHour),
}), }),
action: () => this.snooze(forAnHour), action: () => {
this.track(INSTRUMENT_TODO_ITEM_CLICK, {
label: 'snooze_for_one_hour',
});
this.snooze(forAnHour);
},
}, },
{ {
text: s__('Todos|Until later today'), text: s__('Todos|Until later today'),
@ -70,7 +78,12 @@ export default {
day: dateFormat(untilLaterToday, 'DDDD'), day: dateFormat(untilLaterToday, 'DDDD'),
time: toTimeString(untilLaterToday), time: toTimeString(untilLaterToday),
}), }),
action: () => this.snooze(untilLaterToday), action: () => {
this.track(INSTRUMENT_TODO_ITEM_CLICK, {
label: 'snooze_until_later_today',
});
this.snooze(untilLaterToday);
},
}, },
{ {
text: s__('Todos|Until tomorrow'), text: s__('Todos|Until tomorrow'),
@ -79,6 +92,10 @@ export default {
time: toTimeString(untilTomorrow), time: toTimeString(untilTomorrow),
}), }),
action: () => { action: () => {
this.track(INSTRUMENT_TODO_ITEM_CLICK, {
label: 'snooze_until_tomorrow',
});
this.snooze(untilTomorrow); this.snooze(untilTomorrow);
}, },
}, },
@ -119,6 +136,9 @@ export default {
} }
}, },
async unSnooze() { async unSnooze() {
this.track(INSTRUMENT_TODO_ITEM_CLICK, {
label: 'remove_snooze',
});
try { try {
const { data } = await this.$apollo.mutate({ const { data } = await this.$apollo.mutate({
mutation: unSnoozeTodoMutation, mutation: unSnoozeTodoMutation,

View File

@ -12,7 +12,7 @@ export const i18n = {
const variantCssColorMap = { const variantCssColorMap = {
success: 'gl-text-success', success: 'gl-text-success',
danger: 'gl-text-red-500', danger: 'gl-text-danger',
}; };
export default { export default {
@ -128,8 +128,8 @@ export default {
>{{ item.text }}</span >{{ item.text }}</span
> >
<span class="gl-ml-auto gl-whitespace-nowrap" aria-hidden="true"> <span class="gl-ml-auto gl-whitespace-nowrap" aria-hidden="true">
<span class="gl-text-green-600">+{{ item.added }}</span> <span class="gl-text-success">+{{ item.added }}</span>
<span class="gl-text-red-500">-{{ item.removed }}</span> <span class="gl-text-danger">-{{ item.removed }}</span>
</span> </span>
<span class="gl-sr-only" <span class="gl-sr-only"
>{{ additionsText(item.added) }}, {{ deletionsText(item.removed) }}</span >{{ additionsText(item.added) }}, {{ deletionsText(item.removed) }}</span
@ -150,10 +150,10 @@ export default {
> >
<gl-sprintf :message="$options.i18n.messageAdditionsDeletions"> <gl-sprintf :message="$options.i18n.messageAdditionsDeletions">
<template #additions> <template #additions>
<span class="gl-font-bold gl-text-green-600">{{ additionsText() }}</span> <span class="gl-font-bold gl-text-success">{{ additionsText() }}</span>
</template> </template>
<template #deletions> <template #deletions>
<span class="gl-font-bold gl-text-red-500">{{ deletionsText() }}</span> <span class="gl-font-bold gl-text-danger">{{ deletionsText() }}</span>
</template> </template>
</gl-sprintf> </gl-sprintf>
</span> </span>

View File

@ -103,10 +103,10 @@ export default {
</span> </span>
<span v-if="file.changed || file.tempFile" v-once class="diff-changed-stats"> <span v-if="file.changed || file.tempFile" v-once class="diff-changed-stats">
<span v-if="showDiffStats"> <span v-if="showDiffStats">
<span class="gl-font-bold gl-text-green-600"> <span class="gl-font-bold gl-text-success">
<gl-icon name="file-addition" class="align-text-top" /> {{ file.addedLines }} <gl-icon name="file-addition" class="align-text-top" /> {{ file.addedLines }}
</span> </span>
<span class="ml-1 gl-font-bold gl-text-red-500"> <span class="ml-1 gl-font-bold gl-text-danger">
<gl-icon name="file-deletion" class="align-text-top" /> {{ file.removedLines }} <gl-icon name="file-deletion" class="align-text-top" /> {{ file.removedLines }}
</span> </span>
</span> </span>

View File

@ -251,7 +251,6 @@ export default {
this.$emit('input', target.value); this.$emit('input', target.value);
this.saveDraft(); this.saveDraft();
this.autosizeTextarea();
}, },
renderMarkdown(markdown) { renderMarkdown(markdown) {
const url = setUrlParams( const url = setUrlParams(

View File

@ -0,0 +1,69 @@
# frozen_string_literal: true
module Groups
class BulkPlaceholderAssignmentsController < Groups::ApplicationController
include WorkhorseAuthorization
PERMITTED_FILE_EXTENSIONS = %w[csv].freeze
before_action :authorize_owner_access!
feature_category :importers
def show
return render_404 unless Feature.enabled?(:importer_user_mapping_reassignment_csv, current_user)
csv_response = Import::SourceUsers::GenerateCsvService.new(group, current_user: current_user).execute
if csv_response.success?
send_data(
csv_response.payload,
filename: "bulk_reassignments_for_namespace_#{group.id}_#{Time.current.to_i}.csv",
type: 'text/csv; charset=utf-8'
)
else
redirect_back_or_default(options: { alert: csv_response.message })
end
end
def create
return render_404 unless Feature.enabled?(:importer_user_mapping_reassignment_csv, current_user)
unless file_is_valid?(file_params[:file])
respond_to do |format|
format.json do
render json: { message: s_('UserMapping|You must upload a CSV file with a .csv file extension.') },
status: :unprocessable_entity
end
end
return
end
respond_to do |format|
format.json do
render json: {
message: s_('UserMapping|The file is being processed and you will receive an email when completed.')
}
end
end
end
private
def file_params
params.permit(:file)
end
def uploader_class
FileUploader
end
def file_extension_allowlist
PERMITTED_FILE_EXTENSIONS
end
def maximum_size
Gitlab::CurrentSettings.max_attachment_size.megabytes
end
end
end

View File

@ -13,7 +13,6 @@ class Groups::GroupMembersController < Groups::ApplicationController
end end
# Authorize # Authorize
before_action :authorize_owner_access!, only: :bulk_reassignment_file
before_action :authorize_admin_group_member!, except: admin_not_required_endpoints before_action :authorize_admin_group_member!, except: admin_not_required_endpoints
before_action :authorize_read_group_member!, only: :index before_action :authorize_read_group_member!, only: :index
@ -52,22 +51,6 @@ class Groups::GroupMembersController < Groups::ApplicationController
) )
end end
def bulk_reassignment_file
return render_404 unless Feature.enabled?(:importer_user_mapping_reassignment_csv, current_user)
csv_response = Import::SourceUsers::GenerateCsvService.new(membershipable, current_user: current_user).execute
if csv_response.success?
send_data(
csv_response.payload,
filename: "bulk_reassignments_for_namespace_#{membershipable.id}_#{Time.current.to_i}.csv",
type: 'text/csv; charset=utf-8'
)
else
redirect_back_or_default(options: { alert: csv_response.message })
end
end
# MembershipActions concern # MembershipActions concern
alias_method :membershipable, :group alias_method :membershipable, :group

View File

@ -30,7 +30,7 @@ module Groups::GroupMembersHelper
can_approve_access_requests: true, # true for CE, overridden in EE can_approve_access_requests: true, # true for CE, overridden in EE
placeholder: placeholder_users, placeholder: placeholder_users,
available_roles: available_group_roles(group), available_roles: available_group_roles(group),
reassignment_csv_path: bulk_reassignment_file_group_group_members_path(group) reassignment_csv_path: group_bulk_reassignment_file_path(group)
} }
end end
# rubocop:enable Metrics/ParameterLists # rubocop:enable Metrics/ParameterLists

View File

@ -262,7 +262,6 @@ module MergeRequestsHelper
is_signed_in: current_user.present?.to_s, is_signed_in: current_user.present?.to_s,
show_export_button: "true", show_export_button: "true",
issuable_type: :merge_request, issuable_type: :merge_request,
issuable_count: issuables_count_for_state(:merge_request, params[:state]),
email: current_user.present? ? current_user.notification_email_or_default : nil, email: current_user.present? ? current_user.notification_email_or_default : nil,
rss_url: url_for(safe_params.merge(rss_url_options)), rss_url: url_for(safe_params.merge(rss_url_options)),
emails_help_page_path: help_page_path('development/emails.md', anchor: 'email-namespace'), emails_help_page_path: help_page_path('development/emails.md', anchor: 'email-namespace'),

View File

@ -93,6 +93,7 @@ module ApplicationSettingImplementation
external_pipeline_validation_service_token: nil, external_pipeline_validation_service_token: nil,
external_pipeline_validation_service_url: nil, external_pipeline_validation_service_url: nil,
failed_login_attempts_unlock_period_in_minutes: nil, failed_login_attempts_unlock_period_in_minutes: nil,
fetch_observability_alerts_from_cloud: true,
first_day_of_week: 0, first_day_of_week: 0,
floc_enabled: false, floc_enabled: false,
gitaly_timeout_default: 55, gitaly_timeout_default: 55,

View File

@ -11,19 +11,25 @@ module Integrations
field :recipients, field :recipients,
type: :textarea, type: :textarea,
help: -> { _('Comma-separated list of email addresses.') }, help: -> { _('Comma-separated list of recipient email addresses.') },
required: true required: true
field :notify_only_broken_pipelines, field :notify_only_broken_pipelines,
type: :checkbox type: :checkbox,
description: -> { _('Send notifications for broken pipelines.') }
field :notify_only_default_branch, field :notify_only_default_branch,
type: :checkbox, type: :checkbox,
api_only: true api_only: true,
description: -> { _('Send notifications for the default branch.') }
field :branches_to_be_notified, field :branches_to_be_notified,
type: :select, type: :select,
title: -> { s_('Integrations|Branches for which notifications are to be sent') }, title: -> { s_('Integrations|Branches for which notifications are to be sent') },
description: -> {
_('Branches to send notifications for. Valid options are `all`, `default`, `protected`, ' \
'and `default_and_protected`. The default value is `default`.')
},
choices: branch_choices choices: branch_choices
def initialize_properties def initialize_properties

View File

@ -5,7 +5,7 @@ class WorkItem < Issue
COMMON_QUICK_ACTIONS_COMMANDS = [ COMMON_QUICK_ACTIONS_COMMANDS = [
:title, :reopen, :close, :cc, :tableflip, :shrug, :type, :promote_to, :checkin_reminder, :title, :reopen, :close, :cc, :tableflip, :shrug, :type, :promote_to, :checkin_reminder,
:subscribe, :unsubscribe, :confidential, :award, :react :subscribe, :unsubscribe, :confidential, :award, :react, :move, :clone
].freeze ].freeze
self.table_name = 'issues' self.table_name = 'issues'

View File

@ -63,8 +63,11 @@ module WorkItems
return unless work_item_parent && work_item return unless work_item_parent && work_item
if work_item_parent.confidential? && !work_item.confidential? if work_item_parent.confidential? && !work_item.confidential?
errors.add :work_item, _("cannot assign a non-confidential work item to a confidential "\ errors.add :work_item, format(
"parent. Make the work item confidential and try again.") _("cannot assign a non-confidential %{work_item_type} to a confidential "\
"parent. Make the %{work_item_type} confidential and try again."),
work_item_type: work_item.work_item_type.name.downcase
)
end end
end end

View File

@ -17,7 +17,7 @@ module WorkItems
link.move_to_start link.move_to_start
end end
create_notes_and_resource_event(work_item, link) if link.changed? && link.save create_notes_and_resource_event(work_item, link) if link.save
link link
end end

View File

@ -4,6 +4,7 @@
@breadcrumb_link = merge_requests_dashboard_path(assignee_username: current_user.username) @breadcrumb_link = merge_requests_dashboard_path(assignee_username: current_user.username)
add_page_specific_style 'page_bundles/issuable_list' add_page_specific_style 'page_bundles/issuable_list'
- new_lists_enabled = ::Feature.enabled?(:merge_request_dashboard_new_lists, current_user, type: :wip)
= render_dashboard_ultimate_trial(current_user) = render_dashboard_ultimate_trial(current_user)
= render_if_exists 'shared/dashboard/saml_reauth_notice', = render_if_exists 'shared/dashboard/saml_reauth_notice',
groups_requiring_saml_reauth: user_groups_requiring_reauth groups_requiring_saml_reauth: user_groups_requiring_reauth
@ -26,14 +27,14 @@
= render 'shared/new_project_item_vue_select' = render 'shared/new_project_item_vue_select'
- if merge_request_dashboard_enabled?(current_user) && !current_page?(merge_requests_search_dashboard_path) - if merge_request_dashboard_enabled?(current_user) && !current_page?(merge_requests_search_dashboard_path)
#js-merge-request-dashboard{ data: { base_path: merge_requests_dashboard_path, new_lists_enabled: ::Feature.enabled?(:merge_request_dashboard_new_lists, current_user, type: :wip).to_s, merge_requests_search_dashboard_path: merge_requests_search_dashboard_path(assignee_username: current_user.username), initial_data: merge_request_dashboard_data.to_json } } #js-merge-request-dashboard{ data: { base_path: merge_requests_dashboard_path, new_lists_enabled: new_lists_enabled.to_s, merge_requests_search_dashboard_path: merge_requests_search_dashboard_path(assignee_username: current_user.username), initial_data: merge_request_dashboard_data.to_json } }
= gl_loading_icon(size: 'lg') = gl_loading_icon(size: 'lg')
- if !merge_request_dashboard_enabled?(current_user) || current_page?(merge_requests_search_dashboard_path) - if !merge_request_dashboard_enabled?(current_user) || current_page?(merge_requests_search_dashboard_path)
- if merge_request_dashboard_enabled?(current_user) - if merge_request_dashboard_enabled?(current_user)
= gl_tabs_nav do = gl_tabs_nav do
= gl_tab_link_to _('Needs attention'), merge_requests_dashboard_path = gl_tab_link_to new_lists_enabled ? _('Active') : _('Needs attention'), merge_requests_dashboard_path
= gl_tab_link_to _('Following'), merge_requests_following_dashboard_path = gl_tab_link_to new_lists_enabled ? _('Merged') : _('Following'), merge_requests_following_dashboard_path
= gl_tab_link_to _('Search'), merge_requests_search_dashboard_path, item_active: true = gl_tab_link_to _('Search'), merge_requests_search_dashboard_path, item_active: true
%div{ class: "#{'gl-bg-gray-10' if merge_request_dashboard_enabled?(current_user)}" } %div{ class: "#{'gl-bg-gray-10' if merge_request_dashboard_enabled?(current_user)}" }

View File

@ -48,9 +48,9 @@
pattern: Gitlab::PathRegex::NAMESPACE_FORMAT_REGEX_JS, pattern: Gitlab::PathRegex::NAMESPACE_FORMAT_REGEX_JS,
required: true, required: true,
title: _('Please create a username with only alphanumeric characters.') title: _('Please create a username with only alphanumeric characters.')
%p.validation-error.gl-text-red-500.gl-field-error-ignore.gl-mt-2.field-validation.hide %p.validation-error.gl-text-danger.gl-field-error-ignore.gl-mt-2.field-validation.hide
= _('Username is already taken.') = _('Username is already taken.')
%p.validation-success.gl-text-green-600.gl-field-error-ignore.gl-mt-2.field-validation.hide %p.validation-success.gl-text-success.gl-field-error-ignore.gl-mt-2.field-validation.hide
= _('Username is available.') = _('Username is available.')
%p.validation-pending.gl-field-error-ignore.gl-mt-2.field-validation.hide %p.validation-pending.gl-field-error-ignore.gl-mt-2.field-validation.hide
= _('Checking username availability...') = _('Checking username availability...')

View File

@ -1,24 +1,25 @@
- @can_bulk_update = can?(current_user, :admin_merge_request, @group) && @group.licensed_feature_available?(:group_bulk_edit) && issuables_count_for_state(:merge_requests, :all) > 0 - has_bulk_update_permission = can?(current_user, :admin_merge_request, @group) && @group.licensed_feature_available?(:group_bulk_edit)
- page_title _("Merge requests") - page_title _("Merge requests")
- add_page_specific_style 'page_bundles/issuable_list' - add_page_specific_style 'page_bundles/issuable_list'
- if Feature.enabled?(:vue_merge_request_list, @group) - if Feature.enabled?(:vue_merge_request_list, @group)
.js-merge-request-list-root{ data: group_merge_requests_list_data(@group, current_user) } .js-merge-request-list-root{ data: group_merge_requests_list_data(@group, current_user) }
- if @can_bulk_update - if has_bulk_update_permission
= render_if_exists 'shared/issuable/group_bulk_update_sidebar', group: @group, type: :merge_requests = render_if_exists 'shared/issuable/group_bulk_update_sidebar', group: @group, type: :merge_requests
- else - else
- can_bulk_update = has_bulk_update_permission && issuables_count_for_state(:merge_requests, :all) > 0
.top-area .top-area
= render 'shared/issuable/nav', type: :merge_requests, display_count: !@search_timeout_occurred = render 'shared/issuable/nav', type: :merge_requests, display_count: !@search_timeout_occurred
- if current_user - if current_user
.nav-controls .nav-controls
- if @can_bulk_update - if can_bulk_update
= render_if_exists 'projects/merge_requests/bulk_update_button' = render_if_exists 'projects/merge_requests/bulk_update_button'
= render 'shared/new_project_item_vue_select' = render 'shared/new_project_item_vue_select'
= render 'shared/issuable/search_bar', type: :merge_requests = render 'shared/issuable/search_bar', type: :merge_requests
- if @can_bulk_update - if can_bulk_update
= render_if_exists 'shared/issuable/group_bulk_update_sidebar', group: @group, type: :merge_requests = render_if_exists 'shared/issuable/group_bulk_update_sidebar', group: @group, type: :merge_requests
- if @search_timeout_occurred - if @search_timeout_occurred

View File

@ -0,0 +1,12 @@
---
api_type:
attr: observability_settings
clusterwide: false
column: observability_settings
db_type: jsonb
default: "'{}'::jsonb"
description: Contains application settings for Observability features
encrypted: false
gitlab_com_different_than_default: false
jihu: false
not_null: true

View File

@ -1,9 +0,0 @@
---
name: go_get_handle_relative_url
feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/508593
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/176097
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/510100
milestone: '17.8'
group: group::source code
type: gitlab_com_derisk
default_enabled: false

View File

@ -1,8 +0,0 @@
---
name: ci_secure_files_read_only
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/84089
rollout_issue_url:
milestone: '14.10'
type: ops
group: group::incubation
default_enabled: false

View File

@ -120,7 +120,10 @@ constraints(::Constraints::GroupUrlConstrainer.new) do
post :resend_invite, on: :member post :resend_invite, on: :member
collection do collection do
get :bulk_reassignment_file resource :bulk_reassignment_file, only: %i[show create], controller: 'bulk_placeholder_assignments' do
post :authorize
end
delete :leave delete :leave
end end
end end

View File

@ -0,0 +1,10 @@
# frozen_string_literal: true
class AddO11ySettingsToApplicationSettings < Gitlab::Database::Migration[2.2]
enable_lock_retries!
milestone '17.8'
def change
add_column :application_settings, :observability_settings, :jsonb, default: {}, null: false
end
end

View File

@ -0,0 +1,20 @@
# frozen_string_literal: true
class AddO11ySettingsHashConstraint < Gitlab::Database::Migration[2.2]
disable_ddl_transaction!
milestone '17.8'
CONSTRAINT_NAME = 'check_application_settings_o11y_settings_is_hash'
def up
add_check_constraint(
:application_settings,
"(jsonb_typeof(observability_settings) = 'object')",
CONSTRAINT_NAME
)
end
def down
remove_check_constraint :application_settings, CONSTRAINT_NAME
end
end

View File

@ -0,0 +1 @@
ec474fca5d3e528477f838c937960469619ffc22739cca03b3afb9517a950989

View File

@ -0,0 +1 @@
06234102c3cab9b43a17fcbf3c8a9772174efa97322a3de9beb2b2b6720f3003

View File

@ -7452,6 +7452,7 @@ CREATE TABLE application_settings (
elasticsearch_indexed_field_length_limit integer DEFAULT 0 NOT NULL, elasticsearch_indexed_field_length_limit integer DEFAULT 0 NOT NULL,
elasticsearch_indexed_file_size_limit_kb integer DEFAULT 1024 NOT NULL, elasticsearch_indexed_file_size_limit_kb integer DEFAULT 1024 NOT NULL,
elasticsearch_max_code_indexing_concurrency integer DEFAULT 30 NOT NULL, elasticsearch_max_code_indexing_concurrency integer DEFAULT 30 NOT NULL,
observability_settings jsonb DEFAULT '{}'::jsonb NOT NULL,
CONSTRAINT app_settings_container_reg_cleanup_tags_max_list_size_positive CHECK ((container_registry_cleanup_tags_service_max_list_size >= 0)), CONSTRAINT app_settings_container_reg_cleanup_tags_max_list_size_positive CHECK ((container_registry_cleanup_tags_service_max_list_size >= 0)),
CONSTRAINT app_settings_dep_proxy_ttl_policies_worker_capacity_positive CHECK ((dependency_proxy_ttl_group_policy_worker_capacity >= 0)), CONSTRAINT app_settings_dep_proxy_ttl_policies_worker_capacity_positive CHECK ((dependency_proxy_ttl_group_policy_worker_capacity >= 0)),
CONSTRAINT app_settings_ext_pipeline_validation_service_url_text_limit CHECK ((char_length(external_pipeline_validation_service_url) <= 255)), CONSTRAINT app_settings_ext_pipeline_validation_service_url_text_limit CHECK ((char_length(external_pipeline_validation_service_url) <= 255)),
@ -7508,6 +7509,7 @@ CREATE TABLE application_settings (
CONSTRAINT check_application_settings_elasticsearch_is_hash CHECK ((jsonb_typeof(elasticsearch) = 'object'::text)), CONSTRAINT check_application_settings_elasticsearch_is_hash CHECK ((jsonb_typeof(elasticsearch) = 'object'::text)),
CONSTRAINT check_application_settings_importers_is_hash CHECK ((jsonb_typeof(importers) = 'object'::text)), CONSTRAINT check_application_settings_importers_is_hash CHECK ((jsonb_typeof(importers) = 'object'::text)),
CONSTRAINT check_application_settings_integrations_is_hash CHECK ((jsonb_typeof(integrations) = 'object'::text)), CONSTRAINT check_application_settings_integrations_is_hash CHECK ((jsonb_typeof(integrations) = 'object'::text)),
CONSTRAINT check_application_settings_o11y_settings_is_hash CHECK ((jsonb_typeof(observability_settings) = 'object'::text)),
CONSTRAINT check_application_settings_package_registry_is_hash CHECK ((jsonb_typeof(package_registry) = 'object'::text)), CONSTRAINT check_application_settings_package_registry_is_hash CHECK ((jsonb_typeof(package_registry) = 'object'::text)),
CONSTRAINT check_application_settings_rate_limits_is_hash CHECK ((jsonb_typeof(rate_limits) = 'object'::text)), CONSTRAINT check_application_settings_rate_limits_is_hash CHECK ((jsonb_typeof(rate_limits) = 'object'::text)),
CONSTRAINT check_application_settings_rate_limits_unauth_git_http_is_hash CHECK ((jsonb_typeof(rate_limits_unauthenticated_git_http) = 'object'::text)), CONSTRAINT check_application_settings_rate_limits_unauth_git_http_is_hash CHECK ((jsonb_typeof(rate_limits_unauthenticated_git_http) = 'object'::text)),

View File

@ -32488,10 +32488,6 @@ Returns [`ProjectDataTransfer`](#projectdatatransfer).
Software dependencies used by the project. Software dependencies used by the project.
DETAILS:
**Introduced** in GitLab 15.9.
**Status**: Experiment.
Returns [`DependencyConnection`](#dependencyconnection). Returns [`DependencyConnection`](#dependencyconnection).
This field returns a [connection](#connections). It accepts the This field returns a [connection](#connections). It accepts the
@ -35198,6 +35194,7 @@ JSON structure of a file with matches.
| <a id="searchblobfiletypeblameurl"></a>`blameUrl` **{warning-solid}** | [`String`](#string) | **Introduced** in GitLab 17.2. **Status**: Experiment. Blame URL of the file. | | <a id="searchblobfiletypeblameurl"></a>`blameUrl` **{warning-solid}** | [`String`](#string) | **Introduced** in GitLab 17.2. **Status**: Experiment. Blame URL of the file. |
| <a id="searchblobfiletypechunks"></a>`chunks` **{warning-solid}** | [`[SearchBlobChunk!]`](#searchblobchunk) | **Introduced** in GitLab 17.2. **Status**: Experiment. Maximum matches per file. | | <a id="searchblobfiletypechunks"></a>`chunks` **{warning-solid}** | [`[SearchBlobChunk!]`](#searchblobchunk) | **Introduced** in GitLab 17.2. **Status**: Experiment. Maximum matches per file. |
| <a id="searchblobfiletypefileurl"></a>`fileUrl` **{warning-solid}** | [`String`](#string) | **Introduced** in GitLab 17.2. **Status**: Experiment. URL of the file. | | <a id="searchblobfiletypefileurl"></a>`fileUrl` **{warning-solid}** | [`String`](#string) | **Introduced** in GitLab 17.2. **Status**: Experiment. URL of the file. |
| <a id="searchblobfiletypelanguage"></a>`language` **{warning-solid}** | [`String`](#string) | **Introduced** in GitLab 17.8. **Status**: Experiment. Language of the file. |
| <a id="searchblobfiletypematchcount"></a>`matchCount` **{warning-solid}** | [`Int`](#int) | **Introduced** in GitLab 17.2. **Status**: Experiment. Matches per file up to a max of 50 chunks. Default is 3. | | <a id="searchblobfiletypematchcount"></a>`matchCount` **{warning-solid}** | [`Int`](#int) | **Introduced** in GitLab 17.2. **Status**: Experiment. Matches per file up to a max of 50 chunks. Default is 3. |
| <a id="searchblobfiletypematchcounttotal"></a>`matchCountTotal` **{warning-solid}** | [`Int`](#int) | **Introduced** in GitLab 17.2. **Status**: Experiment. Total number of matches per file. | | <a id="searchblobfiletypematchcounttotal"></a>`matchCountTotal` **{warning-solid}** | [`Int`](#int) | **Introduced** in GitLab 17.2. **Status**: Experiment. Total number of matches per file. |
| <a id="searchblobfiletypepath"></a>`path` **{warning-solid}** | [`String`](#string) | **Introduced** in GitLab 17.2. **Status**: Experiment. Path of the file. | | <a id="searchblobfiletypepath"></a>`path` **{warning-solid}** | [`String`](#string) | **Introduced** in GitLab 17.2. **Status**: Experiment. Path of the file. |
@ -35211,6 +35208,7 @@ JSON structure of each line in a matched chunk.
| Name | Type | Description | | Name | Type | Description |
| ---- | ---- | ----------- | | ---- | ---- | ----------- |
| <a id="searchbloblinehighlights"></a>`highlights` **{warning-solid}** | [`[[Int!]!]`](#int) | **Introduced** in GitLab 17.8. **Status**: Experiment. Column numbers of the first and last highlighted characters on a line. |
| <a id="searchbloblinelinenumber"></a>`lineNumber` **{warning-solid}** | [`Int`](#int) | **Introduced** in GitLab 17.2. **Status**: Experiment. Line number of the blob. | | <a id="searchbloblinelinenumber"></a>`lineNumber` **{warning-solid}** | [`Int`](#int) | **Introduced** in GitLab 17.2. **Status**: Experiment. Line number of the blob. |
| <a id="searchbloblinerichtext"></a>`richText` **{warning-solid}** | [`String`](#string) | **Introduced** in GitLab 17.2. **Status**: Experiment. Rich text of the blob. | | <a id="searchbloblinerichtext"></a>`richText` **{warning-solid}** | [`String`](#string) | **Introduced** in GitLab 17.2. **Status**: Experiment. Rich text of the blob. |
| <a id="searchbloblinetext"></a>`text` **{warning-solid}** | [`String`](#string) | **Introduced** in GitLab 17.2. **Status**: Experiment. Text content of the blob. | | <a id="searchbloblinetext"></a>`text` **{warning-solid}** | [`String`](#string) | **Introduced** in GitLab 17.2. **Status**: Experiment. Text content of the blob. |

View File

@ -582,6 +582,7 @@ To resolve these issues:
- For new projects, set up and run the necessary security scans on the default branch before creating merge requests. - For new projects, set up and run the necessary security scans on the default branch before creating merge requests.
- Consider using scan execution policies or pipeline execution policies to ensure consistent execution of security scans across all branches. - Consider using scan execution policies or pipeline execution policies to ensure consistent execution of security scans across all branches.
- Consider using [`fallback_behavior`](#fallback_behavior) with `open` to prevent invalid or unenforceable rules in a policy from requiring approval. - Consider using [`fallback_behavior`](#fallback_behavior) with `open` to prevent invalid or unenforceable rules in a policy from requiring approval.
- Consider using the [`policy tuning`](#policy_tuning) setting `unblock_rules_using_execution_policies` to address scenarios where security scan artifacts are missing, and scan execution policies are enforced. When enabled, this setting makes approval rules optional when scan artifacts are missing from the target branch and a scan is required by a scan execution policy. This feature only works with an existing scan execution policy that has matching scanners. It offers flexibility in the merge request process when certain security scans cannot be performed due to missing artifacts.
### Support request for debugging of merge request approval policy ### Support request for debugging of merge request approval policy

View File

@ -207,7 +207,7 @@ the only jobs that run are the pipeline execution policy jobs.
### `override_project_ci` ### `override_project_ci`
> - Updated handling of workflow rules [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/175088) in GitLab 17.8 [with a flag](../../../administration/feature_flags.md) named `policies_always_override_project_ci`. Disabled by default. > - Updated handling of workflow rules [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/175088) in GitLab 17.8 [with a flag](../../../administration/feature_flags.md) named `policies_always_override_project_ci`. Enabled by default.
This strategy replaces the project's existing CI/CD configuration with a new one defined by the pipeline execution policy. This strategy is ideal when the entire pipeline needs to be standardized or replaced, like when you want to enforce organization-wide CI/CD standards or compliance requirements in a highly regulated industry. To override the pipeline configuration, define the CI/CD jobs and do not use `include:project`. This strategy replaces the project's existing CI/CD configuration with a new one defined by the pipeline execution policy. This strategy is ideal when the entire pipeline needs to be standardized or replaced, like when you want to enforce organization-wide CI/CD standards or compliance requirements in a highly regulated industry. To override the pipeline configuration, define the CI/CD jobs and do not use `include:project`.

View File

@ -12,11 +12,10 @@ DETAILS:
**Status:** Preview/Beta **Status:** Preview/Beta
> - Introduced as [beta](../../policy/development_stages_support.md#beta) in GitLab 17.7 [with a flag](../../administration/feature_flags.md) named `amazon_q_integration`. Disabled by default. > - Introduced as [beta](../../policy/development_stages_support.md#beta) in GitLab 17.7 [with a flag](../../administration/feature_flags.md) named `amazon_q_integration`. Disabled by default.
> - Feature flag `amazon_q_integration` removed in GitLab 17.8.
FLAG: NOTE:
The availability of this feature is controlled by a feature flag. If you have a Duo Pro or Duo Enterprise add-on, this feature is not available.
For more information, see the history.
This feature is Preview/Beta and is available for testing, but not ready for production use.
At Re:Invent 2024, Amazon announced the GitLab Duo with Amazon Q integration. At Re:Invent 2024, Amazon announced the GitLab Duo with Amazon Q integration.
With this integration, you can automate tasks and increase productivity. With this integration, you can automate tasks and increase productivity.

View File

@ -12,11 +12,10 @@ DETAILS:
**Status:** Preview/Beta **Status:** Preview/Beta
> - Introduced as an [experiment](../../policy/development_stages_support.md#experiment) in GitLab 17.7 [with a flag](../../administration/feature_flags.md) named `amazon_q_integration`. Disabled by default. > - Introduced as an [experiment](../../policy/development_stages_support.md#experiment) in GitLab 17.7 [with a flag](../../administration/feature_flags.md) named `amazon_q_integration`. Disabled by default.
> - Feature flag `amazon_q_integration` removed in GitLab 17.8.
FLAG: NOTE:
The availability of this feature is controlled by a feature flag. If you have a Duo Pro or Duo Enterprise add-on, this feature is not available.
For more information, see the history.
This feature is a Preview/Beta and is available for testing, but not ready for production use.
To use GitLab Duo with Amazon Q, you can [request access to a lab environment](https://about.gitlab.com/partners/technology-partners/aws/#interest). To use GitLab Duo with Amazon Q, you can [request access to a lab environment](https://about.gitlab.com/partners/technology-partners/aws/#interest).
@ -40,7 +39,6 @@ To set up GitLab Duo with Amazon Q, you must:
- With an HTTPS URL that can be accessed by Amazon Q (the SSL certificate must not be self-signed). - With an HTTPS URL that can be accessed by Amazon Q (the SSL certificate must not be self-signed).
For more details about SSL, see [Configure SSL for a Linux package installation](https://docs.gitlab.com/omnibus/settings/ssl/). For more details about SSL, see [Configure SSL for a Linux package installation](https://docs.gitlab.com/omnibus/settings/ssl/).
- With an Ultimate subscription that is synchronized with GitLab. (No trial access.) - With an Ultimate subscription that is synchronized with GitLab. (No trial access.)
- With the `amazon_q_integration` [feature flag enabled](../../administration/feature_flags.md).
- GitLab Duo features [must be turned on](../gitlab_duo/turn_on_off.md#turn-on-beta-and-experimental-features). - GitLab Duo features [must be turned on](../gitlab_duo/turn_on_off.md#turn-on-beta-and-experimental-features).
(Experimental and beta features are off by default.) (Experimental and beta features are off by default.)

View File

@ -23,7 +23,7 @@ GitLab plays the role of a MLflow server. Running `mlflow server` is not necessa
Prerequisites: Prerequisites:
- A [personal](../../../../user/profile/personal_access_tokens.md), [project](../../../../user/project/settings/project_access_tokens.md), or [group](../../../../user/group/settings/group_access_tokens.md) access token with at least the Developer role and the `api` permission. - A [personal](../../../../user/profile/personal_access_tokens.md), [project](../../../../user/project/settings/project_access_tokens.md), or [group](../../../../user/group/settings/group_access_tokens.md) access token with at least the Developer role and the `api` scope.
- The project ID. To find the project ID: - The project ID. To find the project ID:
1. On the left sidebar, select **Search or go to** and find your project. 1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > General**. 1. Select **Settings > General**.
@ -46,19 +46,19 @@ by selecting the vertical ellipsis (**{ellipsis_v}**).
## Model experiments ## Model experiments
When running the training code, MLflow client can be used to create experiments, runs, When running the training code, MLflow client can be used to create experiments, runs,
models, model versions, log parameters, metrics, metadata and artifacts on GitLab. models, model versions, log parameters, metrics, metadata, and artifacts on GitLab.
After experiments are logged, they are listed under `/<your project>/-/ml/experiments`. After experiments are logged, they are listed under `/<your project>/-/ml/experiments`.
Runs are registered as candidates, which can be explored by selecting an experiment, model, or model version. Runs are registered and can be explored by selecting an experiment, model, or model version.
### Associating a candidate to a CI/CD job ### Associating a run to a CI/CD job
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/119454) in GitLab 16.1. > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/119454) in GitLab 16.1.
> - [Changed](https://gitlab.com/groups/gitlab-org/-/epics/9423) to beta in GitLab 17.1. > - [Changed](https://gitlab.com/groups/gitlab-org/-/epics/9423) to beta in GitLab 17.1.
If your training code is being run from a CI/CD job, GitLab can use that information to enhance If your training code is being run from a CI/CD job, GitLab can use that information to enhance
candidate metadata. To associate a candidate to a CI/CD job: run metadata. To associate a run to a CI/CD job:
1. In the [Project CI variables](../../../../ci/variables/index.md), include the following variables: 1. In the [Project CI variables](../../../../ci/variables/index.md), include the following variables:
- `MLFLOW_TRACKING_URI`: `"<your gitlab endpoint>/api/v4/projects/<your project id>/ml/mlflow"` - `MLFLOW_TRACKING_URI`: `"<your gitlab endpoint>/api/v4/projects/<your project id>/ml/mlflow"`
@ -70,7 +70,7 @@ candidate metadata. To associate a candidate to a CI/CD job:
import os import os
import mlflow import mlflow
with mlflow.start_run(run_name=f"Candidate {index}"): with mlflow.start_run(run_name=f"Run {index}"):
# Your training code # Your training code
# Start of snippet to be included # Start of snippet to be included
@ -137,7 +137,7 @@ client.delete_registered_model(model_name)
### Logging candidates to a model ### Logging candidates to a model
Every model has an associated experiment with the same name prefixed by `[model]`. Every model has an associated experiment with the same name prefixed by `[model]`.
To log a candidate/run to the model, use the experiment passing the correct name: To log a run to the model, use the experiment passing the correct name:
```python ```python
from mlflow import MlflowClient from mlflow import MlflowClient
@ -177,7 +177,7 @@ client.create_model_version(model_name, version, description=description, tags=t
**Notes** **Notes**
- Argument `run_id` is ignored. Every model version behaves as a Candidate/Run. Creating a mode version from a run is not yet supported. - Argument `run_id` is ignored. Every model version behaves as a run. Creating a mode version from a run is not yet supported.
- Argument `source` is ignored. GitLab will create a package location for the model version files. - Argument `source` is ignored. GitLab will create a package location for the model version files.
- Argument `run_link` is ignored. - Argument `run_link` is ignored.
- Argument `await_creation_for` is ignored. - Argument `await_creation_for` is ignored.
@ -240,7 +240,7 @@ model = mlflow.pyfunc.load_model(f"models:/{model_name}/latest")
#### Logging metrics and parameters to a model version #### Logging metrics and parameters to a model version
Every model version is also a candidate/run, allowing users to log parameters Every model version is also a run, allowing users to log parameters
and metrics. The run ID can either be found at the Model version page in GitLab, and metrics. The run ID can either be found at the Model version page in GitLab,
or by using the MLflow client: or by using the MLflow client:
@ -285,7 +285,7 @@ Artifacts will then be available under `https/<your project>/-/ml/models/<model_
#### Linking a model version to a CI/CD job #### Linking a model version to a CI/CD job
Similar to candidates, it is also possible to link a model version to a CI/CD job: Similar to runs, it is also possible to link a model version to a CI/CD job:
```python ```python
import os import os
@ -318,7 +318,7 @@ of the methods below are also supported with the same caveats.
| `set_experiment` | Yes | 15.11 | | | `set_experiment` | Yes | 15.11 | |
| `get_run` | Yes | 15.11 | | | `get_run` | Yes | 15.11 | |
| `delete_run` | Yes | 17.5 | | | `delete_run` | Yes | 17.5 | |
| `start_run` | Yes | 15.11 | (16.3) If a name is not provided, the candidate receives a random nickname. | | `start_run` | Yes | 15.11 | (16.3) If a name is not provided, the run receives a random nickname. |
| `search_runs` | Yes | 15.11 | (16.4) `experiment_ids` supports only a single experiment ID with order by column or metric. | | `search_runs` | Yes | 15.11 | (16.4) `experiment_ids` supports only a single experiment ID with order by column or metric. |
| `log_artifact` | Yes with caveat | 15.11 | (15.11) `artifact_path` must be empty. Does not support directories. | | `log_artifact` | Yes with caveat | 15.11 | (15.11) `artifact_path` must be empty. Does not support directories. |
| `log_artifacts` | Yes with caveat | 15.11 | (15.11) `artifact_path` must be empty. Does not support directories. | | `log_artifacts` | Yes with caveat | 15.11 | (15.11) `artifact_path` must be empty. Does not support directories. |

View File

@ -65,7 +65,6 @@ module API
resource do resource do
before do before do
check_read_only_feature_flag_enabled!
authorize! :admin_secure_files, user_project authorize! :admin_secure_files, user_project
end end
@ -116,10 +115,6 @@ module API
def check_api_enabled! def check_api_enabled!
forbidden! unless Gitlab.config.ci_secure_files.enabled forbidden! unless Gitlab.config.ci_secure_files.enabled
end end
def check_read_only_feature_flag_enabled!
service_unavailable! if Feature.enabled?(:ci_secure_files_read_only, user_project, type: :ops)
end
end end
end end
end end

View File

@ -193,32 +193,7 @@ module API
'slack-slash-commands' => ::Integrations::SlackSlashCommands.api_arguments, 'slack-slash-commands' => ::Integrations::SlackSlashCommands.api_arguments,
'packagist' => ::Integrations::Packagist.api_arguments, 'packagist' => ::Integrations::Packagist.api_arguments,
'phorge' => ::Integrations::Phorge.api_arguments, 'phorge' => ::Integrations::Phorge.api_arguments,
'pipelines-email' => [ 'pipelines-email' => ::Integrations::PipelinesEmail.api_arguments,
{
required: true,
name: :recipients,
type: String,
desc: 'Comma-separated list of recipient email addresses'
},
{
required: false,
name: :notify_only_broken_pipelines,
type: ::Grape::API::Boolean,
desc: 'Notify only broken pipelines'
},
{
required: false,
name: :notify_only_default_branch,
type: ::Grape::API::Boolean,
desc: 'Send notifications only for the default branch'
},
{
required: false,
name: :branches_to_be_notified,
type: String,
desc: 'Branches for which notifications are to be sent'
}
],
'pivotaltracker' => ::Integrations::Pivotaltracker.api_arguments, 'pivotaltracker' => ::Integrations::Pivotaltracker.api_arguments,
'pumble' => ::Integrations::Pumble.api_arguments, 'pumble' => ::Integrations::Pumble.api_arguments,
'pushover' => ::Integrations::Pushover.api_arguments, 'pushover' => ::Integrations::Pushover.api_arguments,

View File

@ -14,6 +14,8 @@ module Gitlab
notifications: Gitlab::Agent::Notifications::Rpc::Notifications::Stub notifications: Gitlab::Agent::Notifications::Rpc::Notifications::Stub
}.freeze }.freeze
AUTOFLOW_CI_VARIABLE_ENV_SCOPE = 'autoflow/internal-use'
ConfigurationError = Class.new(StandardError) ConfigurationError = Class.new(StandardError)
def initialize def initialize
@ -72,6 +74,9 @@ module Gitlab
# We only want to send events if AutoFlow is enabled and no-op otherwise # We only want to send events if AutoFlow is enabled and no-op otherwise
return unless Feature.enabled?(:autoflow_enabled, project) return unless Feature.enabled?(:autoflow_enabled, project)
# retrieve all AutoFlow-relevant variables
variables = project.variables.by_environment_scope(AUTOFLOW_CI_VARIABLE_ENV_SCOPE)
project_proto = Gitlab::Agent::Event::Project.new( project_proto = Gitlab::Agent::Event::Project.new(
id: project.id, id: project.id,
full_path: project.full_path full_path: project.full_path
@ -89,7 +94,8 @@ module Gitlab
}, },
text_data: data.to_json text_data: data.to_json
), ),
flow_project: project_proto flow_project: project_proto,
variables: variables.to_h { |v| [v.key, v.value] }
) )
stub_for(:autoflow) stub_for(:autoflow)

View File

@ -80,7 +80,7 @@ module Gitlab
def get_repo_url(project_full_path) def get_repo_url(project_full_path)
return ssh_url(project_full_path) if Gitlab::CurrentSettings.enabled_git_access_protocol == 'ssh' return ssh_url(project_full_path) if Gitlab::CurrentSettings.enabled_git_access_protocol == 'ssh'
build_http_url(project_full_path) "#{http_url(project_full_path)}.git"
end end
# create_go_get_html_response creates a HTML document for go get with the expected meta tags. # create_go_get_html_response creates a HTML document for go get with the expected meta tags.
@ -100,11 +100,7 @@ module Gitlab
# get_root_path returns a root path based on the instance URL # get_root_path returns a root path based on the instance URL
# that includes a relative part of URL if it was set # that includes a relative part of URL if it was set
def get_root_path(project_full_path) def get_root_path(project_full_path)
if feature_flag_enabled? http_url(project_full_path).gsub(%r{\Ahttps?://}, '')
http_url(project_full_path).gsub(%r{\Ahttps?://}, '')
else
Gitlab::Utils.append_path(Gitlab.config.gitlab.host, project_full_path)
end
end end
# http_url returns a direct link to the project # http_url returns a direct link to the project
@ -112,19 +108,6 @@ module Gitlab
Gitlab::Utils.append_path(Gitlab.config.gitlab.url, project_full_path) Gitlab::Utils.append_path(Gitlab.config.gitlab.url, project_full_path)
end end
# build_http_url (temporary) constructs a http url
def build_http_url(project_full_path)
if feature_flag_enabled?
"#{http_url(project_full_path)}.git"
else
Gitlab::RepositoryUrlBuilder.build(project_full_path, protocol: :http)
end
end
def feature_flag_enabled?
Feature.enabled?(:go_get_handle_relative_url, Feature.current_request)
end
# project_for_path searches for a project based on the path_info # project_for_path searches for a project based on the path_info
def project_for_path(path_info) def project_for_path(path_info)
project_path_match = "#{path_info}/".match(PROJECT_PATH_REGEX) project_path_match = "#{path_info}/".match(PROJECT_PATH_REGEX)

View File

@ -109,7 +109,8 @@ module Gitlab
params 'path/to/project [--with_notes]' params 'path/to/project [--with_notes]'
types Issue types Issue
condition do condition do
quick_action_target.persisted? && quick_action_target.try(:supports_move_and_clone?) &&
quick_action_target.persisted? &&
current_user.can?(:"admin_#{quick_action_target.to_ability_name}", project) current_user.can?(:"admin_#{quick_action_target.to_ability_name}", project)
end end
command :clone do |params = ''| command :clone do |params = ''|
@ -144,7 +145,8 @@ module Gitlab
params 'path/to/project' params 'path/to/project'
types Issue types Issue
condition do condition do
quick_action_target.persisted? && quick_action_target.try(:supports_move_and_clone?) &&
quick_action_target.persisted? &&
current_user.can?(:"admin_#{quick_action_target.to_ability_name}", project) current_user.can?(:"admin_#{quick_action_target.to_ability_name}", project)
end end
command :move do |target_project_path| command :move do |target_project_path|

View File

@ -38,9 +38,11 @@ module Gitlab
issuable: target_type) issuable: target_type)
end end
attr_reader :target_type
private private
attr_reader :target_type, :container_type attr_reader :container_type
end end
end end
end end

View File

@ -29,5 +29,13 @@ module Search
def failed?(*) def failed?(*)
error.present? error.present?
end end
def blobs_count
0
end
def file_count
0
end
end end
end end

View File

@ -25,9 +25,8 @@ namespace :tw do
CodeOwnerRule.new('AI Framework', '@sselhorn'), CodeOwnerRule.new('AI Framework', '@sselhorn'),
# CodeOwnerRule.new('AI Model Validation', ''), # CodeOwnerRule.new('AI Model Validation', ''),
# CodeOwnerRule.new('Analytics Instrumentation', ''), # CodeOwnerRule.new('Analytics Instrumentation', ''),
# CodeOwnerRule.new('Anti-Abuse', ''),
CodeOwnerRule.new('Authentication', '@idurham'), CodeOwnerRule.new('Authentication', '@idurham'),
CodeOwnerRule.new('Authorization', '@rlehmann1'), CodeOwnerRule.new('Authorization', '@idurham'),
CodeOwnerRule.new('Cloud Connector', '@jglassman1'), CodeOwnerRule.new('Cloud Connector', '@jglassman1'),
CodeOwnerRule.new('Code Creation', '@jglassman1'), CodeOwnerRule.new('Code Creation', '@jglassman1'),
CodeOwnerRule.new('Code Review', '@aqualls'), CodeOwnerRule.new('Code Review', '@aqualls'),
@ -96,8 +95,8 @@ namespace :tw do
CodeOwnerRule.new('Analytics Instrumentation', CodeOwnerRule.new('Analytics Instrumentation',
'@gitlab-org/analytics-section/product-analytics/engineers/frontend ' \ '@gitlab-org/analytics-section/product-analytics/engineers/frontend ' \
'@gitlab-org/analytics-section/analytics-instrumentation/engineers'), '@gitlab-org/analytics-section/analytics-instrumentation/engineers'),
CodeOwnerRule.new('Authentication', '@gitlab-org/govern/authentication/approvers'), CodeOwnerRule.new('Authentication', '@gitlab-org/software-supply-chain-security/authentication/approvers'),
CodeOwnerRule.new('Authorization', '@gitlab-org/govern/authorization/approvers'), CodeOwnerRule.new('Authorization', '@gitlab-org/software-supply-chain-security/authorization/approvers'),
CodeOwnerRule.new('Compliance', CodeOwnerRule.new('Compliance',
'@gitlab-org/govern/security-policies-frontend @gitlab-org/govern/threat-insights-frontend-team ' \ '@gitlab-org/govern/security-policies-frontend @gitlab-org/govern/threat-insights-frontend-team ' \
'@gitlab-org/govern/threat-insights-backend-team'), '@gitlab-org/govern/threat-insights-backend-team'),

View File

@ -13926,7 +13926,7 @@ msgstr ""
msgid "Comma-separated list of branches to be automatically inspected. Leave blank to include all branches." msgid "Comma-separated list of branches to be automatically inspected. Leave blank to include all branches."
msgstr "" msgstr ""
msgid "Comma-separated list of email addresses." msgid "Comma-separated list of recipient email addresses."
msgstr "" msgstr ""
msgid "Command" msgid "Command"
@ -17857,18 +17857,30 @@ msgstr ""
msgid "DastProfiles|/graphql" msgid "DastProfiles|/graphql"
msgstr "" msgstr ""
msgid "DastProfiles|A URL that is compared to the URL in the browser to determine if authentication has succeeded after the login form is submitted."
msgstr ""
msgid "DastProfiles|A comma-separated list of actions to be run after login but before login verification. Currently supports `click` actions." msgid "DastProfiles|A comma-separated list of actions to be run after login but before login verification. Currently supports `click` actions."
msgstr "" msgstr ""
msgid "DastProfiles|A comma-separated list of selectors representing elements to click on prior to entering the DAST_AUTH_USERNAME and DAST_AUTH_PASSWORD into the login form." msgid "DastProfiles|A comma-separated list of selectors representing elements to click on prior to entering the DAST_AUTH_USERNAME and DAST_AUTH_PASSWORD into the login form."
msgstr "" msgstr ""
msgid "DastProfiles|A cookie name and value to be added to every request."
msgstr ""
msgid "DastProfiles|A passive scan monitors all HTTP messages (requests and responses) sent to the target. An active scan attacks the target to find potential vulnerabilities." msgid "DastProfiles|A passive scan monitors all HTTP messages (requests and responses) sent to the target. An active scan attacks the target to find potential vulnerabilities."
msgstr "" msgstr ""
msgid "DastProfiles|A scanner profile defines the configuration details of a security scanner. %{linkStart}Learn more%{linkEnd}." msgid "DastProfiles|A scanner profile defines the configuration details of a security scanner. %{linkStart}Learn more%{linkEnd}."
msgstr "" msgstr ""
msgid "DastProfiles|A selector describing an element whose presence is used to determine if authentication has succeeded after the login form is submitted."
msgstr ""
msgid "DastProfiles|A selector describing the element that is clicked on to submit the username form of a multi-page login process."
msgstr ""
msgid "DastProfiles|A site profile defines the attributes and configuration details of your deployed application, website, or API. %{linkStart}Learn more%{linkEnd}." msgid "DastProfiles|A site profile defines the attributes and configuration details of your deployed application, website, or API. %{linkStart}Learn more%{linkEnd}."
msgstr "" msgstr ""
@ -17899,9 +17911,15 @@ msgstr ""
msgid "DastProfiles|Additional variables" msgid "DastProfiles|Additional variables"
msgstr "" msgstr ""
msgid "DastProfiles|Advertise scan"
msgstr ""
msgid "DastProfiles|After-login actions" msgid "DastProfiles|After-login actions"
msgstr "" msgstr ""
msgid "DastProfiles|Allowed hosts"
msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?" msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr "" msgstr ""
@ -17914,6 +17932,12 @@ msgstr ""
msgid "DastProfiles|Authentication URL" msgid "DastProfiles|Authentication URL"
msgstr "" msgstr ""
msgid "DastProfiles|Authentication delegation servers"
msgstr ""
msgid "DastProfiles|Authentication type"
msgstr ""
msgid "DastProfiles|Before-login actions" msgid "DastProfiles|Before-login actions"
msgstr "" msgstr ""
@ -17929,7 +17953,10 @@ msgstr ""
msgid "DastProfiles|Clear input fields" msgid "DastProfiles|Clear input fields"
msgstr "" msgstr ""
msgid "DastProfiles|Comma-separated list of check identifiers to use for the scan. For identifiers, see %{linkStart}vulnerability checks.%{linkEnd}" msgid "DastProfiles|Comma-separated list of selectors that are ignored when scanning."
msgstr ""
msgid "DastProfiles|Cookie names"
msgstr "" msgstr ""
msgid "DastProfiles|Could not create the scanner profile. Please try again." msgid "DastProfiles|Could not create the scanner profile. Please try again."
@ -17968,9 +17995,18 @@ msgstr ""
msgid "DastProfiles|DAST profile library" msgid "DastProfiles|DAST profile library"
msgstr "" msgstr ""
msgid "DastProfiles|DOM ready timeout"
msgstr ""
msgid "DastProfiles|DOM stable timeout"
msgstr ""
msgid "DastProfiles|Debug messages" msgid "DastProfiles|Debug messages"
msgstr "" msgstr ""
msgid "DastProfiles|Define how long to wait for updates to the DOM before checking a page is stable. Defaults to `500ms`."
msgstr ""
msgid "DastProfiles|Delete" msgid "DastProfiles|Delete"
msgstr "" msgstr ""
@ -17992,12 +18028,21 @@ msgstr ""
msgid "DastProfiles|Edit site profile" msgid "DastProfiles|Edit site profile"
msgstr "" msgstr ""
msgid "DastProfiles|Element search timeout"
msgstr ""
msgid "DastProfiles|Enable Authentication" msgid "DastProfiles|Enable Authentication"
msgstr "" msgstr ""
msgid "DastProfiles|Enable Basic Authentication" msgid "DastProfiles|Enable Basic Authentication"
msgstr "" msgstr ""
msgid "DastProfiles|Ensures that the provided paths are always scanned. Set to a comma-separated list of URL paths relative to `DAST_TARGET_URL`."
msgstr ""
msgid "DastProfiles|Ensures that the provided paths are always scanned. Set to a file path containing a list of URL paths relative to `DAST_TARGET_URL`. The file must be plain text with one path per line."
msgstr ""
msgid "DastProfiles|Enter URLs in a comma-separated list." msgid "DastProfiles|Enter URLs in a comma-separated list."
msgstr "" msgstr ""
@ -18013,7 +18058,10 @@ msgstr ""
msgid "DastProfiles|Excluded URLs (optional)" msgid "DastProfiles|Excluded URLs (optional)"
msgstr "" msgstr ""
msgid "DastProfiles|Excluded checks" msgid "DastProfiles|Excluded elements"
msgstr ""
msgid "DastProfiles|Excluded hosts"
msgstr "" msgstr ""
msgid "DastProfiles|Excluded paths" msgid "DastProfiles|Excluded paths"
@ -18022,21 +18070,51 @@ msgstr ""
msgid "DastProfiles|Excluded paths (optional)" msgid "DastProfiles|Excluded paths (optional)"
msgstr "" msgstr ""
msgid "DastProfiles|Extract element timeout"
msgstr ""
msgid "DastProfiles|Field must not be blank" msgid "DastProfiles|Field must not be blank"
msgstr "" msgstr ""
msgid "DastProfiles|First submit field"
msgstr ""
msgid "DastProfiles|Hide debug messages" msgid "DastProfiles|Hide debug messages"
msgstr "" msgstr ""
msgid "DastProfiles|Hostnames included in this variable are accessed, not attacked, and not reported against."
msgstr ""
msgid "DastProfiles|Hostnames included in this variable are considered excluded and connections are forcibly dropped."
msgstr ""
msgid "DastProfiles|Hostnames included in this variable are considered in scope when crawled. By default the `DAST_TARGET_URL` hostname is included in the allowed hosts list. Headers set using `DAST_REQUEST_HEADERS` are added to every request made to these hostnames."
msgstr ""
msgid "DastProfiles|Ignored hosts"
msgstr ""
msgid "DastProfiles|Include debug messages in the DAST console output." msgid "DastProfiles|Include debug messages in the DAST console output."
msgstr "" msgstr ""
msgid "DastProfiles|Loading element"
msgstr ""
msgid "DastProfiles|Manage %{profileType} profiles" msgid "DastProfiles|Manage %{profileType} profiles"
msgstr "" msgstr ""
msgid "DastProfiles|Manage profiles" msgid "DastProfiles|Manage profiles"
msgstr "" msgstr ""
msgid "DastProfiles|Maximum action count"
msgstr ""
msgid "DastProfiles|Maximum action depth"
msgstr ""
msgid "DastProfiles|Maximum response size (MB)"
msgstr ""
msgid "DastProfiles|Minimum = 0 (no timeout enabled), Maximum = 2880 minutes" msgid "DastProfiles|Minimum = 0 (no timeout enabled), Maximum = 2880 minutes"
msgstr "" msgstr ""
@ -18076,9 +18154,30 @@ msgstr ""
msgid "DastProfiles|Not Validated" msgid "DastProfiles|Not Validated"
msgstr "" msgstr ""
msgid "DastProfiles|Number of workers that passive scan in parallel. Defaults to the number of available CPUs."
msgstr ""
msgid "DastProfiles|PKCS12 certificate"
msgstr ""
msgid "DastProfiles|PKCS12 password"
msgstr ""
msgid "DastProfiles|Page ready timeout"
msgstr ""
msgid "DastProfiles|Page ready timeout (after action)"
msgstr ""
msgid "DastProfiles|Page ready timeout (after navigation)"
msgstr ""
msgid "DastProfiles|Passive" msgid "DastProfiles|Passive"
msgstr "" msgstr ""
msgid "DastProfiles|Passive scan worker count"
msgstr ""
msgid "DastProfiles|Password" msgid "DastProfiles|Password"
msgstr "" msgstr ""
@ -18094,6 +18193,12 @@ msgstr ""
msgid "DastProfiles|Profile name" msgid "DastProfiles|Profile name"
msgstr "" msgstr ""
msgid "DastProfiles|Ready element"
msgstr ""
msgid "DastProfiles|Request cookies"
msgstr ""
msgid "DastProfiles|Request headers" msgid "DastProfiles|Request headers"
msgstr "" msgstr ""
@ -18145,6 +18250,24 @@ msgstr ""
msgid "DastProfiles|Select site profile" msgid "DastProfiles|Select site profile"
msgstr "" msgstr ""
msgid "DastProfiles|Selector that when detected as visible on the page, indicates to the analyzer that the page has finished loading and the scan can continue. Cannot be used with `DAST_PAGE_IS_LOADING_ELEMENT`."
msgstr ""
msgid "DastProfiles|Selector that, when no longer visible on the page, indicates to the analyzer that the page has finished loading and the scan can continue. Cannot be used with `DAST_PAGE_IS_READY_ELEMENT`."
msgstr ""
msgid "DastProfiles|Set to `false` to disable caching. Default: `true`. **Note:** Disabling cache can cause OOM events or DAST job timeouts."
msgstr ""
msgid "DastProfiles|Set to `true` to add a `Via` header to every request sent, advertising that the request was sent as part of a GitLab DAST scan. Default: `false`."
msgstr ""
msgid "DastProfiles|Set to `true` to prevent DAST from checking that the target is available before scanning. Default: `false`."
msgstr ""
msgid "DastProfiles|Set to a comma-separated list of cookie names to specify which cookies are used for authentication."
msgstr ""
msgid "DastProfiles|Show debug messages" msgid "DastProfiles|Show debug messages"
msgstr "" msgstr ""
@ -18160,30 +18283,93 @@ msgstr ""
msgid "DastProfiles|Site type" msgid "DastProfiles|Site type"
msgstr "" msgstr ""
msgid "DastProfiles|Skip target check"
msgstr ""
msgid "DastProfiles|Submit button" msgid "DastProfiles|Submit button"
msgstr "" msgstr ""
msgid "DastProfiles|Submit button (optional)" msgid "DastProfiles|Submit button (optional)"
msgstr "" msgstr ""
msgid "DastProfiles|Success URL"
msgstr ""
msgid "DastProfiles|Success element"
msgstr ""
msgid "DastProfiles|Success without login form"
msgstr ""
msgid "DastProfiles|Target URL" msgid "DastProfiles|Target URL"
msgstr "" msgstr ""
msgid "DastProfiles|Target check timeout"
msgstr ""
msgid "DastProfiles|Target paths"
msgstr ""
msgid "DastProfiles|Target paths file"
msgstr ""
msgid "DastProfiles|Target timeout" msgid "DastProfiles|Target timeout"
msgstr "" msgstr ""
msgid "DastProfiles|The PKCS12 certificate used for sites that require Mutual TLS. Must be encoded as base64 text."
msgstr ""
msgid "DastProfiles|The authentication type to use."
msgstr ""
msgid "DastProfiles|The maximum amount of time to allow the browser to extract newly found elements or navigations. Defaults to `5s`."
msgstr ""
msgid "DastProfiles|The maximum amount of time to allow the browser to search for new elements or user actions. Defaults to `3s`."
msgstr ""
msgid "DastProfiles|The maximum amount of time to wait for a browser to consider a page loaded and ready for analysis after a navigation completes. Defaults to `6s`."
msgstr ""
msgid "DastProfiles|The maximum amount of time to wait for a browser to consider a page loaded and ready for analysis. Defaults to `7s`."
msgstr ""
msgid "DastProfiles|The maximum amount of time to wait for a browser to navigate from one page to another. Defaults to `15s`."
msgstr ""
msgid "DastProfiles|The maximum amount of time to wait for an element before determining it is ready for analysis. Defaults to `300ms`."
msgstr ""
msgid "DastProfiles|The maximum amount of time to wait for the active scan phase of the scan to complete. Defaults to 3h." msgid "DastProfiles|The maximum amount of time to wait for the active scan phase of the scan to complete. Defaults to 3h."
msgstr "" msgstr ""
msgid "DastProfiles|The maximum amount of time to wait for the crawl phase of the scan to complete. Defaults to `24h`."
msgstr ""
msgid "DastProfiles|The maximum number of actions that the crawler performs. Example actions include selecting a link, or filling out a form. Defaults to `10000`."
msgstr ""
msgid "DastProfiles|The maximum number of chained actions that the crawler takes. For example, `Click, Form Fill, Click` is a depth of three. Defaults to `10`."
msgstr ""
msgid "DastProfiles|The maximum number of concurrent browser instances to use. For instance runners on GitLab.com, we recommended a maximum of three. Private runners with more resources may benefit from a higher number, but are likely to produce little benefit after five to seven instances. The default value is dynamic, equal to the number of usable logical CPUs."
msgstr ""
msgid "DastProfiles|The maximum number of minutes allowed for the crawler to traverse the site." msgid "DastProfiles|The maximum number of minutes allowed for the crawler to traverse the site."
msgstr "" msgstr ""
msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request." msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr "" msgstr ""
msgid "DastProfiles|The maximum size of a HTTP response body. Responses with bodies larger than this are blocked by the browser. Defaults to `10` MB."
msgstr ""
msgid "DastProfiles|The number of active checks to run in parallel. Defaults to 3." msgid "DastProfiles|The number of active checks to run in parallel. Defaults to 3."
msgstr "" msgstr ""
msgid "DastProfiles|The password of the certificate used in `DAST_PKCS12_CERTIFICATE_BASE64`. Create sensitive %{linkStart}custom CI/CI variables%{linkEnd} using the GitLab UI."
msgstr ""
msgid "DastProfiles|This profile is currently being used in a policy." msgid "DastProfiles|This profile is currently being used in a policy."
msgstr "" msgstr ""
@ -18193,6 +18379,12 @@ msgstr ""
msgid "DastProfiles|This site profile is currently being used by a policy. To make edits you must remove it from the active policy." msgid "DastProfiles|This site profile is currently being used by a policy. To make edits you must remove it from the active policy."
msgstr "" msgstr ""
msgid "DastProfiles|Time limit in seconds to wait for target availability. Default: `60s`."
msgstr ""
msgid "DastProfiles|Timeout"
msgstr ""
msgid "DastProfiles|URL" msgid "DastProfiles|URL"
msgstr "" msgstr ""
@ -18202,6 +18394,9 @@ msgstr ""
msgid "DastProfiles|Update variable" msgid "DastProfiles|Update variable"
msgstr "" msgstr ""
msgid "DastProfiles|Use cache"
msgstr ""
msgid "DastProfiles|Username" msgid "DastProfiles|Username"
msgstr "" msgstr ""
@ -18226,12 +18421,21 @@ msgstr ""
msgid "DastProfiles|Variable" msgid "DastProfiles|Variable"
msgstr "" msgstr ""
msgid "DastProfiles|Verifies successful authentication by checking for the absence of a login form after the login form has been submitted. This success check is enabled by default."
msgstr ""
msgid "DastProfiles|Website" msgid "DastProfiles|Website"
msgstr "" msgstr ""
msgid "DastProfiles|What does each method do?" msgid "DastProfiles|What does each method do?"
msgstr "" msgstr ""
msgid "DastProfiles|Which servers should be allowed for integrated authentication and delegation."
msgstr ""
msgid "DastProfiles|Worker count"
msgstr ""
msgid "DastProfiles|You can either choose a passive scan or validate the target site from the site profile management page. %{docsLinkStart}Learn more about site validation.%{docsLinkEnd}" msgid "DastProfiles|You can either choose a passive scan or validate the target site from the site profile management page. %{docsLinkStart}Learn more about site validation.%{docsLinkEnd}"
msgstr "" msgstr ""
@ -20355,6 +20559,9 @@ msgstr ""
msgid "Disable What's new" msgid "Disable What's new"
msgstr "" msgstr ""
msgid "Disable fetching cloud alerts if this GitLab instance is isolated from the public internet, or does not use observe.gitlab.com for Observability features."
msgstr ""
msgid "Disable for this project" msgid "Disable for this project"
msgstr "" msgstr ""
@ -24034,6 +24241,9 @@ msgstr ""
msgid "Fetch and check out this merge request's feature branch:" msgid "Fetch and check out this merge request's feature branch:"
msgstr "" msgstr ""
msgid "Fetch cloud observability alerts"
msgstr ""
msgid "Fetching incoming email" msgid "Fetching incoming email"
msgstr "" msgstr ""
@ -52459,6 +52669,9 @@ msgstr ""
msgid "Send notifications for broken pipelines." msgid "Send notifications for broken pipelines."
msgstr "" msgstr ""
msgid "Send notifications for the default branch."
msgstr ""
msgid "Send report" msgid "Send report"
msgstr "" msgstr ""
@ -61517,6 +61730,9 @@ msgstr ""
msgid "UserMapping|Source name" msgid "UserMapping|Source name"
msgstr "" msgstr ""
msgid "UserMapping|The file is being processed and you will receive an email when completed."
msgstr ""
msgid "UserMapping|The invitation could not be accepted." msgid "UserMapping|The invitation could not be accepted."
msgstr "" msgstr ""
@ -61547,6 +61763,9 @@ msgstr ""
msgid "UserMapping|You might have already accepted or rejected the reassignment, or the assignment might have been canceled." msgid "UserMapping|You might have already accepted or rejected the reassignment, or the assignment might have been canceled."
msgstr "" msgstr ""
msgid "UserMapping|You must upload a CSV file with a .csv file extension."
msgstr ""
msgid "UserProfile|%{count} %{file}" msgid "UserProfile|%{count} %{file}"
msgstr "" msgstr ""
@ -66407,7 +66626,7 @@ msgstr ""
msgid "cannot assign a linked work item as a parent" msgid "cannot assign a linked work item as a parent"
msgstr "" msgstr ""
msgid "cannot assign a non-confidential work item to a confidential parent. Make the work item confidential and try again." msgid "cannot assign a non-confidential %{work_item_type} to a confidential parent. Make the %{work_item_type} confidential and try again."
msgstr "" msgstr ""
msgid "cannot be a date in the past" msgid "cannot be a date in the past"

View File

@ -118,7 +118,7 @@
"apollo-upload-client": "15.0.0", "apollo-upload-client": "15.0.0",
"apollo3-cache-persist": "^0.14.1", "apollo3-cache-persist": "^0.14.1",
"autoprefixer": "^10.4.8", "autoprefixer": "^10.4.8",
"autosize": "^5.0.1", "autosize": "^6.0.1",
"axios": "^0.24.0", "axios": "^0.24.0",
"babel-loader": "^8.4.1", "babel-loader": "^8.4.1",
"babel-plugin-lodash": "^3.3.4", "babel-plugin-lodash": "^3.3.4",
@ -129,7 +129,7 @@
"colord": "^2.9.3", "colord": "^2.9.3",
"compression-webpack-plugin": "^5.0.2", "compression-webpack-plugin": "^5.0.2",
"copy-webpack-plugin": "^6.4.1", "copy-webpack-plugin": "^6.4.1",
"core-js": "^3.39.0", "core-js": "^3.40.0",
"cron-validator": "^1.1.1", "cron-validator": "^1.1.1",
"cronstrue": "^1.122.0", "cronstrue": "^1.122.0",
"cropperjs": "^1.6.1", "cropperjs": "^1.6.1",

View File

@ -0,0 +1,38 @@
diff --git a/node_modules/autosize/dist/autosize.esm.js b/node_modules/autosize/dist/autosize.esm.js
index 224b143..b95fb84 100644
--- a/node_modules/autosize/dist/autosize.esm.js
+++ b/node_modules/autosize/dist/autosize.esm.js
@@ -1 +1 @@
-var e=new Map;function t(t){var o=e.get(t);o&&o.destroy()}function o(t){var o=e.get(t);o&&o.update()}var r=null;"undefined"==typeof window?((r=function(e){return e}).destroy=function(e){return e},r.update=function(e){return e}):((r=function(t,o){return t&&Array.prototype.forEach.call(t.length?t:[t],function(t){return function(t){if(t&&t.nodeName&&"TEXTAREA"===t.nodeName&&!e.has(t)){var o,r=null,n=window.getComputedStyle(t),i=(o=t.value,function(){a({testForHeightReduction:""===o||!t.value.startsWith(o),restoreTextAlign:null}),o=t.value}),l=function(o){t.removeEventListener("autosize:destroy",l),t.removeEventListener("autosize:update",s),t.removeEventListener("input",i),window.removeEventListener("resize",s),Object.keys(o).forEach(function(e){return t.style[e]=o[e]}),e.delete(t)}.bind(t,{height:t.style.height,resize:t.style.resize,textAlign:t.style.textAlign,overflowY:t.style.overflowY,overflowX:t.style.overflowX,wordWrap:t.style.wordWrap});t.addEventListener("autosize:destroy",l),t.addEventListener("autosize:update",s),t.addEventListener("input",i),window.addEventListener("resize",s),t.style.overflowX="hidden",t.style.wordWrap="break-word",e.set(t,{destroy:l,update:s}),s()}function a(e){var o,i,l=e.restoreTextAlign,s=void 0===l?null:l,d=e.testForHeightReduction,u=void 0===d||d,c=n.overflowY;if(0!==t.scrollHeight&&("vertical"===n.resize?t.style.resize="none":"both"===n.resize&&(t.style.resize="horizontal"),u&&(o=function(e){for(var t=[];e&&e.parentNode&&e.parentNode instanceof Element;)e.parentNode.scrollTop&&t.push([e.parentNode,e.parentNode.scrollTop]),e=e.parentNode;return function(){return t.forEach(function(e){var t=e[0],o=e[1];t.style.scrollBehavior="auto",t.scrollTop=o,t.style.scrollBehavior=null})}}(t),t.style.height=""),i="content-box"===n.boxSizing?t.scrollHeight-(parseFloat(n.paddingTop)+parseFloat(n.paddingBottom)):t.scrollHeight+parseFloat(n.borderTopWidth)+parseFloat(n.borderBottomWidth),"none"!==n.maxHeight&&i>parseFloat(n.maxHeight)?("hidden"===n.overflowY&&(t.style.overflow="scroll"),i=parseFloat(n.maxHeight)):"hidden"!==n.overflowY&&(t.style.overflow="hidden"),t.style.height=i+"px",s&&(t.style.textAlign=s),o&&o(),r!==i&&(t.dispatchEvent(new Event("autosize:resized",{bubbles:!0})),r=i),c!==n.overflow&&!s)){var v=n.textAlign;"hidden"===n.overflow&&(t.style.textAlign="start"===v?"end":"start"),a({restoreTextAlign:v,testForHeightReduction:!0})}}function s(){a({testForHeightReduction:!0,restoreTextAlign:null})}}(t)}),t}).destroy=function(e){return e&&Array.prototype.forEach.call(e.length?e:[e],t),e},r.update=function(e){return e&&Array.prototype.forEach.call(e.length?e:[e],o),e});var n=r;export default n;
+var e=new Map;function t(t){var o=e.get(t);o&&o.destroy()}function o(t){var o=e.get(t);o&&o.update()}var r=null;"undefined"==typeof window?((r=function(e){return e}).destroy=function(e){return e},r.update=function(e){return e}):((r=function(t,o){return t&&Array.prototype.forEach.call(t.length?t:[t],function(t){return function(t){if(t&&t.nodeName&&"TEXTAREA"===t.nodeName&&!e.has(t)){var o,r=null,n=window.getComputedStyle(t),i=(o=t.value,function(){s({testForHeightReduction:""===o||!t.value.startsWith(o),restoreTextAlign:null}),o=t.value}),l=function(o){t.removeEventListener("autosize:destroy",l),t.removeEventListener("autosize:update",a),t.removeEventListener("input",i),window.removeEventListener("resize",a),Object.keys(o).forEach(function(e){return t.style[e]=o[e]}),e.delete(t)}.bind(t,{height:t.style.height,resize:t.style.resize,textAlign:t.style.textAlign,overflowY:t.style.overflowY,overflowX:t.style.overflowX,wordWrap:t.style.wordWrap});t.addEventListener("autosize:destroy",l),t.addEventListener("autosize:update",a),t.addEventListener("input",i),window.addEventListener("resize",a),t.style.overflowX="hidden",t.style.wordWrap="break-word",e.set(t,{destroy:l,update:a}),a()}function s(e){var o,i,l=e.restoreTextAlign,a=void 0===l?null:l,d=e.testForHeightReduction,u=void 0===d||d,c=n.overflowY;if(0!==t.scrollHeight&&("vertical"===n.resize?t.style.resize="none":"both"===n.resize&&(t.style.resize="horizontal"),u&&(o=function(e){for(var t=[];e&&e.parentNode&&e.parentNode instanceof Element;)e.parentNode.scrollTop&&t.push([e.parentNode,e.parentNode.scrollTop]),e=e.parentNode;return function(){return t.forEach(function(e){var t=e[0],o=e[1];t.scrollTop!==o&&(t.style.scrollBehavior="auto",t.scrollTop=o,t.style.scrollBehavior=null)})}}(t),t.style.height=""),i="content-box"===n.boxSizing?t.scrollHeight-(parseFloat(n.paddingTop)+parseFloat(n.paddingBottom)):t.scrollHeight+parseFloat(n.borderTopWidth)+parseFloat(n.borderBottomWidth),"none"!==n.maxHeight&&i>parseFloat(n.maxHeight)?("hidden"===n.overflowY&&(t.style.overflow="scroll"),i=parseFloat(n.maxHeight)):"hidden"!==n.overflowY&&(t.style.overflow="hidden"),t.style.height=i+"px",a&&(t.style.textAlign=a),o&&o(),r!==i&&(t.dispatchEvent(new Event("autosize:resized",{bubbles:!0})),r=i),c!==n.overflow&&!a)){var p=n.textAlign;"hidden"===n.overflow&&(t.style.textAlign="start"===p?"end":"start"),s({restoreTextAlign:p,testForHeightReduction:!0})}}function a(){s({testForHeightReduction:!0,restoreTextAlign:null})}}(t)}),t}).destroy=function(e){return e&&Array.prototype.forEach.call(e.length?e:[e],t),e},r.update=function(e){return e&&Array.prototype.forEach.call(e.length?e:[e],o),e});var n=r;export default n;
diff --git a/node_modules/autosize/dist/autosize.js b/node_modules/autosize/dist/autosize.js
index e227c1a..4be6b3e 100644
--- a/node_modules/autosize/dist/autosize.js
+++ b/node_modules/autosize/dist/autosize.js
@@ -24,6 +24,7 @@
return arr.forEach(function (_ref) {
var node = _ref[0],
scrollTop = _ref[1];
+ if (node.scrollTop === scrollTop) return;
node.style.scrollBehavior = 'auto';
node.scrollTop = scrollTop;
node.style.scrollBehavior = null;
diff --git a/node_modules/autosize/dist/autosize.min.js b/node_modules/autosize/dist/autosize.min.js
index 1b24155..ccb470d 100644
--- a/node_modules/autosize/dist/autosize.min.js
+++ b/node_modules/autosize/dist/autosize.min.js
@@ -1 +1 @@
-!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e||self).autosize=t()}(this,function(){var e=new Map;function t(t){var o=e.get(t);o&&o.destroy()}function o(t){var o=e.get(t);o&&o.update()}var r=null;return"undefined"==typeof window?((r=function(e){return e}).destroy=function(e){return e},r.update=function(e){return e}):((r=function(t,o){return t&&Array.prototype.forEach.call(t.length?t:[t],function(t){return function(t){if(t&&t.nodeName&&"TEXTAREA"===t.nodeName&&!e.has(t)){var o,r=null,n=window.getComputedStyle(t),i=(o=t.value,function(){s({testForHeightReduction:""===o||!t.value.startsWith(o),restoreTextAlign:null}),o=t.value}),l=function(o){t.removeEventListener("autosize:destroy",l),t.removeEventListener("autosize:update",a),t.removeEventListener("input",i),window.removeEventListener("resize",a),Object.keys(o).forEach(function(e){return t.style[e]=o[e]}),e.delete(t)}.bind(t,{height:t.style.height,resize:t.style.resize,textAlign:t.style.textAlign,overflowY:t.style.overflowY,overflowX:t.style.overflowX,wordWrap:t.style.wordWrap});t.addEventListener("autosize:destroy",l),t.addEventListener("autosize:update",a),t.addEventListener("input",i),window.addEventListener("resize",a),t.style.overflowX="hidden",t.style.wordWrap="break-word",e.set(t,{destroy:l,update:a}),a()}function s(e){var o,i,l=e.restoreTextAlign,a=void 0===l?null:l,d=e.testForHeightReduction,u=void 0===d||d,f=n.overflowY;if(0!==t.scrollHeight&&("vertical"===n.resize?t.style.resize="none":"both"===n.resize&&(t.style.resize="horizontal"),u&&(o=function(e){for(var t=[];e&&e.parentNode&&e.parentNode instanceof Element;)e.parentNode.scrollTop&&t.push([e.parentNode,e.parentNode.scrollTop]),e=e.parentNode;return function(){return t.forEach(function(e){var t=e[0],o=e[1];t.style.scrollBehavior="auto",t.scrollTop=o,t.style.scrollBehavior=null})}}(t),t.style.height=""),i="content-box"===n.boxSizing?t.scrollHeight-(parseFloat(n.paddingTop)+parseFloat(n.paddingBottom)):t.scrollHeight+parseFloat(n.borderTopWidth)+parseFloat(n.borderBottomWidth),"none"!==n.maxHeight&&i>parseFloat(n.maxHeight)?("hidden"===n.overflowY&&(t.style.overflow="scroll"),i=parseFloat(n.maxHeight)):"hidden"!==n.overflowY&&(t.style.overflow="hidden"),t.style.height=i+"px",a&&(t.style.textAlign=a),o&&o(),r!==i&&(t.dispatchEvent(new Event("autosize:resized",{bubbles:!0})),r=i),f!==n.overflow&&!a)){var c=n.textAlign;"hidden"===n.overflow&&(t.style.textAlign="start"===c?"end":"start"),s({restoreTextAlign:c,testForHeightReduction:!0})}}function a(){s({testForHeightReduction:!0,restoreTextAlign:null})}}(t)}),t}).destroy=function(e){return e&&Array.prototype.forEach.call(e.length?e:[e],t),e},r.update=function(e){return e&&Array.prototype.forEach.call(e.length?e:[e],o),e}),r});
+!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e||self).autosize=t()}(this,function(){var e=new Map;function t(t){var o=e.get(t);o&&o.destroy()}function o(t){var o=e.get(t);o&&o.update()}var r=null;return"undefined"==typeof window?((r=function(e){return e}).destroy=function(e){return e},r.update=function(e){return e}):((r=function(t,o){return t&&Array.prototype.forEach.call(t.length?t:[t],function(t){return function(t){if(t&&t.nodeName&&"TEXTAREA"===t.nodeName&&!e.has(t)){var o,r=null,n=window.getComputedStyle(t),i=(o=t.value,function(){s({testForHeightReduction:""===o||!t.value.startsWith(o),restoreTextAlign:null}),o=t.value}),l=function(o){t.removeEventListener("autosize:destroy",l),t.removeEventListener("autosize:update",a),t.removeEventListener("input",i),window.removeEventListener("resize",a),Object.keys(o).forEach(function(e){return t.style[e]=o[e]}),e.delete(t)}.bind(t,{height:t.style.height,resize:t.style.resize,textAlign:t.style.textAlign,overflowY:t.style.overflowY,overflowX:t.style.overflowX,wordWrap:t.style.wordWrap});t.addEventListener("autosize:destroy",l),t.addEventListener("autosize:update",a),t.addEventListener("input",i),window.addEventListener("resize",a),t.style.overflowX="hidden",t.style.wordWrap="break-word",e.set(t,{destroy:l,update:a}),a()}function s(e){var o,i,l=e.restoreTextAlign,a=void 0===l?null:l,d=e.testForHeightReduction,u=void 0===d||d,f=n.overflowY;if(0!==t.scrollHeight&&("vertical"===n.resize?t.style.resize="none":"both"===n.resize&&(t.style.resize="horizontal"),u&&(o=function(e){for(var t=[];e&&e.parentNode&&e.parentNode instanceof Element;)e.parentNode.scrollTop&&t.push([e.parentNode,e.parentNode.scrollTop]),e=e.parentNode;return function(){return t.forEach(function(e){var t=e[0],o=e[1];t.scrollTop!==o&&(t.style.scrollBehavior="auto",t.scrollTop=o,t.style.scrollBehavior=null)})}}(t),t.style.height=""),i="content-box"===n.boxSizing?t.scrollHeight-(parseFloat(n.paddingTop)+parseFloat(n.paddingBottom)):t.scrollHeight+parseFloat(n.borderTopWidth)+parseFloat(n.borderBottomWidth),"none"!==n.maxHeight&&i>parseFloat(n.maxHeight)?("hidden"===n.overflowY&&(t.style.overflow="scroll"),i=parseFloat(n.maxHeight)):"hidden"!==n.overflowY&&(t.style.overflow="hidden"),t.style.height=i+"px",a&&(t.style.textAlign=a),o&&o(),r!==i&&(t.dispatchEvent(new Event("autosize:resized",{bubbles:!0})),r=i),f!==n.overflow&&!a)){var c=n.textAlign;"hidden"===n.overflow&&(t.style.textAlign="start"===c?"end":"start"),s({restoreTextAlign:c,testForHeightReduction:!0})}}function a(){s({testForHeightReduction:!0,restoreTextAlign:null})}}(t)}),t}).destroy=function(e){return e&&Array.prototype.forEach.call(e.length?e:[e],t),e},r.update=function(e){return e&&Array.prototype.forEach.call(e.length?e:[e],o),e}),r});
diff --git a/node_modules/autosize/src/autosize.js b/node_modules/autosize/src/autosize.js
index c3f1a13..02a627a 100644
--- a/node_modules/autosize/src/autosize.js
+++ b/node_modules/autosize/src/autosize.js
@@ -16,6 +16,7 @@ function assign(ta) {
}
return ()=> arr.forEach(([node, scrollTop]) => {
+ if (node.scrollTop === scrollTop) return;
node.style.scrollBehavior = 'auto';
node.scrollTop = scrollTop;
node.style.scrollBehavior = null;

View File

@ -45,7 +45,6 @@ ee/spec/frontend/geo_sites/components/details/secondary_site/geo_site_replicatio
ee/spec/frontend/geo_sites/index_spec.js ee/spec/frontend/geo_sites/index_spec.js
ee/spec/frontend/groups/components/invite_members_spec.js ee/spec/frontend/groups/components/invite_members_spec.js
ee/spec/frontend/groups/settings/components/comma_separated_list_token_selector_spec.js ee/spec/frontend/groups/settings/components/comma_separated_list_token_selector_spec.js
ee/spec/frontend/insights/insights_router_spec.js
ee/spec/frontend/issues_analytics/components/issues_analytics_table_spec.js ee/spec/frontend/issues_analytics/components/issues_analytics_table_spec.js
ee/spec/frontend/iterations/components/iteration_form_spec.js ee/spec/frontend/iterations/components/iteration_form_spec.js
ee/spec/frontend/iterations/components/iteration_report_issues_spec.js ee/spec/frontend/iterations/components/iteration_report_issues_spec.js

View File

@ -7,7 +7,6 @@ RSpec.describe 'Secure Files', :js, feature_category: :secrets_management do
let(:user) { create(:user) } let(:user) { create(:user) }
before do before do
stub_feature_flags(ci_secure_files_read_only: false)
project.add_maintainer(user) project.add_maintainer(user)
sign_in(user) sign_in(user)
end end

View File

@ -0,0 +1,7 @@
Source host,Import type,Source user identifier,Source user name,Source username,GitLab username,GitLab public email
example.com,github,alice_1,Alice Alison,alice,alice-gl,alice@example.com
example.com,github,bob_1,Bob Bobson,bob,,bob@example.com
example.com,github,carl_1,Carl Calson,carl,carl-gl,
example.com,github,denise_1,Denise Denison,denise,denise-gl,denise@example.com
example.com,github,eric_1,Eric Ericson,eric,eric-gl,eric@example.com
example.com,github,frank_1,Secretive Frank,frank,,frank-secret@example.com
1 Source host Import type Source user identifier Source user name Source username GitLab username GitLab public email
2 example.com github alice_1 Alice Alison alice alice-gl alice@example.com
3 example.com github bob_1 Bob Bobson bob bob@example.com
4 example.com github carl_1 Carl Calson carl carl-gl
5 example.com github denise_1 Denise Denison denise denise-gl denise@example.com
6 example.com github eric_1 Eric Ericson eric eric-gl eric@example.com
7 example.com github frank_1 Secretive Frank frank frank-secret@example.com

View File

@ -63,7 +63,7 @@ describe('diff_stats', () => {
it("renders the bytes changes instead of line changes when the file isn't diffable", () => { it("renders the bytes changes instead of line changes when the file isn't diffable", () => {
const content = getBytesContainer(); const content = getBytesContainer();
expect(content.classes('gl-text-green-600')).toBe(true); expect(content.classes('gl-text-success')).toBe(true);
expect(content.text()).toBe('+1.00 KiB (+100%)'); expect(content.text()).toBe('+1.00 KiB (+100%)');
}); });
}); });

View File

@ -218,7 +218,7 @@ describe('diff_file utilities', () => {
{ {
changed: 1024, changed: 1024,
percent: 100, percent: 100,
classes: 'gl-text-green-600', classes: 'gl-text-success',
sign: '+', sign: '+',
text: '+1.00 KiB (+100%)', text: '+1.00 KiB (+100%)',
valid: true, valid: true,
@ -234,7 +234,7 @@ describe('diff_file utilities', () => {
{ {
changed: -1024, changed: -1024,
percent: -100, percent: -100,
classes: 'gl-text-red-500', classes: 'gl-text-danger',
sign: '', sign: '',
text: '-1.00 KiB (-100%)', text: '-1.00 KiB (-100%)',
valid: true, valid: true,

View File

@ -3,7 +3,11 @@ import MockAdapter from 'axios-mock-adapter';
import { GlModal } from '@gitlab/ui'; import { GlModal } from '@gitlab/ui';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import { createAlert } from '~/alert'; import { createAlert } from '~/alert';
import { HTTP_STATUS_INTERNAL_SERVER_ERROR } from '~/lib/utils/http_status'; import {
HTTP_STATUS_OK,
HTTP_STATUS_INTERNAL_SERVER_ERROR,
HTTP_STATUS_UNPROCESSABLE_ENTITY,
} from '~/lib/utils/http_status';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import CsvUploadModal from '~/members/placeholders/components/csv_upload_modal.vue'; import CsvUploadModal from '~/members/placeholders/components/csv_upload_modal.vue';
import UploadDropzone from '~/vue_shared/components/upload_dropzone/upload_dropzone.vue'; import UploadDropzone from '~/vue_shared/components/upload_dropzone/upload_dropzone.vue';
@ -106,14 +110,45 @@ describe('CsvUploadModal', () => {
expect(axios.post).toHaveBeenCalledWith(MOCK_REASSIGNMENT_CSV_PATH, expectedFormData); expect(axios.post).toHaveBeenCalledWith(MOCK_REASSIGNMENT_CSV_PATH, expectedFormData);
}); });
describe('when the request fails', () => { describe('when the request succeeds', () => {
beforeEach(() => { it('displays the message from the response', async () => {
const mockMessage = 'file is being processed';
mockAxios mockAxios
.onPost(MOCK_REASSIGNMENT_CSV_PATH) .onPost(MOCK_REASSIGNMENT_CSV_PATH)
.reply(HTTP_STATUS_INTERNAL_SERVER_ERROR, { error: new Error('error uploading CSV') }); .reply(HTTP_STATUS_OK, { message: mockMessage });
findGlModal().vm.$emit('primary');
await waitForPromises();
expect(createAlert).toHaveBeenCalledWith({
message: mockMessage,
variant: 'success',
});
});
});
describe('when the request fails', () => {
it('displays the message from the response if present', async () => {
const mockMessage = 'file too large';
mockAxios
.onPost(MOCK_REASSIGNMENT_CSV_PATH)
.reply(HTTP_STATUS_UNPROCESSABLE_ENTITY, { message: mockMessage });
findGlModal().vm.$emit('primary');
await waitForPromises();
expect(createAlert).toHaveBeenCalledWith({
message: mockMessage,
});
}); });
it('display an alert error message', async () => { it('display an alert error message', async () => {
mockAxios
.onPost(MOCK_REASSIGNMENT_CSV_PATH)
.reply(HTTP_STATUS_INTERNAL_SERVER_ERROR, { error: new Error('error uploading CSV') });
findGlModal().vm.$emit('primary'); findGlModal().vm.$emit('primary');
await waitForPromises(); await waitForPromises();

View File

@ -84,7 +84,7 @@ exports[`Merge request dashboard merge request component renders template 1`] =
</span> </span>
</div> </div>
<div <div
class="gl-flex gl-font-bold gl-items-center gl-text-green-600" class="gl-flex gl-font-bold gl-items-center gl-text-success"
> >
<span> <span>
+ +
@ -94,7 +94,7 @@ exports[`Merge request dashboard merge request component renders template 1`] =
</span> </span>
</div> </div>
<div <div
class="gl-flex gl-font-bold gl-items-center gl-text-red-500" class="gl-flex gl-font-bold gl-items-center gl-text-danger"
> >
<span> <span>
@ -167,6 +167,7 @@ exports[`Merge request dashboard merge request component when newListsEnabled is
> >
<gl-icon-stub <gl-icon-stub
class="gl-mt-1" class="gl-mt-1"
data-testid="mr-broken-badge"
name="warning-solid" name="warning-solid"
size="16" size="16"
title="Cannot be merged automatically" title="Cannot be merged automatically"

View File

@ -72,6 +72,7 @@ describe('Merge requests app component', () => {
lists: lists || [ lists: lists || [
[ [
{ {
id: 'assigned',
title: 'Assigned merge requests', title: 'Assigned merge requests',
query: 'assignedMergeRequests', query: 'assignedMergeRequests',
variables: { state: 'opened' }, variables: { state: 'opened' },
@ -120,6 +121,7 @@ describe('Merge requests app component', () => {
[ [
[ [
{ {
id: 'assigned',
title: 'Assigned merge requests', title: 'Assigned merge requests',
query: 'assignedMergeRequests', query: 'assignedMergeRequests',
variables: { state: 'opened' }, variables: { state: 'opened' },
@ -140,6 +142,7 @@ describe('Merge requests app component', () => {
[ [
[ [
{ {
id: 'assigned',
title: 'Assigned merge requests', title: 'Assigned merge requests',
query: 'assignedMergeRequests', query: 'assignedMergeRequests',
variables: { state: 'opened' }, variables: { state: 'opened' },
@ -147,6 +150,7 @@ describe('Merge requests app component', () => {
], ],
[ [
{ {
id: 'reviewer',
title: 'Assigned merge requests', title: 'Assigned merge requests',
query: 'assignedMergeRequests', query: 'assignedMergeRequests',
variables: { state: 'opened' }, variables: { state: 'opened' },

View File

@ -11,6 +11,8 @@ Vue.use(VueApollo);
describe('Merge request dashboard merge request component', () => { describe('Merge request dashboard merge request component', () => {
let wrapper; let wrapper;
const findBrokenBadge = () => wrapper.findByTestId('mr-broken-badge');
function createComponent(mergeRequest = {}, newListsEnabled = false) { function createComponent(mergeRequest = {}, newListsEnabled = false) {
const mockApollo = createMockApollo(); const mockApollo = createMockApollo();
@ -22,6 +24,7 @@ describe('Merge request dashboard merge request component', () => {
propsData: { propsData: {
listId: 'returned_to_you', listId: 'returned_to_you',
mergeRequest: { mergeRequest: {
state: 'opened',
reference: '!123456', reference: '!123456',
title: 'Merge request title', title: 'Merge request title',
author: { author: {
@ -117,5 +120,16 @@ describe('Merge request dashboard merge request component', () => {
expect(wrapper.findComponent(StatusBadge).exists()).toBe(true); expect(wrapper.findComponent(StatusBadge).exists()).toBe(true);
}); });
it.each`
state | exists | test
${'opened'} | ${true} | ${'renders'}
${'closed'} | ${false} | ${'does not render'}
${'merged'} | ${false} | ${'does not render'}
`('$test broken badge when state is $state', ({ state, exists }) => {
createComponent({ state }, true);
expect(findBrokenBadge().exists()).toBe(exists);
});
}); });
}); });

View File

@ -5,6 +5,7 @@ export function createMockMergeRequest(mergeRequest = {}) {
title: 'Title', title: 'Title',
webUrl: '/', webUrl: '/',
draft: false, draft: false,
state: 'opened',
author: { author: {
id: 1, id: 1,
avatarUrl: '/', avatarUrl: '/',

View File

@ -40,7 +40,7 @@ exports[`Snippet Description Edit component rendering matches the snapshot 1`] =
id="reference-0" id="reference-0"
placeholder="Describe what your snippet does or how to use it…" placeholder="Describe what your snippet does or how to use it…"
rows="3" rows="3"
style="overflow-x: hidden; word-wrap: break-word; overflow-y: hidden;" style="overflow-x: hidden; word-wrap: break-word;"
/> />
<div <div
class="div-dropzone-hover" class="div-dropzone-hover"

View File

@ -10,6 +10,7 @@ import unSnoozeTodoMutation from '~/todos/components/mutations/un_snooze_todo.mu
import waitForPromises from 'helpers/wait_for_promises'; import waitForPromises from 'helpers/wait_for_promises';
import { useFakeDate } from 'helpers/fake_date'; import { useFakeDate } from 'helpers/fake_date';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive'; import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import { mockTracking, unmockTracking } from 'jest/__helpers__/tracking_helper';
Vue.use(VueApollo); Vue.use(VueApollo);
@ -140,21 +141,26 @@ describe('ToggleSnoozedStatus', () => {
}); });
it.each` it.each`
index | expectedDate index | expectedDate | expectedTrackingLabel
${0} | ${'2024-12-18T14:24:00.000Z'} ${0} | ${'2024-12-18T14:24:00.000Z'} | ${'snooze_for_one_hour'}
${1} | ${'2024-12-18T17:24:00.000Z'} ${1} | ${'2024-12-18T17:24:00.000Z'} | ${'snooze_until_later_today'}
${2} | ${'2024-12-19T08:00:00.000Z'} ${2} | ${'2024-12-19T08:00:00.000Z'} | ${'snooze_until_tomorrow'}
`( `(
'triggers the snooze action with snoozeUntil = $expectedDate when clicking option #$index', 'triggers the snooze action with snoozeUntil = $expectedDate when clicking option #$index',
({ index, expectedDate }) => { ({ index, expectedDate, expectedTrackingLabel }) => {
createComponent({ props: { isSnoozed: false, isPending: true } }); createComponent({ props: { isSnoozed: false, isPending: true } });
const trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
getPredefinedSnoozingOption(index).action(); getPredefinedSnoozingOption(index).action();
expect(snoozeTodoMutationSuccessHandler).toHaveBeenCalledWith({ expect(snoozeTodoMutationSuccessHandler).toHaveBeenCalledWith({
snoozeUntil: new Date(expectedDate), snoozeUntil: new Date(expectedDate),
todoId: mockTodo.id, todoId: mockTodo.id,
}); });
expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_todo_item_action', {
label: expectedTrackingLabel,
});
unmockTracking();
}, },
); );
@ -265,13 +271,18 @@ describe('ToggleSnoozedStatus', () => {
props: { isSnoozed: true, isPending: true }, props: { isSnoozed: true, isPending: true },
unSnoozeTodoMutationHandler: jest.fn().mockRejectedValue(), unSnoozeTodoMutationHandler: jest.fn().mockRejectedValue(),
}); });
const trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
findUnSnoozeButton().vm.$emit('click'); findUnSnoozeButton().vm.$emit('click');
await waitForPromises(); await waitForPromises();
expect(mockToastShow).toHaveBeenCalledWith('Failed to un-snooze todo. Try again later.', { expect(mockToastShow).toHaveBeenCalledWith('Failed to un-snooze todo. Try again later.', {
variant: 'danger', variant: 'danger',
}); });
expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_todo_item_action', {
label: 'remove_snooze',
});
unmockTracking();
}); });
it('has a tooltip attached', () => { it('has a tooltip attached', () => {

View File

@ -79,7 +79,7 @@ describe('Diff Stats Dropdown', () => {
expect(fileText).toContain(mockFiles[1].name); expect(fileText).toContain(mockFiles[1].name);
expect(fileText).toContain(mockFiles[1].path); expect(fileText).toContain(mockFiles[1].path);
expect(fileData.findComponent(GlIcon).props('name')).toEqual(mockFiles[1].icon); expect(fileData.findComponent(GlIcon).props('name')).toEqual(mockFiles[1].icon);
expect(fileData.findComponent(GlIcon).classes()).toContain('gl-text-red-500'); expect(fileData.findComponent(GlIcon).classes()).toContain('gl-text-danger');
expect(fileData.find('a').attributes('href')).toEqual(mockFiles[1].href); expect(fileData.find('a').attributes('href')).toEqual(mockFiles[1].href);
}); });

View File

@ -260,13 +260,6 @@ describe('vue_shared/component/markdown/markdown_editor', () => {
}); });
describe('autosize', () => { describe('autosize', () => {
it('autosizes the textarea when the value changes', async () => {
buildWrapper();
await findTextarea().setValue('Lots of newlines\n\n\n\n\n\n\nMore content\n\n\nand newlines');
await nextTick();
expect(Autosize.update).toHaveBeenCalled();
});
it('autosizes the textarea when the value changes from outside the component', async () => { it('autosizes the textarea when the value changes from outside the component', async () => {
buildWrapper(); buildWrapper();
wrapper.setProps({ value: 'Lots of newlines\n\n\n\n\n\n\nMore content\n\n\nand newlines' }); wrapper.setProps({ value: 'Lots of newlines\n\n\n\n\n\n\nMore content\n\n\nand newlines' });

View File

@ -342,7 +342,6 @@ RSpec.describe MergeRequestsHelper, feature_category: :code_review_workflow do
new_merge_request_path: project_new_merge_request_path(project), new_merge_request_path: project_new_merge_request_path(project),
show_export_button: 'true', show_export_button: 'true',
issuable_type: :merge_request, issuable_type: :merge_request,
issuable_count: 5,
email: current_user.notification_email_or_default, email: current_user.notification_email_or_default,
export_csv_path: '/csv-url', export_csv_path: '/csv-url',
rss_url: '/rss-url', rss_url: '/rss-url',
@ -455,7 +454,6 @@ RSpec.describe MergeRequestsHelper, feature_category: :code_review_workflow do
is_public_visibility_restricted: 'false', is_public_visibility_restricted: 'false',
is_signed_in: 'true', is_signed_in: 'true',
issuable_type: :merge_request, issuable_type: :merge_request,
issuable_count: 5,
email: current_user.notification_email_or_default, email: current_user.notification_email_or_default,
rss_url: "/rss-url", rss_url: "/rss-url",
releases_endpoint: group_releases_path(group, format: :json), releases_endpoint: group_releases_path(group, format: :json),

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Gitlab::Kas::Client do RSpec.describe Gitlab::Kas::Client, feature_category: :deployment_management do
let_it_be(:project) { create(:project) } let_it_be(:project) { create(:project) }
let_it_be(:agent) { create(:cluster_agent, project: project) } let_it_be(:agent) { create(:cluster_agent, project: project) }
@ -146,6 +146,9 @@ RSpec.describe Gitlab::Kas::Client do
end end
context 'when autoflow_enabled FF is enabled' do context 'when autoflow_enabled FF is enabled' do
let_it_be(:autoflow_var1) { create(:ci_variable, project: project, key: 'test_key_1', value: 'test-value-1', environment_scope: 'autoflow/internal-use') }
let_it_be(:autoflow_var2) { create(:ci_variable, project: project, key: 'test_key_2', value: 'test-value-2', environment_scope: 'autoflow/internal-use') }
let_it_be(:other_var) { create(:ci_variable, project: project, key: 'test_key_3', value: 'test-value-3') }
let(:stub) { instance_double(Gitlab::Agent::AutoFlow::Rpc::AutoFlow::Stub) } let(:stub) { instance_double(Gitlab::Agent::AutoFlow::Rpc::AutoFlow::Stub) }
let(:request) { instance_double(Gitlab::Agent::AutoFlow::Rpc::CloudEventRequest) } let(:request) { instance_double(Gitlab::Agent::AutoFlow::Rpc::CloudEventRequest) }
let(:event_param) { instance_double(Gitlab::Agent::Event::CloudEvent) } let(:event_param) { instance_double(Gitlab::Agent::Event::CloudEvent) }
@ -175,7 +178,14 @@ RSpec.describe Gitlab::Kas::Client do
.and_return(event_param) .and_return(event_param)
expect(Gitlab::Agent::AutoFlow::Rpc::CloudEventRequest).to receive(:new) expect(Gitlab::Agent::AutoFlow::Rpc::CloudEventRequest).to receive(:new)
.with(event: event_param, flow_project: project_param) .with(
event: event_param,
flow_project: project_param,
variables: {
"test_key_1" => "test-value-1",
"test_key_2" => "test-value-2"
}
)
.and_return(request) .and_return(request)
expect(stub).to receive(:cloud_event) expect(stub).to receive(:cloud_event)

View File

@ -64,16 +64,6 @@ RSpec.describe Gitlab::Middleware::Go, feature_category: :source_code_management
it 'returns the full project path' do it 'returns the full project path' do
expect_response_with_path(go, enabled_protocol, project.full_path, url_based: true) expect_response_with_path(go, enabled_protocol, project.full_path, url_based: true)
end end
context 'when feature flag is disabled' do
before do
stub_feature_flags(go_get_handle_relative_url: false)
end
it 'returns the full project path' do
expect_response_with_path(go, enabled_protocol, project.full_path, url_based: false)
end
end
end end
context 'when the project is private' do context 'when the project is private' do

View File

@ -17,6 +17,18 @@ RSpec.describe ::Search::EmptySearchResults, feature_category: :global_search do
end end
end end
describe '#blobs_count' do
it 'returns a zero' do
expect(results.blobs_count).to eq(0)
end
end
describe '#file_count' do
it 'returns a zero' do
expect(results.file_count).to eq(0)
end
end
describe '#highlight_map' do describe '#highlight_map' do
it 'returns an empty hash' do it 'returns an empty hash' do
expect(results.highlight_map).to eq({}) expect(results.highlight_map).to eq({})

View File

@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Integrations::PipelinesEmail, :mailer do RSpec.describe Integrations::PipelinesEmail, :mailer, feature_category: :integrations do
let(:pipeline) do let(:pipeline) do
create(:ci_pipeline, :failed, create(:ci_pipeline, :failed,
project: project, project: project,

View File

@ -263,7 +263,7 @@ RSpec.describe WorkItem, feature_category: :portfolio_management do
it 'returns quick action commands supported for all work items' do it 'returns quick action commands supported for all work items' do
is_expected.to include(:title, :reopen, :close, :cc, :tableflip, :shrug, :type, :promote_to, :checkin_reminder, is_expected.to include(:title, :reopen, :close, :cc, :tableflip, :shrug, :type, :promote_to, :checkin_reminder,
:subscribe, :unsubscribe, :confidential, :award) :subscribe, :unsubscribe, :confidential, :award, :move, :clone)
end end
it 'omits quick action commands from assignees widget' do it 'omits quick action commands from assignees widget' do

View File

@ -250,6 +250,23 @@ RSpec.describe WorkItems::ParentLink, feature_category: :portfolio_management do
expect(link.valid?).to eq(valid) expect(link.valid?).to eq(valid)
end end
end end
context 'when parent is confidential' do
before do
issue.confidential = true
task1.confidential = false
end
it 'sets the correct error message' do
link = build(:parent_link, work_item_parent: issue, work_item: task1)
link.valid?
expect(link.errors[:work_item]).to include(
'cannot assign a non-confidential task to a confidential parent. ' \
'Make the task confidential and try again.')
end
end
end end
end end
end end

View File

@ -5,7 +5,6 @@ require 'spec_helper'
RSpec.describe API::Ci::SecureFiles, feature_category: :mobile_devops do RSpec.describe API::Ci::SecureFiles, feature_category: :mobile_devops do
before do before do
stub_ci_secure_file_object_storage stub_ci_secure_file_object_storage
stub_feature_flags(ci_secure_files_read_only: false)
end end
let_it_be(:maintainer) { create(:user) } let_it_be(:maintainer) { create(:user) }
@ -24,63 +23,6 @@ RSpec.describe API::Ci::SecureFiles, feature_category: :mobile_devops do
end end
describe 'GET /projects/:id/secure_files' do describe 'GET /projects/:id/secure_files' do
context 'ci_secure_files_read_only feature flag' do
context 'when the flag is enabled' do
before do
stub_feature_flags(ci_secure_files_read_only: true)
end
it 'returns a 503 when attempting to upload a file' do
stub_feature_flags(ci_secure_files_read_only: true)
expect do
post api("/projects/#{project.id}/secure_files", maintainer), params: file_params
end.not_to change { project.secure_files.count }
expect(response).to have_gitlab_http_status(:service_unavailable)
end
it 'returns a 200 when downloading a file' do
stub_feature_flags(ci_secure_files_read_only: true)
get api("/projects/#{project.id}/secure_files", developer)
expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to be_a(Array)
end
end
context 'when the feature is disabled at the instance level' do
before do
stub_config(ci_secure_files: { enabled: false })
end
it 'returns a 403 when attempting to upload a file' do
expect do
post api("/projects/#{project.id}/secure_files", maintainer), params: file_params
end.not_to change { project.secure_files.count }
expect(response).to have_gitlab_http_status(:forbidden)
end
it 'returns a 403 when downloading a file' do
get api("/projects/#{project.id}/secure_files", developer)
expect(response).to have_gitlab_http_status(:forbidden)
end
end
context 'when the flag is disabled' do
it 'returns a 201 when uploading a file when the ci_secure_files_read_only feature flag is disabled' do
expect do
post api("/projects/#{project.id}/secure_files", maintainer), params: file_params
end.to change { project.secure_files.count }.by(1)
expect(response).to have_gitlab_http_status(:created)
end
end
end
context 'authenticated user with admin permissions' do context 'authenticated user with admin permissions' do
it 'returns project secure files' do it 'returns project secure files' do
get api("/projects/#{project.id}/secure_files", maintainer) get api("/projects/#{project.id}/secure_files", maintainer)

View File

@ -0,0 +1,158 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Groups::BulkPlaceholderAssignmentsController, feature_category: :importers do
include WorkhorseHelpers
let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group, :public, owners: user) }
let(:file) { fixture_file_upload('spec/fixtures/import/user_mapping/user_mapping_upload.csv') }
describe 'GET /groups/*group_id/-/group_members/bulk_reassignment_file' do
subject(:request) do
get group_bulk_reassignment_file_path(group_id: group)
end
context 'when not signed in' do
it 'forbids access to the endpoint' do
request
expect(response).to have_gitlab_http_status(:forbidden)
end
end
context 'when signed in' do
before do
sign_in(user)
end
it 'responds with CSV data' do
request
expect(response).to have_gitlab_http_status(:success)
end
context 'and the user is not a group owner' do
let_it_be(:group) { create(:group, :public) }
it 'forbids access to the endpoint' do
request
expect(response).to have_gitlab_http_status(:forbidden)
end
end
context 'and the CSV is not generated properly' do
before do
allow_next_instance_of(Import::SourceUsers::GenerateCsvService) do |service|
allow(service).to receive(:execute).and_return(ServiceResponse.error(message: 'my error message'))
end
end
it 'redirects with an error' do
request
expect(response).to be_redirect
expect(flash[:alert]).to eq('my error message')
end
end
context 'when :importer_user_mapping_reassignment_csv is disabled' do
before do
stub_feature_flags(importer_user_mapping_reassignment_csv: false)
end
it 'responds with 404' do
request
expect(response).to have_gitlab_http_status(:not_found)
end
end
end
end
describe 'POST /groups/*group_id/-/group_members/bulk_reassignment_file' do
let(:file) { fixture_file_upload('spec/fixtures/import/user_mapping/user_mapping_upload.csv') }
subject(:request) do
workhorse_post_with_file(
group_bulk_reassignment_file_path(group_id: group, format: :json),
file_key: :file,
params: { file: file }
)
end
context 'when signed in' do
before do
sign_in(user)
end
it 'responds with success' do
request
expect(response).to have_gitlab_http_status(:ok)
end
context 'and the user is not a group owner' do
let_it_be(:group) { create(:group, :public) }
it 'forbids access to the endpoint' do
request
expect(response).to have_gitlab_http_status(:forbidden)
end
end
context 'and the file is not a CSV' do
let(:file) { fixture_file_upload('spec/fixtures/dk.png') }
it 'returns unprocessable_entity' do
request
expect(response).to have_gitlab_http_status(:unprocessable_entity)
end
end
context 'when :importer_user_mapping_reassignment_csv is disabled' do
before do
stub_feature_flags(importer_user_mapping_reassignment_csv: false)
end
it 'responds with 404' do
request
expect(response).to have_gitlab_http_status(:not_found)
end
end
end
context 'when not signed in' do
it 'forbids access to the endpoint' do
request
expect(response).to have_gitlab_http_status(:forbidden)
end
end
end
describe 'POST /groups/*group_id/-/group_members/bulk_reassignment_file/authorize' do
include_context 'workhorse headers'
subject(:request) do
post authorize_group_bulk_reassignment_file_path(group_id: group, format: :json),
params: { file: file },
headers: workhorse_headers
end
before do
sign_in(user)
end
it 'responds with success' do
request
expect(response).to have_gitlab_http_status(:ok)
end
end
end

View File

@ -30,73 +30,4 @@ RSpec.describe Groups::GroupMembersController, feature_category: :groups_and_pro
it_behaves_like 'request_accessable' it_behaves_like 'request_accessable'
end end
describe 'GET /groups/*group_id/-/group_members/bulk_reassignment_file' do
let_it_be(:membershipable) do
create(:group, :public).tap do |group|
group.add_owner(user)
end
end
subject(:request) do
get bulk_reassignment_file_group_group_members_path(group_id: membershipable)
end
context 'when not signed in' do
it 'forbids access to the endpoint' do
request
expect(response).to have_gitlab_http_status(:forbidden)
end
end
context 'when signed in' do
before do
sign_in(user)
end
it 'responds with CSV data' do
request
expect(response).to have_gitlab_http_status(:success)
end
context 'and the user is not a group owner' do
let_it_be(:membershipable) { create(:group, :public) }
it 'forbids access to the endpoint' do
request
expect(response).to have_gitlab_http_status(:forbidden)
end
end
context 'and the CSV is not generated properly' do
before do
allow_next_instance_of(Import::SourceUsers::GenerateCsvService) do |service|
allow(service).to receive(:execute).and_return(ServiceResponse.error(message: 'my error message'))
end
end
it 'redirects with an error' do
request
expect(response).to be_redirect
expect(flash[:alert]).to eq('my error message')
end
end
context 'when :importer_user_mapping_reassignment_csv is disabled' do
before do
stub_feature_flags(importer_user_mapping_reassignment_csv: false)
end
it 'responds with 404' do
request
expect(response).to have_gitlab_http_status(:not_found)
end
end
end
end
end end

View File

@ -51,6 +51,27 @@ RSpec.describe Issues::CloneService, feature_category: :team_planning do
end end
end end
# We will use this service in order to clone WorkItem to a new project. As WorkItem inherits from Issue, there
# should not be any problem with passing a WorkItem instead of an Issue to this service.
# Adding a small test case to cover this.
context "when we pass a work_item" do
include_context 'user can clone issue'
subject(:clone) { clone_service.execute(original_work_item, new_project) }
context "work item is of issue type" do
let_it_be_with_reload(:original_work_item) { create(:work_item, :issue, project: old_project, author: author) }
it { expect { clone }.to change { new_project.issues.count }.by(1) }
end
context "work item is of task type" do
let_it_be_with_reload(:original_work_item) { create(:work_item, :task, project: old_project, author: author) }
it { expect { clone }.to raise_error(described_class::CloneError) }
end
end
context 'generic issue' do context 'generic issue' do
let!(:new_issue) { clone_service.execute(old_issue, new_project, with_notes: with_notes) } let!(:new_issue) { clone_service.execute(old_issue, new_project, with_notes: with_notes) }

View File

@ -44,6 +44,27 @@ RSpec.describe Issues::MoveService, feature_category: :team_planning do
let!(:new_issue) { move_service.execute(old_issue, new_project) } let!(:new_issue) { move_service.execute(old_issue, new_project) }
end end
# We will use this service in order to move WorkItem to a new project. As WorkItem inherits from Issue, there
# should not be any problem with passing a WorkItem instead of an Issue to this service.
# Adding a small test case to cover this.
context "when we pass a work_item" do
include_context 'user can move issue'
subject(:move) { move_service.execute(original_work_item, new_project) }
context "work item is of issue type" do
let_it_be_with_reload(:original_work_item) { create(:work_item, :issue, project: old_project, author: author) }
it { expect { move }.to change { new_project.issues.count }.by(1) }
end
context "work item is of task type" do
let_it_be_with_reload(:original_work_item) { create(:work_item, :task, project: old_project, author: author) }
it { expect { move }.to raise_error(described_class::MoveError) }
end
end
context 'when issue creation fails' do context 'when issue creation fails' do
include_context 'user can move issue' include_context 'user can move issue'

View File

@ -654,6 +654,43 @@ RSpec.describe QuickActions::InterpretService, feature_category: :text_editors d
expect(message).to eq(_("Failed to move this issue because target project doesn't exist.")) expect(message).to eq(_("Failed to move this issue because target project doesn't exist."))
end end
context "when we pass a work_item" do
let(:work_item) { create(:work_item, :issue) }
let(:move_command) { "/move #{project.full_path}" }
it '/move execution method message' do
_, _, message = service.execute(move_command, work_item)
expect(message).to eq("Moved this issue to #{project.full_path}.")
end
end
end
describe 'clone issue command' do
it 'returns the clone issue message' do
_, _, message = service.execute("/clone #{project.full_path}", issue)
translated_string = _("Cloned this issue to %{project_full_path}.")
formatted_message = format(translated_string, project_full_path: project.full_path.to_s)
expect(message).to eq(formatted_message)
end
it 'returns clone issue failure message when the referenced issue is not found' do
_, _, message = service.execute('/clone invalid', issue)
expect(message).to eq(_("Failed to clone this issue because target project doesn't exist."))
end
context "when we pass a work_item" do
let(:work_item) { create(:work_item, :issue, project: project) }
it '/clone execution method message' do
_, _, message = service.execute("/clone #{project.full_path}", work_item)
expect(message).to eq("Cloned this issue to #{project.full_path}.")
end
end
end end
shared_examples 'confidential command' do shared_examples 'confidential command' do
@ -3533,6 +3570,37 @@ RSpec.describe QuickActions::InterpretService, feature_category: :text_editors d
expect(explanations).to eq([_("Moves this issue to test/project.")]) expect(explanations).to eq([_("Moves this issue to test/project.")])
end end
context "when work item type is an issue" do
let(:move_command) { "/move test/project" }
let(:work_item) { create(:work_item, :issue, project: project) }
it "/move is available" do
_, explanations = service.explain(move_command, work_item)
expect(explanations).to match_array(["Moves this issue to test/project."])
end
end
end
describe 'clone issue to another project command' do
let(:content) { '/clone test/project' }
it 'includes the project name' do
_, explanations = service.explain(content, issue)
expect(explanations).to match_array([_("Clones this issue, without comments, to test/project.")])
end
context "when work item type is an issue" do
let(:work_item) { create(:work_item, :issue, project: project) }
it "/clone is available" do
_, explanations = service.explain("/clone test/project", work_item)
expect(explanations).to match_array(["Clones this issue, without comments, to test/project."])
end
end
end end
describe 'tag a commit' do describe 'tag a commit' do
@ -3952,5 +4020,25 @@ RSpec.describe QuickActions::InterpretService, feature_category: :text_editors d
) )
end end
end end
context 'when target is a work item type of issue' do
let(:target) { create(:work_item, :issue) }
context "when work_item supports move and clone commands" do
it 'does recognize the actions' do
expect(service.available_commands(target).pluck(:name)).to include(:move, :clone)
end
end
context "when work_item does not support move and clone commands" do
before do
allow(target).to receive(:supports_move_and_clone?).and_return(false)
end
it 'does not recognize the action' do
expect(service.available_commands(target).pluck(:name)).not_to include(:move, :clone)
end
end
end
end end
end end

View File

@ -88,9 +88,9 @@ internal/upload/destination/objectstore/upload_strategy.go:29: internal/upload/d
internal/upload/destination/objectstore/uploader.go:5:2: G501: Blocklisted import crypto/md5: weak cryptographic primitive (gosec) internal/upload/destination/objectstore/uploader.go:5:2: G501: Blocklisted import crypto/md5: weak cryptographic primitive (gosec)
internal/upload/destination/objectstore/uploader.go:95:12: G401: Use of weak cryptographic primitive (gosec) internal/upload/destination/objectstore/uploader.go:95:12: G401: Use of weak cryptographic primitive (gosec)
internal/upload/exif/exif.go:103:10: G204: Subprocess launched with variable (gosec) internal/upload/exif/exif.go:103:10: G204: Subprocess launched with variable (gosec)
internal/upstream/routes.go:170:74: `(*upstream).wsRoute` - `matchers` always receives `nil` (unparam) internal/upstream/routes.go:171:74: `(*upstream).wsRoute` - `matchers` always receives `nil` (unparam)
internal/upstream/routes.go:230: Function 'configureRoutes' is too long (339 > 60) (funlen) internal/upstream/routes.go:231: Function 'configureRoutes' is too long (340 > 60) (funlen)
internal/upstream/routes.go:485: internal/upstream/routes.go:485: Line contains TODO/BUG/FIXME/NOTE/OPTIMIZE/HACK: "TODO: We should probably not return a HT..." (godox) internal/upstream/routes.go:487: internal/upstream/routes.go:487: Line contains TODO/BUG/FIXME/NOTE/OPTIMIZE/HACK: "TODO: We should probably not return a HT..." (godox)
internal/upstream/upstream.go:116: internal/upstream/upstream.go:116: Line contains TODO/BUG/FIXME/NOTE/OPTIMIZE/HACK: "TODO: move to LabKit https://gitlab.com/..." (godox) internal/upstream/upstream.go:116: internal/upstream/upstream.go:116: Line contains TODO/BUG/FIXME/NOTE/OPTIMIZE/HACK: "TODO: move to LabKit https://gitlab.com/..." (godox)
internal/zipartifacts/metadata.go:118:54: G115: integer overflow conversion int -> uint32 (gosec) internal/zipartifacts/metadata.go:118:54: G115: integer overflow conversion int -> uint32 (gosec)
internal/zipartifacts/open_archive.go:78:28: response body must be closed (bodyclose) internal/zipartifacts/open_archive.go:78:28: response body must be closed (bodyclose)

View File

@ -189,6 +189,7 @@ func TestAcceleratedUpload(t *testing.T) {
{"POST", "/api/v4/projects/2412/packages/helm/api/stable/charts", true}, {"POST", "/api/v4/projects/2412/packages/helm/api/stable/charts", true},
{"POST", "/api/v4/projects/group%2Fproject/packages/helm/api/stable/charts", true}, {"POST", "/api/v4/projects/group%2Fproject/packages/helm/api/stable/charts", true},
{"POST", "/api/v4/projects/group%2Fsubgroup%2Fproject/packages/helm/api/stable/charts", true}, {"POST", "/api/v4/projects/group%2Fsubgroup%2Fproject/packages/helm/api/stable/charts", true},
{"POST", "/groups/my-group/-/group_members/bulk_reassignment_file", true},
} }
allowedHashFunctions := map[string][]string{ allowedHashFunctions := map[string][]string{

View File

@ -60,6 +60,7 @@ const (
gitProjectPattern = `^/.+\.git/` gitProjectPattern = `^/.+\.git/`
geoGitProjectPattern = `^/[^-].+\.git/` // Prevent matching routes like /-/push_from_secondary geoGitProjectPattern = `^/[^-].+\.git/` // Prevent matching routes like /-/push_from_secondary
projectPattern = `^/([^/]+/){1,}[^/]+/` projectPattern = `^/([^/]+/){1,}[^/]+/`
groupPattern = `^/groups/([^/]+/){0,}[^/]+/`
apiProjectPattern = apiPattern + `v4/projects/[^/]+` // API: Projects can be encoded via group%2Fsubgroup%2Fproject apiProjectPattern = apiPattern + `v4/projects/[^/]+` // API: Projects can be encoded via group%2Fsubgroup%2Fproject
apiGroupPattern = apiPattern + `v4/groups/[^/]+` apiGroupPattern = apiPattern + `v4/groups/[^/]+`
apiTopicPattern = apiPattern + `v4/topics` apiTopicPattern = apiPattern + `v4/topics`
@ -390,7 +391,8 @@ func configureRoutes(u *upstream) {
newRoute(apiPattern+`v4/projects/import`, "api_projects_import", railsBackend), mimeMultipartUploader), newRoute(apiPattern+`v4/projects/import`, "api_projects_import", railsBackend), mimeMultipartUploader),
u.route("POST", u.route("POST",
newRoute(apiPattern+`v4/projects/import-relation`, "api_projects_import_relation", railsBackend), mimeMultipartUploader), newRoute(apiPattern+`v4/projects/import-relation`, "api_projects_import_relation", railsBackend), mimeMultipartUploader),
u.route("POST",
newRoute(groupPattern+`-/group_members/bulk_reassignment_file`, "group_placeholder_assignment", railsBackend), mimeMultipartUploader),
// Project Import via UI upload acceleration // Project Import via UI upload acceleration
u.route("POST", u.route("POST",
newRoute(importPattern+`gitlab_project`, "import_gitlab_project", railsBackend), mimeMultipartUploader), newRoute(importPattern+`gitlab_project`, "import_gitlab_project", railsBackend), mimeMultipartUploader),

View File

@ -1408,8 +1408,7 @@
resolved "https://registry.yarnpkg.com/@gitlab/fonts/-/fonts-1.3.0.tgz#df89c1bb6714e4a8a5d3272568aa4de7fb337267" resolved "https://registry.yarnpkg.com/@gitlab/fonts/-/fonts-1.3.0.tgz#df89c1bb6714e4a8a5d3272568aa4de7fb337267"
integrity sha512-DoMUIN3DqjEn7wvcxBg/b7Ite5fTdF5EmuOZoBRo2j0UBGweDXmNBi+9HrTZs4cBU660dOxcf1hATFcG3npbPg== integrity sha512-DoMUIN3DqjEn7wvcxBg/b7Ite5fTdF5EmuOZoBRo2j0UBGweDXmNBi+9HrTZs4cBU660dOxcf1hATFcG3npbPg==
"@gitlab/noop@^1.0.0", jackspeak@^2.3.5, "jackspeak@npm:@gitlab/noop@1.0.0": "@gitlab/noop@^1.0.0":
name jackspeak
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/@gitlab/noop/-/noop-1.0.0.tgz#b1ecb8ae6b2abf9b2e28927e4fbb05b7a1b2704b" resolved "https://registry.yarnpkg.com/@gitlab/noop/-/noop-1.0.0.tgz#b1ecb8ae6b2abf9b2e28927e4fbb05b7a1b2704b"
integrity sha512-nOltttik5o2BjBo8LnyeTFzHoLpMY/XcCVOC+lm9ZwU+ivEam8wafacMF0KTbRn1KVrIoHYdo70QnqS+vJiOVw== integrity sha512-nOltttik5o2BjBo8LnyeTFzHoLpMY/XcCVOC+lm9ZwU+ivEam8wafacMF0KTbRn1KVrIoHYdo70QnqS+vJiOVw==
@ -4530,10 +4529,10 @@ autoprefixer@^10.4.8:
picocolors "^1.0.0" picocolors "^1.0.0"
postcss-value-parser "^4.2.0" postcss-value-parser "^4.2.0"
autosize@^5.0.1: autosize@^6.0.1:
version "5.0.1" version "6.0.1"
resolved "https://registry.yarnpkg.com/autosize/-/autosize-5.0.1.tgz#ed269b0fa9b7eb47627048a1bb3299e99e003a0f" resolved "https://registry.yarnpkg.com/autosize/-/autosize-6.0.1.tgz#64ee78dd7029be959eddd3afbbd33235b957e10f"
integrity sha512-UIWUlE4TOVPNNj2jjrU39wI4hEYbneUypEqcyRmRFIx5CC2gNdg3rQr+Zh7/3h6egbBvm33TDQjNQKtj9Tk1HA== integrity sha512-f86EjiUKE6Xvczc4ioP1JBlWG7FKrE13qe/DxBCpe8GCipCq2nFw73aO8QEBKHfSbYGDN5eB9jXWKen7tspDqQ==
available-typed-arrays@^1.0.7: available-typed-arrays@^1.0.7:
version "1.0.7" version "1.0.7"
@ -5562,10 +5561,10 @@ core-js-pure@^3.30.2:
resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.35.0.tgz#4660033304a050215ae82e476bd2513a419fbb34" resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.35.0.tgz#4660033304a050215ae82e476bd2513a419fbb34"
integrity sha512-f+eRYmkou59uh7BPcyJ8MC76DiGhspj1KMxVIcF24tzP8NA9HVa1uC7BTW2tgx7E1QVCzDzsgp7kArrzhlz8Ew== integrity sha512-f+eRYmkou59uh7BPcyJ8MC76DiGhspj1KMxVIcF24tzP8NA9HVa1uC7BTW2tgx7E1QVCzDzsgp7kArrzhlz8Ew==
core-js@^3.29.1, core-js@^3.39.0, core-js@^3.6.5: core-js@^3.29.1, core-js@^3.40.0, core-js@^3.6.5:
version "3.39.0" version "3.40.0"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.39.0.tgz#57f7647f4d2d030c32a72ea23a0555b2eaa30f83" resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.40.0.tgz#2773f6b06877d8eda102fc42f828176437062476"
integrity sha512-raM0ew0/jJUqkJ0E6e8UDtl+y/7ktFivgWvqw8dNSQeNWoSDLvQ1H/RN3aPXB9tBd4/FhyR4RDPGhsNIMsAn7g== integrity sha512-7vsMc/Lty6AGnn7uFpYT56QesI5D2Y/UkgKounk87OP9Z2H9Z8kj6jzcSGAxFmUtDOS0ntK6lbQz+Nsa0Jj6mQ==
core-util-is@~1.0.0: core-util-is@~1.0.0:
version "1.0.3" version "1.0.3"
@ -9278,6 +9277,11 @@ iterall@^1.2.1:
resolved "https://registry.yarnpkg.com/iterall/-/iterall-1.3.0.tgz#afcb08492e2915cbd8a0884eb93a8c94d0d72fea" resolved "https://registry.yarnpkg.com/iterall/-/iterall-1.3.0.tgz#afcb08492e2915cbd8a0884eb93a8c94d0d72fea"
integrity sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg== integrity sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg==
jackspeak@^2.3.5, "jackspeak@npm:@gitlab/noop@1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@gitlab/noop/-/noop-1.0.0.tgz#b1ecb8ae6b2abf9b2e28927e4fbb05b7a1b2704b"
integrity sha512-nOltttik5o2BjBo8LnyeTFzHoLpMY/XcCVOC+lm9ZwU+ivEam8wafacMF0KTbRn1KVrIoHYdo70QnqS+vJiOVw==
jed@^1.1.1: jed@^1.1.1:
version "1.1.1" version "1.1.1"
resolved "https://registry.yarnpkg.com/jed/-/jed-1.1.1.tgz#7a549bbd9ffe1585b0cd0a191e203055bee574b4" resolved "https://registry.yarnpkg.com/jed/-/jed-1.1.1.tgz#7a549bbd9ffe1585b0cd0a191e203055bee574b4"