From f122881a7babe373ce2715d45a8df2cb406bdeb5 Mon Sep 17 00:00:00 2001 From: Augustin Gottlieb Pequeno <33221555+aguspe@users.noreply.github.com> Date: Mon, 29 Jul 2024 15:30:13 +0200 Subject: [PATCH] Start adding dynamic plugin support (#111) * Start adding dynamic plugin support * Correct extra space * Update Gemfile Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Add and remove commands dynamically * Plugin working * Plugin command running * Fix tests * Fix plugins and update read_me * Update version --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- lib/commands/loaded_commands.rb | 9 ++ lib/commands/plugin_commands.rb | 34 ++++++++ lib/generators/menu_generator.rb | 6 +- lib/generators/templates/common/read_me.tt | 19 ++--- lib/plugin/plugin.rb | 99 ++++++++++++++++++++++ lib/plugin/plugin_exposer.rb | 77 +++++++++++++++++ lib/ruby_raider.rb | 27 +++++- lib/version | 2 +- plugins.yml | 2 + 9 files changed, 258 insertions(+), 17 deletions(-) create mode 100644 lib/commands/loaded_commands.rb create mode 100644 lib/commands/plugin_commands.rb create mode 100644 lib/plugin/plugin.rb create mode 100644 lib/plugin/plugin_exposer.rb create mode 100644 plugins.yml diff --git a/lib/commands/loaded_commands.rb b/lib/commands/loaded_commands.rb new file mode 100644 index 0000000..e5f8cba --- /dev/null +++ b/lib/commands/loaded_commands.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +require 'thor' +require_relative '../plugin/plugin' + +module RubyRaider + class LoadedCommands < Thor + end +end diff --git a/lib/commands/plugin_commands.rb b/lib/commands/plugin_commands.rb new file mode 100644 index 0000000..f0c1726 --- /dev/null +++ b/lib/commands/plugin_commands.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +require 'thor' +require_relative '../plugin/plugin' + +module RubyRaider + # :reek:FeatureEnvy { enabled: false } + # :reek:UtilityFunction { enabled: false } + class PluginCommands < Thor + desc 'add [NAME]', 'Adds a plugin to your project' + + def add(plugin_name) + Plugin.add_plugin(plugin_name) + end + + desc 'delete [NAME]', 'Deletes a plugin from your project' + + def delete(plugin_name) + Plugin.delete_plugin(plugin_name) + end + + desc 'local', 'Lists all the plugin in your project' + + def local + pp Plugin.installed_plugins + end + + desc 'list', 'Lists all the available plugin' + + def list + pp Plugin.available_plugins + end + end +end diff --git a/lib/generators/menu_generator.rb b/lib/generators/menu_generator.rb index 984fadd..d284746 100644 --- a/lib/generators/menu_generator.rb +++ b/lib/generators/menu_generator.rb @@ -84,11 +84,15 @@ def yes_no_menu_choices end def select_automation_framework(menu) + automation_options(menu) + menu.choice :Quit, -> { exit } + end + + def automation_options(menu) menu.choice :Selenium, -> { choose_test_framework('selenium') } menu.choice :Appium, -> { choose_test_framework('appium') } menu.choice :Watir, -> { choose_test_framework('watir') } menu.choice :Applitools, -> { choose_test_framework('applitools') } menu.choice :Axe, -> { choose_test_framework('axe') } - menu.choice :Quit, -> { exit } end end diff --git a/lib/generators/templates/common/read_me.tt b/lib/generators/templates/common/read_me.tt index 9693067..a192429 100644 --- a/lib/generators/templates/common/read_me.tt +++ b/lib/generators/templates/common/read_me.tt @@ -4,12 +4,9 @@
- Logo + Logo -

Ruby Raider

- This is a gem to make setup and start of UI automation projects easier. -
Explore the docs ยป

@@ -79,13 +76,13 @@ Select the ones you will like to work with. If you already know which frameworks you want to use, you can do: ```ruby -raider new [name_of_project] - p framework : [framework] automation : [automation_type] visual : [boolean] axe : [boolean] +raider new [name_of_project] p framework : [framework] automation : [automation_type] ``` An example of the command above would be: ```ruby -raider new test_project -p framework : rspec automation: selenium visual : false axe : true +raider new test_project p framework : rspec automation: selenium ``` Where [frameworks] is a comma separated list of the frameworks you want to use. @@ -120,15 +117,15 @@ Ruby Raider also supports scaffolding: * To create a new steps definition you do: ```raider g steps [STEPS_NAME]``` * To create both a page/spec or a page/feature/steps you do: ```raider g scaffold [SCAFFOLD_NAME]``` -It's possible to add the option --path or -p if you want to specify where to create your features, pages, helpers and +It's possible to add the option --path or p if you want to specify where to create your features, pages, helpers and specs. If you want to set the default path for the creation of your features, helpers and specs: ```ruby -raider u path [PATH_NAME] - -feature or -f -raider u path [PATH_NAME] - -spec or -s -raider u path [PATH_NAME] - -helper or -h +raider u path [PATH_NAME] - -feature or f +raider u path [PATH_NAME] - -spec or s +raider u path [PATH_NAME] - -helper or h ``` If you don't specify an option, path will assume you want to change the default path for pages. @@ -139,4 +136,4 @@ To initialise Appium server run this command: ```ruby raider u start_appium -``` \ No newline at end of file +``` diff --git a/lib/plugin/plugin.rb b/lib/plugin/plugin.rb new file mode 100644 index 0000000..da43e08 --- /dev/null +++ b/lib/plugin/plugin.rb @@ -0,0 +1,99 @@ +# frozen_string_literal: true + +require 'yaml' +require_relative 'plugin_exposer' + +module RubyRaider + module Plugin + class << self + def add_plugin(plugin_name) + return pp 'The plugin was not found' unless available?(plugin_name) + return pp 'The plugin is already installed' if installed?(plugin_name) + + pp "Adding #{plugin_name}..." + add_plugin_to_gemfile(plugin_name) + system('bundle install') + PluginExposer.expose_commands(plugin_name) + pp "The plugin #{plugin_name} is added" + end + + def delete_plugin(plugin_name) + return 'The plugin is not installed' unless installed_plugins.include?(plugin_name) + + pp "Deleting #{plugin_name}..." + remove_plugin_from_gemfile(plugin_name) + PluginExposer.remove_command(plugin_name) + system('bundle install') + pp "The plugin #{plugin_name} is deleted" + end + + def installed_plugins + parsed_gemfile = File.readlines('Gemfile').map { |line| line.sub('gem ', '').strip.delete("'") } + parsed_gemfile.select { |line| available_plugins.include?(line) } + end + + def available_plugins + plugins['plugins'] + end + + def installed?(plugin_name) + installed_plugins.include?(plugin_name) + end + + def available?(plugin_name) + available_plugins.include?(plugin_name) + end + + def camelize(str) + str.split('_').collect(&:capitalize).join + end + + private + + def add_plugin_to_gemfile(plugin_name) + File.open('Gemfile', 'a') do |file| + file.puts "\n# Ruby Raider Plugins\n" unless comment_present? + file.puts "gem '#{plugin_name}'" unless plugin_present?(plugin_name) + end + end + + def remove_plugin_from_gemfile(plugin_name) + output_lines = remove_plugins_and_comments(plugin_name) + update_gemfile(output_lines) + end + + def last_plugin? + installed_plugins.count == 1 + end + + def plugins + @plugins ||= YAML.load_file(File.expand_path('plugins.yml')) + end + + def read_gemfile + File.readlines('Gemfile') + end + + def comment_present? + read_gemfile.grep(/Ruby Raider Plugins/).any? + end + + def plugin_present?(plugin_name) + read_gemfile.grep(/#{plugin_name}/).any? + end + + def remove_plugins_and_comments(plugin_name) + read_gemfile.reject do |line| + line.include?(plugin_name) || line.include?('Ruby Raider Plugins') && last_plugin? + end + end + + # :reek:NestedIterators { enabled: false } + def update_gemfile(output_lines) + File.open('Gemfile', 'w') do |file| + output_lines.each { |line| file.puts line } + end + end + end + end +end diff --git a/lib/plugin/plugin_exposer.rb b/lib/plugin/plugin_exposer.rb new file mode 100644 index 0000000..4770a83 --- /dev/null +++ b/lib/plugin/plugin_exposer.rb @@ -0,0 +1,77 @@ +# frozen_string_literal: true + +require_relative '../plugin/plugin' + +module RubyRaider + module PluginExposer + class << self + FILE_PATH = File.expand_path('../commands/loaded_commands.rb', __dir__) + # :reek:NestedIterators { enabled: false } + def expose_commands(plugin_name) + return pp 'The plugin is already installed' if plugin_present?(plugin_name) + + commands = read_loaded_commands + + File.open(FILE_PATH, 'w') do |file| + commands.each do |line| + file.puts line + file.puts require_plugin(plugin_name, line) + file.puts select_command_formatting(plugin_name, line) + end + end + end + + def remove_command(plugin_name) + return pp 'The plugin is not installed' unless plugin_present?(plugin_name) + + delete_plugin_command(plugin_name) + end + + private + + def any_commands? + read_loaded_commands.any? { |line| line.include?('subcommand') } + end + + def read_loaded_commands + File.readlines(FILE_PATH) + end + + def formatted_command_without_space(plugin_name) + "desc '#{plugin_name}', 'Provides access to all the commands for #{plugin_name}'\n" \ + "subcommand '#{plugin_name}', #{Plugin.camelize(plugin_name)}::PluginCommands" + end + + def formatted_command_with_space(plugin_name) + "\n#{formatted_command_without_space(plugin_name)}" + end + + def plugin_present?(plugin_name) + read_loaded_commands.grep(/#{plugin_name}/).any? + end + + def select_command_formatting(plugin_name, line) + if line.strip == 'class LoadedCommands < Thor' && !any_commands? + formatted_command_without_space(plugin_name) + elsif any_commands? + formatted_command_with_space(plugin_name) + end + end + + def require_plugin(plugin_name, line) + "require '#{plugin_name}'" if line.include?("require 'thor'") && !plugin_present?(plugin_name) + end + + # :reek:NestedIterators { enabled: false } + def delete_plugin_command(plugin_name) + output_lines = read_loaded_commands.reject do |line| + line.include?(plugin_name) if plugin_present?(plugin_name) + end + + File.open(FILE_PATH, 'w') do |file| + output_lines.each { |line| file.puts line } + end + end + end + end +end diff --git a/lib/ruby_raider.rb b/lib/ruby_raider.rb index 1e45ccd..e97034f 100644 --- a/lib/ruby_raider.rb +++ b/lib/ruby_raider.rb @@ -1,5 +1,8 @@ # frozen_string_literal: true +require_relative '../lib/plugin/plugin' +require_relative '../lib/commands/plugin_commands' +require_relative '../lib/commands/loaded_commands' require_relative '../lib/commands/scaffolding_commands' require_relative '../lib/commands/utility_commands' @@ -7,9 +10,19 @@ # :reek:UtilityFunction { enabled: false } module RubyRaider class Raider < Thor + no_tasks do + def self.plugin_commands? + File.readlines(File.expand_path('commands/loaded_commands.rb', __dir__)).any? do |line| + line.include?('subcommand') + end + end + + def current_version = File.read(File.expand_path('version', __dir__)).strip + end + desc 'new [PROJECT_NAME]', 'Creates a new framework based on settings picked' option :parameters, - type: :hash, required: false, desc: 'Parameters to avoid using the menu', aliases: '-p' + type: :hash, required: false, desc: 'Parameters to avoid using the menu', aliases: 'p' def new(project_name) params = options[:parameters] @@ -22,7 +35,7 @@ def new(project_name) MenuGenerator.new(project_name).generate_choice_menu end - map '-n' => 'new' + map 'n' => 'new' desc 'version', 'It shows the version of Ruby Raider you are currently using' @@ -40,8 +53,14 @@ def version subcommand 'utility', UtilityCommands map 'u' => 'utility' - no_commands do - def current_version = File.read(File.expand_path('version', __dir__)).strip + desc 'plugin_manager', 'Provides access to all the commands to manager your plugins' + subcommand 'plugin_manager', PluginCommands + map 'pm' => 'plugin_manager' + + if plugin_commands? + desc 'plugins', 'loaded plugin commands' + subcommand 'plugins', LoadedCommands + map 'ps' => 'plugins' end end end diff --git a/lib/version b/lib/version index 0383441..b5d0ec5 100644 --- a/lib/version +++ b/lib/version @@ -1 +1 @@ -0.9.5 \ No newline at end of file +0.9.8 \ No newline at end of file diff --git a/plugins.yml b/plugins.yml new file mode 100644 index 0000000..95bf38b --- /dev/null +++ b/plugins.yml @@ -0,0 +1,2 @@ +plugins: + - great_axe \ No newline at end of file