[rubygems/rubygems] Add a quality spec to ensure man pages are up to date:

- Ref #8802
- ### Problem

  Whenever a bundler command options is added, we want to make
  sure that the associated command man page is updated to reflect
  the new option (e.g. this mistake was made in #8624)

  ### Solution

  In #8802 we discussed a bit on the implementation which would rely
  on parsing ronn files and introduce some conventions on how options
  documented in man pages should be written.

  I figured I would try a simpler approach by just checking if the man
  page of a command list options using a simple regex.

  Pros:

  - Simpler as we don't have to parse ronn files.
  - No need to modify all existing man pages.

  Cons:

  - We can only verify one way (CLI options -> man pages).
    If a CLI option get removed, we won't be able to warn that
    the existing document man page option needs to be removed.

e10e60bd33
This commit is contained in:
Edouard CHIN 2025-07-23 16:10:50 +02:00 committed by Hiroshi SHIBATA
parent 80712140af
commit 4dd708bf5d

View file

@ -251,9 +251,62 @@ RSpec.describe "The library itself" do
expect(lib_code).to eq(spec_code)
end
it "documents all cli command options in their associated man pages" do
commands = normalize_commands_and_options(Bundler::CLI)
cli_and_man_pages_in_sync!(commands)
Bundler::CLI.subcommand_classes.each do |_, klass|
subcommands = normalize_commands_and_options(klass)
cli_and_man_pages_in_sync!(subcommands)
end
end
private
def each_line(filename, &block)
File.readlines(filename, encoding: "UTF-8").each_with_index(&block)
end
def normalize_commands_and_options(command_class)
commands = {}
command_class.commands.each do |command_name, command|
next if command.is_a?(Bundler::Thor::HiddenCommand)
key = command.ancestor_name || command_name
commands[key] ||= []
# Verify that all subcommands are documented in the main command's man page.
commands[key] << command_name unless command_class == Bundler::CLI
command.options.each do |_, option|
commands[key] << option.switch_name
end
end
commands
end
def cli_and_man_pages_in_sync!(commands)
undocumented_options = ["--all", "--local-git"]
commands.each do |command_name, opts|
man_page_path = man_tracked_files.find {|f| File.basename(f) == "bundle-#{command_name}.1.ronn" }
expect(man_page_path).to_not be_nil, "The command #{command_name} has no associated man page."
next if opts.empty?
man_page_content = File.read(man_page_path)
opts.each do |option_name|
next if undocumented_options.include?(option_name.to_s)
error_msg = <<~EOM
The command #{command_name} has no mention of the option or subcommand `#{option_name}` in its man page.
Document the `#{option_name}` in the man page to discard this error.
EOM
expect(man_page_content).to match(option_name), error_msg
end
end
end
end