diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION
index 3c03f29e505..520f62a3f45 100644
--- a/GITALY_SERVER_VERSION
+++ b/GITALY_SERVER_VERSION
@@ -1 +1 @@
-d99f9cbac9164647666f1778eb912568c261813d
+8e59a9f5d61cceb4ded8b12c02c4b75b48b83f46
diff --git a/Gemfile b/Gemfile
index 3a04f1e1395..237ac191e68 100644
--- a/Gemfile
+++ b/Gemfile
@@ -196,7 +196,7 @@ gem 'acts-as-taggable-on', '~> 7.0'
# Background jobs
gem 'sidekiq', '~> 6.2.2'
-gem 'sidekiq-cron', '~> 1.0'
+gem 'sidekiq-cron', '~> 1.2'
gem 'redis-namespace', '~> 1.8.1'
gem 'gitlab-sidekiq-fetcher', '0.8.0', require: 'sidekiq-reliable-fetch'
diff --git a/Gemfile.lock b/Gemfile.lock
index 7497734d6dc..59e134c4170 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1172,7 +1172,7 @@ GEM
connection_pool (>= 2.2.2)
rack (~> 2.0)
redis (>= 4.2.0)
- sidekiq-cron (1.0.4)
+ sidekiq-cron (1.2.0)
fugit (~> 1.1)
sidekiq (>= 4.2.1)
signet (0.14.0)
@@ -1611,7 +1611,7 @@ DEPENDENCIES
settingslogic (~> 2.0.9)
shoulda-matchers (~> 4.0.1)
sidekiq (~> 6.2.2)
- sidekiq-cron (~> 1.0)
+ sidekiq-cron (~> 1.2)
simple_po_parser (~> 1.1.2)
simplecov (~> 0.18.5)
simplecov-cobertura (~> 1.3.1)
diff --git a/app/assets/javascripts/create_cluster/eks_cluster/components/eks_cluster_configuration_form.vue b/app/assets/javascripts/create_cluster/eks_cluster/components/eks_cluster_configuration_form.vue
index 9d4eddc510a..73458a463f2 100644
--- a/app/assets/javascripts/create_cluster/eks_cluster/components/eks_cluster_configuration_form.vue
+++ b/app/assets/javascripts/create_cluster/eks_cluster/components/eks_cluster_configuration_form.vue
@@ -84,7 +84,7 @@ export default {
),
subnetDropdownHelpPath: 'https://console.aws.amazon.com/vpc/home?#subnets',
securityGroupDropdownHelpText: s__(
- 'ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets.',
+ 'ClusterIntegration|Choose the %{linkStart}security group%{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets.',
),
securityGroupDropdownHelpPath: 'https://console.aws.amazon.com/vpc/home?#securityGroups',
instanceTypesDropdownHelpText: s__(
diff --git a/app/assets/javascripts/ref/constants.js b/app/assets/javascripts/ref/constants.js
index 1cef986a83d..397e3ed2ac8 100644
--- a/app/assets/javascripts/ref/constants.js
+++ b/app/assets/javascripts/ref/constants.js
@@ -15,9 +15,9 @@ export const DEFAULT_I18N = Object.freeze({
searchPlaceholder: __('Search by Git revision'),
noResultsWithQuery: __('No matching results for "%{query}"'),
noResults: __('No matching results'),
- branchesErrorMessage: __('An error occurred while fetching branches. Retry the search.'),
+ branchesErrorMessage: __('An error occurred while fetching branches. Retry the search.'),
tagsErrorMessage: __('An error occurred while fetching tags. Retry the search.'),
- commitsErrorMessage: __('An error occurred while fetching commits. Retry the search.'),
+ commitsErrorMessage: __('An error occurred while fetching commits. Retry the search.'),
branches: __('Branches'),
tags: __('Tags'),
commits: __('Commits'),
diff --git a/app/assets/javascripts/vue_shared/components/content_viewer/viewers/markdown_viewer.vue b/app/assets/javascripts/vue_shared/components/content_viewer/viewers/markdown_viewer.vue
index ea507017caa..9cf8638f3cb 100644
--- a/app/assets/javascripts/vue_shared/components/content_viewer/viewers/markdown_viewer.vue
+++ b/app/assets/javascripts/vue_shared/components/content_viewer/viewers/markdown_viewer.vue
@@ -1,5 +1,8 @@
@@ -111,8 +118,8 @@ export default {
diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss
index c597d2dd8da..cf5e93e94a2 100644
--- a/app/assets/stylesheets/pages/issuable.scss
+++ b/app/assets/stylesheets/pages/issuable.scss
@@ -179,6 +179,7 @@
}
.block,
+ .sidebar-contained-width,
.issuable-sidebar-header {
@include clearfix;
padding: $gl-padding 0;
@@ -317,6 +318,7 @@
padding: 0;
.block,
+ .sidebar-contained-width,
.issuable-sidebar-header {
width: $gutter-collapsed-width - 2px;
padding: 0;
diff --git a/app/controllers/admin/labels_controller.rb b/app/controllers/admin/labels_controller.rb
index 6cc11b40de0..822b7a93c9c 100644
--- a/app/controllers/admin/labels_controller.rb
+++ b/app/controllers/admin/labels_controller.rb
@@ -3,7 +3,7 @@
class Admin::LabelsController < Admin::ApplicationController
before_action :set_label, only: [:show, :edit, :update, :destroy]
- feature_category :issue_tracking
+ feature_category :team_planning
def index
@labels = Label.templates.page(params[:page])
diff --git a/app/controllers/autocomplete_controller.rb b/app/controllers/autocomplete_controller.rb
index 1c07245da08..5cb5690d72d 100644
--- a/app/controllers/autocomplete_controller.rb
+++ b/app/controllers/autocomplete_controller.rb
@@ -5,7 +5,7 @@ class AutocompleteController < ApplicationController
feature_category :users, [:users, :user]
feature_category :projects, [:projects]
- feature_category :issue_tracking, [:award_emojis]
+ feature_category :team_planning, [:award_emojis]
feature_category :code_review, [:merge_request_target_branches]
feature_category :continuous_delivery, [:deploy_keys_with_owners]
diff --git a/app/controllers/boards/issues_controller.rb b/app/controllers/boards/issues_controller.rb
index 7dea6191fa4..e7ae941886d 100644
--- a/app/controllers/boards/issues_controller.rb
+++ b/app/controllers/boards/issues_controller.rb
@@ -21,7 +21,7 @@ module Boards
before_action :validate_id_list, only: [:bulk_move]
before_action :can_move_issues?, only: [:bulk_move]
- feature_category :boards
+ feature_category :team_planning
def index
list_service = Boards::Issues::ListService.new(board_parent, current_user, filter_params)
diff --git a/app/controllers/boards/lists_controller.rb b/app/controllers/boards/lists_controller.rb
index 8ab8337a3ad..696b251301f 100644
--- a/app/controllers/boards/lists_controller.rb
+++ b/app/controllers/boards/lists_controller.rb
@@ -8,7 +8,7 @@ module Boards
before_action :authorize_read_list, only: [:index]
skip_before_action :authenticate_user!, only: [:index]
- feature_category :boards
+ feature_category :team_planning
def index
lists = Boards::Lists::ListService.new(board.resource_parent, current_user).execute(board)
diff --git a/app/controllers/dashboard/labels_controller.rb b/app/controllers/dashboard/labels_controller.rb
index b661efa12c0..d2f31258ecd 100644
--- a/app/controllers/dashboard/labels_controller.rb
+++ b/app/controllers/dashboard/labels_controller.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
class Dashboard::LabelsController < Dashboard::ApplicationController
- feature_category :issue_tracking
+ feature_category :team_planning
def index
respond_to do |format|
diff --git a/app/controllers/dashboard/milestones_controller.rb b/app/controllers/dashboard/milestones_controller.rb
index 1369e82a69b..34d9739d91c 100644
--- a/app/controllers/dashboard/milestones_controller.rb
+++ b/app/controllers/dashboard/milestones_controller.rb
@@ -4,7 +4,7 @@ class Dashboard::MilestonesController < Dashboard::ApplicationController
before_action :projects
before_action :groups, only: :index
- feature_category :issue_tracking
+ feature_category :team_planning
def index
respond_to do |format|
diff --git a/app/controllers/dashboard/todos_controller.rb b/app/controllers/dashboard/todos_controller.rb
index 21bbb4d0c98..2c5e6817427 100644
--- a/app/controllers/dashboard/todos_controller.rb
+++ b/app/controllers/dashboard/todos_controller.rb
@@ -8,7 +8,7 @@ class Dashboard::TodosController < Dashboard::ApplicationController
before_action :authorize_read_group!, only: :index
before_action :find_todos, only: [:index, :destroy_all]
- feature_category :issue_tracking
+ feature_category :team_planning
def index
@sort = params[:sort]
diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb
index 227dd0591d4..8d7686a95fb 100644
--- a/app/controllers/dashboard_controller.rb
+++ b/app/controllers/dashboard_controller.rb
@@ -15,7 +15,7 @@ class DashboardController < Dashboard::ApplicationController
respond_to :html
feature_category :users, [:activity]
- feature_category :issue_tracking, [:issues, :issues_calendar]
+ feature_category :team_planning, [:issues, :issues_calendar]
feature_category :code_review, [:merge_requests]
def activity
diff --git a/app/controllers/groups/autocomplete_sources_controller.rb b/app/controllers/groups/autocomplete_sources_controller.rb
index 5270a718952..82f8854bd2b 100644
--- a/app/controllers/groups/autocomplete_sources_controller.rb
+++ b/app/controllers/groups/autocomplete_sources_controller.rb
@@ -2,7 +2,7 @@
class Groups::AutocompleteSourcesController < Groups::ApplicationController
feature_category :subgroups, [:members]
- feature_category :issue_tracking, [:issues, :labels, :milestones, :commands]
+ feature_category :team_planning, [:issues, :labels, :milestones, :commands]
feature_category :code_review, [:merge_requests]
def members
diff --git a/app/controllers/groups/boards_controller.rb b/app/controllers/groups/boards_controller.rb
index e8e6a7e5c1a..14dfd3f8178 100644
--- a/app/controllers/groups/boards_controller.rb
+++ b/app/controllers/groups/boards_controller.rb
@@ -14,7 +14,7 @@ class Groups::BoardsController < Groups::ApplicationController
push_frontend_feature_flag(:labels_widget, group, default_enabled: :yaml)
end
- feature_category :boards
+ feature_category :team_planning
private
diff --git a/app/controllers/groups/labels_controller.rb b/app/controllers/groups/labels_controller.rb
index 86dde454cbc..7bcc8182bd6 100644
--- a/app/controllers/groups/labels_controller.rb
+++ b/app/controllers/groups/labels_controller.rb
@@ -9,7 +9,7 @@ class Groups::LabelsController < Groups::ApplicationController
respond_to :html
- feature_category :issue_tracking
+ feature_category :team_planning
def index
respond_to do |format|
diff --git a/app/controllers/groups/milestones_controller.rb b/app/controllers/groups/milestones_controller.rb
index 63eff750d1b..75877cdef9c 100644
--- a/app/controllers/groups/milestones_controller.rb
+++ b/app/controllers/groups/milestones_controller.rb
@@ -6,7 +6,7 @@ class Groups::MilestonesController < Groups::ApplicationController
before_action :milestone, only: [:edit, :show, :update, :issues, :merge_requests, :participants, :labels, :destroy]
before_action :authorize_admin_milestones!, only: [:edit, :new, :create, :update, :destroy]
- feature_category :issue_tracking
+ feature_category :team_planning
def index
respond_to do |format|
diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb
index 6e5597d7932..6ae711a6e14 100644
--- a/app/controllers/groups_controller.rb
+++ b/app/controllers/groups_controller.rb
@@ -54,7 +54,7 @@ class GroupsController < Groups::ApplicationController
:destroy, :details, :transfer, :activity
]
- feature_category :issue_tracking, [:issues, :issues_calendar, :preview_markdown]
+ feature_category :team_planning, [:issues, :issues_calendar, :preview_markdown]
feature_category :code_review, [:merge_requests, :unfoldered_environment_names]
feature_category :projects, [:projects]
feature_category :importers, [:export, :download_export]
diff --git a/app/controllers/projects/autocomplete_sources_controller.rb b/app/controllers/projects/autocomplete_sources_controller.rb
index 7c419cac1cc..0d5f64c739c 100644
--- a/app/controllers/projects/autocomplete_sources_controller.rb
+++ b/app/controllers/projects/autocomplete_sources_controller.rb
@@ -3,7 +3,7 @@
class Projects::AutocompleteSourcesController < Projects::ApplicationController
before_action :authorize_read_milestone!, only: :milestones
- feature_category :issue_tracking, [:issues, :labels, :milestones, :commands]
+ feature_category :team_planning, [:issues, :labels, :milestones, :commands]
feature_category :code_review, [:merge_requests]
feature_category :users, [:members]
feature_category :snippets, [:snippets]
diff --git a/app/controllers/projects/boards_controller.rb b/app/controllers/projects/boards_controller.rb
index 834e4baa7dd..bffaa12302a 100644
--- a/app/controllers/projects/boards_controller.rb
+++ b/app/controllers/projects/boards_controller.rb
@@ -14,7 +14,7 @@ class Projects::BoardsController < Projects::ApplicationController
push_frontend_feature_flag(:labels_widget, project, default_enabled: :yaml)
end
- feature_category :boards
+ feature_category :team_planning
private
diff --git a/app/controllers/projects/discussions_controller.rb b/app/controllers/projects/discussions_controller.rb
index 708b7a6c7ba..9f7d47b95f3 100644
--- a/app/controllers/projects/discussions_controller.rb
+++ b/app/controllers/projects/discussions_controller.rb
@@ -9,7 +9,7 @@ class Projects::DiscussionsController < Projects::ApplicationController
before_action :discussion, only: [:resolve, :unresolve]
before_action :authorize_resolve_discussion!, only: [:resolve, :unresolve]
- feature_category :issue_tracking
+ feature_category :team_planning
def resolve
Discussions::ResolveService.new(project, current_user, one_or_more_discussions: discussion).execute
diff --git a/app/controllers/projects/issue_links_controller.rb b/app/controllers/projects/issue_links_controller.rb
index 35f3e00fae7..e8c3110574f 100644
--- a/app/controllers/projects/issue_links_controller.rb
+++ b/app/controllers/projects/issue_links_controller.rb
@@ -7,7 +7,7 @@ module Projects
before_action :authorize_admin_issue_link!, only: [:create, :destroy]
before_action :authorize_issue_link_association!, only: :destroy
- feature_category :issue_tracking
+ feature_category :team_planning
private
diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb
index 6c096b5715a..781c63e32f5 100644
--- a/app/controllers/projects/issues_controller.rb
+++ b/app/controllers/projects/issues_controller.rb
@@ -69,7 +69,7 @@ class Projects::IssuesController < Projects::ApplicationController
alias_method :designs, :show
- feature_category :issue_tracking, [
+ feature_category :team_planning, [
:index, :calendar, :show, :new, :create, :edit, :update,
:destroy, :move, :reorder, :designs, :toggle_subscription,
:discussions, :bulk_update, :realtime_changes,
diff --git a/app/controllers/projects/labels_controller.rb b/app/controllers/projects/labels_controller.rb
index 6bf3885fb7a..814081194d6 100644
--- a/app/controllers/projects/labels_controller.rb
+++ b/app/controllers/projects/labels_controller.rb
@@ -14,7 +14,7 @@ class Projects::LabelsController < Projects::ApplicationController
respond_to :js, :html
- feature_category :issue_tracking
+ feature_category :team_planning
def index
respond_to do |format|
diff --git a/app/controllers/projects/milestones_controller.rb b/app/controllers/projects/milestones_controller.rb
index 630e7ccd43f..5dc9718d7a4 100644
--- a/app/controllers/projects/milestones_controller.rb
+++ b/app/controllers/projects/milestones_controller.rb
@@ -18,7 +18,7 @@ class Projects::MilestonesController < Projects::ApplicationController
respond_to :html
- feature_category :issue_tracking
+ feature_category :team_planning
def index
@sort = params[:sort] || 'due_date_asc'
diff --git a/app/controllers/projects/notes_controller.rb b/app/controllers/projects/notes_controller.rb
index e7e6aed8ec8..1eb4f6f1b7a 100644
--- a/app/controllers/projects/notes_controller.rb
+++ b/app/controllers/projects/notes_controller.rb
@@ -11,7 +11,7 @@ class Projects::NotesController < Projects::ApplicationController
before_action :authorize_create_note!, only: [:create]
before_action :authorize_resolve_note!, only: [:resolve, :unresolve]
- feature_category :issue_tracking
+ feature_category :team_planning
def delete_attachment
note.remove_attachment!
diff --git a/app/controllers/projects/todos_controller.rb b/app/controllers/projects/todos_controller.rb
index 6ba89ab34f8..dafdeb4c9ef 100644
--- a/app/controllers/projects/todos_controller.rb
+++ b/app/controllers/projects/todos_controller.rb
@@ -6,7 +6,7 @@ class Projects::TodosController < Projects::ApplicationController
before_action :authenticate_user!, only: [:create]
- feature_category :issue_tracking
+ feature_category :team_planning
private
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index 26da0436dd8..8e833a2f8dc 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -49,7 +49,7 @@ class ProjectsController < Projects::ApplicationController
]
feature_category :source_code_management, [:remove_fork, :housekeeping, :refs]
- feature_category :issue_tracking, [:preview_markdown, :new_issuable_address]
+ feature_category :team_planning, [:preview_markdown, :new_issuable_address]
feature_category :importers, [:export, :remove_export, :generate_new_export, :download_export]
feature_category :code_review, [:unfoldered_environment_names]
diff --git a/app/models/chat_name.rb b/app/models/chat_name.rb
index ff3f2663b73..da7312df18b 100644
--- a/app/models/chat_name.rb
+++ b/app/models/chat_name.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
class ChatName < ApplicationRecord
+ include LooseForeignKey
+
LAST_USED_AT_INTERVAL = 1.hour
belongs_to :integration, foreign_key: :service_id
@@ -14,6 +16,8 @@ class ChatName < ApplicationRecord
validates :user_id, uniqueness: { scope: [:service_id] }
validates :chat_id, uniqueness: { scope: [:service_id, :team_id] }
+ loose_foreign_key :ci_pipeline_chat_data, :chat_name_id, on_delete: :async_delete
+
# Updates the "last_used_timestamp" but only if it wasn't already updated
# recently.
#
diff --git a/app/models/ci/runner.rb b/app/models/ci/runner.rb
index 2a56d79094a..13f1302bdb0 100644
--- a/app/models/ci/runner.rb
+++ b/app/models/ci/runner.rb
@@ -12,6 +12,7 @@ module Ci
include Gitlab::Utils::StrongMemoize
include TaggableQueries
include Presentable
+ include LooseForeignKey
add_authentication_token_field :token, encrypted: :optional
@@ -167,6 +168,8 @@ module Ci
validates :config, json_schema: { filename: 'ci_runner_config' }
+ loose_foreign_key :clusters_applications_runners, :runner_id, on_delete: :async_nullify
+
# Searches for runners matching the given query.
#
# This method uses ILIKE on PostgreSQL for the description field and performs a full match on tokens.
diff --git a/app/models/namespace.rb b/app/models/namespace.rb
index 79af57a6ff1..f93f21aba23 100644
--- a/app/models/namespace.rb
+++ b/app/models/namespace.rb
@@ -93,9 +93,11 @@ class Namespace < ApplicationRecord
validates :max_artifacts_size, numericality: { only_integer: true, greater_than: 0, allow_nil: true }
validate :validate_parent_type, if: -> { Feature.enabled?(:validate_namespace_parent_type, default_enabled: :yaml) }
- validate :nesting_level_allowed
- validate :changing_shared_runners_enabled_is_allowed
- validate :changing_allow_descendants_override_disabled_shared_runners_is_allowed
+
+ # ProjectNamespaces excluded as they are not meant to appear in the group hierarchy at the moment.
+ validate :nesting_level_allowed, unless: -> { project_namespace? }
+ validate :changing_shared_runners_enabled_is_allowed, unless: -> { project_namespace? }
+ validate :changing_allow_descendants_override_disabled_shared_runners_is_allowed, unless: -> { project_namespace? }
delegate :name, to: :owner, allow_nil: true, prefix: true
delegate :avatar_url, to: :owner, allow_nil: true
diff --git a/app/views/projects/branches/_branch.html.haml b/app/views/projects/branches/_branch.html.haml
index 99a9535b8e8..be6efa310b9 100644
--- a/app/views/projects/branches/_branch.html.haml
+++ b/app/views/projects/branches/_branch.html.haml
@@ -23,7 +23,7 @@
- if commit
= render 'projects/branches/commit', commit: commit, project: @project
- else
- = s_('Branches|Cant find HEAD commit for this branch')
+ = s_('Branches|Can’t find HEAD commit for this branch')
- if branch.name != @repository.root_ref
.js-branch-divergence-graph
diff --git a/app/views/projects/mirrors/_instructions.html.haml b/app/views/projects/mirrors/_instructions.html.haml
index a91751da0aa..2bd2c7cac44 100644
--- a/app/views/projects/mirrors/_instructions.html.haml
+++ b/app/views/projects/mirrors/_instructions.html.haml
@@ -3,7 +3,7 @@
%li
= html_escape(_('The repository must be accessible over %{code_open}http://%{code_close},
%{code_open}https://%{code_close}, %{code_open}ssh://%{code_close} or %{code_open}git://%{code_close}.')) % { code_open: ''.html_safe, code_close: '
'.html_safe }
- %li= html_escape(_('When using the %{code_open}http://%{code_close} or %{code_open}https://%{code_close} protocols, provide the exact URL to the repository. HTTP redirects will not be followed.')) % { code_open: ''.html_safe, code_close: '
'.html_safe }
+ %li= html_escape(_('When using the %{code_open}http://%{code_close} or %{code_open}https://%{code_close} protocols, please provide the exact URL to the repository. HTTP redirects will not be followed.')) % { code_open: ''.html_safe, code_close: '
'.html_safe }
%li= html_escape(_('Include the username in the URL if required: %{code_open}https://username@gitlab.company.com/group/project.git%{code_close}.')) % { code_open: ''.html_safe, code_close: '
'.html_safe }
%li
- minutes = Gitlab.config.gitlab_shell.git_timeout / 60
diff --git a/app/views/projects/pages/_no_domains.html.haml b/app/views/projects/pages/_no_domains.html.haml
index 8d6e403b93a..a537bd80d30 100644
--- a/app/views/projects/pages/_no_domains.html.haml
+++ b/app/views/projects/pages/_no_domains.html.haml
@@ -3,4 +3,4 @@
.card-header
= s_('GitLabPages|Domains')
.nothing-here-block
- = s_("GitLabPages|Support for domains and certificates is disabled. Ask your system's administrator to enable it.")
+ = s_("GitLabPages|Support for domains and certificates is disabled. Ask your system's administrator to enable it.")
diff --git a/app/views/shared/runners/_shared_runners_description.html.haml b/app/views/shared/runners/_shared_runners_description.html.haml
index a276f725576..e2b57a7fd73 100644
--- a/app/views/shared/runners/_shared_runners_description.html.haml
+++ b/app/views/shared/runners/_shared_runners_description.html.haml
@@ -1,4 +1,5 @@
-- link = link_to _('MaxBuilds'), 'https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-runnersmachine-section', target: '_blank'
+-# "MaxBuilds" is a runner configuration keyword so it must not be translated.
+- link = link_to 'MaxBuilds', 'https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-runnersmachine-section', target: '_blank'
%h4
= _('Shared runners')
diff --git a/app/workers/all_queues.yml b/app/workers/all_queues.yml
index a1ecd8ccf25..fa6fcf89a5c 100644
--- a/app/workers/all_queues.yml
+++ b/app/workers/all_queues.yml
@@ -347,7 +347,7 @@
:tags: []
- :name: cronjob:issue_due_scheduler
:worker_name: IssueDueSchedulerWorker
- :feature_category: :issue_tracking
+ :feature_category: :team_planning
:has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
@@ -1260,7 +1260,7 @@
:tags: []
- :name: mail_scheduler:mail_scheduler_issue_due
:worker_name: MailScheduler::IssueDueWorker
- :feature_category: :issue_tracking
+ :feature_category: :team_planning
:has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
@@ -1269,7 +1269,7 @@
:tags: []
- :name: mail_scheduler:mail_scheduler_notification_service
:worker_name: MailScheduler::NotificationServiceWorker
- :feature_category: :issue_tracking
+ :feature_category: :team_planning
:has_external_dependencies:
:urgency: :low
:resource_boundary: :cpu
@@ -1746,7 +1746,7 @@
:tags: []
- :name: todos_destroyer:todos_destroyer_confidential_issue
:worker_name: TodosDestroyer::ConfidentialIssueWorker
- :feature_category: :issue_tracking
+ :feature_category: :team_planning
:has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
@@ -1755,7 +1755,7 @@
:tags: []
- :name: todos_destroyer:todos_destroyer_destroyed_designs
:worker_name: TodosDestroyer::DestroyedDesignsWorker
- :feature_category: :issue_tracking
+ :feature_category: :team_planning
:has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
@@ -1764,7 +1764,7 @@
:tags: []
- :name: todos_destroyer:todos_destroyer_destroyed_issuable
:worker_name: TodosDestroyer::DestroyedIssuableWorker
- :feature_category: :issue_tracking
+ :feature_category: :team_planning
:has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
@@ -1773,7 +1773,7 @@
:tags: []
- :name: todos_destroyer:todos_destroyer_entity_leave
:worker_name: TodosDestroyer::EntityLeaveWorker
- :feature_category: :issue_tracking
+ :feature_category: :team_planning
:has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
@@ -1782,7 +1782,7 @@
:tags: []
- :name: todos_destroyer:todos_destroyer_group_private
:worker_name: TodosDestroyer::GroupPrivateWorker
- :feature_category: :issue_tracking
+ :feature_category: :team_planning
:has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
@@ -1791,7 +1791,7 @@
:tags: []
- :name: todos_destroyer:todos_destroyer_private_features
:worker_name: TodosDestroyer::PrivateFeaturesWorker
- :feature_category: :issue_tracking
+ :feature_category: :team_planning
:has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
@@ -1800,7 +1800,7 @@
:tags: []
- :name: todos_destroyer:todos_destroyer_project_private
:worker_name: TodosDestroyer::ProjectPrivateWorker
- :feature_category: :issue_tracking
+ :feature_category: :team_planning
:has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
@@ -2061,7 +2061,7 @@
:tags: []
- :name: email_receiver
:worker_name: EmailReceiverWorker
- :feature_category: :issue_tracking
+ :feature_category: :team_planning
:has_external_dependencies:
:urgency: :high
:resource_boundary: :unknown
@@ -2125,7 +2125,7 @@
:tags: []
- :name: export_csv
:worker_name: ExportCsvWorker
- :feature_category: :issue_tracking
+ :feature_category: :team_planning
:has_external_dependencies:
:urgency: :low
:resource_boundary: :cpu
@@ -2215,7 +2215,7 @@
:tags: []
- :name: import_issues_csv
:worker_name: ImportIssuesCsvWorker
- :feature_category: :issue_tracking
+ :feature_category: :team_planning
:has_external_dependencies:
:urgency: :low
:resource_boundary: :cpu
@@ -2242,7 +2242,7 @@
:tags: []
- :name: issuable_export_csv
:worker_name: IssuableExportCsvWorker
- :feature_category: :issue_tracking
+ :feature_category: :team_planning
:has_external_dependencies:
:urgency: :low
:resource_boundary: :cpu
@@ -2251,7 +2251,7 @@
:tags: []
- :name: issuable_label_links_destroy
:worker_name: Issuable::LabelLinksDestroyWorker
- :feature_category: :issue_tracking
+ :feature_category: :team_planning
:has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
@@ -2260,7 +2260,7 @@
:tags: []
- :name: issuables_clear_groups_issue_counter
:worker_name: Issuables::ClearGroupsIssueCounterWorker
- :feature_category: :issue_tracking
+ :feature_category: :team_planning
:has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
@@ -2269,7 +2269,7 @@
:tags: []
- :name: issue_placement
:worker_name: IssuePlacementWorker
- :feature_category: :issue_tracking
+ :feature_category: :team_planning
:has_external_dependencies:
:urgency: :high
:resource_boundary: :cpu
@@ -2278,7 +2278,7 @@
:tags: []
- :name: issue_rebalancing
:worker_name: IssueRebalancingWorker
- :feature_category: :issue_tracking
+ :feature_category: :team_planning
:has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
@@ -2287,7 +2287,7 @@
:tags: []
- :name: issues_placement
:worker_name: Issues::PlacementWorker
- :feature_category: :issue_tracking
+ :feature_category: :team_planning
:has_external_dependencies:
:urgency: :high
:resource_boundary: :cpu
@@ -2296,7 +2296,7 @@
:tags: []
- :name: issues_rebalancing
:worker_name: Issues::RebalancingWorker
- :feature_category: :issue_tracking
+ :feature_category: :team_planning
:has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
@@ -2440,7 +2440,7 @@
:tags: []
- :name: new_issue
:worker_name: NewIssueWorker
- :feature_category: :issue_tracking
+ :feature_category: :team_planning
:has_external_dependencies:
:urgency: :high
:resource_boundary: :cpu
@@ -2458,7 +2458,7 @@
:tags: []
- :name: new_note
:worker_name: NewNoteWorker
- :feature_category: :issue_tracking
+ :feature_category: :team_planning
:has_external_dependencies:
:urgency: :high
:resource_boundary: :cpu
diff --git a/app/workers/concerns/todos_destroyer_queue.rb b/app/workers/concerns/todos_destroyer_queue.rb
index 1bbccbfb1f9..1c31b64ad97 100644
--- a/app/workers/concerns/todos_destroyer_queue.rb
+++ b/app/workers/concerns/todos_destroyer_queue.rb
@@ -8,6 +8,6 @@ module TodosDestroyerQueue
included do
queue_namespace :todos_destroyer
- feature_category :issue_tracking
+ feature_category :team_planning
end
end
diff --git a/app/workers/email_receiver_worker.rb b/app/workers/email_receiver_worker.rb
index 51211834e06..a1277ceeada 100644
--- a/app/workers/email_receiver_worker.rb
+++ b/app/workers/email_receiver_worker.rb
@@ -7,7 +7,7 @@ class EmailReceiverWorker # rubocop:disable Scalability/IdempotentWorker
sidekiq_options retry: 3
- feature_category :issue_tracking
+ feature_category :team_planning
urgency :high
weight 2
diff --git a/app/workers/export_csv_worker.rb b/app/workers/export_csv_worker.rb
index 68feaa61cdd..c5feb02b2bd 100644
--- a/app/workers/export_csv_worker.rb
+++ b/app/workers/export_csv_worker.rb
@@ -7,7 +7,7 @@ class ExportCsvWorker # rubocop:disable Scalability/IdempotentWorker
sidekiq_options retry: 3
- feature_category :issue_tracking
+ feature_category :team_planning
worker_resource_boundary :cpu
loggable_arguments 2
diff --git a/app/workers/import_issues_csv_worker.rb b/app/workers/import_issues_csv_worker.rb
index 58e411c7b19..fe5b1c13d56 100644
--- a/app/workers/import_issues_csv_worker.rb
+++ b/app/workers/import_issues_csv_worker.rb
@@ -8,7 +8,7 @@ class ImportIssuesCsvWorker # rubocop:disable Scalability/IdempotentWorker
sidekiq_options retry: 3
idempotent!
- feature_category :issue_tracking
+ feature_category :team_planning
worker_resource_boundary :cpu
weight 2
diff --git a/app/workers/issuable/label_links_destroy_worker.rb b/app/workers/issuable/label_links_destroy_worker.rb
index f88c061bafb..da785550a43 100644
--- a/app/workers/issuable/label_links_destroy_worker.rb
+++ b/app/workers/issuable/label_links_destroy_worker.rb
@@ -7,7 +7,7 @@ module Issuable
data_consistency :always
idempotent!
- feature_category :issue_tracking
+ feature_category :team_planning
def perform(target_id, target_type)
::Issuable::DestroyLabelLinksService.new(target_id, target_type).execute
diff --git a/app/workers/issuable_export_csv_worker.rb b/app/workers/issuable_export_csv_worker.rb
index 7e2c3407772..9d543a21dc3 100644
--- a/app/workers/issuable_export_csv_worker.rb
+++ b/app/workers/issuable_export_csv_worker.rb
@@ -7,7 +7,7 @@ class IssuableExportCsvWorker # rubocop:disable Scalability/IdempotentWorker
sidekiq_options retry: 3
- feature_category :issue_tracking
+ feature_category :team_planning
worker_resource_boundary :cpu
loggable_arguments 2
diff --git a/app/workers/issuables/clear_groups_issue_counter_worker.rb b/app/workers/issuables/clear_groups_issue_counter_worker.rb
index 9e62224b83d..82026bc21c7 100644
--- a/app/workers/issuables/clear_groups_issue_counter_worker.rb
+++ b/app/workers/issuables/clear_groups_issue_counter_worker.rb
@@ -8,7 +8,7 @@ module Issuables
idempotent!
urgency :low
- feature_category :issue_tracking
+ feature_category :team_planning
def perform(group_ids = [])
return if group_ids.empty?
diff --git a/app/workers/issue_due_scheduler_worker.rb b/app/workers/issue_due_scheduler_worker.rb
index ad3470ae64b..ab586dce717 100644
--- a/app/workers/issue_due_scheduler_worker.rb
+++ b/app/workers/issue_due_scheduler_worker.rb
@@ -7,7 +7,7 @@ class IssueDueSchedulerWorker # rubocop:disable Scalability/IdempotentWorker
include CronjobQueue # rubocop:disable Scalability/CronWorkerContext
- feature_category :issue_tracking
+ feature_category :team_planning
# rubocop: disable CodeReuse/ActiveRecord
def perform
diff --git a/app/workers/issue_placement_worker.rb b/app/workers/issue_placement_worker.rb
index 5a66c8d79ea..cfd72b90a42 100644
--- a/app/workers/issue_placement_worker.rb
+++ b/app/workers/issue_placement_worker.rb
@@ -12,7 +12,7 @@ class IssuePlacementWorker
idempotent!
deduplicate :until_executed, including_scheduled: true
- feature_category :issue_tracking
+ feature_category :team_planning
urgency :high
worker_resource_boundary :cpu
weight 2
diff --git a/app/workers/issue_rebalancing_worker.rb b/app/workers/issue_rebalancing_worker.rb
index 9c2a6355d2b..250093362a9 100644
--- a/app/workers/issue_rebalancing_worker.rb
+++ b/app/workers/issue_rebalancing_worker.rb
@@ -12,7 +12,7 @@ class IssueRebalancingWorker
idempotent!
urgency :low
- feature_category :issue_tracking
+ feature_category :team_planning
deduplicate :until_executed, including_scheduled: true
def perform(ignore = nil, project_id = nil, root_namespace_id = nil)
diff --git a/app/workers/issues/placement_worker.rb b/app/workers/issues/placement_worker.rb
index 0aa6b21622d..ec29a754128 100644
--- a/app/workers/issues/placement_worker.rb
+++ b/app/workers/issues/placement_worker.rb
@@ -10,7 +10,7 @@ module Issues
idempotent!
deduplicate :until_executed, including_scheduled: true
- feature_category :issue_tracking
+ feature_category :team_planning
urgency :high
worker_resource_boundary :cpu
weight 2
diff --git a/app/workers/issues/rebalancing_worker.rb b/app/workers/issues/rebalancing_worker.rb
index 05455800860..466617d9fa1 100644
--- a/app/workers/issues/rebalancing_worker.rb
+++ b/app/workers/issues/rebalancing_worker.rb
@@ -10,7 +10,7 @@ module Issues
idempotent!
urgency :low
- feature_category :issue_tracking
+ feature_category :team_planning
deduplicate :until_executed, including_scheduled: true
def perform(ignore = nil, project_id = nil, root_namespace_id = nil)
diff --git a/app/workers/mail_scheduler/issue_due_worker.rb b/app/workers/mail_scheduler/issue_due_worker.rb
index 4c17f8df722..585fa43916e 100644
--- a/app/workers/mail_scheduler/issue_due_worker.rb
+++ b/app/workers/mail_scheduler/issue_due_worker.rb
@@ -9,7 +9,7 @@ module MailScheduler
sidekiq_options retry: 3
include MailSchedulerQueue
- feature_category :issue_tracking
+ feature_category :team_planning
# rubocop: disable CodeReuse/ActiveRecord
def perform(project_id)
diff --git a/app/workers/mail_scheduler/notification_service_worker.rb b/app/workers/mail_scheduler/notification_service_worker.rb
index 0e6494a45d6..25c9ac5547b 100644
--- a/app/workers/mail_scheduler/notification_service_worker.rb
+++ b/app/workers/mail_scheduler/notification_service_worker.rb
@@ -11,7 +11,7 @@ module MailScheduler
sidekiq_options retry: 3
include MailSchedulerQueue
- feature_category :issue_tracking
+ feature_category :team_planning
worker_resource_boundary :cpu
loggable_arguments 0
diff --git a/app/workers/new_issue_worker.rb b/app/workers/new_issue_worker.rb
index 899545fc02c..13936fac1e4 100644
--- a/app/workers/new_issue_worker.rb
+++ b/app/workers/new_issue_worker.rb
@@ -8,7 +8,7 @@ class NewIssueWorker # rubocop:disable Scalability/IdempotentWorker
sidekiq_options retry: 3
include NewIssuable
- feature_category :issue_tracking
+ feature_category :team_planning
urgency :high
worker_resource_boundary :cpu
weight 2
diff --git a/app/workers/new_note_worker.rb b/app/workers/new_note_worker.rb
index e54d84e382e..e1120bee30a 100644
--- a/app/workers/new_note_worker.rb
+++ b/app/workers/new_note_worker.rb
@@ -7,7 +7,7 @@ class NewNoteWorker # rubocop:disable Scalability/IdempotentWorker
sidekiq_options retry: 3
- feature_category :issue_tracking
+ feature_category :team_planning
urgency :high
worker_resource_boundary :cpu
weight 2
diff --git a/config/feature_categories.yml b/config/feature_categories.yml
index e61048a6427..7d351d2b1ff 100644
--- a/config/feature_categories.yml
+++ b/config/feature_categories.yml
@@ -15,7 +15,6 @@
- authentication_and_authorization
- auto_devops
- backup_restore
-- boards
- build_artifacts
- chatops
- cloud_native_installation
@@ -44,7 +43,6 @@
- dynamic_application_security_testing
- editor_extension
- environment_management
-- epics
- error_tracking
- experimentation_activation
- experimentation_adoption
@@ -69,7 +67,6 @@
- intel_code_security
- interactive_application_security_testing
- internationalization
-- issue_tracking
- jenkins_importer
- kubernetes_management
- license
@@ -91,16 +88,17 @@
- pipeline_abuse_prevention
- pipeline_authoring
- planning_analytics
+- portfolio_management
- privacy_control_center
- product_analytics
- projects
- purchase
- quality_management
+- redis
- release_evidence
- release_orchestration
- requirements_management
- review_apps
-- roadmaps
- runbooks
- runner
- scalability
@@ -118,7 +116,7 @@
- static_site_editor
- subgroups
- synthetic_monitoring
-- time_tracking
+- team_planning
- tracing
- usability_testing
- usage_ping
diff --git a/config/initializers/postgres_partitioning.rb b/config/initializers/postgres_partitioning.rb
index 49f382547d6..883824cc16f 100644
--- a/config/initializers/postgres_partitioning.rb
+++ b/config/initializers/postgres_partitioning.rb
@@ -10,6 +10,29 @@ if Gitlab.ee?
IncidentManagement::PendingEscalations::Alert,
IncidentManagement::PendingEscalations::Issue
])
+else
+ Gitlab::Database::Partitioning.register_tables([
+ {
+ table_name: 'incident_management_pending_alert_escalations',
+ partitioned_column: :process_at, strategy: :monthly
+ },
+ {
+ table_name: 'incident_management_pending_issue_escalations',
+ partitioned_column: :process_at, strategy: :monthly
+ }
+ ])
+end
+
+# The following tables are already defined as models
+unless Gitlab.jh?
+ Gitlab::Database::Partitioning.register_tables([
+ # This should be synchronized with the following model:
+ # https://gitlab.com/gitlab-jh/gitlab/-/blob/main-jh/jh/app/models/phone/verification_code.rb
+ {
+ table_name: 'verification_codes',
+ partitioned_column: :created_at, strategy: :monthly
+ }
+ ])
end
begin
diff --git a/db/migrate/20211026143238_remove_index_releases_on_author_id.rb b/db/migrate/20211026143238_remove_index_releases_on_author_id.rb
new file mode 100644
index 00000000000..7cd086dbf7d
--- /dev/null
+++ b/db/migrate/20211026143238_remove_index_releases_on_author_id.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class RemoveIndexReleasesOnAuthorId < Gitlab::Database::Migration[1.0]
+ INDEX_NAME = 'index_releases_on_author_id'
+
+ disable_ddl_transaction!
+
+ def up
+ remove_concurrent_index_by_name :releases, INDEX_NAME
+ end
+
+ def down
+ add_concurrent_index :releases, [:author_id], name: INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20211018152654_schedule_remove_duplicate_vulnerabilities_findings3.rb b/db/post_migrate/20211018152654_schedule_remove_duplicate_vulnerabilities_findings3.rb
new file mode 100644
index 00000000000..ecad4466c53
--- /dev/null
+++ b/db/post_migrate/20211018152654_schedule_remove_duplicate_vulnerabilities_findings3.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+class ScheduleRemoveDuplicateVulnerabilitiesFindings3 < Gitlab::Database::Migration[1.0]
+ disable_ddl_transaction!
+
+ MIGRATION = 'RemoveDuplicateVulnerabilitiesFindings'
+ DELAY_INTERVAL = 2.minutes.to_i
+ BATCH_SIZE = 5_000
+
+ def up
+ queue_background_migration_jobs_by_range_at_intervals(
+ define_batchable_model('vulnerability_occurrences'),
+ MIGRATION,
+ DELAY_INTERVAL,
+ batch_size: BATCH_SIZE
+ )
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/post_migrate/20211027064021_track_deletions_in_ci_runners.rb b/db/post_migrate/20211027064021_track_deletions_in_ci_runners.rb
new file mode 100644
index 00000000000..14cf305fb2e
--- /dev/null
+++ b/db/post_migrate/20211027064021_track_deletions_in_ci_runners.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class TrackDeletionsInCiRunners < Gitlab::Database::Migration[1.0]
+ include Gitlab::Database::MigrationHelpers::LooseForeignKeyHelpers
+
+ enable_lock_retries!
+
+ def up
+ track_record_deletions(:ci_runners)
+ end
+
+ def down
+ untrack_record_deletions(:ci_runners)
+ end
+end
diff --git a/db/post_migrate/20211027064156_track_deletions_in_chat_names.rb b/db/post_migrate/20211027064156_track_deletions_in_chat_names.rb
new file mode 100644
index 00000000000..1c8f9d5196a
--- /dev/null
+++ b/db/post_migrate/20211027064156_track_deletions_in_chat_names.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class TrackDeletionsInChatNames < Gitlab::Database::Migration[1.0]
+ include Gitlab::Database::MigrationHelpers::LooseForeignKeyHelpers
+
+ enable_lock_retries!
+
+ def up
+ track_record_deletions(:chat_names)
+ end
+
+ def down
+ untrack_record_deletions(:chat_names)
+ end
+end
diff --git a/db/schema_migrations/20211018152654 b/db/schema_migrations/20211018152654
new file mode 100644
index 00000000000..86e9980ad10
--- /dev/null
+++ b/db/schema_migrations/20211018152654
@@ -0,0 +1 @@
+fd7b6eb9439c00334f613e3e4977e44054930c1343e5df32bbe82c64acd6ca7b
\ No newline at end of file
diff --git a/db/schema_migrations/20211026143238 b/db/schema_migrations/20211026143238
new file mode 100644
index 00000000000..9f0e7f76cd9
--- /dev/null
+++ b/db/schema_migrations/20211026143238
@@ -0,0 +1 @@
+6b1377dd7e9b78a35c2f5635d2d11f5fe254aa772576510b41fcf1e03ad56c87
\ No newline at end of file
diff --git a/db/schema_migrations/20211027064021 b/db/schema_migrations/20211027064021
new file mode 100644
index 00000000000..3bd57b30583
--- /dev/null
+++ b/db/schema_migrations/20211027064021
@@ -0,0 +1 @@
+f1b218eaddb9bcc5e4d854a6b43fc5e122b38dc989225327a1c4a899f41e5ac6
\ No newline at end of file
diff --git a/db/schema_migrations/20211027064156 b/db/schema_migrations/20211027064156
new file mode 100644
index 00000000000..880b7a00694
--- /dev/null
+++ b/db/schema_migrations/20211027064156
@@ -0,0 +1 @@
+3d7b72684102836d7a7efcab7590b3d14bc63eb3e1bfbc7a95fb5eb5c6a906af
\ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index 54aff7afd13..1b129381081 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -135,6 +135,19 @@ CREATE TABLE incident_management_pending_issue_escalations (
)
PARTITION BY RANGE (process_at);
+CREATE TABLE verification_codes (
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ visitor_id_code text NOT NULL,
+ code text NOT NULL,
+ phone text NOT NULL,
+ CONSTRAINT check_9b84e6aaff CHECK ((char_length(code) <= 8)),
+ CONSTRAINT check_ccc542256b CHECK ((char_length(visitor_id_code) <= 64)),
+ CONSTRAINT check_f5684c195b CHECK ((char_length(phone) <= 32))
+)
+PARTITION BY RANGE (created_at);
+
+COMMENT ON TABLE verification_codes IS 'JiHu-specific table';
+
CREATE TABLE web_hook_logs (
id bigint NOT NULL,
web_hook_id integer NOT NULL,
@@ -20185,19 +20198,6 @@ CREATE SEQUENCE users_statistics_id_seq
ALTER SEQUENCE users_statistics_id_seq OWNED BY users_statistics.id;
-CREATE TABLE verification_codes (
- created_at timestamp with time zone DEFAULT now() NOT NULL,
- visitor_id_code text NOT NULL,
- code text NOT NULL,
- phone text NOT NULL,
- CONSTRAINT check_9b84e6aaff CHECK ((char_length(code) <= 8)),
- CONSTRAINT check_ccc542256b CHECK ((char_length(visitor_id_code) <= 64)),
- CONSTRAINT check_f5684c195b CHECK ((char_length(phone) <= 32))
-)
-PARTITION BY RANGE (created_at);
-
-COMMENT ON TABLE verification_codes IS 'JiHu-specific table';
-
CREATE TABLE vulnerabilities (
id bigint NOT NULL,
milestone_id bigint,
@@ -26446,8 +26446,6 @@ CREATE UNIQUE INDEX index_release_links_on_release_id_and_name ON release_links
CREATE UNIQUE INDEX index_release_links_on_release_id_and_url ON release_links USING btree (release_id, url);
-CREATE INDEX index_releases_on_author_id ON releases USING btree (author_id);
-
CREATE INDEX index_releases_on_author_id_id_created_at ON releases USING btree (author_id, id, created_at);
CREATE INDEX index_releases_on_project_id_and_tag ON releases USING btree (project_id, tag);
@@ -27550,6 +27548,10 @@ ALTER INDEX product_analytics_events_experimental_pkey ATTACH PARTITION gitlab_p
ALTER INDEX product_analytics_events_experimental_pkey ATTACH PARTITION gitlab_partitions_static.product_analytics_events_experimental_63_pkey;
+CREATE TRIGGER chat_names_loose_fk_trigger AFTER DELETE ON chat_names REFERENCING OLD TABLE AS old_table FOR EACH STATEMENT EXECUTE FUNCTION insert_into_loose_foreign_keys_deleted_records();
+
+CREATE TRIGGER ci_runners_loose_fk_trigger AFTER DELETE ON ci_runners REFERENCING OLD TABLE AS old_table FOR EACH STATEMENT EXECUTE FUNCTION insert_into_loose_foreign_keys_deleted_records();
+
CREATE TRIGGER trigger_91dc388a5fe6 BEFORE INSERT OR UPDATE ON dep_ci_build_trace_sections FOR EACH ROW EXECUTE FUNCTION trigger_91dc388a5fe6();
CREATE TRIGGER trigger_delete_project_namespace_on_project_delete AFTER DELETE ON projects FOR EACH ROW WHEN ((old.project_namespace_id IS NOT NULL)) EXECUTE FUNCTION delete_associated_project_namespace();
diff --git a/doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md b/doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md
index 109f451be5a..be03014d4af 100644
--- a/doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md
+++ b/doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md
@@ -965,6 +965,19 @@ license.save
License.current # check to make sure it applied
```
+### Remove licenses
+
+To clean up the [License History table](../../user/admin_area/license.md#license-history):
+
+```ruby
+TYPE = :trial?
+# or :expired?
+
+License.select(&TYPE).each(&:destroy!)
+
+# or even License.all.each(&:destroy!)
+```
+
## Registry
### Registry Disk Space Usage by Project
diff --git a/doc/api/admin_sidekiq_queues.md b/doc/api/admin_sidekiq_queues.md
index 569dfd4c413..079ab96c938 100644
--- a/doc/api/admin_sidekiq_queues.md
+++ b/doc/api/admin_sidekiq_queues.md
@@ -35,7 +35,7 @@ DELETE /admin/sidekiq/queues/:queue_name
| `root_namespace` | string | no | The root namespace of the project |
| `subscription_plan` | string | no | The subscription plan of the root namespace (GitLab.com only) |
| `caller_id` | string | no | The endpoint or background job that schedule the job (for example: `ProjectsController#create`, `/api/:version/projects/:id`, `PostReceive`) |
-| `feature_category` | string | no | The feature category of the background job (for example: `issue_tracking` or `code_review`) |
+| `feature_category` | string | no | The feature category of the background job (for example: `team_planning` or `code_review`) |
| `worker_class` | string | no | The class of the background job worker (for example: `PostReceive` or `MergeWorker`) |
At least one attribute, other than `queue_name`, is required.
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 546ff2f8647..a2853cf7999 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -1554,7 +1554,7 @@ Input type: `DastProfileCreateInput`
| ---- | ---- | ----------- |
| `branchName` | [`String`](#string) | Associated branch. |
| `clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
-| `dastProfileSchedule` | [`DastProfileScheduleInput`](#dastprofilescheduleinput) | Represents a DAST Profile Schedule. Results in an error if `dast_on_demand_scans_scheduler` feature flag is disabled. |
+| `dastProfileSchedule` | [`DastProfileScheduleInput`](#dastprofilescheduleinput) | Represents a DAST Profile Schedule. |
| `dastScannerProfileId` | [`DastScannerProfileID!`](#dastscannerprofileid) | ID of the scanner profile to be associated. |
| `dastSiteProfileId` | [`DastSiteProfileID!`](#dastsiteprofileid) | ID of the site profile to be associated. |
| `description` | [`String`](#string) | Description of the profile. Defaults to an empty string. |
@@ -1619,7 +1619,7 @@ Input type: `DastProfileUpdateInput`
| ---- | ---- | ----------- |
| `branchName` | [`String`](#string) | Associated branch. |
| `clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
-| `dastProfileSchedule` | [`DastProfileScheduleInput`](#dastprofilescheduleinput) | Represents a DAST profile schedule. Results in an error if `dast_on_demand_scans_scheduler` feature flag is disabled. |
+| `dastProfileSchedule` | [`DastProfileScheduleInput`](#dastprofilescheduleinput) | Represents a DAST profile schedule. |
| `dastScannerProfileId` | [`DastScannerProfileID`](#dastscannerprofileid) | ID of the scanner profile to be associated. |
| `dastSiteProfileId` | [`DastSiteProfileID`](#dastsiteprofileid) | ID of the site profile to be associated. |
| `description` | [`String`](#string) | Description of the profile. Defaults to an empty string. |
@@ -8951,7 +8951,7 @@ Represents a DAST Profile.
| Name | Type | Description |
| ---- | ---- | ----------- |
| `branch` | [`DastProfileBranch`](#dastprofilebranch) | Associated branch. |
-| `dastProfileSchedule` | [`DastProfileSchedule`](#dastprofileschedule) | Associated profile schedule. Will always return `null` if `dast_on_demand_scans_scheduler` feature flag is disabled. |
+| `dastProfileSchedule` | [`DastProfileSchedule`](#dastprofileschedule) | Associated profile schedule. |
| `dastScannerProfile` | [`DastScannerProfile`](#dastscannerprofile) | Associated scanner profile. |
| `dastSiteProfile` | [`DastSiteProfile`](#dastsiteprofile) | Associated site profile. |
| `description` | [`String`](#string) | Description of the scan. |
diff --git a/doc/api/releases/index.md b/doc/api/releases/index.md
index ded47b24c12..c253358f01f 100644
--- a/doc/api/releases/index.md
+++ b/doc/api/releases/index.md
@@ -26,6 +26,8 @@ For authentication, the Releases API accepts either:
## List Releases
+> [Changed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/72448) to allow for `JOB-TOKEN` in GitLab 14.5.
+
Paginated list of Releases, sorted by `released_at`.
```plaintext
@@ -231,6 +233,8 @@ Example response:
## Get a Release by a tag name
+> [Changed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/72448) to allow for `JOB-TOKEN` in GitLab 14.5.
+
Get a Release for the given tag.
```plaintext
@@ -508,7 +512,8 @@ adding milestones for ancestor groups raises an error.
## Collect release evidence **(PREMIUM SELF)**
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/199065) in GitLab 12.10.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/199065) in GitLab 12.10.
+> - [Changed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/72448) to allow for `JOB-TOKEN` in GitLab 14.5.
Create Evidence for an existing Release.
@@ -535,6 +540,8 @@ Example response:
## Update a release
+> [Changed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/72448) to allow for `JOB-TOKEN` in GitLab 14.5.
+
Update a release. Developer level access to the project is required to update a release.
```plaintext
@@ -642,6 +649,8 @@ Example response:
## Delete a Release
+> [Changed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/72448) to allow for `JOB-TOKEN` in GitLab 14.5.
+
Delete a release. Deleting a release doesn't delete the associated tag. Maintainer level access to the project is required to delete a release.
```plaintext
diff --git a/doc/ci/jobs/ci_job_token.md b/doc/ci/jobs/ci_job_token.md
index 308f38b22b7..b6a3011a3d6 100644
--- a/doc/ci/jobs/ci_job_token.md
+++ b/doc/ci/jobs/ci_job_token.md
@@ -20,7 +20,7 @@ You can use a GitLab CI/CD job token to authenticate with specific API endpoints
- [Get job artifacts](../../api/job_artifacts.md#get-job-artifacts).
- [Get job token's job](../../api/jobs.md#get-job-tokens-job).
- [Pipeline triggers](../../api/pipeline_triggers.md), using the `token=` parameter.
-- [Release creation](../../api/releases/index.md#create-a-release).
+- [Releases](../../api/releases/index.md).
- [Terraform plan](../../user/infrastructure/index.md).
The token has the same permissions to access the API as the user that executes the
diff --git a/doc/development/application_slis/index.md b/doc/development/application_slis/index.md
index c1d7ac9fa0c..21b2d403a18 100644
--- a/doc/development/application_slis/index.md
+++ b/doc/development/application_slis/index.md
@@ -43,7 +43,7 @@ example:
```ruby
Gitlab::Metrics::Sli.initialize_sli(:received_email, [
{
- feature_category: :issue_tracking,
+ feature_category: :team_planning,
email_type: :create_issue
},
{
diff --git a/doc/development/application_slis/rails_request_apdex.md b/doc/development/application_slis/rails_request_apdex.md
index 2bb94b8406e..c1d792fecfb 100644
--- a/doc/development/application_slis/rails_request_apdex.md
+++ b/doc/development/application_slis/rails_request_apdex.md
@@ -153,7 +153,7 @@ information in the logs to determine this:
the service the endpoint is handled by. The overall duration should
be lower than the target you intend to set.
-1. If the overall duration is below the intended targed. Please also
+1. Assess if the overall duration is below the intended target. Please also
check the peaks over time in [this
graph](https://log.gprd.gitlab.net/goto/9319c4a402461d204d13f3a4924a89fc)
in Kibana. Here, the percentile in question should not peak above
@@ -161,7 +161,7 @@ information in the logs to determine this:
Since decreasing a threshold too much could result in alerts for the
apdex degradation, please also involve a Scalability team member in
-the merge reqeust.
+the merge request.
## How to adjust the urgency
diff --git a/doc/development/feature_categorization/index.md b/doc/development/feature_categorization/index.md
index 20325facc75..d6b64001e13 100644
--- a/doc/development/feature_categorization/index.md
+++ b/doc/development/feature_categorization/index.md
@@ -96,7 +96,7 @@ second argument:
```ruby
class DashboardController < ApplicationController
- feature_category :issue_tracking, [:issues, :issues_calendar]
+ feature_category :team_planning, [:issues, :issues_calendar]
feature_category :code_review, [:merge_requests]
end
```
@@ -137,7 +137,7 @@ Grape API endpoints can use the `feature_category` class method, like
```ruby
module API
class Issues < ::API::Base
- feature_category :issue_tracking
+ feature_category :team_planning
end
end
```
diff --git a/doc/development/testing_guide/end_to_end/running_tests_that_require_special_setup.md b/doc/development/testing_guide/end_to_end/running_tests_that_require_special_setup.md
index 1990b04e155..95984a701e7 100644
--- a/doc/development/testing_guide/end_to_end/running_tests_that_require_special_setup.md
+++ b/doc/development/testing_guide/end_to_end/running_tests_that_require_special_setup.md
@@ -165,20 +165,20 @@ QA_DEBUG=true WEBDRIVER_HEADLESS=false GITLAB_ADMIN_USERNAME=rootusername GITLAB
The following includes more information on the command:
--`QA_DEBUG` - Set to `true` to verbosely log page object actions.
--`WEBDRIVER_HEADLESS` - When running locally, set to `false` to allow browser tests to be visible - watch your tests being run.
--`GITLAB_ADMIN_USERNAME` - Administrator username to use when adding a license.
--`GITLAB_ADMIN_PASSWORD` - Administrator password to use when adding a license.
--`GITLAB_QA_ACCESS_TOKEN` and `GITLAB_QA_ADMIN_ACCESS_TOKEN` - A valid personal access token with the `api` scope. This is used for API access during tests, and is used in the version that staging is currently running. The `ADMIN_ACCESS_TOKEN` is from a user with administrator access. Used for API access as an administrator during tests.
--`CLUSTER_API_URL` - Use the address `https://kubernetes.docker.internal:6443` . This address is used to enable the cluster to be network accessible while deploying using Auto DevOps.
--`https://[YOUR-PORT].qa-tunnel.gitlab.info/` - The address of your local GDK
--`qa/specs/features/browser_ui/8_monitor/all_monitor_core_features_spec.rb` - The path to the monitor core specs
--`--tag` - the meta-tags used to filter the specs correctly
+- `QA_DEBUG` - Set to `true` to verbosely log page object actions.
+- `WEBDRIVER_HEADLESS` - When running locally, set to `false` to allow browser tests to be visible - watch your tests being run.
+- `GITLAB_ADMIN_USERNAME` - Administrator username to use when adding a license.
+- `GITLAB_ADMIN_PASSWORD` - Administrator password to use when adding a license.
+- `GITLAB_QA_ACCESS_TOKEN` and `GITLAB_QA_ADMIN_ACCESS_TOKEN` - A valid personal access token with the `api` scope. This is used for API access during tests, and is used in the version that staging is currently running. The `ADMIN_ACCESS_TOKEN` is from a user with administrator access. Used for API access as an administrator during tests.
+- `CLUSTER_API_URL` - Use the address `https://kubernetes.docker.internal:6443` . This address is used to enable the cluster to be network accessible while deploying using Auto DevOps.
+- `https://[YOUR-PORT].qa-tunnel.gitlab.info/` - The address of your local GDK
+- `qa/specs/features/browser_ui/8_monitor/all_monitor_core_features_spec.rb` - The path to the monitor core specs
+- `--tag` - the meta-tags used to filter the specs correctly
At the moment of this writing, there are two specs which run monitor tests:
--`qa/specs/features/browser_ui/8_monitor/all_monitor_core_features_spec.rb` - has the specs of features in GitLab Free
--`qa/specs/features/ee/browser_ui/8_monitor/all_monitor_features_spec.rb` - has the specs of features for paid GitLab (Enterprise Edition)
+- `qa/specs/features/browser_ui/8_monitor/all_monitor_core_features_spec.rb` - has the specs of features in GitLab Free
+- `qa/specs/features/ee/browser_ui/8_monitor/all_monitor_features_spec.rb` - has the specs of features for paid GitLab (Enterprise Edition)
### How to debug
diff --git a/doc/user/application_security/dast/index.md b/doc/user/application_security/dast/index.md
index fd22e2c9d6c..313ef9934b8 100644
--- a/doc/user/application_security/dast/index.md
+++ b/doc/user/application_security/dast/index.md
@@ -1017,12 +1017,7 @@ The on-demand DAST scan runs, and the project's dashboard shows the results.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/328749) in GitLab 14.3. [Deployed behind the `dast_on_demand_scans_scheduler` flag](../../../administration/feature_flags.md), disabled by default.
> - [Enabled on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/issues/328749) in GitLab 14.4.
> - [Enabled on self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/328749) in GitLab 14.4.
-
-FLAG:
-On self-managed GitLab, by default this feature is available. To hide the feature, ask an
-administrator to [disable the feature flag](../../../administration/feature_flags.md) named
-`dast_on_demand_scans_scheduler`.
-On GitLab.com, this feature is available.
+> - [Feature flag dast_on_demand_scans_scheduler removed](https://gitlab.com/gitlab-org/gitlab/-/issues/328749) in GitLab 14.5.
To schedule a scan:
diff --git a/doc/user/group/insights/index.md b/doc/user/group/insights/index.md
index 9f841691eb8..b3fdeb0ab41 100644
--- a/doc/user/group/insights/index.md
+++ b/doc/user/group/insights/index.md
@@ -7,7 +7,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Insights **(ULTIMATE)**
-> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/725) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 12.0.
+> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/725) in GitLab 12.0.
Configure the Insights that matter for your groups. Explore data such as
triage hygiene, issues created or closed for a given period, average time for merge
diff --git a/doc/user/group/value_stream_analytics/index.md b/doc/user/group/value_stream_analytics/index.md
index 69b3649d713..15d0eb4787b 100644
--- a/doc/user/group/value_stream_analytics/index.md
+++ b/doc/user/group/value_stream_analytics/index.md
@@ -7,7 +7,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Value Stream Analytics **(PREMIUM)**
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/196455) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.9 for groups.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/196455) in GitLab 12.9 for groups.
Value Stream Analytics measures the time spent to go from an
[idea to production](https://about.gitlab.com/blog/2016/08/05/continuous-integration-delivery-and-deployment-with-gitlab/#from-idea-to-production-with-gitlab)
@@ -99,8 +99,8 @@ sole discretion of GitLab Inc.
## How metrics are measured
-> DORA API-based deployment metrics [moved](https://gitlab.com/gitlab-org/gitlab/-/issues/337256)
-> to Premium in GitLab 14.3 for group-level Value Stream Analytics.
+> DORA API-based deployment metrics for group-level Value Stream Analytics were
+> [moved](https://gitlab.com/gitlab-org/gitlab/-/issues/337256) from GitLab Ultimate to GitLab Premium in 14.3.
The "Time" metrics near the top of the page are measured as follows:
@@ -109,10 +109,9 @@ The "Time" metrics near the top of the page are measured as follows:
issue by [crosslinking in the commit message](../../project/issues/crosslinking_issues.md#from-commit-messages).)
- **Lead Time for Changes**: median time between when a merge request is merged and deployed to a
production environment for all merge requests deployed in the given time period.
-[Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/340150) in GitLab 14.5 (**Ultimate**
-tier only).
+[Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/340150) in GitLab 14.5.
-- **Lead Time for Changes**: median duration between merge request merge and deployment to a production environment for all MRs deployed in the given time period. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/340150) in GitLab 14.5 (**Ultimate** tier only).
+- **Lead Time for Changes**: median duration between merge request merge and deployment to a production environment for all MRs deployed in the given time period. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/340150) in GitLab 14.5.
The "Recent Activity" metrics near the top of the page are measured as follows:
@@ -417,8 +416,8 @@ To delete a custom value stream:
## Days to completion chart
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/21631) in GitLab 12.6.
-> - [Chart median line removed](https://gitlab.com/gitlab-org/gitlab/-/issues/235455) in GitLab 13.4.
-> - [Totals replaced with averages](https://gitlab.com/gitlab-org/gitlab/-/issues/262070) in GitLab 13.12.
+> - Chart median line [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/235455) in GitLab 13.4.
+> - Totals [replaced](https://gitlab.com/gitlab-org/gitlab/-/issues/262070) with averages in GitLab 13.12.
This chart visually depicts the average number of days it takes for cycles to be completed.
@@ -430,7 +429,7 @@ The chart data is limited to the last 500 items.
## Type of work - Tasks by type chart
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/32421) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.10.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/32421) in GitLab 12.10.
This chart shows a cumulative count of issues and merge requests per day.
diff --git a/doc/user/search/index.md b/doc/user/search/index.md
index a0ce026f79c..325e5386417 100644
--- a/doc/user/search/index.md
+++ b/doc/user/search/index.md
@@ -321,9 +321,10 @@ GitLab instance.
## Search settings
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/292941) in GitLab 13.8 behind a feature flag, disabled by default.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/292941) in GitLab 13.8 [with a flag](../../administration/feature_flags.md) named `search_settings_in_page`. Disabled by default.
> - [Added to Group, Administrator, and User settings](https://gitlab.com/groups/gitlab-org/-/epics/4842) in GitLab 13.9.
-> - [Enabled by default](https://gitlab.com/gitlab-org/gitlab/-/issues/294025) in GitLab 13.11.
+> - [Feature flag `search_settings_in_page` removed](https://gitlab.com/gitlab-org/gitlab/-/issues/294025) in GitLab 13.11.
+> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/294025) in GitLab 13.11.
You can search inside a Project, Group, Administrator, or User's settings by entering
a search term in the search box located at the top of the page. The search results
diff --git a/lib/api/boards.rb b/lib/api/boards.rb
index 9e829dd5e05..56633c07774 100644
--- a/lib/api/boards.rb
+++ b/lib/api/boards.rb
@@ -7,7 +7,7 @@ module API
prepend_mod_with('API::BoardsResponses') # rubocop: disable Cop/InjectEnterpriseEditionModule
- feature_category :boards
+ feature_category :team_planning
before { authenticate! }
diff --git a/lib/api/group_boards.rb b/lib/api/group_boards.rb
index 92869f8fbba..e9350da555c 100644
--- a/lib/api/group_boards.rb
+++ b/lib/api/group_boards.rb
@@ -7,7 +7,7 @@ module API
prepend_mod_with('API::BoardsResponses') # rubocop: disable Cop/InjectEnterpriseEditionModule
- feature_category :boards
+ feature_category :team_planning
before { authenticate! }
diff --git a/lib/api/group_labels.rb b/lib/api/group_labels.rb
index bea538441ee..7c1f23be828 100644
--- a/lib/api/group_labels.rb
+++ b/lib/api/group_labels.rb
@@ -7,7 +7,7 @@ module API
before { authenticate! }
- feature_category :issue_tracking
+ feature_category :team_planning
params do
requires :id, type: String, desc: 'The ID of a group'
diff --git a/lib/api/group_milestones.rb b/lib/api/group_milestones.rb
index 061d0410a9c..b097022e9c1 100644
--- a/lib/api/group_milestones.rb
+++ b/lib/api/group_milestones.rb
@@ -7,7 +7,7 @@ module API
before { authenticate! }
- feature_category :issue_tracking
+ feature_category :team_planning
params do
requires :id, type: String, desc: 'The ID of a group'
diff --git a/lib/api/helpers/award_emoji.rb b/lib/api/helpers/award_emoji.rb
index 5b659c4dde7..3ea35381c97 100644
--- a/lib/api/helpers/award_emoji.rb
+++ b/lib/api/helpers/award_emoji.rb
@@ -5,7 +5,7 @@ module API
module AwardEmoji
def self.awardables
[
- { type: 'issue', resource: :projects, find_by: :iid, feature_category: :issue_tracking },
+ { type: 'issue', resource: :projects, find_by: :iid, feature_category: :team_planning },
{ type: 'merge_request', resource: :projects, find_by: :iid, feature_category: :code_review },
{ type: 'snippet', resource: :projects, find_by: :id, feature_category: :snippets }
]
diff --git a/lib/api/helpers/discussions_helpers.rb b/lib/api/helpers/discussions_helpers.rb
index cb2feeda1e1..c94199b17bc 100644
--- a/lib/api/helpers/discussions_helpers.rb
+++ b/lib/api/helpers/discussions_helpers.rb
@@ -7,7 +7,7 @@ module API
# This is a method instead of a constant, allowing EE to more easily
# extend it.
{
- Issue => :issue_tracking,
+ Issue => :team_planning,
Snippet => :snippets,
MergeRequest => :code_review,
Commit => :code_review
diff --git a/lib/api/helpers/notes_helpers.rb b/lib/api/helpers/notes_helpers.rb
index 356e4a98c97..45671b09be9 100644
--- a/lib/api/helpers/notes_helpers.rb
+++ b/lib/api/helpers/notes_helpers.rb
@@ -7,7 +7,7 @@ module API
def self.feature_category_per_noteable_type
{
- Issue => :issue_tracking,
+ Issue => :team_planning,
MergeRequest => :code_review,
Snippet => :snippets
}
diff --git a/lib/api/helpers/resource_label_events_helpers.rb b/lib/api/helpers/resource_label_events_helpers.rb
index 7e641130062..eeb68362c1d 100644
--- a/lib/api/helpers/resource_label_events_helpers.rb
+++ b/lib/api/helpers/resource_label_events_helpers.rb
@@ -7,7 +7,7 @@ module API
# This is a method instead of a constant, allowing EE to more easily
# extend it.
{
- Issue => :issue_tracking,
+ Issue => :team_planning,
MergeRequest => :code_review
}
end
diff --git a/lib/api/issue_links.rb b/lib/api/issue_links.rb
index 0b4f4e06d0b..98451afb12d 100644
--- a/lib/api/issue_links.rb
+++ b/lib/api/issue_links.rb
@@ -6,7 +6,7 @@ module API
before { authenticate! }
- feature_category :issue_tracking
+ feature_category :team_planning
params do
requires :id, type: String, desc: 'The ID of a project'
diff --git a/lib/api/issues.rb b/lib/api/issues.rb
index 43e83bd58fe..9958526fa7f 100644
--- a/lib/api/issues.rb
+++ b/lib/api/issues.rb
@@ -7,7 +7,7 @@ module API
before { authenticate_non_get! }
- feature_category :issue_tracking
+ feature_category :team_planning
helpers do
params :negatable_issue_filter_params do
diff --git a/lib/api/labels.rb b/lib/api/labels.rb
index aa3746dae42..e3253d15c15 100644
--- a/lib/api/labels.rb
+++ b/lib/api/labels.rb
@@ -7,7 +7,7 @@ module API
before { authenticate! }
- feature_category :issue_tracking
+ feature_category :team_planning
LABEL_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS.merge(
name: API::NO_SLASH_URL_PART_REGEX,
diff --git a/lib/api/project_milestones.rb b/lib/api/project_milestones.rb
index 107311ea446..435e4bed776 100644
--- a/lib/api/project_milestones.rb
+++ b/lib/api/project_milestones.rb
@@ -7,7 +7,7 @@ module API
before { authenticate! }
- feature_category :issue_tracking
+ feature_category :team_planning
params do
requires :id, type: String, desc: 'The ID of a project'
diff --git a/lib/api/releases.rb b/lib/api/releases.rb
index 3b7e2b4bd27..7b89a177fd9 100644
--- a/lib/api/releases.rb
+++ b/lib/api/releases.rb
@@ -32,6 +32,7 @@ module API
optional :include_html_description, type: Boolean,
desc: 'If `true`, a response includes HTML rendered markdown of the release description.'
end
+ route_setting :authentication, job_token_allowed: true
get ':id/releases' do
releases = ::ReleasesFinder.new(user_project, current_user, declared_params.slice(:order_by, :sort)).execute
@@ -59,6 +60,7 @@ module API
optional :include_html_description, type: Boolean,
desc: 'If `true`, a response includes HTML rendered markdown of the release description.'
end
+ route_setting :authentication, job_token_allowed: true
get ':id/releases/:tag_name', requirements: RELEASE_ENDPOINT_REQUIREMENTS do
authorize_download_code!
@@ -117,6 +119,7 @@ module API
optional :released_at, type: DateTime, desc: 'The date when the release will be/was ready.'
optional :milestones, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, desc: 'The titles of the related milestones'
end
+ route_setting :authentication, job_token_allowed: true
put ':id/releases/:tag_name', requirements: RELEASE_ENDPOINT_REQUIREMENTS do
authorize_update_release!
@@ -142,6 +145,7 @@ module API
params do
requires :tag_name, type: String, desc: 'The name of the tag', as: :tag
end
+ route_setting :authentication, job_token_allowed: true
delete ':id/releases/:tag_name', requirements: RELEASE_ENDPOINT_REQUIREMENTS do
authorize_destroy_release!
diff --git a/lib/api/resource_milestone_events.rb b/lib/api/resource_milestone_events.rb
index aeedd7ad109..c0483ca59c2 100644
--- a/lib/api/resource_milestone_events.rb
+++ b/lib/api/resource_milestone_events.rb
@@ -8,7 +8,7 @@ module API
before { authenticate! }
{
- Issue => :issue_tracking,
+ Issue => :team_planning,
MergeRequest => :code_review
}.each do |eventable_type, feature_category|
parent_type = eventable_type.parent_class.to_s.underscore
diff --git a/lib/api/resource_state_events.rb b/lib/api/resource_state_events.rb
index 3460aa2c00e..9b6f6a954b4 100644
--- a/lib/api/resource_state_events.rb
+++ b/lib/api/resource_state_events.rb
@@ -8,7 +8,7 @@ module API
before { authenticate! }
{
- Issue => :issue_tracking,
+ Issue => :team_planning,
MergeRequest => :code_review
}.each do |eventable_class, feature_category|
eventable_name = eventable_class.to_s.underscore
diff --git a/lib/api/subscriptions.rb b/lib/api/subscriptions.rb
index 87dc1358a51..cda30dc957f 100644
--- a/lib/api/subscriptions.rb
+++ b/lib/api/subscriptions.rb
@@ -22,21 +22,21 @@ module API
entity: Entities::Issue,
source: Project,
finder: ->(id) { find_project_issue(id) },
- feature_category: :issue_tracking
+ feature_category: :team_planning
},
{
type: 'labels',
entity: Entities::ProjectLabel,
source: Project,
finder: ->(id) { find_label(user_project, id) },
- feature_category: :issue_tracking
+ feature_category: :team_planning
},
{
type: 'labels',
entity: Entities::GroupLabel,
source: Group,
finder: ->(id) { find_label(user_group, id) },
- feature_category: :issue_tracking
+ feature_category: :team_planning
}
]
diff --git a/lib/api/todos.rb b/lib/api/todos.rb
index e0e5ca615ac..57a6ee0bebb 100644
--- a/lib/api/todos.rb
+++ b/lib/api/todos.rb
@@ -6,7 +6,7 @@ module API
before { authenticate! }
- feature_category :issue_tracking
+ feature_category :team_planning
ISSUABLE_TYPES = {
'merge_requests' => ->(iid) { find_merge_request_with_access(iid) },
diff --git a/lib/gitlab/database/gitlab_schema.rb b/lib/gitlab/database/gitlab_schema.rb
new file mode 100644
index 00000000000..9490fee1ae4
--- /dev/null
+++ b/lib/gitlab/database/gitlab_schema.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+# This module gathers information about table to schema mapping
+# to understand table affinity
+module Gitlab
+ module Database
+ module GitlabSchema
+ def self.table_schemas(tables)
+ tables.map { |table| table_schema(table) }.to_set
+ end
+
+ def self.table_schema(name)
+ # When undefined it's best to return a unique name so that we don't incorrectly assume that 2 undefined schemas belong on the same database
+ tables_to_schema[name] || :"undefined_#{name}"
+ end
+
+ def self.tables_to_schema
+ @tables_to_schema ||= YAML.load_file(Rails.root.join('lib/gitlab/database/gitlab_schemas.yml'))
+ end
+ end
+ end
+end
diff --git a/spec/support/database/gitlab_schemas.yml b/lib/gitlab/database/gitlab_schemas.yml
similarity index 100%
rename from spec/support/database/gitlab_schemas.yml
rename to lib/gitlab/database/gitlab_schemas.yml
diff --git a/lib/gitlab/database/load_balancing/configuration.rb b/lib/gitlab/database/load_balancing/configuration.rb
index 6156515bd73..7814083a527 100644
--- a/lib/gitlab/database/load_balancing/configuration.rb
+++ b/lib/gitlab/database/load_balancing/configuration.rb
@@ -7,7 +7,7 @@ module Gitlab
class Configuration
attr_accessor :hosts, :max_replication_difference,
:max_replication_lag_time, :replica_check_interval,
- :service_discovery, :model
+ :service_discovery
# Creates a configuration object for the given ActiveRecord model.
def self.for_model(model)
@@ -41,6 +41,8 @@ module Gitlab
end
end
+ config.reuse_primary_connection!
+
config
end
@@ -59,6 +61,24 @@ module Gitlab
disconnect_timeout: 120,
use_tcp: false
}
+
+ # Temporary model for GITLAB_LOAD_BALANCING_REUSE_PRIMARY_
+ # To be removed with FF
+ @primary_model = nil
+ end
+
+ def db_config_name
+ @model.connection_db_config.name.to_sym
+ end
+
+ # With connection re-use the primary connection can be overwritten
+ # to be used from different model
+ def primary_connection_specification_name
+ (@primary_model || @model).connection_specification_name
+ end
+
+ def replica_db_config
+ @model.connection_db_config
end
def pool_size
@@ -86,6 +106,30 @@ module Gitlab
def service_discovery_enabled?
service_discovery[:record].present?
end
+
+ # TODO: This is temporary code to allow re-use of primary connection
+ # if the two connections are pointing to the same host. This is needed
+ # to properly support transaction visibility.
+ #
+ # This behavior is required to support [Phase 3](https://gitlab.com/groups/gitlab-org/-/epics/6160#progress).
+ # This method is meant to be removed as soon as it is finished.
+ #
+ # The remapping is done as-is:
+ # export GITLAB_LOAD_BALANCING_REUSE_PRIMARY_=
+ #
+ # Ex.:
+ # export GITLAB_LOAD_BALANCING_REUSE_PRIMARY_ci=main
+ #
+ def reuse_primary_connection!
+ new_connection = ENV["GITLAB_LOAD_BALANCING_REUSE_PRIMARY_#{db_config_name}"]
+ return unless new_connection.present?
+
+ @primary_model = Gitlab::Database.database_base_models[new_connection.to_sym]
+
+ unless @primary_model
+ raise "Invalid value for 'GITLAB_LOAD_BALANCING_REUSE_PRIMARY_#{db_config_name}=#{new_connection}'"
+ end
+ end
end
end
end
diff --git a/lib/gitlab/database/load_balancing/load_balancer.rb b/lib/gitlab/database/load_balancing/load_balancer.rb
index aee9acf3e9b..dc6678dc93b 100644
--- a/lib/gitlab/database/load_balancing/load_balancer.rb
+++ b/lib/gitlab/database/load_balancing/load_balancer.rb
@@ -12,7 +12,7 @@ module Gitlab
REPLICA_SUFFIX = '_replica'
- attr_reader :name, :host_list, :configuration
+ attr_reader :host_list, :configuration
# configuration - An instance of `LoadBalancing::Configuration` that
# contains the configuration details (such as the hosts)
@@ -26,8 +26,10 @@ module Gitlab
else
HostList.new(configuration.hosts.map { |addr| Host.new(addr, self) })
end
+ end
- @name = @configuration.model.connection_db_config.name.to_sym
+ def name
+ @configuration.db_config_name
end
def primary_only?
@@ -227,7 +229,7 @@ module Gitlab
# host - An optional host name to use instead of the default one.
# port - An optional port to connect to.
def create_replica_connection_pool(pool_size, host = nil, port = nil)
- db_config = pool.db_config
+ db_config = @configuration.replica_db_config
env_config = db_config.configuration_hash.dup
env_config[:pool] = pool_size
@@ -252,7 +254,7 @@ module Gitlab
# leverage that.
def pool
ActiveRecord::Base.connection_handler.retrieve_connection_pool(
- @configuration.model.connection_specification_name,
+ @configuration.primary_connection_specification_name,
role: ActiveRecord::Base.writing_role,
shard: ActiveRecord::Base.default_shard
) || raise(::ActiveRecord::ConnectionNotEstablished)
diff --git a/lib/gitlab/database/load_balancing/rack_middleware.rb b/lib/gitlab/database/load_balancing/rack_middleware.rb
index 7ce7649cc22..99b1c31b04b 100644
--- a/lib/gitlab/database/load_balancing/rack_middleware.rb
+++ b/lib/gitlab/database/load_balancing/rack_middleware.rb
@@ -38,8 +38,8 @@ module Gitlab
def unstick_or_continue_sticking(env)
namespaces_and_ids = sticking_namespaces(env)
- namespaces_and_ids.each do |(model, namespace, id)|
- model.sticking.unstick_or_continue_sticking(namespace, id)
+ namespaces_and_ids.each do |(sticking, namespace, id)|
+ sticking.unstick_or_continue_sticking(namespace, id)
end
end
@@ -47,8 +47,8 @@ module Gitlab
def stick_if_necessary(env)
namespaces_and_ids = sticking_namespaces(env)
- namespaces_and_ids.each do |model, namespace, id|
- model.sticking.stick_if_necessary(namespace, id)
+ namespaces_and_ids.each do |sticking, namespace, id|
+ sticking.stick_if_necessary(namespace, id)
end
end
@@ -74,7 +74,7 @@ module Gitlab
# models that support load balancing. In the future (if we
# determined this to be OK) we may be able to relax this.
::Gitlab::Database::LoadBalancing.base_models.map do |model|
- [model, :user, warden.user.id]
+ [model.sticking, :user, warden.user.id]
end
elsif env[STICK_OBJECT].present?
env[STICK_OBJECT].to_a
diff --git a/lib/gitlab/database/load_balancing/sticking.rb b/lib/gitlab/database/load_balancing/sticking.rb
index df4ad18581f..64c0ad3a858 100644
--- a/lib/gitlab/database/load_balancing/sticking.rb
+++ b/lib/gitlab/database/load_balancing/sticking.rb
@@ -12,7 +12,6 @@ module Gitlab
def initialize(load_balancer)
@load_balancer = load_balancer
- @model = load_balancer.configuration.model
end
# Unsticks or continues sticking the current request.
@@ -28,7 +27,7 @@ module Gitlab
unstick_or_continue_sticking(namespace, id)
env[RackMiddleware::STICK_OBJECT] ||= Set.new
- env[RackMiddleware::STICK_OBJECT] << [@model, namespace, id]
+ env[RackMiddleware::STICK_OBJECT] << [self, namespace, id]
end
# Sticks to the primary if a write was performed.
diff --git a/lib/gitlab/database/partitioning.rb b/lib/gitlab/database/partitioning.rb
index c517cf94c6e..bcefb27b62b 100644
--- a/lib/gitlab/database/partitioning.rb
+++ b/lib/gitlab/database/partitioning.rb
@@ -3,40 +3,73 @@
module Gitlab
module Database
module Partitioning
- def self.register_models(models)
- registered_models.merge(models)
- end
+ class TableWithoutModel
+ include PartitionedTable::ClassMethods
- def self.registered_models
- @registered_models ||= Set.new
- end
+ attr_reader :table_name
- def self.sync_partitions(models_to_sync = registered_models)
- Gitlab::AppLogger.info(message: 'Syncing dynamic postgres partitions')
-
- Gitlab::Database::EachDatabase.each_model_connection(models_to_sync) do |model|
- PartitionManager.new(model).sync_partitions
+ def initialize(table_name:, partitioned_column:, strategy:)
+ @table_name = table_name
+ partitioned_by(partitioned_column, strategy: strategy)
end
- Gitlab::AppLogger.info(message: 'Finished sync of dynamic postgres partitions')
- end
-
- def self.report_metrics(models_to_monitor = registered_models)
- partition_monitoring = PartitionMonitoring.new
-
- Gitlab::Database::EachDatabase.each_model_connection(models_to_monitor) do |model|
- partition_monitoring.report_metrics_for_model(model)
+ def connection
+ Gitlab::Database::SharedModel.connection
end
end
- def self.drop_detached_partitions
- Gitlab::AppLogger.info(message: 'Dropping detached postgres partitions')
-
- Gitlab::Database::EachDatabase.each_database_connection do
- DetachedPartitionDropper.new.perform
+ class << self
+ def register_models(models)
+ registered_models.merge(models)
end
- Gitlab::AppLogger.info(message: 'Finished dropping detached postgres partitions')
+ def register_tables(tables)
+ registered_tables.merge(tables)
+ end
+
+ def sync_partitions(models_to_sync = registered_for_sync)
+ Gitlab::AppLogger.info(message: 'Syncing dynamic postgres partitions')
+
+ Gitlab::Database::EachDatabase.each_model_connection(models_to_sync) do |model|
+ PartitionManager.new(model).sync_partitions
+ end
+
+ Gitlab::AppLogger.info(message: 'Finished sync of dynamic postgres partitions')
+ end
+
+ def report_metrics(models_to_monitor = registered_models)
+ partition_monitoring = PartitionMonitoring.new
+
+ Gitlab::Database::EachDatabase.each_model_connection(models_to_monitor) do |model|
+ partition_monitoring.report_metrics_for_model(model)
+ end
+ end
+
+ def drop_detached_partitions
+ Gitlab::AppLogger.info(message: 'Dropping detached postgres partitions')
+
+ Gitlab::Database::EachDatabase.each_database_connection do
+ DetachedPartitionDropper.new.perform
+ end
+
+ Gitlab::AppLogger.info(message: 'Finished dropping detached postgres partitions')
+ end
+
+ private
+
+ def registered_models
+ @registered_models ||= Set.new
+ end
+
+ def registered_tables
+ @registered_tables ||= Set.new
+ end
+
+ def registered_for_sync
+ registered_models + registered_tables.map do |table|
+ TableWithoutModel.new(**table)
+ end
+ end
end
end
end
diff --git a/lib/gitlab/etag_caching/router/restful.rb b/lib/gitlab/etag_caching/router/restful.rb
index 408a901f69d..176676bd6ba 100644
--- a/lib/gitlab/etag_caching/router/restful.rb
+++ b/lib/gitlab/etag_caching/router/restful.rb
@@ -23,7 +23,7 @@ module Gitlab
[
%r(#{RESERVED_WORDS_PREFIX}/noteable/issue/\d+/notes\z),
'issue_notes',
- 'issue_tracking'
+ 'team_planning'
],
[
%r(#{RESERVED_WORDS_PREFIX}/noteable/merge_request/\d+/notes\z),
@@ -33,7 +33,7 @@ module Gitlab
[
%r(#{RESERVED_WORDS_PREFIX}/issues/\d+/realtime_changes\z),
'issue_title',
- 'issue_tracking'
+ 'team_planning'
],
[
%r(#{RESERVED_WORDS_PREFIX}/commit/\S+/pipelines\.json\z),
diff --git a/lib/gitlab/sidekiq_logging/json_formatter.rb b/lib/gitlab/sidekiq_logging/json_formatter.rb
index 8894b48417c..d22f0851927 100644
--- a/lib/gitlab/sidekiq_logging/json_formatter.rb
+++ b/lib/gitlab/sidekiq_logging/json_formatter.rb
@@ -2,6 +2,7 @@
# This is needed for sidekiq-cluster
require 'json'
+require 'sidekiq/job_retry'
module Gitlab
module SidekiqLogging
diff --git a/lib/gitlab/sidekiq_logging/structured_logger.rb b/lib/gitlab/sidekiq_logging/structured_logger.rb
index 3438bc0f3ef..a9bfcce2e0a 100644
--- a/lib/gitlab/sidekiq_logging/structured_logger.rb
+++ b/lib/gitlab/sidekiq_logging/structured_logger.rb
@@ -2,6 +2,8 @@
require 'active_record'
require 'active_record/log_subscriber'
+require 'sidekiq/job_logger'
+require 'sidekiq/job_retry'
module Gitlab
module SidekiqLogging
diff --git a/lib/gitlab/sidekiq_middleware/monitor.rb b/lib/gitlab/sidekiq_middleware/monitor.rb
index ed825dbfd60..d38fed3b768 100644
--- a/lib/gitlab/sidekiq_middleware/monitor.rb
+++ b/lib/gitlab/sidekiq_middleware/monitor.rb
@@ -1,5 +1,7 @@
# frozen_string_literal: true
+require 'sidekiq/job_retry'
+
module Gitlab
module SidekiqMiddleware
class Monitor
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 969b585b2fb..e468b168f96 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -3610,7 +3610,7 @@ msgstr ""
msgid "An error occurred while fetching ancestors"
msgstr ""
-msgid "An error occurred while fetching branches. Retry the search."
+msgid "An error occurred while fetching branches. Retry the search."
msgstr ""
msgid "An error occurred while fetching codequality mr diff reports."
@@ -3619,7 +3619,7 @@ msgstr ""
msgid "An error occurred while fetching commit data."
msgstr ""
-msgid "An error occurred while fetching commits. Retry the search."
+msgid "An error occurred while fetching commits. Retry the search."
msgstr ""
msgid "An error occurred while fetching coverage reports."
@@ -5672,7 +5672,7 @@ msgstr ""
msgid "Branches|Cancel, keep branch"
msgstr ""
-msgid "Branches|Cant find HEAD commit for this branch"
+msgid "Branches|Can’t find HEAD commit for this branch"
msgstr ""
msgid "Branches|Compare"
@@ -7511,7 +7511,7 @@ msgstr ""
msgid "ClusterIntegration|Check your token"
msgstr ""
-msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Choose the %{linkStart}security group%{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
msgstr ""
msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
@@ -15695,10 +15695,10 @@ msgstr ""
msgid "GitLabPages|Something went wrong while obtaining the Let's Encrypt certificate for %{domain}. To retry visit your %{link_start}domain details%{link_end}."
msgstr ""
-msgid "GitLabPages|Support for domains and certificates is disabled. Ask your system's administrator to enable it."
+msgid "GitLabPages|Support for domains and certificates is disabled. Ask your system's administrator to enable it."
msgstr ""
-msgid "GitLabPages|The total size of deployed static content will be limited to this size. 0 for unlimited. Leave empty to inherit the global value."
+msgid "GitLabPages|The total size of deployed static content will be limited to this size. 0 for unlimited. Leave empty to inherit the global value."
msgstr ""
msgid "GitLabPages|Unverified"
@@ -21051,9 +21051,6 @@ msgstr ""
msgid "Max session time"
msgstr ""
-msgid "MaxBuilds"
-msgstr ""
-
msgid "Maximum 20 characters"
msgstr ""
@@ -34921,7 +34918,7 @@ msgstr ""
msgid "This group, its subgroups and projects has been scheduled for removal on %{date}."
msgstr ""
-msgid "This group, its subgroups and projects will be removed on %{date} since its parent group '%{parent_group_name}'' has been scheduled for removal."
+msgid "This group, its subgroups and projects will be removed on %{date} since its parent group '%{parent_group_name}' has been scheduled for removal."
msgstr ""
msgid "This invitation was sent to %{mail_to_invite_email}, but you are signed in as %{link_to_current_user} with email %{mail_to_current_user}."
@@ -38517,9 +38514,6 @@ msgstr[1] ""
msgid "When using the %{code_open}http://%{code_close} or %{code_open}https://%{code_close} protocols, please provide the exact URL to the repository. HTTP redirects will not be followed."
msgstr ""
-msgid "When using the %{code_open}http://%{code_close} or %{code_open}https://%{code_close} protocols, provide the exact URL to the repository. HTTP redirects will not be followed."
-msgstr ""
-
msgid "When:"
msgstr ""
diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb
index c4f93de5c23..e623c1ab940 100644
--- a/spec/controllers/application_controller_spec.rb
+++ b/spec/controllers/application_controller_spec.rb
@@ -923,7 +923,7 @@ RSpec.describe ApplicationController do
describe '#set_current_context' do
controller(described_class) do
- feature_category :issue_tracking
+ feature_category :team_planning
def index
Gitlab::ApplicationContext.with_raw_context do |context|
@@ -977,7 +977,7 @@ RSpec.describe ApplicationController do
it 'sets the feature_category as defined in the controller' do
get :index, format: :json
- expect(json_response['meta.feature_category']).to eq('issue_tracking')
+ expect(json_response['meta.feature_category']).to eq('team_planning')
end
it 'assigns the context to a variable for logging' do
diff --git a/spec/support_specs/database/gitlab_schema_spec.rb b/spec/lib/gitlab/database/gitlab_schema_spec.rb
similarity index 96%
rename from spec/support_specs/database/gitlab_schema_spec.rb
rename to spec/lib/gitlab/database/gitlab_schema_spec.rb
index 693071bfd60..02a9f6eef7b 100644
--- a/spec/support_specs/database/gitlab_schema_spec.rb
+++ b/spec/lib/gitlab/database/gitlab_schema_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Database::GitlabSchema do
+RSpec.describe Gitlab::Database::GitlabSchema do
it 'matches all the tables in the database', :aggregate_failures do
# These tables do not need a gitlab_schema
excluded_tables = %w(ar_internal_metadata schema_migrations)
diff --git a/spec/lib/gitlab/database/load_balancing/configuration_spec.rb b/spec/lib/gitlab/database/load_balancing/configuration_spec.rb
index 3e5249a3dea..435da8b6ae2 100644
--- a/spec/lib/gitlab/database/load_balancing/configuration_spec.rb
+++ b/spec/lib/gitlab/database/load_balancing/configuration_spec.rb
@@ -3,17 +3,12 @@
require 'spec_helper'
RSpec.describe Gitlab::Database::LoadBalancing::Configuration do
- let(:model) do
- config = ActiveRecord::DatabaseConfigurations::HashConfig
- .new('main', 'test', configuration_hash)
-
- double(:model, connection_db_config: config)
- end
+ let(:configuration_hash) { {} }
+ let(:db_config) { ActiveRecord::DatabaseConfigurations::HashConfig.new('test', 'ci', configuration_hash) }
+ let(:model) { double(:model, connection_db_config: db_config) }
describe '.for_model' do
context 'when load balancing is not configured' do
- let(:configuration_hash) { {} }
-
it 'uses the default settings' do
config = described_class.for_model(model)
@@ -105,6 +100,14 @@ RSpec.describe Gitlab::Database::LoadBalancing::Configuration do
expect(config.pool_size).to eq(4)
end
end
+
+ it 'calls reuse_primary_connection!' do
+ expect_next_instance_of(described_class) do |subject|
+ expect(subject).to receive(:reuse_primary_connection!).and_call_original
+ end
+
+ described_class.for_model(model)
+ end
end
describe '#load_balancing_enabled?' do
@@ -180,4 +183,58 @@ RSpec.describe Gitlab::Database::LoadBalancing::Configuration do
end
end
end
+
+ describe '#db_config_name' do
+ let(:config) { described_class.new(model) }
+
+ subject { config.db_config_name }
+
+ it 'returns connection name as symbol' do
+ is_expected.to eq(:ci)
+ end
+ end
+
+ describe '#replica_db_config' do
+ let(:model) { double(:model, connection_db_config: db_config, connection_specification_name: 'Ci::CiDatabaseRecord') }
+ let(:config) { described_class.for_model(model) }
+
+ it 'returns exactly db_config' do
+ expect(config.replica_db_config).to eq(db_config)
+ end
+
+ context 'when GITLAB_LOAD_BALANCING_REUSE_PRIMARY_ci=main' do
+ it 'does not change replica_db_config' do
+ stub_env('GITLAB_LOAD_BALANCING_REUSE_PRIMARY_ci', 'main')
+
+ expect(config.replica_db_config).to eq(db_config)
+ end
+ end
+ end
+
+ describe 'reuse_primary_connection!' do
+ let(:model) { double(:model, connection_db_config: db_config, connection_specification_name: 'Ci::CiDatabaseRecord') }
+ let(:config) { described_class.for_model(model) }
+
+ context 'when GITLAB_LOAD_BALANCING_REUSE_PRIMARY_* not configured' do
+ it 'the primary connection uses default specification' do
+ expect(config.primary_connection_specification_name).to eq('Ci::CiDatabaseRecord')
+ end
+ end
+
+ context 'when GITLAB_LOAD_BALANCING_REUSE_PRIMARY_ci=main' do
+ it 'the primary connection uses main connection' do
+ stub_env('GITLAB_LOAD_BALANCING_REUSE_PRIMARY_ci', 'main')
+
+ expect(config.primary_connection_specification_name).to eq('ActiveRecord::Base')
+ end
+ end
+
+ context 'when GITLAB_LOAD_BALANCING_REUSE_PRIMARY_ci=unknown' do
+ it 'raises exception' do
+ stub_env('GITLAB_LOAD_BALANCING_REUSE_PRIMARY_ci', 'unknown')
+
+ expect { config.reuse_primary_connection! }.to raise_error /Invalid value for/
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/database/load_balancing/load_balancer_spec.rb b/spec/lib/gitlab/database/load_balancing/load_balancer_spec.rb
index 78d75d69e15..269a1f872dc 100644
--- a/spec/lib/gitlab/database/load_balancing/load_balancer_spec.rb
+++ b/spec/lib/gitlab/database/load_balancing/load_balancer_spec.rb
@@ -4,10 +4,11 @@ require 'spec_helper'
RSpec.describe Gitlab::Database::LoadBalancing::LoadBalancer, :request_store do
let(:conflict_error) { Class.new(RuntimeError) }
- let(:db_host) { ActiveRecord::Base.connection_pool.db_config.host }
+ let(:model) { ActiveRecord::Base }
+ let(:db_host) { model.connection_pool.db_config.host }
let(:config) do
Gitlab::Database::LoadBalancing::Configuration
- .new(ActiveRecord::Base, [db_host, db_host])
+ .new(model, [db_host, db_host])
end
let(:lb) { described_class.new(config) }
@@ -452,4 +453,51 @@ RSpec.describe Gitlab::Database::LoadBalancing::LoadBalancer, :request_store do
expect(lb.send(:get_write_location, double(select_all: []))).to be_nil
end
end
+
+ describe 'primary connection re-use', :reestablished_active_record_base do
+ let(:model) { Ci::CiDatabaseRecord }
+
+ before do
+ # fake additional Database
+ model.establish_connection(
+ ActiveRecord::DatabaseConfigurations::HashConfig.new(Rails.env, 'ci', ActiveRecord::Base.connection_db_config.configuration_hash)
+ )
+ end
+
+ describe '#read' do
+ it 'returns ci replica connection' do
+ expect { |b| lb.read(&b) }.to yield_with_args do |args|
+ expect(args.pool.db_config.name).to eq('ci_replica')
+ end
+ end
+
+ context 'when GITLAB_LOAD_BALANCING_REUSE_PRIMARY_ci=main' do
+ it 'returns ci replica connection' do
+ stub_env('GITLAB_LOAD_BALANCING_REUSE_PRIMARY_ci', 'main')
+
+ expect { |b| lb.read(&b) }.to yield_with_args do |args|
+ expect(args.pool.db_config.name).to eq('ci_replica')
+ end
+ end
+ end
+ end
+
+ describe '#read_write' do
+ it 'returns Ci::CiDatabaseRecord connection' do
+ expect { |b| lb.read_write(&b) }.to yield_with_args do |args|
+ expect(args.pool.db_config.name).to eq('ci')
+ end
+ end
+
+ context 'when GITLAB_LOAD_BALANCING_REUSE_PRIMARY_ci=main' do
+ it 'returns ActiveRecord::Base connection' do
+ stub_env('GITLAB_LOAD_BALANCING_REUSE_PRIMARY_ci', 'main')
+
+ expect { |b| lb.read_write(&b) }.to yield_with_args do |args|
+ expect(args.pool.db_config.name).to eq('main')
+ end
+ end
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/database/load_balancing/rack_middleware_spec.rb b/spec/lib/gitlab/database/load_balancing/rack_middleware_spec.rb
index af7e2a4b167..b768d4ecea3 100644
--- a/spec/lib/gitlab/database/load_balancing/rack_middleware_spec.rb
+++ b/spec/lib/gitlab/database/load_balancing/rack_middleware_spec.rb
@@ -6,12 +6,12 @@ RSpec.describe Gitlab::Database::LoadBalancing::RackMiddleware, :redis do
let(:app) { double(:app) }
let(:middleware) { described_class.new(app) }
let(:warden_user) { double(:warden, user: double(:user, id: 42)) }
- let(:single_sticking_object) { Set.new([[ActiveRecord::Base, :user, 42]]) }
+ let(:single_sticking_object) { Set.new([[ActiveRecord::Base.sticking, :user, 42]]) }
let(:multiple_sticking_objects) do
Set.new([
- [ActiveRecord::Base, :user, 42],
- [ActiveRecord::Base, :runner, '123456789'],
- [ActiveRecord::Base, :runner, '1234']
+ [ActiveRecord::Base.sticking, :user, 42],
+ [ActiveRecord::Base.sticking, :runner, '123456789'],
+ [ActiveRecord::Base.sticking, :runner, '1234']
])
end
@@ -162,7 +162,7 @@ RSpec.describe Gitlab::Database::LoadBalancing::RackMiddleware, :redis do
it 'returns the warden user if present' do
env = { 'warden' => warden_user }
ids = Gitlab::Database::LoadBalancing.base_models.map do |model|
- [model, :user, 42]
+ [model.sticking, :user, 42]
end
expect(middleware.sticking_namespaces(env)).to eq(ids)
@@ -181,9 +181,9 @@ RSpec.describe Gitlab::Database::LoadBalancing::RackMiddleware, :redis do
env = { described_class::STICK_OBJECT => multiple_sticking_objects }
expect(middleware.sticking_namespaces(env)).to eq([
- [ActiveRecord::Base, :user, 42],
- [ActiveRecord::Base, :runner, '123456789'],
- [ActiveRecord::Base, :runner, '1234']
+ [ActiveRecord::Base.sticking, :user, 42],
+ [ActiveRecord::Base.sticking, :runner, '123456789'],
+ [ActiveRecord::Base.sticking, :runner, '1234']
])
end
end
diff --git a/spec/lib/gitlab/database/load_balancing/sticking_spec.rb b/spec/lib/gitlab/database/load_balancing/sticking_spec.rb
index 8ceda52ee85..9d0937f004c 100644
--- a/spec/lib/gitlab/database/load_balancing/sticking_spec.rb
+++ b/spec/lib/gitlab/database/load_balancing/sticking_spec.rb
@@ -22,7 +22,7 @@ RSpec.describe Gitlab::Database::LoadBalancing::Sticking, :redis do
sticking.stick_or_unstick_request(env, :user, 42)
expect(env[Gitlab::Database::LoadBalancing::RackMiddleware::STICK_OBJECT].to_a)
- .to eq([[ActiveRecord::Base, :user, 42]])
+ .to eq([[sticking, :user, 42]])
end
it 'sticks or unsticks multiple objects and updates the Rack environment' do
@@ -42,8 +42,8 @@ RSpec.describe Gitlab::Database::LoadBalancing::Sticking, :redis do
sticking.stick_or_unstick_request(env, :runner, '123456789')
expect(env[Gitlab::Database::LoadBalancing::RackMiddleware::STICK_OBJECT].to_a).to eq([
- [ActiveRecord::Base, :user, 42],
- [ActiveRecord::Base, :runner, '123456789']
+ [sticking, :user, 42],
+ [sticking, :runner, '123456789']
])
end
end
diff --git a/spec/lib/gitlab/database/partitioning_spec.rb b/spec/lib/gitlab/database/partitioning_spec.rb
index 6841af8f69d..ca01667aed2 100644
--- a/spec/lib/gitlab/database/partitioning_spec.rb
+++ b/spec/lib/gitlab/database/partitioning_spec.rb
@@ -45,8 +45,13 @@ RSpec.describe Gitlab::Database::Partitioning do
let(:model) { double('model') }
it 'manages partitions for each registered model' do
+ registered_for_sync = described_class.__send__(:registered_for_sync)
+
+ allow(described_class).to receive(:registered_for_sync)
+ .and_return(registered_for_sync)
+
expect(Gitlab::Database::EachDatabase).to receive(:each_model_connection)
- .with(described_class.registered_models)
+ .with(registered_for_sync)
.and_yield(model)
expect(partition_manager_class).to receive(:new).with(model).and_return(partition_manager)
@@ -71,7 +76,7 @@ RSpec.describe Gitlab::Database::Partitioning do
end
expect(Gitlab::Database::EachDatabase).to receive(:each_model_connection)
- .with(described_class.registered_models)
+ .with(described_class.__send__(:registered_models))
.and_yield(model1)
.and_yield(model2)
@@ -123,7 +128,7 @@ RSpec.describe Gitlab::Database::Partitioning do
context 'ensure that the registered models have partitioning strategy' do
it 'fails when partitioning_strategy is not specified for the model' do
- expect(described_class.registered_models).to all(respond_to(:partitioning_strategy))
+ expect(described_class.__send__(:registered_models)).to all(respond_to(:partitioning_strategy))
end
end
end
diff --git a/spec/lib/gitlab/etag_caching/middleware_spec.rb b/spec/lib/gitlab/etag_caching/middleware_spec.rb
index c4da89e5f5c..982c0d911bc 100644
--- a/spec/lib/gitlab/etag_caching/middleware_spec.rb
+++ b/spec/lib/gitlab/etag_caching/middleware_spec.rb
@@ -174,7 +174,7 @@ RSpec.describe Gitlab::EtagCaching::Middleware, :clean_gitlab_redis_shared_state
it "pushes route's feature category to the context" do
expect(Gitlab::ApplicationContext).to receive(:push).with(
- feature_category: 'issue_tracking'
+ feature_category: 'team_planning'
)
_, _, _ = middleware.call(build_request(path, if_none_match))
diff --git a/spec/lib/gitlab/metrics/requests_rack_middleware_spec.rb b/spec/lib/gitlab/metrics/requests_rack_middleware_spec.rb
index 1145bda3570..3396de9b12c 100644
--- a/spec/lib/gitlab/metrics/requests_rack_middleware_spec.rb
+++ b/spec/lib/gitlab/metrics/requests_rack_middleware_spec.rb
@@ -116,14 +116,14 @@ RSpec.describe Gitlab::Metrics::RequestsRackMiddleware, :aggregate_failures do
context 'application context' do
context 'when a context is present' do
before do
- ::Gitlab::ApplicationContext.push(feature_category: 'issue_tracking', caller_id: 'IssuesController#show')
+ ::Gitlab::ApplicationContext.push(feature_category: 'team_planning', caller_id: 'IssuesController#show')
end
it 'adds the feature category to the labels for required metrics' do
- expect(described_class).to receive_message_chain(:http_requests_total, :increment).with(method: 'get', status: '200', feature_category: 'issue_tracking')
+ expect(described_class).to receive_message_chain(:http_requests_total, :increment).with(method: 'get', status: '200', feature_category: 'team_planning')
expect(described_class).not_to receive(:http_health_requests_total)
expect(Gitlab::Metrics::RailsSlis.request_apdex)
- .to receive(:increment).with(labels: { feature_category: 'issue_tracking', endpoint_id: 'IssuesController#show', request_urgency: :default }, success: true)
+ .to receive(:increment).with(labels: { feature_category: 'team_planning', endpoint_id: 'IssuesController#show', request_urgency: :default }, success: true)
subject.call(env)
end
@@ -141,12 +141,12 @@ RSpec.describe Gitlab::Metrics::RequestsRackMiddleware, :aggregate_failures do
context 'when application raises an exception when the feature category context is present' do
before do
- ::Gitlab::ApplicationContext.push(feature_category: 'issue_tracking')
+ ::Gitlab::ApplicationContext.push(feature_category: 'team_planning')
allow(app).to receive(:call).and_raise(StandardError)
end
it 'adds the feature category to the labels for http_requests_total' do
- expect(described_class).to receive_message_chain(:http_requests_total, :increment).with(method: 'get', status: 'undefined', feature_category: 'issue_tracking')
+ expect(described_class).to receive_message_chain(:http_requests_total, :increment).with(method: 'get', status: 'undefined', feature_category: 'team_planning')
expect(Gitlab::Metrics::RailsSlis).not_to receive(:request_apdex)
expect { subject.call(env) }.to raise_error(StandardError)
diff --git a/spec/lib/gitlab/sidekiq_middleware/worker_context/client_spec.rb b/spec/lib/gitlab/sidekiq_middleware/worker_context/client_spec.rb
index 92a11c83a4a..b9a13fd697e 100644
--- a/spec/lib/gitlab/sidekiq_middleware/worker_context/client_spec.rb
+++ b/spec/lib/gitlab/sidekiq_middleware/worker_context/client_spec.rb
@@ -11,7 +11,7 @@ RSpec.describe Gitlab::SidekiqMiddleware::WorkerContext::Client do
include ApplicationWorker
- feature_category :issue_tracking
+ feature_category :team_planning
def self.job_for_args(args)
jobs.find { |job| job['args'] == args }
@@ -78,8 +78,8 @@ RSpec.describe Gitlab::SidekiqMiddleware::WorkerContext::Client do
job1 = TestWithContextWorker.job_for_args(['job1', 1, 2, 3])
job2 = TestWithContextWorker.job_for_args(['job2', 1, 2, 3])
- expect(job1['meta.feature_category']).to eq('issue_tracking')
- expect(job2['meta.feature_category']).to eq('issue_tracking')
+ expect(job1['meta.feature_category']).to eq('team_planning')
+ expect(job2['meta.feature_category']).to eq('team_planning')
end
it 'takes the feature category from the caller if the worker is not owned' do
@@ -116,8 +116,8 @@ RSpec.describe Gitlab::SidekiqMiddleware::WorkerContext::Client do
job1 = TestWithContextWorker.job_for_args(['job1', 1, 2, 3])
job2 = TestWithContextWorker.job_for_args(['job2', 1, 2, 3])
- expect(job1['meta.feature_category']).to eq('issue_tracking')
- expect(job2['meta.feature_category']).to eq('issue_tracking')
+ expect(job1['meta.feature_category']).to eq('team_planning')
+ expect(job2['meta.feature_category']).to eq('team_planning')
end
it 'takes the feature category from the caller if the worker is not owned' do
diff --git a/spec/migrations/20211018152654_schedule_remove_duplicate_vulnerabilities_findings3_spec.rb b/spec/migrations/20211018152654_schedule_remove_duplicate_vulnerabilities_findings3_spec.rb
new file mode 100644
index 00000000000..95c5be2fc30
--- /dev/null
+++ b/spec/migrations/20211018152654_schedule_remove_duplicate_vulnerabilities_findings3_spec.rb
@@ -0,0 +1,168 @@
+# frozen_string_literal: true
+require 'spec_helper'
+require_migration!('schedule_remove_duplicate_vulnerabilities_findings3')
+
+RSpec.describe ScheduleRemoveDuplicateVulnerabilitiesFindings3, :migration do
+ let(:namespace) { table(:namespaces).create!(name: 'user', path: 'user') }
+ let(:users) { table(:users) }
+ let(:user) { create_user! }
+ let(:project) { table(:projects).create!(id: 14219619, namespace_id: namespace.id) }
+ let(:scanners) { table(:vulnerability_scanners) }
+ let!(:scanner1) { scanners.create!(project_id: project.id, external_id: 'test 1', name: 'test scanner 1') }
+ let!(:scanner2) { scanners.create!(project_id: project.id, external_id: 'test 2', name: 'test scanner 2') }
+ let!(:scanner3) { scanners.create!(project_id: project.id, external_id: 'test 3', name: 'test scanner 3') }
+ let!(:unrelated_scanner) { scanners.create!(project_id: project.id, external_id: 'unreleated_scanner', name: 'unrelated scanner') }
+ let(:vulnerabilities) { table(:vulnerabilities) }
+ let(:vulnerability_findings) { table(:vulnerability_occurrences) }
+ let(:vulnerability_identifiers) { table(:vulnerability_identifiers) }
+ let(:vulnerability_identifier) do
+ vulnerability_identifiers.create!(
+ id: 1244459,
+ project_id: project.id,
+ external_type: 'vulnerability-identifier',
+ external_id: 'vulnerability-identifier',
+ fingerprint: '0a203e8cd5260a1948edbedc76c7cb91ad6a2e45',
+ name: 'vulnerability identifier')
+ end
+
+ let!(:vulnerability_for_first_duplicate) do
+ create_vulnerability!(
+ project_id: project.id,
+ author_id: user.id
+ )
+ end
+
+ let!(:first_finding_duplicate) do
+ create_finding!(
+ id: 5606961,
+ uuid: "bd95c085-71aa-51d7-9bb6-08ae669c262e",
+ vulnerability_id: vulnerability_for_first_duplicate.id,
+ report_type: 0,
+ location_fingerprint: '00049d5119c2cb3bfb3d1ee1f6e031fe925aed75',
+ primary_identifier_id: vulnerability_identifier.id,
+ scanner_id: scanner1.id,
+ project_id: project.id
+ )
+ end
+
+ let!(:vulnerability_for_second_duplicate) do
+ create_vulnerability!(
+ project_id: project.id,
+ author_id: user.id
+ )
+ end
+
+ let!(:second_finding_duplicate) do
+ create_finding!(
+ id: 8765432,
+ uuid: "5b714f58-1176-5b26-8fd5-e11dfcb031b5",
+ vulnerability_id: vulnerability_for_second_duplicate.id,
+ report_type: 0,
+ location_fingerprint: '00049d5119c2cb3bfb3d1ee1f6e031fe925aed75',
+ primary_identifier_id: vulnerability_identifier.id,
+ scanner_id: scanner2.id,
+ project_id: project.id
+ )
+ end
+
+ let!(:vulnerability_for_third_duplicate) do
+ create_vulnerability!(
+ project_id: project.id,
+ author_id: user.id
+ )
+ end
+
+ let!(:third_finding_duplicate) do
+ create_finding!(
+ id: 8832995,
+ uuid: "cfe435fa-b25b-5199-a56d-7b007cc9e2d4",
+ vulnerability_id: vulnerability_for_third_duplicate.id,
+ report_type: 0,
+ location_fingerprint: '00049d5119c2cb3bfb3d1ee1f6e031fe925aed75',
+ primary_identifier_id: vulnerability_identifier.id,
+ scanner_id: scanner3.id,
+ project_id: project.id
+ )
+ end
+
+ let!(:unrelated_finding) do
+ create_finding!(
+ id: 9999999,
+ uuid: "unreleated_finding",
+ vulnerability_id: nil,
+ report_type: 1,
+ location_fingerprint: 'random_location_fingerprint',
+ primary_identifier_id: vulnerability_identifier.id,
+ scanner_id: unrelated_scanner.id,
+ project_id: project.id
+ )
+ end
+
+ before do
+ stub_const("#{described_class}::BATCH_SIZE", 1)
+ end
+
+ around do |example|
+ freeze_time { Sidekiq::Testing.fake! { example.run } }
+ end
+
+ it 'schedules background migration' do
+ migrate!
+
+ expect(BackgroundMigrationWorker.jobs.size).to eq(4)
+ expect(described_class::MIGRATION).to be_scheduled_migration(first_finding_duplicate.id, first_finding_duplicate.id)
+ expect(described_class::MIGRATION).to be_scheduled_migration(second_finding_duplicate.id, second_finding_duplicate.id)
+ expect(described_class::MIGRATION).to be_scheduled_migration(third_finding_duplicate.id, third_finding_duplicate.id)
+ expect(described_class::MIGRATION).to be_scheduled_migration(unrelated_finding.id, unrelated_finding.id)
+ end
+
+ private
+
+ def create_vulnerability!(project_id:, author_id:, title: 'test', severity: 7, confidence: 7, report_type: 0)
+ vulnerabilities.create!(
+ project_id: project_id,
+ author_id: author_id,
+ title: title,
+ severity: severity,
+ confidence: confidence,
+ report_type: report_type
+ )
+ end
+
+ # rubocop:disable Metrics/ParameterLists
+ def create_finding!(
+ id: nil,
+ vulnerability_id:, project_id:, scanner_id:, primary_identifier_id:,
+ name: "test", severity: 7, confidence: 7, report_type: 0,
+ project_fingerprint: '123qweasdzxc', location_fingerprint: 'test',
+ metadata_version: 'test', raw_metadata: 'test', uuid: 'test')
+ vulnerability_findings.create!({
+ id: id,
+ vulnerability_id: vulnerability_id,
+ project_id: project_id,
+ name: name,
+ severity: severity,
+ confidence: confidence,
+ report_type: report_type,
+ project_fingerprint: project_fingerprint,
+ scanner_id: scanner_id,
+ primary_identifier_id: vulnerability_identifier.id,
+ location_fingerprint: location_fingerprint,
+ metadata_version: metadata_version,
+ raw_metadata: raw_metadata,
+ uuid: uuid
+ }.compact)
+ end
+ # rubocop:enable Metrics/ParameterLists
+
+ def create_user!(name: "Example User", email: "user@example.com", user_type: nil, created_at: Time.zone.now, confirmed_at: Time.zone.now)
+ users.create!(
+ name: name,
+ email: email,
+ username: name,
+ projects_limit: 0,
+ user_type: user_type,
+ confirmed_at: confirmed_at
+ )
+ end
+end
diff --git a/spec/models/chat_name_spec.rb b/spec/models/chat_name_spec.rb
index 9ed00003ac1..67e0f98d147 100644
--- a/spec/models/chat_name_spec.rb
+++ b/spec/models/chat_name_spec.rb
@@ -43,4 +43,12 @@ RSpec.describe ChatName do
expect(subject.last_used_at).to eq(time)
end
end
+
+ it_behaves_like 'it has loose foreign keys' do
+ let(:factory_name) { :chat_name }
+
+ before do
+ Ci::PipelineChatData # ensure that the referenced model is loaded
+ end
+ end
end
diff --git a/spec/models/ci/runner_spec.rb b/spec/models/ci/runner_spec.rb
index c44f57ee137..1b679496437 100644
--- a/spec/models/ci/runner_spec.rb
+++ b/spec/models/ci/runner_spec.rb
@@ -5,6 +5,14 @@ require 'spec_helper'
RSpec.describe Ci::Runner do
it_behaves_like 'having unique enum values'
+ it_behaves_like 'it has loose foreign keys' do
+ let(:factory_name) { :ci_runner }
+
+ before do
+ Clusters::Applications::Runner # ensure that the referenced model is loaded
+ end
+ end
+
describe 'groups association' do
# Due to other assoctions such as projects this whole spec is allowed to
# generate cross-database queries. So we have this temporary spec to
diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb
index 351d170a0a1..75e46bb7873 100644
--- a/spec/models/namespace_spec.rb
+++ b/spec/models/namespace_spec.rb
@@ -40,6 +40,30 @@ RSpec.describe Namespace do
end
end
+ shared_examples 'validations called by different namespace types' do |method|
+ using RSpec::Parameterized::TableSyntax
+
+ where(:namespace_type, :call_validation) do
+ :namespace | true
+ :group | true
+ :user_namespace | true
+ :project_namespace | false
+ end
+
+ with_them do
+ it 'conditionally runs given validation' do
+ namespace = build(namespace_type)
+ if call_validation
+ expect(namespace).to receive(method)
+ else
+ expect(namespace).not_to receive(method)
+ end
+
+ namespace.valid?
+ end
+ end
+ end
+
describe 'validations' do
it { is_expected.to validate_presence_of(:name) }
it { is_expected.to validate_length_of(:name).is_at_most(255) }
@@ -112,14 +136,20 @@ RSpec.describe Namespace do
end
end
- it 'does not allow too deep nesting' do
- ancestors = (1..21).to_a
- group = build(:group)
+ describe '#nesting_level_allowed' do
+ context 'for a group' do
+ it 'does not allow too deep nesting' do
+ ancestors = (1..21).to_a
+ group = build(:group)
- allow(group).to receive(:ancestors).and_return(ancestors)
+ allow(group).to receive(:ancestors).and_return(ancestors)
- expect(group).not_to be_valid
- expect(group.errors[:parent_id].first).to eq('has too deep level of nesting')
+ expect(group).not_to be_valid
+ expect(group.errors[:parent_id].first).to eq('has too deep level of nesting')
+ end
+ end
+
+ it_behaves_like 'validations called by different namespace types', :nesting_level_allowed
end
describe 'reserved path validation' do
@@ -1855,87 +1885,95 @@ RSpec.describe Namespace do
end
context 'with a parent' do
- context 'when parent has shared runners disabled' do
- let(:parent) { create(:group, :shared_runners_disabled) }
- let(:group) { build(:group, shared_runners_enabled: true, parent_id: parent.id) }
+ context 'when namespace is a group' do
+ context 'when parent has shared runners disabled' do
+ let(:parent) { create(:group, :shared_runners_disabled) }
+ let(:group) { build(:group, shared_runners_enabled: true, parent_id: parent.id) }
- it 'is invalid' do
- expect(group).to be_invalid
- expect(group.errors[:shared_runners_enabled]).to include('cannot be enabled because parent group has shared Runners disabled')
+ it 'is invalid' do
+ expect(group).to be_invalid
+ expect(group.errors[:shared_runners_enabled]).to include('cannot be enabled because parent group has shared Runners disabled')
+ end
end
- end
- context 'when parent has shared runners disabled but allows override' do
- let(:parent) { create(:group, :shared_runners_disabled, :allow_descendants_override_disabled_shared_runners) }
- let(:group) { build(:group, shared_runners_enabled: true, parent_id: parent.id) }
+ context 'when parent has shared runners disabled but allows override' do
+ let(:parent) { create(:group, :shared_runners_disabled, :allow_descendants_override_disabled_shared_runners) }
+ let(:group) { build(:group, shared_runners_enabled: true, parent_id: parent.id) }
- it 'is valid' do
- expect(group).to be_valid
+ it 'is valid' do
+ expect(group).to be_valid
+ end
end
- end
- context 'when parent has shared runners enabled' do
- let(:parent) { create(:group, shared_runners_enabled: true) }
- let(:group) { build(:group, shared_runners_enabled: true, parent_id: parent.id) }
+ context 'when parent has shared runners enabled' do
+ let(:parent) { create(:group, shared_runners_enabled: true) }
+ let(:group) { build(:group, shared_runners_enabled: true, parent_id: parent.id) }
- it 'is valid' do
- expect(group).to be_valid
+ it 'is valid' do
+ expect(group).to be_valid
+ end
end
end
end
+
+ it_behaves_like 'validations called by different namespace types', :changing_shared_runners_enabled_is_allowed
end
describe 'validation #changing_allow_descendants_override_disabled_shared_runners_is_allowed' do
- context 'without a parent' do
- context 'with shared runners disabled' do
- let(:namespace) { build(:namespace, :allow_descendants_override_disabled_shared_runners, :shared_runners_disabled) }
+ context 'when namespace is a group' do
+ context 'without a parent' do
+ context 'with shared runners disabled' do
+ let(:namespace) { build(:group, :allow_descendants_override_disabled_shared_runners, :shared_runners_disabled) }
- it 'is valid' do
- expect(namespace).to be_valid
+ it 'is valid' do
+ expect(namespace).to be_valid
+ end
+ end
+
+ context 'with shared runners enabled' do
+ let(:namespace) { create(:namespace) }
+
+ it 'is invalid' do
+ namespace.allow_descendants_override_disabled_shared_runners = true
+
+ expect(namespace).to be_invalid
+ expect(namespace.errors[:allow_descendants_override_disabled_shared_runners]).to include('cannot be changed if shared runners are enabled')
+ end
end
end
- context 'with shared runners enabled' do
- let(:namespace) { create(:namespace) }
+ context 'with a parent' do
+ context 'when parent does not allow shared runners' do
+ let(:parent) { create(:group, :shared_runners_disabled) }
+ let(:group) { build(:group, :shared_runners_disabled, :allow_descendants_override_disabled_shared_runners, parent_id: parent.id) }
- it 'is invalid' do
- namespace.allow_descendants_override_disabled_shared_runners = true
+ it 'is invalid' do
+ expect(group).to be_invalid
+ expect(group.errors[:allow_descendants_override_disabled_shared_runners]).to include('cannot be enabled because parent group does not allow it')
+ end
+ end
- expect(namespace).to be_invalid
- expect(namespace.errors[:allow_descendants_override_disabled_shared_runners]).to include('cannot be changed if shared runners are enabled')
+ context 'when parent allows shared runners and setting to true' do
+ let(:parent) { create(:group, shared_runners_enabled: true) }
+ let(:group) { build(:group, :shared_runners_disabled, :allow_descendants_override_disabled_shared_runners, parent_id: parent.id) }
+
+ it 'is valid' do
+ expect(group).to be_valid
+ end
+ end
+
+ context 'when parent allows shared runners and setting to false' do
+ let(:parent) { create(:group, shared_runners_enabled: true) }
+ let(:group) { build(:group, :shared_runners_disabled, allow_descendants_override_disabled_shared_runners: false, parent_id: parent.id) }
+
+ it 'is valid' do
+ expect(group).to be_valid
+ end
end
end
end
- context 'with a parent' do
- context 'when parent does not allow shared runners' do
- let(:parent) { create(:group, :shared_runners_disabled) }
- let(:group) { build(:group, :shared_runners_disabled, :allow_descendants_override_disabled_shared_runners, parent_id: parent.id) }
-
- it 'is invalid' do
- expect(group).to be_invalid
- expect(group.errors[:allow_descendants_override_disabled_shared_runners]).to include('cannot be enabled because parent group does not allow it')
- end
- end
-
- context 'when parent allows shared runners and setting to true' do
- let(:parent) { create(:group, shared_runners_enabled: true) }
- let(:group) { build(:group, :shared_runners_disabled, :allow_descendants_override_disabled_shared_runners, parent_id: parent.id) }
-
- it 'is valid' do
- expect(group).to be_valid
- end
- end
-
- context 'when parent allows shared runners and setting to false' do
- let(:parent) { create(:group, shared_runners_enabled: true) }
- let(:group) { build(:group, :shared_runners_disabled, allow_descendants_override_disabled_shared_runners: false, parent_id: parent.id) }
-
- it 'is valid' do
- expect(group).to be_valid
- end
- end
- end
+ it_behaves_like 'validations called by different namespace types', :changing_allow_descendants_override_disabled_shared_runners_is_allowed
end
describe '#root?' do
diff --git a/spec/requests/api/api_spec.rb b/spec/requests/api/api_spec.rb
index 95eb503c6bc..d57ecce3149 100644
--- a/spec/requests/api/api_spec.rb
+++ b/spec/requests/api/api_spec.rb
@@ -116,7 +116,7 @@ RSpec.describe API::API do
'meta.root_namespace' => project.namespace.full_path,
'meta.user' => user.username,
'meta.client_id' => a_string_matching(%r{\Auser/.+}),
- 'meta.feature_category' => 'issue_tracking',
+ 'meta.feature_category' => 'team_planning',
'route' => '/api/:version/projects/:id/issues')
end
diff --git a/spec/requests/api/releases_spec.rb b/spec/requests/api/releases_spec.rb
index 90b03a480a8..cb9b6a072b1 100644
--- a/spec/requests/api/releases_spec.rb
+++ b/spec/requests/api/releases_spec.rb
@@ -42,6 +42,14 @@ RSpec.describe API::Releases do
expect(response).to have_gitlab_http_status(:ok)
end
+ it 'returns 200 HTTP status when using JOB-TOKEN auth' do
+ job = create(:ci_build, :running, project: project, user: maintainer)
+
+ get api("/projects/#{project.id}/releases"), params: { job_token: job.token }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+
it 'returns releases ordered by released_at' do
get api("/projects/#{project.id}/releases", maintainer)
@@ -316,6 +324,14 @@ RSpec.describe API::Releases do
expect(response).to have_gitlab_http_status(:ok)
end
+ it 'returns 200 HTTP status when using JOB-TOKEN auth' do
+ job = create(:ci_build, :running, project: project, user: maintainer)
+
+ get api("/projects/#{project.id}/releases/v0.1"), params: { job_token: job.token }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+
it 'returns a release entry' do
get api("/projects/#{project.id}/releases/v0.1", maintainer)
@@ -1008,6 +1024,14 @@ RSpec.describe API::Releases do
expect(response).to have_gitlab_http_status(:ok)
end
+ it 'accepts the request when using JOB-TOKEN auth' do
+ job = create(:ci_build, :running, project: project, user: maintainer)
+
+ put api("/projects/#{project.id}/releases/v0.1"), params: params.merge(job_token: job.token)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+
it 'updates the description' do
put api("/projects/#{project.id}/releases/v0.1", maintainer), params: params
@@ -1220,6 +1244,14 @@ RSpec.describe API::Releases do
expect(response).to have_gitlab_http_status(:ok)
end
+ it 'accepts the request when using JOB-TOKEN auth' do
+ job = create(:ci_build, :running, project: project, user: maintainer)
+
+ delete api("/projects/#{project.id}/releases/v0.1"), params: { job_token: job.token }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+
it 'destroys the release' do
expect do
delete api("/projects/#{project.id}/releases/v0.1", maintainer)
diff --git a/spec/support/database/gitlab_schema.rb b/spec/support/database/gitlab_schema.rb
deleted file mode 100644
index 22f997e70e1..00000000000
--- a/spec/support/database/gitlab_schema.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-# frozen_string_literal: true
-
-# This module gathes information about table to schema mapping
-# to understand table affinity
-module Database
- module GitlabSchema
- def self.table_schemas(tables)
- tables.map { |table| table_schema(table) }.to_set
- end
-
- def self.table_schema(name)
- # When undefined it's best to return a unique name so that we don't incorrectly assume that 2 undefined schemas belong on the same database
- tables_to_schema[name] || :"undefined_#{name}"
- end
-
- def self.tables_to_schema
- @tables_to_schema ||= YAML.load_file(Rails.root.join('spec/support/database/gitlab_schemas.yml'))
- end
- end
-end
diff --git a/spec/support/database/prevent_cross_database_modification.rb b/spec/support/database/prevent_cross_database_modification.rb
index 229f5026044..09a87f92072 100644
--- a/spec/support/database/prevent_cross_database_modification.rb
+++ b/spec/support/database/prevent_cross_database_modification.rb
@@ -100,7 +100,7 @@ module Database
cross_database_context[:modified_tables_by_db][database].merge(tables)
all_tables = cross_database_context[:modified_tables_by_db].values.map(&:to_a).flatten
- schemas = Database::GitlabSchema.table_schemas(all_tables)
+ schemas = ::Gitlab::Database::GitlabSchema.table_schemas(all_tables)
if schemas.many?
message = "Cross-database data modification of '#{schemas.to_a.join(", ")}' were detected within " \
diff --git a/spec/support/database/prevent_cross_joins.rb b/spec/support/database/prevent_cross_joins.rb
index b3d2b966815..e69374fbc70 100644
--- a/spec/support/database/prevent_cross_joins.rb
+++ b/spec/support/database/prevent_cross_joins.rb
@@ -35,7 +35,7 @@ module Database
# https://github.com/pganalyze/pg_query/issues/209
tables = PgQuery.parse(sql).tables
- schemas = Database::GitlabSchema.table_schemas(tables)
+ schemas = ::Gitlab::Database::GitlabSchema.table_schemas(tables)
if schemas.include?(:gitlab_ci) && schemas.include?(:gitlab_main)
Thread.current[:has_cross_join_exception] = true
diff --git a/spec/support/shared_examples/loose_foreign_keys/have_loose_foreign_key.rb b/spec/support/shared_examples/loose_foreign_keys/have_loose_foreign_key.rb
new file mode 100644
index 00000000000..7ccd9533811
--- /dev/null
+++ b/spec/support/shared_examples/loose_foreign_keys/have_loose_foreign_key.rb
@@ -0,0 +1,52 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'it has loose foreign keys' do
+ let(:factory_name) { nil }
+ let(:table_name) { described_class.table_name }
+ let(:connection) { described_class.connection }
+
+ it 'includes the LooseForeignKey module' do
+ expect(described_class.ancestors).to include(LooseForeignKey)
+ end
+
+ it 'responds to #loose_foreign_key_definitions' do
+ expect(described_class).to respond_to(:loose_foreign_key_definitions)
+ end
+
+ it 'has at least one loose foreign key definition' do
+ expect(described_class.loose_foreign_key_definitions.size).to be > 0
+ end
+
+ it 'has the deletion trigger present' do
+ sql = <<-SQL
+ SELECT trigger_name
+ FROM information_schema.triggers
+ WHERE event_object_table = '#{table_name}'
+ SQL
+
+ triggers = connection.execute(sql)
+
+ expected_trigger_name = "#{table_name}_loose_fk_trigger"
+ expect(triggers.pluck('trigger_name')).to include(expected_trigger_name)
+ end
+
+ it 'records record deletions' do
+ model = create(factory_name) # rubocop: disable Rails/SaveBang
+ model.destroy!
+
+ deleted_record = LooseForeignKeys::DeletedRecord.find_by(fully_qualified_table_name: "#{connection.current_schema}.#{table_name}", primary_key_value: model.id)
+
+ expect(deleted_record).not_to be_nil
+ end
+
+ it 'cleans up record deletions' do
+ model = create(factory_name) # rubocop: disable Rails/SaveBang
+
+ expect { model.destroy! }.to change { LooseForeignKeys::DeletedRecord.count }.by(1)
+
+ LooseForeignKeys::ProcessDeletedRecordsService.new(connection: connection).execute
+
+ expect(LooseForeignKeys::DeletedRecord.status_pending.count).to be(0)
+ expect(LooseForeignKeys::DeletedRecord.status_processed.count).to be(1)
+ end
+end