From ce34395e91c28f282eeff3792caee84438ebb8a0 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Mon, 13 Jul 2020 12:09:18 +0000 Subject: [PATCH] Add latest changes from gitlab-org/gitlab@master --- app/assets/javascripts/blob/viewer/index.js | 5 + .../code_navigation/components/popover.vue | 37 +- .../code_navigation/store/actions.js | 6 +- .../code_navigation/utils/index.js | 1 + .../javascripts/lib/utils/datetime_utility.js | 6 +- app/assets/stylesheets/framework/files.scss | 23 +- .../projects/ci/lints_controller.rb | 2 +- app/models/alert_management/alert.rb | 8 +- app/models/blob_viewer/image.rb | 2 +- app/models/blob_viewer/notebook.rb | 2 +- app/models/blob_viewer/open_api.rb | 4 +- app/models/blob_viewer/rich.rb | 2 +- app/models/blob_viewer/svg.rb | 2 +- app/models/ci/pipeline.rb | 23 +- app/models/diff_viewer/image.rb | 2 +- app/models/user_detail.rb | 8 + app/services/jira/jql_builder_service.rb | 15 +- app/services/labels/transfer_service.rb | 21 +- app/services/members/destroy_service.rb | 2 +- app/views/projects/blob/_viewer.html.haml | 2 +- .../projects/blob/_viewer_switcher.html.haml | 4 +- app/workers/all_queues.yml | 756 +++++++++--------- .../update_container_registry_info_worker.rb | 15 + .../204839-move-update-logic-to-service.yml | 5 + ...220124-drop-temp-index-on-audit-events.yml | 5 + .../223151-adjust-unique-index-on-alerts.yml | 5 + .../227863-fix-api-error-on-null-bio.yml | 5 + .../unreleased/feat-use-new-api-icon.yml | 5 + .../ph-codeNavigationUXImprovements.yml | 5 + ...suables-worker-when-out-of-transaction.yml | 5 + config/initializers/1_settings.rb | 3 + ...st_unique_index_alert_management_alerts.rb | 35 + ...ruby_objects_in_details_on_audit_events.rb | 18 + db/structure.sql | 8 +- .../geo/replication/disable_geo.md | 93 +++ doc/administration/geo/replication/index.md | 4 + .../monitoring/prometheus/gitlab_metrics.md | 1 + doc/api/users.md | 27 +- doc/integration/recaptcha.md | 6 + doc/user/group/index.md | 27 + doc/user/project/members/index.md | 27 + lib/gitlab/ci/config.rb | 4 + lib/gitlab/ci/config/entry/processable.rb | 4 + lib/gitlab/ci/features.rb | 6 + .../ci/pipeline/chain/config/process.rb | 12 + lib/gitlab/ci/pipeline/chain/helpers.rb | 4 + lib/gitlab/ci/yaml_processor.rb | 64 +- lib/gitlab/config/entry/node.rb | 9 + lib/gitlab/danger/helper.rb | 2 +- lib/gitlab/instrumentation/redis_base.rb | 15 +- .../instrumentation/redis_interceptor.rb | 21 +- lib/gitlab/middleware/multipart.rb | 19 +- locale/gitlab.pot | 12 + .../__snapshots__/popover_spec.js.snap | 48 +- .../components/popover_spec.js | 3 +- .../code_navigation/store/actions_spec.js | 24 +- .../code_navigation/utils/index_spec.js | 2 +- .../lib/utils/datetime_utility_spec.js | 26 + .../ci/config/entry/processable_spec.rb | 12 +- spec/lib/gitlab/ci/yaml_processor_spec.rb | 159 +++- spec/lib/gitlab/danger/helper_spec.rb | 2 +- .../instrumentation/redis_interceptor_spec.rb | 53 +- spec/lib/gitlab/middleware/multipart_spec.rb | 78 ++ ...ique_index_alert_management_alerts_spec.rb | 57 ++ spec/models/alert_management/alert_spec.rb | 39 +- spec/requests/api/users_spec.rb | 8 + .../creation_errors_and_warnings_spec.rb | 114 +++ .../services/jira/jql_builder_service_spec.rb | 24 + spec/services/members/destroy_service_spec.rb | 1 + ...ate_container_registry_info_worker_spec.rb | 15 + 70 files changed, 1553 insertions(+), 516 deletions(-) create mode 100644 app/workers/update_container_registry_info_worker.rb create mode 100644 changelogs/unreleased/204839-move-update-logic-to-service.yml create mode 100644 changelogs/unreleased/220124-drop-temp-index-on-audit-events.yml create mode 100644 changelogs/unreleased/223151-adjust-unique-index-on-alerts.yml create mode 100644 changelogs/unreleased/227863-fix-api-error-on-null-bio.yml create mode 100644 changelogs/unreleased/feat-use-new-api-icon.yml create mode 100644 changelogs/unreleased/ph-codeNavigationUXImprovements.yml create mode 100644 changelogs/unreleased/run-unassign-issuables-worker-when-out-of-transaction.yml create mode 100644 db/migrate/20200706035141_adjust_unique_index_alert_management_alerts.rb create mode 100644 db/post_migrate/20200710102846_drop_index_ruby_objects_in_details_on_audit_events.rb create mode 100644 doc/administration/geo/replication/disable_geo.md create mode 100644 spec/migrations/20200706035141_adjust_unique_index_alert_management_alerts_spec.rb create mode 100644 spec/services/ci/create_pipeline_service/creation_errors_and_warnings_spec.rb create mode 100644 spec/workers/update_container_registry_info_worker_spec.rb diff --git a/app/assets/javascripts/blob/viewer/index.js b/app/assets/javascripts/blob/viewer/index.js index 3ac419557eb..b18faea628a 100644 --- a/app/assets/javascripts/blob/viewer/index.js +++ b/app/assets/javascripts/blob/viewer/index.js @@ -3,6 +3,7 @@ import '~/behaviors/markdown/render_gfm'; import Flash from '../../flash'; import { handleLocationHash } from '../../lib/utils/common_utils'; import axios from '../../lib/utils/axios_utils'; +import eventHub from '../../notes/event_hub'; import { __ } from '~/locale'; const loadRichBlobViewer = type => { @@ -178,6 +179,10 @@ export default class BlobViewer { viewer.innerHTML = data.html; viewer.setAttribute('data-loaded', 'true'); + if (window.gon?.features?.codeNavigation) { + eventHub.$emit('showBlobInteractionZones', viewer.dataset.path); + } + return viewer; }); } diff --git a/app/assets/javascripts/code_navigation/components/popover.vue b/app/assets/javascripts/code_navigation/components/popover.vue index df5f89e4faf..4cc5a5cd6a2 100644 --- a/app/assets/javascripts/code_navigation/components/popover.vue +++ b/app/assets/javascripts/code_navigation/components/popover.vue @@ -31,6 +31,9 @@ export default { }; }, computed: { + isCurrentDefinition() { + return this.data.definitionLineNumber - 1 === this.position.lineIndex; + }, positionStyles() { return { left: `${this.position.x - this.offsetLeft}px`, @@ -43,7 +46,7 @@ export default { } if (this.isDefinitionCurrentBlob) { - return `#${this.data.definition_path.split('#').pop()}`; + return `#L${this.data.definitionLineNumber}`; } return `${this.definitionPathPrefix}/${this.data.definition_path}`; @@ -79,19 +82,29 @@ export default { class="popover code-navigation-popover popover-font-size-normal gl-popover bs-popover-bottom show" >
-
-
-

- {{ hover.value }} -

+
+
+
+

+ {{ hover.value }} +

+
-
+
+ + {{ s__('CodeIntelligence|This is the definition') }} + { const normalizedData = data.reduce((acc, d) => { if (d.hover) { - acc[`${d.start_line}:${d.start_char}`] = d; + acc[`${d.start_line}:${d.start_char}`] = { + ...d, + definitionLineNumber: parseInt(d.definition_path?.split('#L').pop() || 0, 10), + }; addInteractionClass(path, d); } return acc; @@ -67,6 +70,7 @@ export default { x: x || 0, y: y + window.scrollY || 0, height: el.offsetHeight, + lineIndex: parseInt(lineIndex, 10), }; definition = data[`${lineIndex}:${charIndex}`]; diff --git a/app/assets/javascripts/code_navigation/utils/index.js b/app/assets/javascripts/code_navigation/utils/index.js index 4d118852a94..bb33bc556af 100644 --- a/app/assets/javascripts/code_navigation/utils/index.js +++ b/app/assets/javascripts/code_navigation/utils/index.js @@ -22,6 +22,7 @@ export const addInteractionClass = (path, d) => { el.setAttribute('data-char-index', d.start_char); el.setAttribute('data-line-index', d.start_line); el.classList.add('cursor-pointer', 'code-navigation', 'js-code-navigation'); + el.closest('.line').classList.add('code-navigation-line'); } }); }; diff --git a/app/assets/javascripts/lib/utils/datetime_utility.js b/app/assets/javascripts/lib/utils/datetime_utility.js index 6b69d2febe0..b7f794e439a 100644 --- a/app/assets/javascripts/lib/utils/datetime_utility.js +++ b/app/assets/javascripts/lib/utils/datetime_utility.js @@ -89,13 +89,15 @@ export const getDayName = date => * @example * dateFormat('2017-12-05','mmm d, yyyy h:MMtt Z' ) -> "Dec 5, 2017 12:00am GMT+0000" * @param {date} datetime + * @param {String} format + * @param {Boolean} UTC convert local time to UTC * @returns {String} */ -export const formatDate = (datetime, format = 'mmm d, yyyy h:MMtt Z') => { +export const formatDate = (datetime, format = 'mmm d, yyyy h:MMtt Z', utc = false) => { if (isString(datetime) && datetime.match(/\d+-\d+\d+ /)) { throw new Error(__('Invalid date')); } - return dateFormat(datetime, format); + return dateFormat(datetime, format, utc); }; /** diff --git a/app/assets/stylesheets/framework/files.scss b/app/assets/stylesheets/framework/files.scss index eef6d9031f8..8fd507a45bb 100644 --- a/app/assets/stylesheets/framework/files.scss +++ b/app/assets/stylesheets/framework/files.scss @@ -500,16 +500,27 @@ span.idiff { border: transparent; } -.code-navigation { - border-bottom: 1px $gray-darkest dashed; +.code-navigation-line:hover { + .code-navigation { + border-bottom: 1px $gray-darkest dashed; - &:hover { - border-bottom-color: $almost-black; + &:hover { + border-bottom-color: $almost-black; + } } } -.code-navigation-popover { - max-width: 450px; +.code-navigation-popover.popover { + max-width: calc(min(#{px-to-rem(560px)}, calc(100vw - #{$gl-padding-32}))); +} + +.code-navigation-popover-container { + max-height: px-to-rem(320px); +} + +.code-navigation-popover .code { + padding-left: $grid-size * 3; + text-indent: -$grid-size * 2; } .tree-item-link { diff --git a/app/controllers/projects/ci/lints_controller.rb b/app/controllers/projects/ci/lints_controller.rb index b50afa12da0..73b3eb9c205 100644 --- a/app/controllers/projects/ci/lints_controller.rb +++ b/app/controllers/projects/ci/lints_controller.rb @@ -14,7 +14,7 @@ class Projects::Ci::LintsController < Projects::ApplicationController @errors = result.errors if result.valid? - @config_processor = result.content + @config_processor = result.config @stages = @config_processor.stages @builds = @config_processor.builds @jobs = @config_processor.jobs diff --git a/app/models/alert_management/alert.rb b/app/models/alert_management/alert.rb index 0af261a9358..394957beb40 100644 --- a/app/models/alert_management/alert.rb +++ b/app/models/alert_management/alert.rb @@ -55,8 +55,12 @@ module AlertManagement validates :severity, presence: true validates :status, presence: true validates :started_at, presence: true - validates :fingerprint, uniqueness: { scope: :project }, allow_blank: true - validate :hosts_length + validates :fingerprint, allow_blank: true, uniqueness: { + scope: :project, + conditions: -> { where.not(status: STATUSES[:resolved]) }, + message: -> (object, data) { _('Cannot have multiple unresolved alerts') } + }, unless: :resolved? + validate :hosts_length enum severity: { critical: 0, diff --git a/app/models/blob_viewer/image.rb b/app/models/blob_viewer/image.rb index cbebef46c60..97eb0489158 100644 --- a/app/models/blob_viewer/image.rb +++ b/app/models/blob_viewer/image.rb @@ -8,7 +8,7 @@ module BlobViewer self.partial_name = 'image' self.extensions = UploaderHelper::SAFE_IMAGE_EXT self.binary = true - self.switcher_icon = 'picture-o' + self.switcher_icon = 'doc-image' self.switcher_title = 'image' end end diff --git a/app/models/blob_viewer/notebook.rb b/app/models/blob_viewer/notebook.rb index 57d6d802db3..351502d451f 100644 --- a/app/models/blob_viewer/notebook.rb +++ b/app/models/blob_viewer/notebook.rb @@ -8,7 +8,7 @@ module BlobViewer self.partial_name = 'notebook' self.extensions = %w(ipynb) self.binary = false - self.switcher_icon = 'file-text-o' + self.switcher_icon = 'doc-text' self.switcher_title = 'notebook' end end diff --git a/app/models/blob_viewer/open_api.rb b/app/models/blob_viewer/open_api.rb index 963b7336c8d..0551f3bb1e3 100644 --- a/app/models/blob_viewer/open_api.rb +++ b/app/models/blob_viewer/open_api.rb @@ -8,8 +8,6 @@ module BlobViewer self.partial_name = 'openapi' self.file_types = %i(openapi) self.binary = false - # TODO: get an icon for OpenAPI - self.switcher_icon = 'file-pdf-o' - self.switcher_title = 'OpenAPI' + self.switcher_icon = 'api' end end diff --git a/app/models/blob_viewer/rich.rb b/app/models/blob_viewer/rich.rb index 0f66a672102..46f36cc2674 100644 --- a/app/models/blob_viewer/rich.rb +++ b/app/models/blob_viewer/rich.rb @@ -6,7 +6,7 @@ module BlobViewer included do self.type = :rich - self.switcher_icon = 'file-text-o' + self.switcher_icon = 'doc-text' self.switcher_title = 'rendered file' end end diff --git a/app/models/blob_viewer/svg.rb b/app/models/blob_viewer/svg.rb index 454c6a57568..60a11fbd97e 100644 --- a/app/models/blob_viewer/svg.rb +++ b/app/models/blob_viewer/svg.rb @@ -8,7 +8,7 @@ module BlobViewer self.partial_name = 'svg' self.extensions = %w(svg) self.binary = false - self.switcher_icon = 'picture-o' + self.switcher_icon = 'doc-image' self.switcher_title = 'image' end end diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index d2c7923af74..18e8cceb687 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -641,9 +641,22 @@ module Ci end def add_error_message(content) - return unless Gitlab::Ci::Features.store_pipeline_messages?(project) + add_message(:error, content) + end - messages.error.build(content: content) + def add_warning_message(content) + add_message(:warning, content) + end + + # We can't use `messages.error` scope here because messages should also be + # read when the pipeline is not persisted. Using the scope will return no + # results as it would query persisted data. + def error_messages + messages.select(&:error?) + end + + def warning_messages + messages.select(&:warning?) end # Manually set the notes for a Ci::Pipeline @@ -1019,6 +1032,12 @@ module Ci private + def add_message(severity, content) + return unless Gitlab::Ci::Features.store_pipeline_messages?(project) + + messages.build(severity: severity, content: content) + end + def pipeline_data Gitlab::DataBuilder::Pipeline.build(self) end diff --git a/app/models/diff_viewer/image.rb b/app/models/diff_viewer/image.rb index cfda0058d81..62a3446a7b6 100644 --- a/app/models/diff_viewer/image.rb +++ b/app/models/diff_viewer/image.rb @@ -8,7 +8,7 @@ module DiffViewer self.partial_name = 'image' self.extensions = UploaderHelper::SAFE_IMAGE_EXT self.binary = true - self.switcher_icon = 'picture-o' + self.switcher_icon = 'doc-image' self.switcher_title = _('image diff') end end diff --git a/app/models/user_detail.rb b/app/models/user_detail.rb index 09bb2e080e5..9674f9a41da 100644 --- a/app/models/user_detail.rb +++ b/app/models/user_detail.rb @@ -9,6 +9,8 @@ class UserDetail < ApplicationRecord validates :job_title, length: { maximum: 200 } validates :bio, length: { maximum: 255 }, allow_blank: true + before_save :prevent_nil_bio + cache_markdown_field :bio def bio_html @@ -22,4 +24,10 @@ class UserDetail < ApplicationRecord def invalidated_markdown_cache? self.class.column_names.include?('bio_html') && super end + + private + + def prevent_nil_bio + self.bio = '' if bio_changed? && bio.nil? + end end diff --git a/app/services/jira/jql_builder_service.rb b/app/services/jira/jql_builder_service.rb index ddf7c4e30a6..385ea8568d1 100644 --- a/app/services/jira/jql_builder_service.rb +++ b/app/services/jira/jql_builder_service.rb @@ -13,6 +13,7 @@ module Jira @search = params[:search] @labels = params[:labels] @status = params[:status] + @state = params[:state] @reporter = params[:author_username] @assignee = params[:assignee_username] @sort = params[:sort] || DEFAULT_SORT @@ -28,7 +29,7 @@ module Jira private - attr_reader :jira_project_key, :sort, :sort_direction, :search, :labels, :status, :reporter, :assignee + attr_reader :jira_project_key, :sort, :sort_direction, :search, :labels, :status, :reporter, :assignee, :state def jql_filters [ @@ -37,6 +38,7 @@ module Jira by_status, by_reporter, by_assignee, + by_open_and_closed, by_summary_and_description ].compact.join(' AND ') end @@ -80,6 +82,17 @@ module Jira %Q[assignee = "#{escape_quotes(assignee)}"] end + def by_open_and_closed + return if state.blank? + + case state + when 'opened' + %q[statusCategory != Done] + when 'closed' + %q[statusCategory = Done] + end + end + def escape_quotes(param) param.gsub('\\', '\\\\\\').gsub('"', '\\"') end diff --git a/app/services/labels/transfer_service.rb b/app/services/labels/transfer_service.rb index e6f9cf35fcb..b1163d81898 100644 --- a/app/services/labels/transfer_service.rb +++ b/app/services/labels/transfer_service.rb @@ -15,14 +15,18 @@ module Labels def execute return unless old_group.present? + # rubocop: disable CodeReuse/ActiveRecord + link_ids = group_labels_applied_to_issues.pluck("label_links.id") + + group_labels_applied_to_merge_requests.pluck("label_links.id") + # rubocop: disable CodeReuse/ActiveRecord + Label.transaction do labels_to_transfer.find_each do |label| new_label_id = find_or_create_label!(label) next if new_label_id == label.id - update_label_links(group_labels_applied_to_issues, old_label_id: label.id, new_label_id: new_label_id) - update_label_links(group_labels_applied_to_merge_requests, old_label_id: label.id, new_label_id: new_label_id) + update_label_links(link_ids, old_label_id: label.id, new_label_id: new_label_id) update_label_priorities(old_label_id: label.id, new_label_id: new_label_id) end end @@ -46,7 +50,7 @@ module Labels # rubocop: disable CodeReuse/ActiveRecord def group_labels_applied_to_issues - Label.joins(:issues) + @group_labels_applied_to_issues ||= Label.joins(:issues) .where( issues: { project_id: project.id }, labels: { type: 'GroupLabel', group_id: old_group.self_and_ancestors } @@ -56,7 +60,7 @@ module Labels # rubocop: disable CodeReuse/ActiveRecord def group_labels_applied_to_merge_requests - Label.joins(:merge_requests) + @group_labels_applied_to_merge_requests ||= Label.joins(:merge_requests) .where( merge_requests: { target_project_id: project.id }, labels: { type: 'GroupLabel', group_id: old_group.self_and_ancestors } @@ -72,14 +76,7 @@ module Labels end # rubocop: disable CodeReuse/ActiveRecord - def update_label_links(labels, old_label_id:, new_label_id:) - # use 'labels' relation to get label_link ids only of issues/MRs - # in the project being transferred. - # IDs are fetched in a separate query because MySQL doesn't - # allow referring of 'label_links' table in UPDATE query: - # https://gitlab.com/gitlab-org/gitlab-foss/-/jobs/62435068 - link_ids = labels.pluck('label_links.id') - + def update_label_links(link_ids, old_label_id:, new_label_id:) LabelLink.where(id: link_ids, label_id: old_label_id) .update_all(label_id: new_label_id) end diff --git a/app/services/members/destroy_service.rb b/app/services/members/destroy_service.rb index d0e81da5aab..7e620047c78 100644 --- a/app/services/members/destroy_service.rb +++ b/app/services/members/destroy_service.rb @@ -69,7 +69,7 @@ module Members def enqueue_unassign_issuables(member) source_type = member.is_a?(GroupMember) ? 'Group' : 'Project' - member.run_after_commit do + member.run_after_commit_or_now do MembersDestroyer::UnassignIssuablesWorker.perform_async(member.user_id, member.source_id, source_type) end end diff --git a/app/views/projects/blob/_viewer.html.haml b/app/views/projects/blob/_viewer.html.haml index b9663bbba15..a0d82ffd2c7 100644 --- a/app/views/projects/blob/_viewer.html.haml +++ b/app/views/projects/blob/_viewer.html.haml @@ -5,7 +5,7 @@ - external_embed = local_assigns.fetch(:external_embed, false) - viewer_url = local_assigns.fetch(:viewer_url) { url_for(safe_params.merge(viewer: viewer.type, format: :json)) } if load_async -.blob-viewer{ data: { type: viewer.type, rich_type: rich_type, url: viewer_url }, class: ('hidden' if hidden) } +.blob-viewer{ data: { type: viewer.type, rich_type: rich_type, url: viewer_url, path: viewer.blob.path }, class: ('hidden' if hidden) } - if render_error = render 'projects/blob/render_error', viewer: viewer - elsif load_async diff --git a/app/views/projects/blob/_viewer_switcher.html.haml b/app/views/projects/blob/_viewer_switcher.html.haml index 5e0d70b2ca9..df81e509c85 100644 --- a/app/views/projects/blob/_viewer_switcher.html.haml +++ b/app/views/projects/blob/_viewer_switcher.html.haml @@ -5,8 +5,8 @@ .btn-group.js-blob-viewer-switcher.ml-2{ role: "group" }> - simple_label = "Display #{simple_viewer.switcher_title}" %button.btn.btn-default.btn-sm.js-blob-viewer-switch-btn.has-tooltip{ 'aria-label' => simple_label, title: simple_label, data: { viewer: 'simple', container: 'body' } }> - = icon(simple_viewer.switcher_icon) + = sprite_icon(simple_viewer.switcher_icon) - rich_label = "Display #{rich_viewer.switcher_title}" %button.btn.btn-default.btn-sm.js-blob-viewer-switch-btn.has-tooltip{ 'aria-label' => rich_label, title: rich_label, data: { viewer: 'rich', container: 'body' } }> - = icon(rich_viewer.switcher_icon) + = sprite_icon(rich_viewer.switcher_icon) diff --git a/app/workers/all_queues.yml b/app/workers/all_queues.yml index 6cd258b5fac..96928010773 100644 --- a/app/workers/all_queues.yml +++ b/app/workers/all_queues.yml @@ -5,7 +5,7 @@ --- - :name: authorized_project_update:authorized_project_update_project_create :feature_category: :authentication_and_authorization - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 @@ -13,7 +13,7 @@ :tags: [] - :name: authorized_project_update:authorized_project_update_project_group_link_create :feature_category: :authentication_and_authorization - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 @@ -21,7 +21,7 @@ :tags: [] - :name: authorized_project_update:authorized_project_update_user_refresh_over_user_range :feature_category: :authentication_and_authorization - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 @@ -29,7 +29,7 @@ :tags: [] - :name: authorized_project_update:authorized_project_update_user_refresh_with_low_urgency :feature_category: :authentication_and_authorization - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 @@ -37,87 +37,87 @@ :tags: [] - :name: auto_devops:auto_devops_disable :feature_category: :auto_devops - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 2 - :idempotent: + :idempotent: :tags: [] - :name: auto_merge:auto_merge_process :feature_category: :continuous_delivery - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :cpu :weight: 3 - :idempotent: + :idempotent: :tags: [] - :name: chaos:chaos_cpu_spin :feature_category: :not_owned - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 2 - :idempotent: + :idempotent: :tags: [] - :name: chaos:chaos_db_spin :feature_category: :not_owned - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 2 - :idempotent: + :idempotent: :tags: [] - :name: chaos:chaos_kill :feature_category: :not_owned - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 2 - :idempotent: + :idempotent: :tags: [] - :name: chaos:chaos_leak_mem :feature_category: :not_owned - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 2 - :idempotent: + :idempotent: :tags: [] - :name: chaos:chaos_sleep :feature_category: :not_owned - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 2 - :idempotent: + :idempotent: :tags: [] - :name: container_repository:cleanup_container_repository :feature_category: :container_registry - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: container_repository:delete_container_repository :feature_category: :container_registry - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: cronjob:admin_email :feature_category: :source_code_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: cronjob:authorized_project_update_periodic_recalculate :feature_category: :source_code_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 @@ -125,79 +125,79 @@ :tags: [] - :name: cronjob:ci_archive_traces_cron :feature_category: :continuous_integration - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: cronjob:container_expiration_policy :feature_category: :container_registry - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: cronjob:environments_auto_stop_cron :feature_category: :continuous_delivery - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: cronjob:expire_build_artifacts :feature_category: :continuous_integration - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: cronjob:gitlab_usage_ping :feature_category: :collection - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: cronjob:import_export_project_cleanup :feature_category: :importers - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: cronjob:import_stuck_project_import_jobs :feature_category: :importers - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :cpu :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: cronjob:issue_due_scheduler :feature_category: :issue_tracking - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: cronjob:jira_import_stuck_jira_import_jobs :feature_category: :importers - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :cpu :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: cronjob:metrics_dashboard_schedule_annotations_prune :feature_category: :metrics - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 @@ -205,163 +205,171 @@ :tags: [] - :name: cronjob:namespaces_prune_aggregation_schedules :feature_category: :source_code_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :cpu :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: cronjob:pages_domain_removal_cron :feature_category: :pages - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :cpu :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: cronjob:pages_domain_ssl_renewal_cron :feature_category: :pages - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: cronjob:pages_domain_verification_cron :feature_category: :pages - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: cronjob:personal_access_tokens_expiring :feature_category: :authentication_and_authorization - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: cronjob:pipeline_schedule :feature_category: :continuous_integration - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :cpu :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: cronjob:prune_old_events :feature_category: :users - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: cronjob:prune_web_hook_logs :feature_category: :integrations - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: cronjob:remove_expired_group_links :feature_category: :authentication_and_authorization - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: cronjob:remove_expired_members :feature_category: :authentication_and_authorization - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :cpu :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: cronjob:remove_unreferenced_lfs_objects :feature_category: :git_lfs - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: cronjob:repository_archive_cache :feature_category: :source_code_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: cronjob:repository_check_dispatch :feature_category: :source_code_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: cronjob:requests_profiles :feature_category: :source_code_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: cronjob:schedule_migrate_external_diffs :feature_category: :source_code_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: cronjob:stuck_ci_jobs :feature_category: :continuous_integration - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :cpu :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: cronjob:stuck_export_jobs :feature_category: :importers - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :cpu :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: cronjob:stuck_merge_jobs :feature_category: :source_code_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: cronjob:trending_projects :feature_category: :source_code_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: + :tags: [] +- :name: cronjob:update_container_registry_info + :feature_category: :container_registry + :has_external_dependencies: + :urgency: :low + :resource_boundary: :unknown + :weight: 1 + :idempotent: true :tags: [] - :name: cronjob:users_create_statistics :feature_category: :users - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: cronjob:x509_issuer_crl_check :feature_category: :source_code_management @@ -373,27 +381,27 @@ :tags: [] - :name: deployment:deployments_finished :feature_category: :continuous_delivery - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :cpu :weight: 3 - :idempotent: + :idempotent: :tags: [] - :name: deployment:deployments_forward_deployment :feature_category: :continuous_delivery - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 3 - :idempotent: + :idempotent: :tags: [] - :name: deployment:deployments_success :feature_category: :continuous_delivery - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :cpu :weight: 3 - :idempotent: + :idempotent: :tags: [] - :name: gcp_cluster:cluster_configure_istio :feature_category: :kubernetes_management @@ -401,7 +409,7 @@ :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: gcp_cluster:cluster_install_app :feature_category: :kubernetes_management @@ -409,7 +417,7 @@ :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: gcp_cluster:cluster_patch_app :feature_category: :kubernetes_management @@ -417,7 +425,7 @@ :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: gcp_cluster:cluster_provision :feature_category: :kubernetes_management @@ -425,15 +433,15 @@ :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: gcp_cluster:cluster_update_app :feature_category: :kubernetes_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: gcp_cluster:cluster_upgrade_app :feature_category: :kubernetes_management @@ -441,7 +449,7 @@ :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: gcp_cluster:cluster_wait_for_app_installation :feature_category: :kubernetes_management @@ -449,15 +457,15 @@ :urgency: :low :resource_boundary: :cpu :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: gcp_cluster:cluster_wait_for_app_update :feature_category: :kubernetes_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: gcp_cluster:cluster_wait_for_ingress_ip_address :feature_category: :kubernetes_management @@ -465,23 +473,23 @@ :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: gcp_cluster:clusters_applications_activate_service :feature_category: :kubernetes_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: gcp_cluster:clusters_applications_deactivate_service :feature_category: :kubernetes_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: gcp_cluster:clusters_applications_uninstall :feature_category: :kubernetes_management @@ -489,7 +497,7 @@ :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: gcp_cluster:clusters_applications_wait_for_uninstall_app :feature_category: :kubernetes_management @@ -497,7 +505,7 @@ :urgency: :low :resource_boundary: :cpu :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: gcp_cluster:clusters_cleanup_app :feature_category: :kubernetes_management @@ -505,7 +513,7 @@ :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: gcp_cluster:clusters_cleanup_project_namespace :feature_category: :kubernetes_management @@ -513,7 +521,7 @@ :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: gcp_cluster:clusters_cleanup_service_account :feature_category: :kubernetes_management @@ -521,7 +529,7 @@ :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: gcp_cluster:wait_for_cluster_creation :feature_category: :kubernetes_management @@ -529,7 +537,7 @@ :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: github_importer:github_import_import_diff_note :feature_category: :importers @@ -537,7 +545,7 @@ :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: github_importer:github_import_import_issue :feature_category: :importers @@ -545,7 +553,7 @@ :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: github_importer:github_import_import_lfs_object :feature_category: :importers @@ -553,7 +561,7 @@ :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: github_importer:github_import_import_note :feature_category: :importers @@ -561,7 +569,7 @@ :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: github_importer:github_import_import_pull_request :feature_category: :importers @@ -569,103 +577,103 @@ :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: github_importer:github_import_refresh_import_jid :feature_category: :importers - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: github_importer:github_import_stage_finish_import :feature_category: :importers - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: github_importer:github_import_stage_import_base_data :feature_category: :importers - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: github_importer:github_import_stage_import_issues_and_diff_notes :feature_category: :importers - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: github_importer:github_import_stage_import_lfs_objects :feature_category: :importers - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: github_importer:github_import_stage_import_notes :feature_category: :importers - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: github_importer:github_import_stage_import_pull_requests :feature_category: :importers - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: github_importer:github_import_stage_import_repository :feature_category: :importers - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: hashed_storage:hashed_storage_migrator :feature_category: :source_code_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: hashed_storage:hashed_storage_project_migrate :feature_category: :source_code_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: hashed_storage:hashed_storage_project_rollback :feature_category: :source_code_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: hashed_storage:hashed_storage_rollbacker :feature_category: :source_code_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: incident_management:clusters_applications_check_prometheus_health :feature_category: :incident_management @@ -677,159 +685,159 @@ :tags: [] - :name: incident_management:incident_management_process_alert :feature_category: :incident_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 2 - :idempotent: + :idempotent: :tags: [] - :name: incident_management:incident_management_process_prometheus_alert :feature_category: :incident_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :cpu :weight: 2 - :idempotent: + :idempotent: :tags: [] - :name: jira_importer:jira_import_advance_stage :feature_category: :importers - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: jira_importer:jira_import_import_issue :feature_category: :importers - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: jira_importer:jira_import_stage_finish_import :feature_category: :importers - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: jira_importer:jira_import_stage_import_attachments :feature_category: :importers - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: jira_importer:jira_import_stage_import_issues :feature_category: :importers - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: jira_importer:jira_import_stage_import_labels :feature_category: :importers - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: jira_importer:jira_import_stage_import_notes :feature_category: :importers - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: jira_importer:jira_import_stage_start_import :feature_category: :importers - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: mail_scheduler:mail_scheduler_issue_due :feature_category: :issue_tracking - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 2 - :idempotent: + :idempotent: :tags: [] - :name: mail_scheduler:mail_scheduler_notification_service :feature_category: :issue_tracking - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :cpu :weight: 2 - :idempotent: + :idempotent: :tags: [] - :name: object_pool:object_pool_create :feature_category: :gitaly - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: object_pool:object_pool_destroy :feature_category: :gitaly - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: object_pool:object_pool_join :feature_category: :gitaly - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :cpu :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: object_pool:object_pool_schedule_join :feature_category: :gitaly - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: object_storage:object_storage_background_move :feature_category: :not_owned - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: object_storage:object_storage_migrate_uploads :feature_category: :not_owned - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: pipeline_background:archive_trace :feature_category: :continuous_integration - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: pipeline_background:ci_build_report_result :feature_category: :continuous_integration - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 @@ -837,15 +845,15 @@ :tags: [] - :name: pipeline_background:ci_build_trace_chunk_flush :feature_category: :continuous_integration - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: pipeline_background:ci_daily_build_group_report_results :feature_category: :continuous_integration - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 @@ -853,7 +861,7 @@ :tags: [] - :name: pipeline_cache:expire_job_cache :feature_category: :continuous_integration - :has_external_dependencies: + :has_external_dependencies: :urgency: :high :resource_boundary: :unknown :weight: 3 @@ -861,7 +869,7 @@ :tags: [] - :name: pipeline_cache:expire_pipeline_cache :feature_category: :continuous_integration - :has_external_dependencies: + :has_external_dependencies: :urgency: :high :resource_boundary: :cpu :weight: 3 @@ -869,152 +877,152 @@ :tags: [] - :name: pipeline_creation:create_pipeline :feature_category: :continuous_integration - :has_external_dependencies: + :has_external_dependencies: :urgency: :high :resource_boundary: :cpu :weight: 4 - :idempotent: + :idempotent: :tags: [] - :name: pipeline_creation:run_pipeline_schedule :feature_category: :continuous_integration - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 4 - :idempotent: + :idempotent: :tags: [] - :name: pipeline_default:build_coverage :feature_category: :continuous_integration - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 3 - :idempotent: + :idempotent: :tags: [] - :name: pipeline_default:build_trace_sections :feature_category: :continuous_integration - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 3 - :idempotent: + :idempotent: :tags: [] - :name: pipeline_default:ci_create_cross_project_pipeline :feature_category: :continuous_integration - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :cpu :weight: 3 - :idempotent: + :idempotent: :tags: [] - :name: pipeline_default:ci_pipeline_bridge_status :feature_category: :continuous_integration - :has_external_dependencies: + :has_external_dependencies: :urgency: :high :resource_boundary: :cpu :weight: 3 - :idempotent: + :idempotent: :tags: [] - :name: pipeline_default:pipeline_metrics :feature_category: :continuous_integration - :has_external_dependencies: + :has_external_dependencies: :urgency: :high :resource_boundary: :unknown :weight: 3 - :idempotent: + :idempotent: :tags: [] - :name: pipeline_default:pipeline_notification :feature_category: :continuous_integration - :has_external_dependencies: + :has_external_dependencies: :urgency: :high :resource_boundary: :cpu :weight: 3 - :idempotent: + :idempotent: :tags: [] - :name: pipeline_default:pipeline_update_ci_ref_status :feature_category: :continuous_integration - :has_external_dependencies: + :has_external_dependencies: :urgency: :high :resource_boundary: :cpu :weight: 3 - :idempotent: + :idempotent: :tags: [] - :name: pipeline_hooks:build_hooks :feature_category: :continuous_integration - :has_external_dependencies: + :has_external_dependencies: :urgency: :high :resource_boundary: :unknown :weight: 2 - :idempotent: + :idempotent: :tags: [] - :name: pipeline_hooks:pipeline_hooks :feature_category: :continuous_integration - :has_external_dependencies: + :has_external_dependencies: :urgency: :high :resource_boundary: :cpu :weight: 2 - :idempotent: + :idempotent: :tags: [] - :name: pipeline_processing:build_finished :feature_category: :continuous_integration - :has_external_dependencies: + :has_external_dependencies: :urgency: :high :resource_boundary: :cpu :weight: 5 - :idempotent: + :idempotent: :tags: - :requires_disk_io - :name: pipeline_processing:build_queue :feature_category: :continuous_integration - :has_external_dependencies: + :has_external_dependencies: :urgency: :high :resource_boundary: :cpu :weight: 5 - :idempotent: + :idempotent: :tags: [] - :name: pipeline_processing:build_success :feature_category: :continuous_integration - :has_external_dependencies: + :has_external_dependencies: :urgency: :high :resource_boundary: :unknown :weight: 5 - :idempotent: + :idempotent: :tags: [] - :name: pipeline_processing:ci_build_prepare :feature_category: :continuous_integration - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 5 - :idempotent: + :idempotent: :tags: [] - :name: pipeline_processing:ci_build_schedule :feature_category: :continuous_integration - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :cpu :weight: 5 - :idempotent: + :idempotent: :tags: [] - :name: pipeline_processing:ci_resource_groups_assign_resource_from_resource_group :feature_category: :continuous_delivery - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 5 - :idempotent: + :idempotent: :tags: [] - :name: pipeline_processing:pipeline_process :feature_category: :continuous_integration - :has_external_dependencies: + :has_external_dependencies: :urgency: :high :resource_boundary: :unknown :weight: 5 - :idempotent: + :idempotent: :tags: [] - :name: pipeline_processing:pipeline_update :feature_category: :continuous_integration - :has_external_dependencies: + :has_external_dependencies: :urgency: :high :resource_boundary: :unknown :weight: 5 @@ -1022,7 +1030,7 @@ :tags: [] - :name: pipeline_processing:stage_update :feature_category: :continuous_integration - :has_external_dependencies: + :has_external_dependencies: :urgency: :high :resource_boundary: :unknown :weight: 5 @@ -1030,7 +1038,7 @@ :tags: [] - :name: pipeline_processing:update_head_pipeline_for_merge_request :feature_category: :continuous_integration - :has_external_dependencies: + :has_external_dependencies: :urgency: :high :resource_boundary: :cpu :weight: 5 @@ -1038,71 +1046,71 @@ :tags: [] - :name: repository_check:repository_check_batch :feature_category: :source_code_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: repository_check:repository_check_clear :feature_category: :source_code_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: repository_check:repository_check_single_repository :feature_category: :source_code_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: todos_destroyer:todos_destroyer_confidential_issue :feature_category: :issue_tracking - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: todos_destroyer:todos_destroyer_entity_leave :feature_category: :issue_tracking - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: todos_destroyer:todos_destroyer_group_private :feature_category: :issue_tracking - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: todos_destroyer:todos_destroyer_private_features :feature_category: :issue_tracking - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: todos_destroyer:todos_destroyer_project_private :feature_category: :issue_tracking - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: unassign_issuables:members_destroyer_unassign_issuables :feature_category: :authentication_and_authorization - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 @@ -1110,7 +1118,7 @@ :tags: [] - :name: update_namespace_statistics:namespaces_root_statistics :feature_category: :source_code_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 @@ -1118,7 +1126,7 @@ :tags: [] - :name: update_namespace_statistics:namespaces_schedule_aggregation :feature_category: :source_code_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 @@ -1126,7 +1134,7 @@ :tags: [] - :name: authorized_keys :feature_category: :source_code_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :high :resource_boundary: :unknown :weight: 2 @@ -1134,7 +1142,7 @@ :tags: [] - :name: authorized_projects :feature_category: :authentication_and_authorization - :has_external_dependencies: + :has_external_dependencies: :urgency: :high :resource_boundary: :unknown :weight: 2 @@ -1142,11 +1150,11 @@ :tags: [] - :name: background_migration :feature_category: :database - :has_external_dependencies: + :has_external_dependencies: :urgency: :throttled :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: chat_notification :feature_category: :chatops @@ -1154,11 +1162,11 @@ :urgency: :low :resource_boundary: :unknown :weight: 2 - :idempotent: + :idempotent: :tags: [] - :name: create_commit_signature :feature_category: :source_code_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 2 @@ -1166,91 +1174,91 @@ :tags: [] - :name: create_evidence :feature_category: :release_evidence - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 2 - :idempotent: + :idempotent: :tags: [] - :name: create_note_diff_file :feature_category: :source_code_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: default - :feature_category: - :has_external_dependencies: - :urgency: - :resource_boundary: + :feature_category: + :has_external_dependencies: + :urgency: + :resource_boundary: :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: delete_diff_files :feature_category: :source_code_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: delete_merged_branches :feature_category: :source_code_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: delete_stored_files :feature_category: :not_owned - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: delete_user :feature_category: :authentication_and_authorization - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: design_management_new_version :feature_category: :design_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :memory :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: detect_repository_languages :feature_category: :source_code_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: email_receiver :feature_category: :issue_tracking - :has_external_dependencies: + :has_external_dependencies: :urgency: :high :resource_boundary: :unknown :weight: 2 - :idempotent: + :idempotent: :tags: [] - :name: emails_on_push :feature_category: :source_code_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :cpu :weight: 2 - :idempotent: + :idempotent: :tags: [] - :name: error_tracking_issue_link :feature_category: :error_tracking @@ -1258,23 +1266,23 @@ :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: expire_build_instance_artifacts :feature_category: :continuous_integration - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: export_csv :feature_category: :issue_tracking - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :cpu :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: external_service_reactive_caching :feature_category: :not_owned @@ -1282,107 +1290,107 @@ :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: file_hook :feature_category: :integrations - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: git_garbage_collect :feature_category: :gitaly - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: github_import_advance_stage :feature_category: :importers - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: gitlab_shell :feature_category: :source_code_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :high :resource_boundary: :unknown :weight: 2 - :idempotent: + :idempotent: :tags: [] - :name: group_destroy :feature_category: :subgroups - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: group_export :feature_category: :importers - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: group_import :feature_category: :importers - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: import_issues_csv :feature_category: :issue_tracking - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :cpu :weight: 2 - :idempotent: + :idempotent: :tags: [] - :name: invalid_gpg_signature_update :feature_category: :source_code_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 2 - :idempotent: + :idempotent: :tags: [] - :name: irker :feature_category: :integrations - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: mailers - :feature_category: - :has_external_dependencies: - :urgency: - :resource_boundary: + :feature_category: + :has_external_dependencies: + :urgency: + :resource_boundary: :weight: 2 - :idempotent: + :idempotent: :tags: [] - :name: merge :feature_category: :source_code_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :high :resource_boundary: :unknown :weight: 5 - :idempotent: + :idempotent: :tags: [] - :name: merge_request_mergeability_check :feature_category: :source_code_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 @@ -1390,7 +1398,7 @@ :tags: [] - :name: metrics_dashboard_prune_old_annotations :feature_category: :metrics - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 @@ -1398,87 +1406,87 @@ :tags: [] - :name: migrate_external_diffs :feature_category: :source_code_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: namespaceless_project_destroy :feature_category: :authentication_and_authorization - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: new_issue :feature_category: :issue_tracking - :has_external_dependencies: + :has_external_dependencies: :urgency: :high :resource_boundary: :cpu :weight: 2 - :idempotent: + :idempotent: :tags: [] - :name: new_merge_request :feature_category: :source_code_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :high :resource_boundary: :cpu :weight: 2 - :idempotent: + :idempotent: :tags: [] - :name: new_note :feature_category: :issue_tracking - :has_external_dependencies: + :has_external_dependencies: :urgency: :high :resource_boundary: :cpu :weight: 2 - :idempotent: + :idempotent: :tags: [] - :name: pages :feature_category: :pages - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: pages_domain_ssl_renewal :feature_category: :pages - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: pages_domain_verification :feature_category: :pages - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: phabricator_import_import_tasks :feature_category: :importers - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: post_receive :feature_category: :source_code_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :high :resource_boundary: :cpu :weight: 5 - :idempotent: + :idempotent: :tags: [] - :name: process_commit :feature_category: :source_code_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :high :resource_boundary: :unknown :weight: 3 @@ -1486,35 +1494,35 @@ :tags: [] - :name: project_cache :feature_category: :source_code_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :high :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: project_daily_statistics :feature_category: :source_code_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: project_destroy :feature_category: :source_code_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: project_export :feature_category: :importers - :has_external_dependencies: + :has_external_dependencies: :urgency: :throttled :resource_boundary: :memory :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: project_service :feature_category: :integrations @@ -1522,11 +1530,11 @@ :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: project_update_repository_storage :feature_category: :gitaly - :has_external_dependencies: + :has_external_dependencies: :urgency: :throttled :resource_boundary: :unknown :weight: 1 @@ -1534,7 +1542,7 @@ :tags: [] - :name: prometheus_create_default_alerts :feature_category: :incident_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :high :resource_boundary: :unknown :weight: 1 @@ -1542,7 +1550,7 @@ :tags: [] - :name: propagate_integration :feature_category: :integrations - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 @@ -1550,51 +1558,51 @@ :tags: [] - :name: propagate_service_template :feature_category: :source_code_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: reactive_caching :feature_category: :not_owned - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :cpu :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: rebase :feature_category: :source_code_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 2 - :idempotent: + :idempotent: :tags: [] - :name: remote_mirror_notification :feature_category: :source_code_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 2 - :idempotent: + :idempotent: :tags: [] - :name: repository_cleanup :feature_category: :source_code_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: repository_fork :feature_category: :source_code_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: repository_import :feature_category: :importers @@ -1602,15 +1610,15 @@ :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: repository_remove_remote :feature_category: :source_code_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: repository_update_remote_mirror :feature_category: :source_code_management @@ -1618,43 +1626,43 @@ :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: self_monitoring_project_create :feature_category: :metrics - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 2 - :idempotent: + :idempotent: :tags: [] - :name: self_monitoring_project_delete :feature_category: :metrics - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 2 - :idempotent: + :idempotent: :tags: [] - :name: system_hook_push :feature_category: :source_code_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: update_external_pull_requests :feature_category: :source_code_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 3 - :idempotent: + :idempotent: :tags: [] - :name: update_highest_role :feature_category: :authentication_and_authorization - :has_external_dependencies: + :has_external_dependencies: :urgency: :high :resource_boundary: :unknown :weight: 2 @@ -1662,27 +1670,27 @@ :tags: [] - :name: update_merge_requests :feature_category: :source_code_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :high :resource_boundary: :cpu :weight: 3 - :idempotent: + :idempotent: :tags: [] - :name: update_project_statistics :feature_category: :source_code_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: upload_checksum :feature_category: :geo_replication - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: web_hook :feature_category: :integrations @@ -1690,11 +1698,11 @@ :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: x509_certificate_revoke :feature_category: :source_code_management - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 diff --git a/app/workers/update_container_registry_info_worker.rb b/app/workers/update_container_registry_info_worker.rb new file mode 100644 index 00000000000..14a816f25ef --- /dev/null +++ b/app/workers/update_container_registry_info_worker.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +class UpdateContainerRegistryInfoWorker + include ApplicationWorker + include CronjobQueue # rubocop:disable Scalability/CronWorkerContext + + feature_category :container_registry + urgency :low + + idempotent! + + def perform + UpdateContainerRegistryInfoService.new.execute + end +end diff --git a/changelogs/unreleased/204839-move-update-logic-to-service.yml b/changelogs/unreleased/204839-move-update-logic-to-service.yml new file mode 100644 index 00000000000..528be73e097 --- /dev/null +++ b/changelogs/unreleased/204839-move-update-logic-to-service.yml @@ -0,0 +1,5 @@ +--- +title: Periodically update container registry type settings +merge_request: 36415 +author: +type: added diff --git a/changelogs/unreleased/220124-drop-temp-index-on-audit-events.yml b/changelogs/unreleased/220124-drop-temp-index-on-audit-events.yml new file mode 100644 index 00000000000..d2f86aae5ec --- /dev/null +++ b/changelogs/unreleased/220124-drop-temp-index-on-audit-events.yml @@ -0,0 +1,5 @@ +--- +title: Drop index of ruby objects in details on audit_events table +merge_request: 36547 +author: +type: other diff --git a/changelogs/unreleased/223151-adjust-unique-index-on-alerts.yml b/changelogs/unreleased/223151-adjust-unique-index-on-alerts.yml new file mode 100644 index 00000000000..d0033403da4 --- /dev/null +++ b/changelogs/unreleased/223151-adjust-unique-index-on-alerts.yml @@ -0,0 +1,5 @@ +--- +title: Change Alert fingerprint index to run when status is not resolved +merge_request: 36024 +author: +type: changed diff --git a/changelogs/unreleased/227863-fix-api-error-on-null-bio.yml b/changelogs/unreleased/227863-fix-api-error-on-null-bio.yml new file mode 100644 index 00000000000..75fc9609e19 --- /dev/null +++ b/changelogs/unreleased/227863-fix-api-error-on-null-bio.yml @@ -0,0 +1,5 @@ +--- +title: Fix API errors when null value is given for the bio +merge_request: 36650 +author: +type: fixed diff --git a/changelogs/unreleased/feat-use-new-api-icon.yml b/changelogs/unreleased/feat-use-new-api-icon.yml new file mode 100644 index 00000000000..f45279946b8 --- /dev/null +++ b/changelogs/unreleased/feat-use-new-api-icon.yml @@ -0,0 +1,5 @@ +--- +title: Use new icon for api preview +merge_request: 34700 +author: Roger Meier +type: added diff --git a/changelogs/unreleased/ph-codeNavigationUXImprovements.yml b/changelogs/unreleased/ph-codeNavigationUXImprovements.yml new file mode 100644 index 00000000000..07c599dbdc9 --- /dev/null +++ b/changelogs/unreleased/ph-codeNavigationUXImprovements.yml @@ -0,0 +1,5 @@ +--- +title: Improved UX of the code navigation popover +merge_request: +author: +type: changed diff --git a/changelogs/unreleased/run-unassign-issuables-worker-when-out-of-transaction.yml b/changelogs/unreleased/run-unassign-issuables-worker-when-out-of-transaction.yml new file mode 100644 index 00000000000..c858df2f15d --- /dev/null +++ b/changelogs/unreleased/run-unassign-issuables-worker-when-out-of-transaction.yml @@ -0,0 +1,5 @@ +--- +title: Ensure to run unassign issuables worker when not in a transaction +merge_request: 36680 +author: +type: fixed diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index 1a2401c3396..a04b1b60814 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -500,6 +500,9 @@ Settings.cron_jobs['users_create_statistics_worker']['job_class'] = 'Users::Crea Settings.cron_jobs['authorized_project_update_periodic_recalculate_worker'] ||= Settingslogic.new({}) Settings.cron_jobs['authorized_project_update_periodic_recalculate_worker']['cron'] ||= '45 1 * * 6' Settings.cron_jobs['authorized_project_update_periodic_recalculate_worker']['job_class'] = 'AuthorizedProjectUpdate::PeriodicRecalculateWorker' +Settings.cron_jobs['update_container_registry_info_worker'] ||= Settingslogic.new({}) +Settings.cron_jobs['update_container_registry_info_worker']['cron'] ||= '0 0 * * *' +Settings.cron_jobs['update_container_registry_info_worker']['job_class'] = 'UpdateContainerRegistryInfoWorker' Gitlab.ee do Settings.cron_jobs['adjourned_group_deletion_worker'] ||= Settingslogic.new({}) diff --git a/db/migrate/20200706035141_adjust_unique_index_alert_management_alerts.rb b/db/migrate/20200706035141_adjust_unique_index_alert_management_alerts.rb new file mode 100644 index 00000000000..0a6e614be9a --- /dev/null +++ b/db/migrate/20200706035141_adjust_unique_index_alert_management_alerts.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +class AdjustUniqueIndexAlertManagementAlerts < ActiveRecord::Migration[6.0] + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + INDEX_NAME = 'index_alert_management_alerts_on_project_id_and_fingerprint' + NEW_INDEX_NAME = 'index_partial_am_alerts_on_project_id_and_fingerprint' + RESOLVED_STATUS = 2 + + disable_ddl_transaction! + + def up + add_concurrent_index(:alert_management_alerts, %w(project_id fingerprint), where: "status <> #{RESOLVED_STATUS}", name: NEW_INDEX_NAME, unique: true, using: :btree) + remove_concurrent_index_by_name :alert_management_alerts, INDEX_NAME + end + + def down + # Nullify duplicate fingerprints, except for the newest of each match (project_id, fingerprint). + query = <<-SQL + UPDATE alert_management_alerts am + SET fingerprint = NULL + WHERE am.created_at <> + (SELECT MAX(created_at) + FROM alert_management_alerts am2 + WHERE am.fingerprint = am2.fingerprint AND am.project_id = am2.project_id) + AND am.fingerprint IS NOT NULL; + SQL + + execute(query) + + remove_concurrent_index_by_name :alert_management_alerts, NEW_INDEX_NAME + add_concurrent_index(:alert_management_alerts, %w(project_id fingerprint), name: INDEX_NAME, unique: true, using: :btree) + end +end diff --git a/db/post_migrate/20200710102846_drop_index_ruby_objects_in_details_on_audit_events.rb b/db/post_migrate/20200710102846_drop_index_ruby_objects_in_details_on_audit_events.rb new file mode 100644 index 00000000000..6869938466a --- /dev/null +++ b/db/post_migrate/20200710102846_drop_index_ruby_objects_in_details_on_audit_events.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +class DropIndexRubyObjectsInDetailsOnAuditEvents < ActiveRecord::Migration[6.0] + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + INDEX_NAME = 'index_audit_events_on_ruby_object_in_details' + + disable_ddl_transaction! + + def up + remove_concurrent_index_by_name(:audit_events, INDEX_NAME) + end + + def down + add_concurrent_index(:audit_events, :id, where: "details ~~ '%ruby/object%'", name: INDEX_NAME) + end +end diff --git a/db/structure.sql b/db/structure.sql index 03f5b95313e..5519f7150ca 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -18505,8 +18505,6 @@ CREATE INDEX index_alert_management_alerts_on_environment_id ON public.alert_man CREATE INDEX index_alert_management_alerts_on_issue_id ON public.alert_management_alerts USING btree (issue_id); -CREATE UNIQUE INDEX index_alert_management_alerts_on_project_id_and_fingerprint ON public.alert_management_alerts USING btree (project_id, fingerprint); - CREATE UNIQUE INDEX index_alert_management_alerts_on_project_id_and_iid ON public.alert_management_alerts USING btree (project_id, iid); CREATE INDEX index_alert_management_alerts_on_prometheus_alert_id ON public.alert_management_alerts USING btree (prometheus_alert_id) WHERE (prometheus_alert_id IS NOT NULL); @@ -18609,8 +18607,6 @@ CREATE INDEX index_approvers_on_user_id ON public.approvers USING btree (user_id CREATE INDEX index_audit_events_on_entity_id_entity_type_id_desc_author_id ON public.audit_events USING btree (entity_id, entity_type, id DESC, author_id); -CREATE INDEX index_audit_events_on_ruby_object_in_details ON public.audit_events USING btree (id) WHERE (details ~~ '%ruby/object%'::text); - CREATE INDEX index_award_emoji_on_awardable_type_and_awardable_id ON public.award_emoji USING btree (awardable_type, awardable_id); CREATE INDEX index_award_emoji_on_user_id_and_name ON public.award_emoji USING btree (user_id, name); @@ -19755,6 +19751,8 @@ CREATE INDEX index_pages_domains_on_verified_at_and_enabled_until ON public.page CREATE INDEX index_pages_domains_on_wildcard ON public.pages_domains USING btree (wildcard); +CREATE UNIQUE INDEX index_partial_am_alerts_on_project_id_and_fingerprint ON public.alert_management_alerts USING btree (project_id, fingerprint) WHERE (status <> 2); + CREATE UNIQUE INDEX index_partitioned_foreign_keys_unique_index ON public.partitioned_foreign_keys USING btree (to_table, from_table, from_column); CREATE INDEX index_pat_on_user_id_and_expires_at ON public.personal_access_tokens USING btree (user_id, expires_at); @@ -23641,10 +23639,12 @@ COPY "schema_migrations" (version) FROM STDIN; 20200704143633 20200704161600 20200706005325 +20200706035141 20200706154619 20200706170536 20200707071941 20200707094341 20200707095849 +20200710102846 \. diff --git a/doc/administration/geo/replication/disable_geo.md b/doc/administration/geo/replication/disable_geo.md new file mode 100644 index 00000000000..f53b4c1b796 --- /dev/null +++ b/doc/administration/geo/replication/disable_geo.md @@ -0,0 +1,93 @@ +--- +stage: Enablement +group: Geo +info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers +type: howto +--- + +# Disabling Geo **(PREMIUM ONLY)** + +If you want to revert to a regular Omnibus setup after a test, or you have encountered a Disaster Recovery +situation and you want to disable Geo momentarily, you can use these instructions to disable your +Geo setup. + +There should be no functional difference between disabling Geo and having an active Geo setup with +no secondary Geo nodes if you remove them correctly. + +To disable Geo, follow these steps: + +1. [Remove all secondary Geo nodes](#remove-all-secondary-geo-nodes). +1. [Remove the primary node from the UI](#remove-the-primary-node-from-the-ui). +1. [Remove secondary replication slots](#remove-secondary-replication-slots). +1. [Remove Geo-related configuration](#remove-geo-related-configuration). +1. [(Optional) Revert PostgreSQL settings to use a password and listen on an IP](#optional-revert-postgresql-settings-to-use-a-password-and-listen-on-an-ip). + +## Remove all secondary Geo nodes + +To disable Geo, you need to first remove all your secondary Geo nodes, which means replication will not happen +anymore on these nodes. You can follow our docs to [remove your secondary Geo nodes](./remove_geo_node.md). + +If the current node that you want to keep using is a secondary node, you need to first promote it to primary. +You can use our steps on [how to promote a secondary node](../disaster_recovery/#step-3-promoting-a-secondary-node) +in order to do that. + +## Remove the primary node from the UI + +1. Go to **{admin}** **Admin Area >** **{location-dot}** **Geo** (`/admin/geo/nodes`). +1. Click the **Remove** button for the **primary** node. +1. Confirm by clicking **Remove** when the prompt appears. + +## Remove secondary replication slots + +To remove secondary replication slots, run one of the following queries on your primary +Geo node in a PostgreSQL console (`sudo gitlab-psql`): + +- If you already have a PostgreSQL cluster, drop individual replication slots by name to prevent + removing your secondary databases from the same cluster. You can use the following to get + all names and then drop each individual slot: + + ```sql + SELECT slot_name, slot_type, active FROM pg_replication_slots; -- view present replication slots + SELECT pg_drop_replication_slot('slot_name'); -- where slot_name is the one expected from above + ``` + +- To remove all secondary replication slots: + + ```sql + SELECT pg_drop_replication_slot(slot_name) FROM pg_replication_slots; + ``` + +## Remove Geo-related configuration + +1. SSH into your primary Geo node and log in as root: + + ```shell + sudo -i + ``` + +1. Edit `/etc/gitlab/gitlab.rb` and remove the Geo related configuration by + removing any lines that enabled `geo_primary_role`: + + ```ruby + ## In pre-11.5 documentation, the role was enabled as follows. Remove this line. + geo_primary_role['enable'] = true + + ## In 11.5+ documentation, the role was enabled as follows. Remove this line. + roles ['geo_primary_role'] + ``` + +1. After making these changes, [reconfigure GitLab](../../restart_gitlab.md#omnibus-gitlab-reconfigure) + for the changes to take effect. + +## (Optional) Revert PostgreSQL settings to use a password and listen on an IP + +If you want to remove the PostgreSQL-specific settings and revert +to the defaults (using a socket instead), you can safely remove the following +lines from the `/etc/gitlab/gitlab.rb` file: + +```ruby +postgresql['sql_user_password'] = '...' +gitlab_rails['db_password'] = '...' +postgresql['listen_address'] = '...' +postgresql['md5_auth_cidr_addresses'] = ['...', '...'] +``` diff --git a/doc/administration/geo/replication/index.md b/doc/administration/geo/replication/index.md index 2acebe6ff00..51c831abaf3 100644 --- a/doc/administration/geo/replication/index.md +++ b/doc/administration/geo/replication/index.md @@ -265,6 +265,10 @@ For an example of how to set up a location-aware Git remote URL with AWS Route53 For more information on removing a Geo node, see [Removing **secondary** Geo nodes](remove_geo_node.md). +## Disable Geo + +To find out how to disable Geo, see [Disabling Geo](disable_geo.md). + ## Current limitations CAUTION: **Caution:** diff --git a/doc/administration/monitoring/prometheus/gitlab_metrics.md b/doc/administration/monitoring/prometheus/gitlab_metrics.md index c07e874c40e..7b633b4d926 100644 --- a/doc/administration/monitoring/prometheus/gitlab_metrics.md +++ b/doc/administration/monitoring/prometheus/gitlab_metrics.md @@ -264,6 +264,7 @@ instance (`cache`, `shared_state` etc.). |:--------------------------------- |:------- |:----- |:----------- | | `gitlab_redis_client_exceptions_total` | Counter | 13.2 | Number of Redis client exceptions, broken down by exception class | | `gitlab_redis_client_requests_total` | Counter | 13.2 | Number of Redis client requests | +| `gitlab_redis_client_requests_duration_seconds` | Histogram | 13.2 | Redis request latency, excluding blocking commands | ## Metrics shared directory diff --git a/doc/api/users.md b/doc/api/users.md index 15f99367b2e..a6ae4f384aa 100644 --- a/doc/api/users.md +++ b/doc/api/users.md @@ -89,8 +89,8 @@ GET /users "web_url": "http://localhost:3000/john_smith", "created_at": "2012-05-23T08:00:58Z", "is_admin": false, - "bio": null, - "bio_html": null, + "bio": "", + "bio_html": "", "location": null, "skype": "", "linkedin": "", @@ -129,8 +129,8 @@ GET /users "web_url": "http://localhost:3000/jack_smith", "created_at": "2012-05-23T08:01:01Z", "is_admin": false, - "bio": null, - "bio_html": null, + "bio": "", + "bio_html": "", "location": null, "skype": "", "linkedin": "", @@ -247,8 +247,8 @@ Parameters: "avatar_url": "http://localhost:3000/uploads/user/avatar/1/cd8.jpeg", "web_url": "http://localhost:3000/john_smith", "created_at": "2012-05-23T08:00:58Z", - "bio": null, - "bio_html": null, + "bio": "", + "bio_html": "", "location": null, "public_email": "john@example.com", "skype": "", @@ -283,8 +283,8 @@ Example Responses: "web_url": "http://localhost:3000/john_smith", "created_at": "2012-05-23T08:00:58Z", "is_admin": false, - "bio": null, - "bio_html": null, + "bio": "", + "bio_html": "", "location": null, "public_email": "john@example.com", "skype": "", @@ -372,6 +372,9 @@ over `password`. In addition, `reset_password` and NOTE: **Note:** From [GitLab 12.1](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/29888/), `private_profile` will default to `false`. +NOTE: **Note:** +From [GitLab 13.2](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/35604), `bio` will default to `""` instead of `null`. + ```plaintext POST /users ``` @@ -503,8 +506,8 @@ GET /user "avatar_url": "http://localhost:3000/uploads/user/avatar/1/index.jpg", "web_url": "http://localhost:3000/john_smith", "created_at": "2012-05-23T08:00:58Z", - "bio": null, - "bio_html": null, + "bio": "", + "bio_html": "", "location": null, "public_email": "john@example.com", "skype": "", @@ -553,8 +556,8 @@ GET /user "web_url": "http://localhost:3000/john_smith", "created_at": "2012-05-23T08:00:58Z", "is_admin": false, - "bio": null, - "bio_html": null, + "bio": "", + "bio_html": "", "location": null, "public_email": "john@example.com", "skype": "", diff --git a/doc/integration/recaptcha.md b/doc/integration/recaptcha.md index bf2e6568ea6..48c83f1393b 100644 --- a/doc/integration/recaptcha.md +++ b/doc/integration/recaptcha.md @@ -15,6 +15,12 @@ To use reCAPTCHA, first you must create a site and private key. 1. Fill all reCAPTCHA fields with keys from previous steps. 1. Check the `Enable reCAPTCHA` checkbox. 1. Save the configuration. +1. Change the first line of the `#execute` method in `app/services/spam/spam_verdict_service.rb` + to `return CONDITONAL_ALLOW` so that the spam check short-circuits and triggers the response to + return `recaptcha_html`. + +NOTE: **Note:** +Make sure you are viewing an issuable in a project that is public, and if you're working with an issue, the issue is public. ## Enabling reCAPTCHA for user logins via passwords diff --git a/doc/user/group/index.md b/doc/user/group/index.md index 77ccf342e5a..1db9105c9ab 100644 --- a/doc/user/group/index.md +++ b/doc/user/group/index.md @@ -184,6 +184,33 @@ of a group: 1. Give a different member **Owner** permissions. 1. Have the new owner sign in and remove **Owner** permissions from you. +## Remove a member from the group + +Only users with permissions of [Owner](../permissions.md#group-members-permissions) can manage +group members. + +You can remove a member from the group if the given member has a direct membership in the group. If +membership is inherited from a parent group, then the member can be removed only from the parent +group itself. + +When removing a member, you can decide whether to unassign the user from all issues and merge +requests they are currently assigned or leave the assignments as they are. + +- **Unassigning the removed member** from all issues and merge requests might be helpful when a user + is leaving a private group and you wish to revoke their access to any issues and merge requests + they are assigned. +- **Keeping the issues and merge requests assigned** might be helpful for groups that accept public + contributions where a user doesn't have to be a member to be able to contribute to issues and + merge requests. + +To remove a member from a group: + +1. In a group, go to **{users}** **Members**. +1. Click the **Delete** **{remove}** button next to a group member you want to remove. + A **Remove member** modal appears. +1. (Optional) Select the **Also unassign this user from related issues and merge requests** checkbox. +1. Click **Remove member**. + ## Changing the default branch protection of a group > [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/7583) in GitLab 12.9. diff --git a/doc/user/project/members/index.md b/doc/user/project/members/index.md index 787a74b0065..3eb411aef18 100644 --- a/doc/user/project/members/index.md +++ b/doc/user/project/members/index.md @@ -128,3 +128,30 @@ If you change your mind before your request is approved, just click the ## Share project with group Alternatively, you can [share a project with an entire group](share_project_with_groups.md) instead of adding users one by one. + +## Remove a member from the project + +Only users with permissions of [Owner](../../permissions.md#group-members-permissions) can manage +project members. + +You can remove a user from the project if the given member has a direct membership in the project. +If membership is inherited from a parent group, then the member can be removed only from the parent +group itself. + +When removing a member, you can decide whether to unassign the user from all issues and merge +requests they are currently assigned or leave the assignments as they are. + +- **Unassigning the removed member** from all issues and merge requests might be helpful when a user + is leaving a private project and you wish to revoke their access to any issues and merge requests + they are assigned. +- **Keeping the issues and merge requests assigned** might be helpful for projects that accept public + contributions where a user doesn't have to be a member to be able to contribute to issues and + merge requests. + +To remove a member from a project: + +1. In a project, go to **{users}** **Members**. +1. Click the **Delete** **{remove}** button next to a project member you want to remove. + A **Remove member** modal appears. +1. (Optional) Select the **Also unassign this user from related issues and merge requests** checkbox. +1. Click **Remove member**. diff --git a/lib/gitlab/ci/config.rb b/lib/gitlab/ci/config.rb index c01b08d703d..d81a3fef1f5 100644 --- a/lib/gitlab/ci/config.rb +++ b/lib/gitlab/ci/config.rb @@ -39,6 +39,10 @@ module Gitlab @root.errors end + def warnings + @root.warnings + end + def to_hash @config end diff --git a/lib/gitlab/ci/config/entry/processable.rb b/lib/gitlab/ci/config/entry/processable.rb index 81211acbec7..b4539475d88 100644 --- a/lib/gitlab/ci/config/entry/processable.rb +++ b/lib/gitlab/ci/config/entry/processable.rb @@ -82,6 +82,10 @@ module Gitlab @entries.delete(:except) unless except_defined? # rubocop:disable Gitlab/ModuleWithInstanceVariables end + if has_rules? && !has_workflow_rules && Gitlab::Ci::Features.raise_job_rules_without_workflow_rules_warning? + add_warning('uses `rules` without defining `workflow:rules`') + end + # inherit root variables @root_variables_value = deps&.variables_value # rubocop:disable Gitlab/ModuleWithInstanceVariables diff --git a/lib/gitlab/ci/features.rb b/lib/gitlab/ci/features.rb index 7fefcd00881..1889b9e0731 100644 --- a/lib/gitlab/ci/features.rb +++ b/lib/gitlab/ci/features.rb @@ -47,6 +47,12 @@ module Gitlab def self.variables_api_filter_environment_scope? ::Feature.enabled?(:ci_variables_api_filter_environment_scope, default_enabled: false) end + + # This FF is only used for development purpose to test that warnings can be + # raised and propagated to the UI. + def self.raise_job_rules_without_workflow_rules_warning? + ::Feature.enabled?(:ci_raise_job_rules_without_workflow_rules_warning) + end end end end diff --git a/lib/gitlab/ci/pipeline/chain/config/process.rb b/lib/gitlab/ci/pipeline/chain/config/process.rb index 1e47be21b93..2cfcb295407 100644 --- a/lib/gitlab/ci/pipeline/chain/config/process.rb +++ b/lib/gitlab/ci/pipeline/chain/config/process.rb @@ -19,7 +19,11 @@ module Gitlab parent_pipeline: parent_pipeline } ) + + add_warnings_to_pipeline(@command.config_processor.warnings) rescue Gitlab::Ci::YamlProcessor::ValidationError => ex + add_warnings_to_pipeline(ex.warnings) + error(ex.message, config_error: true) rescue => ex Gitlab::ErrorTracking.track_exception(ex, @@ -34,6 +38,14 @@ module Gitlab def break? @pipeline.errors.any? || @pipeline.persisted? end + + private + + def add_warnings_to_pipeline(warnings) + return unless warnings.present? + + warnings.each { |message| warning(message) } + end end end end diff --git a/lib/gitlab/ci/pipeline/chain/helpers.rb b/lib/gitlab/ci/pipeline/chain/helpers.rb index 34a4e25528d..aba7dab508d 100644 --- a/lib/gitlab/ci/pipeline/chain/helpers.rb +++ b/lib/gitlab/ci/pipeline/chain/helpers.rb @@ -19,6 +19,10 @@ module Gitlab # https://gitlab.com/gitlab-org/gitlab/-/issues/220823 pipeline.errors.add(:base, message) end + + def warning(message) + pipeline.add_warning_message(message) + end end end end diff --git a/lib/gitlab/ci/yaml_processor.rb b/lib/gitlab/ci/yaml_processor.rb index 6a9b7b2fc85..e74fa7e7213 100644 --- a/lib/gitlab/ci/yaml_processor.rb +++ b/lib/gitlab/ci/yaml_processor.rb @@ -3,15 +3,33 @@ module Gitlab module Ci class YamlProcessor - ValidationError = Class.new(StandardError) + # ValidationError is treated like a result object in the form of an exception. + # We can return any warnings, raised during the config validation, along with + # the error object until we support multiple messages to be returned. + class ValidationError < StandardError + attr_reader :warnings + + def initialize(message, warnings: []) + @warnings = warnings + super(message) + end + end include Gitlab::Config::Entry::LegacyValidationHelpers attr_reader :stages, :jobs - ResultWithErrors = Struct.new(:content, :errors) do + class Result + attr_reader :config, :errors, :warnings + + def initialize(config: nil, errors: [], warnings: []) + @config = config + @errors = errors + @warnings = warnings + end + def valid? - errors.empty? + config.present? && errors.empty? end end @@ -20,24 +38,32 @@ module Gitlab @config = @ci_config.to_hash unless @ci_config.valid? - raise ValidationError, @ci_config.errors.first + error!(@ci_config.errors.first) end initial_parsing rescue Gitlab::Ci::Config::ConfigError => e - raise ValidationError, e.message + error!(e.message) end def self.new_with_validation_errors(content, opts = {}) - return ResultWithErrors.new('', ['Please provide content of .gitlab-ci.yml']) if content.blank? + return Result.new(errors: ['Please provide content of .gitlab-ci.yml']) if content.blank? config = Gitlab::Ci::Config.new(content, **opts) - return ResultWithErrors.new("", config.errors) unless config.valid? + return Result.new(errors: config.errors, warnings: config.warnings) unless config.valid? config = Gitlab::Ci::YamlProcessor.new(content, opts) - ResultWithErrors.new(config, []) - rescue ValidationError, Gitlab::Ci::Config::ConfigError => e - ResultWithErrors.new('', [e.message]) + Result.new(config: config, warnings: config.warnings) + + rescue ValidationError => e + Result.new(errors: [e.message], warnings: e.warnings) + + rescue Gitlab::Ci::Config::ConfigError => e + Result.new(errors: [e.message]) + end + + def warnings + @ci_config&.warnings || [] end def builds @@ -157,10 +183,14 @@ module Gitlab return unless job[:stage] unless job[:stage].is_a?(String) && job[:stage].in?(@stages) - raise ValidationError, "#{name} job: chosen stage does not exist; available stages are #{@stages.join(", ")}" + error!("#{name} job: chosen stage does not exist; available stages are #{@stages.join(", ")}") end end + def error!(message) + raise ValidationError.new(message, warnings: warnings) + end + def validate_job_dependencies!(name, job) return unless job[:dependencies] @@ -190,7 +220,7 @@ module Gitlab def validate_job_dependency!(name, dependency, dependency_type = 'dependency') unless @jobs[dependency.to_sym] - raise ValidationError, "#{name} job: undefined #{dependency_type}: #{dependency}" + error!("#{name} job: undefined #{dependency_type}: #{dependency}") end job_stage_index = stage_index(name) @@ -199,7 +229,7 @@ module Gitlab # A dependency might be defined later in the configuration # with a stage that does not exist unless dependency_stage_index.present? && dependency_stage_index < job_stage_index - raise ValidationError, "#{name} job: #{dependency_type} #{dependency} is not defined in prior stages" + error!("#{name} job: #{dependency_type} #{dependency} is not defined in prior stages") end end @@ -221,19 +251,19 @@ module Gitlab on_stop_job = @jobs[on_stop.to_sym] unless on_stop_job - raise ValidationError, "#{name} job: on_stop job #{on_stop} is not defined" + error!("#{name} job: on_stop job #{on_stop} is not defined") end unless on_stop_job[:environment] - raise ValidationError, "#{name} job: on_stop job #{on_stop} does not have environment defined" + error!("#{name} job: on_stop job #{on_stop} does not have environment defined") end unless on_stop_job[:environment][:name] == environment[:name] - raise ValidationError, "#{name} job: on_stop job #{on_stop} have different environment name" + error!("#{name} job: on_stop job #{on_stop} have different environment name") end unless on_stop_job[:environment][:action] == 'stop' - raise ValidationError, "#{name} job: on_stop job #{on_stop} needs to have action stop defined" + error!("#{name} job: on_stop job #{on_stop} needs to have action stop defined") end end end diff --git a/lib/gitlab/config/entry/node.rb b/lib/gitlab/config/entry/node.rb index f653df20b2e..32912cb1046 100644 --- a/lib/gitlab/config/entry/node.rb +++ b/lib/gitlab/config/entry/node.rb @@ -16,6 +16,7 @@ module Gitlab @config = config @metadata = metadata @entries = {} + @warnings = [] yield(self) if block_given? @@ -60,6 +61,14 @@ module Gitlab [] end + def warnings + @warnings + descendants.flat_map(&:warnings) + end + + def add_warning(message) + @warnings << "#{location} #{message}" + end + def value if leaf? @config diff --git a/lib/gitlab/danger/helper.rb b/lib/gitlab/danger/helper.rb index 5f6de3b0a6a..5d8a07957dc 100644 --- a/lib/gitlab/danger/helper.rb +++ b/lib/gitlab/danger/helper.rb @@ -102,7 +102,7 @@ module Gitlab }.freeze # First-match win, so be sure to put more specific regex at the top... CATEGORIES = { - %r{\Adoc/} => :docs, + %r{\Adoc/.*(\.(md|png|gif|jpg))\z} => :docs, %r{\A(CONTRIBUTING|LICENSE|MAINTENANCE|PHILOSOPHY|PROCESS|README)(\.md)?\z} => :docs, %r{\A(ee/)?app/(assets|views)/} => :frontend, diff --git a/lib/gitlab/instrumentation/redis_base.rb b/lib/gitlab/instrumentation/redis_base.rb index 52817bde97e..7c08d5e8461 100644 --- a/lib/gitlab/instrumentation/redis_base.rb +++ b/lib/gitlab/instrumentation/redis_base.rb @@ -81,12 +81,12 @@ module Gitlab self end - def count_request + def instance_count_request @request_counter ||= Gitlab::Metrics.counter(:gitlab_redis_client_requests_total, 'Client side Redis request count, per Redis server') @request_counter.increment({ storage: storage_key }) end - def count_exception(ex) + def instance_count_exception(ex) # This metric is meant to give a client side view of how the Redis # server is doing. Redis itself does not expose error counts. This # metric can be used for Redis alerting and service health monitoring. @@ -94,6 +94,17 @@ module Gitlab @exception_counter.increment({ storage: storage_key, exception: ex.class.to_s }) end + def instance_observe_duration(duration) + @request_latency_histogram ||= Gitlab::Metrics.histogram( + :gitlab_redis_client_requests_duration_seconds, + 'Client side Redis request latency, per Redis server, excluding blocking commands', + {}, + [0.001, 0.005, 0.01] + ) + + @request_latency_histogram.observe({ storage: storage_key }, duration) + end + private def request_count_key diff --git a/lib/gitlab/instrumentation/redis_interceptor.rb b/lib/gitlab/instrumentation/redis_interceptor.rb index 6847e8aa65c..b5a5f8fd984 100644 --- a/lib/gitlab/instrumentation/redis_interceptor.rb +++ b/lib/gitlab/instrumentation/redis_interceptor.rb @@ -5,19 +5,26 @@ require 'redis' module Gitlab module Instrumentation module RedisInterceptor + APDEX_EXCLUDE = %w[brpop blpop brpoplpush bzpopmin bzpopmax xread xreadgroup].freeze + def call(*args, &block) - instrumentation_class.count_request + start = Time.now # must come first so that 'start' is always defined + instrumentation_class.instance_count_request instrumentation_class.redis_cluster_validate!(args.first) - start = Time.now super(*args, &block) rescue ::Redis::BaseError => ex - instrumentation_class.count_exception(ex) + instrumentation_class.instance_count_exception(ex) raise ex ensure - duration = (Time.now - start) + duration = Time.now - start + + unless APDEX_EXCLUDE.include?(command_from_args(args)) + instrumentation_class.instance_observe_duration(duration) + end if ::RequestStore.active? + # These metrics measure total Redis usage per Rails request / job. instrumentation_class.increment_request_count instrumentation_class.add_duration(duration) instrumentation_class.add_call_details(duration, args) @@ -83,6 +90,12 @@ module Gitlab def instrumentation_class @options[:instrumentation_class] # rubocop:disable Gitlab/ModuleWithInstanceVariables end + + def command_from_args(args) + command = args[0] + command = command[0] if command.is_a?(Array) + command.to_s.downcase + end end end end diff --git a/lib/gitlab/middleware/multipart.rb b/lib/gitlab/middleware/multipart.rb index 3c45f841653..c0b671abd44 100644 --- a/lib/gitlab/middleware/multipart.rb +++ b/lib/gitlab/middleware/multipart.rb @@ -105,6 +105,21 @@ module Gitlab private + def package_allowed_paths + packages_config = ::Gitlab.config.packages + return [] unless allow_packages_storage_path?(packages_config) + + [::Packages::PackageFileUploader.workhorse_upload_path] + end + + def allow_packages_storage_path?(packages_config) + return false unless packages_config.enabled + return false unless packages_config['storage_path'] + return false if packages_config.object_store.enabled && packages_config.object_store.direct_upload + + true + end + def allowed_paths [ ::FileUploader.root, @@ -112,7 +127,7 @@ module Gitlab JobArtifactUploader.workhorse_upload_path, LfsObjectUploader.workhorse_upload_path, File.join(Rails.root, 'public/uploads/tmp') - ] + ] + package_allowed_paths end end @@ -135,5 +150,3 @@ module Gitlab end end end - -::Gitlab::Middleware::Multipart::Handler.prepend_if_ee('EE::Gitlab::Middleware::Multipart::Handler') diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 98d19314be6..1610bf040fe 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -4140,6 +4140,9 @@ msgstr "" msgid "Cannot have multiple Jira imports running at the same time" msgstr "" +msgid "Cannot have multiple unresolved alerts" +msgstr "" + msgid "Cannot import because issues are not available in this project." msgstr "" @@ -5841,6 +5844,9 @@ msgstr "" msgid "Code owners" msgstr "" +msgid "CodeIntelligence|This is the definition" +msgstr "" + msgid "CodeOwner|Pattern" msgstr "" @@ -22982,6 +22988,9 @@ msgid_plural "The %{type} contains the following errors:" msgstr[0] "" msgstr[1] "" +msgid "The .gitlab-ci.yml has been successfully created." +msgstr "" + msgid "The Advanced Global Search in GitLab is a powerful search service that saves you time. Instead of creating duplicate code and wasting time, you can now search for code within other teams that can help your own project." msgstr "" @@ -23566,6 +23575,9 @@ msgstr "" msgid "There was an error when unsubscribing from this label." msgstr "" +msgid "There was an error while fetching configuration data." +msgstr "" + msgid "There was an error while fetching value stream analytics data." msgstr "" diff --git a/spec/frontend/code_navigation/components/__snapshots__/popover_spec.js.snap b/spec/frontend/code_navigation/components/__snapshots__/popover_spec.js.snap index 7079ddfc2ab..65c658536a3 100644 --- a/spec/frontend/code_navigation/components/__snapshots__/popover_spec.js.snap +++ b/spec/frontend/code_navigation/components/__snapshots__/popover_spec.js.snap @@ -11,43 +11,47 @@ exports[`Code navigation popover component renders popover 1`] = ` />
-
-      
         
-          function
+          
+            function
+          
+          
+             main() {
+          
         
-        
-           main() {
+        
+          
+            }
+          
         
-      
-      
-        
-          }
-        
-      
-    
+ +
{ payload: { path: 'index.js', normalizedData: { - '0:0': { start_line: 0, start_char: 0, hover: { value: '123' } }, + '0:0': { + definitionLineNumber: 0, + start_line: 0, + start_char: 0, + hover: { value: '123' }, + }, }, }, }, @@ -91,7 +96,12 @@ describe('Code navigation actions', () => { payload: { path: 'index.js', normalizedData: { - '0:0': { start_line: 0, start_char: 0, hover: { value: '123' } }, + '0:0': { + definitionLineNumber: 0, + start_line: 0, + start_char: 0, + hover: { value: '123' }, + }, }, }, }, @@ -159,7 +169,9 @@ describe('Code navigation actions', () => { let target; beforeEach(() => { - setFixtures('
'); + setFixtures( + '
', + ); target = document.querySelector('.js-test'); }); @@ -186,7 +198,7 @@ describe('Code navigation actions', () => { payload: { blobPath: 'index.js', definition: { hover: 'test' }, - position: { height: 0, x: 0, y: 0 }, + position: { height: 0, x: 0, y: 0, lineIndex: 0 }, }, }, ], @@ -210,7 +222,7 @@ describe('Code navigation actions', () => { payload: { blobPath: 'index.js', definition: { hover: 'test' }, - position: { height: 0, x: 0, y: 0 }, + position: { height: 0, x: 0, y: 0, lineIndex: 0 }, }, }, ], @@ -235,7 +247,7 @@ describe('Code navigation actions', () => { payload: { blobPath: 'index.js', definition: { hover: 'test' }, - position: { height: 0, x: 0, y: 0 }, + position: { height: 0, x: 0, y: 0, lineIndex: 0 }, }, }, ], diff --git a/spec/frontend/code_navigation/utils/index_spec.js b/spec/frontend/code_navigation/utils/index_spec.js index 58c48a90075..6a01249d2a3 100644 --- a/spec/frontend/code_navigation/utils/index_spec.js +++ b/spec/frontend/code_navigation/utils/index_spec.js @@ -36,7 +36,7 @@ describe('setCurrentHoverElement', () => { describe('addInteractionClass', () => { beforeEach(() => { setFixtures( - '
console.log
function
', + '
console.log
function
', ); }); diff --git a/spec/frontend/lib/utils/datetime_utility_spec.js b/spec/frontend/lib/utils/datetime_utility_spec.js index f6878c7c920..adf5c312149 100644 --- a/spec/frontend/lib/utils/datetime_utility_spec.js +++ b/spec/frontend/lib/utils/datetime_utility_spec.js @@ -1,5 +1,6 @@ import { __, s__ } from '~/locale'; import $ from 'jquery'; +import timezoneMock from 'timezone-mock'; import '~/commons/bootstrap'; import * as datetimeUtility from '~/lib/utils/datetime_utility'; @@ -86,6 +87,31 @@ describe('Date time utils', () => { datetimeUtility.formatDate('2016-07-23 00:00:00 UTC'); }).toThrow(new Error('Invalid date')); }); + + describe('convert local timezone to UTC with utc parameter', () => { + const midnightUTC = '2020-07-09'; + const format = 'mmm d, yyyy'; + + beforeEach(() => { + timezoneMock.register('US/Pacific'); + }); + + afterEach(() => { + timezoneMock.unregister(); + }); + + it('defaults to false', () => { + const formattedDate = datetimeUtility.formatDate(midnightUTC, format); + + expect(formattedDate).toBe('Jul 8, 2020'); + }); + + it('converts local time to UTC if utc flag is true', () => { + const formattedDate = datetimeUtility.formatDate(midnightUTC, format, true); + + expect(formattedDate).toBe('Jul 9, 2020'); + }); + }); }); describe('get day difference', () => { diff --git a/spec/lib/gitlab/ci/config/entry/processable_spec.rb b/spec/lib/gitlab/ci/config/entry/processable_spec.rb index 26a4355fb17..fdf6008f89f 100644 --- a/spec/lib/gitlab/ci/config/entry/processable_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/processable_spec.rb @@ -231,6 +231,12 @@ RSpec.describe Gitlab::Ci::Config::Entry::Processable do end context 'when workflow rules is used' do + let(:workflow) { double('workflow', 'has_rules?' => true) } + + before do + entry.compose!(deps) + end + context 'when rules are used' do let(:config) { { script: 'ls', cache: { key: 'test' }, rules: [] } } @@ -239,11 +245,11 @@ RSpec.describe Gitlab::Ci::Config::Entry::Processable do end end - context 'when rules are not used' do + context 'when rules are not used and only is defined' do let(:config) { { script: 'ls', cache: { key: 'test' }, only: [] } } - it 'does not define only' do - expect(entry).not_to be_only_defined + it 'keeps only entry' do + expect(entry).to be_only_defined end end end diff --git a/spec/lib/gitlab/ci/yaml_processor_spec.rb b/spec/lib/gitlab/ci/yaml_processor_spec.rb index b7bcbf61ed4..5c6d748d66c 100644 --- a/spec/lib/gitlab/ci/yaml_processor_spec.rb +++ b/spec/lib/gitlab/ci/yaml_processor_spec.rb @@ -435,6 +435,153 @@ module Gitlab end end + describe '#warnings' do + before do + stub_feature_flags(ci_raise_job_rules_without_workflow_rules_warning: true) + end + + context 'when a warning is raised in a given entry' do + let(:config) do + <<-EOYML + rspec: + script: rspec + rules: + - if: '$VAR == "value"' + EOYML + end + + it 'is propagated all the way up to the processor' do + expect(subject.warnings).to contain_exactly('jobs:rspec uses `rules` without defining `workflow:rules`') + end + end + + context 'when a warning is raised together with errors' do + let(:config) do + <<-EOYML + rspec: + script: rspec + rules: + - if: '$VAR == "value"' + invalid: + script: echo + artifacts: + - wrong_key: value + EOYML + end + + it 'is propagated all the way up into the raised exception' do + expect { subject }.to raise_error do |error| + expect(error).to be_a(described_class::ValidationError) + expect(error.message).to eq('jobs:invalid:artifacts config should be a hash') + expect(error.warnings).to contain_exactly('jobs:rspec uses `rules` without defining `workflow:rules`') + end + end + end + + context 'when error is raised before composing the config' do + let(:config) do + <<-EOYML + include: unknown/file.yml + rspec: + script: rspec + rules: + - if: '$VAR == "value"' + EOYML + end + + it 'raises an exception with empty warnings array' do + expect { subject }.to raise_error do |error| + expect(error).to be_a(described_class::ValidationError) + expect(error.message).to eq('Local file `unknown/file.yml` does not have project!') + expect(error.warnings).to be_empty + end + end + end + + context 'when error is raised after composing the config with warnings' do + shared_examples 'has warnings and expected error' do |error_message| + it 'raises an exception including warnings' do + expect { subject }.to raise_error do |error| + expect(error).to be_a(described_class::ValidationError) + expect(error.message).to match(error_message) + expect(error.warnings).to be_present + end + end + end + + context 'when stage does not exist' do + let(:config) do + <<-EOYML + rspec: + stage: custom_stage + script: rspec + rules: + - if: '$VAR == "value"' + EOYML + end + + it_behaves_like 'has warnings and expected error', /rspec job: chosen stage does not exist/ + end + + context 'job dependency does not exist' do + let(:config) do + <<-EOYML + build: + stage: build + script: echo + rules: + - if: '$VAR == "value"' + test: + stage: test + script: echo + needs: [unknown_job] + EOYML + end + + it_behaves_like 'has warnings and expected error', /test job: undefined need: unknown_job/ + end + + context 'job dependency defined in later stage' do + let(:config) do + <<-EOYML + build: + stage: build + script: echo + needs: [test] + rules: + - if: '$VAR == "value"' + test: + stage: test + script: echo + EOYML + end + + it_behaves_like 'has warnings and expected error', /build job: need test is not defined in prior stages/ + end + end + + context 'when feature flag is disabled' do + before do + stub_feature_flags(ci_raise_job_rules_without_workflow_rules_warning: false) + end + + context 'job rules used without workflow rules' do + let(:config) do + <<-EOYML + rspec: + script: rspec + rules: + - if: '$VAR == "value"' + EOYML + end + + it 'does not raise the warning' do + expect(subject.warnings).to be_empty + end + end + end + end + describe 'only / except policies validations' do context 'when `only` has an invalid value' do let(:config) { { rspec: { script: "rspec", type: "test", only: only } } } @@ -2517,7 +2664,7 @@ module Gitlab it 'returns errors and empty configuration' do expect(subject.valid?).to eq(false) expect(subject.errors).to eq(['Invalid configuration format']) - expect(subject.content).to be_blank + expect(subject.config).to be_blank end end @@ -2527,7 +2674,7 @@ module Gitlab it 'returns errors and empty configuration' do expect(subject.valid?).to eq(false) expect(subject.errors).to eq(['jobs:rspec:tags config should be an array of strings']) - expect(subject.content).to be_blank + expect(subject.config).to be_blank end end @@ -2539,7 +2686,7 @@ module Gitlab expect(subject.errors).to contain_exactly( 'jobs:rspec config contains unknown keys: bad_tags', 'jobs:rspec rules should be an array of hashes') - expect(subject.content).to be_blank + expect(subject.config).to be_blank end end @@ -2549,7 +2696,7 @@ module Gitlab it 'returns errors and empty configuration' do expect(subject.valid?).to eq(false) expect(subject.errors).to eq(['Please provide content of .gitlab-ci.yml']) - expect(subject.content).to be_blank + expect(subject.config).to be_blank end end @@ -2559,7 +2706,7 @@ module Gitlab it 'returns errors and empty configuration' do expect(subject.valid?).to eq(false) expect(subject.errors).to eq(['Unknown alias: bad_alias']) - expect(subject.content).to be_blank + expect(subject.config).to be_blank end end @@ -2569,7 +2716,7 @@ module Gitlab it 'returns errors and empty configuration' do expect(subject.valid?).to eq(true) expect(subject.errors).to be_empty - expect(subject.content).to be_present + expect(subject.config).to be_present end end end diff --git a/spec/lib/gitlab/danger/helper_spec.rb b/spec/lib/gitlab/danger/helper_spec.rb index 3508d02838c..711958b8eff 100644 --- a/spec/lib/gitlab/danger/helper_spec.rb +++ b/spec/lib/gitlab/danger/helper_spec.rb @@ -167,7 +167,7 @@ RSpec.describe Gitlab::Danger::Helper do describe '#categories_for_file' do where(:path, :expected_categories) do - 'doc/foo' | [:docs] + 'doc/foo.md' | [:docs] 'CONTRIBUTING.md' | [:docs] 'LICENSE' | [:docs] 'MAINTENANCE.md' | [:docs] diff --git a/spec/lib/gitlab/instrumentation/redis_interceptor_spec.rb b/spec/lib/gitlab/instrumentation/redis_interceptor_spec.rb index e34753987d6..5b0ad63ee72 100644 --- a/spec/lib/gitlab/instrumentation/redis_interceptor_spec.rb +++ b/spec/lib/gitlab/instrumentation/redis_interceptor_spec.rb @@ -47,15 +47,15 @@ RSpec.describe Gitlab::Instrumentation::RedisInterceptor, :clean_gitlab_redis_sh let(:instrumentation_class) { Gitlab::Redis::SharedState.instrumentation_class } it 'counts successful requests' do - expect(instrumentation_class).to receive(:count_request).and_call_original + expect(instrumentation_class).to receive(:instance_count_request).and_call_original Gitlab::Redis::SharedState.with { |redis| redis.call(:get, 'foobar') } end it 'counts exceptions' do - expect(instrumentation_class).to receive(:count_exception) + expect(instrumentation_class).to receive(:instance_count_exception) .with(instance_of(Redis::CommandError)).and_call_original - expect(instrumentation_class).to receive(:count_request).and_call_original + expect(instrumentation_class).to receive(:instance_count_request).and_call_original expect do Gitlab::Redis::SharedState.with do |redis| @@ -64,4 +64,51 @@ RSpec.describe Gitlab::Instrumentation::RedisInterceptor, :clean_gitlab_redis_sh end.to raise_exception(Redis::CommandError) end end + + describe 'latency' do + let(:instrumentation_class) { Gitlab::Redis::SharedState.instrumentation_class } + + describe 'commands in the apdex' do + where(:command) do + [ + [[:get, 'foobar']], + [%w[GET foobar]] + ] + end + + with_them do + it 'measures requests we want in the apdex' do + expect(instrumentation_class).to receive(:instance_observe_duration).with(a_value > 0) + .and_call_original + + Gitlab::Redis::SharedState.with { |redis| redis.call(*command) } + end + end + end + + describe 'commands not in the apdex' do + where(:command) do + [ + [%w[brpop foobar 0.01]], + [%w[blpop foobar 0.01]], + [%w[brpoplpush foobar bazqux 0.01]], + [%w[bzpopmin foobar 0.01]], + [%w[bzpopmax foobar 0.01]], + [%w[xread block 1 streams mystream 0-0]], + [%w[xreadgroup group mygroup myconsumer block 1 streams foobar 0-0]] + ] + end + + with_them do + it 'skips requests we do not want in the apdex' do + expect(instrumentation_class).not_to receive(:instance_observe_duration) + + begin + Gitlab::Redis::SharedState.with { |redis| redis.call(*command) } + rescue Gitlab::Instrumentation::RedisClusterValidator::CrossSlotError, ::Redis::CommandError + end + end + end + end + end end diff --git a/spec/lib/gitlab/middleware/multipart_spec.rb b/spec/lib/gitlab/middleware/multipart_spec.rb index 48aba7d4fb8..3b64fe335e8 100644 --- a/spec/lib/gitlab/middleware/multipart_spec.rb +++ b/spec/lib/gitlab/middleware/multipart_spec.rb @@ -232,4 +232,82 @@ RSpec.describe Gitlab::Middleware::Multipart do middleware.call(env) end end + + describe '#call' do + context 'with packages storage' do + using RSpec::Parameterized::TableSyntax + + let(:storage_path) { 'shared/packages' } + + RSpec.shared_examples 'allowing the multipart upload' do + it 'allows files to be uploaded' do + with_tmp_dir('tmp/uploads', storage_path) do |dir, env| + allow(Packages::PackageFileUploader).to receive(:root).and_return(File.join(dir, storage_path)) + + expect(app).to receive(:call) do |env| + expect(get_params(env)['file']).to be_a(::UploadedFile) + end + + middleware.call(env) + end + end + end + + RSpec.shared_examples 'not allowing the multipart upload when package upload path is used' do + it 'does not allow files to be uploaded' do + with_tmp_dir('tmp/uploads', storage_path) do |dir, env| + # with_tmp_dir sets the same workhorse_upload_path for all Uploaders, + # so we have to prevent JobArtifactUploader and LfsObjectUploader to + # allow the tested path + allow(JobArtifactUploader).to receive(:workhorse_upload_path).and_return(Dir.tmpdir) + allow(LfsObjectUploader).to receive(:workhorse_upload_path).and_return(Dir.tmpdir) + + status, headers, body = middleware.call(env) + + expect(status).to eq(400) + expect(headers).to eq({ 'Content-Type' => 'text/plain' }) + expect(body).to start_with('insecure path used') + end + end + end + + RSpec.shared_examples 'adding package storage to multipart allowed paths' do + before do + expect(::Packages::PackageFileUploader).to receive(:workhorse_upload_path).and_call_original + end + + it_behaves_like 'allowing the multipart upload' + end + + RSpec.shared_examples 'not adding package storage to multipart allowed paths' do + before do + expect(::Packages::PackageFileUploader).not_to receive(:workhorse_upload_path) + end + + it_behaves_like 'not allowing the multipart upload when package upload path is used' + end + + where(:object_storage_enabled, :direct_upload_enabled, :example_name) do + false | true | 'adding package storage to multipart allowed paths' + false | false | 'adding package storage to multipart allowed paths' + true | true | 'not adding package storage to multipart allowed paths' + true | false | 'adding package storage to multipart allowed paths' + end + + with_them do + before do + stub_config(packages: { + enabled: true, + object_store: { + enabled: object_storage_enabled, + direct_upload: direct_upload_enabled + }, + storage_path: storage_path + }) + end + + it_behaves_like params[:example_name] + end + end + end end diff --git a/spec/migrations/20200706035141_adjust_unique_index_alert_management_alerts_spec.rb b/spec/migrations/20200706035141_adjust_unique_index_alert_management_alerts_spec.rb new file mode 100644 index 00000000000..0068571ad0d --- /dev/null +++ b/spec/migrations/20200706035141_adjust_unique_index_alert_management_alerts_spec.rb @@ -0,0 +1,57 @@ +# frozen_string_literal: true + +require 'spec_helper' +require Rails.root.join('db', 'migrate', '20200706035141_adjust_unique_index_alert_management_alerts.rb') + +RSpec.describe AdjustUniqueIndexAlertManagementAlerts, :migration do + let(:migration) { described_class.new } + let(:alerts) { AlertManagement::Alert } + let(:project) { create_project } + let(:other_project) { create_project } + let(:resolved_state) { 2 } + let(:triggered_state) { 1 } + let!(:existing_alert) { create_alert(project, resolved_state, '1234', 1) } + let!(:p2_alert) { create_alert(other_project, resolved_state, '1234', 1) } + let!(:p2_alert_diff_fingerprint) { create_alert(other_project, resolved_state, '4567', 2) } + + it 'can reverse the migration' do + expect(existing_alert.fingerprint).not_to eq(nil) + expect(p2_alert.fingerprint).not_to eq(nil) + expect(p2_alert_diff_fingerprint.fingerprint).not_to eq(nil) + + migrate! + + # Adding a second alert with the same fingerprint now that we can + second_alert = create_alert(project, triggered_state, '1234', 2) + expect(alerts.count).to eq(4) + + schema_migrate_down! + + # We keep the alerts, but the oldest ones fingerprint is removed + expect(alerts.count).to eq(4) + expect(second_alert.reload.fingerprint).not_to eq(nil) + expect(p2_alert.fingerprint).not_to eq(nil) + expect(p2_alert_diff_fingerprint.fingerprint).not_to eq(nil) + expect(existing_alert.reload.fingerprint).to eq(nil) + end + + def namespace + @namespace ||= table(:namespaces).create!(name: 'foo', path: 'foo') + end + + def create_project + table(:projects).create!(namespace_id: namespace.id) + end + + def create_alert(project, status, fingerprint, iid) + params = { + title: 'test', + started_at: Time.current, + iid: iid, + project_id: project.id, + status: status, + fingerprint: fingerprint + } + table(:alert_management_alerts).create!(params) + end +end diff --git a/spec/models/alert_management/alert_spec.rb b/spec/models/alert_management/alert_spec.rb index 85f5b74c90c..2c62046a7eb 100644 --- a/spec/models/alert_management/alert_spec.rb +++ b/spec/models/alert_management/alert_spec.rb @@ -83,21 +83,50 @@ RSpec.describe AlertManagement::Alert do end describe 'fingerprint' do + let_it_be(:project) { create(:project) } let_it_be(:fingerprint) { 'fingerprint' } - let_it_be(:existing_alert) { create(:alert_management_alert, fingerprint: fingerprint) } let(:new_alert) { build(:alert_management_alert, fingerprint: fingerprint, project: project) } subject { new_alert } context 'adding an alert with the same fingerprint' do - context 'same project' do - let(:project) { existing_alert.project } + context 'same project, various states' do + using RSpec::Parameterized::TableSyntax - it { is_expected.not_to be_valid } + # We are only validating uniqueness for non-resolved alerts + where(:existing_status, :new_status, :valid) do + :resolved | :triggered | true + :resolved | :acknowledged | true + :resolved | :ignored | true + :resolved | :resolved | true + :triggered | :triggered | false + :triggered | :acknowledged | false + :triggered | :ignored | false + :triggered | :resolved | true + :acknowledged | :triggered | false + :acknowledged | :acknowledged | false + :acknowledged | :ignored | false + :acknowledged | :resolved | true + :ignored | :triggered | false + :ignored | :acknowledged | false + :ignored | :ignored | false + :ignored | :resolved | true + end + + with_them do + let!(:existing_alert) { create(:alert_management_alert, existing_status, fingerprint: fingerprint, project: project) } + let(:new_alert) { build(:alert_management_alert, new_status, fingerprint: fingerprint, project: project) } + + if params[:valid] + it { is_expected.to be_valid } + else + it { is_expected.to be_invalid } + end + end end context 'different project' do - let(:project) { create(:project) } + let!(:existing_alert) { create(:alert_management_alert, fingerprint: fingerprint) } it { is_expected.to be_valid } end diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb index bae8e0cdec2..17f9112c1d5 100644 --- a/spec/requests/api/users_spec.rb +++ b/spec/requests/api/users_spec.rb @@ -910,6 +910,14 @@ RSpec.describe API::Users, :do_not_mock_admin_mode do expect(user.reload.bio).to eq('') end + it 'updates user with nil bio' do + put api("/users/#{user.id}", admin), params: { bio: nil } + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response['bio']).to eq('') + expect(user.reload.bio).to eq('') + end + it "updates user with new password and forces reset on next login" do put api("/users/#{user.id}", admin), params: { password: '12345678' } diff --git a/spec/services/ci/create_pipeline_service/creation_errors_and_warnings_spec.rb b/spec/services/ci/create_pipeline_service/creation_errors_and_warnings_spec.rb new file mode 100644 index 00000000000..16205529f1c --- /dev/null +++ b/spec/services/ci/create_pipeline_service/creation_errors_and_warnings_spec.rb @@ -0,0 +1,114 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Ci::CreatePipelineService do + describe 'creation errors and warnings' do + let_it_be(:user) { create(:admin) } + let_it_be(:project) { create(:project, :repository, creator: user) } + + let(:ref) { 'refs/heads/master' } + let(:source) { :push } + let(:service) { described_class.new(project, user, { ref: ref }) } + let(:pipeline) { service.execute(source) } + + before do + stub_ci_pipeline_yaml_file(config) + stub_feature_flags(ci_raise_job_rules_without_workflow_rules_warning: true) + end + + context 'when created successfully' do + context 'when warnings are raised' do + let(:config) do + <<~YAML + test: + script: rspec + rules: + - if: '$CI_COMMIT_BRANCH' + YAML + end + + it 'contains only warnings' do + expect(pipeline.error_messages.map(&:content)).to be_empty + + expect(pipeline.warning_messages.map(&:content)).to contain_exactly( + 'jobs:test uses `rules` without defining `workflow:rules`' + ) + end + + context 'when feature flag is disabled for the particular warning' do + before do + stub_feature_flags(ci_raise_job_rules_without_workflow_rules_warning: false) + end + + it 'does not contain warnings' do + expect(pipeline.error_messages.map(&:content)).to be_empty + + expect(pipeline.warning_messages.map(&:content)).to be_empty + end + end + end + + context 'when no warnings are raised' do + let(:config) do + <<~YAML + test: + script: rspec + YAML + end + + it 'contains no warnings' do + expect(pipeline.error_messages).to be_empty + + expect(pipeline.warning_messages).to be_empty + end + end + end + + context 'when failed to create the pipeline' do + context 'when warnings are raised' do + let(:config) do + <<~YAML + build: + stage: build + script: echo + needs: [test] + test: + stage: test + script: echo + rules: + - if: '$CI_COMMIT_BRANCH' + YAML + end + + it 'contains both errors and warnings' do + error_message = 'build job: need test is not defined in prior stages' + warning_message = 'jobs:test uses `rules` without defining `workflow:rules`' + + expect(pipeline.yaml_errors).to eq(error_message) + expect(pipeline.error_messages.map(&:content)).to contain_exactly(error_message) + expect(pipeline.errors.full_messages).to contain_exactly(error_message) + + expect(pipeline.warning_messages.map(&:content)).to contain_exactly(warning_message) + end + end + + context 'when no warnings are raised' do + let(:config) do + <<~YAML + invalid: yaml + YAML + end + + it 'contains only errors' do + error_message = 'root config contains unknown keys: invalid' + expect(pipeline.yaml_errors).to eq(error_message) + expect(pipeline.error_messages.map(&:content)).to contain_exactly(error_message) + expect(pipeline.errors.full_messages).to contain_exactly(error_message) + + expect(pipeline.warning_messages).to be_empty + end + end + end + end +end diff --git a/spec/services/jira/jql_builder_service_spec.rb b/spec/services/jira/jql_builder_service_spec.rb index f51dec18094..120ce907a8c 100644 --- a/spec/services/jira/jql_builder_service_spec.rb +++ b/spec/services/jira/jql_builder_service_spec.rb @@ -85,5 +85,29 @@ RSpec.describe Jira::JqlBuilderService do expect(subject).to eq('project = PROJECT_KEY order by updated ASC') end end + + context 'with opened state param' do + let(:params) { { state: 'opened' } } + + it 'builds jql' do + expect(subject).to eq('project = PROJECT_KEY AND statusCategory != Done order by created DESC') + end + end + + context 'with closed state param' do + let(:params) { { state: 'closed' } } + + it 'builds jql' do + expect(subject).to eq('project = PROJECT_KEY AND statusCategory = Done order by created DESC') + end + end + + context 'with any other state param' do + let(:params) { { state: 'all' } } + + it 'builds jql' do + expect(subject).to eq('project = PROJECT_KEY order by created DESC') + end + end end end diff --git a/spec/services/members/destroy_service_spec.rb b/spec/services/members/destroy_service_spec.rb index 005fbe4fb83..ce1077b1167 100644 --- a/spec/services/members/destroy_service_spec.rb +++ b/spec/services/members/destroy_service_spec.rb @@ -25,6 +25,7 @@ RSpec.describe Members::DestroyService do before do type = member.is_a?(GroupMember) ? 'Group' : 'Project' expect(TodosDestroyer::EntityLeaveWorker).to receive(:perform_in).with(Todo::WAIT_FOR_DELETE, member.user_id, member.source_id, type) + expect(MembersDestroyer::UnassignIssuablesWorker).to receive(:perform_async).with(member.user_id, member.source_id, type) if opts[:unassign_issuables] end it 'destroys the member' do diff --git a/spec/workers/update_container_registry_info_worker_spec.rb b/spec/workers/update_container_registry_info_worker_spec.rb new file mode 100644 index 00000000000..ace9e55cbce --- /dev/null +++ b/spec/workers/update_container_registry_info_worker_spec.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe UpdateContainerRegistryInfoWorker do + describe '#perform' do + it 'calls UpdateContainerRegistryInfoService' do + expect_next_instance_of(UpdateContainerRegistryInfoService) do |service| + expect(service).to receive(:execute) + end + + subject.perform + end + end +end