Merge pull request #50384 from skipkayhil/hm-fix-alphabetical-configuring

Fix railspect not validating alphabetical order
This commit is contained in:
Jonathan Hefner 2024-01-01 11:37:44 -06:00 committed by GitHub
commit dfc6adc2d2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 96 additions and 38 deletions

@ -209,14 +209,6 @@ Makes application believe that all requests are arriving over SSL. This is usefu
Enables writing log file output immediately instead of buffering. Defaults to Enables writing log file output immediately instead of buffering. Defaults to
`true`. `true`.
#### `config.autoload_once_paths`
Accepts an array of paths from which Rails will autoload constants that won't be wiped per request. Relevant if reloading is enabled, which it is by default in the `development` environment. Otherwise, all autoloading happens only once. All elements of this array must also be in `autoload_paths`. Default is an empty array.
#### `config.autoload_paths`
Accepts an array of paths from which Rails will autoload constants. Default is an empty array. Since [Rails 6](upgrading_ruby_on_rails.html#autoloading), it is not recommended to adjust this. See [Autoloading and Reloading Constants](autoloading_and_reloading_constants.html#autoload-paths).
#### `config.autoload_lib(ignore:)` #### `config.autoload_lib(ignore:)`
This method adds `lib` to `config.autoload_paths` and `config.eager_load_paths`. This method adds `lib` to `config.autoload_paths` and `config.eager_load_paths`.
@ -235,6 +227,14 @@ The method `config.autoload_lib_once` is similar to `config.autoload_lib`, excep
By calling `config.autoload_lib_once`, classes and modules in `lib` can be autoloaded, even from application initializers, but won't be reloaded. By calling `config.autoload_lib_once`, classes and modules in `lib` can be autoloaded, even from application initializers, but won't be reloaded.
#### `config.autoload_once_paths`
Accepts an array of paths from which Rails will autoload constants that won't be wiped per request. Relevant if reloading is enabled, which it is by default in the `development` environment. Otherwise, all autoloading happens only once. All elements of this array must also be in `autoload_paths`. Default is an empty array.
#### `config.autoload_paths`
Accepts an array of paths from which Rails will autoload constants. Default is an empty array. Since [Rails 6](upgrading_ruby_on_rails.html#autoloading), it is not recommended to adjust this. See [Autoloading and Reloading Constants](autoloading_and_reloading_constants.html#autoload-paths).
#### `config.beginning_of_week` #### `config.beginning_of_week`
Sets the default beginning of week for the Sets the default beginning of week for the
@ -310,10 +310,6 @@ Sets the format used in responses when errors occur in the development environme
Controls whether or not someone can start a console in sandbox mode. This is helpful to avoid a long running session of sandbox console, that could lead a database server to run out of memory. Defaults to `false`. Controls whether or not someone can start a console in sandbox mode. This is helpful to avoid a long running session of sandbox console, that could lead a database server to run out of memory. Defaults to `false`.
#### `config.sandbox_by_default`
When `true`, rails console starts in sandbox mode. To start rails console in non-sandbox mode, `--no-sandbox` must be specified. This is helpful to avoid accidental writing to the production database. Defaults to `false`.
#### `config.dom_testing_default_html_version` #### `config.dom_testing_default_html_version`
Controls whether an HTML4 parser or an HTML5 parser is used by default by the test helpers in Action View, Action Dispatch, and `rails-dom-testing`. Controls whether an HTML4 parser or an HTML5 parser is used by default by the test helpers in Action View, Action Dispatch, and `rails-dom-testing`.
@ -539,6 +535,10 @@ Enables or disables reloading of classes only when tracked files change. By defa
Causes the app to not boot if a master key hasn't been made available through `ENV["RAILS_MASTER_KEY"]` or the `config/master.key` file. Causes the app to not boot if a master key hasn't been made available through `ENV["RAILS_MASTER_KEY"]` or the `config/master.key` file.
#### `config.sandbox_by_default`
When `true`, rails console starts in sandbox mode. To start rails console in non-sandbox mode, `--no-sandbox` must be specified. This is helpful to avoid accidental writing to the production database. Defaults to `false`.
#### `config.secret_key_base` #### `config.secret_key_base`
The fallback for specifying the input secret for an application's key generator. The fallback for specifying the input secret for an application's key generator.

@ -6,17 +6,37 @@ module RailInspector
class Configuring class Configuring
module Check module Check
class GeneralConfiguration class GeneralConfiguration
attr_reader :checker class AccessorParser
def initialize(checker)
@checker = checker
end
def initialize(checker) def call
visitor = Visitor::Attribute.new
visitor.visit(app_config_tree)
visitor.attribute_map[APP_CONFIG_CONST]["attr_accessor"]
end
private
APP_CONFIG_CONST = "Rails::Application::Configuration"
def app_config_tree
@checker.parse(APPLICATION_CONFIGURATION_PATH)
end
end
attr_reader :checker, :expected_accessors
def initialize(checker, expected_accessors: AccessorParser.new(checker).call)
@checker = checker @checker = checker
@expected_accessors = expected_accessors
end end
def check def check
header, *config_sections = documented_general_config header, *config_sections = documented_general_config
non_nested_accessors = non_nested_accessors =
general_accessors.reject do |a| expected_accessors.reject do |a|
config_sections.any? { |section| /\.#{a}\./.match?(section[0]) } config_sections.any? { |section| /\.#{a}\./.match?(section[0]) }
end end
@ -24,23 +44,21 @@ def check
config_header = "#### `config.#{accessor}`" config_header = "#### `config.#{accessor}`"
unless config_sections.any? { |section| section[0] == config_header } unless config_sections.any? { |section| section[0] == config_header }
checker.errors << config_header checker.errors << "Missing configuration: #{config_header}"
config_sections << [config_header, "", "FIXME", ""] config_sections << [config_header, "", "FIXME", ""]
end end
end end
checker.doc.general_config = new_config = header + config_sections.sort_by { |section| section[0].split("`")[1] }.flatten
[header] +
config_sections.sort_by { |section| section[0].split("`")[1] } return if new_config == checker.doc.general_config
checker.errors << "General Configuration is not alphabetical"
checker.doc.general_config = new_config
end end
private private
APP_CONFIG_CONST = "Rails::Application::Configuration"
def app_config_tree
checker.parse(APPLICATION_CONFIGURATION_PATH)
end
def documented_general_config def documented_general_config
checker checker
.doc .doc
@ -48,19 +66,6 @@ def documented_general_config
.slice_before { |line| line.start_with?("####") } .slice_before { |line| line.start_with?("####") }
.to_a .to_a
end end
def general_accessors
visitor.attribute_map[APP_CONFIG_CONST]["attr_accessor"]
end
def visitor
@visitor ||=
begin
visitor = Visitor::Attribute.new
visitor.visit(app_config_tree)
visitor
end
end
end end
end end
end end

@ -0,0 +1,50 @@
# frozen_string_literal: true
require "test_helper"
require "rail_inspector/configuring"
class TestGeneralConfiguration < ActiveSupport::TestCase
def test_errors_when_configuration_out_of_order
with_general_config <<~MD
#### `config.b`
#### `config.a`
MD
check([:a, :b]).check
assert_not_empty checker.errors
end
def test_no_errors_when_configuration_alphabetical
with_general_config <<~MD
#### `config.a`
#### `config.b`
MD
check([:a, :b]).check
assert_empty checker.errors
end
private
def check(expected_accessors)
@check ||= RailInspector::Configuring::Check::GeneralConfiguration.new(checker, expected_accessors: expected_accessors)
end
def checker
@checker ||= RailInspector::Configuring.new("../..")
end
HEADER = [
"### Rails General Configuration",
"",
"The following configuration methods are to be called on a `Rails::Railtie` object, such as a subclass of `Rails::Engine` or `Rails::Application`.",
"",
].freeze
def with_general_config(markdown)
checker.doc.general_config = HEADER + markdown.split("\n")
end
end

@ -0,0 +1,3 @@
# frozen_string_literal: true
require "active_support"