diff --git a/.gitignore b/.gitignore index 93b360575852a315f2e28b346a0a36de8e82d957..63e7966576d42069a73a52bb8a6a51dca7bd822b 100644 --- a/.gitignore +++ b/.gitignore @@ -126,6 +126,3 @@ config/helpers/tailwind/css_in_js.js # ruby-lsp .index.yml - -# Rubocop cop documentation generation -.yardoc diff --git a/.gitlab/ci/pages.gitlab-ci.yml b/.gitlab/ci/pages.gitlab-ci.yml index fdd631a97b986eee20795ff29a645d0d74774af7..08812f0f9deb7059feab76a5f3cf08476d25e7e0 100644 --- a/.gitlab/ci/pages.gitlab-ci.yml +++ b/.gitlab/ci/pages.gitlab-ci.yml @@ -16,7 +16,6 @@ pages: - "compile-storybook" - "update-tests-metadata" - "generate-frontend-fixtures-mapping" - - "rubocop:docs-site" before_script: - apt-get update && apt-get -y install brotli gzip script: @@ -25,7 +24,6 @@ pages: - mkdir -p public/$(dirname "$KNAPSACK_RSPEC_SUITE_REPORT_PATH") public/$(dirname "$FLAKY_RSPEC_SUITE_REPORT_PATH") public/$(dirname "$RSPEC_PACKED_TESTS_MAPPING_PATH") public/$(dirname "$RSPEC_PACKED_TESTS_MAPPING_ALT_PATH") public/$(dirname "$FRONTEND_FIXTURES_MAPPING_PATH") - mv coverage/ public/coverage-ruby/ || true - mv coverage-frontend/ public/coverage-frontend/ || true - - mv rubocop/docs-hugo/public/ public/rubocop-docs/ || true - mv storybook/public public/storybook || true - cp .public/assets/application-*.css public/application.css || true - mv $KNAPSACK_RSPEC_SUITE_REPORT_PATH public/$KNAPSACK_RSPEC_SUITE_REPORT_PATH || true diff --git a/.gitlab/ci/static-analysis.gitlab-ci.yml b/.gitlab/ci/static-analysis.gitlab-ci.yml index 6940ff4c28229f4ff33f2e161112053f1fbf6b7d..d65b64e54b91ef8f305dd2bbd6d8b8630be94be5 100644 --- a/.gitlab/ci/static-analysis.gitlab-ci.yml +++ b/.gitlab/ci/static-analysis.gitlab-ci.yml @@ -147,24 +147,6 @@ rubocop-docs: script: - bundle exec rubocop --only Gitlab/DocumentationLinks/Link -rubocop:docs-site: - extends: - - .static-analysis-base - - .rubocop-job-cache - allow_failure: true - script: - - apt-get update && apt-get -y install hugo - - rake rubocop:docs - - cd rubocop/docs-hugo - - hugo --minify - - cd ../../ - artifacts: - name: rubocop-docs-site - expire_in: 31d - when: always - paths: - - rubocop/docs-hugo/public - rails-next-dependency-check: stage: lint needs: [] diff --git a/Gemfile b/Gemfile index 65c19ff2544edc9239faa472eb3b32cbccb6551a..f28d7e6705f99ddebdb2471fda9e00b0ac6ddbee 100644 --- a/Gemfile +++ b/Gemfile @@ -552,8 +552,6 @@ group :development, :test do gem 'vite_ruby', '~> 3.9.0', feature_category: :shared gem 'gitlab-housekeeper', path: 'gems/gitlab-housekeeper', feature_category: :tooling - - gem 'yard', '~> 0.9', require: false, feature_category: :tooling end group :development, :test, :danger do diff --git a/Gemfile.lock b/Gemfile.lock index a798465ac8c950de85d9ff25b5c5bab4964cb4ec..46dcd7f564e951c6f03ed671d6d1dc9c71215f1b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -2362,7 +2362,6 @@ DEPENDENCIES webrick (~> 1.8.1) wikicloth (= 0.8.1) yajl-ruby (~> 1.4.3) - yard (~> 0.9) BUNDLED WITH 2.5.11 diff --git a/Gemfile.next.lock b/Gemfile.next.lock index 1fd857c7dfb7926f588367a7eb9d9a742b21b1ba..4e5a8ad367926b9ff87a3fc91071afa747437f7f 100644 --- a/Gemfile.next.lock +++ b/Gemfile.next.lock @@ -2397,7 +2397,6 @@ DEPENDENCIES webrick (~> 1.8.1) wikicloth (= 0.8.1) yajl-ruby (~> 1.4.3) - yard (~> 0.9) BUNDLED WITH 2.5.11 diff --git a/lib/tasks/rubocop.rake b/lib/tasks/rubocop.rake index a5ca101355c232a41d287588fa2798c548f3bb9b..0c257585bd0ac023cd16d603ba00b8f540441da9 100644 --- a/lib/tasks/rubocop.rake +++ b/lib/tasks/rubocop.rake @@ -73,80 +73,5 @@ unless Rails.env.production? todo_dir.delete_inspected end end - - desc 'Update documentation of all cops' - task :docs do - require 'yard' - - YARD::Rake::YardocTask.new(:yard_rubocop_docs) do |task| - task.files = ['rubocop/cop/**/*.rb'] + gitlab_styles_cops - task.options = ['--no-output'] - end - - Rake::Task[:yard_rubocop_docs].invoke - - cops_registry = RuboCop::Cop::Registry.new - gitlab_cops.each { |cop| cops_registry.enlist(cop) } - - FileUtils.rm_rf('tmp/docs/') - FileUtils.rm_rf('rubocop/docs-hugo/content/doc/') - - require_relative '../../rubocop/cops_documentation_generator' - - departments = cops_registry.map { |cop_class| cop_class.to_s.split("::")[-2] }.uniq - formatter = RuboCop::CopsDocumentationGenerator::Formatters::HugoMarkdown.new - base_dir = 'tmp' - - RuboCop::CopsDocumentationGenerator.new(departments:, cops_registry:, formatter:, base_dir:).call - - puts "Moving content to `rubocop/docs-hugo/content/doc/`..." - FileUtils.mv('tmp/docs/modules/ROOT/pages/', 'rubocop/docs-hugo/content/doc/') - FileUtils.rm_rf('tmp/docs/') - - update_headers_for_cop_documentations - end - - def update_headers_for_cop_documentations - documentation_metadata = <<~META - --- - title: %{title} - --- - META - - Dir.glob('rubocop/docs-hugo/content/doc/*.md').each do |file| - content = File.read(file) - page_h1_match = content.match(/^# +(.*)\n/) - title = page_h1_match.present? ? "#{page_h1_match[1]} RuboCop docs" : 'RuboCop docs' - content.sub!(page_h1_match[0], '') if page_h1_match - current_documentation_metadata = format(documentation_metadata, title:) - File.write(file, current_documentation_metadata + content) unless content.start_with?("---\n") - end - end - - def gitlab_cops - # Pre-load existing cops so we can exclude them from the list of cops we generate documentation for - require 'rubocop' - require 'rubocop-capybara' - require 'rubocop-factory_bot' - require 'rubocop-graphql' - require 'rubocop-performance' - require 'rubocop-rails' - require 'rubocop-rspec' - require 'rubocop-rspec_rails' - - existing_cops = RuboCop::Cop::Registry.global.to_a - - Dir['rubocop/cop/**/*.rb'].each { |file| require_relative File.join('../..', file) } - gitlab_styles_cops.each { |file| require file } - - RuboCop::Cop::Registry.global.to_a - existing_cops - end - - def gitlab_styles_cops - return @gitlab_styles_cops if defined?(@gitlab_styles_cops) - - gem_dir = Gem::Specification.find_by_name('gitlab-styles').gem_dir - @gitlab_styles_cops ||= Dir["#{gem_dir}/lib/rubocop/cop/**/*.rb"] - end end end diff --git a/rubocop/cop/gitlab/avoid_current_organization.rb b/rubocop/cop/gitlab/avoid_current_organization.rb index b6a10609c7e29957f84ccfc78f900b76c941a52f..57d64d0d05ac1a92cde04d6a592b1dc20eff1e8a 100644 --- a/rubocop/cop/gitlab/avoid_current_organization.rb +++ b/rubocop/cop/gitlab/avoid_current_organization.rb @@ -9,29 +9,29 @@ module Gitlab # # @example # - # # bad - # class SomeService - # def execute - # do_something_with(Current.organization) - # end + # # bad + # class SomeService + # def execute + # do_something_with(Current.organization) # end + # end # - # # good - # class SomeController < ApplicationController - # def create - # response = SomeService.new(organization: Current.organization).execute - # end + # # good + # class SomeController < ApplicationController + # def create + # response = SomeService.new(organization: Current.organization).execute # end + # end # - # class SomeService - # def initialize(organization:) - # @organization = organization - # end + # class SomeService + # def initialize(organization:) + # @organization = organization + # end # - # def execute - # do_something_with(@organization) - # end + # def execute + # do_something_with(@organization) # end + # end # # class AvoidCurrentOrganization < RuboCop::Cop::Base diff --git a/rubocop/cop/gitlab/event_store_subscriber.rb b/rubocop/cop/gitlab/event_store_subscriber.rb index 97494038e99dad16e2af0f6b428ae7f584dc32b5..04dc29ec400e36673ba07a70bd3963b354145512 100644 --- a/rubocop/cop/gitlab/event_store_subscriber.rb +++ b/rubocop/cop/gitlab/event_store_subscriber.rb @@ -9,28 +9,26 @@ module Gitlab # must implement the method #handle_event(event) and # must not override the method #perform(*args) # - # @example + # # bad + # class MySubscriber + # include Gitlab::EventStore::Subscriber # - # # bad - # class MySubscriber - # include Gitlab::EventStore::Subscriber + # def perform(*args) + # end + # end # - # def perform(*args) - # end - # end + # # bad + # class MySubscriber + # include Gitlab::EventStore::Subscriber + # end # - # # bad - # class MySubscriber - # include Gitlab::EventStore::Subscriber - # end + # # good + # class MySubscriber + # include Gitlab::EventStore::Subscriber # - # # good - # class MySubscriber - # include Gitlab::EventStore::Subscriber - # - # def handle_event(event) - # end - # end + # def handle_event(event) + # end + # end # class EventStoreSubscriber < RuboCop::Cop::Base SUBSCRIBER_MODULE_NAME = 'Gitlab::EventStore::Subscriber' diff --git a/rubocop/cop/rails/strong_params.rb b/rubocop/cop/rails/strong_params.rb index c0430b1faa0e2c9a663e135962d577dcff3ca090..6651da575d79c1606bce492ac600cf16452f1b4d 100644 --- a/rubocop/cop/rails/strong_params.rb +++ b/rubocop/cop/rails/strong_params.rb @@ -3,7 +3,7 @@ module RuboCop module Cop module Rails - # Cop that detects passing `params` as an argument without making them + # Cop that detects passing params as an argument without making them # StrongParams first. Used to reduce the likelihood of input # validation errors outside of ActiveModel. E.g. when a parameter # is an array of strings instead of a single string, and that gets diff --git a/rubocop/cop/redis_queue_usage.rb b/rubocop/cop/redis_queue_usage.rb index bef24663b44c2540f5d6dbae6bb6301bb2645f2b..d993abc63276494a8568b090f4e0560e7917ee74 100644 --- a/rubocop/cop/redis_queue_usage.rb +++ b/rubocop/cop/redis_queue_usage.rb @@ -2,8 +2,8 @@ module RuboCop module Cop - # This class complements `Rubocop::Cop::SidekiqRedisCall` by disallowing the use of - # `Gitlab::Redis::Queues` with the exception of initialising Sidekiq and monitoring. + # This class complements Rubocop::Cop::SidekiqRedisCall by disallowing the use of + # Gitlab::Redis::Queues with the exception of initialising Sidekiq and monitoring. class RedisQueueUsage < RuboCop::Cop::Base MSG = 'Gitlab::Redis::Queues should only be used by Sidekiq initializers. '\ 'Assignments or using its params to initialise another connection is not allowed.' diff --git a/rubocop/cop/scalability/file_uploads.rb b/rubocop/cop/scalability/file_uploads.rb index 8764eab1682d756ad67186711b4e2318801a5e1d..8f8c9605d094f773518dc4d43b558b1e8752b2b6 100644 --- a/rubocop/cop/scalability/file_uploads.rb +++ b/rubocop/cop/scalability/file_uploads.rb @@ -3,7 +3,7 @@ module RuboCop module Cop module Scalability - # This cop checks for `File` `params` in API + # This cop checks for `File` params in API # # @example # diff --git a/rubocop/cop/scalability/idempotent_worker.rb b/rubocop/cop/scalability/idempotent_worker.rb index 012ffd4e2dc970390292414ab96fc6fafad19475..fee9e952105e457834cb2ffa46e49846e8c83309 100644 --- a/rubocop/cop/scalability/idempotent_worker.rb +++ b/rubocop/cop/scalability/idempotent_worker.rb @@ -9,19 +9,19 @@ module Scalability # # @example # - # # bad - # class TroubleMakerWorker - # def perform - # end + # # bad + # class TroubleMakerWorker + # def perform # end + # end # - # # good - # class NiceWorker - # idempotent! + # # good + # class NiceWorker + # idempotent! # - # def perform - # end + # def perform # end + # end # class IdempotentWorker < RuboCop::Cop::Base include CodeReuseHelpers diff --git a/rubocop/cop/sidekiq_load_balancing/worker_data_consistency.rb b/rubocop/cop/sidekiq_load_balancing/worker_data_consistency.rb index 8915d537ebb70fdba059dec293580d94129540d6..1d421a5d017075d74a56baa9ba2571cb4c161582 100644 --- a/rubocop/cop/sidekiq_load_balancing/worker_data_consistency.rb +++ b/rubocop/cop/sidekiq_load_balancing/worker_data_consistency.rb @@ -9,19 +9,19 @@ module SidekiqLoadBalancing # # @example # - # # bad - # class BadWorker - # def perform - # end + # # bad + # class BadWorker + # def perform # end + # end # - # # good - # class GoodWorker - # data_consistency :delayed + # # good + # class GoodWorker + # data_consistency :delayed # - # def perform - # end + # def perform # end + # end # class WorkerDataConsistency < RuboCop::Cop::Base include CodeReuseHelpers diff --git a/rubocop/cop/static_translation_definition.rb b/rubocop/cop/static_translation_definition.rb index c863de81b94d127e6caf6b9b57d19dc69a0ddab4..55c1176e31bbdc58f7e662c934099711f29839f4 100644 --- a/rubocop/cop/static_translation_definition.rb +++ b/rubocop/cop/static_translation_definition.rb @@ -9,47 +9,47 @@ module Cop # # @example # - # # bad - # class MyExample - # # Constant - # Translation = _('A translation.') + # # bad + # class MyExample + # # Constant + # Translation = _('A translation.') # - # # Class scope - # field :foo, title: _('A title') + # # Class scope + # field :foo, title: _('A title') # - # validates :title, :presence, message: _('is missing') + # validates :title, :presence, message: _('is missing') # - # # Memoized - # def self.translations - # @cached ||= { text: _('A translation.') } - # end + # # Memoized + # def self.translations + # @cached ||= { text: _('A translation.') } + # end # - # included do # or prepended or class_methods - # self.error_message = _('Something went wrong.') - # end + # included do # or prepended or class_methods + # self.error_message = _('Something went wrong.') # end + # end # - # # good - # class MyExample - # # Keep translations dynamic. - # Translation = -> { _('A translation.') } - # # OR - # def translation - # _('A translation.') - # end + # # good + # class MyExample + # # Keep translations dynamic. + # Translation = -> { _('A translation.') } + # # OR + # def translation + # _('A translation.') + # end # - # field :foo, title: -> { _('A title') } + # field :foo, title: -> { _('A title') } # - # validates :title, :presence, message: -> { _('is missing') } + # validates :title, :presence, message: -> { _('is missing') } # - # def self.translations - # { text: _('A translation.') } - # end + # def self.translations + # { text: _('A translation.') } + # end # - # included do # or prepended or class_methods - # self.error_message = -> { _('Something went wrong.') } - # end + # included do # or prepended or class_methods + # self.error_message = -> { _('Something went wrong.') } # end + # end # class StaticTranslationDefinition < RuboCop::Cop::Base MSG = <<~TEXT.tr("\n", ' ') diff --git a/rubocop/cop/style/inline_disable_annotation.rb b/rubocop/cop/style/inline_disable_annotation.rb index a5fb301267b93f23b8a45679ce8fe37306bac82b..c3db541fe8241cddcb4df6e658d54e94dbf57ab4 100644 --- a/rubocop/cop/style/inline_disable_annotation.rb +++ b/rubocop/cop/style/inline_disable_annotation.rb @@ -2,20 +2,20 @@ module RuboCop module Cop - # rubocop:disable Lint/RedundantCopDisableDirective -- For examples module Style - # Checks that RuboCop inline disabling is formatted according + # rubocop:disable Lint/RedundantCopDisableDirective -- For examples + # Checks that rubocop inline disabling is formatted according # to guidelines. # See: https://docs.gitlab.com/ee/development/rubocop_development_guide.html#disabling-rules-inline, # https://gitlab.com/gitlab-org/gitlab/-/issues/428762 # - # @example # # bad # # rubocop:disable Some/Cop, Another/Cop # # # good # # rubocop:disable Some/Cop, Another/Cop -- Some reason # + # rubocop:enable Lint/RedundantCopDisableDirective class InlineDisableAnnotation < RuboCop::Cop::Base include RangeHelp @@ -47,6 +47,5 @@ def on_new_investigation end end end - # rubocop:enable Lint/RedundantCopDisableDirective end end diff --git a/rubocop/cops_documentation_generator.rb b/rubocop/cops_documentation_generator.rb deleted file mode 100644 index 24c5fb0fd01841fbd40d9dba652ef45cc54d5063..0000000000000000000000000000000000000000 --- a/rubocop/cops_documentation_generator.rb +++ /dev/null @@ -1,494 +0,0 @@ -# frozen_string_literal: true - -require 'fileutils' -require 'yard' - -# This file has been copied from https://github.com/rubocop/rubocop/blob/master/lib/rubocop/cops_documentation_generator.rb -# It has been altered to work with Markdown, and the changes will be pushed upstream - -# rubocop:disable Lint/RedundantCopDisableDirective -- Don't remove the disables already in place from the upstream repo, so it's easier to merge back - -# Class for generating documentation of all cops departments -# @api private -module RuboCop - class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength -- Exception already existed in upstream repo - module Formatters - class Markdown - def to_filename(base_name) - "#{base_name}.md" - end - - def to_header(text, level: 1) - "\n#{'#' * level} #{text}\n\n" - end - - def to_link(link_to, text, anchor: nil) - link_to = "#{link_to}##{anchor}" if anchor - - "[#{text}](#{link_to})" - end - - def to_bullet_point(text) - "- #{text}\n" - end - - def to_anchor(anchor_text) - "<a name=\"#{anchor_text}\"></a>\n" - end - - def to_comment(comment) - <<~COMMENT - <!--- - #{comment} - --> - COMMENT - end - - def to_code(ruby_code) - <<~CODE - ```ruby - #{ruby_code.text.gsub('@good', '# good').gsub('@bad', '# bad').strip} - ``` - CODE - end - - def to_table(headers, content) - table = "| #{headers.join(' | ')} |\n" - table += "| #{headers.map { |header| ('-' * header.length) }.join(' | ')} |\n" - - content.each do |row| - table += "| #{row.join(' | ')} |\n" - end - table - end - end - - class HugoMarkdown < Markdown - def to_link(link_to, text, anchor: nil) - link_to = "#{link_to}##{anchor}" if anchor - - %{[#{text}]({{< ref "#{link_to}" >}})} - end - end - - class Asciidoc - def to_filename(base_name) - "#{base_name}.adoc" - end - - def to_header(text, level: 1) - "#{'=' * level} #{text}\n\n" - end - - def to_link(link_to, text, anchor: nil) - if anchor - "xref:#{link_to}[#{text}#{anchor}]" - else - "xref:#{link_to}[#{text}]" - end - end - - def to_code(ruby_code) - content = +"[source,ruby]\n----\n" - content << ruby_code.text.gsub('@good', '# good').gsub('@bad', '# bad').strip - content << "\n----\n" - content - end - - def to_bullet_point(text) - "* #{text}\n" - end - - def to_anchor(anchor_text) - "[##{anchor_text}]\n" - end - - def to_comment(comment) - <<~COMMENT - //// - #{comment} - //// - COMMENT - end - - def to_table(header, content) - table = ['|===', "| #{header.join(' | ')}\n\n"].join("\n") - marked_contents = content.map do |plain_content| - # Escape `|` with backslash to prevent the regexp `|` is not used as a table separator. - plain_content.map { |c| "| #{c.gsub('|', '\|')}" }.join("\n") - end - table << marked_contents.join("\n\n") - table << "\n|===\n" - end - end - end - - include ::RuboCop::Cop::Documentation - - CopData = Struct.new( - :cop, :description, :example_objects, :safety_objects, :see_objects, :config, keyword_init: true - ) - - # rubocop:disable Layout/HashAlignment -- Rule differs in upstream repo - STRUCTURE = { - name: ->(data) { cop_header(data.cop) }, - required_ruby_version: ->(data) { required_ruby_version(data.cop) }, - properties: ->(data) { properties(data.cop) }, - description: ->(data) { "#{data.description}\n" }, - safety: ->(data) { safety_object(data.safety_objects, data.cop) }, - examples: ->(data) { examples(data.example_objects, data.cop) }, - configuration: ->(data) { configurations(data.cop.department, data.config, data.cop) }, - references: ->(data) { references(data.cop, data.see_objects) } - }.freeze - # rubocop:enable Layout/HashAlignment - - # This class will only generate documentation for cops that belong to one of - # the departments given in the `departments` array. E.g. if we only wanted - # documentation for Lint cops: - # - # CopsDocumentationGenerator.new(departments: ['Lint']).call - # - # You can append additional information: - # - # callback = ->(data) { required_rails_version(data.cop) } - # CopsDocumentationGenerator.new(extra_info: { ruby_version: callback }).call - # - # This will insert the string returned from the lambda _after_ the section from RuboCop itself. - # See `CopsDocumentationGenerator::STRUCTURE` for available sections. - # - def initialize( - formatter: Formatters::Asciidoc.new, cops_registry: RuboCop::Cop::Registry.global, - departments: [], extra_info: {}, base_dir: Dir.pwd - ) - @departments = departments.map(&:to_sym).sort! - @extra_info = extra_info - @formatter = formatter - @cops = cops_registry - @config = RuboCop::ConfigLoader.default_configuration - @base_dir = base_dir - @docs_path = "#{base_dir}/docs/modules/ROOT" - FileUtils.mkdir_p("#{@docs_path}/pages") - end - - def call - YARD::Registry.load! - departments.each { |department| print_cops_of_department(department) } - - print_table_of_contents - ensure - RuboCop::ConfigLoader.default_configuration = nil - end - - private - - attr_reader :departments, :cops, :config, :docs_path, :formatter - - def cops_of_department(department) - cops.with_department(department).sort! - end - - def cops_body(data) - check_examples_to_have_the_default_enforced_style!(data.example_objects, data.cop) - - content = +'' - STRUCTURE.each do |section, block| - content << instance_exec(data, &block) - content << @extra_info[section].call(data) if @extra_info[section] - end - content - end - - def check_examples_to_have_the_default_enforced_style!(example_objects, cop) - return if example_objects.none? - - examples_describing_enforced_style = example_objects.map(&:name).grep(/EnforcedStyle:/) - return if examples_describing_enforced_style.none? - - if examples_describing_enforced_style.index { |name| name.match?('default') }.nonzero? - raise "Put the example with the default EnforcedStyle on top for #{cop.cop_name}" - end - - return if examples_describing_enforced_style.any? { |name| name.match?('default') } - - raise "Specify the default EnforcedStyle for #{cop.cop_name}" - end - - def examples(example_objects, cop) - return '' if example_objects.none? - - example_objects.each_with_object(cop_subsection('Examples', cop).dup) do |example, content| - content << "\n" unless content.end_with?("\n\n") - content << example_header(example.name, cop) unless example.name == '' - content << formatter.to_code(example) - end - end - - def safety_object(safety_objects, cop) - return '' if safety_objects.all? { |s| s.text.blank? } - - safety_objects.each_with_object(cop_subsection('Safety', cop).dup) do |safety_object, content| - next if safety_object.text.blank? - - content << "\n" unless content.end_with?("\n\n") - content << safety_object.text - content << "\n" - end - end - - def required_ruby_version(cop) - return '' unless cop.respond_to?(:required_minimum_ruby_version) - - if cop.required_minimum_ruby_version - requirement = cop.required_minimum_ruby_version - elsif cop.required_maximum_ruby_version - requirement = "<= #{cop.required_maximum_ruby_version}" - else - return '' - end - - "NOTE: Requires Ruby version #{requirement}\n\n" - end - - # rubocop:disable Metrics/MethodLength -- Exception already existed in upstream repo - def properties(cop) - header = [ - 'Enabled by default', 'Safe', 'Supports autocorrection', 'Version Added', - 'Version Changed' - ] - autocorrect = if cop.support_autocorrect? # rubocop:disable Cop/LineBreakAroundConditionalBlock -- Rule differs in upstream repo - context = cop.new.always_autocorrect? ? 'Always' : 'Command-line only' - - "#{context}#{' (Unsafe)' unless cop.new(config).safe_autocorrect?}" - else - 'No' - end - cop_config = config.for_cop(cop) - content = [[ - cop_status(cop_config.fetch('Enabled')), - cop_config.fetch('Safe', true) ? 'Yes' : 'No', - autocorrect, - cop_config.fetch('VersionAdded', '-'), - cop_config.fetch('VersionChanged', '-') - ]] - "#{formatter.to_table(header, content)}\n" - end - # rubocop:enable Metrics/MethodLength - - def cop_header(cop) - content = +"\n" - content << formatter.to_anchor(to_anchor(cop.cop_name)) - content << formatter.to_header(cop.cop_name, level: 2) - content - end - - def cop_subsection(title, cop) - content = +"\n" - content << formatter.to_anchor("#{to_anchor(title)}-#{to_anchor(cop.cop_name)}") - content << formatter.to_header(title, level: 3) - content - end - - def example_header(title, cop) - content = +formatter.to_anchor("#{to_anchor(title)}-#{to_anchor(cop.cop_name)}") - content << formatter.to_header(title, level: 4) - content - end - - def configurations(department, pars, cop) # rubocop:disable Metrics/MethodLength -- Rule differs in upstream repo - return '' if pars.empty? - - header = ['Name', 'Default value', 'Configurable values'] - configs = pars - .each_key - .reject { |key| key.start_with?('Supported') } - .reject { |key| key.start_with?('AllowMultipleStyles') } - content = configs.map do |name| - configurable = configurable_values(pars, name) - default = format_table_value(pars[name]) - - [configuration_name(department, name), default, configurable] - end - - cop_subsection('Configurable attributes', cop) + formatter.to_table(header, content) - end - - def configuration_name(department, name) - return name unless name == 'AllowMultilineFinalElement' - - filename = formatter.to_filename(department_to_basename(department)) - "xref:#{filename}#allowmultilinefinalelement[AllowMultilineFinalElement]" - end - - # rubocop:disable Metrics/CyclomaticComplexity,Metrics/MethodLength -- Exception already existed in upstream repo - def configurable_values(pars, name) - case name - when /^Enforced/ - supported_style_name = RuboCop::Cop::Util.to_supported_styles(name) - format_table_value(pars[supported_style_name]) - when 'IndentationWidth' - 'Integer' - when 'Database' - format_table_value(pars['SupportedDatabases']) - else - case pars[name] - when String - 'String' - when Integer - 'Integer' - when Float - 'Float' - when true, false - 'Boolean' - when Array - 'Array' - else - '' - end - end - end - # rubocop:enable Metrics/CyclomaticComplexity,Metrics/MethodLength - - def format_table_value(val) # rubocop:disable Metrics/MethodLength -- Rule differs in upstream repo - value = - case val - when Array - if val.empty? - '`[]`' - else - val.map { |config| format_table_value(config) }.join(', ') - end - else - wrap_backtick(val.nil? ? '<none>' : val) - end - value.gsub("#{@base_dir}/", '').rstrip - end - - def wrap_backtick(value) - if value.is_a?(String) - # Use `+` to prevent text like `**/*.gemspec`, `spec/**/*` from being bold. - value.include?('*') ? "`+#{value}+`" : "`#{value}`" - else - "`#{value}`" - end - end - - def references(cop, see_objects) # rubocop:disable Metrics/AbcSize -- Exception already existed in upstream repo - cop_config = config.for_cop(cop) - urls = RuboCop::Cop::MessageAnnotator.new(config, cop.name, cop_config, {}).urls - return '' if urls.empty? && see_objects.empty? - - content = cop_subsection('References', cop) - content << urls.map { |url| "* #{url}" }.join("\n") - content << "\n" unless urls.empty? - content << see_objects.map { |see| "* #{see.name}" }.join("\n") - content << "\n" unless see_objects.empty? - content - end - - def footer_for_department(department) - return '' unless department == :Layout - - filename = formatter.to_filename("#{department_to_basename(department)}_footer") - file = "#{docs_path}/partials/#{filename}" - return '' unless File.exist?(file) - - "\ninclude::../partials/#{filename}[]\n" - end - - # rubocop:disable Metrics/MethodLength -- Exception already existed in upstream repo - def print_cops_of_department(department) - selected_cops = cops_of_department(department) - content = formatter.to_comment(+<<~HEADER) - Do NOT edit this file by hand directly, as it is automatically generated. - - Please make any necessary changes to the cop documentation within the source files themselves. - HEADER - content += formatter.to_header(department) - selected_cops.each { |cop| content << print_cop_with_doc(cop) } - content << footer_for_department(department) - file_name = formatter.to_filename("#{docs_path}/pages/#{department_to_basename(department)}") - File.open(file_name, 'w') do |file| - puts "* generated #{file_name}" - file.write("#{content.strip}\n") - end - end - # rubocop:enable Metrics/MethodLength - - def print_cop_with_doc(cop) # rubocop:todo Metrics/AbcSize, Metrics/MethodLength -- Exception already existed in upstream repo - cop_config = config.for_cop(cop) - non_display_keys = %w[ - AutoCorrect Description Enabled StyleGuide Reference Safe SafeAutoCorrect VersionAdded - VersionChanged - ] - pars = cop_config.reject { |k| non_display_keys.include? k } - description = 'No documentation' - example_objects = safety_objects = see_objects = [] - cop_code(cop) do |code_object| - description = code_object.docstring unless code_object.docstring.blank? - example_objects = code_object.tags('example') - safety_objects = code_object.tags('safety') - see_objects = code_object.tags('see') - end - data = CopData.new(cop: cop, description: description, example_objects: example_objects, - safety_objects: safety_objects, see_objects: see_objects, config: pars) # rubocop:disable Layout/ArgumentAlignment -- Exception already existed in upstream repo - cops_body(data) - end - - def cop_code(cop) - YARD::Registry.all(:class).detect do |code_object| - next unless RuboCop::Cop::Badge.for(code_object.to_s) == cop.badge - - yield code_object - end - end - - def table_of_content_for_department(department) - type_title = department[0].upcase + department[1..] - filename = formatter.to_filename(department_to_basename(department)) - content = +formatter.to_header("Department #{formatter.to_link(filename, type_title)}", level: 3) - cops_of_department(department).each do |cop| - anchor = to_anchor(cop.cop_name) - content << formatter.to_bullet_point(formatter.to_link(filename, cop.cop_name, anchor:)) - end - - content - end - - def print_table_of_contents - path = formatter.to_filename("#{docs_path}/pages/cops") - - File.write(path, table_contents) and return unless File.exist?(path) # rubocop:disable Style/AndOr -- Rule differs in upstream repo - - original = File.read(path) - content = +"// START_COP_LIST\n\n" - - content << table_contents - - content << "\n// END_COP_LIST" - - content = original.sub(%r{// START_COP_LIST.+// END_COP_LIST}m, content) - File.write(path, content) - end - - def table_contents - departments.map { |department| table_of_content_for_department(department) }.join("\n") - end - - def cop_status(status) - return 'Disabled' unless status - - status == 'pending' ? 'Pending' : 'Enabled' - end - - # HTML anchor are somewhat limited in what characters they can contain, just - # accept a known-good subset. As long as it's consistent it doesn't matter. - # - # Style/AccessModifierDeclarations => styleaccessmodifierdeclarations - # OnlyFor: [] (default) => onlyfor_-__-_default_ - def to_anchor(title) - title.delete('/').tr(' ', '-').gsub(/[^a-zA-Z0-9-]/, '_').downcase - end - end -end - -# rubocop:enable Lint/RedundantCopDisableDirective diff --git a/rubocop/docs-hugo/.gitignore b/rubocop/docs-hugo/.gitignore deleted file mode 100644 index 5215ac93c30e50d77c56824d884e004ed4f2f298..0000000000000000000000000000000000000000 --- a/rubocop/docs-hugo/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -public/ -resources/_gen/ -.hugo_build.lock -content/doc/ diff --git a/rubocop/docs-hugo/content/_index.md b/rubocop/docs-hugo/content/_index.md deleted file mode 100644 index 12dc7dcc602e668bc0770e3fad1e3106ac7082da..0000000000000000000000000000000000000000 --- a/rubocop/docs-hugo/content/_index.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -title: "GitLab RuboCop Documentation" -type: page -cascade: - _target: - kind: home - layout: single ---- - -{{< readFile "doc/cops.md" >}} diff --git a/rubocop/docs-hugo/go.mod b/rubocop/docs-hugo/go.mod deleted file mode 100644 index 5efcbc860d67e55945f5c9077d86b6018d283ad0..0000000000000000000000000000000000000000 --- a/rubocop/docs-hugo/go.mod +++ /dev/null @@ -1,5 +0,0 @@ -module gitlab.com/gitlab-org/gitlab/rubocop/docs-hugo - -go 1.23 - -require github.com/nanxiaobei/hugo-paper v0.0.0-20241205182052-8eeb1e8a513d // indirect diff --git a/rubocop/docs-hugo/go.sum b/rubocop/docs-hugo/go.sum deleted file mode 100644 index 0cf3bf325aa31ddefb7aa4154d99cd13472cd732..0000000000000000000000000000000000000000 --- a/rubocop/docs-hugo/go.sum +++ /dev/null @@ -1,2 +0,0 @@ -github.com/nanxiaobei/hugo-paper v0.0.0-20241205182052-8eeb1e8a513d h1:a0JmoLOkCtzijzho4MvMkqVlafP2Yne1sJ+Y6xzkhHg= -github.com/nanxiaobei/hugo-paper v0.0.0-20241205182052-8eeb1e8a513d/go.mod h1:cS2hTYPgmZ2FkPTQbOiX6vB0yLQcWD067kJx2lkRPVQ= diff --git a/rubocop/docs-hugo/hugo.toml b/rubocop/docs-hugo/hugo.toml deleted file mode 100644 index 4fd61dfe516ee2dd2fd4ae458b3c9c9c04f0959f..0000000000000000000000000000000000000000 --- a/rubocop/docs-hugo/hugo.toml +++ /dev/null @@ -1,14 +0,0 @@ -baseURL = 'https://gitlab-org.gitlab.io/gitlab/rubocop-docs/' -languageCode = 'en-us' -title = 'GitLab RuboCop Docs' -theme = ["github.com/nanxiaobei/hugo-paper"] - -[[module.mounts]] -source = 'content' -target = 'content' - -[params] - mainSections = ["doc"] - -[permalinks] - doc = "/:filename/" diff --git a/rubocop/docs-hugo/layouts/partials/footer.html b/rubocop/docs-hugo/layouts/partials/footer.html deleted file mode 100644 index 6d7e1c781325a83d682e96a3a008c49e01942859..0000000000000000000000000000000000000000 --- a/rubocop/docs-hugo/layouts/partials/footer.html +++ /dev/null @@ -1,19 +0,0 @@ -<footer - class="mx-auto flex h-[4.5rem] max-w-[--w] items-center px-8 text-xs uppercase tracking-wider opacity-60" -> - - <div class="mr-auto"> - <a class="link mx-6" href="https://gitlab.com/gitlab-org/gitlab" >GitLab Source</a> - <a class="link mx-6" href="https://gitlab.com/gitlab-org/gitlab-styles" >GitLab Styles Source</a> - </div> - <a class="link mx-6" href="https://gohugo.io/" rel="noopener" target="_blank" - >powered by hugoï¸ï¸</a - >ï¸ - <a - class="link" - href="https://github.com/nanxiaobei/hugo-paper" - rel="noopener" - target="_blank" - >hugo-paper</a - > -</footer> diff --git a/rubocop/docs-hugo/layouts/shortcodes/readFile.html b/rubocop/docs-hugo/layouts/shortcodes/readFile.html deleted file mode 100644 index 4c5a2b025812a5b61983addb2611fa0404b18d76..0000000000000000000000000000000000000000 --- a/rubocop/docs-hugo/layouts/shortcodes/readFile.html +++ /dev/null @@ -1,4 +0,0 @@ -{{ $file := .Get 0 }} -{{ $content := readFile $file }} -{{ $content := split $content "---" }} -{{ index $content 2 | markdownify }} diff --git a/spec/rubocop/cops_documentation_generator_spec.rb b/spec/rubocop/cops_documentation_generator_spec.rb deleted file mode 100644 index 9e9398da579e482c0fb092e95b5358a092a9f511..0000000000000000000000000000000000000000 --- a/spec/rubocop/cops_documentation_generator_spec.rb +++ /dev/null @@ -1,38 +0,0 @@ -# frozen_string_literal: true - -require 'rubocop' -require 'tmpdir' -require_relative '../../rubocop/cops_documentation_generator' - -RSpec.describe RuboCop::CopsDocumentationGenerator, feature_category: :tooling do - around do |example| - new_global = RuboCop::Cop::Registry.new([RuboCop::Cop::Style::HashSyntax]) - RuboCop::Cop::Registry.with_temporary_global(new_global) { example.run } - end - - context 'when using default Asciidoc formatter' do - it 'generates docs without errors' do - Dir.mktmpdir do |tmpdir| - generator = described_class.new(departments: %w[Style], base_dir: tmpdir) - - expect do - generator.call - end.to output(%r{generated .*docs/modules/ROOT/pages/cops_style.adoc}).to_stdout - end - end - end - - context 'when using Markdown formatter' do - it 'generates docs without errors' do - Dir.mktmpdir do |tmpdir| - generator = described_class.new( - formatter: RuboCop::CopsDocumentationGenerator::Formatters::Markdown.new, departments: %w[Style], - base_dir: tmpdir - ) - expect do - generator.call - end.to output(%r{generated .*docs/modules/ROOT/pages/cops_style.md}).to_stdout - end - end - end -end diff --git a/spec/tasks/rubocop_rake_spec.rb b/spec/tasks/rubocop_rake_spec.rb index 901c75e50662271f3631f2f44eaa1b3f1f85aa26..2dff7fdaf0956d42f42cc8963eede33b8d16f6de 100644 --- a/spec/tasks/rubocop_rake_spec.rb +++ b/spec/tasks/rubocop_rake_spec.rb @@ -16,6 +16,7 @@ include NextInstanceOf before do + stub_const('Rails', double(:rails_env)) allow(Rails).to receive(:env).and_return(double(production?: false)) stub_const('ENV', ENV.to_hash.dup) @@ -188,31 +189,6 @@ def with_inflections ActiveSupport::Inflector::Inflections.instance_variable_set(:@__instance__, en: original) end end - - describe 'docs' do - subject(:run_task) { run_rake_task('rubocop:docs') } - - before do - FileUtils.rm_rf('rubocop/docs-hugo/content/doc/') - end - - it 'generates markdown files for the GitLab cops and not upstream cops' do - rspec_cops_file = 'rubocop/docs-hugo/content/doc/cops_rspec.md' - expect { run_task }.to change { File.exist?(rspec_cops_file) }.from(false).to(true) - rspec_cops_data = File.read(rspec_cops_file) - - expect(rspec_cops_data).to include("---\ntitle: RSpec RuboCop docs\n---") - - # Cop defined in GitLab repo - expect(rspec_cops_data).to include('## RSpec/AnyInstanceOf') - - # Cop defined in gitlab-styles - expect(rspec_cops_data).to include('## RSpec/SingleLineHook') - - # Exists upstream, so shouldn't be included - expect(rspec_cops_data).not_to include('## RSpec/AlignLeftLetBrace') - end - end end # rubocop:enable RSpec/VerifiedDoubles