diff --git a/CHANGELOG.md b/CHANGELOG.md index 444f15b8..3fcbbb51 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## master (unreleased) +* Adds Sidekiq generator. ([@TheZero0-ctrl][]) * Update Tailwind generator to use tailwindcss-rails gem instead of manually installing everything via npm ([@coolprobn][]) * Fixed callback method name for Google OAuth2 Omniauth ([@coezbek][] & [@coolprobn][]) diff --git a/README.md b/README.md index 04c44110..a3025291 100644 --- a/README.md +++ b/README.md @@ -98,6 +98,7 @@ The boring generator introduces following generators: - Install Annotate: `rails generate boring:annotate:install` - Install CanCanCan: `rails generate boring:cancancan:install` - Install Gitlab CI: `rails generate boring:ci:gitlab_ci: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..ca8991fc --- /dev/null +++ b/lib/generators/boring/sidekiq/install/install_generator.rb @@ -0,0 +1,93 @@ +# 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_web_ui, + type: :boolean, + aliases: "-sw", + default: false, + desc: + "Tell us if you want to skip sidekiq routes for viewing Web UI. Defaults to false." + class_option :skip_authenticated_web_ui, + type: :boolean, + aliases: "-saw", + default: false, + desc: + "Tell us if you want sidekiq web UI 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_web_ui + return if options[:skip_web_ui] + + say "Adding sidekiq web UI", :green + + if options[:skip_authenticated_web_ui] + route = "mount Sidekiq::Web => '/sidekiq'\n\n" + else + route = <<~RUBY + authenticate :user do + mount Sidekiq::Web => '/sidekiq' + end + + RUBY + 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_install_generator_test.rb b/test/generators/sidekiq_install_generator_test.rb new file mode 100644 index 00000000..4d08f38b --- /dev/null +++ b/test/generators/sidekiq_install_generator_test.rb @@ -0,0 +1,76 @@ +# 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(/authenticate :user do/, 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_web_ui + Dir.chdir(app_path) do + quietly { run_generator %w[--skip_web_ui] } + + assert_file "config/routes.rb" do |content| + assert_no_match(/mount Sidekiq::Web/, content) + end + end + end + + def test_should_skip_authenticated_web_ui + Dir.chdir(app_path) do + quietly { run_generator %w[--skip_authenticated_web_ui] } + + assert_file "config/routes.rb" do |content| + refute_match(/authenticate :user do/, content) + assert_match(/mount Sidekiq::Web/, content) + end + end + end + + def test_should_skip_procfile_config + 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