@@ -834,7 +829,7 @@ export default {
v-gl-tooltip
:title="s__('BulkImport|Some groups will be imported without projects.')"
name="warning"
- class="gl-text-orange-500"
+ variant="warning"
data-testid="import-projects-warning"
/>
@@ -869,6 +864,7 @@ export default {
selectable
select-mode="multi"
selected-variant="primary"
+ stacked="lg"
@row-selected="preventSelectingAlreadyImportedGroups"
>
@@ -911,13 +907,13 @@ export default {
/>
-
-
+
+
+
+
diff --git a/app/assets/javascripts/lib/utils/vue3compat/vue_router.js b/app/assets/javascripts/lib/utils/vue3compat/vue_router.js
index f3d5d041716..491e1706ce3 100644
--- a/app/assets/javascripts/lib/utils/vue3compat/vue_router.js
+++ b/app/assets/javascripts/lib/utils/vue3compat/vue_router.js
@@ -92,6 +92,16 @@ const transformOptions = (options = {}) => {
const installed = new WeakMap();
+export const getMatchedComponents = (instance, path) => {
+ if (instance.getMatchedComponents) {
+ return instance.getMatchedComponents(path);
+ }
+
+ const route = path ? instance.resolve(path) : instance.currentRoute.value;
+
+ return route.matched.flatMap((record) => Object.values(record.components));
+};
+
export default class VueRouterCompat {
constructor(options) {
// eslint-disable-next-line no-constructor-return
diff --git a/app/assets/javascripts/ml/model_registry/components/searchable_list.vue b/app/assets/javascripts/ml/model_registry/components/searchable_list.vue
deleted file mode 100644
index cee16c8c255..00000000000
--- a/app/assets/javascripts/ml/model_registry/components/searchable_list.vue
+++ /dev/null
@@ -1,151 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/assets/javascripts/repository/router.js b/app/assets/javascripts/repository/router.js
index 5be77e391ba..da197301761 100644
--- a/app/assets/javascripts/repository/router.js
+++ b/app/assets/javascripts/repository/router.js
@@ -9,11 +9,21 @@ import { getRefType } from './utils/ref_type';
Vue.use(VueRouter);
+const normalizePathParam = (pathParam) => {
+ // Vue Router 4 when there's more than one `:path` segment
+ if (Array.isArray(pathParam)) {
+ return joinPaths(...pathParam);
+ }
+
+ // Vue Router 3, or when there's zero or one `:path` segments.
+ return pathParam?.replace(/^\//, '') || '/';
+};
+
export default function createRouter(base, baseRef) {
const treePathRoute = {
component: TreePage,
props: (route) => ({
- path: route.params.path?.replace(/^\//, '') || '/',
+ path: normalizePathParam(route.params.path),
refType: getRefType(route.query.ref_type || null),
}),
};
@@ -36,25 +46,25 @@ export default function createRouter(base, baseRef) {
{
name: 'treePathDecoded',
// Sometimes the ref needs decoding depending on how the backend sends it to us
- path: `(/-)?/tree/${decodeURI(baseRef)}/:path*`,
+ path: `/:dash(-)?/tree/${decodeURI(baseRef)}/:path*`,
...treePathRoute,
},
{
name: 'treePath',
// Support without decoding as well just in case the ref doesn't need to be decoded
- path: `(/-)?/tree/${escapeRegExp(baseRef)}/:path*`,
+ path: `/:dash(-)?/tree/${escapeRegExp(baseRef)}/:path*`,
...treePathRoute,
},
{
name: 'blobPathDecoded',
// Sometimes the ref needs decoding depending on how the backend sends it to us
- path: `(/-)?/blob/${decodeURI(baseRef)}/:path*`,
+ path: `/:dash(-)?/blob/${decodeURI(baseRef)}/:path*`,
...blobPathRoute,
},
{
name: 'blobPath',
// Support without decoding as well just in case the ref doesn't need to be decoded
- path: `(/-)?/blob/${escapeRegExp(baseRef)}/:path*`,
+ path: `/:dash(-)?/blob/${escapeRegExp(baseRef)}/:path*`,
...blobPathRoute,
},
{
@@ -80,7 +90,7 @@ export default function createRouter(base, baseRef) {
'edit',
decodeURI(baseRef),
'-',
- to.params.path || '',
+ normalizePathParam(to.params.path),
needsClosingSlash && '/',
),
);
diff --git a/app/models/project.rb b/app/models/project.rb
index 7cdc2c805b9..1f3ac4ffba1 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -1623,7 +1623,9 @@ class Project < ApplicationRecord
# - Relation import
# - Direct Transfer
def any_import_in_progress?
- relation_import_trackers.last&.started? ||
+ last_relation_import_tracker = relation_import_trackers.last
+
+ (last_relation_import_tracker&.started? && !last_relation_import_tracker.stale?) ||
import_started? ||
BulkImports::Entity.with_status(:started).where(project_id: id).any?
end
diff --git a/app/models/projects/import_export/relation_import_tracker.rb b/app/models/projects/import_export/relation_import_tracker.rb
index 49f9c8ba0ff..d71f91c5831 100644
--- a/app/models/projects/import_export/relation_import_tracker.rb
+++ b/app/models/projects/import_export/relation_import_tracker.rb
@@ -10,6 +10,8 @@ module Projects
validates :relation, presence: true
validate :cannot_be_created_for_importing_project, on: :create
+ STALE_TIMEOUT = 24.hours
+
enum :relation, { issues: 0, merge_requests: 1, ci_pipelines: 2, milestones: 3 }
state_machine :status, initial: :created do
@@ -20,6 +22,7 @@ module Projects
event :start do
transition created: :started
+ transition started: :started
end
event :finish do
@@ -34,7 +37,7 @@ module Projects
def stale?
return false if finished? || failed?
- created_at.before?(24.hours.ago)
+ created_at.before?(STALE_TIMEOUT.ago)
end
private
diff --git a/app/views/groups/group_members/index.html.haml b/app/views/groups/group_members/index.html.haml
index 1d9cec9b6f4..27f90f15f3c 100644
--- a/app/views/groups/group_members/index.html.haml
+++ b/app/views/groups/group_members/index.html.haml
@@ -7,10 +7,10 @@
= render ::Layouts::PageHeadingComponent.new(_('Group members')) do |c|
- c.with_description do
= group_member_header_subtext(@group)
- - c.with_actions do
- if current_appearance&.member_guidelines?
.gl-w-full.order-md-1
= brand_member_guidelines
+ - c.with_actions do
.js-invite-group-trigger{ data: { classes: 'md:gl-w-auto gl-w-full', display_text: _('Invite a group') } }
.js-invite-members-trigger{ data: { variant: 'confirm',
classes: 'md:gl-w-auto gl-w-full',
diff --git a/app/workers/projects/import_export/relation_import_worker.rb b/app/workers/projects/import_export/relation_import_worker.rb
index 7be04940309..1943d68cfa4 100644
--- a/app/workers/projects/import_export/relation_import_worker.rb
+++ b/app/workers/projects/import_export/relation_import_worker.rb
@@ -4,6 +4,7 @@ module Projects
module ImportExport
class RelationImportWorker
include ApplicationWorker
+ include Sidekiq::InterruptionsExhausted
sidekiq_options retry: 6
@@ -16,12 +17,26 @@ module Projects
attr_reader :tracker, :project, :current_user
+ sidekiq_retries_exhausted do |job, exception|
+ new.perform_failure(job['args'].first, exception)
+ end
+
+ sidekiq_interruptions_exhausted do |job|
+ new.perform_failure(job['args'].first,
+ ::Import::Exceptions::SidekiqExhaustedInterruptionsError.new
+ )
+ end
+
def perform(tracker_id, user_id)
@current_user = User.find(user_id)
@tracker = ::Projects::ImportExport::RelationImportTracker.find(tracker_id)
@project = tracker.project
- return unless tracker.can_start?
+ unless tracker.can_start?
+ ::Import::Framework::Logger.info(message: 'Cannot start tracker', tracker_id: tracker.id,
+ tracker_status: tracker.status_name)
+ return
+ end
tracker.start!
@@ -31,20 +46,21 @@ module Projects
tracker.finish!
rescue StandardError => error
- failure_service = Gitlab::ImportExport::ImportFailureService.new(project)
- failure_service.log_import_failure(
- source: 'RelationImportWorker#perform',
- exception: error,
- relation_key: tracker.relation
- )
-
- tracker.fail_op!
+ log_failure(error)
raise
ensure
remove_extracted_import
end
+ def perform_failure(tracker_id, exception)
+ @tracker = ::Projects::ImportExport::RelationImportTracker.find(tracker_id)
+ @project = tracker.project
+
+ log_failure(exception)
+ tracker.fail_op!
+ end
+
private
def extract_import_file
@@ -104,6 +120,15 @@ module Projects
def perform_post_import_tasks
project.reset_counters_and_iids
end
+
+ def log_failure(exception)
+ failure_service = Gitlab::ImportExport::ImportFailureService.new(project)
+ failure_service.log_import_failure(
+ source: 'RelationImportWorker#perform',
+ exception: exception,
+ relation_key: tracker.relation
+ )
+ end
end
end
end
diff --git a/data/deprecations/17-9-kpt-based-agentk-install.yml b/data/deprecations/17-9-kpt-based-agentk-install.yml
new file mode 100644
index 00000000000..f46b3e31a42
--- /dev/null
+++ b/data/deprecations/17-9-kpt-based-agentk-install.yml
@@ -0,0 +1,23 @@
+- title: "`kpt`-based `agentk` is deprecated"
+ removal_milestone: "18.0"
+ announcement_milestone: "17.9"
+ breaking_change: true
+ window: 2
+ reporter: nagyv-gitlab
+ stage: deploy
+ issue_url: https://gitlab.com/gitlab-org/cluster-integration/gitlab-agent/-/issues/656
+ # Use the impact calculator https://gitlab-com.gitlab.io/gl-infra/breaking-change-impact-calculator/?
+ # https://gitlab-com.gitlab.io/gl-infra/breaking-change-impact-calculator/?usage=edge_case&migration_complexity=minor_manual&scope=project&identification_complexity=manual&additional_complexity=no&base_impact=major&pipeline_impact=none&compliance_impact=none&availability_impact=none&authorization_impact=none&API_impact=none
+ impact: low
+ scope: project
+ resolution_role: Maintainer
+ manual_task: true
+ body: | # (required) Don't change this line.
+ In GitLab 18.0, we'll remove support for the `kpt`-based installation of the agent for Kubernetes.
+ Instead, you should install the agent with one of the supported installation methods:
+
+ - Helm (recommended)
+ - GitLab CLI
+ - Flux
+
+ To migrate from `kpt` to Helm, follow [the agent installation documentation](https://docs.gitlab.com/ee/user/clusters/agent/install/) to overwrite your `kpt`-deployed `agentk` instance.
diff --git a/data/deprecations/17-9-spotbugs-builds.yml b/data/deprecations/17-9-spotbugs-builds.yml
new file mode 100644
index 00000000000..1f23e83b974
--- /dev/null
+++ b/data/deprecations/17-9-spotbugs-builds.yml
@@ -0,0 +1,23 @@
+- title: "Support for project build as part of SpotBugs scans"
+ removal_milestone: "18.0"
+ announcement_milestone: "17.9"
+ breaking_change: false
+ window: 1 # Note: a change window is not applicable to a non-breaking change
+ reporter: thiagocsf
+ stage: application security testing
+ issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/513409
+ impact: low
+ scope: project
+ resolution_role: Developer
+ manual_task: true
+ body: | # (required) Don't change this line.
+ The SpotBugs [SAST analyzer](https://docs.gitlab.com/ee/user/application_security/sast/index.html#supported-languages-and-frameworks)
+ can perform a build when the artifacts to be scanned aren't present. While this usually works well for simple projects, it can fail on more complex builds.
+
+ From GitLab 18.0, to resolve SpotBugs analyzer build failures, you should:
+
+ 1. [Pre-compile](https://docs.gitlab.com/ee/user/application_security/sast/#pre-compilation) the project.
+ 1. Pass the artifacts you want to scan to the analyzer.
+ end_of_support_milestone: 18.0
+ tiers: [Free, Silver, Gold, Core, Premium, Ultimate]
+ documentation_url: https://docs.gitlab.com/ee/user/application_security/sast/troubleshooting.html#project-couldnt-be-built
diff --git a/db/docs/batched_background_migrations/backfill_bulk_import_failures_namespace_id.yml b/db/docs/batched_background_migrations/backfill_bulk_import_failures_namespace_id.yml
new file mode 100644
index 00000000000..f4b2918e8e9
--- /dev/null
+++ b/db/docs/batched_background_migrations/backfill_bulk_import_failures_namespace_id.yml
@@ -0,0 +1,8 @@
+---
+migration_job_name: BackfillBulkImportFailuresNamespaceId
+description: Backfills sharding key `bulk_import_failures.namespace_id` from `bulk_import_entities`.
+feature_category: importers
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/180435
+milestone: '17.9'
+queued_migration_version: 20250205194756
+finalized_by: # version of the migration that finalized this BBM
diff --git a/db/docs/batched_background_migrations/backfill_bulk_import_failures_organization_id.yml b/db/docs/batched_background_migrations/backfill_bulk_import_failures_organization_id.yml
new file mode 100644
index 00000000000..c2b07bf93a2
--- /dev/null
+++ b/db/docs/batched_background_migrations/backfill_bulk_import_failures_organization_id.yml
@@ -0,0 +1,8 @@
+---
+migration_job_name: BackfillBulkImportFailuresOrganizationId
+description: Backfills sharding key `bulk_import_failures.organization_id` from `bulk_import_entities`.
+feature_category: importers
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/180435
+milestone: '17.9'
+queued_migration_version: 20250205194761
+finalized_by: # version of the migration that finalized this BBM
diff --git a/db/docs/batched_background_migrations/backfill_bulk_import_failures_project_id.yml b/db/docs/batched_background_migrations/backfill_bulk_import_failures_project_id.yml
new file mode 100644
index 00000000000..b15d435d3c2
--- /dev/null
+++ b/db/docs/batched_background_migrations/backfill_bulk_import_failures_project_id.yml
@@ -0,0 +1,8 @@
+---
+migration_job_name: BackfillBulkImportFailuresProjectId
+description: Backfills sharding key `bulk_import_failures.project_id` from `bulk_import_entities`.
+feature_category: importers
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/180435
+milestone: '17.9'
+queued_migration_version: 20250205194751
+finalized_by: # version of the migration that finalized this BBM
diff --git a/db/docs/bulk_import_failures.yml b/db/docs/bulk_import_failures.yml
index 6476dce5679..43006f5b44e 100644
--- a/db/docs/bulk_import_failures.yml
+++ b/db/docs/bulk_import_failures.yml
@@ -34,3 +34,7 @@ desired_sharding_key:
table: bulk_import_entities
sharding_key: organization_id
belongs_to: entity
+desired_sharding_key_migration_job_name:
+- BackfillBulkImportFailuresProjectId
+- BackfillBulkImportFailuresNamespaceId
+- BackfillBulkImportFailuresOrganizationId
diff --git a/db/migrate/20250205194747_add_project_id_to_bulk_import_failures.rb b/db/migrate/20250205194747_add_project_id_to_bulk_import_failures.rb
new file mode 100644
index 00000000000..f8ba85e2597
--- /dev/null
+++ b/db/migrate/20250205194747_add_project_id_to_bulk_import_failures.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+class AddProjectIdToBulkImportFailures < Gitlab::Database::Migration[2.2]
+ milestone '17.9'
+
+ def change
+ add_column :bulk_import_failures, :project_id, :bigint
+ end
+end
diff --git a/db/migrate/20250205194752_add_namespace_id_to_bulk_import_failures.rb b/db/migrate/20250205194752_add_namespace_id_to_bulk_import_failures.rb
new file mode 100644
index 00000000000..efecb519c62
--- /dev/null
+++ b/db/migrate/20250205194752_add_namespace_id_to_bulk_import_failures.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+class AddNamespaceIdToBulkImportFailures < Gitlab::Database::Migration[2.2]
+ milestone '17.9'
+
+ def change
+ add_column :bulk_import_failures, :namespace_id, :bigint
+ end
+end
diff --git a/db/migrate/20250205194757_add_organization_id_to_bulk_import_failures.rb b/db/migrate/20250205194757_add_organization_id_to_bulk_import_failures.rb
new file mode 100644
index 00000000000..867ed2fe9f5
--- /dev/null
+++ b/db/migrate/20250205194757_add_organization_id_to_bulk_import_failures.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+class AddOrganizationIdToBulkImportFailures < Gitlab::Database::Migration[2.2]
+ milestone '17.9'
+
+ def change
+ add_column :bulk_import_failures, :organization_id, :bigint
+ end
+end
diff --git a/db/post_migrate/20250205194748_index_bulk_import_failures_on_project_id.rb b/db/post_migrate/20250205194748_index_bulk_import_failures_on_project_id.rb
new file mode 100644
index 00000000000..c5df62d973c
--- /dev/null
+++ b/db/post_migrate/20250205194748_index_bulk_import_failures_on_project_id.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+class IndexBulkImportFailuresOnProjectId < Gitlab::Database::Migration[2.2]
+ milestone '17.9'
+ disable_ddl_transaction!
+
+ INDEX_NAME = 'index_bulk_import_failures_on_project_id'
+
+ def up
+ add_concurrent_index :bulk_import_failures, :project_id, name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name :bulk_import_failures, INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20250205194749_add_bulk_import_failures_project_id_fk.rb b/db/post_migrate/20250205194749_add_bulk_import_failures_project_id_fk.rb
new file mode 100644
index 00000000000..0568871b4e1
--- /dev/null
+++ b/db/post_migrate/20250205194749_add_bulk_import_failures_project_id_fk.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+class AddBulkImportFailuresProjectIdFk < Gitlab::Database::Migration[2.2]
+ milestone '17.9'
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_foreign_key :bulk_import_failures, :projects, column: :project_id, on_delete: :cascade
+ end
+
+ def down
+ with_lock_retries do
+ remove_foreign_key :bulk_import_failures, column: :project_id
+ end
+ end
+end
diff --git a/db/post_migrate/20250205194750_add_bulk_import_failures_project_id_trigger.rb b/db/post_migrate/20250205194750_add_bulk_import_failures_project_id_trigger.rb
new file mode 100644
index 00000000000..546f25a55fa
--- /dev/null
+++ b/db/post_migrate/20250205194750_add_bulk_import_failures_project_id_trigger.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+class AddBulkImportFailuresProjectIdTrigger < Gitlab::Database::Migration[2.2]
+ milestone '17.9'
+
+ def up
+ install_sharding_key_assignment_trigger(
+ table: :bulk_import_failures,
+ sharding_key: :project_id,
+ parent_table: :bulk_import_entities,
+ parent_sharding_key: :project_id,
+ foreign_key: :bulk_import_entity_id
+ )
+ end
+
+ def down
+ remove_sharding_key_assignment_trigger(
+ table: :bulk_import_failures,
+ sharding_key: :project_id,
+ parent_table: :bulk_import_entities,
+ parent_sharding_key: :project_id,
+ foreign_key: :bulk_import_entity_id
+ )
+ end
+end
diff --git a/db/post_migrate/20250205194751_queue_backfill_bulk_import_failures_project_id.rb b/db/post_migrate/20250205194751_queue_backfill_bulk_import_failures_project_id.rb
new file mode 100644
index 00000000000..a312f6b1bb1
--- /dev/null
+++ b/db/post_migrate/20250205194751_queue_backfill_bulk_import_failures_project_id.rb
@@ -0,0 +1,40 @@
+# frozen_string_literal: true
+
+class QueueBackfillBulkImportFailuresProjectId < Gitlab::Database::Migration[2.2]
+ milestone '17.9'
+ restrict_gitlab_migration gitlab_schema: :gitlab_main_cell
+
+ MIGRATION = "BackfillBulkImportFailuresProjectId"
+ DELAY_INTERVAL = 2.minutes
+ BATCH_SIZE = 1000
+ SUB_BATCH_SIZE = 100
+
+ def up
+ queue_batched_background_migration(
+ MIGRATION,
+ :bulk_import_failures,
+ :id,
+ :project_id,
+ :bulk_import_entities,
+ :project_id,
+ :bulk_import_entity_id,
+ job_interval: DELAY_INTERVAL,
+ batch_size: BATCH_SIZE,
+ sub_batch_size: SUB_BATCH_SIZE
+ )
+ end
+
+ def down
+ delete_batched_background_migration(
+ MIGRATION,
+ :bulk_import_failures,
+ :id,
+ [
+ :project_id,
+ :bulk_import_entities,
+ :project_id,
+ :bulk_import_entity_id
+ ]
+ )
+ end
+end
diff --git a/db/post_migrate/20250205194753_index_bulk_import_failures_on_namespace_id.rb b/db/post_migrate/20250205194753_index_bulk_import_failures_on_namespace_id.rb
new file mode 100644
index 00000000000..2a91cb17f01
--- /dev/null
+++ b/db/post_migrate/20250205194753_index_bulk_import_failures_on_namespace_id.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+class IndexBulkImportFailuresOnNamespaceId < Gitlab::Database::Migration[2.2]
+ milestone '17.9'
+ disable_ddl_transaction!
+
+ INDEX_NAME = 'index_bulk_import_failures_on_namespace_id'
+
+ def up
+ add_concurrent_index :bulk_import_failures, :namespace_id, name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name :bulk_import_failures, INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20250205194754_add_bulk_import_failures_namespace_id_fk.rb b/db/post_migrate/20250205194754_add_bulk_import_failures_namespace_id_fk.rb
new file mode 100644
index 00000000000..805586b1b19
--- /dev/null
+++ b/db/post_migrate/20250205194754_add_bulk_import_failures_namespace_id_fk.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+class AddBulkImportFailuresNamespaceIdFk < Gitlab::Database::Migration[2.2]
+ milestone '17.9'
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_foreign_key :bulk_import_failures, :namespaces, column: :namespace_id, on_delete: :cascade
+ end
+
+ def down
+ with_lock_retries do
+ remove_foreign_key :bulk_import_failures, column: :namespace_id
+ end
+ end
+end
diff --git a/db/post_migrate/20250205194755_add_bulk_import_failures_namespace_id_trigger.rb b/db/post_migrate/20250205194755_add_bulk_import_failures_namespace_id_trigger.rb
new file mode 100644
index 00000000000..711c33b0bf4
--- /dev/null
+++ b/db/post_migrate/20250205194755_add_bulk_import_failures_namespace_id_trigger.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+class AddBulkImportFailuresNamespaceIdTrigger < Gitlab::Database::Migration[2.2]
+ milestone '17.9'
+
+ def up
+ install_sharding_key_assignment_trigger(
+ table: :bulk_import_failures,
+ sharding_key: :namespace_id,
+ parent_table: :bulk_import_entities,
+ parent_sharding_key: :namespace_id,
+ foreign_key: :bulk_import_entity_id
+ )
+ end
+
+ def down
+ remove_sharding_key_assignment_trigger(
+ table: :bulk_import_failures,
+ sharding_key: :namespace_id,
+ parent_table: :bulk_import_entities,
+ parent_sharding_key: :namespace_id,
+ foreign_key: :bulk_import_entity_id
+ )
+ end
+end
diff --git a/db/post_migrate/20250205194756_queue_backfill_bulk_import_failures_namespace_id.rb b/db/post_migrate/20250205194756_queue_backfill_bulk_import_failures_namespace_id.rb
new file mode 100644
index 00000000000..e0a0d2f23fe
--- /dev/null
+++ b/db/post_migrate/20250205194756_queue_backfill_bulk_import_failures_namespace_id.rb
@@ -0,0 +1,40 @@
+# frozen_string_literal: true
+
+class QueueBackfillBulkImportFailuresNamespaceId < Gitlab::Database::Migration[2.2]
+ milestone '17.9'
+ restrict_gitlab_migration gitlab_schema: :gitlab_main_cell
+
+ MIGRATION = "BackfillBulkImportFailuresNamespaceId"
+ DELAY_INTERVAL = 2.minutes
+ BATCH_SIZE = 1000
+ SUB_BATCH_SIZE = 100
+
+ def up
+ queue_batched_background_migration(
+ MIGRATION,
+ :bulk_import_failures,
+ :id,
+ :namespace_id,
+ :bulk_import_entities,
+ :namespace_id,
+ :bulk_import_entity_id,
+ job_interval: DELAY_INTERVAL,
+ batch_size: BATCH_SIZE,
+ sub_batch_size: SUB_BATCH_SIZE
+ )
+ end
+
+ def down
+ delete_batched_background_migration(
+ MIGRATION,
+ :bulk_import_failures,
+ :id,
+ [
+ :namespace_id,
+ :bulk_import_entities,
+ :namespace_id,
+ :bulk_import_entity_id
+ ]
+ )
+ end
+end
diff --git a/db/post_migrate/20250205194758_index_bulk_import_failures_on_organization_id.rb b/db/post_migrate/20250205194758_index_bulk_import_failures_on_organization_id.rb
new file mode 100644
index 00000000000..4a89232e370
--- /dev/null
+++ b/db/post_migrate/20250205194758_index_bulk_import_failures_on_organization_id.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+class IndexBulkImportFailuresOnOrganizationId < Gitlab::Database::Migration[2.2]
+ milestone '17.9'
+ disable_ddl_transaction!
+
+ INDEX_NAME = 'index_bulk_import_failures_on_organization_id'
+
+ def up
+ add_concurrent_index :bulk_import_failures, :organization_id, name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name :bulk_import_failures, INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20250205194759_add_bulk_import_failures_organization_id_fk.rb b/db/post_migrate/20250205194759_add_bulk_import_failures_organization_id_fk.rb
new file mode 100644
index 00000000000..49491e11a63
--- /dev/null
+++ b/db/post_migrate/20250205194759_add_bulk_import_failures_organization_id_fk.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+class AddBulkImportFailuresOrganizationIdFk < Gitlab::Database::Migration[2.2]
+ milestone '17.9'
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_foreign_key :bulk_import_failures, :organizations, column: :organization_id, on_delete: :cascade
+ end
+
+ def down
+ with_lock_retries do
+ remove_foreign_key :bulk_import_failures, column: :organization_id
+ end
+ end
+end
diff --git a/db/post_migrate/20250205194760_add_bulk_import_failures_organization_id_trigger.rb b/db/post_migrate/20250205194760_add_bulk_import_failures_organization_id_trigger.rb
new file mode 100644
index 00000000000..58031c0dce0
--- /dev/null
+++ b/db/post_migrate/20250205194760_add_bulk_import_failures_organization_id_trigger.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+class AddBulkImportFailuresOrganizationIdTrigger < Gitlab::Database::Migration[2.2]
+ milestone '17.9'
+
+ def up
+ install_sharding_key_assignment_trigger(
+ table: :bulk_import_failures,
+ sharding_key: :organization_id,
+ parent_table: :bulk_import_entities,
+ parent_sharding_key: :organization_id,
+ foreign_key: :bulk_import_entity_id
+ )
+ end
+
+ def down
+ remove_sharding_key_assignment_trigger(
+ table: :bulk_import_failures,
+ sharding_key: :organization_id,
+ parent_table: :bulk_import_entities,
+ parent_sharding_key: :organization_id,
+ foreign_key: :bulk_import_entity_id
+ )
+ end
+end
diff --git a/db/post_migrate/20250205194761_queue_backfill_bulk_import_failures_organization_id.rb b/db/post_migrate/20250205194761_queue_backfill_bulk_import_failures_organization_id.rb
new file mode 100644
index 00000000000..882c57cdb02
--- /dev/null
+++ b/db/post_migrate/20250205194761_queue_backfill_bulk_import_failures_organization_id.rb
@@ -0,0 +1,40 @@
+# frozen_string_literal: true
+
+class QueueBackfillBulkImportFailuresOrganizationId < Gitlab::Database::Migration[2.2]
+ milestone '17.9'
+ restrict_gitlab_migration gitlab_schema: :gitlab_main_cell
+
+ MIGRATION = "BackfillBulkImportFailuresOrganizationId"
+ DELAY_INTERVAL = 2.minutes
+ BATCH_SIZE = 1000
+ SUB_BATCH_SIZE = 100
+
+ def up
+ queue_batched_background_migration(
+ MIGRATION,
+ :bulk_import_failures,
+ :id,
+ :organization_id,
+ :bulk_import_entities,
+ :organization_id,
+ :bulk_import_entity_id,
+ job_interval: DELAY_INTERVAL,
+ batch_size: BATCH_SIZE,
+ sub_batch_size: SUB_BATCH_SIZE
+ )
+ end
+
+ def down
+ delete_batched_background_migration(
+ MIGRATION,
+ :bulk_import_failures,
+ :id,
+ [
+ :organization_id,
+ :bulk_import_entities,
+ :organization_id,
+ :bulk_import_entity_id
+ ]
+ )
+ end
+end
diff --git a/db/schema_migrations/20250205194747 b/db/schema_migrations/20250205194747
new file mode 100644
index 00000000000..54a90b264be
--- /dev/null
+++ b/db/schema_migrations/20250205194747
@@ -0,0 +1 @@
+52712f6673056c27341c0b8981fc6e924e28a11a047472f1f59ba10552afb0c9
\ No newline at end of file
diff --git a/db/schema_migrations/20250205194748 b/db/schema_migrations/20250205194748
new file mode 100644
index 00000000000..70213709523
--- /dev/null
+++ b/db/schema_migrations/20250205194748
@@ -0,0 +1 @@
+1826e690211f4de94c2c8c235fcd23ad9868469b277d475e175e8534d654d064
\ No newline at end of file
diff --git a/db/schema_migrations/20250205194749 b/db/schema_migrations/20250205194749
new file mode 100644
index 00000000000..5776c48a894
--- /dev/null
+++ b/db/schema_migrations/20250205194749
@@ -0,0 +1 @@
+5bd5f02ddfc2b28cb62879d42d1145823002976560e5e88bafb5391f8686f50c
\ No newline at end of file
diff --git a/db/schema_migrations/20250205194750 b/db/schema_migrations/20250205194750
new file mode 100644
index 00000000000..06408a37cb5
--- /dev/null
+++ b/db/schema_migrations/20250205194750
@@ -0,0 +1 @@
+c07b8cf01fa5c903693ded23b53cace5868fef5c0200fa129f61bc94100dd89c
\ No newline at end of file
diff --git a/db/schema_migrations/20250205194751 b/db/schema_migrations/20250205194751
new file mode 100644
index 00000000000..2f88a8652b6
--- /dev/null
+++ b/db/schema_migrations/20250205194751
@@ -0,0 +1 @@
+fdf2ce5da9d2b550e3c32a2cef6ff8d4289720710dc6030a6c8b8eb2ae3c2be7
\ No newline at end of file
diff --git a/db/schema_migrations/20250205194752 b/db/schema_migrations/20250205194752
new file mode 100644
index 00000000000..b7ac16f0a2d
--- /dev/null
+++ b/db/schema_migrations/20250205194752
@@ -0,0 +1 @@
+67eb82e6774e8472e8e88e5c549a03747faa2c41d76c83668a04fbb2c506edca
\ No newline at end of file
diff --git a/db/schema_migrations/20250205194753 b/db/schema_migrations/20250205194753
new file mode 100644
index 00000000000..95bec4d0c4f
--- /dev/null
+++ b/db/schema_migrations/20250205194753
@@ -0,0 +1 @@
+a13a7693c5a4f67bb590c1f05842b65d8b04d40e1c83a44eec8d1775531b5360
\ No newline at end of file
diff --git a/db/schema_migrations/20250205194754 b/db/schema_migrations/20250205194754
new file mode 100644
index 00000000000..1a5e012b328
--- /dev/null
+++ b/db/schema_migrations/20250205194754
@@ -0,0 +1 @@
+289108e9ba6d848506b00d3566a3f1c9bff4773dd726e2f01ce8822e9aedb19d
\ No newline at end of file
diff --git a/db/schema_migrations/20250205194755 b/db/schema_migrations/20250205194755
new file mode 100644
index 00000000000..7319d4da25d
--- /dev/null
+++ b/db/schema_migrations/20250205194755
@@ -0,0 +1 @@
+29d384cb9a5a1be7a91dafd1d94c94db0f4b869994ba5fb7755d5cf6f490f908
\ No newline at end of file
diff --git a/db/schema_migrations/20250205194756 b/db/schema_migrations/20250205194756
new file mode 100644
index 00000000000..974fa4baa66
--- /dev/null
+++ b/db/schema_migrations/20250205194756
@@ -0,0 +1 @@
+ee612f8ca1b98df84b025491cdc1b918776eaeca56935da53d2a275c406c28e1
\ No newline at end of file
diff --git a/db/schema_migrations/20250205194757 b/db/schema_migrations/20250205194757
new file mode 100644
index 00000000000..86a503b9b29
--- /dev/null
+++ b/db/schema_migrations/20250205194757
@@ -0,0 +1 @@
+06a8ce5524fd572a45e227c867e82a32a0ad0df5699905ce753679d5069bff84
\ No newline at end of file
diff --git a/db/schema_migrations/20250205194758 b/db/schema_migrations/20250205194758
new file mode 100644
index 00000000000..be937d520b9
--- /dev/null
+++ b/db/schema_migrations/20250205194758
@@ -0,0 +1 @@
+ccd7b40c4d897a0ba4554bd655dc5c951d4382293efd5bc1f690019d4d8c093c
\ No newline at end of file
diff --git a/db/schema_migrations/20250205194759 b/db/schema_migrations/20250205194759
new file mode 100644
index 00000000000..8862d076585
--- /dev/null
+++ b/db/schema_migrations/20250205194759
@@ -0,0 +1 @@
+4a0bf49e38e6bd69c194150d3b524e64e362fd401e06bcb95b7d5ef3dcdade40
\ No newline at end of file
diff --git a/db/schema_migrations/20250205194760 b/db/schema_migrations/20250205194760
new file mode 100644
index 00000000000..784dbf5e716
--- /dev/null
+++ b/db/schema_migrations/20250205194760
@@ -0,0 +1 @@
+0d6cf422a4cc20ec42cbf4651f7ae204c94e9f1a566abd3c3acec21a0c1707f5
\ No newline at end of file
diff --git a/db/schema_migrations/20250205194761 b/db/schema_migrations/20250205194761
new file mode 100644
index 00000000000..dd6c110fdef
--- /dev/null
+++ b/db/schema_migrations/20250205194761
@@ -0,0 +1 @@
+667b89da80348593027e2ba887e8df8abcbc1e30d62ed9f2081c6b0e2d7953ef
\ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index bee8bc9fad2..7282c75a622 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -1755,6 +1755,22 @@ RETURN NEW;
END
$$;
+CREATE FUNCTION trigger_36cb404f9a02() RETURNS trigger
+ LANGUAGE plpgsql
+ AS $$
+BEGIN
+IF NEW."organization_id" IS NULL THEN
+ SELECT "organization_id"
+ INTO NEW."organization_id"
+ FROM "bulk_import_entities"
+ WHERE "bulk_import_entities"."id" = NEW."bulk_import_entity_id";
+END IF;
+
+RETURN NEW;
+
+END
+$$;
+
CREATE FUNCTION trigger_388de55cd36c() RETURNS trigger
LANGUAGE plpgsql
AS $$
@@ -2475,6 +2491,22 @@ RETURN NEW;
END
$$;
+CREATE FUNCTION trigger_7b21c87a1f91() RETURNS trigger
+ LANGUAGE plpgsql
+ AS $$
+BEGIN
+IF NEW."project_id" IS NULL THEN
+ SELECT "project_id"
+ INTO NEW."project_id"
+ FROM "bulk_import_entities"
+ WHERE "bulk_import_entities"."id" = NEW."bulk_import_entity_id";
+END IF;
+
+RETURN NEW;
+
+END
+$$;
+
CREATE FUNCTION trigger_7b378a0c402b() RETURNS trigger
LANGUAGE plpgsql
AS $$
@@ -2664,6 +2696,22 @@ RETURN NEW;
END
$$;
+CREATE FUNCTION trigger_8cb8ad095bf6() RETURNS trigger
+ LANGUAGE plpgsql
+ AS $$
+BEGIN
+IF NEW."namespace_id" IS NULL THEN
+ SELECT "namespace_id"
+ INTO NEW."namespace_id"
+ FROM "bulk_import_entities"
+ WHERE "bulk_import_entities"."id" = NEW."bulk_import_entity_id";
+END IF;
+
+RETURN NEW;
+
+END
+$$;
+
CREATE FUNCTION trigger_8d002f38bdef() RETURNS trigger
LANGUAGE plpgsql
AS $$
@@ -9836,6 +9884,9 @@ CREATE TABLE bulk_import_failures (
source_url text,
source_title text,
subrelation text,
+ project_id bigint,
+ namespace_id bigint,
+ organization_id bigint,
CONSTRAINT check_053d65c7a4 CHECK ((char_length(pipeline_class) <= 255)),
CONSTRAINT check_6eca8f972e CHECK ((char_length(exception_message) <= 255)),
CONSTRAINT check_721a422375 CHECK ((char_length(pipeline_step) <= 255)),
@@ -31690,6 +31741,12 @@ CREATE INDEX index_bulk_import_failures_on_bulk_import_entity_id ON bulk_import_
CREATE INDEX index_bulk_import_failures_on_correlation_id_value ON bulk_import_failures USING btree (correlation_id_value);
+CREATE INDEX index_bulk_import_failures_on_namespace_id ON bulk_import_failures USING btree (namespace_id);
+
+CREATE INDEX index_bulk_import_failures_on_organization_id ON bulk_import_failures USING btree (organization_id);
+
+CREATE INDEX index_bulk_import_failures_on_project_id ON bulk_import_failures USING btree (project_id);
+
CREATE INDEX index_bulk_import_trackers_on_namespace_id ON bulk_import_trackers USING btree (namespace_id);
CREATE INDEX index_bulk_import_trackers_on_organization_id ON bulk_import_trackers USING btree (organization_id);
@@ -38146,6 +38203,8 @@ CREATE TRIGGER trigger_2dafd0d13605 BEFORE INSERT OR UPDATE ON pages_domain_acme
CREATE TRIGGER trigger_30209d0fba3e BEFORE INSERT OR UPDATE ON alert_management_alert_user_mentions FOR EACH ROW EXECUTE FUNCTION trigger_30209d0fba3e();
+CREATE TRIGGER trigger_36cb404f9a02 BEFORE INSERT OR UPDATE ON bulk_import_failures FOR EACH ROW EXECUTE FUNCTION trigger_36cb404f9a02();
+
CREATE TRIGGER trigger_388de55cd36c BEFORE INSERT OR UPDATE ON ci_builds_runner_session FOR EACH ROW EXECUTE FUNCTION trigger_388de55cd36c();
CREATE TRIGGER trigger_38bfee591e40 BEFORE INSERT OR UPDATE ON dependency_proxy_blob_states FOR EACH ROW EXECUTE FUNCTION trigger_38bfee591e40();
@@ -38236,6 +38295,8 @@ CREATE TRIGGER trigger_7943cb549289 BEFORE INSERT OR UPDATE ON issuable_metric_i
CREATE TRIGGER trigger_7a8b08eed782 BEFORE INSERT OR UPDATE ON boards_epic_board_positions FOR EACH ROW EXECUTE FUNCTION trigger_7a8b08eed782();
+CREATE TRIGGER trigger_7b21c87a1f91 BEFORE INSERT OR UPDATE ON bulk_import_failures FOR EACH ROW EXECUTE FUNCTION trigger_7b21c87a1f91();
+
CREATE TRIGGER trigger_7b378a0c402b BEFORE INSERT OR UPDATE ON issue_user_mentions FOR EACH ROW EXECUTE FUNCTION trigger_7b378a0c402b();
CREATE TRIGGER trigger_7de792ddbc05 BEFORE INSERT OR UPDATE ON dast_site_validations FOR EACH ROW EXECUTE FUNCTION trigger_7de792ddbc05();
@@ -38266,6 +38327,8 @@ CREATE TRIGGER trigger_8b39d532224c BEFORE INSERT OR UPDATE ON ci_secure_file_st
CREATE TRIGGER trigger_8ba074736a77 BEFORE INSERT OR UPDATE ON snippet_repository_storage_moves FOR EACH ROW EXECUTE FUNCTION trigger_8ba074736a77();
+CREATE TRIGGER trigger_8cb8ad095bf6 BEFORE INSERT OR UPDATE ON bulk_import_failures FOR EACH ROW EXECUTE FUNCTION trigger_8cb8ad095bf6();
+
CREATE TRIGGER trigger_8d002f38bdef BEFORE INSERT OR UPDATE ON packages_debian_group_components FOR EACH ROW EXECUTE FUNCTION trigger_8d002f38bdef();
CREATE TRIGGER trigger_8d17725116fe BEFORE INSERT OR UPDATE ON merge_request_reviewers FOR EACH ROW EXECUTE FUNCTION trigger_8d17725116fe();
@@ -39281,6 +39344,9 @@ ALTER TABLE ONLY deploy_tokens
ALTER TABLE ONLY oauth_openid_requests
ADD CONSTRAINT fk_7092424b77 FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE;
+ALTER TABLE ONLY bulk_import_failures
+ ADD CONSTRAINT fk_70f30b02fd FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
+
ALTER TABLE ONLY protected_branch_push_access_levels
ADD CONSTRAINT fk_7111b68cdb FOREIGN KEY (group_id) REFERENCES namespaces(id) ON DELETE CASCADE;
@@ -39500,6 +39566,9 @@ ALTER TABLE ONLY protected_branch_merge_access_levels
ALTER TABLE ONLY work_item_dates_sources
ADD CONSTRAINT fk_8a4948b668 FOREIGN KEY (start_date_sourcing_work_item_id) REFERENCES issues(id) ON DELETE SET NULL;
+ALTER TABLE ONLY bulk_import_failures
+ ADD CONSTRAINT fk_8c0911e763 FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE;
+
ALTER TABLE ONLY bulk_import_exports
ADD CONSTRAINT fk_8c6f33cebe FOREIGN KEY (group_id) REFERENCES namespaces(id) ON DELETE CASCADE;
@@ -40124,6 +40193,9 @@ ALTER TABLE ONLY personal_access_tokens
ALTER TABLE ONLY project_group_links
ADD CONSTRAINT fk_daa8cee94c FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
+ALTER TABLE ONLY bulk_import_failures
+ ADD CONSTRAINT fk_dad28985ee FOREIGN KEY (namespace_id) REFERENCES namespaces(id) ON DELETE CASCADE;
+
ALTER TABLE ONLY project_topics
ADD CONSTRAINT fk_db13576296 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
diff --git a/doc/.vale/gitlab_base/NonStandardSpaces.yml b/doc/.vale/gitlab_base/NonStandardSpaces.yml
new file mode 100644
index 00000000000..05b5939a2b7
--- /dev/null
+++ b/doc/.vale/gitlab_base/NonStandardSpaces.yml
@@ -0,0 +1,19 @@
+---
+# Warning: gitlab_base.NonStandardSpaces
+#
+# Use only standard spaces. Do not use:
+#
+# U+202F : NARROW NO-BREAK SPACE [NNBSP]
+# U+00A0 : NO-BREAK SPACE [NBSP]
+# U+200B : ZERO WIDTH SPACE [ZWSP]
+#
+# For a list of all options, see https://vale.sh/docs/topics/styles/
+extends: existence
+message: "Use standard spaces only. Do not use no-break or zero width spaces."
+vocab: false
+level: error
+ignorecase: true
+link: https://docs.gitlab.com/ee/development/documentation/styleguide/index.html#punctuation
+scope: raw
+raw:
+ - '[ ]'
diff --git a/doc/administration/geo/disaster_recovery/background_verification.md b/doc/administration/geo/disaster_recovery/background_verification.md
index 5032c19e289..a4b7b726d09 100644
--- a/doc/administration/geo/disaster_recovery/background_verification.md
+++ b/doc/administration/geo/disaster_recovery/background_verification.md
@@ -78,23 +78,7 @@ On the **primary** site:
## Reset verification for projects where verification has failed
Geo actively tries to correct verification failures marking the repository to
-be resynced with a back-off period. If you want to reset them manually, this
-Rake task marks projects where verification has failed or the checksum mismatch
-to be resynced without the back-off period:
-
-Run the appropriate commands on a **Rails node on the secondary** site.
-
-For repositories:
-
-```shell
-sudo gitlab-rake geo:verification:repository:reset
-```
-
-For wikis:
-
-```shell
-sudo gitlab-rake geo:verification:wiki:reset
-```
+be resynced with a back-off period. You can also manually [resync and reverify individual components through the UI or the Rails console](../replication/troubleshooting/synchronization_verification.md#resync-and-reverify-individual-components).
## Reconcile differences with checksum mismatches
diff --git a/doc/administration/geo/replication/troubleshooting/common.md b/doc/administration/geo/replication/troubleshooting/common.md
index d7dab564203..67ef1775499 100644
--- a/doc/administration/geo/replication/troubleshooting/common.md
+++ b/doc/administration/geo/replication/troubleshooting/common.md
@@ -484,16 +484,6 @@ See the [PostgreSQL wiki for more details](https://wiki.postgresql.org/wiki/Loca
This section documents common error messages reported in the **Admin** area on the web interface, and how to fix them.
-### Geo database configuration file is missing
-
-GitLab cannot find or doesn't have permission to access the `database_geo.yml` configuration file.
-
-In a Linux package installation, the file should be in `/var/opt/gitlab/gitlab-rails/etc`.
-If it doesn't exist or inadvertent changes have been made to it, run `sudo gitlab-ctl reconfigure` to restore it to its correct state.
-
-If this path is mounted on a remote volume, ensure your volume configuration
-has the correct permissions.
-
### An existing tracking database cannot be reused
Geo cannot reuse an existing tracking database.
diff --git a/doc/development/documentation/hugo_migration.md b/doc/development/documentation/hugo_migration.md
index 221c59930c5..6a8e4ab60ca 100644
--- a/doc/development/documentation/hugo_migration.md
+++ b/doc/development/documentation/hugo_migration.md
@@ -12,6 +12,13 @@ While existing content will be automatically updated, any new or modified docume
For the latest migration status, see [this issue](https://gitlab.com/gitlab-org/technical-writing/docs-gitlab-com/-/issues/44).
+## New project
+
+The new Docs website is in the [`gitlab-org/technical-writing/docs-gitlab-com`](https://gitlab.com/gitlab-org/technical-writing/docs-gitlab-com) project.
+
+After launch, all issues from the [original `gitlab-org/gitlab-docs` project](https://gitlab.com/gitlab-org/gitlab-docs)
+will be moved over to the new one, or closed if they're no longer applicable.
+
## Formatting changes
### Page titles
@@ -120,7 +127,7 @@ With Hugo, these will no longer have any effect. They will render as plain text.
**Why:** Hugo uses the Goldmark Markdown rendering engine, not Kramdown.
-**When:** After launch.
+**When:** At this time, avoid adding new Kramdown tags. Support for these is dropped entirely after launch.
**Testing:** We are running an audit job on the CI pipeline for Kramdown tags ([example](https://gitlab.com/gitlab-org/technical-writing-group/gitlab-docs-hugo/-/jobs/8885163533)).
These tags will be manually removed as part of launch.
diff --git a/doc/install/install_ai_gateway.md b/doc/install/install_ai_gateway.md
index 34cba12710c..0eeb0c2727d 100644
--- a/doc/install/install_ai_gateway.md
+++ b/doc/install/install_ai_gateway.md
@@ -260,3 +260,21 @@ resources:
| Small | 2 vCPUs, 8 GB RAM | Single instance | 40 | Fixed deployment; no autoscaling. |
| Medium | AWS t3.2xlarge | Single instance | 160 | HPA based on CPU or latency thresholds. |
| Large | Multiple t3.2xlarge | Clustered instances | 160 per instance | HPA + node autoscaling for high demand. |
+
+## Support multiple GitLab instances
+
+You can deploy a single AI gateway to support multiple GitLab instances, or deploy separate AI gateways per instance or geographic region. To help decide which is appropriate, consider:
+
+- Expected traffic of approximately seven requests per second per 1,000 billable users.
+- Resource requirements based on total concurrent requests across all instances.
+- Best practice authentication configuration for each GitLab instance.
+
+## Co-locate your AI gateway and instance
+
+The AI gateway is available in multiple regions globally to ensure optimal performance for users regardless of location, through:
+
+- Improved response times for Duo features.
+- Reduced latency for geographically distributed users.
+- Data sovereignty requirements compliance.
+
+You should locate your AI gateway in the same geographic region as your GitLab instance to help provide a frictionless developer experience, particularly for latency-sensitive features like Code Suggestions.
diff --git a/doc/update/breaking_windows.md b/doc/update/breaking_windows.md
index 1b210ac09f3..fecf135b230 100644
--- a/doc/update/breaking_windows.md
+++ b/doc/update/breaking_windows.md
@@ -67,6 +67,7 @@ This window takes place on April 28 - 30, 2025 from 09:00 UTC to 22:00 UTC.
| [`mergeTrainIndex` and `mergeTrainsCount` GraphQL fields deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/473759) | Low | Verify | Project |
| [RunnersRegistrationTokenReset GraphQL mutation is deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/505703) | High | Verify | Instance, group, project |
| [Behavior change for Upcoming and Started milestone filters](https://gitlab.com/gitlab-org/gitlab/-/issues/501294) | Low | Plan | Group, project |
+| [`kpt`-based `agentk` is deprecated](https://gitlab.com/gitlab-org/cluster-integration/gitlab-agent/-/issues/656) | Low | Deploy | Project |
## Window 3
diff --git a/doc/update/deprecations.md b/doc/update/deprecations.md
index 4031cb18a1c..b56d3b0c7e6 100644
--- a/doc/update/deprecations.md
+++ b/doc/update/deprecations.md
@@ -1587,6 +1587,29 @@ SLES 15 SP6 for continued support.