diff options
127 files changed, 950 insertions, 321 deletions
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 @@ -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 @@ <script> -import { GlDeprecatedSkeletonLoading as GlSkeletonLoading } from '@gitlab/ui'; +import { + GlDeprecatedSkeletonLoading as GlSkeletonLoading, + GlSafeHtmlDirective as SafeHtml, +} from '@gitlab/ui'; import $ from 'jquery'; import '~/behaviors/markdown/render_gfm'; import { forEach, escape } from 'lodash'; @@ -13,6 +16,9 @@ export default { components: { GlSkeletonLoading, }, + directives: { + SafeHtml, + }, props: { content: { type: String, @@ -103,6 +109,7 @@ export default { } }, }, + safeHtmlConfig: { ADD_TAGS: ['gl-emoji', 'use'] }, }; </script> @@ -111,8 +118,8 @@ export default { <gl-skeleton-loading v-if="isLoading" /> <div v-else + v-safe-html:[$options.safeHtmlConfig]="previewContent" class="md gl-ml-auto gl-mr-auto" - v-html="previewContent /* eslint-disable-line vue/no-v-html */" ></div> </div> </template> 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: '<code>'.html_safe, code_close: '</code>'.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: '<code>'.html_safe, code_close: '</code>'.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: '<code>'.html_safe, code_close: '</code>'.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: '<code>'.html_safe, code_close: '</code>'.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` | ---- | ---- | ----------- | | <a id="mutationdastprofilecreatebranchname"></a>`branchName` | [`String`](#string) | Associated branch. | | <a id="mutationdastprofilecreateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. | -| <a id="mutationdastprofilecreatedastprofileschedule"></a>`dastProfileSchedule` | [`DastProfileScheduleInput`](#dastprofilescheduleinput) | Represents a DAST Profile Schedule. Results in an error if `dast_on_demand_scans_scheduler` feature flag is disabled. | +| <a id="mutationdastprofilecreatedastprofileschedule"></a>`dastProfileSchedule` | [`DastProfileScheduleInput`](#dastprofilescheduleinput) | Represents a DAST Profile Schedule. | | <a id="mutationdastprofilecreatedastscannerprofileid"></a>`dastScannerProfileId` | [`DastScannerProfileID!`](#dastscannerprofileid) | ID of the scanner profile to be associated. | | <a id="mutationdastprofilecreatedastsiteprofileid"></a>`dastSiteProfileId` | [`DastSiteProfileID!`](#dastsiteprofileid) | ID of the site profile to be associated. | | <a id="mutationdastprofilecreatedescription"></a>`description` | [`String`](#string) | Description of the profile. Defaults to an empty string. | @@ -1619,7 +1619,7 @@ Input type: `DastProfileUpdateInput` | ---- | ---- | ----------- | | <a id="mutationdastprofileupdatebranchname"></a>`branchName` | [`String`](#string) | Associated branch. | | <a id="mutationdastprofileupdateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. | -| <a id="mutationdastprofileupdatedastprofileschedule"></a>`dastProfileSchedule` | [`DastProfileScheduleInput`](#dastprofilescheduleinput) | Represents a DAST profile schedule. Results in an error if `dast_on_demand_scans_scheduler` feature flag is disabled. | +| <a id="mutationdastprofileupdatedastprofileschedule"></a>`dastProfileSchedule` | [`DastProfileScheduleInput`](#dastprofilescheduleinput) | Represents a DAST profile schedule. | | <a id="mutationdastprofileupdatedastscannerprofileid"></a>`dastScannerProfileId` | [`DastScannerProfileID`](#dastscannerprofileid) | ID of the scanner profile to be associated. | | <a id="mutationdastprofileupdatedastsiteprofileid"></a>`dastSiteProfileId` | [`DastSiteProfileID`](#dastsiteprofileid) | ID of the site profile to be associated. | | <a id="mutationdastprofileupdatedescription"></a>`description` | [`String`](#string) | Description of the profile. Defaults to an empty string. | @@ -8951,7 +8951,7 @@ Represents a DAST Profile. | Name | Type | Description | | ---- | ---- | ----------- | | <a id="dastprofilebranch"></a>`branch` | [`DastProfileBranch`](#dastprofilebranch) | Associated branch. | -| <a id="dastprofiledastprofileschedule"></a>`dastProfileSchedule` | [`DastProfileSchedule`](#dastprofileschedule) | Associated profile schedule. Will always return `null` if `dast_on_demand_scans_scheduler` feature flag is disabled. | +| <a id="dastprofiledastprofileschedule"></a>`dastProfileSchedule` | [`DastProfileSchedule`](#dastprofileschedule) | Associated profile schedule. | | <a id="dastprofiledastscannerprofile"></a>`dastScannerProfile` | [`DastScannerProfile`](#dastscannerprofile) | Associated scanner profile. | | <a id="dastprofiledastsiteprofile"></a>`dastSiteProfile` | [`DastSiteProfile`](#dastsiteprofile) | Associated site profile. | | <a id="dastprofiledescription"></a>`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 index d46f2803c93..d46f2803c93 100644 --- a/spec/support/database/gitlab_schemas.yml +++ b/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_<name-of-connection>=<new-name-of-connection> + # + # 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 + + attr_reader :table_name - def self.registered_models - @registered_models ||= Set.new + def initialize(table_name:, partitioned_column:, strategy:) + @table_name = table_name + partitioned_by(partitioned_column, strategy: strategy) + end + + def connection + Gitlab::Database::SharedModel.connection + end end - def self.sync_partitions(models_to_sync = registered_models) - Gitlab::AppLogger.info(message: 'Syncing dynamic postgres partitions') + class << self + def register_models(models) + registered_models.merge(models) + end - Gitlab::Database::EachDatabase.each_model_connection(models_to_sync) do |model| - PartitionManager.new(model).sync_partitions + def register_tables(tables) + registered_tables.merge(tables) end - Gitlab::AppLogger.info(message: 'Finished sync of dynamic postgres partitions') - end + def sync_partitions(models_to_sync = registered_for_sync) + Gitlab::AppLogger.info(message: 'Syncing dynamic postgres partitions') - def self.report_metrics(models_to_monitor = registered_models) - partition_monitoring = PartitionMonitoring.new + Gitlab::Database::EachDatabase.each_model_connection(models_to_sync) do |model| + PartitionManager.new(model).sync_partitions + end - Gitlab::Database::EachDatabase.each_model_connection(models_to_monitor) do |model| - partition_monitoring.report_metrics_for_model(model) + Gitlab::AppLogger.info(message: 'Finished sync of dynamic postgres partitions') end - end - def self.drop_detached_partitions - Gitlab::AppLogger.info(message: 'Dropping detached postgres partitions') + 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::Database::EachDatabase.each_database_connection do - DetachedPartitionDropper.new.perform + Gitlab::AppLogger.info(message: 'Finished dropping detached postgres partitions') end - Gitlab::AppLogger.info(message: 'Finished dropping detached postgres partitions') + 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 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) } - - 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') + 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') + 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 - end - context 'with shared runners enabled' do - let(:namespace) { create(:namespace) } + context 'with shared runners enabled' do + let(:namespace) { create(:namespace) } - it 'is invalid' do - namespace.allow_descendants_override_disabled_shared_runners = true + 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') + 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 - 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) } + 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') + 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 - 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) } + 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 + it 'is valid' do + expect(group).to be_valid + end 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) } + 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 + it 'is valid' do + expect(group).to be_valid + end 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 |