Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
d2bb9c16d9
commit
1be06f9dcb
|
|
@ -137,7 +137,11 @@ export const config = {
|
|||
}
|
||||
|
||||
// we want to concat next page of children work items within Hierarchy widget to the existing ones
|
||||
if (incomingWidget?.type === WIDGET_TYPE_HIERARCHY && context.variables.endCursor) {
|
||||
if (
|
||||
incomingWidget?.type === WIDGET_TYPE_HIERARCHY &&
|
||||
context.variables.endCursor &&
|
||||
incomingWidget.children?.nodes
|
||||
) {
|
||||
// concatPagination won't work because we were placing new widget here so we have to do this manually
|
||||
return {
|
||||
...incomingWidget,
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
<script>
|
||||
import { GlNavItem, GlTabs, GlTab } from '@gitlab/ui';
|
||||
import { GlTabs, GlTab } from '@gitlab/ui';
|
||||
import { s__ } from '~/locale';
|
||||
import { settingsTabTitle } from '~/integrations/constants';
|
||||
import { visitUrl } from '~/lib/utils/url_utility';
|
||||
|
||||
export default {
|
||||
name: 'ExclusionsTabs',
|
||||
components: {
|
||||
GlNavItem,
|
||||
GlTabs,
|
||||
GlTab,
|
||||
},
|
||||
|
|
@ -19,21 +19,17 @@ export default {
|
|||
settingsTabTitle,
|
||||
projectsTabTitle: s__('Integrations|Exclusions'),
|
||||
},
|
||||
methods: {
|
||||
goToSettings() {
|
||||
visitUrl(this.editPath);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<gl-tabs content-class="gl-p-0">
|
||||
<template #tabs-start>
|
||||
<gl-nav-item role="presentation" link-classes="gl-tab-nav-item" :href="editPath">{{
|
||||
$options.i18n.settingsTabTitle
|
||||
}}</gl-nav-item>
|
||||
</template>
|
||||
|
||||
<gl-tab active>
|
||||
<template #title>
|
||||
{{ $options.i18n.projectsTabTitle }}
|
||||
</template>
|
||||
</gl-tab>
|
||||
<gl-tab :title="$options.i18n.settingsTabTitle" @click="goToSettings" />
|
||||
<gl-tab :title="$options.i18n.projectsTabTitle" active />
|
||||
</gl-tabs>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
<script>
|
||||
import { GlBadge, GlNavItem, GlTabs, GlTab } from '@gitlab/ui';
|
||||
import { GlBadge, GlTabs, GlTab } from '@gitlab/ui';
|
||||
import { settingsTabTitle, overridesTabTitle } from '~/integrations/constants';
|
||||
import { visitUrl } from '~/lib/utils/url_utility';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GlBadge,
|
||||
GlNavItem,
|
||||
GlTabs,
|
||||
GlTab,
|
||||
},
|
||||
|
|
@ -25,16 +25,17 @@ export default {
|
|||
settingsTabTitle,
|
||||
overridesTabTitle,
|
||||
},
|
||||
methods: {
|
||||
goToSettings() {
|
||||
visitUrl(this.editPath);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<gl-tabs>
|
||||
<template #tabs-start>
|
||||
<gl-nav-item role="presentation" link-classes="gl-tab-nav-item" :href="editPath">{{
|
||||
$options.i18n.settingsTabTitle
|
||||
}}</gl-nav-item>
|
||||
</template>
|
||||
<gl-tab :title="$options.i18n.settingsTabTitle" @click="goToSettings" />
|
||||
|
||||
<gl-tab active>
|
||||
<template #title>
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ export const initMembersApp = (el, context, options) => {
|
|||
canApproveAccessRequests,
|
||||
namespaceUserLimit,
|
||||
availableRoles,
|
||||
reassignmentCsvPath,
|
||||
...vuexStoreAttributes
|
||||
} = parseDataAttributes(el);
|
||||
|
||||
|
|
@ -76,6 +77,7 @@ export const initMembersApp = (el, context, options) => {
|
|||
namespaceUserLimit,
|
||||
availableRoles,
|
||||
context,
|
||||
reassignmentCsvPath,
|
||||
group: {
|
||||
name: groupName,
|
||||
path: groupPath,
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ export default {
|
|||
GlAlert,
|
||||
},
|
||||
inject: {
|
||||
reassignmentCsvDownloadPath: {
|
||||
reassignmentCsvPath: {
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
|
|
@ -56,7 +56,7 @@ export default {
|
|||
<ol class="gl-ml-0 gl-mt-5">
|
||||
<li>
|
||||
<gl-button
|
||||
:href="reassignmentCsvDownloadPath"
|
||||
:href="reassignmentCsvPath"
|
||||
variant="link"
|
||||
icon="download"
|
||||
data-testid="csv-download-button"
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ import {
|
|||
} from '~/issues/show/utils';
|
||||
import { getSortableDefaultOptions, isDragging } from '~/sortable/utils';
|
||||
import SafeHtml from '~/vue_shared/directives/safe_html';
|
||||
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
|
||||
const FULL_OPACITY = 'gl-opacity-10';
|
||||
const isCheckbox = (target) => target?.classList.contains('task-list-item-checkbox');
|
||||
|
|
@ -25,7 +24,6 @@ export default {
|
|||
components: {
|
||||
GlButton,
|
||||
},
|
||||
mixins: [glFeatureFlagMixin()],
|
||||
props: {
|
||||
disableTruncation: {
|
||||
type: Boolean,
|
||||
|
|
@ -74,7 +72,7 @@ export default {
|
|||
return this.descriptionHtml?.trim() === '';
|
||||
},
|
||||
isTruncated() {
|
||||
return this.truncated && !this.disableTruncation && this.glFeatures.workItemsBeta;
|
||||
return this.truncated && !this.disableTruncation;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,43 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Mutations
|
||||
module Ml
|
||||
module Models
|
||||
class Edit < Base
|
||||
graphql_name 'MlModelEdit'
|
||||
|
||||
include FindsProject
|
||||
|
||||
argument :model_id, GraphQL::Types::Int,
|
||||
required: false,
|
||||
description: 'Id of the model.'
|
||||
|
||||
argument :name, GraphQL::Types::String,
|
||||
required: true,
|
||||
description: 'Name of the model.'
|
||||
|
||||
argument :description, GraphQL::Types::String,
|
||||
required: false,
|
||||
description: 'Description of the model.'
|
||||
|
||||
def resolve(project_path:, name:, model_id:, description:)
|
||||
project = authorized_find!(project_path)
|
||||
model = ::Ml::FindModelService.new(project, name, model_id).execute
|
||||
service_response = ::Ml::UpdateModelService.new(model, description).execute
|
||||
|
||||
if service_response.success?
|
||||
{
|
||||
model: service_response.payload,
|
||||
errors: []
|
||||
}
|
||||
else
|
||||
{
|
||||
model: nil,
|
||||
errors: service_response.errors
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -219,6 +219,7 @@ module Types
|
|||
mount_mutation Mutations::WorkItems::Subscribe, alpha: { milestone: '16.3' }
|
||||
mount_mutation Mutations::Admin::AbuseReportLabels::Create, alpha: { milestone: '16.4' }
|
||||
mount_mutation Mutations::Ml::Models::Create, alpha: { milestone: '16.8' }
|
||||
mount_mutation Mutations::Ml::Models::Edit, alpha: { milestone: '17.3' }
|
||||
mount_mutation Mutations::Ml::Models::Destroy, alpha: { milestone: '16.10' }
|
||||
mount_mutation Mutations::Ml::Models::Delete, alpha: { milestone: '17.0' }
|
||||
mount_mutation Mutations::Ml::ModelVersions::Create, alpha: { milestone: '17.1' }
|
||||
|
|
|
|||
|
|
@ -29,7 +29,8 @@ module Groups::GroupMembersHelper
|
|||
group_path: group.full_path,
|
||||
can_approve_access_requests: true, # true for CE, overridden in EE
|
||||
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)
|
||||
}
|
||||
end
|
||||
# rubocop:enable Metrics/ParameterLists
|
||||
|
|
|
|||
|
|
@ -29,7 +29,8 @@ module Projects
|
|||
model_id: model.id,
|
||||
model_name: model.name,
|
||||
max_allowed_file_size: max_allowed_file_size(project),
|
||||
latest_version: model.latest_version&.version
|
||||
latest_version: model.latest_version&.version,
|
||||
markdown_preview_path: ::Gitlab::Routing.url_helpers.project_ml_preview_markdown_url(project)
|
||||
}
|
||||
|
||||
to_json(data)
|
||||
|
|
|
|||
|
|
@ -109,6 +109,10 @@ module Import
|
|||
accepted_status? ? reassign_to_user : placeholder_user
|
||||
end
|
||||
|
||||
def mapped_user_id
|
||||
accepted_status? ? reassign_to_user_id : placeholder_user_id
|
||||
end
|
||||
|
||||
def accepted_status?
|
||||
STATUSES.slice(*ACCEPTED_STATUSES).value?(status)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -34,6 +34,8 @@ module VirtualRegistries
|
|||
after_validation :reset_credentials, if: -> { persisted? && url_changed? }
|
||||
before_save :write_credentials
|
||||
|
||||
prevent_from_serialization(:username, :password) if respond_to?(:prevent_from_serialization)
|
||||
|
||||
def url_for(path)
|
||||
full_url = File.join(url, path)
|
||||
Addressable::URI.parse(full_url).to_s
|
||||
|
|
|
|||
|
|
@ -2,12 +2,24 @@
|
|||
|
||||
module Ml
|
||||
class FindModelService
|
||||
def initialize(project, name)
|
||||
def initialize(project, name = nil, model_id = nil)
|
||||
@project = project
|
||||
@name = name
|
||||
@model_id = model_id
|
||||
end
|
||||
|
||||
def execute
|
||||
return find_by_model_id if @model_id
|
||||
return find_by_project_and_name if @name
|
||||
|
||||
nil
|
||||
end
|
||||
|
||||
def find_by_model_id
|
||||
Ml::Model.by_project_id_and_id(@project.id, @model_id)
|
||||
end
|
||||
|
||||
def find_by_project_and_name
|
||||
Ml::Model.by_project_id_and_name(@project.id, @name)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -8,9 +8,18 @@ module Ml
|
|||
end
|
||||
|
||||
def execute
|
||||
@model.update!(description: @description)
|
||||
return error('Model not found') unless @model
|
||||
|
||||
@model
|
||||
@model.update!(description: @description)
|
||||
success(@model)
|
||||
end
|
||||
|
||||
def success(model)
|
||||
ServiceResponse.success(payload: model)
|
||||
end
|
||||
|
||||
def error(reason)
|
||||
ServiceResponse.error(message: reason)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
- page_title _("Groups")
|
||||
|
||||
= render_dashboard_ultimate_trial(current_user)
|
||||
%div{ data: { testid: 'groups-page' } }
|
||||
= render_dashboard_ultimate_trial(current_user)
|
||||
- if current_user.groups.exists?
|
||||
= render 'dashboard/groups_head'
|
||||
= render 'groups'
|
||||
|
|
|
|||
|
|
@ -1,25 +1,16 @@
|
|||
- if @related_branches.any?
|
||||
- if @related_branches.any?
|
||||
= render Pajamas::CardComponent.new(card_options: { class: 'gl-new-card' }, header_options: { class: 'gl-new-card-header' } , body_options: { class: 'gl-new-card-body' }) do |c|
|
||||
- c.with_header do
|
||||
.gl-new-card-title-wrapper
|
||||
%h3.gl-new-card-title
|
||||
= link_to "", "#related-branches", class: "gl-link anchor position-absolute gl-text-decoration-none", "aria-hidden": true
|
||||
= _('Related branches')
|
||||
.gl-new-card-count
|
||||
= sprite_icon('branch', css_class: "gl-mr-2 gl-text-gray-500 gl-icon")
|
||||
= @related_branches.size
|
||||
- c.with_body do
|
||||
.gl-new-card-content
|
||||
%ul.related-merge-requests.content-list
|
||||
- @related_branches.each do |branch|
|
||||
%li.list-item{ class: "gl-py-0! gl-border-0!" }
|
||||
.item-body.gl-display-flex.gl-align-items-center.gl-px-3.gl-pr-2.-gl-mx-2
|
||||
.item-contents.gl-display-flex.gl-align-items-center.gl-flex-wrap.gl-flex-grow-1.gl-min-h-7
|
||||
.item-title.gl-display-flex.mb-xl-0.gl-min-w-0.gl-align-items-center
|
||||
- if branch[:pipeline_status].present?
|
||||
%span.-gl-mt-2.-gl-mb-2.gl-mr-3
|
||||
= render 'ci/status/icon', status: branch[:pipeline_status]
|
||||
%span.related-branch-info
|
||||
%strong
|
||||
= link_to branch[:name], branch[:link], class: "ref-name"
|
||||
= render ::Layouts::CrudComponent.new(_('Related branches'),
|
||||
icon: 'branch',
|
||||
count: @related_branches.size,
|
||||
options: { class: 'gl-mt-5' },
|
||||
body_options: { class: 'gl-p-3' }) do |c|
|
||||
- c.with_body do
|
||||
%ul.related-merge-requests.content-list
|
||||
- @related_branches.each do |branch|
|
||||
%li{ class: '!gl-p-0 !gl-border-b-0' }
|
||||
.item-body.gl-p-3
|
||||
.gl-flex.gl-items-center.gl-gap-3
|
||||
- if branch[:pipeline_status].present?
|
||||
%span.-gl-my-2
|
||||
= render 'ci/status/icon', status: branch[:pipeline_status]
|
||||
= link_to branch[:name], branch[:link], class: 'ref-name'
|
||||
|
|
|
|||
|
|
@ -1,5 +1,9 @@
|
|||
- if labels.any?
|
||||
= render Pajamas::CardComponent.new(card_options: { class: 'gl-new-card' }, body_options: { class: 'gl-new-card-body gl-px-0' }) do |c|
|
||||
= render ::Layouts::CrudComponent.new(s_('Labels'),
|
||||
icon: 'label',
|
||||
count: labels.size,
|
||||
options: { class: 'gl-mt-5' },
|
||||
body_options: { class: '!gl-m-0' }) do |c|
|
||||
- c.with_body do
|
||||
%ul.manage-labels-list.gl-px-0.gl-mb-0
|
||||
- labels.each do |label|
|
||||
|
|
|
|||
|
|
@ -6,4 +6,4 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/153236
|
|||
milestone: '17.3'
|
||||
queued_migration_version: 20240717093514
|
||||
finalize_after: '2024-08-01'
|
||||
finalized_by:
|
||||
finalized_by: 20240812010237
|
||||
|
|
|
|||
|
|
@ -7,4 +7,4 @@ milestone: '17.3'
|
|||
queued_migration_version: 20240708105034
|
||||
# Replace with the approximate date you think it's best to ensure the completion of this BBM.
|
||||
finalize_after: '2024-08-22'
|
||||
finalized_by: # version of the migration that finalized this BBM
|
||||
finalized_by: 20240812084505
|
||||
|
|
|
|||
|
|
@ -7,4 +7,4 @@ milestone: '17.2'
|
|||
queued_migration_version: 20240627122810
|
||||
# Replace with the approximate date you think it's best to ensure the completion of this BBM.
|
||||
finalize_after: '2024-07-22'
|
||||
finalized_by: # version of the migration that finalized this BBM
|
||||
finalized_by: 20240812062443
|
||||
|
|
|
|||
|
|
@ -0,0 +1,58 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class RemoveCrmContactsWidgetFromWorkItemTypes < Gitlab::Database::Migration[2.2]
|
||||
class WorkItemType < MigrationRecord
|
||||
self.table_name = 'work_item_types'
|
||||
end
|
||||
|
||||
class WidgetDefinition < MigrationRecord
|
||||
self.table_name = 'work_item_widget_definitions'
|
||||
end
|
||||
|
||||
restrict_gitlab_migration gitlab_schema: :gitlab_main
|
||||
disable_ddl_transaction!
|
||||
milestone '17.4'
|
||||
|
||||
WIDGET_NAME = 'CrmContacts'
|
||||
WIDGET_ENUM_VALUE = 24
|
||||
WORK_ITEM_TYPES = %w[
|
||||
Epic
|
||||
Task
|
||||
].freeze
|
||||
|
||||
def up
|
||||
WORK_ITEM_TYPES.each do |type_name|
|
||||
type = WorkItemType.find_by_name_and_namespace_id(type_name, nil)
|
||||
next unless type
|
||||
|
||||
WidgetDefinition.where(name: WIDGET_NAME, work_item_type_id: type.id).delete_all
|
||||
end
|
||||
end
|
||||
|
||||
def down
|
||||
widgets = []
|
||||
|
||||
WORK_ITEM_TYPES.each do |type_name|
|
||||
type = WorkItemType.find_by_name_and_namespace_id(type_name, nil)
|
||||
|
||||
unless type
|
||||
Gitlab::AppLogger.warn("type #{type_name} is missing, not adding widget")
|
||||
|
||||
next
|
||||
end
|
||||
|
||||
widgets << {
|
||||
work_item_type_id: type.id,
|
||||
name: WIDGET_NAME,
|
||||
widget_type: WIDGET_ENUM_VALUE
|
||||
}
|
||||
end
|
||||
|
||||
return if widgets.empty?
|
||||
|
||||
WidgetDefinition.upsert_all(
|
||||
widgets,
|
||||
unique_by: :index_work_item_widget_definitions_on_default_witype_and_name
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class FinalizeBackfillPartitionIdCiDailyBuildGroupReportResultAttempt2 < Gitlab::Database::Migration[2.2]
|
||||
milestone '17.4'
|
||||
disable_ddl_transaction!
|
||||
restrict_gitlab_migration gitlab_schema: :gitlab_ci
|
||||
|
||||
MIGRATION = 'BackfillPartitionIdCiDailyBuildGroupReportResult'
|
||||
|
||||
def up
|
||||
ensure_batched_background_migration_is_finished(
|
||||
job_class_name: MIGRATION,
|
||||
table_name: :ci_daily_build_group_report_results,
|
||||
column_name: :id,
|
||||
job_arguments: [],
|
||||
finalize: true
|
||||
)
|
||||
end
|
||||
|
||||
def down
|
||||
# no-op
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class PartitionedFkToCiPipelinesFromCiDailyBuildGroupReportResults < Gitlab::Database::Migration[2.2]
|
||||
milestone '17.4'
|
||||
|
||||
SOURCE_TABLE_NAME = :ci_daily_build_group_report_results
|
||||
COLUMN = :last_pipeline_id
|
||||
PARTITION_COLUMN = :partition_id
|
||||
FK_NAME = :fk_rails_ee072d13b3_p
|
||||
|
||||
def up
|
||||
validate_foreign_key(
|
||||
SOURCE_TABLE_NAME, [PARTITION_COLUMN, COLUMN],
|
||||
name: FK_NAME
|
||||
)
|
||||
end
|
||||
|
||||
def down
|
||||
# no-op
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class FinalizeBackfillAutoCanceledByPartitionIdForPipelines < Gitlab::Database::Migration[2.2]
|
||||
milestone '17.4'
|
||||
disable_ddl_transaction!
|
||||
restrict_gitlab_migration gitlab_schema: :gitlab_ci
|
||||
|
||||
MIGRATION = 'QueueBackfillAutocancelPartitionIdOnCiPipelines'
|
||||
TABLE_NAME = :ci_pipelines
|
||||
COLUMN_NAME = :id
|
||||
|
||||
def up
|
||||
ensure_batched_background_migration_is_finished(
|
||||
job_class_name: MIGRATION,
|
||||
table_name: TABLE_NAME,
|
||||
column_name: COLUMN_NAME,
|
||||
job_arguments: [],
|
||||
finalize: true
|
||||
)
|
||||
end
|
||||
|
||||
def down
|
||||
# no-op
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ValidateFkAutoCanceledByIdForCiPipelines < Gitlab::Database::Migration[2.2]
|
||||
milestone '17.4'
|
||||
|
||||
SOURCE_TABLE_NAME = :ci_pipelines
|
||||
COLUMN = :auto_canceled_by_id
|
||||
PARTITION_COLUMN = :auto_canceled_by_partition_id
|
||||
FK_NAME = :fk_262d4c2d19_p
|
||||
|
||||
def up
|
||||
validate_foreign_key(
|
||||
SOURCE_TABLE_NAME, [PARTITION_COLUMN, COLUMN],
|
||||
name: FK_NAME
|
||||
)
|
||||
end
|
||||
|
||||
def down
|
||||
# no-op
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class FinalizeBackfillUpstreamPipelinePartitionIdForBuilds < Gitlab::Database::Migration[2.2]
|
||||
milestone '17.4'
|
||||
disable_ddl_transaction!
|
||||
restrict_gitlab_migration gitlab_schema: :gitlab_ci
|
||||
|
||||
MIGRATION = 'BackfillUpstreamPipelinePartitionIdOnPCiBuilds'
|
||||
|
||||
def up
|
||||
ensure_batched_background_migration_is_finished(
|
||||
job_class_name: MIGRATION,
|
||||
table_name: :p_ci_builds,
|
||||
column_name: :upstream_pipeline_id,
|
||||
job_arguments: [],
|
||||
finalize: true
|
||||
)
|
||||
end
|
||||
|
||||
def down
|
||||
# no-op
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddFkUpstreamPipelineIdForPCiBuilds < Gitlab::Database::Migration[2.2]
|
||||
include Gitlab::Database::PartitioningMigrationHelpers::ForeignKeyHelpers
|
||||
|
||||
milestone '17.4'
|
||||
disable_ddl_transaction!
|
||||
|
||||
SOURCE_TABLE_NAME = :p_ci_builds
|
||||
TARGET_TABLE_NAME = :ci_pipelines
|
||||
COLUMN = :upstream_pipeline_id
|
||||
PARTITION_COLUMN = :upstream_pipeline_partition_id
|
||||
TARGET_COLUMN = :id
|
||||
TARGET_PARTITION_COLUMN = :partition_id
|
||||
FK_NAME = :fk_87f4cefcda_p
|
||||
|
||||
def up
|
||||
add_concurrent_partitioned_foreign_key(
|
||||
SOURCE_TABLE_NAME,
|
||||
TARGET_TABLE_NAME,
|
||||
column: [PARTITION_COLUMN, COLUMN],
|
||||
target_column: [TARGET_PARTITION_COLUMN, TARGET_COLUMN],
|
||||
validate: true,
|
||||
reverse_lock_order: true,
|
||||
on_update: :cascade,
|
||||
on_delete: :cascade,
|
||||
name: FK_NAME
|
||||
)
|
||||
end
|
||||
|
||||
def down
|
||||
with_lock_retries do
|
||||
remove_foreign_key_if_exists(
|
||||
SOURCE_TABLE_NAME,
|
||||
TARGET_TABLE_NAME,
|
||||
name: FK_NAME,
|
||||
reverse_lock_order: true
|
||||
)
|
||||
end
|
||||
|
||||
add_concurrent_partitioned_foreign_key(
|
||||
SOURCE_TABLE_NAME,
|
||||
TARGET_TABLE_NAME,
|
||||
column: [PARTITION_COLUMN, COLUMN],
|
||||
target_column: [TARGET_PARTITION_COLUMN, TARGET_COLUMN],
|
||||
validate: false,
|
||||
reverse_lock_order: true,
|
||||
on_update: :cascade,
|
||||
on_delete: :cascade,
|
||||
name: FK_NAME
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
074508a89bf7e84826fe6c94093a8ba8c3022a88be8f583d9043e2208e1a934a
|
||||
|
|
@ -0,0 +1 @@
|
|||
7eafb011d36e7a20e6ca47951f96beb512997abda4dda0a4de12b80bd406f451
|
||||
|
|
@ -0,0 +1 @@
|
|||
4fe56834e4bcb4750cab7a95f9baa452761262721250617d15760e3e3d64f19e
|
||||
|
|
@ -0,0 +1 @@
|
|||
ed4ecaa771a6b6f3a233d08a209d0e6749159c50f91c671c2cd6ec14a4826f39
|
||||
|
|
@ -0,0 +1 @@
|
|||
10011db577bc89ecc877a22f7088038eeb564ea2d013a36d7522306aa1b04239
|
||||
|
|
@ -0,0 +1 @@
|
|||
7725aa4f55c8e94d3b89f95b2a8760dc21e2d679e476c08a1117077ae58a88d2
|
||||
|
|
@ -0,0 +1 @@
|
|||
9a962866caa0a9101bc5e9a992b5f28a7383599108464d009d7bff9ada44fc44
|
||||
|
|
@ -32630,7 +32630,7 @@ ALTER TABLE ONLY ci_pipelines
|
|||
ADD CONSTRAINT fk_262d4c2d19 FOREIGN KEY (auto_canceled_by_id) REFERENCES ci_pipelines(id) ON DELETE SET NULL;
|
||||
|
||||
ALTER TABLE ONLY ci_pipelines
|
||||
ADD CONSTRAINT fk_262d4c2d19_p FOREIGN KEY (auto_canceled_by_partition_id, auto_canceled_by_id) REFERENCES ci_pipelines(partition_id, id) ON UPDATE CASCADE ON DELETE SET NULL NOT VALID;
|
||||
ADD CONSTRAINT fk_262d4c2d19_p FOREIGN KEY (auto_canceled_by_partition_id, auto_canceled_by_id) REFERENCES ci_pipelines(partition_id, id) ON UPDATE CASCADE ON DELETE SET NULL;
|
||||
|
||||
ALTER TABLE ONLY user_namespace_callouts
|
||||
ADD CONSTRAINT fk_27a69fd1bd FOREIGN KEY (namespace_id) REFERENCES namespaces(id) ON DELETE CASCADE;
|
||||
|
|
@ -33154,8 +33154,8 @@ ALTER TABLE ONLY packages_package_files
|
|||
ALTER TABLE p_ci_builds
|
||||
ADD CONSTRAINT fk_87f4cefcda FOREIGN KEY (upstream_pipeline_id) REFERENCES ci_pipelines(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY ci_builds
|
||||
ADD CONSTRAINT fk_87f4cefcda_p FOREIGN KEY (upstream_pipeline_partition_id, upstream_pipeline_id) REFERENCES ci_pipelines(partition_id, id) ON UPDATE CASCADE ON DELETE CASCADE NOT VALID;
|
||||
ALTER TABLE p_ci_builds
|
||||
ADD CONSTRAINT fk_87f4cefcda_p FOREIGN KEY (upstream_pipeline_partition_id, upstream_pipeline_id) REFERENCES ci_pipelines(partition_id, id) ON UPDATE CASCADE ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY approval_group_rules_users
|
||||
ADD CONSTRAINT fk_888a0df3b7 FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
|
||||
|
|
@ -35726,7 +35726,7 @@ ALTER TABLE ONLY ci_daily_build_group_report_results
|
|||
ADD CONSTRAINT fk_rails_ee072d13b3 FOREIGN KEY (last_pipeline_id) REFERENCES ci_pipelines(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY ci_daily_build_group_report_results
|
||||
ADD CONSTRAINT fk_rails_ee072d13b3_p FOREIGN KEY (partition_id, last_pipeline_id) REFERENCES ci_pipelines(partition_id, id) ON UPDATE CASCADE ON DELETE CASCADE NOT VALID;
|
||||
ADD CONSTRAINT fk_rails_ee072d13b3_p FOREIGN KEY (partition_id, last_pipeline_id) REFERENCES ci_pipelines(partition_id, id) ON UPDATE CASCADE ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY import_source_users
|
||||
ADD CONSTRAINT fk_rails_ee30e569be FOREIGN KEY (namespace_id) REFERENCES namespaces(id) ON DELETE CASCADE;
|
||||
|
|
|
|||
|
|
@ -1033,3 +1033,19 @@ gitlab-ctl restart mailroom
|
|||
```
|
||||
|
||||
::EndTabs
|
||||
|
||||
### Incoming emails are rejected by providers with email address limit
|
||||
|
||||
Your GitLab instance might not receive incoming emails, because some email providers impose a
|
||||
64-character limit on the local part of the email address (before the `@`).
|
||||
All emails from addresses that exceed this limit are rejected emails.
|
||||
|
||||
As a workaround, maintain a shorter path:
|
||||
|
||||
- Ensure that the local part configured before `%{key}` in `incoming_email_address` is as short as
|
||||
possible, and not longer than 31 characters.
|
||||
- Place the designated projects at a higher group hierarchy.
|
||||
- Rename [groups](../user/group/manage.md#change-a-groups-path) and
|
||||
[project](../user/project/working_with_projects.md#rename-a-repository) to shorter names.
|
||||
|
||||
Track this feature in [issue 460206](https://gitlab.com/gitlab-org/gitlab/-/issues/460206).
|
||||
|
|
|
|||
|
|
@ -7048,6 +7048,32 @@ Input type: `MlModelDestroyInput`
|
|||
| <a id="mutationmlmodeldestroymessage"></a>`message` | [`String`](#string) | Model deletion result message. |
|
||||
| <a id="mutationmlmodeldestroymodel"></a>`model` | [`MlModel`](#mlmodel) | Model after mutation. |
|
||||
|
||||
### `Mutation.mlModelEdit`
|
||||
|
||||
DETAILS:
|
||||
**Introduced** in GitLab 17.3.
|
||||
**Status**: Experiment.
|
||||
|
||||
Input type: `MlModelEditInput`
|
||||
|
||||
#### Arguments
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="mutationmlmodeleditclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
|
||||
| <a id="mutationmlmodeleditdescription"></a>`description` | [`String`](#string) | Description of the model. |
|
||||
| <a id="mutationmlmodeleditmodelid"></a>`modelId` | [`Int`](#int) | Id of the model. |
|
||||
| <a id="mutationmlmodeleditname"></a>`name` | [`String!`](#string) | Name of the model. |
|
||||
| <a id="mutationmlmodeleditprojectpath"></a>`projectPath` | [`ID!`](#id) | Project the model to mutate is in. |
|
||||
|
||||
#### Fields
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="mutationmlmodeleditclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
|
||||
| <a id="mutationmlmodelediterrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
|
||||
| <a id="mutationmlmodeleditmodel"></a>`model` | [`MlModel`](#mlmodel) | Model after mutation. |
|
||||
|
||||
### `Mutation.mlModelVersionCreate`
|
||||
|
||||
DETAILS:
|
||||
|
|
|
|||
|
|
@ -161,7 +161,7 @@ curl --request PATCH \
|
|||
|
||||
## Delete a container registry protection rule
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/457518) in GitLab 17.3.
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/457518) in GitLab 17.4.
|
||||
|
||||
Deletes a container registry protection rule from a project.
|
||||
|
||||
|
|
|
|||
|
|
@ -273,8 +273,8 @@ this limit. Repository limits apply to both public and private projects.
|
|||
The [import sources](../project/import/index.md#supported-import-sources) that are available to you by default depend on
|
||||
which GitLab you use:
|
||||
|
||||
- GitLab.com: all available import sources are enabled by default.
|
||||
- GitLab self-managed: no import sources are enabled by default and must be
|
||||
- GitLab.com: All available import sources are enabled by default.
|
||||
- GitLab self-managed: No import sources are enabled by default and must be
|
||||
[enabled](../../administration/settings/import_and_export_settings.md#configure-allowed-import-sources).
|
||||
|
||||
## IP range
|
||||
|
|
@ -286,7 +286,7 @@ from those IPs and allow them.
|
|||
GitLab.com is fronted by Cloudflare. For incoming connections to GitLab.com, you might need to allow CIDR blocks of Cloudflare ([IPv4](https://www.cloudflare.com/ips-v4/) and [IPv6](https://www.cloudflare.com/ips-v6/)).
|
||||
|
||||
For outgoing connections from CI/CD runners, we are not providing static IP addresses.
|
||||
All GitLab.com instance runners are deployed into Google Cloud Platform (GCP) in `us-east1`.
|
||||
Most GitLab.com instance runners are deployed into Google Cloud Platform (GCP) in `us-east1`, except _Linux GPU-enabled_ and _Linux Arm64_, hosted in `us-central1`.
|
||||
Any IP-based firewall can be configured by looking up
|
||||
[IP address ranges or CIDR blocks for GCP](https://cloud.google.com/compute/docs/faq#find_ip_range).
|
||||
|
||||
|
|
|
|||
|
|
@ -87,13 +87,13 @@ The following features are not found in standard Markdown:
|
|||
|
||||
The following features are extended from standard Markdown:
|
||||
|
||||
| Standard Markdown | Extended Markdown in GitLab |
|
||||
|---------------------------------------|---------------------------------------------------------------------------------------|
|
||||
| [Blockquotes](#blockquotes) | [Multiline blockquotes](#multiline-blockquote) |
|
||||
| [Code blocks](#code-spans-and-blocks) | [Colored code and syntax highlighting](#syntax-highlighting) |
|
||||
| [Headings](#headings) | [Linkable heading IDs](#heading-ids-and-links) |
|
||||
| [Images](#images) | [Embedded videos](#videos) and [audio](#audio) |
|
||||
| [Links](#links) | [Automatically linking URLs](#url-auto-linking) |
|
||||
| Standard Markdown | Extended Markdown in GitLab |
|
||||
|---------------------------------------|-----------------------------|
|
||||
| [Blockquotes](#blockquotes) | [Multiline blockquotes](#multiline-blockquote) |
|
||||
| [Code blocks](#code-spans-and-blocks) | [Colored code and syntax highlighting](#syntax-highlighting) |
|
||||
| [Headings](#headings) | [Linkable heading IDs](#heading-ids-and-links) |
|
||||
| [Images](#images) | [Embedded videos](#videos) and [audio](#audio) |
|
||||
| [Links](#links) | [Automatically linking URLs](#url-auto-linking) |
|
||||
|
||||
## Markdown and accessibility
|
||||
|
||||
|
|
@ -1015,13 +1015,13 @@ The number of math blocks is also limited based on render time. If the limit is
|
|||
GitLab renders the excess math instances as text. Wiki and repository files do not have
|
||||
these limits.
|
||||
|
||||
Math written between dollar signs with backticks (``$`...`$``) or single dollar signs (`$...$`)
|
||||
Math written between dollar signs with backticks (``` $`...`$ ```) or single dollar signs (`$...$`)
|
||||
is rendered inline with the text.
|
||||
|
||||
Math written between double dollar signs (`$$...$$`) or in a [code block](#code-spans-and-blocks) with
|
||||
the language declared as `math` is rendered on a separate line:
|
||||
|
||||
````markdown
|
||||
`````markdown
|
||||
This math is inline: $`a^2+b^2=c^2`$.
|
||||
|
||||
This math is on a separate line using a ```` ```math ```` block:
|
||||
|
|
@ -1037,7 +1037,7 @@ This math is on a separate line using a `$$...$$` block:
|
|||
$$
|
||||
a^2+b^2=c^2
|
||||
$$
|
||||
````
|
||||
`````
|
||||
|
||||

|
||||
|
||||
|
|
@ -1049,16 +1049,12 @@ When creating tables:
|
|||
|
||||
- The first line contains the headers, separated by "pipes" (`|`).
|
||||
- The second line separates the headers from the cells.
|
||||
- The cells can contain only empty spaces, hyphens, and
|
||||
(optionally) colons for horizontal alignment.
|
||||
- Each cell must contain at least one hyphen, but adding more hyphens to a
|
||||
cell does not change the cell's rendering.
|
||||
- The cells can contain only empty spaces, hyphens, and (optionally) colons for horizontal alignment.
|
||||
- Each cell must contain at least one hyphen, but adding more hyphens to a cell does not change the cell's rendering.
|
||||
- Any content other than hyphens, whitespace, or colons is not allowed
|
||||
- The third, and any following lines, contain the cell values.
|
||||
- You **can't** have cells separated over many lines in the Markdown, they must be kept to single lines,
|
||||
but they can be very long. You can also include HTML `<br>` tags to force newlines if needed.
|
||||
- The cell sizes **don't** have to match each other. They are flexible, but must be separated
|
||||
by pipes (`|`).
|
||||
- You **can't** have cells separated over many lines in the Markdown, they must be kept to single lines, but they can be very long. You can also include HTML `<br>` tags to force newlines if needed.
|
||||
- The cell sizes **don't** have to match each other. They are flexible, but must be separated by pipes (`|`).
|
||||
- You **can** have blank cells.
|
||||
- Column widths are calculated dynamically based on the content of the cells.
|
||||
- To use the pipe character (`|`) in the text and not as table delimiter, you must [escape](#escape-characters) it with a backslash (`\|`).
|
||||
|
|
|
|||
|
|
@ -85,10 +85,10 @@ difficult, but several tools exist including:
|
|||
DETAILS:
|
||||
**Status:** Experiment
|
||||
|
||||
> - [Introduced to migration by using direct transfer](https://gitlab.com/gitlab-org/gitlab/-/issues/443557) in GitLab 17.3 [with a flag](../../../administration/feature_flags.md) named `importer_user_mapping`. Disabled by default. This feature is an [experiment](../../../policy/experiment-beta-support.md).
|
||||
> - [Introduced to migration by using direct transfer](https://gitlab.com/gitlab-org/gitlab/-/issues/443557) in GitLab 17.4 [with flags](../../../administration/feature_flags.md) named `importer_user_mapping` and `bulk_import_importer_user_mapping`. Disabled by default. This feature is an [experiment](../../../policy/experiment-beta-support.md).
|
||||
|
||||
FLAG:
|
||||
The availability of this feature is controlled by a feature flag.
|
||||
The availability of this feature is controlled by feature flags.
|
||||
For more information, see the history.
|
||||
This feature is available for internal testing only, it is not ready for production use.
|
||||
|
||||
|
|
|
|||
|
|
@ -263,6 +263,20 @@ it inherits the issue's milestone and labels.
|
|||
For performance reasons, automatic issue closing is disabled for the very first
|
||||
push from an existing repository.
|
||||
|
||||
#### User responsibility when merging
|
||||
|
||||
When you merge a merge request, it's your responsibility to check that it's appropriate for any targeted issues
|
||||
to close. Users can include issue closing patterns in the merge request description, and also in the body
|
||||
of a commit message. Closing messages in commit messages are easy to miss. In both cases, the merge request widget
|
||||
shows information about the issue to close on merge:
|
||||
|
||||

|
||||
|
||||
When you merge a merge request, GitLab checks that you have permission to close the targeted issues.
|
||||
In public repositories, this check is important, because external users can create both merge requests
|
||||
and commits that contain closing patterns. When you are the user who merges, it's important
|
||||
that you are aware of the effects the merge has on both the code and issues in your project.
|
||||
|
||||
#### Default closing pattern
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/465391) work item (task, objective, or key result) references in GitLab 17.3.
|
||||
|
|
|
|||
|
|
@ -65,6 +65,10 @@ To do this from the GitLab user interface:
|
|||
1. Scroll to the merge request reports section.
|
||||
1. Optional. Select your desired merge options, such as **Delete source branch**,
|
||||
**Squash commits**, or **Edit commit message**.
|
||||
1. Review the contents of the merge request widget. If it contains an
|
||||
[issue closing pattern](../issues/managing_issues.md#closing-issues-automatically), confirm
|
||||
that the issue should close when this work merges:
|
||||

|
||||
1. Select **Auto-merge**.
|
||||
|
||||
Commenting on a merge request after you select **Auto-merge**,
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
|
|
@ -173,6 +173,13 @@ a merge request, or:
|
|||
|
||||
GitLab adds the merge request to the user's **Assigned merge requests** page.
|
||||
|
||||
## Merge a merge request
|
||||
|
||||
During the merge request [review process](reviews/index.md), reviewers provide feedback on your merge request.
|
||||
When a reviewer decides that the contents of your merge request are acceptable, the reviewer can set
|
||||
[auto-merge](auto_merge.md) on it, even if some merge checks are failing. When a merge request is set to auto-merge,
|
||||
it merges after all merge checks pass, without more action from you.
|
||||
|
||||
## Close a merge request
|
||||
|
||||
If you decide to permanently stop work on a merge request, close it rather than
|
||||
|
|
|
|||
|
|
@ -22,11 +22,6 @@ module API
|
|||
}.freeze
|
||||
|
||||
included do
|
||||
include ::API::Helpers::Authentication
|
||||
|
||||
feature_category :virtual_registry
|
||||
urgency :low
|
||||
|
||||
helpers do
|
||||
def require_non_web_browser!
|
||||
browser = ::Browser.new(request.user_agent)
|
||||
|
|
@ -79,12 +74,7 @@ module API
|
|||
end
|
||||
|
||||
after_validation do
|
||||
not_found! unless Feature.enabled?(:virtual_registry_maven, current_user)
|
||||
|
||||
require_non_web_browser!
|
||||
require_dependency_proxy_enabled!
|
||||
|
||||
authenticate!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,151 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
module Concerns
|
||||
module VirtualRegistries
|
||||
module Packages
|
||||
module Maven
|
||||
module UpstreamEndpoints
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
desc 'List all maven virtual registry upstreams' do
|
||||
detail 'This feature was introduced in GitLab 17.3. \
|
||||
This feature is currently in experiment state. \
|
||||
This feature behind the `virtual_registry_maven` feature flag.'
|
||||
success code: 200
|
||||
failure [
|
||||
{ code: 400, message: 'Bad Request' },
|
||||
{ code: 401, message: 'Unauthorized' },
|
||||
{ code: 403, message: 'Forbidden' },
|
||||
{ code: 404, message: 'Not found' }
|
||||
]
|
||||
tags %w[maven_virtual_registries]
|
||||
hidden true
|
||||
end
|
||||
get do
|
||||
authorize! :read_virtual_registry, registry
|
||||
|
||||
present [upstream].compact, with: Entities::VirtualRegistries::Packages::Maven::Upstream
|
||||
end
|
||||
|
||||
desc 'Add a maven virtual registry upstream' do
|
||||
detail 'This feature was introduced in GitLab 17.3. \
|
||||
This feature is currently in experiment state. \
|
||||
This feature behind the `virtual_registry_maven` feature flag.'
|
||||
success code: 201
|
||||
failure [
|
||||
{ code: 400, message: 'Bad Request' },
|
||||
{ code: 401, message: 'Unauthorized' },
|
||||
{ code: 403, message: 'Forbidden' },
|
||||
{ code: 404, message: 'Not found' },
|
||||
{ code: 409, message: 'Conflict' }
|
||||
]
|
||||
tags %w[maven_virtual_registries]
|
||||
hidden true
|
||||
end
|
||||
params do
|
||||
requires :url, type: String, desc: 'The URL of the maven virtual registry upstream', allow_blank: false
|
||||
optional :username, type: String, desc: 'The username of the maven virtual registry upstream'
|
||||
optional :password, type: String, desc: 'The password of the maven virtual registry upstream'
|
||||
all_or_none_of :username, :password
|
||||
end
|
||||
post do
|
||||
authorize! :create_virtual_registry, registry
|
||||
|
||||
conflict!(_('Upstream already exists')) if upstream
|
||||
|
||||
registry.build_upstream(declared_params.merge(group: group))
|
||||
registry_upstream.group = group
|
||||
|
||||
ApplicationRecord.transaction do
|
||||
render_validation_error!(upstream) unless upstream.save
|
||||
render_validation_error!(registry_upstream) unless registry_upstream.save
|
||||
end
|
||||
|
||||
created!
|
||||
end
|
||||
|
||||
route_param :upstream_id, type: Integer, desc: 'The ID of the maven virtual registry upstream' do
|
||||
desc 'Get a specific maven virtual registry upstream' do
|
||||
detail 'This feature was introduced in GitLab 17.3. \
|
||||
This feature is currently in experiment state. \
|
||||
This feature behind the `virtual_registry_maven` feature flag.'
|
||||
success code: 200
|
||||
failure [
|
||||
{ code: 400, message: 'Bad Request' },
|
||||
{ code: 401, message: 'Unauthorized' },
|
||||
{ code: 403, message: 'Forbidden' },
|
||||
{ code: 404, message: 'Not found' }
|
||||
]
|
||||
tags %w[maven_virtual_registries]
|
||||
hidden true
|
||||
end
|
||||
get do
|
||||
authorize! :read_virtual_registry, registry
|
||||
|
||||
not_found! if upstream&.id != params[:upstream_id]
|
||||
|
||||
present upstream, with: Entities::VirtualRegistries::Packages::Maven::Upstream
|
||||
end
|
||||
|
||||
desc 'Update a maven virtual registry upstream' do
|
||||
detail 'This feature was introduced in GitLab 17.3. \
|
||||
This feature is currently in experiment state. \
|
||||
This feature behind the `virtual_registry_maven` feature flag.'
|
||||
success code: 200
|
||||
failure [
|
||||
{ code: 400, message: 'Bad Request' },
|
||||
{ code: 401, message: 'Unauthorized' },
|
||||
{ code: 403, message: 'Forbidden' },
|
||||
{ code: 404, message: 'Not found' }
|
||||
]
|
||||
tags %w[maven_virtual_registries]
|
||||
hidden true
|
||||
end
|
||||
params do
|
||||
optional :url, type: String, desc: 'The URL of the maven virtual registry upstream',
|
||||
allow_blank: false
|
||||
optional :username, type: String, desc: 'The username of the maven virtual registry upstream',
|
||||
allow_blank: false
|
||||
optional :password, type: String, desc: 'The password of the maven virtual registry upstream',
|
||||
allow_blank: false
|
||||
at_least_one_of :url, :username, :password
|
||||
end
|
||||
patch do
|
||||
authorize! :update_virtual_registry, registry
|
||||
|
||||
render_validation_error!(upstream) unless upstream.update(declared_params(include_missing: false))
|
||||
|
||||
status :ok
|
||||
end
|
||||
|
||||
desc 'Delete a maven virtual registry upstream' do
|
||||
detail 'This feature was introduced in GitLab 17.3. \
|
||||
This feature is currently in experiment state. \
|
||||
This feature behind the `virtual_registry_maven` feature flag.'
|
||||
success code: 204
|
||||
failure [
|
||||
{ code: 400, message: 'Bad Request' },
|
||||
{ code: 401, message: 'Unauthorized' },
|
||||
{ code: 403, message: 'Forbidden' },
|
||||
{ code: 404, message: 'Not found' }
|
||||
]
|
||||
tags %w[maven_virtual_registries]
|
||||
hidden true
|
||||
end
|
||||
delete do
|
||||
authorize! :destroy_virtual_registry, registry
|
||||
|
||||
not_found! if upstream&.id != params[:upstream_id]
|
||||
|
||||
destroy_conditionally!(upstream)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
module Entities
|
||||
module VirtualRegistries
|
||||
module Packages
|
||||
module Maven
|
||||
class Upstream < Grape::Entity
|
||||
expose :id, :group_id, :url, :created_at, :updated_at
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -78,7 +78,9 @@ module API
|
|||
desc: 'Optional description for registered model.'
|
||||
end
|
||||
patch 'update', urgency: :low do
|
||||
present ::Ml::UpdateModelService.new(find_model(user_project, params[:name]), params[:description]).execute,
|
||||
present ::Ml::UpdateModelService.new(
|
||||
find_model(user_project, params[:name]), params[:description]
|
||||
).execute.payload,
|
||||
with: Entities::Ml::Mlflow::RegisteredModel, root: :registered_model
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -4,8 +4,12 @@ module API
|
|||
module VirtualRegistries
|
||||
module Packages
|
||||
class Maven < ::API::Base
|
||||
include ::API::Helpers::Authentication
|
||||
include ::API::Concerns::VirtualRegistries::Packages::Endpoint
|
||||
|
||||
feature_category :virtual_registry
|
||||
urgency :low
|
||||
|
||||
authenticate_with do |accept|
|
||||
accept.token_types(:personal_access_token).sent_through(:http_private_token_header)
|
||||
accept.token_types(:deploy_token).sent_through(:http_deploy_token_header)
|
||||
|
|
@ -21,47 +25,71 @@ module API
|
|||
helpers do
|
||||
include ::Gitlab::Utils::StrongMemoize
|
||||
|
||||
delegate :group, :upstream, :registry_upstream, to: :registry
|
||||
|
||||
def require_dependency_proxy_enabled!
|
||||
not_found! unless ::Gitlab.config.dependency_proxy.enabled
|
||||
end
|
||||
|
||||
def registry
|
||||
::VirtualRegistries::Packages::Maven::Registry.find(declared_params[:id])
|
||||
::VirtualRegistries::Packages::Maven::Registry.find(params[:id])
|
||||
end
|
||||
strong_memoize_attr :registry
|
||||
end
|
||||
|
||||
desc 'Download endpoint of the Maven virtual registry.' do
|
||||
detail 'This feature was introduced in GitLab 17.3. \
|
||||
This feature is currently in experiment state. \
|
||||
This feature behind the `virtual_registry_maven` feature flag.'
|
||||
success [
|
||||
{ code: 200 }
|
||||
]
|
||||
failure [
|
||||
{ code: 400, message: 'Bad request' },
|
||||
{ code: 401, message: 'Unauthorized' },
|
||||
{ code: 403, message: 'Forbidden' },
|
||||
{ code: 404, message: 'Not Found' }
|
||||
]
|
||||
tags %w[maven_virtual_registries]
|
||||
hidden true
|
||||
end
|
||||
params do
|
||||
requires :id,
|
||||
type: Integer,
|
||||
desc: 'The ID of the Maven virtual registry'
|
||||
requires :path,
|
||||
type: String,
|
||||
file_path: true,
|
||||
desc: 'Package path',
|
||||
documentation: { example: 'foo/bar/mypkg/1.0-SNAPSHOT/mypkg-1.0-SNAPSHOT.jar' }
|
||||
end
|
||||
get 'virtual_registries/packages/maven/:id/*path', format: false do
|
||||
service_response = ::VirtualRegistries::Packages::Maven::HandleFileRequestService.new(
|
||||
registry: registry,
|
||||
current_user: current_user,
|
||||
params: { path: declared_params[:path] }
|
||||
).execute
|
||||
after_validation do
|
||||
not_found! unless Feature.enabled?(:virtual_registry_maven, current_user)
|
||||
|
||||
send_error_response_from!(service_response: service_response) if service_response.error?
|
||||
send_successful_response_from(service_response: service_response)
|
||||
require_dependency_proxy_enabled!
|
||||
|
||||
authenticate!
|
||||
end
|
||||
|
||||
namespace 'virtual_registries/packages/maven' do
|
||||
namespace :registries do
|
||||
route_param :id, type: Integer, desc: 'The ID of the maven virtual registry' do
|
||||
namespace :upstreams do
|
||||
include ::API::Concerns::VirtualRegistries::Packages::Maven::UpstreamEndpoints
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
desc 'Download endpoint of the Maven virtual registry.' do
|
||||
detail 'This feature was introduced in GitLab 17.3. \
|
||||
This feature is currently in experiment state. \
|
||||
This feature behind the `virtual_registry_maven` feature flag.'
|
||||
success [
|
||||
{ code: 200 }
|
||||
]
|
||||
failure [
|
||||
{ code: 400, message: 'Bad request' },
|
||||
{ code: 401, message: 'Unauthorized' },
|
||||
{ code: 403, message: 'Forbidden' },
|
||||
{ code: 404, message: 'Not Found' }
|
||||
]
|
||||
tags %w[maven_virtual_registries]
|
||||
hidden true
|
||||
end
|
||||
params do
|
||||
requires :id,
|
||||
type: Integer,
|
||||
desc: 'The ID of the Maven virtual registry'
|
||||
requires :path,
|
||||
type: String,
|
||||
file_path: true,
|
||||
desc: 'Package path',
|
||||
documentation: { example: 'foo/bar/mypkg/1.0-SNAPSHOT/mypkg-1.0-SNAPSHOT.jar' }
|
||||
end
|
||||
get ':id/*path', format: false do
|
||||
service_response = ::VirtualRegistries::Packages::Maven::HandleFileRequestService.new(
|
||||
registry: registry,
|
||||
current_user: current_user,
|
||||
params: { path: declared_params[:path] }
|
||||
).execute
|
||||
|
||||
send_error_response_from!(service_response: service_response) if service_response.error?
|
||||
send_successful_response_from(service_response: service_response)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ module BulkImports
|
|||
user_gid: id
|
||||
public_email: publicEmail
|
||||
username: username
|
||||
name: name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,10 @@ module BulkImports
|
|||
PROJECT_MEMBER_RELATIONS = %i[direct inherited invited_groups shared_into_ancestors].freeze
|
||||
|
||||
transformer Common::Transformers::ProhibitedAttributesTransformer
|
||||
# The transformer is skipped when bulk_import_importer_user_mapping is enabled
|
||||
transformer Common::Transformers::MemberAttributesTransformer
|
||||
# The transformer is skipped when bulk_import_importer_user_mapping is disabled
|
||||
transformer Import::BulkImports::Common::Transformers::SourceUserMemberAttributesTransformer
|
||||
|
||||
def extract(context)
|
||||
graphql_extractor.extract(context)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ module BulkImports
|
|||
module Transformers
|
||||
class MemberAttributesTransformer
|
||||
def transform(context, data)
|
||||
return data if context.importer_user_mapping_enabled?
|
||||
|
||||
user = find_user(data&.dig('user', 'public_email'))
|
||||
access_level = data&.dig('access_level', 'integer_value')
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,57 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Import
|
||||
module BulkImports
|
||||
module Common
|
||||
module Transformers
|
||||
class SourceUserMemberAttributesTransformer
|
||||
def transform(context, data)
|
||||
return data if !context.importer_user_mapping_enabled? || data.nil?
|
||||
|
||||
# Create source_user and placeholder user if they do not exists so
|
||||
# they can be mapped to contributions in subsequent pipelines
|
||||
source_user = find_or_create_source_user(context, data)
|
||||
|
||||
# For now, members are only created on subsequent imports for users
|
||||
# that have accepted the reassignment.
|
||||
# https://gitlab.com/gitlab-org/gitlab/-/issues/477845 will handle
|
||||
# membership for source_users mapped to placeholder users
|
||||
return unless source_user.accepted_status?
|
||||
|
||||
access_level = data.dig('access_level', 'integer_value')
|
||||
return unless valid_access_level?(access_level)
|
||||
|
||||
{
|
||||
user_id: source_user.mapped_user_id,
|
||||
access_level: access_level,
|
||||
created_at: data['created_at'],
|
||||
updated_at: data['updated_at'],
|
||||
expires_at: data['expires_at'],
|
||||
created_by_id: context.current_user.id
|
||||
}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def valid_access_level?(access_level)
|
||||
Gitlab::Access.options_with_owner.value?(access_level)
|
||||
end
|
||||
|
||||
def find_or_create_source_user(context, data)
|
||||
gid = data.dig('user', 'user_gid')
|
||||
|
||||
source_user_id = GlobalID.parse(gid).model_id
|
||||
source_name = data.dig('user', 'name')
|
||||
source_username = data.dig('user', 'username')
|
||||
|
||||
context.source_user_mapper.find_or_create_source_user(
|
||||
source_user_identifier: source_user_id,
|
||||
source_name: source_name,
|
||||
source_username: source_username
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1025,9 +1025,6 @@ msgstr ""
|
|||
msgid "%{linkStart}Advanced search%{linkEnd} is enabled."
|
||||
msgstr ""
|
||||
|
||||
msgid "%{link_start}Add a start date and due date%{link_end} to view a burndown chart."
|
||||
msgstr ""
|
||||
|
||||
msgid "%{listToShow}, and %{awardsListLength} more"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -3119,6 +3116,9 @@ msgstr ""
|
|||
msgid "Add Zoom meeting"
|
||||
msgstr ""
|
||||
|
||||
msgid "Add a %{link_start}start date and due date%{link_end} to view a burndown chart."
|
||||
msgstr ""
|
||||
|
||||
msgid "Add a GCP region"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -19725,6 +19725,27 @@ msgstr ""
|
|||
msgid "DuoCodeReview|I have encountered some issues while I was reviewing. Please try again later."
|
||||
msgstr ""
|
||||
|
||||
msgid "DuoEnterpriseTrial|Congratulations, your free GitLab Duo Enterprise trial is activated and will expire on %{exp_date}. The new license might take a minute to show on the page. To give members access to new GitLab Duo Enterprise features, %{assign_link_start}assign them%{assign_link_end} to GitLab Duo Enterprise seats."
|
||||
msgstr ""
|
||||
|
||||
msgid "DuoEnterpriseTrial|Enhance security and remediate vulnerabilities efficiently"
|
||||
msgstr ""
|
||||
|
||||
msgid "DuoEnterpriseTrial|Gain deeper insights into GitLab Duo usage patterns"
|
||||
msgstr ""
|
||||
|
||||
msgid "DuoEnterpriseTrial|GitLab Duo Enterprise is is your end-to-end AI partner for faster, more secure software development."
|
||||
msgstr ""
|
||||
|
||||
msgid "DuoEnterpriseTrial|GitLab Duo Enterprise is only available for purchase for Ultimate customers."
|
||||
msgstr ""
|
||||
|
||||
msgid "DuoEnterpriseTrial|Maintain control and keep your data safe"
|
||||
msgstr ""
|
||||
|
||||
msgid "DuoEnterpriseTrial|Quickly remedy broken pipelines to deliver products faster"
|
||||
msgstr ""
|
||||
|
||||
msgid "DuoEnterpriseTrial|Start your free Duo Enterprise trial"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -19734,6 +19755,9 @@ msgstr ""
|
|||
msgid "DuoEnterpriseTrial|Start your free GitLab Duo Enterprise trial on %{group_name}"
|
||||
msgstr ""
|
||||
|
||||
msgid "DuoEnterpriseTrial|Stay on top of regulatory requirements with self-hosted model deployment"
|
||||
msgstr ""
|
||||
|
||||
msgid "DuoEnterpriseTrial|We just need some additional information to activate your trial."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -57232,6 +57256,9 @@ msgstr ""
|
|||
msgid "Upstream Gitaly has been exhausted. Try again later"
|
||||
msgstr ""
|
||||
|
||||
msgid "Upstream already exists"
|
||||
msgstr ""
|
||||
|
||||
msgid "Upvotes"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
70
package.json
70
package.json
|
|
@ -84,41 +84,41 @@
|
|||
"@snowplow/browser-plugin-timezone": "^3.24.2",
|
||||
"@snowplow/browser-tracker": "^3.24.2",
|
||||
"@sourcegraph/code-host-integration": "0.0.95",
|
||||
"@tiptap/core": "^2.5.9",
|
||||
"@tiptap/extension-blockquote": "^2.5.9",
|
||||
"@tiptap/extension-bold": "^2.5.9",
|
||||
"@tiptap/extension-bubble-menu": "^2.5.9",
|
||||
"@tiptap/extension-bullet-list": "^2.5.9",
|
||||
"@tiptap/extension-code": "^2.5.9",
|
||||
"@tiptap/extension-code-block": "^2.5.9",
|
||||
"@tiptap/extension-code-block-lowlight": "^2.5.9",
|
||||
"@tiptap/extension-document": "^2.5.9",
|
||||
"@tiptap/extension-dropcursor": "^2.5.9",
|
||||
"@tiptap/extension-gapcursor": "^2.5.9",
|
||||
"@tiptap/extension-hard-break": "^2.5.9",
|
||||
"@tiptap/extension-heading": "^2.5.9",
|
||||
"@tiptap/extension-highlight": "^2.5.9",
|
||||
"@tiptap/extension-history": "^2.5.9",
|
||||
"@tiptap/extension-horizontal-rule": "^2.5.9",
|
||||
"@tiptap/extension-image": "^2.5.9",
|
||||
"@tiptap/extension-italic": "^2.5.9",
|
||||
"@tiptap/extension-link": "^2.5.9",
|
||||
"@tiptap/extension-list-item": "^2.5.9",
|
||||
"@tiptap/extension-ordered-list": "^2.5.9",
|
||||
"@tiptap/extension-paragraph": "^2.5.9",
|
||||
"@tiptap/extension-strike": "^2.5.9",
|
||||
"@tiptap/extension-subscript": "^2.5.9",
|
||||
"@tiptap/extension-superscript": "^2.5.9",
|
||||
"@tiptap/extension-table": "^2.5.9",
|
||||
"@tiptap/extension-table-cell": "^2.5.9",
|
||||
"@tiptap/extension-table-header": "^2.5.9",
|
||||
"@tiptap/extension-table-row": "^2.5.9",
|
||||
"@tiptap/extension-task-item": "^2.5.9",
|
||||
"@tiptap/extension-task-list": "^2.5.9",
|
||||
"@tiptap/extension-text": "^2.5.9",
|
||||
"@tiptap/pm": "^2.5.9",
|
||||
"@tiptap/suggestion": "^2.5.9",
|
||||
"@tiptap/vue-2": "^2.5.9",
|
||||
"@tiptap/core": "^2.6.0",
|
||||
"@tiptap/extension-blockquote": "^2.6.0",
|
||||
"@tiptap/extension-bold": "^2.6.0",
|
||||
"@tiptap/extension-bubble-menu": "^2.6.0",
|
||||
"@tiptap/extension-bullet-list": "^2.6.0",
|
||||
"@tiptap/extension-code": "^2.6.0",
|
||||
"@tiptap/extension-code-block": "^2.6.0",
|
||||
"@tiptap/extension-code-block-lowlight": "^2.6.0",
|
||||
"@tiptap/extension-document": "^2.6.0",
|
||||
"@tiptap/extension-dropcursor": "^2.6.0",
|
||||
"@tiptap/extension-gapcursor": "^2.6.0",
|
||||
"@tiptap/extension-hard-break": "^2.6.0",
|
||||
"@tiptap/extension-heading": "^2.6.0",
|
||||
"@tiptap/extension-highlight": "^2.6.0",
|
||||
"@tiptap/extension-history": "^2.6.0",
|
||||
"@tiptap/extension-horizontal-rule": "^2.6.0",
|
||||
"@tiptap/extension-image": "^2.6.0",
|
||||
"@tiptap/extension-italic": "^2.6.0",
|
||||
"@tiptap/extension-link": "^2.6.0",
|
||||
"@tiptap/extension-list-item": "^2.6.0",
|
||||
"@tiptap/extension-ordered-list": "^2.6.0",
|
||||
"@tiptap/extension-paragraph": "^2.6.0",
|
||||
"@tiptap/extension-strike": "^2.6.0",
|
||||
"@tiptap/extension-subscript": "^2.6.0",
|
||||
"@tiptap/extension-superscript": "^2.6.0",
|
||||
"@tiptap/extension-table": "^2.6.0",
|
||||
"@tiptap/extension-table-cell": "^2.6.0",
|
||||
"@tiptap/extension-table-header": "^2.6.0",
|
||||
"@tiptap/extension-table-row": "^2.6.0",
|
||||
"@tiptap/extension-task-item": "^2.6.0",
|
||||
"@tiptap/extension-task-list": "^2.6.0",
|
||||
"@tiptap/extension-text": "^2.6.0",
|
||||
"@tiptap/pm": "^2.6.0",
|
||||
"@tiptap/suggestion": "^2.6.0",
|
||||
"@tiptap/vue-2": "^2.6.0",
|
||||
"@vue/apollo-components": "^4.0.0-beta.4",
|
||||
"@vue/apollo-option": "^4.0.0-beta.4",
|
||||
"apollo-upload-client": "15.0.0",
|
||||
|
|
|
|||
|
|
@ -58,7 +58,8 @@ RSpec.describe 'Work item children', :js, feature_category: :team_planning do
|
|||
end
|
||||
end
|
||||
|
||||
it 'adds a new child task', :aggregate_failures do
|
||||
it 'adds a new child task', :aggregate_failures,
|
||||
quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/461666' do
|
||||
allow(Gitlab::QueryLimiting::Transaction).to receive(:threshold).and_return(108)
|
||||
|
||||
within_testid('work-item-links') do
|
||||
|
|
|
|||
|
|
@ -1,14 +1,20 @@
|
|||
import { GlNavItem, GlTabs, GlTab } from '@gitlab/ui';
|
||||
import { GlTabs, GlTab } from '@gitlab/ui';
|
||||
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
||||
|
||||
import { visitUrl } from '~/lib/utils/url_utility';
|
||||
import ExclusionsTabs from '~/integrations/beyond_identity/components/exclusions_tabs.vue';
|
||||
|
||||
jest.mock('~/lib/utils/url_utility', () => ({
|
||||
...jest.requireActual('~/lib/utils/url_utility'),
|
||||
visitUrl: jest.fn(),
|
||||
}));
|
||||
|
||||
describe('ExclusionsTabs component', () => {
|
||||
let wrapper;
|
||||
const editPath = 'path/to/edit';
|
||||
|
||||
const findTabs = () => wrapper.findComponent(GlTabs);
|
||||
const findNavItem = () => wrapper.findComponent(GlNavItem);
|
||||
const findTab = () => wrapper.findComponent(GlTab);
|
||||
const findAllTabs = () => wrapper.findAllComponents(GlTab);
|
||||
|
||||
const createComponent = () =>
|
||||
shallowMountExtended(ExclusionsTabs, {
|
||||
|
|
@ -28,12 +34,21 @@ describe('ExclusionsTabs component', () => {
|
|||
});
|
||||
|
||||
it('renders a nav item for Settings', () => {
|
||||
expect(findNavItem().text()).toBe('Settings');
|
||||
expect(findNavItem().attributes('href')).toBe(editPath);
|
||||
const tab = findAllTabs().at(0);
|
||||
expect(tab.attributes('title')).toBe('Settings');
|
||||
});
|
||||
|
||||
it('renders a tab for Exclusions', () => {
|
||||
expect(findTab().text()).toBe('Exclusions');
|
||||
const tab = findAllTabs().at(1);
|
||||
expect(tab.attributes('title')).toBe('Exclusions');
|
||||
});
|
||||
|
||||
it('redirects to editPath when the settings tab is clicked', async () => {
|
||||
const tab = findAllTabs().at(0);
|
||||
|
||||
await tab.vm.$emit('click');
|
||||
|
||||
expect(visitUrl).toHaveBeenCalledWith(editPath);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,16 +1,22 @@
|
|||
import { mount, shallowMount } from '@vue/test-utils';
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import { GlBadge, GlTab } from '@gitlab/ui';
|
||||
|
||||
import { visitUrl } from '~/lib/utils/url_utility';
|
||||
import IntegrationTabs from '~/integrations/overrides/components/integration_tabs.vue';
|
||||
import { settingsTabTitle, overridesTabTitle } from '~/integrations/constants';
|
||||
|
||||
jest.mock('~/lib/utils/url_utility', () => ({
|
||||
...jest.requireActual('~/lib/utils/url_utility'),
|
||||
visitUrl: jest.fn(),
|
||||
}));
|
||||
|
||||
describe('IntegrationTabs', () => {
|
||||
let wrapper;
|
||||
|
||||
const editPath = 'mock/edit';
|
||||
|
||||
const createComponent = ({ mountFn = shallowMount, props = {} } = {}) => {
|
||||
wrapper = mountFn(IntegrationTabs, {
|
||||
const createComponent = (props = {}) => {
|
||||
wrapper = shallowMount(IntegrationTabs, {
|
||||
propsData: props,
|
||||
provide: {
|
||||
editPath,
|
||||
|
|
@ -22,28 +28,37 @@ describe('IntegrationTabs', () => {
|
|||
};
|
||||
|
||||
const findGlBadge = () => wrapper.findComponent(GlBadge);
|
||||
const findGlTab = () => wrapper.findComponent(GlTab);
|
||||
const findSettingsLink = () => wrapper.find('a');
|
||||
const findAllTabs = () => wrapper.findAllComponents(GlTab);
|
||||
|
||||
describe('template', () => {
|
||||
it('renders "Settings" tab as a link', () => {
|
||||
createComponent({ mountFn: mount });
|
||||
it('renders "Settings" tab', () => {
|
||||
createComponent();
|
||||
|
||||
expect(findSettingsLink().text()).toMatchInterpolatedText(settingsTabTitle);
|
||||
expect(findSettingsLink().attributes('href')).toBe(editPath);
|
||||
const tab = findAllTabs().at(0);
|
||||
|
||||
expect(tab.exists()).toBe(true);
|
||||
expect(tab.attributes('title')).toBe(settingsTabTitle);
|
||||
});
|
||||
|
||||
it('redirects to editPath when the settings tab is clicked', async () => {
|
||||
createComponent();
|
||||
|
||||
const tab = findAllTabs().at(0);
|
||||
|
||||
await tab.vm.$emit('click');
|
||||
|
||||
expect(visitUrl).toHaveBeenCalledWith(editPath);
|
||||
});
|
||||
|
||||
it('renders "Projects using custom settings" tab as active', () => {
|
||||
const projectOverridesCount = '1';
|
||||
|
||||
createComponent({
|
||||
props: { projectOverridesCount },
|
||||
});
|
||||
createComponent({ projectOverridesCount });
|
||||
|
||||
expect(findGlTab().exists()).toBe(true);
|
||||
expect(findGlTab().text()).toMatchInterpolatedText(
|
||||
`${overridesTabTitle} ${projectOverridesCount}`,
|
||||
);
|
||||
const tab = findAllTabs().at(1);
|
||||
|
||||
expect(tab.exists()).toBe(true);
|
||||
expect(tab.text()).toMatchInterpolatedText(`${overridesTabTitle} ${projectOverridesCount}`);
|
||||
expect(findGlBadge().text()).toBe(projectOverridesCount);
|
||||
});
|
||||
|
||||
|
|
@ -51,8 +66,10 @@ describe('IntegrationTabs', () => {
|
|||
it('renders "Projects using custom settings" tab without count', () => {
|
||||
createComponent();
|
||||
|
||||
expect(findGlTab().exists()).toBe(true);
|
||||
expect(findGlTab().text()).toMatchInterpolatedText(overridesTabTitle);
|
||||
const tab = findAllTabs().at(1);
|
||||
|
||||
expect(tab.exists()).toBe(true);
|
||||
expect(tab.text()).toMatchInterpolatedText(overridesTabTitle);
|
||||
expect(findGlBadge().exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ describe('PlaceholdersTabApp', () => {
|
|||
apolloProvider: mockApollo,
|
||||
store,
|
||||
provide: {
|
||||
reassignmentCsvDownloadPath: 'foo/bar',
|
||||
reassignmentCsvPath: 'foo/bar',
|
||||
group: mockGroup,
|
||||
...provide,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ describe('CsvUploadModal', () => {
|
|||
let wrapper;
|
||||
|
||||
const defaultInjectedAttributes = {
|
||||
reassignmentCsvDownloadPath: 'foo/bar',
|
||||
reassignmentCsvPath: 'foo/bar',
|
||||
};
|
||||
|
||||
const findDownloadLink = () => wrapper.findByTestId('csv-download-button');
|
||||
|
|
@ -29,8 +29,6 @@ describe('CsvUploadModal', () => {
|
|||
const downloadLink = findDownloadLink();
|
||||
|
||||
expect(downloadLink.exists()).toBe(true);
|
||||
expect(downloadLink.attributes('href')).toBe(
|
||||
defaultInjectedAttributes.reassignmentCsvDownloadPath,
|
||||
);
|
||||
expect(downloadLink.attributes('href')).toBe(defaultInjectedAttributes.reassignmentCsvPath);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -56,7 +56,6 @@ describe('WorkItemDescriptionRendered', () => {
|
|||
return true;
|
||||
},
|
||||
},
|
||||
hasWorkItemsBeta: true,
|
||||
});
|
||||
|
||||
expect(wrapper.find('[data-test-id="description-read-more"]').exists()).toBe(true);
|
||||
|
|
@ -75,7 +74,6 @@ describe('WorkItemDescriptionRendered', () => {
|
|||
return false;
|
||||
},
|
||||
},
|
||||
hasWorkItemsBeta: true,
|
||||
});
|
||||
|
||||
expect(wrapper.find('[data-test-id="description-read-more"]').exists()).toBe(false);
|
||||
|
|
|
|||
|
|
@ -57,7 +57,8 @@ RSpec.describe Projects::Ml::ModelRegistryHelper, feature_category: :mlops do
|
|||
'mlflowTrackingUrl' => "http://localhost/api/v4/projects/#{project.id}/ml/mlflow/",
|
||||
'modelId' => model.id,
|
||||
'modelName' => 'cool_model',
|
||||
'latestVersion' => model.latest_version.version
|
||||
'latestVersion' => model.latest_version.version,
|
||||
"markdownPreviewPath" => "http://localhost/#{project.full_path}/-/ml/preview_markdown"
|
||||
})
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe API::Entities::VirtualRegistries::Packages::Maven::Upstream, feature_category: :virtual_registry do
|
||||
let(:upstream) { build_stubbed(:virtual_registries_packages_maven_upstream) }
|
||||
|
||||
subject { described_class.new(upstream).as_json }
|
||||
|
||||
it { is_expected.to include(:id, :group_id, :url, :created_at, :updated_at) }
|
||||
end
|
||||
|
|
@ -3,8 +3,9 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe BulkImports::Common::Pipelines::MembersPipeline, feature_category: :importers do
|
||||
let_it_be(:default_organization) { create(:organization, :default) }
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:bulk_import) { create(:bulk_import, user: user) }
|
||||
let_it_be(:bulk_import) { create(:bulk_import, :with_configuration, user: user) }
|
||||
let_it_be(:member_user1) { create(:user, email: 'email1@email.com') }
|
||||
let_it_be(:member_user2) { create(:user, email: 'email2@email.com') }
|
||||
let_it_be(:member_data) do
|
||||
|
|
@ -29,7 +30,7 @@ RSpec.describe BulkImports::Common::Pipelines::MembersPipeline, feature_category
|
|||
allow(pipeline).to receive(:set_source_objects_counter)
|
||||
end
|
||||
|
||||
def extracted_data(email:, has_next_page: false)
|
||||
def extracted_data(email: '', id: 1, has_next_page: false)
|
||||
data = {
|
||||
'created_at' => '2020-01-01T00:00:00Z',
|
||||
'updated_at' => '2020-01-02T00:00:00Z',
|
||||
|
|
@ -38,7 +39,10 @@ RSpec.describe BulkImports::Common::Pipelines::MembersPipeline, feature_category
|
|||
'integer_value' => 30
|
||||
},
|
||||
'user' => {
|
||||
'public_email' => email
|
||||
'user_gid' => "gid://gitlab/User/#{id}",
|
||||
'public_email' => email,
|
||||
'name' => 'source_name',
|
||||
'username' => 'source_username'
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -71,6 +75,56 @@ RSpec.describe BulkImports::Common::Pipelines::MembersPipeline, feature_category
|
|||
{ user_id: member_user2.id, access_level: 30 }
|
||||
)
|
||||
end
|
||||
|
||||
context 'when importer_user_mapping is enabled' do
|
||||
let!(:import_source_user) do
|
||||
create(:import_source_user,
|
||||
namespace: context.portable.root_ancestor,
|
||||
source_hostname: bulk_import.configuration.source_hostname,
|
||||
import_type: Import::SOURCE_DIRECT_TRANSFER,
|
||||
source_user_identifier: '101'
|
||||
)
|
||||
end
|
||||
|
||||
let!(:reassigned_import_source_user) do
|
||||
create(:import_source_user,
|
||||
:completed,
|
||||
namespace: context.portable.root_ancestor,
|
||||
source_hostname: bulk_import.configuration.source_hostname,
|
||||
import_type: Import::SOURCE_DIRECT_TRANSFER,
|
||||
source_user_identifier: '102'
|
||||
)
|
||||
end
|
||||
|
||||
before do
|
||||
allow(context).to receive(:importer_user_mapping_enabled?).and_return(true)
|
||||
|
||||
first_page = extracted_data(id: import_source_user.source_user_identifier, has_next_page: true)
|
||||
second_page = extracted_data(id: reassigned_import_source_user.source_user_identifier, has_next_page: true)
|
||||
last_page = extracted_data(id: 103)
|
||||
|
||||
allow_next_instance_of(BulkImports::Common::Extractors::GraphqlExtractor) do |extractor|
|
||||
allow(extractor).to receive(:extract).and_return(first_page, second_page, last_page)
|
||||
end
|
||||
end
|
||||
|
||||
it 'finds and creates source users and creates membership for the reassigned users' do
|
||||
expect { pipeline.run }.to change { portable.members.count }.by(1).and(
|
||||
change { Import::SourceUser.count }.by(1)
|
||||
)
|
||||
|
||||
expect(Import::SourceUser.last).to have_attributes(
|
||||
source_user_identifier: '103',
|
||||
namespace: context.portable.root_ancestor,
|
||||
source_hostname: bulk_import.configuration.source_hostname,
|
||||
import_type: Import::SOURCE_DIRECT_TRANSFER.to_s
|
||||
)
|
||||
|
||||
expect(members).to contain_exactly(
|
||||
{ user_id: reassigned_import_source_user.reassign_to_user.id, access_level: 30 }
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#load' do
|
||||
|
|
|
|||
|
|
@ -140,6 +140,16 @@ RSpec.describe BulkImports::Common::Transformers::MemberAttributesTransformer, f
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when importer_user_mapping is enabled' do
|
||||
before do
|
||||
allow(context).to receive(:importer_user_mapping_enabled?).and_return(true)
|
||||
end
|
||||
|
||||
it 'does not transform the data' do
|
||||
expect(subject.transform(context, { 'id' => 1 })).to eq({ 'id' => 1 })
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a project' do
|
||||
|
|
|
|||
|
|
@ -0,0 +1,159 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Import::BulkImports::Common::Transformers::SourceUserMemberAttributesTransformer,
|
||||
:with_current_organization, feature_category: :importers do
|
||||
let_it_be(:default_organization) { create(:organization, :default) }
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:bulk_import) { create(:bulk_import, :with_configuration, user: user) }
|
||||
|
||||
shared_examples 'import source user members attribute transformer' do
|
||||
let_it_be(:tracker) { create(:bulk_import_tracker, entity: entity) }
|
||||
let_it_be(:context) { BulkImports::Pipeline::Context.new(tracker) }
|
||||
|
||||
let_it_be(:import_source_user) do
|
||||
create(:import_source_user,
|
||||
namespace: context.portable.root_ancestor,
|
||||
source_hostname: bulk_import.configuration.source_hostname,
|
||||
import_type: Import::SOURCE_DIRECT_TRANSFER,
|
||||
source_user_identifier: '101'
|
||||
)
|
||||
end
|
||||
|
||||
let_it_be(:reassigned_import_source_user) do
|
||||
create(:import_source_user, :completed,
|
||||
namespace: context.portable.root_ancestor,
|
||||
source_hostname: bulk_import.configuration.source_hostname,
|
||||
import_type: Import::SOURCE_DIRECT_TRANSFER,
|
||||
source_user_identifier: '102'
|
||||
)
|
||||
end
|
||||
|
||||
let(:importer_user_mapping_enabled) { true }
|
||||
|
||||
before do
|
||||
allow(context).to receive(:importer_user_mapping_enabled?).and_return(importer_user_mapping_enabled)
|
||||
end
|
||||
|
||||
context 'when an import source user exists and is mapped to a user' do
|
||||
let(:data) { member_data(source_user_id: reassigned_import_source_user.source_user_identifier) }
|
||||
|
||||
it 'does not create an import source user' do
|
||||
expect { subject.transform(context, data) }.not_to change { Import::SourceUser.count }
|
||||
end
|
||||
|
||||
it 'returns member hash with the reassigned_to_user_id' do
|
||||
expect(subject.transform(context, data)).to eq(
|
||||
access_level: 30,
|
||||
user_id: reassigned_import_source_user.reassign_to_user_id,
|
||||
created_by_id: user.id,
|
||||
created_at: '2020-01-01T00:00:00Z',
|
||||
updated_at: '2020-01-01T00:00:00Z',
|
||||
expires_at: nil
|
||||
)
|
||||
end
|
||||
|
||||
context 'when access level is invalid' do
|
||||
let(:data) do
|
||||
member_data(access_level: 999, source_user_id: reassigned_import_source_user.source_user_identifier)
|
||||
end
|
||||
|
||||
it 'ignores record' do
|
||||
expect(subject.transform(context, data)).to eq(nil)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when importer_user_mapping is disabled' do
|
||||
let(:importer_user_mapping_enabled) { false }
|
||||
|
||||
it 'does not create an import source user' do
|
||||
expect { subject.transform(context, data) }.not_to change { Import::SourceUser.count }
|
||||
end
|
||||
|
||||
it 'does not transform the data' do
|
||||
expect(subject.transform(context, { id: 1 })).to eq({ id: 1 })
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when an import source user does not exist' do
|
||||
let(:data) { member_data(source_user_id: 999) }
|
||||
|
||||
it 'creates an import source user' do
|
||||
expect { subject.transform(context, data) }.to change { Import::SourceUser.count }.by(1)
|
||||
|
||||
expect(Import::SourceUser.last).to have_attributes(
|
||||
source_user_identifier: '999',
|
||||
source_username: 'source_username',
|
||||
source_name: 'source_name',
|
||||
import_type: Import::SOURCE_DIRECT_TRANSFER.to_s
|
||||
)
|
||||
end
|
||||
|
||||
it 'retuns nil' do
|
||||
expect(subject.transform(context, data)).to eq(nil)
|
||||
end
|
||||
|
||||
context 'when importer_user_mapping is disabled' do
|
||||
let(:importer_user_mapping_enabled) { false }
|
||||
|
||||
it 'does not create an import source user' do
|
||||
expect { subject.transform(context, data) }.not_to change { Import::SourceUser.count }
|
||||
end
|
||||
|
||||
it 'does not transform the data' do
|
||||
expect(subject.transform(context, { id: 1 })).to eq({ id: 1 })
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when an import source user exists and is mapped to placeholder user' do
|
||||
let(:data) { member_data(source_user_id: import_source_user.source_user_identifier) }
|
||||
|
||||
it 'does not create an import source user' do
|
||||
expect { subject.transform(context, data) }.not_to change { Import::SourceUser.count }
|
||||
end
|
||||
|
||||
it 'retuns nil' do
|
||||
expect(subject.transform(context, data)).to eq(nil)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when data is nil' do
|
||||
it 'returns nil' do
|
||||
expect(subject.transform(context, nil)).to eq(nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a project' do
|
||||
let_it_be(:project) { create(:project) }
|
||||
let_it_be(:entity) { create(:bulk_import_entity, :project_entity, bulk_import: bulk_import, project: project) }
|
||||
|
||||
include_examples 'import source user members attribute transformer'
|
||||
end
|
||||
|
||||
context 'with a group' do
|
||||
let_it_be(:group) { create(:group) }
|
||||
let_it_be(:entity) { create(:bulk_import_entity, bulk_import: bulk_import, group: group) }
|
||||
|
||||
include_examples 'import source user members attribute transformer'
|
||||
end
|
||||
|
||||
def member_data(source_user_id:, access_level: 30)
|
||||
{
|
||||
'created_at' => '2020-01-01T00:00:00Z',
|
||||
'updated_at' => '2020-01-01T00:00:00Z',
|
||||
'expires_at' => nil,
|
||||
'access_level' => {
|
||||
'integer_value' => access_level
|
||||
},
|
||||
'user' => {
|
||||
'user_gid' => "gid://gitlab/User/#{source_user_id}",
|
||||
'username' => 'source_username',
|
||||
'name' => 'source_name'
|
||||
}
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
require_migration!
|
||||
|
||||
RSpec.describe RemoveCrmContactsWidgetFromWorkItemTypes, :migration, feature_category: :team_planning do
|
||||
let(:widget_name) { described_class::WIDGET_NAME }
|
||||
let(:work_item_types) { described_class::WORK_ITEM_TYPES }
|
||||
|
||||
let(:migration) { described_class.new }
|
||||
let(:work_item_definitions) { table(:work_item_widget_definitions) }
|
||||
let(:work_item_type_count) { work_item_types.size }
|
||||
let(:find_method_name) { :find_by_name_and_namespace_id }
|
||||
|
||||
describe '#up', :migration_with_transaction do
|
||||
it "removes definitions for widget" do
|
||||
migration.down
|
||||
|
||||
expect { migrate! }.to change { work_item_definitions.count }.by(-work_item_type_count)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#down', :migration_with_transaction do
|
||||
before do
|
||||
migrate!
|
||||
end
|
||||
|
||||
it "creates widget definition in all types" do
|
||||
work_item_definitions.where(name: widget_name).delete_all
|
||||
|
||||
expect { migration.down }.to change { work_item_definitions.count }.by(work_item_type_count)
|
||||
expect(work_item_definitions.all.pluck(:name)).to include(widget_name)
|
||||
end
|
||||
|
||||
it 'logs a warning if the type is missing' do
|
||||
type_name = work_item_types.first
|
||||
|
||||
allow(described_class::WorkItemType).to receive(find_method_name).and_call_original
|
||||
allow(described_class::WorkItemType).to receive(find_method_name)
|
||||
.with(type_name, nil).and_return(nil)
|
||||
|
||||
expect(Gitlab::AppLogger).to receive(:warn).with("type #{type_name} is missing, not adding widget")
|
||||
migration.down
|
||||
end
|
||||
|
||||
context 'when the widget already exists' do
|
||||
let(:work_item_types_table) { table(:work_item_types) }
|
||||
|
||||
before do
|
||||
work_item_types.each do |type_name|
|
||||
type = work_item_types_table.find_by_name(type_name)
|
||||
work_item_definitions.create!(
|
||||
name: widget_name,
|
||||
work_item_type_id: type.id,
|
||||
widget_type: described_class::WIDGET_ENUM_VALUE
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
it 'upserts the widget definitions and raises no error' do
|
||||
expect { migration.down }.to not_change {
|
||||
work_item_definitions.where(name: widget_name).count
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -253,6 +253,28 @@ RSpec.describe Import::SourceUser, type: :model, feature_category: :importers do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#mapped_user_id' do
|
||||
let_it_be(:source_user) { build(:import_source_user, :with_reassign_to_user) }
|
||||
|
||||
subject(:mapped_user_id) { source_user.mapped_user_id }
|
||||
|
||||
before do
|
||||
allow(source_user).to receive(:accepted_status?).and_return(accepted)
|
||||
end
|
||||
|
||||
context 'when accepted' do
|
||||
let(:accepted) { true }
|
||||
|
||||
it { is_expected.to eq(source_user.reassign_to_user_id) }
|
||||
end
|
||||
|
||||
context 'when not accepted' do
|
||||
let(:accepted) { false }
|
||||
|
||||
it { is_expected.to eq(source_user.placeholder_user_id) }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#reassignable_status?' do
|
||||
reassignable_statuses = [:pending_reassignment, :rejected]
|
||||
all_states = described_class.state_machines[:status].states
|
||||
|
|
|
|||
|
|
@ -174,4 +174,10 @@ RSpec.describe VirtualRegistries::Packages::Maven::Upstream, type: :model, featu
|
|||
it { is_expected.to eq(expected_headers) }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#as_json' do
|
||||
subject { upstream.as_json }
|
||||
|
||||
it { is_expected.not_to include('username', 'password') }
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,83 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'Editing of a machine learning model', feature_category: :mlops do
|
||||
include GraphqlHelpers
|
||||
|
||||
let_it_be(:project) { create(:project) }
|
||||
let_it_be(:current_user) { project.owner }
|
||||
let_it_be(:guest) { create(:user) }
|
||||
|
||||
let(:name) { 'some_name' }
|
||||
let(:description) { 'A description' }
|
||||
|
||||
let(:input) { { project_path: project.full_path, name: name, description: description } }
|
||||
|
||||
let(:model) { create(:ml_models, project: project, name: name, description: description) }
|
||||
|
||||
let(:new_description) { 'A new description' }
|
||||
let(:edit_input) { { project_path: project.full_path, name: name, description: new_description, model_id: model.id } }
|
||||
|
||||
let(:mutation) { graphql_mutation(:ml_model_edit, edit_input, nil, ['version']) }
|
||||
let(:mutation_response) { graphql_mutation_response(:ml_model_edit) }
|
||||
|
||||
context 'when user is not allowed write changes' do
|
||||
before do
|
||||
allow(Ability).to receive(:allowed?).and_call_original
|
||||
allow(Ability).to receive(:allowed?)
|
||||
.with(current_user, :write_model_registry, project)
|
||||
.and_return(false)
|
||||
end
|
||||
|
||||
it_behaves_like 'a mutation that returns a top-level access error'
|
||||
end
|
||||
|
||||
context 'when the user is not part of the project' do
|
||||
it 'returns an error' do
|
||||
post_graphql_mutation(mutation, current_user: guest)
|
||||
expect { mutation }.to not_change { ::Ml::Model.count }
|
||||
expect(mutation_response).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the user is authenticated' do
|
||||
context 'when the model does not exist' do
|
||||
it 'returns an error' do
|
||||
edit_input[:model_id] = 0
|
||||
|
||||
post_graphql_mutation(mutation, current_user: current_user)
|
||||
|
||||
expect(mutation_response['errors']).not_to be_empty
|
||||
expect(mutation_response['errors']).to match_array(['Model not found'])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the model exists' do
|
||||
before do
|
||||
model
|
||||
end
|
||||
|
||||
it 'updates the model description' do
|
||||
post_graphql_mutation(mutation, current_user: current_user)
|
||||
|
||||
expect(mutation_response['errors']).to be_empty
|
||||
|
||||
model.reload
|
||||
expect(model.name).to eq(name)
|
||||
expect(model.description).to eq(new_description)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the model is not part of the project' do
|
||||
let(:model) { create(:ml_models, name: name, description: description) }
|
||||
|
||||
it 'returns an error' do
|
||||
post_graphql_mutation(mutation, current_user: current_user)
|
||||
|
||||
expect(mutation_response['errors']).not_to be_empty
|
||||
expect(mutation_response['errors']).to match_array(['Model not found'])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -7,11 +7,480 @@ RSpec.describe API::VirtualRegistries::Packages::Maven, feature_category: :virtu
|
|||
include WorkhorseHelpers
|
||||
include HttpBasicAuthHelpers
|
||||
|
||||
let_it_be(:registry) { create(:virtual_registries_packages_maven_registry, :with_upstream) }
|
||||
let_it_be(:project) { create(:project, namespace: registry.group) }
|
||||
let_it_be_with_reload(:registry) { create(:virtual_registries_packages_maven_registry) }
|
||||
let_it_be(:upstream) { create(:virtual_registries_packages_maven_upstream, registry: registry) }
|
||||
let_it_be(:group) { registry.group }
|
||||
let_it_be(:project) { create(:project, namespace: group) }
|
||||
let_it_be(:user) { project.creator }
|
||||
let_it_be(:personal_access_token) { create(:personal_access_token, user: user) }
|
||||
let_it_be(:job) { create(:ci_build, :running, user: user, project: project) }
|
||||
let_it_be(:deploy_token) do
|
||||
create(:deploy_token, :group, groups: [group], read_virtual_registry: true)
|
||||
end
|
||||
|
||||
let(:upstream) { registry.upstream }
|
||||
let_it_be(:headers) { user_basic_auth_header(user, personal_access_token) }
|
||||
|
||||
shared_examples 'disabled feature flag' do
|
||||
before do
|
||||
stub_feature_flags(virtual_registry_maven: false)
|
||||
end
|
||||
|
||||
it_behaves_like 'returning response status', :not_found
|
||||
end
|
||||
|
||||
shared_examples 'disabled dependency proxy' do
|
||||
before do
|
||||
stub_config(dependency_proxy: { enabled: false })
|
||||
end
|
||||
|
||||
it_behaves_like 'returning response status', :not_found
|
||||
end
|
||||
|
||||
shared_examples 'not authenticated user' do
|
||||
let(:headers) { {} }
|
||||
|
||||
it_behaves_like 'returning response status', :unauthorized
|
||||
end
|
||||
|
||||
before do
|
||||
stub_config(dependency_proxy: { enabled: true })
|
||||
end
|
||||
|
||||
describe 'GET /api/v4/virtual_registries/packages/maven/registries/:id/upstreams' do
|
||||
let(:registry_id) { registry.id }
|
||||
let(:url) { "/virtual_registries/packages/maven/registries/#{registry_id}/upstreams" }
|
||||
|
||||
subject(:api_request) { get api(url), headers: headers }
|
||||
|
||||
shared_examples 'successful response' do
|
||||
it 'returns a successful response' do
|
||||
api_request
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(Gitlab::Json.parse(response.body)).to contain_exactly(registry.upstream.as_json)
|
||||
end
|
||||
end
|
||||
|
||||
it { is_expected.to have_request_urgency(:low) }
|
||||
|
||||
it_behaves_like 'disabled feature flag'
|
||||
it_behaves_like 'disabled dependency proxy'
|
||||
it_behaves_like 'not authenticated user'
|
||||
|
||||
context 'with valid registry' do
|
||||
it_behaves_like 'successful response'
|
||||
end
|
||||
|
||||
context 'with invalid registry' do
|
||||
where(:registry_id, :status) do
|
||||
non_existing_record_id | :not_found
|
||||
'foo' | :bad_request
|
||||
'' | :bad_request
|
||||
end
|
||||
|
||||
with_them do
|
||||
it_behaves_like 'returning response status', params[:status]
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a non member user' do
|
||||
let_it_be(:user) { create(:user) }
|
||||
|
||||
where(:group_access_level, :status) do
|
||||
'PUBLIC' | :ok
|
||||
'INTERNAL' | :ok
|
||||
'PRIVATE' | :forbidden
|
||||
end
|
||||
|
||||
with_them do
|
||||
before do
|
||||
group.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_access_level, false))
|
||||
end
|
||||
|
||||
if params[:status] == :ok
|
||||
it_behaves_like 'successful response'
|
||||
else
|
||||
it_behaves_like 'returning response status', params[:status]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'for authentication' do
|
||||
where(:token, :sent_as, :status) do
|
||||
:personal_access_token | :header | :ok
|
||||
:personal_access_token | :basic_auth | :ok
|
||||
:deploy_token | :header | :ok
|
||||
:deploy_token | :basic_auth | :ok
|
||||
:job_token | :header | :ok
|
||||
:job_token | :basic_auth | :ok
|
||||
end
|
||||
|
||||
with_them do
|
||||
let(:headers) do
|
||||
case sent_as
|
||||
when :header
|
||||
token_header(token)
|
||||
when :basic_auth
|
||||
token_basic_auth(token)
|
||||
end
|
||||
end
|
||||
|
||||
it_behaves_like 'returning response status', params[:status]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v4/virtual_registries/packages/maven/registries/:id/upstreams' do
|
||||
let(:registry_id) { registry.id }
|
||||
let(:url) { "/virtual_registries/packages/maven/registries/#{registry_id}/upstreams" }
|
||||
let(:params) { { url: 'http://example.com' } }
|
||||
|
||||
subject(:api_request) { post api(url), headers: headers, params: params }
|
||||
|
||||
shared_examples 'successful response' do
|
||||
it 'returns a successful response' do
|
||||
expect { api_request }.to change { ::VirtualRegistries::Packages::Maven::Upstream.count }.by(1)
|
||||
.and change { ::VirtualRegistries::Packages::Maven::RegistryUpstream.count }.by(1)
|
||||
end
|
||||
end
|
||||
|
||||
it { is_expected.to have_request_urgency(:low) }
|
||||
|
||||
it_behaves_like 'disabled feature flag'
|
||||
it_behaves_like 'disabled dependency proxy'
|
||||
it_behaves_like 'not authenticated user'
|
||||
|
||||
context 'with valid params' do
|
||||
where(:user_role, :status) do
|
||||
:owner | :created
|
||||
:maintainer | :created
|
||||
:developer | :forbidden
|
||||
:reporter | :forbidden
|
||||
:guest | :forbidden
|
||||
end
|
||||
|
||||
with_them do
|
||||
before do
|
||||
registry.upstream&.destroy!
|
||||
group.send(:"add_#{user_role}", user)
|
||||
end
|
||||
|
||||
if params[:status] == :created
|
||||
it_behaves_like 'successful response'
|
||||
else
|
||||
it_behaves_like 'returning response status', params[:status]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with invalid registry' do
|
||||
where(:registry_id, :status) do
|
||||
non_existing_record_id | :not_found
|
||||
'foo' | :bad_request
|
||||
'' | :not_found
|
||||
end
|
||||
|
||||
with_them do
|
||||
it_behaves_like 'returning response status', params[:status]
|
||||
end
|
||||
end
|
||||
|
||||
context 'for params' do
|
||||
where(:params, :status) do
|
||||
{ url: 'http://example.com', username: 'test', password: 'test' } | :created
|
||||
{ url: '', username: 'test', password: 'test' } | :bad_request
|
||||
{ url: 'http://example.com', username: 'test' } | :bad_request
|
||||
{} | :bad_request
|
||||
end
|
||||
|
||||
before do
|
||||
registry.upstream&.destroy!
|
||||
end
|
||||
|
||||
before_all do
|
||||
group.add_maintainer(user)
|
||||
end
|
||||
|
||||
with_them do
|
||||
if params[:status] == :created
|
||||
it_behaves_like 'successful response'
|
||||
else
|
||||
it_behaves_like 'returning response status', params[:status]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with existing upstream' do
|
||||
before_all do
|
||||
group.add_maintainer(user)
|
||||
create(:virtual_registries_packages_maven_upstream, registry: registry)
|
||||
end
|
||||
|
||||
it_behaves_like 'returning response status', :conflict
|
||||
end
|
||||
|
||||
context 'for authentication' do
|
||||
before_all do
|
||||
group.add_maintainer(user)
|
||||
end
|
||||
|
||||
before do
|
||||
registry.upstream&.destroy!
|
||||
end
|
||||
|
||||
where(:token, :sent_as, :status) do
|
||||
:personal_access_token | :header | :created
|
||||
:personal_access_token | :basic_auth | :created
|
||||
:deploy_token | :header | :forbidden
|
||||
:deploy_token | :basic_auth | :forbidden
|
||||
:job_token | :header | :created
|
||||
:job_token | :basic_auth | :created
|
||||
end
|
||||
|
||||
with_them do
|
||||
let(:headers) do
|
||||
case sent_as
|
||||
when :header
|
||||
token_header(token)
|
||||
when :basic_auth
|
||||
token_basic_auth(token)
|
||||
end
|
||||
end
|
||||
|
||||
if params[:status] == :created
|
||||
it_behaves_like 'successful response'
|
||||
else
|
||||
it_behaves_like 'returning response status', params[:status]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET /api/v4/virtual_registries/packages/maven/registries/:id/upstreams/:upstream_id' do
|
||||
let(:url) { "/virtual_registries/packages/maven/registries/#{registry.id}/upstreams/#{upstream.id}" }
|
||||
|
||||
subject(:api_request) { get api(url), headers: headers }
|
||||
|
||||
shared_examples 'successful response' do
|
||||
it 'returns a successful response' do
|
||||
api_request
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(Gitlab::Json.parse(response.body)).to eq(registry.upstream.as_json)
|
||||
end
|
||||
end
|
||||
|
||||
it { is_expected.to have_request_urgency(:low) }
|
||||
|
||||
it_behaves_like 'disabled feature flag'
|
||||
it_behaves_like 'disabled dependency proxy'
|
||||
it_behaves_like 'not authenticated user'
|
||||
|
||||
context 'with valid params' do
|
||||
it_behaves_like 'successful response'
|
||||
end
|
||||
|
||||
context 'with a non member user' do
|
||||
let_it_be(:user) { build_stubbed(:user) }
|
||||
|
||||
where(:group_access_level, :status) do
|
||||
'PUBLIC' | :ok
|
||||
'INTERNAL' | :ok
|
||||
'PRIVATE' | :forbidden
|
||||
end
|
||||
|
||||
with_them do
|
||||
before do
|
||||
group.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_access_level, false))
|
||||
end
|
||||
|
||||
if params[:status] == :ok
|
||||
it_behaves_like 'successful response'
|
||||
else
|
||||
it_behaves_like 'returning response status', params[:status]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'for authentication' do
|
||||
where(:token, :sent_as, :status) do
|
||||
:personal_access_token | :header | :ok
|
||||
:personal_access_token | :basic_auth | :ok
|
||||
:deploy_token | :header | :ok
|
||||
:deploy_token | :basic_auth | :ok
|
||||
:job_token | :header | :ok
|
||||
:job_token | :basic_auth | :ok
|
||||
end
|
||||
|
||||
with_them do
|
||||
let(:headers) do
|
||||
case sent_as
|
||||
when :header
|
||||
token_header(token)
|
||||
when :basic_auth
|
||||
token_basic_auth(token)
|
||||
end
|
||||
end
|
||||
|
||||
it_behaves_like 'returning response status', params[:status]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'PATCH /api/v4/virtual_registries/packages/maven/registries/:id/upstreams/:upstream_id' do
|
||||
let(:url) { "/virtual_registries/packages/maven/registries/#{registry.id}/upstreams/#{upstream.id}" }
|
||||
|
||||
subject(:api_request) { patch api(url), params: params, headers: headers }
|
||||
|
||||
context 'with valid params' do
|
||||
let(:params) { { url: 'http://example.com', username: 'test', password: 'test' } }
|
||||
|
||||
it { is_expected.to have_request_urgency(:low) }
|
||||
|
||||
it_behaves_like 'disabled feature flag'
|
||||
it_behaves_like 'disabled dependency proxy'
|
||||
it_behaves_like 'not authenticated user'
|
||||
|
||||
where(:user_role, :status) do
|
||||
:owner | :ok
|
||||
:maintainer | :ok
|
||||
:developer | :forbidden
|
||||
:reporter | :forbidden
|
||||
:guest | :forbidden
|
||||
end
|
||||
|
||||
with_them do
|
||||
before do
|
||||
group.send(:"add_#{user_role}", user)
|
||||
end
|
||||
|
||||
it_behaves_like 'returning response status', params[:status]
|
||||
end
|
||||
|
||||
context 'for authentication' do
|
||||
before_all do
|
||||
group.add_maintainer(user)
|
||||
end
|
||||
|
||||
where(:token, :sent_as, :status) do
|
||||
:personal_access_token | :header | :ok
|
||||
:personal_access_token | :basic_auth | :ok
|
||||
:deploy_token | :header | :forbidden
|
||||
:deploy_token | :basic_auth | :forbidden
|
||||
:job_token | :header | :ok
|
||||
:job_token | :basic_auth | :ok
|
||||
end
|
||||
|
||||
with_them do
|
||||
let(:headers) do
|
||||
case sent_as
|
||||
when :header
|
||||
token_header(token)
|
||||
when :basic_auth
|
||||
token_basic_auth(token)
|
||||
end
|
||||
end
|
||||
|
||||
it_behaves_like 'returning response status', params[:status]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'for params' do
|
||||
before_all do
|
||||
group.add_maintainer(user)
|
||||
end
|
||||
|
||||
where(:param_url, :username, :password, :status) do
|
||||
nil | 'test' | 'test' | :ok
|
||||
'http://example.com' | nil | 'test' | :ok
|
||||
'http://example.com' | 'test' | nil | :ok
|
||||
'' | 'test' | 'test' | :bad_request
|
||||
'http://example.com' | '' | 'test' | :bad_request
|
||||
'http://example.com' | 'test' | '' | :bad_request
|
||||
nil | nil | nil | :bad_request
|
||||
end
|
||||
|
||||
with_them do
|
||||
let(:params) { { url: param_url, username: username, password: password }.compact }
|
||||
|
||||
it_behaves_like 'returning response status', params[:status]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'DELETE /api/v4/virtual_registries/packages/maven/registries/:id/upstreams/:upstream_id' do
|
||||
let(:url) { "/virtual_registries/packages/maven/registries/#{registry.id}/upstreams/#{upstream.id}" }
|
||||
|
||||
subject(:api_request) { delete api(url), headers: headers }
|
||||
|
||||
shared_examples 'successful response' do
|
||||
it 'returns a successful response' do
|
||||
expect { api_request }.to change { ::VirtualRegistries::Packages::Maven::Upstream.count }.by(-1)
|
||||
.and change { ::VirtualRegistries::Packages::Maven::RegistryUpstream.count }.by(-1)
|
||||
end
|
||||
end
|
||||
|
||||
it { is_expected.to have_request_urgency(:low) }
|
||||
|
||||
it_behaves_like 'disabled feature flag'
|
||||
it_behaves_like 'disabled dependency proxy'
|
||||
it_behaves_like 'not authenticated user'
|
||||
|
||||
context 'for different user roles' do
|
||||
where(:user_role, :status) do
|
||||
:owner | :no_content
|
||||
:maintainer | :no_content
|
||||
:developer | :forbidden
|
||||
:reporter | :forbidden
|
||||
:guest | :forbidden
|
||||
end
|
||||
|
||||
with_them do
|
||||
before do
|
||||
group.send(:"add_#{user_role}", user)
|
||||
end
|
||||
|
||||
if params[:status] == :no_content
|
||||
it_behaves_like 'successful response'
|
||||
else
|
||||
it_behaves_like 'returning response status', params[:status]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'for authentication' do
|
||||
before_all do
|
||||
group.add_maintainer(user)
|
||||
end
|
||||
|
||||
where(:token, :sent_as, :status) do
|
||||
:personal_access_token | :header | :no_content
|
||||
:personal_access_token | :basic_auth | :no_content
|
||||
:deploy_token | :header | :forbidden
|
||||
:deploy_token | :basic_auth | :forbidden
|
||||
:job_token | :header | :no_content
|
||||
:job_token | :basic_auth | :no_content
|
||||
end
|
||||
|
||||
with_them do
|
||||
let(:headers) do
|
||||
case sent_as
|
||||
when :header
|
||||
token_header(token)
|
||||
when :basic_auth
|
||||
token_basic_auth(token)
|
||||
end
|
||||
end
|
||||
|
||||
if params[:status] == :no_content
|
||||
it_behaves_like 'successful response'
|
||||
else
|
||||
it_behaves_like 'returning response status', params[:status]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET /api/v4/virtual_registries/packages/maven/:id/*path' do
|
||||
let(:path) { 'com/test/package/1.2.3/package-1.2.3.pom' }
|
||||
|
|
@ -32,7 +501,6 @@ RSpec.describe API::VirtualRegistries::Packages::Maven, feature_category: :virtu
|
|||
.to receive(:new)
|
||||
.with(registry: registry, current_user: user, params: { path: path })
|
||||
.and_return(service_double)
|
||||
stub_config(dependency_proxy: { enabled: true }) # not enabled by default
|
||||
end
|
||||
|
||||
subject(:request) do
|
||||
|
|
@ -152,13 +620,7 @@ RSpec.describe API::VirtualRegistries::Packages::Maven, feature_category: :virtu
|
|||
end
|
||||
end
|
||||
|
||||
context 'with feature flag virtual_registry_maven disabled' do
|
||||
before do
|
||||
stub_feature_flags(virtual_registry_maven: false)
|
||||
end
|
||||
|
||||
it_behaves_like 'returning response status', :not_found
|
||||
end
|
||||
it_behaves_like 'disabled feature flag'
|
||||
|
||||
context 'with a web browser' do
|
||||
described_class::MAJOR_BROWSERS.each do |browser|
|
||||
|
|
@ -179,19 +641,30 @@ RSpec.describe API::VirtualRegistries::Packages::Maven, feature_category: :virtu
|
|||
end
|
||||
end
|
||||
|
||||
context 'with the dependency proxy disabled' do
|
||||
before do
|
||||
stub_config(dependency_proxy: { enabled: false })
|
||||
end
|
||||
it_behaves_like 'disabled dependency proxy'
|
||||
it_behaves_like 'not authenticated user'
|
||||
end
|
||||
end
|
||||
|
||||
it_behaves_like 'returning response status', :not_found
|
||||
end
|
||||
def token_header(token)
|
||||
case token
|
||||
when :personal_access_token
|
||||
{ 'PRIVATE-TOKEN' => personal_access_token.token }
|
||||
when :deploy_token
|
||||
{ 'Deploy-Token' => deploy_token.token }
|
||||
when :job_token
|
||||
{ 'Job-Token' => job.token }
|
||||
end
|
||||
end
|
||||
|
||||
context 'as anonymous' do
|
||||
let(:headers) { {} }
|
||||
|
||||
it_behaves_like 'returning response status', :unauthorized
|
||||
end
|
||||
def token_basic_auth(token)
|
||||
case token
|
||||
when :personal_access_token
|
||||
user_basic_auth_header(user, personal_access_token)
|
||||
when :deploy_token
|
||||
deploy_token_basic_auth_header(deploy_token)
|
||||
when :job_token
|
||||
job_basic_auth_header(job)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -5,24 +5,54 @@ require 'spec_helper'
|
|||
RSpec.describe ::Ml::FindModelService, feature_category: :mlops do
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:existing_model) { create(:ml_models) }
|
||||
let(:finder) { described_class.new(project, name) }
|
||||
let(:finder) { described_class.new(project, name, model_id) }
|
||||
let(:model_id) { nil }
|
||||
|
||||
describe '#execute' do
|
||||
context 'when model name does not exist in the project' do
|
||||
let(:name) { 'new_model' }
|
||||
context 'when model_id is provided' do
|
||||
let(:project) { existing_model.project }
|
||||
let(:name) { nil }
|
||||
let(:model_id) { existing_model.id }
|
||||
|
||||
it 'reutrns nil' do
|
||||
expect(finder.execute).to be nil
|
||||
it 'returns the model with the given model_id' do
|
||||
expect(finder.execute).to eq(existing_model)
|
||||
end
|
||||
|
||||
context 'when model_id does not exist' do
|
||||
let(:model_id) { non_existing_record_id }
|
||||
|
||||
it 'returns nil' do
|
||||
expect(finder.execute).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when model with name exists' do
|
||||
let(:name) { existing_model.name }
|
||||
context 'when neither model_id nor name is provided' do
|
||||
let(:project) { existing_model.project }
|
||||
let(:name) { nil }
|
||||
|
||||
it 'returns the existing model' do
|
||||
expect(finder.execute).to eq(existing_model)
|
||||
it 'returns nil' do
|
||||
expect(finder.execute).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'when model_id is not provided' do
|
||||
context 'when model name does not exist in the project' do
|
||||
let(:name) { 'new_model' }
|
||||
let(:project) { existing_model.project }
|
||||
|
||||
it 'returns nil' do
|
||||
expect(finder.execute).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'when model with name exists' do
|
||||
let(:name) { existing_model.name }
|
||||
let(:project) { existing_model.project }
|
||||
|
||||
it 'returns the existing model' do
|
||||
expect(finder.execute).to eq(existing_model)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -4,23 +4,27 @@ require 'spec_helper'
|
|||
|
||||
RSpec.describe ::Ml::UpdateModelService, feature_category: :mlops do
|
||||
let_it_be(:model) { create(:ml_models) }
|
||||
let_it_be(:description) { 'updated model description' }
|
||||
let(:service) { described_class.new(model, description) }
|
||||
let_it_be(:new_description) { 'updated model description' }
|
||||
let(:service) { described_class.new(model, new_description) }
|
||||
|
||||
describe '#execute' do
|
||||
subject(:service_result) { service.execute }
|
||||
|
||||
context 'when supplied with a non-model object' do
|
||||
let(:model) { nil }
|
||||
|
||||
it 'returns nil' do
|
||||
expect { service.execute }.to raise_error(NoMethodError)
|
||||
it 'returns an error' do
|
||||
expect(service_result).to be_error
|
||||
end
|
||||
end
|
||||
|
||||
context 'with an existing model' do
|
||||
it 'description is initially blank' do
|
||||
expect(model.description).to eq(nil)
|
||||
end
|
||||
|
||||
it 'updates the description' do
|
||||
updated = service.execute
|
||||
expect(updated.class).to be(Ml::Model)
|
||||
expect(updated.description).to eq(description)
|
||||
expect(service_result.payload.description).to eq(new_description)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module HttpBasicAuthHelpers
|
||||
def user_basic_auth_header(user)
|
||||
access_token = create(:personal_access_token, user: user)
|
||||
def user_basic_auth_header(user, access_token = nil)
|
||||
access_token ||= create(:personal_access_token, user: user)
|
||||
|
||||
basic_auth_header(user.username, access_token.token)
|
||||
end
|
||||
|
|
@ -11,6 +11,10 @@ module HttpBasicAuthHelpers
|
|||
basic_auth_header(::Gitlab::Auth::CI_JOB_USER, job.token)
|
||||
end
|
||||
|
||||
def deploy_token_basic_auth_header(deploy_token)
|
||||
basic_auth_header(deploy_token.username, deploy_token.token)
|
||||
end
|
||||
|
||||
def client_basic_auth_header(client)
|
||||
basic_auth_header(client.uid, client.secret)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -26,6 +26,6 @@ RSpec.describe 'projects/issues/_related_branches' do
|
|||
expect(rendered).to have_link(href: 'link-to-feature')
|
||||
expect(rendered).to have_link(href: 'link-to-other')
|
||||
expect(rendered).to have_css('[data-testid="ci-icon"]')
|
||||
expect(rendered).to have_css('.related-branch-info')
|
||||
expect(rendered).to have_css('.ref-name')
|
||||
end
|
||||
end
|
||||
|
|
|
|||
292
yarn.lock
292
yarn.lock
|
|
@ -2619,181 +2619,181 @@
|
|||
dom-accessibility-api "^0.5.1"
|
||||
pretty-format "^26.4.2"
|
||||
|
||||
"@tiptap/core@^2.5.9":
|
||||
version "2.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/core/-/core-2.5.9.tgz#1deb0b7c748e24ec32613263e0af8d55a3b3c2ca"
|
||||
integrity sha512-PPUR+0tbr+wX2G8RG4FEps4qhbnAPEeXK1FUtirLXSRh8vm+TDgafu3sms7wBc4fAyw9zTO/KNNZ90GBe04guA==
|
||||
"@tiptap/core@^2.6.0":
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/core/-/core-2.6.0.tgz#c222f53043abfa69d8d41a081bb3dfc1181fc841"
|
||||
integrity sha512-MG2OXwpMVaiacGuipqZ3VXi36gMvtV3i3ncrtXufsMducWvniENMi8fEonj/Q7nkeVi59OcoW8vD6kqdKkh2Gw==
|
||||
|
||||
"@tiptap/extension-blockquote@^2.5.9":
|
||||
version "2.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-blockquote/-/extension-blockquote-2.5.9.tgz#d873a8496fcf572c69aaac2a7a341e035fdbae22"
|
||||
integrity sha512-LhGyigmd/v1OjYPeoVK8UvFHbH6ffh175ZuNvseZY4PsBd7kZhrSUiuMG8xYdNX8FxamsxAzr2YpsYnOzu3W7A==
|
||||
"@tiptap/extension-blockquote@^2.6.0":
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-blockquote/-/extension-blockquote-2.6.0.tgz#3f0a80ebd82e1f5d174c24f9794e22ac3184c072"
|
||||
integrity sha512-/rYTYnn7fk/LBixLv7R1fEee3JDrDo3VHEJ+gBGuyLXcNaYtzWuRfqdeIraNSOuhzHffWQ5dg1oxpVFrVrd6AQ==
|
||||
|
||||
"@tiptap/extension-bold@^2.5.9":
|
||||
version "2.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-bold/-/extension-bold-2.5.9.tgz#00c9b7b5211048b1e1c5d67e355935b9c92e3532"
|
||||
integrity sha512-XUJdzFb31t0+bwiRquJf0btBpqOB3axQNHTKM9XADuL4S+Z6OBPj0I5rYINeElw/Q7muvdWrHWHh/ovNJA1/5A==
|
||||
"@tiptap/extension-bold@^2.6.0":
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-bold/-/extension-bold-2.6.0.tgz#eea678778fce751d6f771b6a18c15513f1bbd8ff"
|
||||
integrity sha512-supo1j/lZFXkQ7aQxYTduncSF4aKiDomceJbqQN2HnsRmf1b1SimsGugjhcqT0g10bYb0zuscNPnk15xG8gVTA==
|
||||
|
||||
"@tiptap/extension-bubble-menu@^2.5.9":
|
||||
version "2.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.5.9.tgz#d600bbcaa1d98a99f32b3b8b8c3d35752161200c"
|
||||
integrity sha512-NddZ8Qn5dgPPa1W4yk0jdhF4tDBh0FwzBpbnDu2Xz/0TUHrA36ugB2CvR5xS1we4zUKckgpVqOqgdelrmqqFVg==
|
||||
"@tiptap/extension-bubble-menu@^2.6.0":
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.6.0.tgz#91fb19abd94a4dcbd8816c89285d8b3a0dd6c098"
|
||||
integrity sha512-d8LiaWVRCa3jc26OOCGTGLtJhbTlylokAJvKK1U0IGoX/jjzwWIypg6FZawYB2Fj0JANdTD100e7xDfLTOLLKg==
|
||||
dependencies:
|
||||
tippy.js "^6.3.7"
|
||||
|
||||
"@tiptap/extension-bullet-list@^2.5.9":
|
||||
version "2.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-bullet-list/-/extension-bullet-list-2.5.9.tgz#2852aba9a1dacbf2c673cda6a4994b1f3c33cd5c"
|
||||
integrity sha512-hJTv1x4omFgaID4LMRT5tOZb/VKmi8Kc6jsf4JNq4Grxd2sANmr9qpmKtBZvviK+XD5PpTXHvL+1c8C1SQtuHQ==
|
||||
"@tiptap/extension-bullet-list@^2.6.0":
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-bullet-list/-/extension-bullet-list-2.6.0.tgz#2a0458701c46295ee2e600807312ac0f76c9ecdb"
|
||||
integrity sha512-zf46le3It6OO/wrLk/FTckLRh+EPEBCLKiff4n0N/YwIpSGj0VNEjzPjN5X8KSSiDfP50hWsLVFU0h8A2c8keQ==
|
||||
|
||||
"@tiptap/extension-code-block-lowlight@^2.5.9":
|
||||
version "2.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block-lowlight/-/extension-code-block-lowlight-2.5.9.tgz#ccd6569422d98b11813df3e0dbd09b1dcf957def"
|
||||
integrity sha512-taIXxXQ/Lka9CegHFHQS+nx6cX9i9Ws63ZFMPbrXLMSJRhXk8+m4UAoGZQJH9CGGb5/Rv0p3Z8I59AGiyUHLEw==
|
||||
"@tiptap/extension-code-block-lowlight@^2.6.0":
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block-lowlight/-/extension-code-block-lowlight-2.6.0.tgz#680ce93869639fb06faccb689622149ff58d3830"
|
||||
integrity sha512-d1JFRmR75HjHeARP4B+ay4wUdeSBDe1Q5+hGLXMvNIrB1pGsuOUERrfL4QPxC51vi2EUbtxsUJh+h2V+ecGd+A==
|
||||
|
||||
"@tiptap/extension-code-block@^2.5.9":
|
||||
version "2.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block/-/extension-code-block-2.5.9.tgz#8cd99515b286fc62ad1215a411aea5da9a7d9701"
|
||||
integrity sha512-+MUwp0VFFv2aFiZ/qN6q10vfIc6VhLoFFpfuETX10eIRks0Xuj2nGiqCDj7ca0/M44bRg2VvW8+tg/ZEHFNl9g==
|
||||
"@tiptap/extension-code-block@^2.6.0":
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block/-/extension-code-block-2.6.0.tgz#62a7327d0d96adfd91ca10d921abc2d16eede8ba"
|
||||
integrity sha512-sDQhuxetwgCAqbD5hAjz6bqpvnPbS8cuv0kWmkHd29filzTn3CiwIRkXIz715POadN/jkZv7CDw5WsJcHiUjng==
|
||||
|
||||
"@tiptap/extension-code@^2.5.9":
|
||||
version "2.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-code/-/extension-code-2.5.9.tgz#93c4433eca8b2aa239ea7f408b90f152b7fc4603"
|
||||
integrity sha512-Q1PL3DUXiEe5eYUwOug1haRjSaB0doAKwx7KFVI+kSGbDwCV6BdkKAeYf3us/O2pMP9D0im8RWX4dbSnatgwBA==
|
||||
"@tiptap/extension-code@^2.6.0":
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-code/-/extension-code-2.6.0.tgz#6fac1eafcfbbb7ab6c8d2ce88864305a1cd10a8f"
|
||||
integrity sha512-xs7VhgnpIncVORP/a5K8Ad7ASOQ0P/JaF2nKnK4Sy6mFU2f8PgwOXbgbAaLtUfv2e5nLrqS3hGegePQ3y3R8+Q==
|
||||
|
||||
"@tiptap/extension-document@^2.5.9":
|
||||
version "2.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-document/-/extension-document-2.5.9.tgz#13a22b2d3bdc1463844872b1f1c926633df431a8"
|
||||
integrity sha512-VdNZYDyCzC3W430UdeRXR9IZzPeODSbi5Xz/JEdV93THVp8AC9CrZR7/qjqdBTgbTB54VP8Yr6bKfCoIAF0BeQ==
|
||||
"@tiptap/extension-document@^2.6.0":
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-document/-/extension-document-2.6.0.tgz#5c21fcb40dcbabdfedc54bd17f964ec2a28164c8"
|
||||
integrity sha512-aKyKCaErlZSOav2mttktvbyYhpgNfQcEvrupkDuRYRsdy1CH5h66Of1Vc2F9z/NgZvkyJLWWv2T7fwyAYnMnYw==
|
||||
|
||||
"@tiptap/extension-dropcursor@^2.5.9":
|
||||
version "2.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-dropcursor/-/extension-dropcursor-2.5.9.tgz#648f683f929056a0526620f530f73e6b052c1481"
|
||||
integrity sha512-nEOb37UryG6bsU9JAs/HojE6Jg43LupNTAMISbnuB1CPAeAqNsFMwORd9eEPkyEwnQT7MkhsMOSJM44GoPGIFA==
|
||||
"@tiptap/extension-dropcursor@^2.6.0":
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-dropcursor/-/extension-dropcursor-2.6.0.tgz#0f2ed1ecb6eade94a629689ff4fd20300c5ac86f"
|
||||
integrity sha512-l0u+T5EDICm7KKC1HBCKYyPKfoSINsG01QXAYBcogbFBsJRQJk0m9e0Bsf3kczbndV8+Sn/SOb+S1wbBoXcq7Q==
|
||||
|
||||
"@tiptap/extension-floating-menu@^2.5.9":
|
||||
version "2.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-floating-menu/-/extension-floating-menu-2.5.9.tgz#b970905f3c1af49a916dcbd477a4302086187974"
|
||||
integrity sha512-MWJIQQT6e5MgqHny8neeH2Dx926nVPF7sv4p84nX4E0dnkRbEYUP8mCsWYhSUvxxIif6e+yY+4654f2Q9qTx1w==
|
||||
"@tiptap/extension-floating-menu@^2.6.0":
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-floating-menu/-/extension-floating-menu-2.6.0.tgz#6dd656ce00e80d5312dacc7fe472d3233ccddad7"
|
||||
integrity sha512-eFmDaJJgGC+PBdRwfWSTzNfJR5Z0udPjHUf4pJosz2PcIg6wzeAxJyELzprk8qWNKbrxDm0CeJ0nz4uXxECdVw==
|
||||
dependencies:
|
||||
tippy.js "^6.3.7"
|
||||
|
||||
"@tiptap/extension-gapcursor@^2.5.9":
|
||||
version "2.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-gapcursor/-/extension-gapcursor-2.5.9.tgz#68b9e227cd7876aac353a8ac029995b4c092a763"
|
||||
integrity sha512-yW7V2ebezsa7mWEDWCg4A1ZGsmSV5bEHKse9wzHCDkb7TutSVhLZxGo72U6hNN9PnAksv+FJQk03NuZNYvNyRQ==
|
||||
"@tiptap/extension-gapcursor@^2.6.0":
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-gapcursor/-/extension-gapcursor-2.6.0.tgz#a38d426f6f7691e3cb8bb038542557733bf8ec8b"
|
||||
integrity sha512-mfkoMQuqLlnjamFJobWgXQb3g8S9P0Y8XuuyxK7MLTUdDgQdmw9/c2mF0LiaoJ825xjRRHELNuHZIPnyRWoP9Q==
|
||||
|
||||
"@tiptap/extension-hard-break@^2.5.9":
|
||||
version "2.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-hard-break/-/extension-hard-break-2.5.9.tgz#4f38f06dbeb5fb3e58ff7fc0c48b9db9c4ee4ecd"
|
||||
integrity sha512-8hQ63SgZRG4BqHOeSfeaowG2eMr2beced018pOGbpHbE3XSYoISkMVuFz4Z8UEVR3W9dTbKo4wxNufSTducocQ==
|
||||
"@tiptap/extension-hard-break@^2.6.0":
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-hard-break/-/extension-hard-break-2.6.0.tgz#6a475ca5422a53c2739c0b54eaf488098972e6cc"
|
||||
integrity sha512-RX5Xmj2svS7T3QkDs0X8aTekkcDxpnJ3hqHarzR1gK0GdVsrpowVKYhuEAc1zAAUirVa/IBimKXAIkXjDvuvNA==
|
||||
|
||||
"@tiptap/extension-heading@^2.5.9":
|
||||
version "2.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-heading/-/extension-heading-2.5.9.tgz#b9ec3b3b48dea939606d06eff56c4bdc7bed0662"
|
||||
integrity sha512-HHowAlGUbFn1qvmY02ydM7qiPPMTGhAJn2A46enDRjNHW5UoqeMfkMpTEYaioOexyguRFSfDT3gpK68IHkQORQ==
|
||||
"@tiptap/extension-heading@^2.6.0":
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-heading/-/extension-heading-2.6.0.tgz#347e99128de6f368b6942d07f8b1ba99fdb0da17"
|
||||
integrity sha512-dq3o9DoiqqzITKIeFrJSRuExrukrP1fNEwPEsrGx8vcwz3c0HIvQ9h/0jKzmjVD9UT+qhM/6DOiYlFnqDlTzqg==
|
||||
|
||||
"@tiptap/extension-highlight@^2.5.9":
|
||||
version "2.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-highlight/-/extension-highlight-2.5.9.tgz#290426538abcbb2299809d3e1274ba5af1ba9f68"
|
||||
integrity sha512-tRaSIIbCI7aBlvlmgUgBI5lVBqnMy49lc++UVAx1Pjey1j2KW031vUyvZfEwf6wk8Y7W3kVSkN0mW9IYCcOAOQ==
|
||||
"@tiptap/extension-highlight@^2.6.0":
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-highlight/-/extension-highlight-2.6.0.tgz#082f01e3e66d069f9c49e25a9d9e9c410ff9c52e"
|
||||
integrity sha512-k25Krl4KwqY3kaldFm3rp9evm5tJZyJmNQeHVfcjn20TqWP+g1OTAFYvai/Gwy5UtPpk03i6SyzvVNl6hwLxrQ==
|
||||
|
||||
"@tiptap/extension-history@^2.5.9":
|
||||
version "2.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-history/-/extension-history-2.5.9.tgz#f48f64ff95407f0ce27bcdd020762e49d0dd60d1"
|
||||
integrity sha512-hGPtJgoZSwnVVqi/xipC2ET/9X2G2UI/Y+M3IYV1ZlM0tCYsv4spNi3uXlZqnXRwYcBXLk5u6e/dmsy5QFbL8g==
|
||||
"@tiptap/extension-history@^2.6.0":
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-history/-/extension-history-2.6.0.tgz#a52ec849834ec86035805fcbead9d13f2b4edd02"
|
||||
integrity sha512-uFQU5Eo5pKboJmI8paqZLe+c3eV9RQ0RLvQ8PsJsKRTJnlq69l6phl6ATvNJC9GmVD2OwxHoroByPB5jS0o+HA==
|
||||
|
||||
"@tiptap/extension-horizontal-rule@^2.5.9":
|
||||
version "2.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.5.9.tgz#9f91a17b80700670e53e241fcee40365c57aa994"
|
||||
integrity sha512-/ES5NdxCndBmZAgIXSpCJH8YzENcpxR0S8w34coSWyv+iW0Sq7rW/mksQw8ZIVsj8a7ntpoY5OoRFpSlqcvyGw==
|
||||
"@tiptap/extension-horizontal-rule@^2.6.0":
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.6.0.tgz#00039d78f8e44844de7234279ab76bd85af79c6d"
|
||||
integrity sha512-CJ2ma8Wxww+E0SdSp8t/V2Gvv7q99fPplSSEWSgDWXnMDfcfV3vg637kvnLZpGX+qiRmgYAvjRsyNRQxTvJGgQ==
|
||||
|
||||
"@tiptap/extension-image@^2.5.9":
|
||||
version "2.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-image/-/extension-image-2.5.9.tgz#2f2be205d889f6688ef85c76071d2199baab03e4"
|
||||
integrity sha512-v4WZISCvbriac6HE6v7kYYY7KX+v9rJaIZC3gbYGtqnBWfaAwZiVVu8Z03xSrqYhoc+KHuI+oQ4VubcvZ/i7OQ==
|
||||
"@tiptap/extension-image@^2.6.0":
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-image/-/extension-image-2.6.0.tgz#0515bd949e58efe499546ee9d5965fd0ae4520cd"
|
||||
integrity sha512-j50e6P+L344iDxaPVV9svERBJv8MF+N3bKYJWPIu5GhHpoT1yO2L46rnXB8AHz2k5NHs4ZOj9SnSivMKDf/o7w==
|
||||
|
||||
"@tiptap/extension-italic@^2.5.9":
|
||||
version "2.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-italic/-/extension-italic-2.5.9.tgz#8ea0e19e650f0f1d6fc30425ec28291511143dda"
|
||||
integrity sha512-Bw+P139L4cy+B56zpUiRjP8BZSaAUl3JFMnr/FO+FG55QhCxFMXIc6XrC3vslNy5ef3B3zv4gCttS3ee8ByMiw==
|
||||
"@tiptap/extension-italic@^2.6.0":
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-italic/-/extension-italic-2.6.0.tgz#00768b7c8916cb0098c2b85be6647e5a4289d8f5"
|
||||
integrity sha512-ZILwDaTbFv5GVuxAga72GDmx8VHYqFOK8rkg/GCtW6OfAQVrlC17pzo2uRphzHpYTmOvNW5e63PC0fRbA1qXsg==
|
||||
|
||||
"@tiptap/extension-link@^2.5.9":
|
||||
version "2.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-link/-/extension-link-2.5.9.tgz#6cb323d36b82700963ad2b9d189a7d07c81c7d6e"
|
||||
integrity sha512-7v9yRsX7NuiY8DPslIsPIlFqcD8aGBMLqfEGXltJDvuG6kykdr+khEZeWcJ8ihHIL4yWR3/MAgeT2W72Z/nxiQ==
|
||||
"@tiptap/extension-link@^2.6.0":
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-link/-/extension-link-2.6.0.tgz#2a3f65742fcb2776973541e9f2cea3169ce4a204"
|
||||
integrity sha512-16ckFDnwqt0tYtQRgnVhooAUTLSk7liaqcGgc3NJ35gqWZho8hSnaTOl+72dlyJqUjqwt8D24NHFJsSqB9PSxA==
|
||||
dependencies:
|
||||
linkifyjs "^4.1.0"
|
||||
|
||||
"@tiptap/extension-list-item@^2.5.9":
|
||||
version "2.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-list-item/-/extension-list-item-2.5.9.tgz#0805b7216371b8b54649abe5ab29bd2c2155f05f"
|
||||
integrity sha512-d9Eo+vBz74SMxP0r25aqiErV256C+lGz+VWMjOoqJa6xWLM1keYy12JtGQWJi8UDVZrDskJKCHq81A0uLt27WA==
|
||||
"@tiptap/extension-list-item@^2.6.0":
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-list-item/-/extension-list-item-2.6.0.tgz#5b960a8c6bceea1fe5f7c730cb3547b920fe0706"
|
||||
integrity sha512-vgrLi3lYe1YHBPCjEFLBfUyeS2DueU/w/L8uNuM0SP38k0wuGZRbYr2mc5oZmVRrCsBdoY9abvjkJHLDVvzwTA==
|
||||
|
||||
"@tiptap/extension-ordered-list@^2.5.9":
|
||||
version "2.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-ordered-list/-/extension-ordered-list-2.5.9.tgz#44aab6ec3e19429a8e3b73e42c04156f2b0bc730"
|
||||
integrity sha512-9MsWpvVvzILuEOd/GdroF7RI7uDuE1M6at9rzsaVGvCPVHZBvu1XR3MSVK5OdiJbbJuPGttlzEFLaN/rQdCGFg==
|
||||
"@tiptap/extension-ordered-list@^2.6.0":
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-ordered-list/-/extension-ordered-list-2.6.0.tgz#ca163a9237dad834b258bf2e159cb78a794f333a"
|
||||
integrity sha512-eRYux5eRQFCUApOc0L4+R8uAa2tdiCCYqboe/Hadm35u5Z9VsO9V828BWeVVqtkUwSYJY3dz3tXplBkZ+ot+7A==
|
||||
|
||||
"@tiptap/extension-paragraph@^2.5.9":
|
||||
version "2.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-paragraph/-/extension-paragraph-2.5.9.tgz#05210b6e7a9940b1acc09fdd4ec769fc6406da2b"
|
||||
integrity sha512-HDXGiHTJ/V85dbDMjcFj4XfqyTQZqry6V21ucMzgBZYX60X3gIn7VpQTQnnRjvULSgtfOASSJP6BELc5TyiK0w==
|
||||
"@tiptap/extension-paragraph@^2.6.0":
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-paragraph/-/extension-paragraph-2.6.0.tgz#721921477e3785c0a0abf132ea109e67bcea9fae"
|
||||
integrity sha512-ztmgfCSaCGFCR4VudA91WJDEQrpXH2FirQrJSaoOOwk3OfrNSSvcbqAhTmxJHl8e7aFwuR5eH8wbIxKw9In3Kg==
|
||||
|
||||
"@tiptap/extension-strike@^2.5.9":
|
||||
version "2.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-strike/-/extension-strike-2.5.9.tgz#f2d54161d24ee37dc8a41b5077c553048ed69f99"
|
||||
integrity sha512-QezkOZpczpl09S8lp5JL7sRkwREoPY16Y/lTvBcFKm3TZbVzYZZ/KwS0zpwK9HXTfXr8os4L9AGjQf0tHonX+w==
|
||||
"@tiptap/extension-strike@^2.6.0":
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-strike/-/extension-strike-2.6.0.tgz#1bff3ab3b91f7cdbb39bd7a860ad30e60e1750bd"
|
||||
integrity sha512-+gt750H4ioTpwIQXYV5K4BScvAMBuWHvW/f4197LYE/fy6uNqUf62XRz6Ew12z13rEbWGzMHRdpYIguTHcqvzA==
|
||||
|
||||
"@tiptap/extension-subscript@^2.5.9":
|
||||
version "2.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-subscript/-/extension-subscript-2.5.9.tgz#b6201139faf9cf4b8be013a21161806af660c666"
|
||||
integrity sha512-SY1VCf/zlsBLowZaayXGl7dkIGPMNieCO0P1luFBjsiEXCRff0WYVpxi24wzgMeWE6q28SXmd3eD5BsGBudx9g==
|
||||
"@tiptap/extension-subscript@^2.6.0":
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-subscript/-/extension-subscript-2.6.0.tgz#124ea99a960c9af399d65388d2b6b81ab5478d13"
|
||||
integrity sha512-FSkUVNg2kIzJAP4sgoEulLk/7T1qhaDAFCMB3i6/ppftlpEtr+HaWUx3F3qaBCeHmRpMGOF/nje72Y9+SrKZMg==
|
||||
|
||||
"@tiptap/extension-superscript@^2.5.9":
|
||||
version "2.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-superscript/-/extension-superscript-2.5.9.tgz#da9549e767d7686c2ca716d5eeb46d26814950f7"
|
||||
integrity sha512-ggpVx/oJk6tBDq7mNxrJNXhitHVqkJVbeOKaac5FACCoA3ZzHgZ75JooxZqn5wRoCaqShmbljLb8ZqefdX/PRg==
|
||||
"@tiptap/extension-superscript@^2.6.0":
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-superscript/-/extension-superscript-2.6.0.tgz#15f74fbc522c7cbc69f54c4f4cc1549e07acc219"
|
||||
integrity sha512-zs3C1xt0qXAfE20HbgKq49P7t2q+3w9YzEUXy3ky/d2pNCHrrZU1nddpn8+cPf3KnG7kLarYb6cv/1JZmDsrEQ==
|
||||
|
||||
"@tiptap/extension-table-cell@^2.5.9":
|
||||
version "2.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-table-cell/-/extension-table-cell-2.5.9.tgz#dffcd23cb11d3ca1239c7290297c9caf0d3b8434"
|
||||
integrity sha512-83zg+d8iY7FLZDC2qJVvHFEIwqB9e/zGPyfRMglYH7YxHeJSycG2K969DQhwkSq+z0PhHEO2XHDcD9aFnXRQNQ==
|
||||
"@tiptap/extension-table-cell@^2.6.0":
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-table-cell/-/extension-table-cell-2.6.0.tgz#8b6c01ddafed7a914f06349cd72cc2b316e9673f"
|
||||
integrity sha512-+zOR3c9fzSr9TRFl7p2KxY1WOLit/+0kgIpbsidCAvVH1rigV7x/l/Lo3zOVP+lCzUoAVvaJX293PY9y61lDQQ==
|
||||
|
||||
"@tiptap/extension-table-header@^2.5.9":
|
||||
version "2.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-table-header/-/extension-table-header-2.5.9.tgz#405da76163ec4899b1d6b81f2fbbdb7c0f71bf59"
|
||||
integrity sha512-+FKfxpEO8RnsHUhcWFeSpsI3ZRaDtgcX2c4kBBXZGJBMWHxw71VK9gkRM+JtxCl70hNyZR13qpOw1RmByf2kdw==
|
||||
"@tiptap/extension-table-header@^2.6.0":
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-table-header/-/extension-table-header-2.6.0.tgz#790d51971b19c1ab5a1042a1a6d389fd62dbcf43"
|
||||
integrity sha512-mkh9RPA2iueMDsQjbs7YwExxS02EY+fYy/mA2bIqhu/4eZXLgHuZADmbW6VfPjkEZ0nRoToQCyDvP8NHS5WpWA==
|
||||
|
||||
"@tiptap/extension-table-row@^2.5.9":
|
||||
version "2.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-table-row/-/extension-table-row-2.5.9.tgz#62e5e329b38daf6142b39d7c17de045dfc6918be"
|
||||
integrity sha512-VPmkzraT9m7g2/88qsTF9EQdFvkcwhvOD+WWZTflN92LMsRHddJt3peJ/fpuf0QKnwwn5qIB3fXWja4VcZe3wQ==
|
||||
"@tiptap/extension-table-row@^2.6.0":
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-table-row/-/extension-table-row-2.6.0.tgz#f1629be948c58d8f9fc0bee01b52ca05b92f7331"
|
||||
integrity sha512-2rJCjK6cHPPA81YtrBew+hfSAUclvaz1nSV2WBvoWiY8UQHdaRhESVmmpkEhUSuX7JaevN93mZhpQ4Tj6Q7B6w==
|
||||
|
||||
"@tiptap/extension-table@^2.5.9":
|
||||
version "2.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-table/-/extension-table-2.5.9.tgz#a7b80a668a683c3abe59725812091123b2c12b88"
|
||||
integrity sha512-kLZdYBO0Ug4sNjzyDfa3W29qL4HdRK/IaMxcmcEbyKSt42qiMJlIelbGzVENzxe9AbcNTeiWje70Nhk4dbb8Ag==
|
||||
"@tiptap/extension-table@^2.6.0":
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-table/-/extension-table-2.6.0.tgz#9866f5dfff14f9038d57e3f5e5615bd2bcc43bc0"
|
||||
integrity sha512-dTOvgX7a9EnzqfqUZMlk6MUolb0nFN3JQG8foppxVPnO04H5Apwyhq39n87JHWQorFR5+dbbPg0FQk+3qNzP5g==
|
||||
|
||||
"@tiptap/extension-task-item@^2.5.9":
|
||||
version "2.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-task-item/-/extension-task-item-2.5.9.tgz#623590d549aa0e21ccd1d34396ebbeeea45886f5"
|
||||
integrity sha512-g4HK3r3yNE0RcXQOkJHs94Ws/fhhTqa1L5iAy4gwYKNNFFnIQl8BpE6nn9d5h33kWDN9jjY+PZmq+0PvxCLODQ==
|
||||
"@tiptap/extension-task-item@^2.6.0":
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-task-item/-/extension-task-item-2.6.0.tgz#93a064cd7d3b83a33d885092a964acf6f22ca6dd"
|
||||
integrity sha512-IWJgtyKPU1N+Vb3YpwU2k7m8APl/YVnH2OMFV6PohV9eAA0BoH4bGC8fLaPO4Kq7Jl7er4darHDI8touTSQyVg==
|
||||
|
||||
"@tiptap/extension-task-list@^2.5.9":
|
||||
version "2.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-task-list/-/extension-task-list-2.5.9.tgz#9934b3ae84dbfc27804d0d54e64aeb9e8fcaf418"
|
||||
integrity sha512-OylVo5cAh0117PzhyM8MGaUIrCskGiF7v7x6/zAHMFIqVdcbKsq+hMueVPnABfOyLcIH5Zojo3NzNOJeKeblCg==
|
||||
"@tiptap/extension-task-list@^2.6.0":
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-task-list/-/extension-task-list-2.6.0.tgz#7f720a398cd8ad0163841481dfcff676d00b3350"
|
||||
integrity sha512-bH0yQN4U3RhW/jlnXExfsZYPFHUjU1YxhbM2UvKY6w1IrqEDxIN+zjvaQ/anu9+4Z4zuzL6qNaJw7O5CdzqkqA==
|
||||
|
||||
"@tiptap/extension-text@^2.5.9":
|
||||
version "2.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-text/-/extension-text-2.5.9.tgz#a5bef0b9c5324511dbc2804a3a5ac8b9b5d5dc4c"
|
||||
integrity sha512-W0pfiQUPsMkwaV5Y/wKW4cFsyXAIkyOFt7uN5u6LrZ/iW9KZ/IsDODPJDikWp0aeQnXzT9NNQULTpCjbHzzS6g==
|
||||
"@tiptap/extension-text@^2.6.0":
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-text/-/extension-text-2.6.0.tgz#395cd44456059c11fb5f3e2215093a5c32ba59a3"
|
||||
integrity sha512-Bg/FXGzj6WGvqgCVvFKzTWOpgg8Nl4X2a/bUT7nEmBafpUNAiN6enomMWnniylGTFEqZrywr5KRcvbgl8ubeDQ==
|
||||
|
||||
"@tiptap/pm@^2.5.9":
|
||||
version "2.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/pm/-/pm-2.5.9.tgz#f97889210374993a1ce78e9ecb23461d0e4644bf"
|
||||
integrity sha512-YSUaEQVtvZnGzGjif2Tl2o9utE+6tR2Djhz0EqFUcAUEVhOMk7UYUO+r/aPfcCRraIoKKuDQzyCpjKmJicjCUA==
|
||||
"@tiptap/pm@^2.6.0":
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/pm/-/pm-2.6.0.tgz#b2ef8aba2f5a04ac3f5051e3d891ffe26f37967b"
|
||||
integrity sha512-Oj912Jfowuq/K+oEkqx+pADjuVwBCXroC2hdrRMo4w18bb2gI2Nhse6St1KQ9kWWGF36O81RpDbpLe7L1YQhzQ==
|
||||
dependencies:
|
||||
prosemirror-changeset "^2.2.1"
|
||||
prosemirror-collab "^1.3.1"
|
||||
|
|
@ -2814,18 +2814,18 @@
|
|||
prosemirror-transform "^1.9.0"
|
||||
prosemirror-view "^1.33.9"
|
||||
|
||||
"@tiptap/suggestion@^2.5.9":
|
||||
version "2.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/suggestion/-/suggestion-2.5.9.tgz#af54bd41c2146454619fcadf15129a499bb6d05d"
|
||||
integrity sha512-s7UU0j2IRreVXrMMxsFvsNjJnZeTS1SAwsjLkN2YX+/ZQss92s0BLP3HsxEr2oFHlFye8E0qR9xjWZ4vSc9asw==
|
||||
"@tiptap/suggestion@^2.6.0":
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/suggestion/-/suggestion-2.6.0.tgz#457ae6a7f50ec47cf8fa7c2a3d1c88a8dfb0ed6d"
|
||||
integrity sha512-NAsXzAbHa3epnvnK4mqzRYhvjBYndu/lnC4SVOFvgBbCqQ/V698DwYDZ8iKLBeEzckzd7G6RON223AyvCF+9lw==
|
||||
|
||||
"@tiptap/vue-2@^2.5.9":
|
||||
version "2.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/vue-2/-/vue-2-2.5.9.tgz#a8bd3854ffff25ce09b1843d4f0b663d643b84b6"
|
||||
integrity sha512-gqwwUfRy1WT9uHaZEpTWjEavLrsDfpjwzSQ/w1NjX/broyDMKc9WR/G2qlBCruYLBuypJSX9Z3nCMABD7Zhyaw==
|
||||
"@tiptap/vue-2@^2.6.0":
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/vue-2/-/vue-2-2.6.0.tgz#df7113e33b773a5faaf99f056430ff2ad257c831"
|
||||
integrity sha512-o6yw06XACSzFFDBdKTl8o0B/R2HVcfRKyTPQTakKcCwlHMKpsgdWNNf5F4BV8n9nSry4g7jSIhrD0WS5Eu7klg==
|
||||
dependencies:
|
||||
"@tiptap/extension-bubble-menu" "^2.5.9"
|
||||
"@tiptap/extension-floating-menu" "^2.5.9"
|
||||
"@tiptap/extension-bubble-menu" "^2.6.0"
|
||||
"@tiptap/extension-floating-menu" "^2.6.0"
|
||||
vue-ts-types "^1.6.0"
|
||||
|
||||
"@tootallnate/once@2":
|
||||
|
|
|
|||
Loading…
Reference in New Issue