Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-08-27 03:10:33 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-08-27 03:10:33 +0300
commit7422896aeeaf745e987d1dbced7faee37d9dee4b (patch)
tree87a00a43134db0cd340549f393677bd41f5f9226
parented98ffb618acda4f207f13d6b262399368709023 (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--app/services/issue_rebalancing_service.rb71
-rw-r--r--app/services/issues/base_service.rb13
-rw-r--r--app/services/issues/create_service.rb1
-rw-r--r--app/services/issues/update_service.rb1
-rw-r--r--app/workers/all_queues.yml782
-rw-r--r--app/workers/issue_rebalancing_worker.rb17
-rw-r--r--changelogs/unreleased/ajk-relative-positioning-worker.yml5
-rw-r--r--config/feature_flags/development/rebalance_issues.yml7
-rw-r--r--config/sidekiq_queues.yml2
-rw-r--r--doc/user/project/issues/index.md2
-rw-r--r--doc/user/project/merge_requests/squash_and_merge.md17
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/move_project_create_fork_spec.rb4
-rw-r--r--spec/services/issue_rebalancing_service_spec.rb101
-rw-r--r--spec/services/issues/create_service_spec.rb31
-rw-r--r--spec/services/issues/update_service_spec.rb62
-rw-r--r--spec/workers/issue_rebalancing_worker_spec.rb32
16 files changed, 754 insertions, 394 deletions
diff --git a/app/services/issue_rebalancing_service.rb b/app/services/issue_rebalancing_service.rb
new file mode 100644
index 00000000000..4138c6441c8
--- /dev/null
+++ b/app/services/issue_rebalancing_service.rb
@@ -0,0 +1,71 @@
+# frozen_string_literal: true
+
+class IssueRebalancingService
+ MAX_ISSUE_COUNT = 10_000
+ TooManyIssues = Class.new(StandardError)
+
+ def initialize(issue)
+ @issue = issue
+ @base = Issue.relative_positioning_query_base(issue)
+ end
+
+ def execute
+ gates = [issue.project, issue.project.group].compact
+ return unless gates.any? { |gate| Feature.enabled?(:rebalance_issues, gate) }
+
+ raise TooManyIssues, "#{issue_count} issues" if issue_count > MAX_ISSUE_COUNT
+
+ start = RelativePositioning::START_POSITION - (gaps / 2) * gap_size
+
+ Issue.transaction do
+ indexed_ids.each_slice(100) { |pairs| assign_positions(start, pairs) }
+ end
+ end
+
+ private
+
+ attr_reader :issue, :base
+
+ # rubocop: disable CodeReuse/ActiveRecord
+ def indexed_ids
+ base.reorder(:relative_position, :id).pluck(:id).each_with_index
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+
+ # rubocop: disable CodeReuse/ActiveRecord
+ def assign_positions(start, positions)
+ values = positions.map do |id, index|
+ "(#{id}, #{start + (index * gap_size)})"
+ end.join(', ')
+
+ Issue.connection.exec_query(<<~SQL, "rebalance issue positions")
+ WITH cte(cte_id, new_pos) AS (
+ SELECT *
+ FROM (VALUES #{values}) as t (id, pos)
+ )
+ UPDATE #{Issue.table_name}
+ SET relative_position = cte.new_pos
+ FROM cte
+ WHERE cte_id = id
+ SQL
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+
+ def issue_count
+ @issue_count ||= base.count
+ end
+
+ def gaps
+ issue_count - 1
+ end
+
+ def gap_size
+ # We could try to split the available range over the number of gaps we need,
+ # but IDEAL_DISTANCE * MAX_ISSUE_COUNT is only 0.1% of the available range,
+ # so we are guaranteed not to exhaust it by using this static value.
+ #
+ # If we raise MAX_ISSUE_COUNT or IDEAL_DISTANCE significantly, this may
+ # change!
+ RelativePositioning::IDEAL_DISTANCE
+ end
+end
diff --git a/app/services/issues/base_service.rb b/app/services/issues/base_service.rb
index 9e72f6dad8d..8e42db746dd 100644
--- a/app/services/issues/base_service.rb
+++ b/app/services/issues/base_service.rb
@@ -19,6 +19,19 @@ module Issues
private
+ NO_REBALANCING_NEEDED = ((RelativePositioning::MIN_POSITION * 0.9999)..(RelativePositioning::MAX_POSITION * 0.9999)).freeze
+
+ def rebalance_if_needed(issue)
+ return unless issue
+ return if issue.relative_position.nil?
+ return if NO_REBALANCING_NEEDED.cover?(issue.relative_position)
+
+ gates = [issue.project, issue.project.group].compact
+ return unless gates.any? { |gate| Feature.enabled?(:rebalance_issues, gate) }
+
+ IssueRebalancingWorker.perform_async(issue.id)
+ end
+
def create_assignee_note(issue, old_assignees)
SystemNoteService.change_issuable_assignees(
issue, issue.project, current_user, old_assignees)
diff --git a/app/services/issues/create_service.rb b/app/services/issues/create_service.rb
index c0194f5b847..d9209191c1c 100644
--- a/app/services/issues/create_service.rb
+++ b/app/services/issues/create_service.rb
@@ -30,6 +30,7 @@ module Issues
user_agent_detail_service.create
resolve_discussions_with_issue(issuable)
delete_milestone_total_issue_counter_cache(issuable.milestone)
+ rebalance_if_needed(issuable)
super
end
diff --git a/app/services/issues/update_service.rb b/app/services/issues/update_service.rb
index ac7baba3b7c..b0cec002a23 100644
--- a/app/services/issues/update_service.rb
+++ b/app/services/issues/update_service.rb
@@ -83,6 +83,7 @@ module Issues
raise ActiveRecord::RecordNotFound unless issue_before || issue_after
issue.move_between(issue_before, issue_after)
+ rebalance_if_needed(issue)
end
# rubocop: disable CodeReuse/ActiveRecord
diff --git a/app/workers/all_queues.yml b/app/workers/all_queues.yml
index 5ce588c9dd8..f2ee0cc9204 100644
--- a/app/workers/all_queues.yml
+++ b/app/workers/all_queues.yml
@@ -5,7 +5,7 @@
---
- :name: authorized_project_update:authorized_project_update_project_create
:feature_category: :authentication_and_authorization
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
@@ -13,7 +13,7 @@
:tags: []
- :name: authorized_project_update:authorized_project_update_project_group_link_create
:feature_category: :authentication_and_authorization
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
@@ -21,7 +21,7 @@
:tags: []
- :name: authorized_project_update:authorized_project_update_user_refresh_over_user_range
:feature_category: :authentication_and_authorization
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
@@ -29,7 +29,7 @@
:tags: []
- :name: authorized_project_update:authorized_project_update_user_refresh_with_low_urgency
:feature_category: :authentication_and_authorization
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
@@ -37,87 +37,87 @@
:tags: []
- :name: auto_devops:auto_devops_disable
:feature_category: :auto_devops
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: auto_merge:auto_merge_process
:feature_category: :continuous_delivery
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :cpu
:weight: 3
- :idempotent:
+ :idempotent:
:tags: []
- :name: chaos:chaos_cpu_spin
:feature_category: :not_owned
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: chaos:chaos_db_spin
:feature_category: :not_owned
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: chaos:chaos_kill
:feature_category: :not_owned
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: chaos:chaos_leak_mem
:feature_category: :not_owned
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: chaos:chaos_sleep
:feature_category: :not_owned
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: container_repository:cleanup_container_repository
:feature_category: :container_registry
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: container_repository:delete_container_repository
:feature_category: :container_registry
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:admin_email
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:authorized_project_update_periodic_recalculate
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
@@ -125,79 +125,79 @@
:tags: []
- :name: cronjob:ci_archive_traces_cron
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:container_expiration_policy
:feature_category: :container_registry
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:environments_auto_stop_cron
:feature_category: :continuous_delivery
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:expire_build_artifacts
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:gitlab_usage_ping
:feature_category: :collection
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:import_export_project_cleanup
:feature_category: :importers
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:import_stuck_project_import_jobs
:feature_category: :importers
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :cpu
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:issue_due_scheduler
:feature_category: :issue_tracking
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:jira_import_stuck_jira_import_jobs
:feature_category: :importers
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :cpu
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:metrics_dashboard_schedule_annotations_prune
:feature_category: :metrics
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
@@ -205,39 +205,39 @@
:tags: []
- :name: cronjob:namespaces_prune_aggregation_schedules
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :cpu
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:pages_domain_removal_cron
:feature_category: :pages
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :cpu
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:pages_domain_ssl_renewal_cron
:feature_category: :pages
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:pages_domain_verification_cron
:feature_category: :pages
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:partition_creation
:feature_category: :database
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
@@ -245,135 +245,135 @@
:tags: []
- :name: cronjob:personal_access_tokens_expired_notification
:feature_category: :authentication_and_authorization
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:personal_access_tokens_expiring
:feature_category: :authentication_and_authorization
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:pipeline_schedule
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :cpu
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:prune_old_events
:feature_category: :users
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:prune_web_hook_logs
:feature_category: :integrations
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:remove_expired_group_links
:feature_category: :authentication_and_authorization
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:remove_expired_members
:feature_category: :authentication_and_authorization
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :cpu
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:remove_unreferenced_lfs_objects
:feature_category: :git_lfs
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:repository_archive_cache
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:repository_check_dispatch
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:requests_profiles
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:schedule_migrate_external_diffs
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:stuck_ci_jobs
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :cpu
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:stuck_export_jobs
:feature_category: :importers
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :cpu
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:stuck_merge_jobs
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:trending_projects
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:update_container_registry_info
:feature_category: :container_registry
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
@@ -381,11 +381,11 @@
:tags: []
- :name: cronjob:users_create_statistics
:feature_category: :users
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:x509_issuer_crl_check
:feature_category: :source_code_management
@@ -397,27 +397,27 @@
:tags: []
- :name: deployment:deployments_finished
:feature_category: :continuous_delivery
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :cpu
:weight: 3
- :idempotent:
+ :idempotent:
:tags: []
- :name: deployment:deployments_forward_deployment
:feature_category: :continuous_delivery
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 3
- :idempotent:
+ :idempotent:
:tags: []
- :name: deployment:deployments_success
:feature_category: :continuous_delivery
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :cpu
:weight: 3
- :idempotent:
+ :idempotent:
:tags: []
- :name: gcp_cluster:cluster_configure_istio
:feature_category: :kubernetes_management
@@ -425,7 +425,7 @@
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: gcp_cluster:cluster_install_app
:feature_category: :kubernetes_management
@@ -433,7 +433,7 @@
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: gcp_cluster:cluster_patch_app
:feature_category: :kubernetes_management
@@ -441,7 +441,7 @@
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: gcp_cluster:cluster_provision
:feature_category: :kubernetes_management
@@ -449,15 +449,15 @@
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: gcp_cluster:cluster_update_app
:feature_category: :kubernetes_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: gcp_cluster:cluster_upgrade_app
:feature_category: :kubernetes_management
@@ -465,7 +465,7 @@
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: gcp_cluster:cluster_wait_for_app_installation
:feature_category: :kubernetes_management
@@ -473,15 +473,15 @@
:urgency: :low
:resource_boundary: :cpu
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: gcp_cluster:cluster_wait_for_app_update
:feature_category: :kubernetes_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: gcp_cluster:cluster_wait_for_ingress_ip_address
:feature_category: :kubernetes_management
@@ -489,23 +489,23 @@
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: gcp_cluster:clusters_applications_activate_service
:feature_category: :kubernetes_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: gcp_cluster:clusters_applications_deactivate_service
:feature_category: :kubernetes_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: gcp_cluster:clusters_applications_uninstall
:feature_category: :kubernetes_management
@@ -513,7 +513,7 @@
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: gcp_cluster:clusters_applications_wait_for_uninstall_app
:feature_category: :kubernetes_management
@@ -521,7 +521,7 @@
:urgency: :low
:resource_boundary: :cpu
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: gcp_cluster:clusters_cleanup_app
:feature_category: :kubernetes_management
@@ -529,7 +529,7 @@
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: gcp_cluster:clusters_cleanup_project_namespace
:feature_category: :kubernetes_management
@@ -537,7 +537,7 @@
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: gcp_cluster:clusters_cleanup_service_account
:feature_category: :kubernetes_management
@@ -545,7 +545,7 @@
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: gcp_cluster:wait_for_cluster_creation
:feature_category: :kubernetes_management
@@ -553,7 +553,7 @@
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: github_importer:github_import_import_diff_note
:feature_category: :importers
@@ -561,7 +561,7 @@
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: github_importer:github_import_import_issue
:feature_category: :importers
@@ -569,7 +569,7 @@
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: github_importer:github_import_import_lfs_object
:feature_category: :importers
@@ -577,7 +577,7 @@
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: github_importer:github_import_import_note
:feature_category: :importers
@@ -585,7 +585,7 @@
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: github_importer:github_import_import_pull_request
:feature_category: :importers
@@ -593,103 +593,103 @@
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: github_importer:github_import_refresh_import_jid
:feature_category: :importers
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: github_importer:github_import_stage_finish_import
:feature_category: :importers
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: github_importer:github_import_stage_import_base_data
:feature_category: :importers
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: github_importer:github_import_stage_import_issues_and_diff_notes
:feature_category: :importers
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: github_importer:github_import_stage_import_lfs_objects
:feature_category: :importers
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: github_importer:github_import_stage_import_notes
:feature_category: :importers
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: github_importer:github_import_stage_import_pull_requests
:feature_category: :importers
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: github_importer:github_import_stage_import_repository
:feature_category: :importers
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: hashed_storage:hashed_storage_migrator
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: hashed_storage:hashed_storage_project_migrate
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: hashed_storage:hashed_storage_project_rollback
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: hashed_storage:hashed_storage_rollbacker
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: incident_management:clusters_applications_check_prometheus_health
:feature_category: :incident_management
@@ -701,175 +701,175 @@
:tags: []
- :name: incident_management:incident_management_pager_duty_process_incident
:feature_category: :incident_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: incident_management:incident_management_process_alert
:feature_category: :incident_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: incident_management:incident_management_process_prometheus_alert
:feature_category: :incident_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :cpu
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: jira_importer:jira_import_advance_stage
:feature_category: :importers
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: jira_importer:jira_import_import_issue
:feature_category: :importers
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: jira_importer:jira_import_stage_finish_import
:feature_category: :importers
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: jira_importer:jira_import_stage_import_attachments
:feature_category: :importers
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: jira_importer:jira_import_stage_import_issues
:feature_category: :importers
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: jira_importer:jira_import_stage_import_labels
:feature_category: :importers
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: jira_importer:jira_import_stage_import_notes
:feature_category: :importers
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: jira_importer:jira_import_stage_start_import
:feature_category: :importers
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: mail_scheduler:mail_scheduler_issue_due
:feature_category: :issue_tracking
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: mail_scheduler:mail_scheduler_notification_service
:feature_category: :issue_tracking
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :cpu
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: object_pool:object_pool_create
:feature_category: :gitaly
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: object_pool:object_pool_destroy
:feature_category: :gitaly
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: object_pool:object_pool_join
:feature_category: :gitaly
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :cpu
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: object_pool:object_pool_schedule_join
:feature_category: :gitaly
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: object_storage:object_storage_background_move
:feature_category: :not_owned
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: object_storage:object_storage_migrate_uploads
:feature_category: :not_owned
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: package_repositories:packages_nuget_extraction
:feature_category: :package_registry
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: pipeline_background:archive_trace
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: pipeline_background:ci_build_report_result
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
@@ -877,15 +877,15 @@
:tags: []
- :name: pipeline_background:ci_build_trace_chunk_flush
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: pipeline_background:ci_daily_build_group_report_results
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
@@ -893,7 +893,7 @@
:tags: []
- :name: pipeline_background:ci_pipeline_success_unlock_artifacts
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
@@ -901,7 +901,7 @@
:tags: []
- :name: pipeline_background:ci_pipelines_create_artifact
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
@@ -909,7 +909,7 @@
:tags: []
- :name: pipeline_background:ci_ref_delete_unlock_artifacts
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
@@ -917,7 +917,7 @@
:tags: []
- :name: pipeline_cache:expire_job_cache
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :unknown
:weight: 3
@@ -925,7 +925,7 @@
:tags: []
- :name: pipeline_cache:expire_pipeline_cache
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :cpu
:weight: 3
@@ -933,152 +933,152 @@
:tags: []
- :name: pipeline_creation:create_pipeline
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :cpu
:weight: 4
- :idempotent:
+ :idempotent:
:tags: []
- :name: pipeline_creation:run_pipeline_schedule
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 4
- :idempotent:
+ :idempotent:
:tags: []
- :name: pipeline_default:build_coverage
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 3
- :idempotent:
+ :idempotent:
:tags: []
- :name: pipeline_default:build_trace_sections
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 3
- :idempotent:
+ :idempotent:
:tags: []
- :name: pipeline_default:ci_create_cross_project_pipeline
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :cpu
:weight: 3
- :idempotent:
+ :idempotent:
:tags: []
- :name: pipeline_default:ci_pipeline_bridge_status
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :cpu
:weight: 3
- :idempotent:
+ :idempotent:
:tags: []
- :name: pipeline_default:pipeline_metrics
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :unknown
:weight: 3
- :idempotent:
+ :idempotent:
:tags: []
- :name: pipeline_default:pipeline_notification
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :cpu
:weight: 3
- :idempotent:
+ :idempotent:
:tags: []
- :name: pipeline_default:pipeline_update_ci_ref_status
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :cpu
:weight: 3
- :idempotent:
+ :idempotent:
:tags: []
- :name: pipeline_hooks:build_hooks
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :unknown
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: pipeline_hooks:pipeline_hooks
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :cpu
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: pipeline_processing:build_finished
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :cpu
:weight: 5
- :idempotent:
+ :idempotent:
:tags:
- :requires_disk_io
- :name: pipeline_processing:build_queue
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :cpu
:weight: 5
- :idempotent:
+ :idempotent:
:tags: []
- :name: pipeline_processing:build_success
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :unknown
:weight: 5
- :idempotent:
+ :idempotent:
:tags: []
- :name: pipeline_processing:ci_build_prepare
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 5
- :idempotent:
+ :idempotent:
:tags: []
- :name: pipeline_processing:ci_build_schedule
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :cpu
:weight: 5
- :idempotent:
+ :idempotent:
:tags: []
- :name: pipeline_processing:ci_resource_groups_assign_resource_from_resource_group
:feature_category: :continuous_delivery
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 5
- :idempotent:
+ :idempotent:
:tags: []
- :name: pipeline_processing:pipeline_process
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :unknown
:weight: 5
- :idempotent:
+ :idempotent:
:tags: []
- :name: pipeline_processing:pipeline_update
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :unknown
:weight: 5
@@ -1086,7 +1086,7 @@
:tags: []
- :name: pipeline_processing:stage_update
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :unknown
:weight: 5
@@ -1094,7 +1094,7 @@
:tags: []
- :name: pipeline_processing:update_head_pipeline_for_merge_request
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :cpu
:weight: 5
@@ -1102,71 +1102,71 @@
:tags: []
- :name: repository_check:repository_check_batch
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: repository_check:repository_check_clear
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: repository_check:repository_check_single_repository
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: todos_destroyer:todos_destroyer_confidential_issue
:feature_category: :issue_tracking
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: todos_destroyer:todos_destroyer_entity_leave
:feature_category: :issue_tracking
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: todos_destroyer:todos_destroyer_group_private
:feature_category: :issue_tracking
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: todos_destroyer:todos_destroyer_private_features
:feature_category: :issue_tracking
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: todos_destroyer:todos_destroyer_project_private
:feature_category: :issue_tracking
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: unassign_issuables:members_destroyer_unassign_issuables
:feature_category: :authentication_and_authorization
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
@@ -1174,7 +1174,7 @@
:tags: []
- :name: update_namespace_statistics:namespaces_root_statistics
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
@@ -1182,7 +1182,7 @@
:tags: []
- :name: update_namespace_statistics:namespaces_schedule_aggregation
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
@@ -1190,7 +1190,7 @@
:tags: []
- :name: authorized_keys
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :unknown
:weight: 2
@@ -1198,7 +1198,7 @@
:tags: []
- :name: authorized_projects
:feature_category: :authentication_and_authorization
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :unknown
:weight: 2
@@ -1206,11 +1206,11 @@
:tags: []
- :name: background_migration
:feature_category: :database
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :throttled
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: chat_notification
:feature_category: :chatops
@@ -1218,11 +1218,11 @@
:urgency: :low
:resource_boundary: :unknown
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: create_commit_signature
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 2
@@ -1230,91 +1230,91 @@
:tags: []
- :name: create_evidence
:feature_category: :release_evidence
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: create_note_diff_file
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: default
- :feature_category:
- :has_external_dependencies:
- :urgency:
- :resource_boundary:
+ :feature_category:
+ :has_external_dependencies:
+ :urgency:
+ :resource_boundary:
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: delete_diff_files
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: delete_merged_branches
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: delete_stored_files
:feature_category: :not_owned
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: delete_user
:feature_category: :authentication_and_authorization
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: design_management_new_version
:feature_category: :design_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :memory
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: detect_repository_languages
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: email_receiver
:feature_category: :issue_tracking
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :unknown
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: emails_on_push
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :cpu
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: error_tracking_issue_link
:feature_category: :error_tracking
@@ -1322,23 +1322,23 @@
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: expire_build_instance_artifacts
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: export_csv
:feature_category: :issue_tracking
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :cpu
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: external_service_reactive_caching
:feature_category: :not_owned
@@ -1346,15 +1346,15 @@
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: file_hook
:feature_category: :integrations
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: flush_counter_increments
:feature_category: :not_owned
@@ -1366,87 +1366,95 @@
:tags: []
- :name: git_garbage_collect
:feature_category: :gitaly
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: github_import_advance_stage
:feature_category: :importers
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: gitlab_shell
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :unknown
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: group_destroy
:feature_category: :subgroups
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: group_export
:feature_category: :importers
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: group_import
:feature_category: :importers
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: import_issues_csv
:feature_category: :issue_tracking
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :cpu
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: invalid_gpg_signature_update
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: irker
:feature_category: :integrations
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
+ :tags: []
+- :name: issue_rebalancing
+ :feature_category: :issue_tracking
+ :has_external_dependencies:
+ :urgency: :low
+ :resource_boundary: :unknown
+ :weight: 1
+ :idempotent: true
:tags: []
- :name: mailers
- :feature_category:
- :has_external_dependencies:
- :urgency:
- :resource_boundary:
+ :feature_category:
+ :has_external_dependencies:
+ :urgency:
+ :resource_boundary:
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: merge
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :unknown
:weight: 5
@@ -1454,7 +1462,7 @@
:tags: []
- :name: merge_request_mergeability_check
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
@@ -1462,7 +1470,7 @@
:tags: []
- :name: metrics_dashboard_prune_old_annotations
:feature_category: :metrics
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
@@ -1470,67 +1478,67 @@
:tags: []
- :name: migrate_external_diffs
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: namespaceless_project_destroy
:feature_category: :authentication_and_authorization
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: new_issue
:feature_category: :issue_tracking
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :cpu
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: new_merge_request
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :cpu
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: new_note
:feature_category: :issue_tracking
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :cpu
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: pages
:feature_category: :pages
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: pages_domain_ssl_renewal
:feature_category: :pages
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: pages_domain_verification
:feature_category: :pages
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: pages_remove
:feature_category: :pages
@@ -1550,7 +1558,7 @@
:tags: []
- :name: pages_update_configuration
:feature_category: :pages
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
@@ -1558,23 +1566,23 @@
:tags: []
- :name: phabricator_import_import_tasks
:feature_category: :importers
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: post_receive
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :cpu
:weight: 5
- :idempotent:
+ :idempotent:
:tags: []
- :name: process_commit
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :unknown
:weight: 3
@@ -1582,35 +1590,35 @@
:tags: []
- :name: project_cache
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: project_daily_statistics
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: project_destroy
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: project_export
:feature_category: :importers
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :throttled
:resource_boundary: :memory
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: project_service
:feature_category: :integrations
@@ -1618,11 +1626,11 @@
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: project_update_repository_storage
:feature_category: :gitaly
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :throttled
:resource_boundary: :unknown
:weight: 1
@@ -1630,7 +1638,7 @@
:tags: []
- :name: prometheus_create_default_alerts
:feature_category: :incident_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :unknown
:weight: 1
@@ -1638,7 +1646,7 @@
:tags: []
- :name: propagate_integration
:feature_category: :integrations
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
@@ -1646,51 +1654,51 @@
:tags: []
- :name: propagate_service_template
:feature_category: :integrations
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: reactive_caching
:feature_category: :not_owned
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :cpu
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: rebase
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: remote_mirror_notification
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: repository_cleanup
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: repository_fork
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: repository_import
:feature_category: :importers
@@ -1698,15 +1706,15 @@
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: repository_remove_remote
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: repository_update_remote_mirror
:feature_category: :source_code_management
@@ -1714,51 +1722,51 @@
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: self_monitoring_project_create
:feature_category: :metrics
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: self_monitoring_project_delete
:feature_category: :metrics
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: service_desk_email_receiver
:feature_category: :issue_tracking
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: system_hook_push
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: update_external_pull_requests
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 3
- :idempotent:
+ :idempotent:
:tags: []
- :name: update_highest_role
:feature_category: :authentication_and_authorization
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :unknown
:weight: 2
@@ -1766,27 +1774,27 @@
:tags: []
- :name: update_merge_requests
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :cpu
:weight: 3
- :idempotent:
+ :idempotent:
:tags: []
- :name: update_project_statistics
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: upload_checksum
:feature_category: :geo_replication
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: web_hook
:feature_category: :integrations
@@ -1794,11 +1802,11 @@
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: x509_certificate_revoke
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
diff --git a/app/workers/issue_rebalancing_worker.rb b/app/workers/issue_rebalancing_worker.rb
new file mode 100644
index 00000000000..c31b6cfbd86
--- /dev/null
+++ b/app/workers/issue_rebalancing_worker.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class IssueRebalancingWorker
+ include ApplicationWorker
+
+ idempotent!
+ urgency :low
+ feature_category :issue_tracking
+
+ def perform(issue_id)
+ issue = Issue.find(issue_id)
+
+ IssueRebalancingService.new(issue).execute
+ rescue ActiveRecord::RecordNotFound, IssueRebalancingService::TooManyIssues => e
+ Gitlab::ErrorTracking.log_exception(e, issue_id: issue_id)
+ end
+end
diff --git a/changelogs/unreleased/ajk-relative-positioning-worker.yml b/changelogs/unreleased/ajk-relative-positioning-worker.yml
new file mode 100644
index 00000000000..5fe891ec987
--- /dev/null
+++ b/changelogs/unreleased/ajk-relative-positioning-worker.yml
@@ -0,0 +1,5 @@
+---
+title: Add background worker to rebalance issues
+merge_request: 40124
+author:
+type: added
diff --git a/config/feature_flags/development/rebalance_issues.yml b/config/feature_flags/development/rebalance_issues.yml
new file mode 100644
index 00000000000..4c14824a35d
--- /dev/null
+++ b/config/feature_flags/development/rebalance_issues.yml
@@ -0,0 +1,7 @@
+---
+name: rebalance_issues
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40124
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/239344
+group: 'group::project management'
+type: development
+default_enabled: false
diff --git a/config/sidekiq_queues.yml b/config/sidekiq_queues.yml
index a3e98c77746..0452a9b6621 100644
--- a/config/sidekiq_queues.yml
+++ b/config/sidekiq_queues.yml
@@ -138,6 +138,8 @@
- 2
- - irker
- 1
+- - issue_rebalancing
+ - 1
- - jira_connect
- 1
- - jira_importer
diff --git a/doc/user/project/issues/index.md b/doc/user/project/issues/index.md
index 87b705bca94..17d9cdb1e2a 100644
--- a/doc/user/project/issues/index.md
+++ b/doc/user/project/issues/index.md
@@ -112,8 +112,6 @@ and modify them if you have the necessary [permissions](../../permissions.md).
#### Real-time sidebar **(CORE ONLY)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/17589) in GitLab 13.3.
-> - It cannot be enabled or disabled per-project.
-> - It's not recommended for production use.
Assignees in the sidebar are updated in real time. This feature is **disabled by default**.
To enable, you need to enable [ActionCable in-app mode](https://docs.gitlab.com/omnibus/settings/actioncable.html).
diff --git a/doc/user/project/merge_requests/squash_and_merge.md b/doc/user/project/merge_requests/squash_and_merge.md
index bea3faf9af5..ef49a026c99 100644
--- a/doc/user/project/merge_requests/squash_and_merge.md
+++ b/doc/user/project/merge_requests/squash_and_merge.md
@@ -65,14 +65,27 @@ meaningful commit messages and:
## Enabling squash for a merge request
Anyone who can create or edit a merge request can choose for it to be squashed
-on the merge request form:
+on the merge request form. Users can select or unselect the checkbox at the moment
+they are creating the merge request:
![Squash commits checkbox on edit form](img/squash_edit_form.png)
-This can then be overridden at the time of accepting the merge request:
+After the merge request is submitted, Squash and Merge can still be enabled or disabled
+by editing the merge request description:
+
+1. Scroll to the top of the merge request page and click **Edit**.
+1. Scroll down to the end of the merge request form and select the checkbox
+**Squash commits when merge request is accepted**.
+
+This setting can then be overridden at the time of accepting the merge request.
+At the end of the merge request widget, next to the **Merge** button, the **Squash commits** checkbox
+can be either selected or unselected:
![Squash commits checkbox on accept merge request form](img/squash_mr_widget.png)
+Note that Squash and Merge might not be available depending on the project's configuration
+for [Squash Commit Options](#squash-commits-options).
+
## Commit metadata for squashed commits
The squashed commit has the following metadata:
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/move_project_create_fork_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/move_project_create_fork_spec.rb
index c9dc82baf41..db1cf1acea9 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/move_project_create_fork_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/move_project_create_fork_spec.rb
@@ -1,8 +1,8 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Create', quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/217002', type: :investigating } do
- describe 'Gitaly repository storage', :orchestrated, :repository_storage, :requires_admin do
+ RSpec.describe 'Create', :orchestrated, :repository_storage, :requires_admin, quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/217002', type: :investigating } do
+ describe 'Gitaly repository storage' do
let(:user) { Resource::User.fabricate_or_use(Runtime::Env.gitlab_qa_username_1, Runtime::Env.gitlab_qa_password_1) }
let(:parent_project) do
Resource::Project.fabricate_via_api! do |project|
diff --git a/spec/services/issue_rebalancing_service_spec.rb b/spec/services/issue_rebalancing_service_spec.rb
new file mode 100644
index 00000000000..94f594c8083
--- /dev/null
+++ b/spec/services/issue_rebalancing_service_spec.rb
@@ -0,0 +1,101 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe IssueRebalancingService do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:user) { project.creator }
+ let_it_be(:start) { RelativePositioning::START_POSITION }
+ let_it_be(:max_pos) { RelativePositioning::MAX_POSITION }
+ let_it_be(:min_pos) { RelativePositioning::MIN_POSITION }
+ let_it_be(:clump_size) { 300 }
+
+ let_it_be(:unclumped) do
+ (0..clump_size).to_a.map do |i|
+ create(:issue, project: project, author: user, relative_position: start + (1024 * i))
+ end
+ end
+
+ let_it_be(:end_clump) do
+ (0..clump_size).to_a.map do |i|
+ create(:issue, project: project, author: user, relative_position: max_pos - i)
+ end
+ end
+
+ let_it_be(:start_clump) do
+ (0..clump_size).to_a.map do |i|
+ create(:issue, project: project, author: user, relative_position: min_pos + i)
+ end
+ end
+
+ def issues_in_position_order
+ project.reload.issues.reorder(relative_position: :asc).to_a
+ end
+
+ it 'rebalances a set of issues with clumps at the end and start' do
+ all_issues = start_clump + unclumped + end_clump.reverse
+ service = described_class.new(project.issues.first)
+
+ expect { service.execute }.not_to change { issues_in_position_order.map(&:id) }
+
+ all_issues.each(&:reset)
+
+ gaps = all_issues.take(all_issues.count - 1).zip(all_issues.drop(1)).map do |a, b|
+ b.relative_position - a.relative_position
+ end
+
+ expect(gaps).to all(be > RelativePositioning::MIN_GAP)
+ expect(all_issues.first.relative_position).to be > (RelativePositioning::MIN_POSITION * 0.9999)
+ expect(all_issues.last.relative_position).to be < (RelativePositioning::MAX_POSITION * 0.9999)
+ end
+
+ it 'is idempotent' do
+ service = described_class.new(project.issues.first)
+
+ expect do
+ service.execute
+ service.execute
+ end.not_to change { issues_in_position_order.map(&:id) }
+ end
+
+ it 'does nothing if the feature flag is disabled' do
+ stub_feature_flags(rebalance_issues: false)
+ issue = project.issues.first
+ issue.project
+ issue.project.group
+ old_pos = issue.relative_position
+
+ service = described_class.new(issue)
+
+ expect { service.execute }.not_to exceed_query_limit(0)
+ expect(old_pos).to eq(issue.reload.relative_position)
+ end
+
+ it 'acts if the flag is enabled for the project' do
+ issue = create(:issue, project: project, author: user, relative_position: max_pos)
+ stub_feature_flags(rebalance_issues: issue.project)
+
+ service = described_class.new(issue)
+
+ expect { service.execute }.to change { issue.reload.relative_position }
+ end
+
+ it 'acts if the flag is enabled for the group' do
+ issue = create(:issue, project: project, author: user, relative_position: max_pos)
+ project.update!(group: create(:group))
+ stub_feature_flags(rebalance_issues: issue.project.group)
+
+ service = described_class.new(issue)
+
+ expect { service.execute }.to change { issue.reload.relative_position }
+ end
+
+ it 'aborts if there are too many issues' do
+ issue = project.issues.first
+ base = double(count: 10_001)
+
+ allow(Issue).to receive(:relative_positioning_query_base).with(issue).and_return(base)
+
+ expect { described_class.new(issue).execute }.to raise_error(described_class::TooManyIssues)
+ end
+end
diff --git a/spec/services/issues/create_service_spec.rb b/spec/services/issues/create_service_spec.rb
index fdf2326b75e..004c37a0a7a 100644
--- a/spec/services/issues/create_service_spec.rb
+++ b/spec/services/issues/create_service_spec.rb
@@ -75,6 +75,37 @@ RSpec.describe Issues::CreateService do
expect(Todo.where(attributes).count).to eq 1
end
+ it 'rebalances if needed' do
+ create(:issue, project: project, relative_position: RelativePositioning::MAX_POSITION)
+ expect(IssueRebalancingWorker).to receive(:perform_async).with(Integer)
+
+ expect(issue.relative_position).to eq(project.issues.maximum(:relative_position))
+ end
+
+ it 'does not rebalance if the flag is disabled' do
+ stub_feature_flags(rebalance_issues: false)
+
+ create(:issue, project: project, relative_position: RelativePositioning::MAX_POSITION)
+ expect(IssueRebalancingWorker).not_to receive(:perform_async).with(Integer)
+
+ expect(issue.relative_position).to eq(project.issues.maximum(:relative_position))
+ end
+
+ it 'does rebalance if the flag is enabled for the project' do
+ stub_feature_flags(rebalance_issues: project)
+
+ create(:issue, project: project, relative_position: RelativePositioning::MAX_POSITION)
+ expect(IssueRebalancingWorker).to receive(:perform_async).with(Integer)
+
+ expect(issue.relative_position).to eq(project.issues.maximum(:relative_position))
+ end
+
+ it 'does not rebalance unless needed' do
+ expect(IssueRebalancingWorker).not_to receive(:perform_async)
+
+ expect(issue.relative_position).to eq(project.issues.maximum(:relative_position))
+ end
+
context 'when label belongs to project group' do
let(:group) { create(:group) }
let(:group_labels) { create_pair(:group_label, group: group) }
diff --git a/spec/services/issues/update_service_spec.rb b/spec/services/issues/update_service_spec.rb
index 42452e95f6b..aa9ce4ce1a9 100644
--- a/spec/services/issues/update_service_spec.rb
+++ b/spec/services/issues/update_service_spec.rb
@@ -106,7 +106,7 @@ RSpec.describe Issues::UpdateService, :mailer do
[issue, issue1, issue2].each do |issue|
issue.move_to_end
- issue.save
+ issue.save!
end
opts[:move_between_ids] = [issue1.id, issue2.id]
@@ -116,6 +116,66 @@ RSpec.describe Issues::UpdateService, :mailer do
expect(issue.relative_position).to be_between(issue1.relative_position, issue2.relative_position)
end
+ it 'does not rebalance even if needed if the flag is disabled' do
+ stub_feature_flags(rebalance_issues: false)
+
+ range = described_class::NO_REBALANCING_NEEDED
+ issue1 = create(:issue, project: project, relative_position: range.first - 100)
+ issue2 = create(:issue, project: project, relative_position: range.first)
+ issue.update!(relative_position: RelativePositioning::START_POSITION)
+
+ opts[:move_between_ids] = [issue1.id, issue2.id]
+
+ expect(IssueRebalancingWorker).not_to receive(:perform_async).with(issue.id)
+
+ update_issue(opts)
+ expect(issue.relative_position).to be_between(issue1.relative_position, issue2.relative_position)
+ end
+
+ it 'rebalances if needed if the flag is enabled for the project' do
+ stub_feature_flags(rebalance_issues: project)
+
+ range = described_class::NO_REBALANCING_NEEDED
+ issue1 = create(:issue, project: project, relative_position: range.first - 100)
+ issue2 = create(:issue, project: project, relative_position: range.first)
+ issue.update!(relative_position: RelativePositioning::START_POSITION)
+
+ opts[:move_between_ids] = [issue1.id, issue2.id]
+
+ expect(IssueRebalancingWorker).to receive(:perform_async).with(issue.id)
+
+ update_issue(opts)
+ expect(issue.relative_position).to be_between(issue1.relative_position, issue2.relative_position)
+ end
+
+ it 'rebalances if needed on the left' do
+ range = described_class::NO_REBALANCING_NEEDED
+ issue1 = create(:issue, project: project, relative_position: range.first - 100)
+ issue2 = create(:issue, project: project, relative_position: range.first)
+ issue.update!(relative_position: RelativePositioning::START_POSITION)
+
+ opts[:move_between_ids] = [issue1.id, issue2.id]
+
+ expect(IssueRebalancingWorker).to receive(:perform_async).with(issue.id)
+
+ update_issue(opts)
+ expect(issue.relative_position).to be_between(issue1.relative_position, issue2.relative_position)
+ end
+
+ it 'rebalances if needed on the right' do
+ range = described_class::NO_REBALANCING_NEEDED
+ issue1 = create(:issue, project: project, relative_position: range.last)
+ issue2 = create(:issue, project: project, relative_position: range.last + 100)
+ issue.update!(relative_position: RelativePositioning::START_POSITION)
+
+ opts[:move_between_ids] = [issue1.id, issue2.id]
+
+ expect(IssueRebalancingWorker).to receive(:perform_async).with(issue.id)
+
+ update_issue(opts)
+ expect(issue.relative_position).to be_between(issue1.relative_position, issue2.relative_position)
+ end
+
context 'when moving issue between issues from different projects' do
let(:group) { create(:group) }
let(:subgroup) { create(:group, parent: group) }
diff --git a/spec/workers/issue_rebalancing_worker_spec.rb b/spec/workers/issue_rebalancing_worker_spec.rb
new file mode 100644
index 00000000000..a2e44e74e06
--- /dev/null
+++ b/spec/workers/issue_rebalancing_worker_spec.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe IssueRebalancingWorker do
+ describe '#perform' do
+ let_it_be(:issue) { create(:issue) }
+
+ it 'runs an instance of IssueRebalancingService' do
+ service = double(execute: nil)
+ expect(IssueRebalancingService).to receive(:new).with(issue).and_return(service)
+
+ described_class.new.perform(issue.id)
+ end
+
+ it 'anticipates the inability to find the issue' do
+ expect(Gitlab::ErrorTracking).to receive(:log_exception).with(ActiveRecord::RecordNotFound, include(issue_id: -1))
+ expect(IssueRebalancingService).not_to receive(:new)
+
+ described_class.new.perform(-1)
+ end
+
+ it 'anticipates there being too many issues' do
+ service = double
+ allow(service).to receive(:execute) { raise IssueRebalancingService::TooManyIssues }
+ expect(IssueRebalancingService).to receive(:new).with(issue).and_return(service)
+ expect(Gitlab::ErrorTracking).to receive(:log_exception).with(IssueRebalancingService::TooManyIssues, include(issue_id: issue.id))
+
+ described_class.new.perform(issue.id)
+ end
+ end
+end