tasks
Folders and files
Name | Name | Last commit date | ||
---|---|---|---|---|
parent directory.. | ||||
# typed: true # frozen_string_literal: true require "tapioca" require "tapioca/internal" desc("Updates the README file") task :readme do def assert_synchronized(path) # Do not print diff and yield whether exit code was zero sh("test -z \"$(git status --porcelain #{path})\"") do |outcome, _| return if outcome # Output diff before raising error sh("git status --porcelain #{path}") warn(<<~WARNING) The `#{path}` is out of sync. Run `bin/readme` and commit the results. WARNING exit! end end def skip_command?(command) ignored_commands = ["configure", "init"] command.hidden? || command.name.start_with?("__") || ignored_commands.include?(command.name) end def skip_option?(option) option.name == "auth" end def option_value(option) fallback_value = case option.type when :boolean true when :numeric 1 when :hash {} when :array [] when :string "" end if option.default.nil? fallback_value else option.default end end def command_options(command) command.options.filter_map do |name, opt| next if skip_option?(opt) [name.to_s, option_value(opt)] end.to_h end def config Tapioca::Cli.commands.filter_map do |command_name, command| next if skip_command?(command) [command_name, command_options(command)] end.to_h end def replace_section(contents, section_name, replacement) contents.sub( /(<!-- START_#{section_name} -->).+(<!-- END_#{section_name} -->)/m, <<~OUT.chomp \\1 #{replacement.chomp} \\2 OUT ) end def print_config_template(contents) replace_section(contents, "CONFIG_TEMPLATE", <<~MARKDOWN) ```yaml #{config.to_yaml.chomp} ``` MARKDOWN end class FakeShell < Thor::Shell::Basic DEFAULT_TERMINAL_WIDTH = 120 def stdout @stdout ||= StringIO.new end def contents stdout.string end def clear @stdout = StringIO.new self end def terminal_width DEFAULT_TERMINAL_WIDTH end end def print_help(contents) shell = FakeShell.new $PROGRAM_NAME = "tapioca" section = "HELP" Tapioca::Cli.help(shell.clear) contents = replace_section(contents, section, <<~MARKDOWN) ```shell $ #{$PROGRAM_NAME} help #{shell.contents.chomp} ``` MARKDOWN contents end def print_commands_help(contents) shell = FakeShell.new Tapioca::Cli.commands.each_key do |command_name| $PROGRAM_NAME = "tapioca" section = "HELP_COMMAND_#{command_name.upcase}" Tapioca::Cli.command_help(shell.clear, command_name) contents = replace_section(contents, section, <<~MARKDOWN) ```shell $ #{$PROGRAM_NAME} help #{command_name} #{shell.contents.chomp} ``` MARKDOWN end contents end require "kramdown" class TocConverter < Kramdown::Converter::Toc class << self def convert(doc, options) result, _ = super(doc.root, options) convert_to_list_items(result.children) end def convert_to_list_items(elements) elements.flat_map do |elem| level = elem.value.options[:level] text = elem.value.options[:raw_text] id = elem.attr[:id] padding = " " * (level - 2) ["#{padding}* [#{text}](##{id})"] + convert_to_list_items(elem.children) end end end def in_toc?(el) super && el.options[:raw_text] !~ /<!--\sno_toc\s-->/ end end def print_toc(contents) section = "TOC" doc = Kramdown::Document.new(contents) toc = TocConverter.convert(doc, { auto_id: true, toc_levels: (2..6) }) replace_section(contents, section, toc.join("\n")) end path = "#{Dir.pwd}/README.md" contents = File.read(path) contents = print_config_template(contents) contents = print_help(contents) contents = print_commands_help(contents) contents = print_toc(contents) File.write(path, contents) assert_synchronized(path) if ENV["CI"] == "true" end