Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2024-07-23 00:26:35 +00:00
parent 013d339e9a
commit 8212b8fd70
77 changed files with 619 additions and 239 deletions

View File

@ -587,11 +587,13 @@ lib/gitlab/checks/**
/doc/administration/package_information/ @axil
/doc/administration/packages/ @marcel.amirault
/doc/administration/packages/index.md @phillipwells
/doc/administration/pages/ @msedlakjakubowski
/doc/administration/polling.md @axil
/doc/administration/postgresql/ @lciutacu
/doc/administration/raketasks/ @axil
/doc/administration/raketasks/ldap.md @jglassman1
/doc/administration/raketasks/praefect.md @eread
/doc/administration/raketasks/tokens/ @jglassman1
/doc/administration/read_only_gitlab.md @axil
/doc/administration/redis/ @axil
/doc/administration/reference_architectures/ @axil
@ -646,6 +648,7 @@ lib/gitlab/checks/**
/doc/administration/troubleshooting/ @axil
/doc/administration/uploads.md @axil
/doc/administration/user_settings.md @jglassman1
/doc/administration/wikis/ @msedlakjakubowski
/doc/api/access_requests.md @jglassman1
/doc/api/admin_sidekiq_queues.md @axil
/doc/api/api_resources.md @eread
@ -706,6 +709,7 @@ lib/gitlab/checks/**
/doc/api/group_releases.md @phillipwells
/doc/api/group_repository_storage_moves.md @ashrafkhamis
/doc/api/group_ssh_certificates.md @msedlakjakubowski
/doc/api/group_wikis.md @msedlakjakubowski
/doc/api/groups.md @lciutacu
/doc/api/import.md @eread
/doc/api/index.md @eread
@ -738,6 +742,8 @@ lib/gitlab/checks/**
/doc/api/openapi/ @eread
/doc/api/packages.md @phillipwells
/doc/api/packages/ @phillipwells
/doc/api/pages.md @msedlakjakubowski
/doc/api/pages_domains.md @msedlakjakubowski
/doc/api/personal_access_tokens.md @jglassman1
/doc/api/pipeline_schedules.md @marcel.amirault @lyspin
/doc/api/pipeline_triggers.md @marcel.amirault @lyspin
@ -800,6 +806,7 @@ lib/gitlab/checks/**
/doc/api/vulnerabilities.md @rdickenson
/doc/api/vulnerability_exports.md @rdickenson
/doc/api/vulnerability_findings.md @rdickenson
/doc/api/wikis.md @msedlakjakubowski
/doc/ci/ @marcel.amirault @lyspin
/doc/ci/chatops/ @phillipwells
/doc/ci/cloud_deployment/ @phillipwells
@ -899,6 +906,7 @@ lib/gitlab/checks/**
/doc/tutorials/dependency_scanning.md @rdickenson @phillipwells
/doc/tutorials/export_sbom.md @rdickenson @phillipwells
/doc/tutorials/fuzz_testing/ @rdickenson @phillipwells
/doc/tutorials/hugo/ @msedlakjakubowski
/doc/tutorials/idea_management/ @msedlakjakubowski
/doc/tutorials/install_gitlab_single_node/ @axil
/doc/tutorials/issue_triage/ @msedlakjakubowski
@ -914,6 +922,7 @@ lib/gitlab/checks/**
/doc/tutorials/update_commit_messages/ @msedlakjakubowski
/doc/tutorials/website_project_with_analytics/ @lciutacu
/doc/update/ @axil
/doc/user/ @msedlakjakubowski
/doc/user/analytics/ @lciutacu
/doc/user/analytics/ci_cd_analytics.md @phillipwells
/doc/user/application_security/ @rdickenson @phillipwells
@ -923,13 +932,11 @@ lib/gitlab/checks/**
/doc/user/application_security/security_dashboard/ @rdickenson
/doc/user/application_security/vulnerabilities/ @rdickenson
/doc/user/application_security/vulnerability_report/ @rdickenson
/doc/user/asciidoc.md @msedlakjakubowski
/doc/user/clusters/ @phillipwells
/doc/user/compliance/ @eread
/doc/user/compliance/license_approval_policies.md @rdickenson
/doc/user/compliance/license_scanning_of_cyclonedx_files/ @rdickenson @phillipwells
/doc/user/discussions/ @aqualls
/doc/user/emoji_reactions.md @msedlakjakubowski
/doc/user/enterprise_user/ @jglassman1
/doc/user/get_started/get_started_managing_code.md @msedlakjakubowski
/doc/user/get_started/get_started_managing_infrastructure.md @phillipwells
@ -962,9 +969,7 @@ lib/gitlab/checks/**
/doc/user/infrastructure/ @phillipwells
/doc/user/infrastructure/clusters/manage/management_project_applications/ @phillipwells
/doc/user/infrastructure/clusters/manage/management_project_applications/runner.md @ashrafkhamis
/doc/user/markdown.md @msedlakjakubowski
/doc/user/namespace/ @lciutacu
/doc/user/okrs.md @msedlakjakubowski
/doc/user/operations_dashboard/ @phillipwells
/doc/user/organization/ @lciutacu
/doc/user/packages/ @phillipwells
@ -976,7 +981,6 @@ lib/gitlab/checks/**
/doc/user/profile/achievements.md @lciutacu
/doc/user/profile/comment_templates.md @aqualls
/doc/user/profile/contributions_calendar.md @lciutacu
/doc/user/project/ @msedlakjakubowski
/doc/user/project/badges.md @lciutacu
/doc/user/project/clusters/ @phillipwells
/doc/user/project/code_intelligence.md @aqualls
@ -1028,11 +1032,9 @@ lib/gitlab/checks/**
/doc/user/public_access.md @lciutacu
/doc/user/reserved_names.md @lciutacu
/doc/user/search/ @ashrafkhamis
/doc/user/snippets.md @msedlakjakubowski
/doc/user/ssh.md @jglassman1
/doc/user/ssh_troubleshooting.md @jglassman1
/doc/user/storage_management_automation.md @fneill
/doc/user/tasks.md @msedlakjakubowski
/doc/user/usage_quotas.md @fneill
/doc/user/workspace/ @ashrafkhamis
# End rake-managed-docs-block

View File

@ -407,7 +407,8 @@ gem 'webrick', '~> 1.8.1', require: false # rubocop:todo Gemfile/MissingFeatureC
gem 'prometheus-client-mmap', '~> 1.1', '>= 1.1.1', require: 'prometheus/client' # rubocop:todo Gemfile/MissingFeatureCategory
# Event-driven reactor for Ruby
gem 'async', '~> 2.12.1' # rubocop:disable Gemfile/MissingFeatureCategory -- This is general utility gem
# Required manually in config/initializers/require_async_gem
gem 'async', '~> 2.12.1', require: false # rubocop:disable Gemfile/MissingFeatureCategory -- This is general utility gem
# OpenTelemetry
group :opentelemetry do

View File

@ -8,7 +8,7 @@ import { getCookie, setCookie, parseBoolean } from '~/lib/utils/common_utils';
import { waitForElement } from '~/lib/utils/dom_utils';
import findAndFollowLink from '~/lib/utils/navigation_utility';
import { refreshCurrentPage } from '~/lib/utils/url_utility';
import { helpCenterState } from '~/super_sidebar/constants';
import { duoChatGlobalState } from '~/super_sidebar/constants';
import {
keysFor,
TOGGLE_KEYBOARD_SHORTCUTS_DIALOG,
@ -225,7 +225,7 @@ export default class Shortcuts {
static onToggleDuoChat(e) {
e.preventDefault();
helpCenterState.showTanukiBotChatDrawer = !helpCenterState.showTanukiBotChatDrawer;
duoChatGlobalState.isShown = !duoChatGlobalState.isShown;
}
static onTogglePerfBar(e) {

View File

@ -60,6 +60,7 @@ export default {
modelData: null,
versionData: null,
markdownDocPath: helpPagePath('user/markdown'),
markdownEditorRestrictedToolBarItems: ['full-screen'],
};
},
computed: {
@ -242,7 +243,7 @@ export default {
:title="$options.modal.title"
:action-primary="actionPrimary"
:action-secondary="$options.modal.actionSecondary"
size="sm"
size="lg"
@primary="create"
@secondary="resetModal"
>
@ -284,6 +285,7 @@ export default {
:markdown-docs-path="markdownDocPath"
:disable-attachments="disableAttachments"
:placeholder="$options.modal.nameDescriptionPlaceholder"
:restricted-tool-bar-items="markdownEditorRestrictedToolBarItems"
@input="setDescription"
/>
</gl-form-group>

View File

@ -173,7 +173,7 @@ export default {
:title="$options.modal.title"
:action-primary="actionPrimary"
:action-secondary="$options.modal.actionSecondary"
size="sm"
size="lg"
@primary="create"
@secondary="resetModal"
>

View File

@ -6,7 +6,7 @@ import { FORUM_URL, PROMO_URL } from 'jh_else_ce/lib/utils/url_utility';
import { __ } from '~/locale';
import { STORAGE_KEY } from '~/whats_new/utils/notification';
import Tracking from '~/tracking';
import { DROPDOWN_Y_OFFSET, HELP_MENU_TRACKING_DEFAULTS, helpCenterState } from '../constants';
import { DROPDOWN_Y_OFFSET, HELP_MENU_TRACKING_DEFAULTS, duoChatGlobalState } from '../constants';
export default {
components: {
@ -39,7 +39,7 @@ export default {
data() {
return {
showWhatsNewNotification: this.shouldShowWhatsNewNotification(),
helpCenterState,
duoChatGlobalState,
toggleWhatsNewDrawer: null,
};
},

View File

@ -21,8 +21,9 @@ export const sidebarState = Vue.observable({
wasHoverPeek: false,
});
export const helpCenterState = Vue.observable({
showTanukiBotChatDrawer: false,
export const duoChatGlobalState = Vue.observable({
commands: [],
isShown: false,
});
export const SUPER_SIDEBAR_PEEK_OPEN_DELAY = 200;

View File

@ -119,6 +119,11 @@ export default {
required: false,
default: () => ({}),
},
restrictedToolBarItems: {
type: Array,
required: false,
default: () => [],
},
},
data() {
const editingMode =
@ -139,7 +144,9 @@ export default {
return this.autofocus && !this.autofocused ? 'end' : false;
},
markdownFieldRestrictedToolBarItems() {
return this.disableAttachments ? ['attach-file'] : [];
const restrictAttachments = this.disableAttachments ? ['attach-file'] : [];
return [...this.restrictedToolBarItems, ...restrictAttachments];
},
},
watch: {

View File

@ -187,10 +187,15 @@ class GraphqlController < ApplicationController
def disable_query_limiting
return unless Gitlab::QueryLimiting.enabled_for_env?
disable_issue = request.headers[DISABLE_SQL_QUERY_LIMIT_HEADER]
return unless disable_issue
disable_reference = request.headers[DISABLE_SQL_QUERY_LIMIT_HEADER]
return unless disable_reference
Gitlab::QueryLimiting.disable!(disable_issue)
disable_issue, new_threshold = disable_reference.split(';')
if new_threshold
Gitlab::QueryLimiting.disable!(disable_issue, new_threshold: new_threshold&.to_i)
else
Gitlab::QueryLimiting.disable!(disable_issue)
end
end
def set_user_last_activity

View File

@ -21,7 +21,10 @@ class Import::GitlabGroupsController < ApplicationController
)
.with_defaults(organization_id: Current.organization_id)
response = ::Groups::CreateService.new(current_user, group_data).execute
response = Namespace.with_disabled_organization_validation do
::Groups::CreateService.new(current_user, group_data).execute
end
group = response[:group]
if response.success?

View File

@ -22,7 +22,9 @@ class Ldap::OmniauthCallbacksController < OmniauthCallbacksController
return admin_mode_flow(Gitlab::Auth::Ldap::User) if current_user_mode.admin_mode_requested?
end
sign_in_user_flow(Gitlab::Auth::Ldap::User)
Namespace.with_disabled_organization_validation do
sign_in_user_flow(Gitlab::Auth::Ldap::User)
end
end
define_providers!

View File

@ -165,7 +165,9 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
redirect_identity_exists
end
else
sign_in_user_flow(auth_module::User)
Namespace.with_disabled_organization_validation do
sign_in_user_flow(auth_module::User)
end
end
end

View File

@ -38,14 +38,15 @@ class RegistrationsController < Devise::RegistrationsController
def create
set_resource_fields
super do |new_user|
if new_user.persisted?
after_successful_create_hook(new_user)
else
track_error(new_user)
Namespace.with_disabled_organization_validation do
super do |new_user|
if new_user.persisted?
after_successful_create_hook(new_user)
else
track_error(new_user)
end
end
end
# Devise sets a flash message on both successful & failed signups,
# but we only want to show a message if the resource is blocked by a pending approval.
flash[:notice] = nil unless allow_flash_content?(resource)

View File

@ -7,79 +7,42 @@ module Types
graphql_name 'WorkItemWidget'
field :type, ::Types::WorkItems::WidgetTypeEnum,
field :type,
::Types::WorkItems::WidgetTypeEnum,
null: true,
description: 'Widget type.'
ORPHAN_TYPES = [
::Types::WorkItems::Widgets::DescriptionType,
::Types::WorkItems::Widgets::HierarchyType,
::Types::WorkItems::Widgets::LabelsType,
::Types::WorkItems::Widgets::AssigneesType,
::Types::WorkItems::Widgets::StartAndDueDateType,
::Types::WorkItems::Widgets::MilestoneType,
::Types::WorkItems::Widgets::NotesType,
::Types::WorkItems::Widgets::NotificationsType,
::Types::WorkItems::Widgets::CurrentUserTodosType,
::Types::WorkItems::Widgets::AwardEmojiType,
::Types::WorkItems::Widgets::LinkedItemsType,
::Types::WorkItems::Widgets::ParticipantsType,
::Types::WorkItems::Widgets::TimeTracking::TimeTrackingType,
::Types::WorkItems::Widgets::DesignsType,
::Types::WorkItems::Widgets::DevelopmentType,
::Types::WorkItems::Widgets::CrmContactsType
].freeze
def self.ce_orphan_types
ORPHAN_TYPES
end
# Whenever a new widget is added make sure to update the spec to avoid N + 1 queries in
# spec/requests/api/graphql/project/work_items_spec.rb and add the necessary preloads
# in app/graphql/resolvers/work_items_resolver.rb
#
# rubocop:disable Metrics/CyclomaticComplexity -- we'll have a lot of widgets to handle in the WidgetInterface
def self.resolve_type(object, context)
case object
when ::WorkItems::Widgets::Description
::Types::WorkItems::Widgets::DescriptionType
when ::WorkItems::Widgets::Hierarchy
::Types::WorkItems::Widgets::HierarchyType
when ::WorkItems::Widgets::Assignees
::Types::WorkItems::Widgets::AssigneesType
when ::WorkItems::Widgets::Labels
::Types::WorkItems::Widgets::LabelsType
when ::WorkItems::Widgets::StartAndDueDate
::Types::WorkItems::Widgets::StartAndDueDateType
when ::WorkItems::Widgets::Milestone
::Types::WorkItems::Widgets::MilestoneType
when ::WorkItems::Widgets::Notes
::Types::WorkItems::Widgets::NotesType
when ::WorkItems::Widgets::Notifications
::Types::WorkItems::Widgets::NotificationsType
when ::WorkItems::Widgets::CurrentUserTodos
::Types::WorkItems::Widgets::CurrentUserTodosType
when ::WorkItems::Widgets::AwardEmoji
::Types::WorkItems::Widgets::AwardEmojiType
when ::WorkItems::Widgets::LinkedItems
::Types::WorkItems::Widgets::LinkedItemsType
when ::WorkItems::Widgets::Participants
::Types::WorkItems::Widgets::ParticipantsType
when ::WorkItems::Widgets::TimeTracking
::Types::WorkItems::Widgets::TimeTracking::TimeTrackingType
when ::WorkItems::Widgets::Designs
::Types::WorkItems::Widgets::DesignsType
when ::WorkItems::Widgets::Development
::Types::WorkItems::Widgets::DevelopmentType
when ::WorkItems::Widgets::CrmContacts
::Types::WorkItems::Widgets::CrmContactsType
else
raise "Unknown GraphQL type for widget #{object}"
end
end
# rubocop:enable Metrics/CyclomaticComplexity
TYPE_MAPPINGS = {
::WorkItems::Widgets::Description => ::Types::WorkItems::Widgets::DescriptionType,
::WorkItems::Widgets::Hierarchy => ::Types::WorkItems::Widgets::HierarchyType,
::WorkItems::Widgets::Labels => ::Types::WorkItems::Widgets::LabelsType,
::WorkItems::Widgets::Assignees => ::Types::WorkItems::Widgets::AssigneesType,
::WorkItems::Widgets::StartAndDueDate => ::Types::WorkItems::Widgets::StartAndDueDateType,
::WorkItems::Widgets::Milestone => ::Types::WorkItems::Widgets::MilestoneType,
::WorkItems::Widgets::Notes => ::Types::WorkItems::Widgets::NotesType,
::WorkItems::Widgets::Notifications => ::Types::WorkItems::Widgets::NotificationsType,
::WorkItems::Widgets::CurrentUserTodos => ::Types::WorkItems::Widgets::CurrentUserTodosType,
::WorkItems::Widgets::AwardEmoji => ::Types::WorkItems::Widgets::AwardEmojiType,
::WorkItems::Widgets::LinkedItems => ::Types::WorkItems::Widgets::LinkedItemsType,
::WorkItems::Widgets::Participants => ::Types::WorkItems::Widgets::ParticipantsType,
::WorkItems::Widgets::TimeTracking => ::Types::WorkItems::Widgets::TimeTracking::TimeTrackingType,
::WorkItems::Widgets::Designs => ::Types::WorkItems::Widgets::DesignsType,
::WorkItems::Widgets::Development => ::Types::WorkItems::Widgets::DevelopmentType,
::WorkItems::Widgets::CrmContacts => ::Types::WorkItems::Widgets::CrmContactsType
}.freeze
orphan_types(*ORPHAN_TYPES)
def self.type_mappings
TYPE_MAPPINGS
end
def self.resolve_type(object, context)
type_mappings[object.class] || raise("Unknown GraphQL type for widget #{object}")
end
orphan_types(*type_mappings.values)
end
end
end

View File

@ -115,6 +115,7 @@ class Namespace < ApplicationRecord
has_one :import_user, class_name: 'User', through: :namespace_import_user, foreign_key: :user_id
validates :owner, presence: true, if: ->(n) { n.owner_required? }
validates :organization, presence: true, if: :require_organization?
validates :name,
presence: true,
length: { maximum: 255 }
@ -351,6 +352,15 @@ class Namespace < ApplicationRecord
coalesce = Arel::Nodes::NamedFunction.new('COALESCE', [sum, 0])
coalesce.as(column.to_s)
end
def with_disabled_organization_validation
current_value = Gitlab::SafeRequestStore[:require_organization]
Gitlab::SafeRequestStore[:require_organization] = false
yield
ensure
Gitlab::SafeRequestStore[:require_organization] = current_value
end
end
def to_reference_base(from = nil, full: false, absolute_path: false)
@ -712,6 +722,12 @@ class Namespace < ApplicationRecord
:active_pages_deployments)
end
def require_organization?
return false unless Feature.enabled?(:require_organization, Feature.current_request)
Gitlab::SafeRequestStore.fetch(:require_organization) { true } # rubocop:disable Style/RedundantFetchBlock -- This fetch has a different interface
end
private
def cross_namespace_reference?(from)

View File

@ -27,7 +27,9 @@ module Ci
runner = ::Ci::Runner.new(params)
return ServiceResponse.success(payload: { runner: runner }) if runner.save
if Namespace.with_disabled_organization_validation { runner.save }
return ServiceResponse.success(payload: { runner: runner })
end
ServiceResponse.error(message: runner.errors.full_messages, reason: :save_error)
end

View File

@ -17,7 +17,7 @@ module Groups
@group.name ||= @group.path.dup
create_chat_team
create_group
Namespace.with_disabled_organization_validation { create_group }
return error_response unless @group.persisted?

View File

@ -39,7 +39,7 @@ module Groups
group.assign_attributes(params)
begin
success = group.save
success = Namespace.with_disabled_organization_validation { group.save }
after_update if success

View File

@ -88,7 +88,7 @@ module MergeRequests
trigger_merge_request_reviewers_updated(merge_request)
capture_suggested_reviewers_accepted(merge_request)
set_first_reviewer_assigned_at_metrics(merge_request, current_user) if new_reviewers.any?
set_first_reviewer_assigned_at_metrics(merge_request) if new_reviewers.any?
end
def cleanup_environments(merge_request)
@ -279,9 +279,7 @@ module MergeRequests
# Implemented in EE
end
def set_first_reviewer_assigned_at_metrics(merge_request, user)
return unless Feature.enabled?(:store_first_reviewer_assignment_timestamp_in_metrics, user, type: :beta)
def set_first_reviewer_assigned_at_metrics(merge_request)
metrics = merge_request.metrics
return unless metrics

View File

@ -13,7 +13,9 @@ module Users
user = build_class.new(current_user, params).execute
reset_token = user.generate_reset_token if user.recently_sent_password_reset?
after_create_hook(user, reset_token) if user.save
Namespace.with_disabled_organization_validation do
after_create_hook(user, reset_token) if user.save
end
user
end

View File

@ -1,9 +1,9 @@
---
name: store_first_reviewer_assignment_timestamp_in_metrics
feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/466383
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/158422
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/470926
milestone: '17.2'
group: group::optimize
type: beta
default_enabled: true
name: require_organization
feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/411832
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/155732
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/470839
milestone: '17.3'
group: group::tenant scale
type: gitlab_com_derisk
default_enabled: false

View File

@ -0,0 +1,13 @@
# frozen_string_literal: true
if RUBY_VERSION >= "3.3"
# No more such warnings in Ruby 3.3+
require 'async'
else
# Silences this warning while requiring async gem:
# `warning: IO::Buffer is experimental and both the Ruby and C interface may change in the future!`
# See also https://github.com/socketry/io-event/issues/82
Kernel.silence_warnings do
require 'async'
end
end

View File

@ -0,0 +1,9 @@
---
migration_job_name: BackfillEvidencesProjectId
description: Backfills sharding key `evidences.project_id` from `releases`.
feature_category: release_evidence
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/159580
milestone: '17.3'
queued_migration_version: 20240716133952
finalize_after: '2024-08-22'
finalized_by: # version of the migration that finalized this BBM

View File

@ -17,3 +17,4 @@ desired_sharding_key:
table: releases
sharding_key: project_id
belongs_to: release
desired_sharding_key_migration_job_name: BackfillEvidencesProjectId

View File

@ -0,0 +1,9 @@
# frozen_string_literal: true
class AddProjectIdToEvidences < Gitlab::Database::Migration[2.2]
milestone '17.3'
def change
add_column :evidences, :project_id, :bigint
end
end

View File

@ -0,0 +1,16 @@
# frozen_string_literal: true
class IndexEvidencesOnProjectId < Gitlab::Database::Migration[2.2]
milestone '17.3'
disable_ddl_transaction!
INDEX_NAME = 'index_evidences_on_project_id'
def up
add_concurrent_index :evidences, :project_id, name: INDEX_NAME
end
def down
remove_concurrent_index_by_name :evidences, INDEX_NAME
end
end

View File

@ -0,0 +1,16 @@
# frozen_string_literal: true
class AddEvidencesProjectIdFk < Gitlab::Database::Migration[2.2]
milestone '17.3'
disable_ddl_transaction!
def up
add_concurrent_foreign_key :evidences, :projects, column: :project_id, on_delete: :cascade
end
def down
with_lock_retries do
remove_foreign_key :evidences, column: :project_id
end
end
end

View File

@ -0,0 +1,25 @@
# frozen_string_literal: true
class AddEvidencesProjectIdTrigger < Gitlab::Database::Migration[2.2]
milestone '17.3'
def up
install_sharding_key_assignment_trigger(
table: :evidences,
sharding_key: :project_id,
parent_table: :releases,
parent_sharding_key: :project_id,
foreign_key: :release_id
)
end
def down
remove_sharding_key_assignment_trigger(
table: :evidences,
sharding_key: :project_id,
parent_table: :releases,
parent_sharding_key: :project_id,
foreign_key: :release_id
)
end
end

View File

@ -0,0 +1,40 @@
# frozen_string_literal: true
class QueueBackfillEvidencesProjectId < Gitlab::Database::Migration[2.2]
milestone '17.3'
restrict_gitlab_migration gitlab_schema: :gitlab_main_cell
MIGRATION = "BackfillEvidencesProjectId"
DELAY_INTERVAL = 2.minutes
BATCH_SIZE = 1000
SUB_BATCH_SIZE = 100
def up
queue_batched_background_migration(
MIGRATION,
:evidences,
:id,
:project_id,
:releases,
:project_id,
:release_id,
job_interval: DELAY_INTERVAL,
batch_size: BATCH_SIZE,
sub_batch_size: SUB_BATCH_SIZE
)
end
def down
delete_batched_background_migration(
MIGRATION,
:evidences,
:id,
[
:project_id,
:releases,
:project_id,
:release_id
]
)
end
end

View File

@ -0,0 +1 @@
db1a5709484f2352e0858fb1efc4191e408c361aba1d3b94a50f943c508fd941

View File

@ -0,0 +1 @@
4b6c8960d7eab5e62087b56afb1855b277eab8bd38662f7fc8c269392638ff06

View File

@ -0,0 +1 @@
8680f5ef0acbc1e9b4bebf9b8c81e7d72f72f7f2bdc68d6aab247dd9b8ad4416

View File

@ -0,0 +1 @@
1798657b951493363ac8bd42596b3ff2b6007a0e80f026a2f1890543b1d2f7bf

View File

@ -0,0 +1 @@
b88c38cc0991bda066f569bbb3e6a1519bccc19219dde3782eb7afdffbe4063c

View File

@ -1757,6 +1757,22 @@ RETURN NEW;
END
$$;
CREATE FUNCTION trigger_cac7c0698291() RETURNS trigger
LANGUAGE plpgsql
AS $$
BEGIN
IF NEW."project_id" IS NULL THEN
SELECT "project_id"
INTO NEW."project_id"
FROM "releases"
WHERE "releases"."id" = NEW."release_id";
END IF;
RETURN NEW;
END
$$;
CREATE FUNCTION trigger_d4487a75bd44() RETURNS trigger
LANGUAGE plpgsql
AS $$
@ -10457,7 +10473,8 @@ CREATE TABLE evidences (
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL,
summary_sha bytea,
summary jsonb DEFAULT '{}'::jsonb NOT NULL
summary jsonb DEFAULT '{}'::jsonb NOT NULL,
project_id bigint
);
CREATE SEQUENCE evidences_id_seq
@ -27366,6 +27383,8 @@ CREATE INDEX index_events_on_project_id_and_id ON events USING btree (project_id
CREATE UNIQUE INDEX index_events_on_target_type_and_target_id_and_fingerprint ON events USING btree (target_type, target_id, fingerprint);
CREATE INDEX index_evidences_on_project_id ON evidences USING btree (project_id);
CREATE INDEX index_evidences_on_release_id ON evidences USING btree (release_id);
CREATE INDEX index_expired_and_not_notified_personal_access_tokens ON personal_access_tokens USING btree (id, expires_at) WHERE ((impersonation = false) AND (revoked = false) AND (expire_notification_delivered = false));
@ -31914,6 +31933,8 @@ CREATE TRIGGER trigger_c8bc8646bce9 BEFORE INSERT OR UPDATE ON vulnerability_sta
CREATE TRIGGER trigger_c9090feed334 BEFORE INSERT OR UPDATE ON boards_epic_lists FOR EACH ROW EXECUTE FUNCTION trigger_c9090feed334();
CREATE TRIGGER trigger_cac7c0698291 BEFORE INSERT OR UPDATE ON evidences FOR EACH ROW EXECUTE FUNCTION trigger_cac7c0698291();
CREATE TRIGGER trigger_catalog_resource_sync_event_on_project_update AFTER UPDATE ON projects FOR EACH ROW WHEN ((((old.name)::text IS DISTINCT FROM (new.name)::text) OR (old.description IS DISTINCT FROM new.description) OR (old.visibility_level IS DISTINCT FROM new.visibility_level))) EXECUTE FUNCTION insert_catalog_resource_sync_event();
CREATE TRIGGER trigger_d4487a75bd44 BEFORE INSERT OR UPDATE ON terraform_state_versions FOR EACH ROW EXECUTE FUNCTION trigger_d4487a75bd44();
@ -33125,6 +33146,9 @@ ALTER TABLE ONLY personal_access_tokens
ALTER TABLE ONLY jira_tracker_data
ADD CONSTRAINT fk_c98abcd54c FOREIGN KEY (integration_id) REFERENCES integrations(id) ON DELETE CASCADE;
ALTER TABLE ONLY evidences
ADD CONSTRAINT fk_ca4bbc114d FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
ALTER TABLE ONLY subscription_add_on_purchases
ADD CONSTRAINT fk_caed789645 FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE;

View File

@ -21,6 +21,7 @@ exceptions:
- ANSI
- APAC
- API
- ARIA
- APM
- ARM
- ARN

View File

@ -46,7 +46,8 @@ Instead of checking repositories manually, GitLab can be configured to run the c
1. Enable **Enable repository checks**.
When enabled, GitLab periodically runs a repository check on all project repositories and wiki
repositories to detect possible data corruption. A project is checked no more than once per month.
repositories to detect possible data corruption. A project is checked no more than once per month, and new projects aren't checked for at least 24 hours.
Administrators can configure the frequency of repository checks. To edit the frequency:
- For Linux package installations, edit `gitlab_rails['repository_check_worker_cron']` in

View File

@ -118,45 +118,38 @@ Chat interface. The following example shows how to open the GitLab Duo Chat
drawer by using an event listener and the GitLab Duo Chat global state:
```javascript
import { helpCenterState } from '~/super_sidebar/constants';
import { duoChatGlobalState } from '~/super_sidebar/constants';
myFancyToggleToOpenChat.addEventListener('click', () => {
helpCenterState.showTanukiBotChatDrawer = true;
duoChatGlobalState.isShown = true;
});
```
#### Initiating GitLab Duo Chat with a pre-defined prompt
In some scenarios, you may want to direct users towards a specific topic or
query when they open GitLab Duo Chat. The following example method:
1. Opens the GitLab Duo Chat drawer.
1. Sends a pre-defined prompt to GitLab Duo Chat.
query when they open GitLab Duo Chat. We have a utility function that will
open DuoChat drawer and send a command in a queue for DuoChat to execute on.
This should trigger the loading state and the streaming with the given prompt.
```javascript
import chatMutation from 'ee/ai/graphql/chat.mutation.graphql';
import { helpCenterState } from '~/super_sidebar/constants';
import { sendDuoChatCommand } from 'ee/ai/utils';
[...]
methods: {
openChatWithPrompt() {
const myPrompt = "What is the meaning of life?"
helpCenterState.showTanukiBotChatDrawer = true;
this.$apollo
.mutate({
mutation: chatMutation,
variables: {
question: myPrompt,
resourceId: this.resourceId,
},
})
.catch((error) => {
// handle potential errors here
});
sendDuoChatCommand(
{
question: '/feedback' // This is your prompt
resourceId: 'gid:://gitlab/WorkItem/1', // A unique ID to identify the action for streaming
variables: {} // Any additional graphql variables you want to pass to ee/app/assets/javascripts/ai/graphql/chat.mutation.graphql when executing the query
}
)
}
}
```
Note that `sendDuoChatCommand` cannot be chained, meaning that you can send one command to DuoChat and have to wait until this action is done before sending a different command or the previous command might not work as expected.
This enhancement allows for a more tailored user experience by guiding the
conversation in GitLab Duo Chat towards predefined areas of interest or concern.

View File

@ -31,6 +31,7 @@ All tables with the following `gitlab_schema` are considered "cell-local":
- `gitlab_main_cell`
- `gitlab_ci`
- `gitlab_sec`
All newly created cell-local tables are required to have a `sharding_key`
defined in the corresponding `db/docs/` file for that table.

View File

@ -12,4 +12,15 @@ The following feature flags exist in GitLab. These flags determine the availabil
For self-managed instances, [GitLab administrators can change the state of the flag](../administration/feature_flags.md).
<!-- markdownlint-disable MD044 -->
<!-- MD044/proper-names test disabled after this line to make page compatible with markdownlint-cli 0.29.0. -->
<!-- See https://docs.gitlab.com/ee/development/documentation/testing/markdownlint.html#disable-markdownlint-tests -->
<div class="d-none">
<strong>If you don't see the feature flag tables below, view them at <a href="https://docs.gitlab.com/ee/user/feature_flags.html">docs.gitlab.com</a>.</strong>
</div>
<!-- the div above will not display on the docs site but will display on /help -->
<!-- markdownlint-enable MD044 -->
<!-- When published, everything below this line is generated by 'layouts/feature_flags_table.md.erb' in the 'gitlab-docs' repository -->

View File

@ -57,7 +57,9 @@ module Gitlab
block_after_save = needs_blocking?
Users::UpdateService.new(gl_user, user: gl_user).execute!
Namespace.with_disabled_organization_validation do
Users::UpdateService.new(gl_user, user: gl_user).execute!
end
gl_user.block_pending_approval if block_after_save
activate_user_if_user_cap_not_reached

View File

@ -0,0 +1,10 @@
# frozen_string_literal: true
module Gitlab
module BackgroundMigration
class BackfillEvidencesProjectId < BackfillDesiredShardingKeyJob
operation_name :backfill_evidences_project_id
feature_category :release_evidence
end
end
end

View File

@ -19,7 +19,9 @@ module Gitlab
)
user.assign_personal_namespace(Organizations::Organization.default_organization)
user.save!
Namespace.with_disabled_organization_validation do
user.save!
end
user
end

View File

@ -178,7 +178,7 @@ module Gitlab
modify_attributes
@importable.save!(touch: false)
Namespace.with_disabled_organization_validation { @importable.save!(touch: false) }
end
def filter_attributes(params)

View File

@ -178,7 +178,9 @@ module Gitlab
def create_group(**args)
logger.info(message: 'Creating group', **args)
ensure_success(::Groups::CreateService.new(@user, **args).execute[:group])
Namespace.with_disabled_organization_validation do
ensure_success(::Groups::CreateService.new(@user, **args).execute[:group])
end
end
def ensure_project(name:, namespace_id:, **args)
@ -194,7 +196,9 @@ module Gitlab
def create_project(**args)
logger.info(message: 'Creating project', **args)
ensure_success(::Projects::CreateService.new(@user, **args).execute)
Namespace.with_disabled_organization_validation do
ensure_success(::Projects::CreateService.new(@user, **args).execute)
end
end
def register_record(record, records)

View File

@ -18,6 +18,7 @@ namespace :tw do
end
end
# For groups without an assigned TW, comment out the line.
CODE_OWNER_RULES = [
# CodeOwnerRule.new('Activation', ''),
# CodeOwnerRule.new('Acquisition', ''),
@ -56,7 +57,7 @@ namespace :tw do
CodeOwnerRule.new('Remote Development', '@ashrafkhamis'),
CodeOwnerRule.new('Import and Integrate', '@eread'),
CodeOwnerRule.new('Infrastructure', '@sselhorn'),
# CodeOwnerRule.new('Knowledge', ''),
CodeOwnerRule.new('Knowledge', '@msedlakjakubowski'),
CodeOwnerRule.new('MLOps', '@sselhorn @jglassman1 @fneill'),
# CodeOwnerRule.new('Observability', ''),
CodeOwnerRule.new('Optimize', '@lciutacu'),

View File

@ -37,7 +37,9 @@ namespace :gitlab do
tmp_namespace_path = "tmp-project-import-#{Time.now.to_i}"
puts "Creating temporary namespace #{tmp_namespace_path}"
tmp_namespace = Namespace.create!(owner: admin, name: tmp_namespace_path, path: tmp_namespace_path, type: Namespaces::UserNamespace.sti_name)
tmp_namespace = Namespace.with_disabled_organization_validation do
Namespace.create!(owner: admin, name: tmp_namespace_path, path: tmp_namespace_path, type: Namespaces::UserNamespace.sti_name)
end
templates = if template_names.empty?
Gitlab::ProjectTemplate.all
@ -54,7 +56,7 @@ namespace :gitlab do
}
puts "Creating project for #{template.title}"
project = Projects::CreateService.new(admin, params).execute
project = Namespace.with_disabled_organization_validation { Projects::CreateService.new(admin, params).execute }
unless project.persisted?
raise "Failed to create project: #{project.errors.messages}"

View File

@ -2156,12 +2156,6 @@ msgstr ""
msgid "AISummary|View summary"
msgstr ""
msgid "AI|An error occurred while explaining the code."
msgstr ""
msgid "AI|An error occurred while troubleshooting the failed job."
msgstr ""
msgid "AI|Apply AI-generated description"
msgstr ""

View File

@ -11,7 +11,7 @@ gem 'capybara', '~> 3.40.0'
gem 'capybara-screenshot', '~> 1.0.26'
gem 'rake', '~> 13', '>= 13.2.1'
gem 'rspec', '~> 3.13'
gem 'selenium-webdriver', '= 4.22.0'
gem 'selenium-webdriver', '= 4.23.0'
gem 'airborne', '~> 0.3.7', require: false # airborne is messing with rspec sandboxed mode so not requiring by default
gem 'rest-client', '~> 2.1.0'
gem 'rspec_junit_formatter', '~> 0.6.0'

View File

@ -328,7 +328,7 @@ GEM
sawyer (0.9.2)
addressable (>= 2.3.5)
faraday (>= 0.17.3, < 3)
selenium-webdriver (4.22.0)
selenium-webdriver (4.23.0)
base64 (~> 0.2)
logger (~> 1.4)
rexml (~> 3.2, >= 3.2.5)
@ -423,7 +423,7 @@ DEPENDENCIES
rspec-parameterized (~> 1.0.2)
rspec_junit_formatter (~> 0.6.0)
ruby-debug-ide (~> 0.7.3)
selenium-webdriver (= 4.22.0)
selenium-webdriver (= 4.23.0)
slack-notifier (~> 2.4)
terminal-table (~> 3.0.2)
warning (~> 1.4)

View File

@ -11,6 +11,8 @@ FactoryBot.define do
owner { association(:user, strategy: :build, namespace: instance, username: path) }
association :organization
after(:create) do |namespace, evaluator|
# simulating ::Namespaces::ProcessSyncEventsWorker because most tests don't run Sidekiq inline
# Note: we need to get refreshed `traversal_ids` it is updated via SQL query

View File

@ -115,8 +115,6 @@ describe('ModelCreate', () => {
it('should show markdown editor', () => {
createWrapper();
expect(findMarkdownEditor().exists()).toBe(true);
expect(findMarkdownEditor().props()).toMatchObject({
enableContentEditor: true,
formFieldProps: {
@ -127,6 +125,7 @@ describe('ModelCreate', () => {
markdownDocsPath: '/help/user/markdown',
renderMarkdownPath: '/markdown-preview',
uploadsPath: '',
restrictedToolBarItems: ['full-screen'],
});
});
});
@ -238,7 +237,7 @@ describe('ModelCreate', () => {
expect(findGlModal().props()).toMatchObject({
modalId: 'create-model-modal',
title: 'Create model, version & import artifacts',
size: 'sm',
size: 'lg',
});
});

View File

@ -124,7 +124,7 @@ describe('ModelVersionCreate', () => {
expect(findGlModal().props()).toMatchObject({
modalId: 'create-model-version-modal',
title: 'Create model version & import artifacts',
size: 'sm',
size: 'lg',
});
});

View File

@ -203,6 +203,31 @@ describe('vue_shared/component/markdown/markdown_editor', () => {
});
});
describe('when additional restricted tool bar items are given', () => {
beforeEach(() => {
buildWrapper({ propsData: { restrictedToolBarItems: ['full-screen'] } });
});
it('passes them to restrictedToolBarItems', () => {
expect(findMarkdownField().props().restrictedToolBarItems).toContain('full-screen');
});
describe('when attachments are disabled', () => {
beforeEach(() => {
buildWrapper({
propsData: { disableAttachments: true, restrictedToolBarItems: ['full-screen'] },
});
});
it('passes `attach-file` and `full-screen` restrictedToolBarItems', () => {
expect(findMarkdownField().props().restrictedToolBarItems).toEqual([
'full-screen',
'attach-file',
]);
});
});
});
describe('disabled', () => {
it('disables markdown field when disabled prop is true', () => {
buildWrapper({ propsData: { disabled: true } });

View File

@ -266,13 +266,5 @@ RSpec.describe GitlabSchema.types['Group'], feature_category: :groups_and_projec
)
end
end
context 'when group does not have an organization associated with it' do
let_it_be(:group) { create(:group, :public, organization: nil) }
it 'returns nil' do
expect(organization_edit_path).to be_nil
end
end
end
end

View File

@ -1305,13 +1305,5 @@ RSpec.describe GitlabSchema.types['Project'], feature_category: :groups_and_proj
)
end
end
context 'when project does not have an organization associated with it' do
let_it_be(:project) { create(:project, :public, organization: nil) }
it 'returns nil' do
expect(organization_edit_path).to be_nil
end
end
end
end

View File

@ -4,6 +4,7 @@ require 'spec_helper'
RSpec.describe Types::WorkItems::WidgetInterface, feature_category: :team_planning do
include GraphqlHelpers
using RSpec::Parameterized::TableSyntax
it 'exposes the expected fields' do
expected_fields = %i[type]
@ -11,42 +12,45 @@ RSpec.describe Types::WorkItems::WidgetInterface, feature_category: :team_planni
expect(described_class).to have_graphql_fields(*expected_fields)
end
describe ".resolve_type" do
using RSpec::Parameterized::TableSyntax
where(:widget_class, :widget_type_name) do
WorkItems::Widgets::Description | Types::WorkItems::Widgets::DescriptionType
WorkItems::Widgets::Hierarchy | Types::WorkItems::Widgets::HierarchyType
WorkItems::Widgets::Assignees | Types::WorkItems::Widgets::AssigneesType
WorkItems::Widgets::Labels | Types::WorkItems::Widgets::LabelsType
WorkItems::Widgets::Notes | Types::WorkItems::Widgets::NotesType
WorkItems::Widgets::Notifications | Types::WorkItems::Widgets::NotificationsType
WorkItems::Widgets::CurrentUserTodos | Types::WorkItems::Widgets::CurrentUserTodosType
WorkItems::Widgets::AwardEmoji | Types::WorkItems::Widgets::AwardEmojiType
WorkItems::Widgets::LinkedItems | Types::WorkItems::Widgets::LinkedItemsType
WorkItems::Widgets::LinkedItems | Types::WorkItems::Widgets::LinkedItemsType
WorkItems::Widgets::StartAndDueDate | Types::WorkItems::Widgets::StartAndDueDateType
WorkItems::Widgets::Milestone | Types::WorkItems::Widgets::MilestoneType
WorkItems::Widgets::Participants | Types::WorkItems::Widgets::ParticipantsType
WorkItems::Widgets::TimeTracking | Types::WorkItems::Widgets::TimeTracking::TimeTrackingType
WorkItems::Widgets::Designs | Types::WorkItems::Widgets::DesignsType
WorkItems::Widgets::CrmContacts | Types::WorkItems::Widgets::CrmContactsType
end
where(:widget_class, :widget_type_name) do
WorkItems::Widgets::Description | Types::WorkItems::Widgets::DescriptionType
WorkItems::Widgets::Hierarchy | Types::WorkItems::Widgets::HierarchyType
WorkItems::Widgets::Assignees | Types::WorkItems::Widgets::AssigneesType
WorkItems::Widgets::Labels | Types::WorkItems::Widgets::LabelsType
WorkItems::Widgets::Notes | Types::WorkItems::Widgets::NotesType
WorkItems::Widgets::Notifications | Types::WorkItems::Widgets::NotificationsType
WorkItems::Widgets::CurrentUserTodos | Types::WorkItems::Widgets::CurrentUserTodosType
WorkItems::Widgets::AwardEmoji | Types::WorkItems::Widgets::AwardEmojiType
WorkItems::Widgets::LinkedItems | Types::WorkItems::Widgets::LinkedItemsType
WorkItems::Widgets::LinkedItems | Types::WorkItems::Widgets::LinkedItemsType
WorkItems::Widgets::StartAndDueDate | Types::WorkItems::Widgets::StartAndDueDateType
WorkItems::Widgets::Milestone | Types::WorkItems::Widgets::MilestoneType
WorkItems::Widgets::Participants | Types::WorkItems::Widgets::ParticipantsType
WorkItems::Widgets::TimeTracking | Types::WorkItems::Widgets::TimeTracking::TimeTrackingType
WorkItems::Widgets::Designs | Types::WorkItems::Widgets::DesignsType
WorkItems::Widgets::Development | Types::WorkItems::Widgets::DevelopmentType
WorkItems::Widgets::CrmContacts | Types::WorkItems::Widgets::CrmContactsType
end
with_them do
with_them do
describe ".resolve_type" do
it 'knows the correct type for objects' do
expect(
described_class.resolve_type(widget_class.new(build(:work_item)), {})
).to eq(widget_type_name)
end
it 'raises an error for an unknown type' do
project = build(:project)
expect { described_class.resolve_type(project, {}) }
.to raise_error("Unknown GraphQL type for widget #{project}")
end
end
it 'raises an error for an unknown type' do
project = build(:project)
expect { described_class.resolve_type(project, {}) }
.to raise_error("Unknown GraphQL type for widget #{project}")
describe '.orphan_types' do
it 'includes the type' do
expect(described_class.orphan_types).to include(widget_type_name)
end
end
end
end

View File

@ -51,7 +51,7 @@ RSpec.describe Gitlab::Auth::Ldap::User do
describe '#valid_sign_in?' do
before do
gl_user.save!
Namespace.with_disabled_organization_validation { gl_user.save! }
end
it 'returns true' do

View File

@ -30,6 +30,10 @@ RSpec.describe Gitlab::Auth::OAuth::User, feature_category: :system_access do
let(:ldap_user) { Gitlab::Auth::Ldap::Person.new(Net::LDAP::Entry.new, 'ldapmain') }
let(:ldap_user_2) { Gitlab::Auth::Ldap::Person.new(Net::LDAP::Entry.new, 'ldapmain') }
around do |example|
Namespace.with_disabled_organization_validation { example.run }
end
describe '.find_by_uid_and_provider' do
let(:provider) { 'provider' }
let(:uid) { 'uid' }

View File

@ -0,0 +1,15 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::BackgroundMigration::BackfillEvidencesProjectId,
feature_category: :release_evidence,
schema: 20240716133948 do
include_examples 'desired sharding key backfill job' do
let(:batch_table) { :evidences }
let(:backfill_column) { :project_id }
let(:backfill_via_table) { :releases }
let(:backfill_via_column) { :project_id }
let(:backfill_via_foreign_key) { :release_id }
end
end

View File

@ -43,18 +43,8 @@ RSpec.describe Gitlab::Git::ObjectPool, feature_category: :source_code_managemen
subject.create # rubocop:disable Rails/SaveBang
end
context "when the pool doesn't exist yet" do
it 'creates the pool' do
expect(subject.exists?).to be(true)
end
end
context 'when the pool already exists' do
it 'raises an FailedPrecondition' do
expect do
subject.create # rubocop:disable Rails/SaveBang
end.to raise_error(GRPC::FailedPrecondition)
end
it 'creates the pool' do
expect(subject.exists?).to be(true)
end
end

View File

@ -0,0 +1,33 @@
# frozen_string_literal: true
require 'spec_helper'
require_migration!
RSpec.describe QueueBackfillEvidencesProjectId, feature_category: :release_evidence do
let!(:batched_migration) { described_class::MIGRATION }
it 'schedules a new batched migration' do
reversible_migration do |migration|
migration.before -> {
expect(batched_migration).not_to have_scheduled_batched_migration
}
migration.after -> {
expect(batched_migration).to have_scheduled_batched_migration(
table_name: :evidences,
column_name: :id,
interval: described_class::DELAY_INTERVAL,
batch_size: described_class::BATCH_SIZE,
sub_batch_size: described_class::SUB_BATCH_SIZE,
gitlab_schema: :gitlab_main_cell,
job_arguments: [
:project_id,
:releases,
:project_id,
:release_id
]
)
}
end
end
end

View File

@ -42,8 +42,8 @@ RSpec.describe Analytics::CycleAnalytics::Stage, feature_category: :value_stream
describe '.distinct_stages_within_hierarchy' do
let_it_be(:group) { create(:group) }
let_it_be(:sub_group) { create(:group, parent: group) }
let_it_be(:project) { create(:project, group: sub_group).reload }
let_it_be(:sub_group) { create(:group, organization: group.organization, parent: group) }
let_it_be(:project) { create(:project, organization: group.organization, group: sub_group).reload }
before do
# event identifiers are the same

View File

@ -314,7 +314,7 @@ RSpec.describe Namespaces::ProjectNamespace, 'Routable', :with_clean_rails_cache
it 'skips route creation for the resource' do
expect do
described_class.create!(project: nil, parent: group, visibility_level: Gitlab::VisibilityLevel::PUBLIC, path: 'foo', name: 'foo')
described_class.create!(project: nil, organization: group.organization, parent: group, visibility_level: Gitlab::VisibilityLevel::PUBLIC, path: 'foo', name: 'foo')
end.not_to change { Route.count }
end
end

View File

@ -271,7 +271,7 @@ RSpec.describe Group, feature_category: :groups_and_projects do
it 'does not allow a subgroup to have the same name as an existing subgroup' do
sub_group1 = create(:group, parent: group, name: "SG", path: 'api')
sub_group2 = described_class.new(parent: group, name: "SG", path: 'api2')
sub_group2 = described_class.new(parent: group, name: "SG", path: 'api2', organization: sub_group1.organization)
expect(sub_group1).to be_valid
expect(sub_group2).not_to be_valid

View File

@ -1277,7 +1277,7 @@ RSpec.describe Member, feature_category: :groups_and_projects do
end
context 'for updating organization_users' do
let_it_be(:group) { create(:group, :with_organization) }
let_it_be(:group) { create(:group) }
let_it_be(:user) { create(:user) }
let(:member) { create(:group_member, source: group, user: user) }
@ -1362,12 +1362,6 @@ RSpec.describe Member, feature_category: :groups_and_projects do
it_behaves_like 'does not create an organization_user entry'
end
context 'when organization does not exist' do
let(:member) { create(:group_member, user: user) }
it_behaves_like 'does not create an organization_user entry'
end
end
context 'when updating' do

View File

@ -90,6 +90,7 @@ RSpec.describe Namespace, feature_category: :groups_and_projects do
it { is_expected.to validate_presence_of(:path) }
it { is_expected.to validate_length_of(:path).is_at_most(255) }
it { is_expected.to validate_presence_of(:owner) }
it { is_expected.to validate_presence_of(:organization) }
it { is_expected.to validate_numericality_of(:max_artifacts_size).only_integer.is_greater_than(0) }
context 'validating the parent of a namespace' do
@ -702,6 +703,54 @@ RSpec.describe Namespace, feature_category: :groups_and_projects do
it { is_expected.to include_module(Namespaces::Traversal::LinearScopes) }
end
context 'when feature flag require_organization is disabled' do
before do
stub_feature_flags(require_organization: false)
end
it 'does not require organization' do
namespace.organization = nil
expect(namespace.valid?).to eq(true)
end
end
context 'when feature flag require_organization is enabled' do
it 'does require organization' do
namespace.organization = nil
Namespace.with_disabled_organization_validation do
expect(namespace.valid?).to eq(false)
end
end
describe '.with_disabled_organization_validation', :request_store do
it 'does not require organization' do
namespace.organization = nil
Namespace.with_disabled_organization_validation do
expect(namespace.valid?).to eq(true)
end
end
context 'with nested calls' do
it 'only last call will enable the validation' do
result = []
Namespace.with_disabled_organization_validation do
result << described_class.new.require_organization?
Namespace.with_disabled_organization_validation do
result << described_class.new.require_organization?
end
result << described_class.new.require_organization?
end
expect(result.any?(true)).to be false
expect(described_class.new.require_organization?).to be true
end
end
end
end
describe '#traversal_ids' do
let(:namespace) { build(:group) }

View File

@ -2,7 +2,7 @@
require 'spec_helper'
RSpec.describe Namespaces::ProjectNamespace, type: :model do
RSpec.describe Namespaces::ProjectNamespace, type: :model, feature_category: :groups_and_projects do
let_it_be(:organization) { create(:organization) }
describe 'relationships' do

View File

@ -28,7 +28,7 @@ RSpec.describe Preloaders::ProjectPolicyPreloader do
control = ActiveRecord::QueryRecorder.new { authorize_all_projects(user) }
new_project1 = create(:project, :private, maintainers: user)
new_project2 = create(:project, :private, namespace: root_parent)
new_project2 = create(:project, :private, namespace: root_parent, maintainers: user)
another_root = create(:group, :private, name: 'root-3', path: 'root-3')
new_project3 = create(:project, :private, namespace: another_root, maintainers: user)

View File

@ -59,7 +59,7 @@ RSpec.describe 'getting merge request listings nested in a project', feature_cat
# We cannot disable SQL query limiting here, since the transaction does not
# begin until we enter the controller.
headers = {
'X-GITLAB-DISABLE-SQL-QUERY-LIMIT' => 'https://gitlab.com/gitlab-org/gitlab/-/issues/322979'
'X-GITLAB-DISABLE-SQL-QUERY-LIMIT' => 'https://gitlab.com/gitlab-org/gitlab/-/issues/469250;205'
}
post_graphql(query, current_user: current_user, headers: headers)

View File

@ -64,7 +64,7 @@ RSpec.describe API::ProjectImport, :aggregate_failures, feature_category: :impor
it 'executes a limited number of queries', :use_clean_rails_redis_caching do
control = ActiveRecord::QueryRecorder.new { perform_archive_upload }
expect(control.count).to be <= 114
expect(control.count).to be <= 115
end
it 'schedules an import using a namespace' do

View File

@ -700,15 +700,6 @@ RSpec.describe MergeRequests::UpdateService, :mailer, feature_category: :code_re
describe 'recording the first reviewer assigned at timestamp' do
subject(:metrics) { merge_request.reload.metrics }
context 'when store_first_reviewer_assignment_timestamp_in_metrics feature flag is off' do
it 'does not record anything' do
stub_feature_flags(store_first_reviewer_assignment_timestamp_in_metrics: false)
update_merge_request(reviewer_ids: [user2.id])
expect(metrics.reviewer_first_assigned_at).to eq(nil)
end
end
it 'sets the current timestamp' do
freeze_time do
update_merge_request(reviewer_ids: [user2.id])

View File

@ -393,7 +393,7 @@ RSpec.describe ResourceAccessTokens::CreateService, feature_category: :system_ac
end
context 'when resource organization is not set', :enable_admin_mode do
let_it_be(:resource) { create(:project, :private, organization: nil) }
let_it_be(:resource) { create(:project, :private, organization_id: nil) }
let_it_be(:default_organization) { Organizations::Organization.default_organization }
let(:user) { create(:admin) }

View File

@ -18,7 +18,7 @@ RSpec.describe Users::RegistrationsBuildService, feature_category: :system_acces
it 'creates the user_detail record' do
user = service.execute
expect { user.save! }.to change { UserDetail.count }.by(1)
expect { Namespace.with_disabled_organization_validation { user.save! } }.to change { UserDetail.count }.by(1)
end
end

View File

@ -205,6 +205,7 @@ RSpec.configure do |config|
config.include UserWithNamespaceShim
config.include OrphanFinalArtifactsCleanupHelpers, :orphan_final_artifacts_cleanup
config.include ClickHouseHelpers, :click_house
config.include DisableNamespaceOrganizationValidationHelper
config.include_context 'when rendered has no HTML escapes', type: :view

View File

@ -0,0 +1,70 @@
---
- ee/spec/controllers/ee/groups_controller_spec.rb
- ee/spec/controllers/ee/registrations_controller_spec.rb
- ee/spec/controllers/ee/omniauth_callbacks_controller_spec.rb
- ee/spec/controllers/groups/omniauth_callbacks_controller_spec.rb
- ee/spec/controllers/ldap/omniauth_callbacks_controller_spec.rb
- ee/spec/controllers/registrations/groups_controller_spec.rb
- ee/spec/features/groups_spec.rb
- ee/spec/features/projects/settings/merge_requests_settings_spec.rb
- ee/spec/features/registrations/combined_registration_spec.rb
- ee/spec/features/registrations/saas/sso_signin_standard_flow_company_creating_project_spec.rb
- ee/spec/features/registrations/saas/standard_flow_company_creating_project_spec.rb
- ee/spec/features/registrations/saas/standard_flow_just_me_creating_project_spec.rb
- ee/spec/features/registrations/saas/standard_flow_just_me_importing_project_spec.rb
- ee/spec/features/registrations/saas/subscription_flow_company_paid_plan_spec.rb
- ee/spec/features/registrations/saas/subscription_flow_just_me_paid_plan_spec.rb
- ee/spec/features/registrations/saas/trial_flow_company_creating_project_spec.rb
- ee/spec/features/registrations/saas/trial_flow_company_importing_project_spec.rb
- ee/spec/features/registrations/saas/trial_flow_just_me_creating_project_spec.rb
- ee/spec/features/registrations/saas/trial_flow_just_me_importing_project_spec.rb
- ee/spec/features/registrations/sign_up_with_trial_from_external_site_without_confirmation_spec.rb
- ee/spec/features/registrations/start_trial_from_external_site_without_confirmation_spec.rb
- ee/spec/features/subscriptions/subscription_flow_for_existing_user_with_eligible_group_spec.rb
- ee/spec/features/trials/saas/creation_with_multiple_existing_namespace_flow_spec.rb
- ee/spec/features/trials/saas/creation_with_no_existing_namespace_flow_spec.rb
- ee/spec/features/trials/saas/creation_with_one_existing_namespace_flow_spec.rb
- ee/spec/lib/gitlab/auth/group_saml/user_spec.rb
- ee/spec/lib/gitlab/auth/ldap/user_spec.rb
- ee/spec/lib/gitlab/auth/oidc/user_spec.rb
- ee/spec/lib/gitlab/auth/saml/user_spec.rb
- ee/spec/lib/ee/gitlab/scim/provisioning_service_spec.rb
- ee/spec/lib/ee/gitlab/scim/group/provisioning_service_spec.rb
- ee/spec/services/ee/groups/create_service_spec.rb
- ee/spec/services/ee/users/create_service_spec.rb
- ee/spec/services/users/service_accounts/create_service_spec.rb
- ee/spec/services/epics/update_dates_service_spec.rb
- ee/spec/services/gitlab_subscriptions/trials/create_service_spec.rb
- ee/spec/services/registrations/import_namespace_create_service_spec.rb
- ee/spec/services/registrations/standard_namespace_create_service_spec.rb
- spec/controllers/admin/groups_controller_spec.rb
- spec/controllers/admin/users_controller_spec.rb
- spec/controllers/groups_controller_spec.rb
- spec/controllers/import/bitbucket_controller_spec.rb
- spec/controllers/omniauth_callbacks_controller_spec.rb
- spec/controllers/registrations_controller_spec.rb
- spec/features/admin/admin_groups_spec.rb
- spec/features/dashboard/group_spec.rb
- spec/features/file_uploads/group_import_spec.rb
- spec/features/groups/import_export/import_file_spec.rb
- spec/features/groups_spec.rb
- spec/frontend/fixtures/groups.rb
- spec/graphql/types/group_type_spec.rb
- spec/graphql/types/project_type_spec.rb
- spec/lib/gitlab/auth/atlassian/user_spec.rb
- spec/lib/gitlab/auth/ldap/user_spec.rb
- spec/lib/gitlab/auth/o_auth/user_spec.rb
- spec/lib/gitlab/auth/saml/user_spec.rb
- spec/lib/gitlab/import/placeholder_user_creator_spec.rb
- spec/lib/gitlab/import/source_user_mapper_spec.rb
- spec/lib/gitlab/seeders/ci/runner/runner_fleet_seeder_spec.rb
- spec/models/hooks/system_hook_spec.rb
- spec/requests/api/groups_spec.rb
- spec/requests/import/gitlab_groups_controller_spec.rb
- spec/services/users/create_service_spec.rb
- spec/services/users/registrations_build_service_spec.rb
- spec/services/groups/create_service_spec.rb
- spec/services/groups/nested_create_service_spec.rb
- spec/services/resource_access_tokens/create_service_spec.rb
- spec/tasks/gitlab/seed/runner_fleet_rake_spec.rb
- spec/tasks/gitlab/update_templates_rake_spec.rb

View File

@ -0,0 +1,32 @@
# frozen_string_literal: true
module DisableNamespaceOrganizationValidationHelper
extend ActiveSupport::Concern
SPECS_FOR_CODE_TO_FIX = File.join(__dir__, 'disable_namespace_organization_validation.yml')
class << self
include Gitlab::Utils::StrongMemoize
def todo_list
YAML.load_file(SPECS_FOR_CODE_TO_FIX).filter_map { |path| full_path(path) } || []
end
strong_memoize_attr :todo_list
def full_path(path)
return unless File.exist?(path)
Pathname.new(path).realpath.to_s
end
end
included do
spec_file = Pathname.new(example.metadata[:example_group][:file_path]).realpath.to_s
if spec_file.in?(DisableNamespaceOrganizationValidationHelper.todo_list)
around do |example|
::Gitlab::SafeRequestStore.ensure_request_store { example.run }
end
end
end
end