lib/discourse_theme/cli.rb in discourse_theme-0.8.0 vs lib/discourse_theme/cli.rb in discourse_theme-0.9.0

- old
+ new

@@ -1,6 +1,8 @@ # frozen_string_literal: true + +require_relative "cli_commands/rspec" module DiscourseTheme class Cli @@cli_settings_filename = File.expand_path("~/.discourse_theme") def self.settings_file @@ -10,18 +12,29 @@ def self.settings_file=(filename) @@cli_settings_filename = filename end def usage - puts "Usage: discourse_theme COMMAND [--reset]" - puts - puts "discourse_theme new DIR - Creates a new theme in the designated directory" - puts "discourse_theme download DIR - Downloads a theme from the server and stores in the designated directory" - puts "discourse_theme upload DIR - Uploads the theme directory to Discourse" - puts "discourse_theme watch DIR - Watches the theme directory and synchronizes with Discourse" - puts - puts "Use --reset to change the configuration for a directory" + puts <<~USAGE + Usage: discourse_theme COMMAND [DIR] [OPTIONS] + + Commands: + new DIR - Creates a new theme in the specified directory. + download DIR - Downloads a theme from the server and stores it in the specified directory. + upload DIR - Uploads the theme from the specified directory to Discourse. + watch DIR - Watches the theme in the specified directory and synchronizes any changes with Discourse. + rspec DIR [OPTIONS] - Runs the RSpec tests in the specified directory. The tests can be run using a local Discourse repository or a Docker container. + --headless - Runs the RSpec system type tests in headless mode. Applies to both modes. + + If specified directory has been configured to run in a Docker container, the additional options are supported. + --rebuild - Forces a rebuilds of Docker container. + --verbose - Runs the command to prepare the Docker container in verbose mode. + + Global Options: + --reset - Resets the configuration for the specified directory. + USAGE + exit 1 end def run(args) usage unless args[1] @@ -36,11 +49,13 @@ theme_id = settings.theme_id components = settings.components if command == "new" - raise DiscourseTheme::ThemeError.new "'#{dir}' is not empty" if Dir.exist?(dir) && !Dir.empty?(dir) + if Dir.exist?(dir) && !Dir.empty?(dir) + raise DiscourseTheme::ThemeError.new "'#{dir}' is not empty" + end raise DiscourseTheme::ThemeError.new "git is not installed" if !command?("git") raise DiscourseTheme::ThemeError.new "yarn is not installed" if !command?("yarn") DiscourseTheme::Scaffold.generate(dir) watch_theme?(args) @@ -55,36 +70,47 @@ options["Sync with existing theme: '#{theme["name"]}' (id:#{theme_id})"] = :default end options["Create and sync with a new theme"] = :create options["Select a different theme"] = :select - choice = UI.select('How would you like to sync this theme?', options.keys) + choice = UI.select("How would you like to sync this theme?", options.keys) if options[choice] == :create theme_id = nil elsif options[choice] == :select themes = render_theme_list(theme_list) - choice = UI.select('Which theme would you like to sync with?', themes) + choice = UI.select("Which theme would you like to sync with?", themes) theme_id = extract_theme_id(choice) theme = theme_list.find { |t| t["id"] == theme_id } end - about_json = JSON.parse(File.read(File.join(dir, 'about.json'))) rescue nil + about_json = + begin + JSON.parse(File.read(File.join(dir, "about.json"))) + rescue StandardError + nil + end already_uploaded = !!theme is_component = theme&.[]("component") component_count = about_json&.[]("components")&.length || 0 if !already_uploaded && !is_component && component_count > 0 options = {} options["Yes"] = :sync options["No"] = :none options = options.sort_by { |_, b| b == components.to_sym ? 0 : 1 }.to_h if components - choice = UI.select('Would you like to update child theme components?', options.keys) + choice = UI.select("Would you like to update child theme components?", options.keys) settings.components = components = options[choice].to_s end - uploader = DiscourseTheme::Uploader.new(dir: dir, client: client, theme_id: theme_id, components: components) + uploader = + DiscourseTheme::Uploader.new( + dir: dir, + client: client, + theme_id: theme_id, + components: components, + ) UI.progress "Uploading theme from #{dir}" settings.theme_id = theme_id = uploader.upload_full_theme UI.success "Theme uploaded (id:#{theme_id})" @@ -109,11 +135,11 @@ raise DiscourseTheme::ThemeError.new "'#{dir} is not empty" unless Dir.empty?(dir) UI.progress "Loading theme list..." themes = render_theme_list(client.get_themes_list) - choice = UI.select('Which theme would you like to download?', themes) + choice = UI.select("Which theme would you like to download?", themes) theme_id = extract_theme_id(choice) UI.progress "Downloading theme into #{dir}" downloader.download_theme(theme_id) @@ -122,19 +148,29 @@ UI.success "Theme downloaded" watch_theme?(args) elsif command == "upload" raise DiscourseTheme::ThemeError.new "'#{dir} does not exist" unless Dir.exist?(dir) - raise DiscourseTheme::ThemeError.new "No theme_id is set, please sync via the 'watch' command initially" if theme_id == 0 + if theme_id == 0 + raise DiscourseTheme::ThemeError.new "No theme_id is set, please sync via the 'watch' command initially" + end client = DiscourseTheme::Client.new(dir, settings, reset: reset) theme_list = client.get_themes_list theme = theme_list.find { |t| t["id"] == theme_id } - raise DiscourseTheme::ThemeError.new "theme_id is set, but the theme does not exist in Discourse" unless theme + unless theme + raise DiscourseTheme::ThemeError.new "theme_id is set, but the theme does not exist in Discourse" + end - uploader = DiscourseTheme::Uploader.new(dir: dir, client: client, theme_id: theme_id, components: components) + uploader = + DiscourseTheme::Uploader.new( + dir: dir, + client: client, + theme_id: theme_id, + components: components, + ) UI.progress "Uploading theme (id:#{theme_id}) from #{dir} " settings.theme_id = theme_id = uploader.upload_full_theme UI.success "Theme uploaded (id:#{theme_id})" @@ -142,10 +178,17 @@ if client.is_theme_creator UI.info "Manage: #{client.root}/my/themes" else UI.info "Manage: #{client.root}/admin/customize/themes/#{theme_id}" end + elsif command == "rspec" + DiscourseTheme::CliCommands::Rspec.run( + settings: settings, + dir: dir, + args: args, + reset: reset, + ) else usage end UI.progress "Exiting..." @@ -156,31 +199,35 @@ end private def command?(cmd) - exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : [''] - ENV['PATH'].split(File::PATH_SEPARATOR).each do |path| - exts.each do |ext| - exe = File.join(path, "#{cmd}#{ext}") - return true if File.executable?(exe) && !File.directory?(exe) + exts = ENV["PATHEXT"] ? ENV["PATHEXT"].split(";") : [""] + ENV["PATH"] + .split(File::PATH_SEPARATOR) + .each do |path| + exts.each do |ext| + exe = File.join(path, "#{cmd}#{ext}") + return true if File.executable?(exe) && !File.directory?(exe) + end end - end false end def watch_theme?(args) if UI.yes?("Would you like to start 'watching' this theme?") args[0] = "watch" - UI.progress "Running discourse_theme #{args.join(' ')}" + UI.progress "Running discourse_theme #{args.join(" ")}" run(args) end end def render_theme_list(themes) - themes.sort_by { |t| t["updated_at"] } - .reverse.map { |theme| "#{theme["name"]} (id:#{theme["id"]})" } + themes + .sort_by { |t| t["updated_at"] } + .reverse + .map { |theme| "#{theme["name"]} (id:#{theme["id"]})" } end def extract_theme_id(rendered_name) /\(id:([0-9]+)\)$/.match(rendered_name)[1].to_i end