diff --git a/CHANGELOG.md b/CHANGELOG.md index a9135699..45472cb6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ * Adds Honeybadger generator. ([@mausamp][]) * Adds Rails ERD generator. ([@mausamp][]) * Adds Annotate Generator. ([@TheZero0-ctrl][]) +* Adds Sidekiq generator. ([@TheZero0-ctrl][]) ## 0.13.0 (March 26th, 2024) * Adds Letter Opener generator. ([@coolprobn][]) diff --git a/README.md b/README.md index a771077c..98a2ea56 100644 --- a/README.md +++ b/README.md @@ -96,6 +96,7 @@ The boring generator introduces following generators: - Install Honeybadger: `rails generate boring:honeybadger:install` - Install Rails ERD: `rails generate boring:rails_erd:install` - Install Annotate: `rails generate boring:annotate:install` +- Install Sidekiq: `rails generate boring:sidekiq:install` ## Screencasts diff --git a/lib/generators/boring/sidekiq/install/install_generator.rb b/lib/generators/boring/sidekiq/install/install_generator.rb new file mode 100644 index 00000000..a3a84074 --- /dev/null +++ b/lib/generators/boring/sidekiq/install/install_generator.rb @@ -0,0 +1,91 @@ +# frozen_string_literal: true + +require 'boring_generators/generator_helper' + +module Boring + module Sidekiq + class InstallGenerator < Rails::Generators::Base + include BoringGenerators::GeneratorHelper + + desc "Adds Sidekiq to the application" + source_root File.expand_path("templates", __dir__) + + class_option :skip_routes, + type: :boolean, + aliases: "-sr", + default: false, + desc: "Tell us if you want to skip sidekiq routes for viewing Web UI. Defaults to false." + class_option :authenticate_routes_with_devise, + type: :boolean, + aliases: "-ar", + default: false, + desc: "Tell us if you want sidekiq routes to only be accessed by authenticated users. Defaults to false." + class_option :skip_procfile_config, + type: :boolean, + aliases: "-sp", + default: false, + desc: "Tell us if you want to skip adding sidekiq worker to Procfile. Defaults to false." + + def add_sidekiq_gem + say "Adding sidekiq gem to Gemfile", :green + check_and_install_gem("sidekiq") + bundle_install + end + + def set_sidekiq_as_active_job_adapter + say "Setting sidekiq as active_job adapter", :green + + inject_into_file "config/application.rb", + optimize_indentation( + "config.active_job.queue_adapter = :sidekiq\n", + 4 + ), + after: /class Application < Rails::Application\n/ + + end + + def add_sidekiq_routes + return if options[:skip_routes] + + say "Adding sidekiq routes", :green + + if options[:authenticate_routes_with_devise] + route = <<~RUBY + authenticate :user do + mount Sidekiq::Web => '/sidekiq' + end + + RUBY + else + route = "mount Sidekiq::Web => '/sidekiq'\n\n" + end + + inject_into_file "config/routes.rb", + "require 'sidekiq/web'\n\n", + before: "Rails.application.routes.draw do\n" + + inject_into_file "config/routes.rb", + optimize_indentation(route, 2), + after: "Rails.application.routes.draw do\n" + end + + def add_sidekiq_worker_to_procfile + return if options[:skip_procfile_config] || !File.exist?("Procfile.dev") + + say "Adding sidekiq worker to Procfile.dev", :green + append_to_file "Procfile.dev", "worker: bundle exec sidekiq" + end + + def show_message + return if options[:skip_routes] + + if options[:authenticate_routes_with_devise] + readme "README" + else + say "\nWe've added Sidekiq routes. Please protect it as necessary to suit your requirements.", + :yellow + end + end + end + end +end diff --git a/lib/generators/boring/sidekiq/install/templates/README b/lib/generators/boring/sidekiq/install/templates/README new file mode 100644 index 00000000..b3c132d6 --- /dev/null +++ b/lib/generators/boring/sidekiq/install/templates/README @@ -0,0 +1,12 @@ +=============================================================================== + +We've protected Sidekiq routes with Devise to ensure only authenticated users can access them. +This is implemented in the following snippet located in the config/routes.rb file. +``` +authenticate :user do + mount Sidekiq::Web => '/sidekiq' +end +``` +Please adjust it as necessary to suit your requirements. + +=============================================================================== diff --git a/test/generators/sidekiq/sidekiq_install_generator_test.rb b/test/generators/sidekiq/sidekiq_install_generator_test.rb new file mode 100644 index 00000000..12754566 --- /dev/null +++ b/test/generators/sidekiq/sidekiq_install_generator_test.rb @@ -0,0 +1,75 @@ +# frozen_string_literal: true + +require "test_helper" +require "generators/boring/sidekiq/install/install_generator" + +class SidekiqInstallGeneratorTest < Rails::Generators::TestCase + tests Boring::Sidekiq::InstallGenerator + setup :build_app + teardown :teardown_app + + include GeneratorHelper + include ActiveSupport::Testing::Isolation + + def destination_root + app_path + end + + def test_should_configure_sidekiq + Dir.chdir(app_path) do + add_procfile + quietly { run_generator } + + assert_gem "sidekiq" + assert_file "config/application.rb" do |content| + assert_match(/config\.active_job\.queue_adapter = :sidekiq/, content) + end + assert_file "config/routes.rb" do |content| + assert_match(/require 'sidekiq\/web'/, content) + assert_match(/mount Sidekiq::Web/, content) + end + + assert_file "Procfile.dev" do |content| + assert_match(/worker: bundle exec sidekiq/, content) + end + end + end + + def test_should_skip_sidekiq_routes + Dir.chdir(app_path) do + quietly { run_generator %w[--skip-routes] } + + assert_file "config/routes.rb" do |content| + assert_no_match(/mount Sidekiq::Web/, content) + end + end + end + + def test_should_authenticate_routes_with_devise + Dir.chdir(app_path) do + quietly { run_generator %w[--authenticate_routes_with_devise] } + + assert_file "config/routes.rb" do |content| + assert_match(/authenticate :user do/, content) + assert_match(/mount Sidekiq::Web/, content) + end + end + end + + def test_should_skip_adding_sidekiq_worker_to_procfile + Dir.chdir(app_path) do + add_procfile + quietly { run_generator %w[--skip_procfile_config] } + + assert_file "Procfile.dev" do |content| + assert_no_match(/worker: bundle exec sidekiq/, content) + end + end + end + + private + + def add_procfile + File.write("#{app_path}/Procfile.dev", "web: bin/rails server -p 3000 -b 0.0.0.0") + end +end