diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-09-01 15:11:56 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-09-01 15:11:56 +0300 |
commit | a53033814ddff597cd05244f378915bacdcb5aea (patch) | |
tree | c72cddf8268e72cd46e3a1b0f04298aa6a04533b | |
parent | f60abc43151ae4589e96824c3c8674e76cb0cb9c (diff) |
Add latest changes from gitlab-org/gitlab@master
68 files changed, 755 insertions, 315 deletions
diff --git a/.rubocop_todo/layout/hash_alignment.yml b/.rubocop_todo/layout/hash_alignment.yml index 3e5694d0811..eafd3d58c65 100644 --- a/.rubocop_todo/layout/hash_alignment.yml +++ b/.rubocop_todo/layout/hash_alignment.yml @@ -36,7 +36,6 @@ Layout/HashAlignment: - 'spec/lib/gitlab/error_tracking/stack_trace_highlight_decorator_spec.rb' - 'spec/lib/gitlab/etag_caching/middleware_spec.rb' - 'spec/lib/gitlab/etag_caching/router/graphql_spec.rb' - - 'spec/lib/gitlab/git/repository_spec.rb' - 'spec/lib/gitlab/grape_logging/formatters/lograge_with_timestamp_spec.rb' - 'spec/lib/gitlab/import_export/attributes_finder_spec.rb' - 'spec/lib/gitlab/import_export/group/object_builder_spec.rb' @@ -55,10 +54,8 @@ Layout/HashAlignment: - 'spec/lib/gitlab/metrics/subscribers/active_record_spec.rb' - 'spec/lib/gitlab/metrics/subscribers/load_balancing_spec.rb' - 'spec/models/ci/build_spec.rb' - - 'spec/models/ci/pipeline_spec.rb' - 'spec/models/ci/processable_spec.rb' - 'spec/models/clusters/platforms/kubernetes_spec.rb' - - 'spec/models/commit_status_spec.rb' - 'spec/models/container_registry/event_spec.rb' - 'spec/models/deployment_spec.rb' - 'spec/models/design_management/version_spec.rb' @@ -72,7 +69,6 @@ Layout/HashAlignment: - 'spec/models/remote_mirror_spec.rb' - 'spec/models/repository_spec.rb' - 'spec/models/user_spec.rb' - - 'spec/presenters/clusters/cluster_presenter_spec.rb' - 'spec/presenters/project_presenter_spec.rb' - 'spec/routing/project_routing_spec.rb' - 'spec/serializers/ci/lint/job_entity_spec.rb' @@ -80,30 +76,3 @@ Layout/HashAlignment: - 'spec/serializers/deployment_entity_spec.rb' - 'spec/serializers/environment_serializer_spec.rb' - 'spec/serializers/merge_request_metrics_helper_spec.rb' - - 'spec/services/ci/create_downstream_pipeline_service_spec.rb' - - 'spec/services/ci/create_pipeline_service/logger_spec.rb' - - 'spec/services/ci/create_pipeline_service/tags_spec.rb' - - 'spec/services/ci/job_artifacts/create_service_spec.rb' - - 'spec/services/ci/retry_job_service_spec.rb' - - 'spec/services/deployments/link_merge_requests_service_spec.rb' - - 'spec/services/discussions/capture_diff_note_positions_service_spec.rb' - - 'spec/services/environments/stop_service_spec.rb' - - 'spec/services/event_create_service_spec.rb' - - 'spec/services/groups/import_export/import_service_spec.rb' - - 'spec/services/issuable/bulk_update_service_spec.rb' - - 'spec/services/issues/create_service_spec.rb' - - 'spec/services/merge_requests/build_service_spec.rb' - - 'spec/services/merge_requests/create_service_spec.rb' - - 'spec/services/merge_requests/update_service_spec.rb' - - 'spec/services/metrics/dashboard/clone_dashboard_service_spec.rb' - - 'spec/services/notes/create_service_spec.rb' - - 'spec/services/notes/destroy_service_spec.rb' - - 'spec/services/packages/debian/parse_debian822_service_spec.rb' - - 'spec/services/projects/destroy_service_spec.rb' - - 'spec/services/service_ping/submit_service_ping_service_spec.rb' - - 'spec/services/suggestions/apply_service_spec.rb' - - 'spec/services/work_items/widgets/description_service/update_service_spec.rb' - - 'spec/tooling/danger/datateam_spec.rb' - - 'spec/views/projects/tags/index.html.haml_spec.rb' - - 'spec/workers/emails_on_push_worker_spec.rb' - - 'spec/workers/pages_domain_ssl_renewal_cron_worker_spec.rb' diff --git a/app/assets/stylesheets/startup/startup-dark.scss b/app/assets/stylesheets/startup/startup-dark.scss index 71c99883297..9f2b249e714 100644 --- a/app/assets/stylesheets/startup/startup-dark.scss +++ b/app/assets/stylesheets/startup/startup-dark.scss @@ -10,7 +10,6 @@ body.gl-dark { --gray-50: #303030; --gray-100: #404040; --gray-200: #525252; - --gray-600: #bfbfbf; --gray-700: #dbdbdb; --gray-900: #fafafa; --green-100: #0d532a; @@ -1791,9 +1790,6 @@ body.gl-dark { .avatar { background: rgba(255, 255, 255, 0.04); } -.nav-sidebar li a { - color: var(--gray-600); -} body.gl-dark { --gl-theme-accent: #868686; } diff --git a/app/assets/stylesheets/themes/dark_mode_overrides.scss b/app/assets/stylesheets/themes/dark_mode_overrides.scss index 9348216c2ac..e1ba2a69420 100644 --- a/app/assets/stylesheets/themes/dark_mode_overrides.scss +++ b/app/assets/stylesheets/themes/dark_mode_overrides.scss @@ -60,12 +60,6 @@ } .nav-sidebar { - li { - a { - color: var(--gray-600); - } - } - .sidebar-sub-level-items.fly-out-list { box-shadow: none; border: 1px solid $border-color; @@ -78,7 +72,7 @@ aside.right-sidebar:not(.right-sidebar-merge-requests) { } body.gl-dark { - @include gitlab-theme($gray-900, $gray-400, $gray-500, $gray-900, $gray-900, $white); + @include gitlab-theme($gray-900, $gray-400, $gray-500, $gray-900, $white); .terms { .logo-text { diff --git a/app/assets/stylesheets/themes/theme_blue.scss b/app/assets/stylesheets/themes/theme_blue.scss index 817557f37cd..90122cec31f 100644 --- a/app/assets/stylesheets/themes/theme_blue.scss +++ b/app/assets/stylesheets/themes/theme_blue.scss @@ -6,7 +6,6 @@ body { $theme-blue-200, $theme-blue-500, $theme-blue-700, - $gray-900, $theme-blue-900, $white ); diff --git a/app/assets/stylesheets/themes/theme_gray.scss b/app/assets/stylesheets/themes/theme_gray.scss index 75b111f90c7..a6cdfb36a7c 100644 --- a/app/assets/stylesheets/themes/theme_gray.scss +++ b/app/assets/stylesheets/themes/theme_gray.scss @@ -7,7 +7,6 @@ body { $gray-300, $gray-500, $gray-900, - $gray-900, $white ); } diff --git a/app/assets/stylesheets/themes/theme_green.scss b/app/assets/stylesheets/themes/theme_green.scss index 7e387e97452..0300f261d64 100644 --- a/app/assets/stylesheets/themes/theme_green.scss +++ b/app/assets/stylesheets/themes/theme_green.scss @@ -6,7 +6,6 @@ body { $theme-green-200, $theme-green-500, $theme-green-700, - $gray-900, $theme-green-900, $white ); diff --git a/app/assets/stylesheets/themes/theme_helper.scss b/app/assets/stylesheets/themes/theme_helper.scss index 042e21cebd6..d644d8acc98 100644 --- a/app/assets/stylesheets/themes/theme_helper.scss +++ b/app/assets/stylesheets/themes/theme_helper.scss @@ -6,18 +6,22 @@ $search-and-nav-links, $accent, $border-and-box-shadow, - $sidebar-text, - $nav-svg-color, - $color-alternate + $navbar-theme-color, + $navbar-theme-contrast-color ) { // Set custom properties --gl-theme-accent: #{$accent}; + $search-and-nav-links-a20: rgba($search-and-nav-links, 0.2); + $search-and-nav-links-a30: rgba($search-and-nav-links, 0.3); + $search-and-nav-links-a40: rgba($search-and-nav-links, 0.4); + $search-and-nav-links-a80: rgba($search-and-nav-links, 0.8); + // Header .navbar-gitlab { - background-color: $nav-svg-color; + background-color: $navbar-theme-color; .navbar-collapse { color: $search-and-nav-links; @@ -37,7 +41,7 @@ > button { &:hover, &:focus { - background-color: rgba($search-and-nav-links, 0.2); + background-color: $search-and-nav-links-a20; } } @@ -45,13 +49,13 @@ &.dropdown.show { > a, > button { - color: $nav-svg-color; - background-color: $color-alternate; + color: $navbar-theme-color; + background-color: $navbar-theme-contrast-color; } } &.line-separator { - border-left: 1px solid rgba($search-and-nav-links, 0.2); + border-left: 1px solid $search-and-nav-links-a20; } } } @@ -65,12 +69,12 @@ color: $search-and-nav-links; &.header-search-new { - color: $sidebar-text; + color: $gray-900; } > a { .notification-dot { - border: 2px solid $nav-svg-color; + border: 2px solid $navbar-theme-color; } &.header-help-dropdown-toggle { @@ -88,7 +92,7 @@ &:hover, &:focus { @include media-breakpoint-up(sm) { - background-color: rgba($search-and-nav-links, 0.2); + background-color: $search-and-nav-links-a20; } svg { @@ -97,7 +101,7 @@ .notification-dot { will-change: border-color, background-color; - border-color: adjust-color($nav-svg-color, $red: 33, $green: 33, $blue: 33); + border-color: adjust-color($navbar-theme-color, $red: 33, $green: 33, $blue: 33); } &.header-help-dropdown-toggle .notification-dot { @@ -108,12 +112,12 @@ &.active > a, &.dropdown.show > a { - color: $nav-svg-color; - background-color: $color-alternate; + color: $navbar-theme-color; + background-color: $navbar-theme-contrast-color; &:hover { svg { - fill: $nav-svg-color; + fill: $navbar-theme-color; } } @@ -123,7 +127,7 @@ &.header-help-dropdown-toggle { .notification-dot { - background-color: $nav-svg-color; + background-color: $navbar-theme-color; } } } @@ -131,7 +135,7 @@ .impersonated-user, .impersonated-user:hover { svg { - fill: $nav-svg-color; + fill: $navbar-theme-color; } } } @@ -142,30 +146,30 @@ > a { &:hover, &:focus { - background-color: rgba($search-and-nav-links, 0.2); + background-color: $search-and-nav-links-a20; } } } .header-search { - background-color: rgba($search-and-nav-links, 0.2) !important; + background-color: $search-and-nav-links-a20 !important; border-radius: $border-radius-default; &:hover { - background-color: rgba($search-and-nav-links, 0.3) !important; + background-color: $search-and-nav-links-a30 !important; } svg.gl-search-box-by-type-search-icon { - color: rgba($search-and-nav-links, 0.8); + color: $search-and-nav-links-a80; } input { background-color: transparent; - color: rgba($search-and-nav-links, 0.8); - box-shadow: inset 0 0 0 1px rgba($search-and-nav-links, 0.4); + color: $search-and-nav-links-a80; + box-shadow: inset 0 0 0 1px $search-and-nav-links-a40; &::placeholder { - color: rgba($search-and-nav-links, 0.8); + color: $search-and-nav-links-a80; } &:focus, @@ -178,27 +182,27 @@ .keyboard-shortcut-helper { color: $search-and-nav-links; - background-color: rgba($search-and-nav-links, 0.2); + background-color: $search-and-nav-links-a20; } } .search { form { - background-color: rgba($search-and-nav-links, 0.2); + background-color: $search-and-nav-links-a20; &:hover { - background-color: rgba($search-and-nav-links, 0.3); + background-color: $search-and-nav-links-a30; } } .search-input::placeholder { - color: rgba($search-and-nav-links, 0.8); + color: $search-and-nav-links-a80; } .search-input-wrap { .search-icon, .clear-icon { - fill: rgba($search-and-nav-links, 0.8); + fill: $search-and-nav-links-a80; } } @@ -209,7 +213,7 @@ .search-input-wrap { .search-icon { - fill: rgba($search-and-nav-links, 0.8); + fill: $search-and-nav-links-a80; } } } @@ -217,7 +221,7 @@ // Sidebar .nav-sidebar li.active > a { - color: $sidebar-text; + color: $gray-900; } .nav-sidebar { diff --git a/app/assets/stylesheets/themes/theme_indigo.scss b/app/assets/stylesheets/themes/theme_indigo.scss index 3bf6cfea650..5a27a9cfdc5 100644 --- a/app/assets/stylesheets/themes/theme_indigo.scss +++ b/app/assets/stylesheets/themes/theme_indigo.scss @@ -6,7 +6,6 @@ body { $indigo-200, $indigo-500, $indigo-700, - $gray-900, $indigo-900, $white ); diff --git a/app/assets/stylesheets/themes/theme_light_blue.scss b/app/assets/stylesheets/themes/theme_light_blue.scss index 771a84911b3..7cb0d98802e 100644 --- a/app/assets/stylesheets/themes/theme_light_blue.scss +++ b/app/assets/stylesheets/themes/theme_light_blue.scss @@ -6,7 +6,6 @@ body { $theme-light-blue-200, $theme-light-blue-500, $theme-light-blue-500, - $gray-900, $theme-light-blue-700, $white ); diff --git a/app/assets/stylesheets/themes/theme_light_gray.scss b/app/assets/stylesheets/themes/theme_light_gray.scss index ad19438d79a..a0cbec9a92b 100644 --- a/app/assets/stylesheets/themes/theme_light_gray.scss +++ b/app/assets/stylesheets/themes/theme_light_gray.scss @@ -6,7 +6,6 @@ body { $gray-500, $gray-700, $gray-500, - $gray-900, $gray-50, $gray-500 ); diff --git a/app/assets/stylesheets/themes/theme_light_green.scss b/app/assets/stylesheets/themes/theme_light_green.scss index 8c991a7bfb3..797279cc37b 100644 --- a/app/assets/stylesheets/themes/theme_light_green.scss +++ b/app/assets/stylesheets/themes/theme_light_green.scss @@ -6,7 +6,6 @@ body { $theme-green-200, $theme-green-500, $theme-green-500, - $gray-900, $theme-light-green-700, $white ); diff --git a/app/assets/stylesheets/themes/theme_light_indigo.scss b/app/assets/stylesheets/themes/theme_light_indigo.scss index 6c220e0459a..3632c5ad45a 100644 --- a/app/assets/stylesheets/themes/theme_light_indigo.scss +++ b/app/assets/stylesheets/themes/theme_light_indigo.scss @@ -6,7 +6,6 @@ body { $indigo-200, $indigo-500, $indigo-500, - $gray-900, $indigo-700, $white ); diff --git a/app/assets/stylesheets/themes/theme_light_red.scss b/app/assets/stylesheets/themes/theme_light_red.scss index e1a715293b4..6c10d9178f1 100644 --- a/app/assets/stylesheets/themes/theme_light_red.scss +++ b/app/assets/stylesheets/themes/theme_light_red.scss @@ -6,7 +6,6 @@ body { $theme-light-red-200, $theme-light-red-500, $theme-light-red-500, - $gray-900, $theme-light-red-700, $white ); diff --git a/app/assets/stylesheets/themes/theme_red.scss b/app/assets/stylesheets/themes/theme_red.scss index 19fd150727d..140e27de6e2 100644 --- a/app/assets/stylesheets/themes/theme_red.scss +++ b/app/assets/stylesheets/themes/theme_red.scss @@ -6,7 +6,6 @@ body { $theme-red-200, $theme-red-500, $theme-red-700, - $gray-900, $theme-red-900, $white ); diff --git a/app/components/pajamas/badge_component.html.haml b/app/components/pajamas/badge_component.html.haml new file mode 100644 index 00000000000..eaadc681f0e --- /dev/null +++ b/app/components/pajamas/badge_component.html.haml @@ -0,0 +1,6 @@ +- if link? + %a{ href: @href, **html_options }>< + = badge_content +- else + %span{ **html_options }>< + = badge_content diff --git a/app/components/pajamas/badge_component.rb b/app/components/pajamas/badge_component.rb new file mode 100644 index 00000000000..244064b0e1e --- /dev/null +++ b/app/components/pajamas/badge_component.rb @@ -0,0 +1,72 @@ +# frozen_string_literal: true + +module Pajamas + class BadgeComponent < Pajamas::Component + def initialize( + text = nil, + icon: nil, + icon_classes: [], + icon_only: false, + href: nil, + size: :md, + variant: :muted, + **html_options + ) + @text = text.presence + @icon = icon.to_s.presence + @icon_classes = Array.wrap(icon_classes) + @icon_only = @icon && icon_only + @href = href.presence + @size = filter_attribute(size.to_sym, SIZE_OPTIONS, default: :md) + @variant = filter_attribute(variant.to_sym, VARIANT_OPTIONS, default: :muted) + @html_options = html_options + end + + private + + SIZE_OPTIONS = [:sm, :md, :lg].freeze + VARIANT_OPTIONS = [:muted, :neutral, :info, :success, :warning, :danger].freeze + + delegate :sprite_icon, to: :helpers + + def badge_classes + ["gl-badge", "badge", "badge-pill", "badge-#{@variant}", @size.to_s] + end + + def icon_classes + classes = %w[gl-icon gl-badge-icon] + @icon_classes + classes.push("gl-mr-2") unless icon_only? + classes.join(" ") + end + + def icon_only? + @icon_only + end + + def link? + @href.present? + end + + # Determines the rendered text content. + # The content slot takes presedence over the text param. + def text + content || @text + end + + def badge_content + if icon_only? + sprite_icon(@icon, css_class: icon_classes) + elsif @icon.present? + sprite_icon(@icon, css_class: icon_classes) + text + else + text + end + end + + def html_options + options = format_options(options: @html_options, css_classes: badge_classes) + options.merge!({ aria: { label: text }, role: "img" }) if icon_only? + options + end + end +end diff --git a/app/helpers/badges_helper.rb b/app/helpers/badges_helper.rb index d48eae26a90..069c15433a5 100644 --- a/app/helpers/badges_helper.rb +++ b/app/helpers/badges_helper.rb @@ -1,25 +1,6 @@ # frozen_string_literal: true module BadgesHelper - VARIANT_CLASSES = { - muted: "badge-muted", - neutral: "badge-neutral", - info: "badge-info", - success: "badge-success", - warning: "badge-warning", - danger: "badge-danger" - }.tap { |hash| hash.default = hash.fetch(:muted) }.freeze - - SIZE_CLASSES = { - sm: "sm", - md: "md", - lg: "lg" - }.tap { |hash| hash.default = hash.fetch(:md) }.freeze - - GL_BADGE_CLASSES = %w[gl-badge badge badge-pill].freeze - - GL_ICON_CLASSES = %w[gl-icon gl-badge-icon].freeze - # Creates a GitLab UI badge. # # Examples: @@ -53,47 +34,16 @@ module BadgesHelper # # See also https://gitlab-org.gitlab.io/gitlab-ui/?path=/story/base-badge--default. def gl_badge_tag(*args, &block) + # Merge the options and html_options hashes if both are present, + # because the badge component wants a flat list of keyword args. + args.compact! + hashes, params = args.partition { |a| a.is_a? Hash } + options_hash = hashes.reduce({}, :merge) + if block - build_gl_badge_tag(capture(&block), *args) + render Pajamas::BadgeComponent.new(**options_hash), &block else - build_gl_badge_tag(*args) + render Pajamas::BadgeComponent.new(*params, **options_hash) end end - - private - - def build_gl_badge_tag(content, options = nil, html_options = nil) - options ||= {} - html_options ||= {} - - icon_only = options[:icon_only] - variant_class = VARIANT_CLASSES[options.fetch(:variant, :muted)] - size_class = SIZE_CLASSES[options.fetch(:size, :md)] - icon_classes = GL_ICON_CLASSES.dup << options.fetch(:icon_classes, nil) - - html_options = html_options.merge( - class: [ - *GL_BADGE_CLASSES, - variant_class, - size_class, - *html_options[:class] - ] - ) - - if icon_only - html_options['aria-label'] = content - html_options['role'] = 'img' - end - - if options[:icon] - icon_classes << "gl-mr-2" unless icon_only - icon = sprite_icon(options[:icon], css_class: icon_classes.join(' ')) - - content = icon_only ? icon : icon + content - end - - tag = html_options[:href].nil? ? :span : :a - - content_tag(tag, content, html_options) - end end diff --git a/app/models/users/credit_card_validation.rb b/app/models/users/credit_card_validation.rb index 998a5deb0fd..6f1cadb4344 100644 --- a/app/models/users/credit_card_validation.rb +++ b/app/models/users/credit_card_validation.rb @@ -21,5 +21,9 @@ module Users network: network ).order(credit_card_validated_at: :desc).includes(:user) end + + def similar_holder_names_count + self.class.where('lower(holder_name) = :value', value: holder_name.downcase).count + end end end diff --git a/config/metrics/counts_28d/20210216184937_user_packages_total_unique_counts_monthly.yml b/config/metrics/counts_28d/20210216184937_user_packages_total_unique_counts_monthly.yml index 52e2eec71c5..e758f06bea9 100644 --- a/config/metrics/counts_28d/20210216184937_user_packages_total_unique_counts_monthly.yml +++ b/config/metrics/counts_28d/20210216184937_user_packages_total_unique_counts_monthly.yml @@ -15,17 +15,13 @@ options: events: - i_package_composer_user - i_package_conan_user - - i_package_container_user - - i_package_debian_user - i_package_generic_user - - i_package_golang_user - i_package_helm_user - i_package_maven_user - i_package_npm_user - i_package_nuget_user - i_package_pypi_user - i_package_rubygems_user - - i_package_tag_user - i_package_terraform_module_user distribution: - ee diff --git a/config/metrics/counts_7d/20210216184935_user_packages_total_unique_counts_weekly.yml b/config/metrics/counts_7d/20210216184935_user_packages_total_unique_counts_weekly.yml index 81181baa4ee..e7465b79667 100644 --- a/config/metrics/counts_7d/20210216184935_user_packages_total_unique_counts_weekly.yml +++ b/config/metrics/counts_7d/20210216184935_user_packages_total_unique_counts_weekly.yml @@ -15,17 +15,13 @@ options: events: - i_package_composer_user - i_package_conan_user - - i_package_container_user - - i_package_debian_user - i_package_generic_user - - i_package_golang_user - i_package_helm_user - i_package_maven_user - i_package_npm_user - i_package_nuget_user - i_package_pypi_user - i_package_rubygems_user - - i_package_tag_user - i_package_terraform_module_user distribution: - ee diff --git a/db/migrate/20220829183356_replace_index_on_credit_card_validations.rb b/db/migrate/20220829183356_replace_index_on_credit_card_validations.rb new file mode 100644 index 00000000000..05fa7f75feb --- /dev/null +++ b/db/migrate/20220829183356_replace_index_on_credit_card_validations.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +class ReplaceIndexOnCreditCardValidations < Gitlab::Database::Migration[2.0] + disable_ddl_transaction! + + OLD_INDEX_NAME = 'index_user_credit_card_validations_meta_data_full_match' + NEW_INDEX_NAME = 'index_user_credit_card_validations_meta_data_full_match_lower' + OLD_FIELDS = [:holder_name, :expiration_date, :last_digits, :credit_card_validated_at] + NEW_FIELDS = 'lower(holder_name), expiration_date, last_digits, credit_card_validated_at' + + def up + add_concurrent_index :user_credit_card_validations, NEW_FIELDS, name: NEW_INDEX_NAME + remove_concurrent_index :user_credit_card_validations, OLD_FIELDS, name: OLD_INDEX_NAME + end + + def down + add_concurrent_index :user_credit_card_validations, OLD_FIELDS, name: OLD_INDEX_NAME + remove_concurrent_index :user_credit_card_validations, NEW_FIELDS, name: NEW_INDEX_NAME + end +end diff --git a/db/schema_migrations/20220829183356 b/db/schema_migrations/20220829183356 new file mode 100644 index 00000000000..087a8a8ab6b --- /dev/null +++ b/db/schema_migrations/20220829183356 @@ -0,0 +1 @@ +4d8be5080046eff9c3736cd2494c02b2d2cb1eeea2753479617cb344bc5b1cbb
\ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index a5f072d7c84..9a2b9805046 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -30341,7 +30341,7 @@ CREATE UNIQUE INDEX index_user_canonical_emails_on_user_id ON user_canonical_ema CREATE UNIQUE INDEX index_user_canonical_emails_on_user_id_and_canonical_email ON user_canonical_emails USING btree (user_id, canonical_email); -CREATE INDEX index_user_credit_card_validations_meta_data_full_match ON user_credit_card_validations USING btree (holder_name, expiration_date, last_digits, credit_card_validated_at); +CREATE INDEX index_user_credit_card_validations_meta_data_full_match_lower ON user_credit_card_validations USING btree (lower(holder_name), expiration_date, last_digits, credit_card_validated_at); CREATE INDEX index_user_credit_card_validations_meta_data_partial_match ON user_credit_card_validations USING btree (expiration_date, last_digits, network, credit_card_validated_at); diff --git a/doc/administration/external_pipeline_validation.md b/doc/administration/external_pipeline_validation.md index 99876cdf503..b9bf0cfdc50 100644 --- a/doc/administration/external_pipeline_validation.md +++ b/doc/administration/external_pipeline_validation.md @@ -44,6 +44,7 @@ required number of seconds. "required" : [ "project", "user", + "credit_card", "pipeline", "builds", "total_builds_count", @@ -85,6 +86,17 @@ required number of seconds. "sign_in_count": { "type": "integer" } } }, + "credit_card": { + "type": "object", + "required": [ + "similar_cards_count", + "similar_holder_names_count" + ], + "properties": { + "similar_cards_count": { "type": "integer" }, + "similar_holder_names_count": { "type": "integer" } + } + }, "pipeline": { "type": "object", "required": [ diff --git a/doc/api/merge_request_approvals.md b/doc/api/merge_request_approvals.md index 1d99c323946..f32a5eebaeb 100644 --- a/doc/api/merge_request_approvals.md +++ b/doc/api/merge_request_approvals.md @@ -33,6 +33,7 @@ GET /projects/:id/approvals { "approvals_before_merge": 2, "reset_approvals_on_push": true, + "selective_code_owner_removals": false, "disable_overriding_approvers_per_merge_request": false, "merge_requests_author_approval": true, "merge_requests_disable_committers_approval": false, @@ -57,16 +58,18 @@ POST /projects/:id/approvals | ------------------------------------------------ | ------- | -------- | --------------------------------------------------------------------------------------------------- | | `id` | integer or string | yes | The ID or [URL-encoded path of a project](index.md#namespaced-path-encoding) | | `approvals_before_merge` | integer | no | How many approvals are required before an MR can be merged. Deprecated in 12.0 in favor of Approval Rules API. | -| `reset_approvals_on_push` | boolean | no | Reset approvals on a new push | | `disable_overriding_approvers_per_merge_request` | boolean | no | Allow or prevent overriding approvers per MR | | `merge_requests_author_approval` | boolean | no | Allow or prevent authors from self approving merge requests; `true` means authors can self approve | | `merge_requests_disable_committers_approval` | boolean | no | Allow or prevent committers from self approving merge requests | | `require_password_to_approve` | boolean | no | Require approver to enter a password to authenticate before adding the approval | +| `reset_approvals_on_push` | boolean | no | Reset approvals on a new push. | +| `selective_code_owner_removals` | boolean | no | Reset approvals from Code Owners if their files changed. Can be enabled only if `reset_approvals_on_push` is disabled. | ```json { "approvals_before_merge": 2, "reset_approvals_on_push": true, + "selective_code_owner_removals": false, "disable_overriding_approvers_per_merge_request": false, "merge_requests_author_approval": false, "merge_requests_disable_committers_approval": false, diff --git a/doc/architecture/blueprints/ci_data_decay/pipeline_partitioning.md b/doc/architecture/blueprints/ci_data_decay/pipeline_partitioning.md index 097c6743042..d46eef0b9fc 100644 --- a/doc/architecture/blueprints/ci_data_decay/pipeline_partitioning.md +++ b/doc/architecture/blueprints/ci_data_decay/pipeline_partitioning.md @@ -159,21 +159,32 @@ and artifacts, will share the same value. We want to add the `partition_id` column into all 6 problematic tables because we can avoid backfilling this data when we decide it is time to start partitioning them. -We want to partition CI/CD data iteratively, so we will start with the -pipelines table, and create at least one, but likely two, partitions. The -pipelines table will be partitioned using the `LIST` partitioning strategy. It -is possible that, after some time, `p_ci_pipelines` will store data in two -partitions with IDs of `100` and `101`. Then we will try partitioning -`ci_builds`. Therefore we might want to use `RANGE` partitioning in -`p_ci_builds` with IDs `100` and `101`, because builds for the two logical -partitions used will still be stored in a single table. +We want to partition CI/CD data iteratively. We plan to start with the +`ci_builds_metadata` table, because this is the fastest growing table in the CI +database and want to contain this rapid growth. This table has also the most +simple access patterns - a row from it is being read when a build is exposed to +a runner, and other access patterns are relatively simple too. Starting with +`p_ci_builds_metadata` will allow us to achieve tangible and quantifiable +results earlier, and will become a new pattern that makes partitioning the +largest table possible. We will partition builds metadata using the `LIST` +partitioning strategy. + +Once we have many partitions attached to `p_ci_builds_metadata`, with many +`partition_ids` we will choose another CI table to partition next. In that case +we might want to use `RANGE` partitioning in for that next table because +`p_ci_builds_metadata` will already have many physical partitions, and +therefore many logical `partition_ids` will be used at that time. For example, +if we choose `ci_builds` as the next partitioning candidate, after having +partitioned `p_ci_builds_metadata`, it will have many different values stored +in `ci_builds.partition_id`. Using `RANGE` partitioning in that case might be +easier. Physical partitioning and logical partitioning will be separated, and a -strategy will be determined when we implement partitioning for the respective -database tables. Using `RANGE` partitioning works similarly to using `LIST` -partitioning in database tables other than `ci_pipelines`, but because we can -guarantee continuity of `partition_id` values, using `RANGE` partitioning might -be a better strategy. +strategy will be determined when we implement physical partitioning for the +respective database tables. Using `RANGE` partitioning works similarly to using +`LIST` partitioning in database tables, but because we can guarantee continuity +of `partition_id` values, using `RANGE` partitioning might be a better +strategy. ## Why do we want to use explicit logical partition ids? @@ -335,9 +346,116 @@ scope block takes an argument). Preloading instance dependent scopes is not supported. ``` -We also need to build a proof of concept for removing data on the PostgreSQL -side (using foreign keys with `ON DELETE CASCADE`) and removing data through -Rails associations, as this might be an important area of uncertainty. +### Foreign keys + +Foreign keys must reference columns that either are a primary key or form a +unique constraint. We can define them using these strategies: + +#### Between routing tables sharing partition ID + +For relations that are part of the same pipeline hierarchy it is possible to +share the `partition_id` column to define the foreign key constraint: + +```plaintext +p_ci_pipelines: + - id + - partition_id + +p_ci_builds: + - id + - partition_id + - pipeline_id +``` + +In this case, `p_ci_builds.partition_id` indicates the partition for the build +and also for the pipeline. We can add a FK on the routing table using: + +```sql +ALTER TABLE ONLY p_ci_builds + ADD CONSTRAINT fk_on_pipeline_and_partition + FOREIGN KEY (pipeline_id, partition_id) + REFERENCES p_ci_pipelines(id, partition_id) ON DELETE CASCADE; +``` + +#### Between routing tables with different partition IDs + +It's not possible to reuse the `partition_id` for all relations in the CI domain, +so in this case we'll need to store the value as a different attribute. For +example, when canceling redundant pipelines we store on the old pipeline row +the ID of the new pipeline that cancelled it as `auto_canceled_by_id`: + +```plaintext +p_ci_pipelines: + - id + - partition_id + - auto_canceled_by_id + - auto_canceled_by_partition_id +``` + +In this case we can't ensure that the canceling pipeline is part of the same +hierarchy as the canceled pipelines, so we need an extra attribute to store its +partition, `auto_canceled_by_partition_id`, and the FK becomes: + +```sql +ALTER TABLE ONLY p_ci_pipelines + ADD CONSTRAINT fk_cancel_redundant_pieplines + FOREIGN KEY (auto_canceled_by_id, auto_canceled_by_partition_id) + REFERENCES p_ci_pipelines(id, partition_id) ON DELETE SET NULL; +``` + +#### Between routing tables and regular tables + +Not all of the tables in the CI domain will be partitioned, so we'll have routing +tables that will reference non-partitioned tables, for example we reference +`external_pull_requests` from `ci_pipelines`: + +```sql +FOREIGN KEY (external_pull_request_id) +REFERENCES external_pull_requests(id) +ON DELETE SET NULL +``` + +In this case we only need to move the FK definition from the partition level +to the routing table so that new pipeline partitions may use it: + +```sql +ALTER TABLE p_ci_pipelines + ADD CONSTRAINT fk_external_request + FOREIGN KEY (external_pull_request_id) + REFERENCES external_pull_requests(id) ON DELETE SET NULL; +``` + +#### Between regular tables and routing tables + +Most of the tables from the CI domain reference at least one table that will be +turned into a routing tables, for example `ci_pipeline_messages` references +`ci_pipelines`. These definitions will need to be updated to use the routing +tables and for this they will need a `partition_id` column: + +```plaintext +p_ci_pipelines: + - id + - partition_id + +ci_pipeline_messages: + - id + - pipeline_id + - pipeline_partition_id +``` + +The foreign key can be defined by using: + +```sql +ALTER TABLE ci_pipeline_messages ADD CONSTRAINT fk_pipeline_partitioned + FOREIGN KEY (pipeline_id, pipeline_partition_id) + REFERENCES p_ci_pipelines(id, partition_id) ON DELETE CASCADE; +``` + +The old FK definition will need to be removed, otherwise new inserts in the +`ci_pipeline_messages` with pipeline IDs from non-zero partition will fail with +reference errors. + +### Indexes We [learned](https://gitlab.com/gitlab-org/gitlab/-/issues/360148) that `PostgreSQL` does not allow to create a single index (unique or otherwise) across all partitions of a table. diff --git a/lib/banzai/filter/kroki_filter.rb b/lib/banzai/filter/kroki_filter.rb index 845c7f2bc0a..713ff2439fc 100644 --- a/lib/banzai/filter/kroki_filter.rb +++ b/lib/banzai/filter/kroki_filter.rb @@ -14,7 +14,10 @@ module Banzai return doc unless settings.kroki_enabled diagram_selectors = ::Gitlab::Kroki.formats(settings) - .map { |diagram_type| %(pre[lang="#{diagram_type}"] > code) } + .map do |diagram_type| + %(pre[lang="#{diagram_type}"] > code, + pre > code[lang="#{diagram_type}"]) + end .join(', ') xpath = Gitlab::Utils::Nokogiri.css_to_xpath(diagram_selectors) @@ -22,7 +25,7 @@ module Banzai diagram_format = "svg" doc.xpath(xpath).each do |node| - diagram_type = node.parent['lang'] + diagram_type = node.parent['lang'] || node['lang'] diagram_src = node.content image_src = create_image_src(diagram_type, diagram_format, diagram_src) img_tag = Nokogiri::HTML::DocumentFragment.parse(%(<img src="#{image_src}" />)) @@ -33,8 +36,8 @@ module Banzai img_tag.set_attribute('hidden', '') if lazy_load img_tag.set_attribute('class', 'js-render-kroki') - img_tag.set_attribute('data-diagram', node.parent['lang']) - img_tag.set_attribute('data-diagram-src', "data:text/plain;base64,#{Base64.strict_encode64(node.content)}") + img_tag.set_attribute('data-diagram', diagram_type) + img_tag.set_attribute('data-diagram-src', "data:text/plain;base64,#{Base64.strict_encode64(diagram_src)}") node.parent.replace(img_tag) end diff --git a/lib/banzai/pipeline/markup_pipeline.rb b/lib/banzai/pipeline/markup_pipeline.rb index 17a73f29afb..330914f7238 100644 --- a/lib/banzai/pipeline/markup_pipeline.rb +++ b/lib/banzai/pipeline/markup_pipeline.rb @@ -9,8 +9,8 @@ module Banzai Filter::AssetProxyFilter, Filter::ExternalLinkFilter, Filter::PlantumlFilter, - Filter::SyntaxHighlightFilter, - Filter::KrokiFilter + Filter::KrokiFilter, + Filter::SyntaxHighlightFilter ] end diff --git a/lib/gitlab/ci/pipeline/chain/validate/external.rb b/lib/gitlab/ci/pipeline/chain/validate/external.rb index ba6de77d57d..f4fa9e5fe2a 100644 --- a/lib/gitlab/ci/pipeline/chain/validate/external.rb +++ b/lib/gitlab/ci/pipeline/chain/validate/external.rb @@ -97,6 +97,10 @@ module Gitlab last_sign_in_ip: current_user.last_sign_in_ip, sign_in_count: current_user.sign_in_count }, + credit_card: { + similar_cards_count: current_user.credit_card_validation&.similar_records&.count.to_i, + similar_holder_names_count: current_user.credit_card_validation&.similar_holder_names_count.to_i + }, pipeline: { sha: pipeline.sha, ref: pipeline.ref, diff --git a/lib/gitlab/usage_data_counters/hll_redis_counter.rb b/lib/gitlab/usage_data_counters/hll_redis_counter.rb index 51dc3689dfd..d85e9beea39 100644 --- a/lib/gitlab/usage_data_counters/hll_redis_counter.rb +++ b/lib/gitlab/usage_data_counters/hll_redis_counter.rb @@ -31,7 +31,6 @@ module Gitlab issues_edit pipeline_authoring quickactions - user_packages ].freeze CATEGORIES_COLLECTED_FROM_METRICS_DEFINITIONS = %w[ @@ -49,6 +48,7 @@ module Gitlab source_code terraform testing + user_packages work_items ].freeze diff --git a/locale/gitlab.pot b/locale/gitlab.pot index ab1356dd35c..e46cf759410 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -11894,15 +11894,6 @@ msgstr "" msgid "DastProfiles|Delete profile" msgstr "" -msgid "DastProfiles|Do you want to discard this scanner profile?" -msgstr "" - -msgid "DastProfiles|Do you want to discard this site profile?" -msgstr "" - -msgid "DastProfiles|Do you want to discard your changes?" -msgstr "" - msgid "DastProfiles|Edit profile" msgstr "" @@ -27282,6 +27273,12 @@ msgstr "" msgid "OnDemandScans|Description (optional)" msgstr "" +msgid "OnDemandScans|Discard changes" +msgstr "" + +msgid "OnDemandScans|Do you want to discard the changes or keep editing this profile? Unsaved changes will be lost." +msgstr "" + msgid "OnDemandScans|Dynamic Application Security Testing (DAST)" msgstr "" @@ -27303,6 +27300,9 @@ msgstr "" msgid "OnDemandScans|For example: Tests the login page for SQL injections" msgstr "" +msgid "OnDemandScans|Keep editing" +msgstr "" + msgid "OnDemandScans|Manage scanner profiles" msgstr "" @@ -27426,6 +27426,9 @@ msgstr "" msgid "OnDemandScans|View results" msgstr "" +msgid "OnDemandScans|You have unsaved changes" +msgstr "" + msgid "OnDemandScans|You must create a repository within your project to run an on-demand scan." msgstr "" diff --git a/rubocop/cop/gitlab/mark_used_feature_flags.rb b/rubocop/cop/gitlab/mark_used_feature_flags.rb index df524c8b0d2..8fbcc56b906 100644 --- a/rubocop/cop/gitlab/mark_used_feature_flags.rb +++ b/rubocop/cop/gitlab/mark_used_feature_flags.rb @@ -37,7 +37,8 @@ module RuboCop USAGE_DATA_COUNTERS_EVENTS_YAML_GLOBS = [ File.expand_path("../../../config/metrics/aggregates/*.yml", __dir__), - File.expand_path("../../../lib/gitlab/usage_data_counters/known_events/*.yml", __dir__) + File.expand_path("../../../lib/gitlab/usage_data_counters/known_events/*.yml", __dir__), + File.expand_path("../../../ee/lib/ee/gitlab/usage_data_counters/known_events/*.yml", __dir__) ].freeze class << self diff --git a/spec/components/pajamas/badge_component_spec.rb b/spec/components/pajamas/badge_component_spec.rb new file mode 100644 index 00000000000..4c564121ba2 --- /dev/null +++ b/spec/components/pajamas/badge_component_spec.rb @@ -0,0 +1,148 @@ +# frozen_string_literal: true + +require "spec_helper" + +RSpec.describe Pajamas::BadgeComponent, type: :component do + let(:text) { "Hello" } + let(:options) { {} } + let(:html_options) { {} } + + before do + render_inline(described_class.new(text, **options, **html_options)) + end + + describe "text param" do + it "is shown inside the badge" do + expect(page).to have_css ".gl-badge", text: text + end + end + + describe "content slot" do + it "can be used instead of the text param" do + render_inline(described_class.new) do + "Slot content" + end + expect(page).to have_css ".gl-badge", text: "Slot content" + end + + it "takes presendence over the text param" do + render_inline(described_class.new(text)) do + "Slot wins." + end + expect(page).to have_css ".gl-badge", text: "Slot wins." + end + end + + describe "options" do + describe "icon" do + let(:options) { { icon: :tanuki } } + + it "adds the correct icon and margin" do + expect(page).to have_css ".gl-icon.gl-badge-icon.gl-mr-2[data-testid='tanuki-icon']" + end + end + + describe "icon_classes" do + let(:options) { { icon: :tanuki, icon_classes: icon_classes } } + + context "as string" do + let(:icon_classes) { "js-special-badge-icon js-extra-special" } + + it "combines custom classes and component classes" do + expect(page).to have_css \ + ".gl-icon.gl-badge-icon.gl-mr-2.js-special-badge-icon.js-extra-special[data-testid='tanuki-icon']" + end + end + + context "as array" do + let(:icon_classes) { %w[js-special-badge-icon js-extra-special] } + + it "combines custom classes and component classes" do + expect(page).to have_css \ + ".gl-icon.gl-badge-icon.gl-mr-2.js-special-badge-icon.js-extra-special[data-testid='tanuki-icon']" + end + end + end + + describe "icon_only" do + let(:options) { { icon: :tanuki, icon_only: true } } + + it "adds no extra margin to the icon" do + expect(page).not_to have_css ".gl-icon.gl-mr-2" + end + + it "adds the text as ARIA label" do + expect(page).to have_css ".gl-badge[aria-label='#{text}'][role='img']" + end + end + + describe "href" do + let(:options) { { href: "/foo" } } + + it "makes the a badge a link" do + expect(page).to have_link text, class: "gl-badge", href: "/foo" + end + end + + describe "size" do + where(:size) { [:sm, :md, :lg] } + + with_them do + let(:options) { { size: size } } + + it "adds size class" do + expect(page).to have_css ".gl-badge.#{size}" + end + end + + context "with unknown size" do + let(:options) { { size: :xxl } } + + it "adds the default size class" do + expect(page).to have_css ".gl-badge.md" + end + end + end + + describe "variant" do + where(:variant) { [:muted, :neutral, :info, :success, :warning, :danger] } + + with_them do + let(:options) { { variant: variant } } + + it "adds variant class" do + expect(page).to have_css ".gl-badge.badge-#{variant}" + end + end + + context "with unknown variant" do + let(:options) { { variant: :foo } } + + it "adds the default variant class" do + expect(page).to have_css ".gl-badge.badge-muted" + end + end + end + end + + describe "HTML options" do + let(:html_options) { { id: "badge-33", data: { foo: "bar" } } } + + it "get added as HTML attributes" do + expect(page).to have_css ".gl-badge#badge-33[data-foo='bar']" + end + + it "can be combined with component options in no particular order" do + render_inline(described_class.new(text, id: "badge-34", variant: :success, data: { foo: "baz" }, size: :sm)) + expect(page).to have_css ".gl-badge.badge-success.sm#badge-34[data-foo='baz']" + end + + context "with custom CSS classes" do + let(:html_options) { { id: "badge-35", class: "js-special-badge" } } + + it "combines custom classes and component classes" do + expect(page).to have_css ".gl-badge.js-special-badge#badge-35" + end + end + end +end diff --git a/spec/components/previews/pajamas/badge_component_preview.rb b/spec/components/previews/pajamas/badge_component_preview.rb new file mode 100644 index 00000000000..e740a4a38aa --- /dev/null +++ b/spec/components/previews/pajamas/badge_component_preview.rb @@ -0,0 +1,61 @@ +# frozen_string_literal: true + +module Pajamas + class BadgeComponentPreview < ViewComponent::Preview + # Badge + # --- + # + # See its design reference [here](https://design.gitlab.com/components/badge). + # + # @param icon select [~, star-o, issue-closed, tanuki] + # @param icon_only toggle + # @param href url + # @param size select [sm, md, lg] + # @param text text + # @param variant select [muted, neutral, info, success, warning, danger] + def default(icon: :tanuki, icon_only: false, href: nil, size: :md, text: "Tanuki", variant: :muted) + render Pajamas::BadgeComponent.new( + text, + icon: icon, + icon_only: icon_only, + href: href, + size: size, + variant: variant + ) + end + + # Using the content slot + # --- + # + # Use the content slot instead of the `text` param when things get more complicated than a plain string. + # All other options (`icon`, `size`, etc.) work as usual. + def slot + render Pajamas::BadgeComponent.new(size: :lg, variant: :info) do + "!ereht olleh".reverse.capitalize + end + end + + # Custom HTML attributes and icon classes + # --- + # + # Any extra options passed into the component are treated as HTML attributes. + # This makes adding data or an id easy. + # + # CSS classes provided with the `class:` option are combined with the component classes. + # + # It is also possible to set custom `icon_classes:`. + # + # The order in which you provide these keywords doesn't matter. + def custom + render Pajamas::BadgeComponent.new( + "I'm special.", + class: "js-special-badge", + data: { count: 1 }, + icon: :tanuki, + icon_classes: ["js-special-badge-icon"], + id: "special-badge-22", + variant: :success + ) + end + end +end diff --git a/spec/controllers/projects/pipeline_schedules_controller_spec.rb b/spec/controllers/projects/pipeline_schedules_controller_spec.rb index fa90a0d9abc..5bcfae4227c 100644 --- a/spec/controllers/projects/pipeline_schedules_controller_spec.rb +++ b/spec/controllers/projects/pipeline_schedules_controller_spec.rb @@ -354,13 +354,14 @@ RSpec.describe Projects::PipelineSchedulesController do end def go - put :update, params: { + put :update, + params: { namespace_id: project.namespace.to_param, project_id: project, id: pipeline_schedule, schedule: schedule }, - as: :html + as: :html end end diff --git a/spec/controllers/projects/service_desk_controller_spec.rb b/spec/controllers/projects/service_desk_controller_spec.rb index bc507a033dc..e078bf9461e 100644 --- a/spec/controllers/projects/service_desk_controller_spec.rb +++ b/spec/controllers/projects/service_desk_controller_spec.rb @@ -4,8 +4,9 @@ require 'spec_helper' RSpec.describe Projects::ServiceDeskController do let_it_be(:project) do - create(:project, :private, :custom_repo, service_desk_enabled: true, - files: { '.gitlab/issue_templates/service_desk.md' => 'template' }) + create(:project, :private, :custom_repo, + service_desk_enabled: true, + files: { '.gitlab/issue_templates/service_desk.md' => 'template' }) end let_it_be(:user) { create(:user) } diff --git a/spec/fixtures/api/schemas/external_validation.json b/spec/fixtures/api/schemas/external_validation.json index 4a2538a020e..411c2ed591b 100644 --- a/spec/fixtures/api/schemas/external_validation.json +++ b/spec/fixtures/api/schemas/external_validation.json @@ -3,6 +3,7 @@ "required" : [ "project", "user", + "credit_card", "pipeline", "builds", "total_builds_count" @@ -43,6 +44,17 @@ "sign_in_count": { "type": "integer" } } }, + "credit_card": { + "type": "object", + "required": [ + "similar_cards_count", + "similar_holder_names_count" + ], + "properties": { + "similar_cards_count": { "type": "integer" }, + "similar_holder_names_count": { "type": "integer" } + } + }, "pipeline": { "type": "object", "required": [ diff --git a/spec/helpers/tab_helper_spec.rb b/spec/helpers/tab_helper_spec.rb index dd5707e2aff..80a1224abbb 100644 --- a/spec/helpers/tab_helper_spec.rb +++ b/spec/helpers/tab_helper_spec.rb @@ -182,7 +182,7 @@ RSpec.describe TabHelper do context 'with data attributes' do it 'creates a tab counter badge with the data attributes' do expect(helper.gl_tab_counter_badge(1, { data: { some_attribute: 'foo' } })).to eq( - '<span data-some-attribute="foo" class="gl-badge badge badge-pill badge-muted sm gl-tab-counter-badge">1</span>' + '<span class="gl-badge badge badge-pill badge-muted sm gl-tab-counter-badge" data-some-attribute="foo">1</span>' ) end end diff --git a/spec/lib/banzai/filter/kroki_filter_spec.rb b/spec/lib/banzai/filter/kroki_filter_spec.rb index 1fb61ad1991..3f4f3aafdd6 100644 --- a/spec/lib/banzai/filter/kroki_filter_spec.rb +++ b/spec/lib/banzai/filter/kroki_filter_spec.rb @@ -46,4 +46,12 @@ RSpec.describe Banzai::Filter::KrokiFilter do expect(doc.to_s).to start_with '<img src="http://localhost:8000/nomnoml/svg/eNqLDsgsSixJrUmtTHXOL80rsVLwzCupKUrMTNHQtC7IzMlJTE_V0KyJyVNQiE5KTSxKidXVjS5ILCrKL4lFFrSyi07LL81RyM0vLckAysRGjxo8avCowaMGjxo8avCowaMGU8lgAE7mIdc=" hidden="" class="js-render-kroki" data-diagram="nomnoml" data-diagram-src="data:text/plain;base64,W1BpcmF0ZXxleWVDb3VudDog' end + + it 'allows the lang attribute on the code tag to support RST files processed by gitlab-markup gem' do + stub_application_setting(kroki_enabled: true, kroki_url: "http://localhost:8000") + text = '[Pirate|eyeCount: Int|raid();pillage()|\n [beard]--[parrot]\n [beard]-:>[foul mouth]\n]' * 25 + doc = filter("<pre><code lang='nomnoml'>#{text}</code></pre>") + + expect(doc.to_s).to start_with '<img src="http://localhost:8000/nomnoml/svg/eNqLDsgsSixJrUmtTHXOL80rsVLwzCupKUrMTNHQtC7IzMlJTE_V0KyJyVNQiE5KTSxKidXVjS5ILCrKL4lFFrSyi07LL81RyM0vLckAysRGjxo8avCowaMGjxo8avCowaMGU8lgAE7mIdc=" hidden="" class="js-render-kroki" data-diagram="nomnoml" data-diagram-src="data:text/plain;base64,W1BpcmF0ZXxleWVDb3VudDog' + end end diff --git a/spec/lib/gitlab/ci/pipeline/chain/validate/external_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/validate/external_spec.rb index fb1a360a4b7..52a00e0d501 100644 --- a/spec/lib/gitlab/ci/pipeline/chain/validate/external_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/chain/validate/external_spec.rb @@ -179,6 +179,70 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Validate::External do perform! end end + + describe 'credit_card' do + context 'with no registered credit_card' do + it 'returns the expected credit card counts' do + expect(::Gitlab::HTTP).to receive(:post) do |_url, params| + payload = Gitlab::Json.parse(params[:body]) + + expect(payload['credit_card']['similar_cards_count']).to eq(0) + expect(payload['credit_card']['similar_holder_names_count']).to eq(0) + end + + perform! + end + end + + context 'with a registered credit card' do + let!(:credit_card) { create(:credit_card_validation, last_digits: 10, holder_name: 'Alice', user: user) } + + it 'returns the expected credit card counts' do + expect(::Gitlab::HTTP).to receive(:post) do |_url, params| + payload = Gitlab::Json.parse(params[:body]) + + expect(payload['credit_card']['similar_cards_count']).to eq(1) + expect(payload['credit_card']['similar_holder_names_count']).to eq(1) + end + + perform! + end + + context 'with similar credit cards registered by other users' do + before do + create(:credit_card_validation, last_digits: 10, holder_name: 'Bob') + end + + it 'returns the expected credit card counts' do + expect(::Gitlab::HTTP).to receive(:post) do |_url, params| + payload = Gitlab::Json.parse(params[:body]) + + expect(payload['credit_card']['similar_cards_count']).to eq(2) + expect(payload['credit_card']['similar_holder_names_count']).to eq(1) + end + + perform! + end + end + + context 'with similar holder names registered by other users' do + before do + create(:credit_card_validation, last_digits: 11, holder_name: 'Alice') + end + + it 'returns the expected credit card counts' do + expect(::Gitlab::HTTP).to receive(:post) do |_url, params| + payload = Gitlab::Json.parse(params[:body]) + + expect(payload['credit_card']['similar_cards_count']).to eq(1) + expect(payload['credit_card']['similar_holder_names_count']).to eq(2) + end + + perform! + end + end + end + end end context 'when EXTERNAL_VALIDATION_SERVICE_TOKEN is set' do diff --git a/spec/models/users/credit_card_validation_spec.rb b/spec/models/users/credit_card_validation_spec.rb index 34cfd500c26..c003e004d29 100644 --- a/spec/models/users/credit_card_validation_spec.rb +++ b/spec/models/users/credit_card_validation_spec.rb @@ -28,4 +28,15 @@ RSpec.describe Users::CreditCardValidation do expect(subject.similar_records).to eq([match2, match1, subject]) end end + + describe '.similar_holder_names_count' do + subject!(:credit_card_validation) { create(:credit_card_validation, holder_name: 'ALICE M SMITH') } + + let!(:match) { create(:credit_card_validation, holder_name: 'Alice M Smith') } + let!(:non_match) { create(:credit_card_validation, holder_name: 'Bob B Brown') } + + it 'returns the count of cards with similar case insensitive holder names' do + expect(subject.similar_holder_names_count).to eq(2) + end + end end diff --git a/spec/services/ci/create_downstream_pipeline_service_spec.rb b/spec/services/ci/create_downstream_pipeline_service_spec.rb index 11fb564b843..c990d195e51 100644 --- a/spec/services/ci/create_downstream_pipeline_service_spec.rb +++ b/spec/services/ci/create_downstream_pipeline_service_spec.rb @@ -440,10 +440,7 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do let!(:trigger_project_bridge) do create( - :ci_bridge, status: :pending, - user: user, - options: trigger_downstream_project, - pipeline: child_pipeline + :ci_bridge, status: :pending, user: user, options: trigger_downstream_project, pipeline: child_pipeline ) end diff --git a/spec/services/ci/create_pipeline_service/logger_spec.rb b/spec/services/ci/create_pipeline_service/logger_spec.rb index c4063751fa8..2be23802757 100644 --- a/spec/services/ci/create_pipeline_service/logger_spec.rb +++ b/spec/services/ci/create_pipeline_service/logger_spec.rb @@ -19,9 +19,9 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes let(:counters) do { 'count' => a_kind_of(Numeric), - 'avg' => a_kind_of(Numeric), - 'max' => a_kind_of(Numeric), - 'min' => a_kind_of(Numeric) + 'avg' => a_kind_of(Numeric), + 'max' => a_kind_of(Numeric), + 'min' => a_kind_of(Numeric) } end diff --git a/spec/services/ci/create_pipeline_service/tags_spec.rb b/spec/services/ci/create_pipeline_service/tags_spec.rb index 7eb9acfb422..7450df11eac 100644 --- a/spec/services/ci/create_pipeline_service/tags_spec.rb +++ b/spec/services/ci/create_pipeline_service/tags_spec.rb @@ -37,7 +37,7 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes context 'tags persistence' do let(:config) do { - build: { + build: { script: 'ls', stage: 'build', tags: build_tag_list(label: 'build') diff --git a/spec/services/ci/job_artifacts/create_service_spec.rb b/spec/services/ci/job_artifacts/create_service_spec.rb index 7b3f67b192f..6809b694b22 100644 --- a/spec/services/ci/job_artifacts/create_service_spec.rb +++ b/spec/services/ci/job_artifacts/create_service_spec.rb @@ -151,9 +151,8 @@ RSpec.describe Ci::JobArtifacts::CreateService do expect { subject }.not_to change { Ci::JobArtifact.count } expect(subject).to match( - a_hash_including(http_status: :bad_request, - message: 'another artifact of the same type already exists', - status: :error)) + a_hash_including( + http_status: :bad_request, message: 'another artifact of the same type already exists', status: :error)) end end end diff --git a/spec/services/ci/retry_job_service_spec.rb b/spec/services/ci/retry_job_service_spec.rb index b14e4187c7a..5914e0fc4c1 100644 --- a/spec/services/ci/retry_job_service_spec.rb +++ b/spec/services/ci/retry_job_service_spec.rb @@ -7,14 +7,13 @@ RSpec.describe Ci::RetryJobService do let_it_be(:developer) { create(:user) } let_it_be(:project) { create(:project, :repository) } let_it_be(:pipeline) do - create(:ci_pipeline, project: project, - sha: 'b83d6e391c22777fca1ed3012fce84f633d7fed0') + create(:ci_pipeline, project: project, sha: 'b83d6e391c22777fca1ed3012fce84f633d7fed0') end let_it_be(:stage) do create(:ci_stage, project: project, - pipeline: pipeline, - name: 'test') + pipeline: pipeline, + name: 'test') end let(:job_variables_attributes) { [{ key: 'MANUAL_VAR', value: 'manual test var' }] } @@ -31,9 +30,8 @@ RSpec.describe Ci::RetryJobService do let_it_be(:downstream_project) { create(:project, :repository) } let_it_be_with_refind(:job) do - create( - :ci_bridge, :success, pipeline: pipeline, downstream: downstream_project, - description: 'a trigger job', stage_id: stage.id + create(:ci_bridge, :success, + pipeline: pipeline, downstream: downstream_project, description: 'a trigger job', stage_id: stage.id ) end @@ -133,9 +131,7 @@ RSpec.describe Ci::RetryJobService do end let!(:subsequent_bridge) do - create(:ci_bridge, :skipped, stage_idx: 2, - pipeline: pipeline, - stage: 'deploy') + create(:ci_bridge, :skipped, stage_idx: 2, pipeline: pipeline, stage: 'deploy') end it 'resumes pipeline processing in the subsequent stage' do @@ -245,10 +241,13 @@ RSpec.describe Ci::RetryJobService do let(:environment_name) { 'review/$CI_COMMIT_REF_SLUG-$GITLAB_USER_ID' } let!(:job) do - create(:ci_build, :with_deployment, environment: environment_name, - options: { environment: { name: environment_name } }, - pipeline: pipeline, stage_id: stage.id, project: project, - user: other_developer) + create(:ci_build, :with_deployment, + environment: environment_name, + options: { environment: { name: environment_name } }, + pipeline: pipeline, + stage_id: stage.id, + project: project, + user: other_developer) end it 'creates a new deployment' do diff --git a/spec/services/deployments/link_merge_requests_service_spec.rb b/spec/services/deployments/link_merge_requests_service_spec.rb index 62adc834733..a653cd2b48b 100644 --- a/spec/services/deployments/link_merge_requests_service_spec.rb +++ b/spec/services/deployments/link_merge_requests_service_spec.rb @@ -159,10 +159,10 @@ RSpec.describe Deployments::LinkMergeRequestsService do it "doesn't link the same merge_request twice" do create(:merge_request, :merged, merge_commit_sha: mr1_merge_commit_sha, - source_project: project) + source_project: project) picked_mr = create(:merge_request, :merged, merge_commit_sha: '123abc', - source_project: project) + source_project: project) # the first MR includes c1c67abba which is a cherry-pick of the fake picked_mr merge request create(:track_mr_picking_note, noteable: picked_mr, project: project, commit_id: 'c1c67abbaf91f624347bb3ae96eabe3a1b742478') diff --git a/spec/services/discussions/capture_diff_note_positions_service_spec.rb b/spec/services/discussions/capture_diff_note_positions_service_spec.rb index 25e5f549bee..8ba54495d4c 100644 --- a/spec/services/discussions/capture_diff_note_positions_service_spec.rb +++ b/spec/services/discussions/capture_diff_note_positions_service_spec.rb @@ -18,8 +18,8 @@ RSpec.describe Discussions::CaptureDiffNotePositionsService do def build_position(diff_refs, new_line: nil, old_line: nil) path = 'files/markdown/ruby-style-guide.md' - Gitlab::Diff::Position.new(old_path: path, new_path: path, - new_line: new_line, old_line: old_line, diff_refs: diff_refs) + Gitlab::Diff::Position.new( + old_path: path, new_path: path, new_line: new_line, old_line: old_line, diff_refs: diff_refs) end def note_for(new_line: nil, old_line: nil) diff --git a/spec/services/environments/stop_service_spec.rb b/spec/services/environments/stop_service_spec.rb index 3ed8a0b1da0..b0c9826b137 100644 --- a/spec/services/environments/stop_service_spec.rb +++ b/spec/services/environments/stop_service_spec.rb @@ -208,8 +208,11 @@ RSpec.describe Environments::StopService do context 'when pipeline is a branch pipeline for merge request' do let(:pipeline) do - create(:ci_pipeline, source: :push, project: project, sha: merge_request.diff_head_sha, - merge_requests_as_head_pipeline: [merge_request]) + create(:ci_pipeline, + source: :push, + project: project, + sha: merge_request.diff_head_sha, + merge_requests_as_head_pipeline: [merge_request]) end it 'does not stop the active environment' do diff --git a/spec/services/event_create_service_spec.rb b/spec/services/event_create_service_spec.rb index e66b413a5c9..06f0eb1efbc 100644 --- a/spec/services/event_create_service_spec.rb +++ b/spec/services/event_create_service_spec.rb @@ -420,9 +420,9 @@ RSpec.describe EventCreateService, :clean_gitlab_redis_cache, :clean_gitlab_redi service.save_designs(author, create: [design]) expect_snowplow_event( - category: Gitlab::UsageDataCounters::TrackUniqueEvents::DESIGN_ACTION.to_s, + category: Gitlab::UsageDataCounters::TrackUniqueEvents::DESIGN_ACTION.to_s, action: 'create', - namespace: design.project.namespace, + namespace: design.project.namespace, user: author, project: design.project, label: 'design_users' @@ -433,9 +433,9 @@ RSpec.describe EventCreateService, :clean_gitlab_redis_cache, :clean_gitlab_redi service.save_designs(author, update: [design]) expect_snowplow_event( - category: Gitlab::UsageDataCounters::TrackUniqueEvents::DESIGN_ACTION.to_s, + category: Gitlab::UsageDataCounters::TrackUniqueEvents::DESIGN_ACTION.to_s, action: 'update', - namespace: design.project.namespace, + namespace: design.project.namespace, user: author, project: design.project, label: 'design_users' @@ -481,9 +481,9 @@ RSpec.describe EventCreateService, :clean_gitlab_redis_cache, :clean_gitlab_redi service.destroy_designs([design], author) expect_snowplow_event( - category: Gitlab::UsageDataCounters::TrackUniqueEvents::DESIGN_ACTION.to_s, + category: Gitlab::UsageDataCounters::TrackUniqueEvents::DESIGN_ACTION.to_s, action: 'destroy', - namespace: design.project.namespace, + namespace: design.project.namespace, user: author, project: design.project, label: 'design_users' diff --git a/spec/services/groups/import_export/import_service_spec.rb b/spec/services/groups/import_export/import_service_spec.rb index 292f2e2b86b..a4dfec4723a 100644 --- a/spec/services/groups/import_export/import_service_spec.rb +++ b/spec/services/groups/import_export/import_service_spec.rb @@ -149,9 +149,9 @@ RSpec.describe Groups::ImportExport::ImportService do it 'logs the import success' do expect(import_logger).to receive(:info).with( - group_id: group.id, + group_id: group.id, group_name: group.name, - message: 'Group Import/Export: Import succeeded' + message: 'Group Import/Export: Import succeeded' ).once subject @@ -161,9 +161,9 @@ RSpec.describe Groups::ImportExport::ImportService do context 'when user does not have correct permissions' do it 'logs the error and raises an exception' do expect(import_logger).to receive(:error).with( - group_id: group.id, + group_id: group.id, group_name: group.name, - message: a_string_including('Errors occurred') + message: a_string_including('Errors occurred') ) expect { subject }.to raise_error(Gitlab::ImportExport::Error) @@ -186,9 +186,9 @@ RSpec.describe Groups::ImportExport::ImportService do it 'logs the error and raises an exception' do expect(import_logger).to receive(:error).with( - group_id: group.id, + group_id: group.id, group_name: group.name, - message: a_string_including('Errors occurred') + message: a_string_including('Errors occurred') ).once expect { subject }.to raise_error(Gitlab::ImportExport::Error) @@ -267,9 +267,9 @@ RSpec.describe Groups::ImportExport::ImportService do it 'logs the import success' do expect(import_logger).to receive(:info).with( - group_id: group.id, + group_id: group.id, group_name: group.name, - message: 'Group Import/Export: Import succeeded' + message: 'Group Import/Export: Import succeeded' ).once subject @@ -279,9 +279,9 @@ RSpec.describe Groups::ImportExport::ImportService do context 'when user does not have correct permissions' do it 'logs the error and raises an exception' do expect(import_logger).to receive(:error).with( - group_id: group.id, + group_id: group.id, group_name: group.name, - message: a_string_including('Errors occurred') + message: a_string_including('Errors occurred') ) expect { subject }.to raise_error(Gitlab::ImportExport::Error) @@ -304,9 +304,9 @@ RSpec.describe Groups::ImportExport::ImportService do it 'logs the error and raises an exception' do expect(import_logger).to receive(:error).with( - group_id: group.id, + group_id: group.id, group_name: group.name, - message: a_string_including('Errors occurred') + message: a_string_including('Errors occurred') ).once expect { subject }.to raise_error(Gitlab::ImportExport::Error) @@ -328,9 +328,9 @@ RSpec.describe Groups::ImportExport::ImportService do allow(Gitlab::Import::Logger).to receive(:build).and_return(import_logger) expect(import_logger).to receive(:info).with( - group_id: group.id, + group_id: group.id, group_name: group.name, - message: 'Group Import/Export: Import succeeded' + message: 'Group Import/Export: Import succeeded' ) subject diff --git a/spec/services/issuable/bulk_update_service_spec.rb b/spec/services/issuable/bulk_update_service_spec.rb index 55e0e799c19..dc72cf04776 100644 --- a/spec/services/issuable/bulk_update_service_spec.rb +++ b/spec/services/issuable/bulk_update_service_spec.rb @@ -47,7 +47,7 @@ RSpec.describe Issuable::BulkUpdateService do let(:bulk_update_params) do { - add_label_ids: add_labels.map(&:id), + add_label_ids: add_labels.map(&:id), remove_label_ids: remove_labels.map(&:id) } end diff --git a/spec/services/issues/create_service_spec.rb b/spec/services/issues/create_service_spec.rb index efff967614d..4a84862b9d5 100644 --- a/spec/services/issues/create_service_spec.rb +++ b/spec/services/issues/create_service_spec.rb @@ -416,7 +416,7 @@ RSpec.describe Issues::CreateService do context "when issuable feature is private" do before do project.project_feature.update!(issues_access_level: ProjectFeature::PRIVATE, - merge_requests_access_level: ProjectFeature::PRIVATE) + merge_requests_access_level: ProjectFeature::PRIVATE) end levels = [Gitlab::VisibilityLevel::INTERNAL, Gitlab::VisibilityLevel::PUBLIC] diff --git a/spec/services/merge_requests/build_service_spec.rb b/spec/services/merge_requests/build_service_spec.rb index 3c9d2271ddc..6a6f01e6a95 100644 --- a/spec/services/merge_requests/build_service_spec.rb +++ b/spec/services/merge_requests/build_service_spec.rb @@ -20,18 +20,30 @@ RSpec.describe MergeRequests::BuildService do let(:merge_request) { service.execute } let(:compare) { double(:compare, commits: commits) } let(:commit_1) do - double(:commit_1, sha: 'f00ba6', safe_message: 'Initial commit', - gitaly_commit?: false, id: 'f00ba6', parent_ids: ['f00ba5']) + double(:commit_1, + sha: 'f00ba6', + safe_message: 'Initial commit', + gitaly_commit?: false, + id: 'f00ba6', + parent_ids: ['f00ba5']) end let(:commit_2) do - double(:commit_2, sha: 'f00ba7', safe_message: "Closes #1234 Second commit\n\nCreate the app", - gitaly_commit?: false, id: 'f00ba7', parent_ids: ['f00ba6']) + double(:commit_2, + sha: 'f00ba7', + safe_message: "Closes #1234 Second commit\n\nCreate the app", + gitaly_commit?: false, + id: 'f00ba7', + parent_ids: ['f00ba6']) end let(:commit_3) do - double(:commit_3, sha: 'f00ba8', safe_message: 'This is a bad commit message!', - gitaly_commit?: false, id: 'f00ba8', parent_ids: ['f00ba7']) + double(:commit_3, + sha: 'f00ba8', + safe_message: 'This is a bad commit message!', + gitaly_commit?: false, + id: 'f00ba8', + parent_ids: ['f00ba7']) end let(:commits) { nil } diff --git a/spec/services/merge_requests/create_service_spec.rb b/spec/services/merge_requests/create_service_spec.rb index 9c9bcb79990..4102cdc101e 100644 --- a/spec/services/merge_requests/create_service_spec.rb +++ b/spec/services/merge_requests/create_service_spec.rb @@ -434,7 +434,7 @@ RSpec.describe MergeRequests::CreateService, :clean_gitlab_redis_shared_state do context "when issuable feature is private" do before do project.project_feature.update!(issues_access_level: ProjectFeature::PRIVATE, - merge_requests_access_level: ProjectFeature::PRIVATE) + merge_requests_access_level: ProjectFeature::PRIVATE) end levels = [Gitlab::VisibilityLevel::INTERNAL, Gitlab::VisibilityLevel::PUBLIC] diff --git a/spec/services/merge_requests/update_service_spec.rb b/spec/services/merge_requests/update_service_spec.rb index 606fd066f1c..64145a85b62 100644 --- a/spec/services/merge_requests/update_service_spec.rb +++ b/spec/services/merge_requests/update_service_spec.rb @@ -510,9 +510,9 @@ RSpec.describe MergeRequests::UpdateService, :mailer do before do create(:ci_pipeline, project: project, - ref: merge_request.source_branch, - sha: merge_request.diff_head_sha, - status: :success) + ref: merge_request.source_branch, + sha: merge_request.diff_head_sha, + status: :success) perform_enqueued_jobs do @merge_request = service.execute(merge_request) diff --git a/spec/services/metrics/dashboard/clone_dashboard_service_spec.rb b/spec/services/metrics/dashboard/clone_dashboard_service_spec.rb index b326fc1726d..47e5557105b 100644 --- a/spec/services/metrics/dashboard/clone_dashboard_service_spec.rb +++ b/spec/services/metrics/dashboard/clone_dashboard_service_spec.rb @@ -62,7 +62,7 @@ RSpec.describe Metrics::Dashboard::CloneDashboardService, :use_clean_rails_memor start_branch: project.default_branch, encoding: 'text', file_path: ".gitlab/dashboards/custom_dashboard.yml", - file_content: file_content_hash.to_yaml + file_content: file_content_hash.to_yaml } end diff --git a/spec/services/notes/create_service_spec.rb b/spec/services/notes/create_service_spec.rb index 37318d76586..74684bc05ce 100644 --- a/spec/services/notes/create_service_spec.rb +++ b/spec/services/notes/create_service_spec.rb @@ -134,8 +134,7 @@ RSpec.describe Notes::CreateService do context 'in a merge request' do let_it_be(:project_with_repo) { create(:project, :repository) } let_it_be(:merge_request) do - create(:merge_request, source_project: project_with_repo, - target_project: project_with_repo) + create(:merge_request, source_project: project_with_repo, target_project: project_with_repo) end context 'noteable highlight cache clearing' do @@ -181,8 +180,7 @@ RSpec.describe Notes::CreateService do it 'does not clear cache when note is not the first of the discussion' do prev_note = - create(:diff_note_on_merge_request, noteable: merge_request, - project: project_with_repo) + create(:diff_note_on_merge_request, noteable: merge_request, project: project_with_repo) reply_opts = opts.merge(in_reply_to_discussion_id: prev_note.discussion_id, type: 'DiffNote', diff --git a/spec/services/notes/destroy_service_spec.rb b/spec/services/notes/destroy_service_spec.rb index be95a4bb181..82caec52aee 100644 --- a/spec/services/notes/destroy_service_spec.rb +++ b/spec/services/notes/destroy_service_spec.rb @@ -57,13 +57,11 @@ RSpec.describe Notes::DestroyService do context 'in a merge request' do let_it_be(:repo_project) { create(:project, :repository) } let_it_be(:merge_request) do - create(:merge_request, source_project: repo_project, - target_project: repo_project) + create(:merge_request, source_project: repo_project, target_project: repo_project) end let_it_be(:note) do - create(:diff_note_on_merge_request, project: repo_project, - noteable: merge_request) + create(:diff_note_on_merge_request, project: repo_project, noteable: merge_request) end it 'does not track issue comment removal usage data' do @@ -84,9 +82,8 @@ RSpec.describe Notes::DestroyService do end it 'does not clear cache when note is not the first of the discussion' do - reply_note = create(:diff_note_on_merge_request, in_reply_to: note, - project: repo_project, - noteable: merge_request) + reply_note = create(:diff_note_on_merge_request, + in_reply_to: note, project: repo_project, noteable: merge_request) expect(merge_request).not_to receive(:diffs) diff --git a/spec/services/packages/debian/parse_debian822_service_spec.rb b/spec/services/packages/debian/parse_debian822_service_spec.rb index ff146fda250..a2731816459 100644 --- a/spec/services/packages/debian/parse_debian822_service_spec.rb +++ b/spec/services/packages/debian/parse_debian822_service_spec.rb @@ -77,7 +77,7 @@ RSpec.describe Packages::Debian::ParseDebian822Service do 'Depends' => '${shlibs:Depends}, ${misc:Depends}', 'Description' => "Some mostly empty lib\nUsed in GitLab tests.\n\nTesting another paragraph." }, - 'Package: sample-udeb' => { + 'Package: sample-udeb' => { 'Package' => 'sample-udeb', 'Package-Type' => 'udeb', 'Architecture' => 'any', diff --git a/spec/services/projects/destroy_service_spec.rb b/spec/services/projects/destroy_service_spec.rb index e4ccd83e3ef..94320320407 100644 --- a/spec/services/projects/destroy_service_spec.rb +++ b/spec/services/projects/destroy_service_spec.rb @@ -312,7 +312,7 @@ RSpec.describe Projects::DestroyService, :aggregate_failures, :event_store_publi before do stub_container_registry_tags(repository: project.full_path + '/image', - tags: ['tag']) + tags: ['tag']) project.container_repositories << container_repository end @@ -350,7 +350,7 @@ RSpec.describe Projects::DestroyService, :aggregate_failures, :event_store_publi context 'when there are tags for legacy root repository' do before do stub_container_registry_tags(repository: project.full_path, - tags: ['tag']) + tags: ['tag']) end context 'when image repository tags deletion succeeds' do diff --git a/spec/services/service_ping/submit_service_ping_service_spec.rb b/spec/services/service_ping/submit_service_ping_service_spec.rb index b863b2a46b0..70de02723cd 100644 --- a/spec/services/service_ping/submit_service_ping_service_spec.rb +++ b/spec/services/service_ping/submit_service_ping_service_spec.rb @@ -386,12 +386,12 @@ RSpec.describe ServicePing::SubmitService do let(:payload) do { uuid: 'uuid', - metric_a: metric_double, - metric_group: { + metric_a: metric_double, + metric_group: { metric_b: metric_double }, - metric_without_timing: "value", - recorded_at: Time.current + metric_without_timing: "value", + recorded_at: Time.current } end @@ -399,10 +399,10 @@ RSpec.describe ServicePing::SubmitService do { metadata: { uuid: 'uuid', - metrics: [ - { name: 'metric_a', time_elapsed: 123 }, - { name: 'metric_group.metric_b', time_elapsed: 123 } - ] + metrics: [ + { name: 'metric_a', time_elapsed: 123 }, + { name: 'metric_group.metric_b', time_elapsed: 123 } + ] } } end diff --git a/spec/services/suggestions/apply_service_spec.rb b/spec/services/suggestions/apply_service_spec.rb index e34324d5fe2..41ccd8523fa 100644 --- a/spec/services/suggestions/apply_service_spec.rb +++ b/spec/services/suggestions/apply_service_spec.rb @@ -35,7 +35,7 @@ RSpec.describe Suggestions::ApplyService do def apply(suggestions, custom_message = nil) result = apply_service.new(user, *suggestions, message: custom_message).execute - suggestions.map { |suggestion| suggestion.reload } + suggestions.map(&:reload) expect(result[:status]).to eq(:success) end @@ -136,21 +136,20 @@ RSpec.describe Suggestions::ApplyService do end let(:merge_request) do - create(:merge_request, source_project: project, - target_project: project, - source_branch: 'master') + create(:merge_request, + source_project: project, target_project: project, source_branch: 'master') end let(:position) { build_position } let(:diff_note) do - create(:diff_note_on_merge_request, noteable: merge_request, - position: position, project: project) + create(:diff_note_on_merge_request, + noteable: merge_request, position: position, project: project) end let(:suggestion) do - create(:suggestion, :content_from_repo, note: diff_note, - to_content: " raise RuntimeError, 'Explosion'\n # explosion?\n") + create(:suggestion, :content_from_repo, + note: diff_note, to_content: " raise RuntimeError, 'Explosion'\n # explosion?\n") end let(:suggestion2) do @@ -311,9 +310,9 @@ RSpec.describe Suggestions::ApplyService do context 'when HEAD from position is different from source branch HEAD on repo' do it 'returns error message' do - allow(suggestion).to receive(:appliable?) { true } - allow(suggestion.position).to receive(:head_sha) { 'old-sha' } - allow(suggestion.noteable).to receive(:source_branch_sha) { 'new-sha' } + allow(suggestion).to receive(:appliable?).and_return(true) + allow(suggestion.position).to receive(:head_sha).and_return('old-sha') + allow(suggestion.noteable).to receive(:source_branch_sha).and_return('new-sha') result = apply_service.new(user, suggestion).execute @@ -430,7 +429,6 @@ RSpec.describe Suggestions::ApplyService do suggestion1_diff = fetch_raw_diff(suggestion1) suggestion2_diff = fetch_raw_diff(suggestion2) - # rubocop: disable Layout/TrailingWhitespace expected_suggestion1_diff = <<-CONTENT.strip_heredoc @@ -10,7 +10,7 @@ module Popen end @@ -442,9 +440,6 @@ RSpec.describe Suggestions::ApplyService do "PWD" => path } CONTENT - # rubocop: enable Layout/TrailingWhitespace - - # rubocop: disable Layout/TrailingWhitespace expected_suggestion2_diff = <<-CONTENT.strip_heredoc @@ -28,7 +28,7 @@ module Popen @@ -455,8 +450,6 @@ RSpec.describe Suggestions::ApplyService do @cmd_status = wait_thr.value.exitstatus end CONTENT - # rubocop: enable Layout/TrailingWhitespace - expect(suggestion1_diff.strip).to eq(expected_suggestion1_diff.strip) expect(suggestion2_diff.strip).to eq(expected_suggestion2_diff.strip) end @@ -508,10 +501,8 @@ RSpec.describe Suggestions::ApplyService do end let(:suggestion) do - create(:suggestion, :content_from_repo, note: diff_note, - lines_above: 2, - lines_below: 3, - to_content: "# multi\n# line\n") + create(:suggestion, :content_from_repo, + note: diff_note, lines_above: 2, lines_below: 3, to_content: "# multi\n# line\n") end let(:suggestions) { [suggestion] } @@ -568,7 +559,7 @@ RSpec.describe Suggestions::ApplyService do end let(:suggestion) do - create_suggestion( to_content: "", new_line: 13) + create_suggestion(to_content: "", new_line: 13) end let(:suggestions) { [suggestion] } @@ -616,14 +607,12 @@ RSpec.describe Suggestions::ApplyService do context 'no permission' do let(:merge_request) do - create(:merge_request, source_project: project, - target_project: project) + create(:merge_request, source_project: project, target_project: project) end let(:diff_note) do - create(:diff_note_on_merge_request, noteable: merge_request, - position: position, - project: project) + create(:diff_note_on_merge_request, + noteable: merge_request, position: position, project: project) end context 'user cannot write in project repo' do @@ -642,14 +631,12 @@ RSpec.describe Suggestions::ApplyService do context 'patch is not appliable' do let(:merge_request) do - create(:merge_request, source_project: project, - target_project: project) + create(:merge_request, source_project: project, target_project: project) end let(:diff_note) do - create(:diff_note_on_merge_request, noteable: merge_request, - position: position, - project: project) + create(:diff_note_on_merge_request, + noteable: merge_request, position: position, project: project) end before do @@ -669,7 +656,7 @@ RSpec.describe Suggestions::ApplyService do let(:result) { apply_service.new(user, suggestion).execute } before do - expect(suggestion.note).to receive(:latest_diff_file) { nil } + expect(suggestion.note).to receive(:latest_diff_file).and_return(nil) end it 'returns error message' do diff --git a/spec/services/work_items/widgets/description_service/update_service_spec.rb b/spec/services/work_items/widgets/description_service/update_service_spec.rb index 582d9dc85f7..4275950e720 100644 --- a/spec/services/work_items/widgets/description_service/update_service_spec.rb +++ b/spec/services/work_items/widgets/description_service/update_service_spec.rb @@ -13,7 +13,7 @@ RSpec.describe WorkItems::Widgets::DescriptionService::UpdateService do let(:current_user) { author } let(:work_item) do create(:work_item, author: author, project: project, description: 'old description', - last_edited_at: Date.yesterday, last_edited_by: random_user + last_edited_at: Date.yesterday, last_edited_by: random_user ) end diff --git a/spec/tooling/danger/datateam_spec.rb b/spec/tooling/danger/datateam_spec.rb index e4ab3a6f4b1..de8a93baa27 100644 --- a/spec/tooling/danger/datateam_spec.rb +++ b/spec/tooling/danger/datateam_spec.rb @@ -24,7 +24,7 @@ RSpec.describe Tooling::Danger::Datateam do impacted: true, impacted_files: %w(db/structure.sql) }, - 'with structure.sql changes and Data Warehouse::Impact Check label' => { + 'with structure.sql changes and Data Warehouse::Impact Check label' => { modified_files: %w(db/structure.sql), changed_lines: ['+group_id bigint NOT NULL)'], mr_labels: ['Data Warehouse::Impact Check'], diff --git a/spec/views/projects/tags/index.html.haml_spec.rb b/spec/views/projects/tags/index.html.haml_spec.rb index aff233b697f..99db5d9e2a8 100644 --- a/spec/views/projects/tags/index.html.haml_spec.rb +++ b/spec/views/projects/tags/index.html.haml_spec.rb @@ -7,8 +7,8 @@ RSpec.describe 'projects/tags/index.html.haml' do let_it_be(:git_tag) { project.repository.tags.last } let_it_be(:release) do create(:release, project: project, - sha: git_tag.target_commit.sha, - tag: 'v1.1.0') + sha: git_tag.target_commit.sha, + tag: 'v1.1.0') end let(:pipeline) { create(:ci_pipeline, :success, project: project, ref: git_tag.name, sha: release.sha) } diff --git a/spec/workers/emails_on_push_worker_spec.rb b/spec/workers/emails_on_push_worker_spec.rb index 3e313610054..7d11957e2df 100644 --- a/spec/workers/emails_on_push_worker_spec.rb +++ b/spec/workers/emails_on_push_worker_spec.rb @@ -51,7 +51,7 @@ RSpec.describe EmailsOnPushWorker, :mailer do context "when push is a force push to delete commits" do before do data_force_push = data.stringify_keys.merge( - "after" => data[:before], + "after" => data[:before], "before" => data[:after] ) diff --git a/spec/workers/pages_domain_ssl_renewal_cron_worker_spec.rb b/spec/workers/pages_domain_ssl_renewal_cron_worker_spec.rb index 563bbdef1be..70ffef5342e 100644 --- a/spec/workers/pages_domain_ssl_renewal_cron_worker_spec.rb +++ b/spec/workers/pages_domain_ssl_renewal_cron_worker_spec.rb @@ -25,8 +25,8 @@ RSpec.describe PagesDomainSslRenewalCronWorker do end let!(:domain_with_failed_auto_ssl) do - create(:pages_domain, :without_certificate, :without_key, project: project, - auto_ssl_enabled: true, auto_ssl_failed: true) + create(:pages_domain, :without_certificate, :without_key, + project: project, auto_ssl_enabled: true, auto_ssl_failed: true) end let!(:domain_with_expired_auto_ssl) do |