Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generator for Rack CORS #27

Open
wants to merge 21 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
# Changelog

## master (unreleased)
* Adds Figjam generator. ([@mausamp][])
* Adds Pronto Generator with Gitlab CI ([@coolprobn][])
* Adds Rack Mini Profiler generator. ([@mausamp][])
* Adds VCR generator. ([@TheZero0-ctrl][])
* Adds Pronto Generator with Gihub Action. ([@TheZero0-ctrl][])
* Adds Doorkeeper Generator with Devise. ([@TheZero0-ctrl][])
* Adds Avo generator. ([@mausamp][])
* Adds Sentry generator. ([@mausamp][])
* Adds Dotenv generator. ([@mausamp][])
* Adds Honeybadger generator. ([@mausamp][])
* Adds Rack CORS generator. ([@mausamp][])

## 0.13.0 (March 26th, 2024)
* Adds Letter Opener generator. ([@coolprobn][])
Expand Down Expand Up @@ -84,3 +95,5 @@
[@luathn]: https://github.com/luathn
[@coolprobn]: https://github.com/coolprobn
[@aadil]: https://github.com/AdilRT
[@mausamp]: https://github.com/mausamp
[@TheZero0-ctrl]: https://github.com/TheZero0-ctrl
4 changes: 2 additions & 2 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
boring_generators (0.12.0)
boring_generators (0.13.0)
railties

GEM
Expand Down Expand Up @@ -143,4 +143,4 @@ DEPENDENCIES
sqlite3 (~> 1.4)

BUNDLED WITH
2.1.4
2.2.33
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,17 @@ The boring generator introduces following generators:
- Install Whenever: `rails generate boring:whenever:install`
- Install Rswag: `rails generate boring:rswag:install --rails_port=<rails_app_port> --authentication_type=<api_authentication_type> --skip_api_authentication=<skip_api_authentication> --api_authentication_options=<api_authentication_options> --enable_swagger_ui_authentication=<enable_swagger_ui_authentication>`
- Install Webmock: `rails generate boring:webmock:install --app_test_framework=<test_framework>`
- Install Figjam: `rails generate boring:figjam:install`
- Install Pronto with Gitlab CI: `rails generate boring:pronto:gitlab_ci:install`
- Install Pronto with Github Action: `rails generate boring:pronto:github_action:install`
- Install Rack Mini Profiler: `rails generate boring:rack_mini_profiler:install`
- Install VCR: `rails generate boring:vcr:install --testing_framework=<testing_framework> --stubbing_libraries=<stubbing_libraries>`
- Install Avo: `rails generate boring:avo:install`
- Install Doorkeeper with devise: `rails generate boring:devise:doorkeeper:install`
- Install Sentry: `rails generate boring:sentry:install --use_env_variable --breadcrumbs_logger=<breadcrumbs_logger_options>`
- Install Dotenv: `rails generate boring:dotenv:install`
- Install Honeybadger: `rails generate boring:honeybadger:install`
- Install Rack CORS: `rails generate boring:rack_cors:install --origins=<origins>`

## Screencasts

Expand Down
38 changes: 38 additions & 0 deletions lib/boring_generators/generator_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
module BoringGenerators
module GeneratorHelper
include Rails::Generators::Actions

def app_ruby_version
with_ruby_string = `grep "^ruby.*$" Gemfile` || `cat .ruby-version`

# only keep 3.3.0
with_ruby_string.gsub(/[^\d\.]/, '').squish
end

def gem_installed?(gem_name)
gem_regex = /gem.*\b#{gem_name}\b.*/
File.read("Gemfile").match?(gem_regex)
end

def bundle_install
Bundler.with_unbundled_env do
run "bundle install"
end
end

def check_and_install_gem(*args)
gem_name, = args

gem_file_content_array = File.readlines("Gemfile")


gem_exists = gem_file_content_array.any? { |line| line.include?(gem_name) }

if gem_exists
say "#{gem_name} is already in the Gemfile, skipping it ...", :yellow
else
gem *args
end
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ module Boring
module ActiveStorage
module Azure
class InstallGenerator < Rails::Generators::Base
desc "Adds ActiveStorage Mircosoft Azure the application"
desc "Adds ActiveStorage Microsoft Azure the application"

class_option :skip_active_storage, type: :boolean, aliases: "-s",
desc: "Skips running ActiveStorage installer"
Expand Down
2 changes: 1 addition & 1 deletion lib/generators/boring/audit/install/install_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def add_bullet_gem
\n
\t# Patch-level verification for Bundler. https://github.com/rubysec/bundler-audit
\tgem "bundler-audit", require: false
\t# vulnerabity checker for Ruby itself. https://github.com/civisanalytics/ruby_audit
\t# vulnerability checker for Ruby itself. https://github.com/civisanalytics/ruby_audit
\tgem "ruby_audit", require: false
RUBY
insert_into_file "Gemfile", audit_gems_content, after: /group :development do/
Expand Down
25 changes: 25 additions & 0 deletions lib/generators/boring/avo/install/install_generator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# frozen_string_literal: true

module Boring
module Avo
class InstallGenerator < Rails::Generators::Base
desc 'Adds Avo to the application'

def add_avo_gem
say 'Adding Avo gem', :green

Bundler.with_unbundled_env do
run 'bundle add avo'
end
end

def configure_avo
say 'Setting up Avo', :green

Bundler.with_unbundled_env do
run 'bundle exec rails generate avo:install'
end
end
end
end
end
190 changes: 190 additions & 0 deletions lib/generators/boring/devise/doorkeeper/install/install_generator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
# frozen_string_literal: true

require 'boring_generators/generator_helper'

module Boring
module Devise
module Doorkeeper
class InstallGenerator < Rails::Generators::Base
include BoringGenerators::GeneratorHelper

desc "Adds doorkeeper with devise to the application"

class_option :model_name, type: :string, aliases: "-m", default: "User",
desc: "Tell us the user model name which will be used for authentication. Defaults to User"
class_option :grant_flows, type: :array, aliases: "-gf", default: %w[authorization_code client_credentials],
enum: %w[authorization_code client_credentials password],
desc: "Tell us the grant flows you want to use separated by space. Defaults to authorization_code and client_credentials"
class_option :api_only, type: :boolean, aliases: "-a", default: false,
desc: "Tell us if you want to setup doorkeeper for API only application. Defaults to false"
class_option :skip_applications_routes, type: :boolean, aliases: "-sr", default: false,
desc: "Tell us if you want to skip adding doorkeeper routes to manage applications. Defaults to false"
class_option :use_refresh_token, type: :boolean, aliases: "-rt", default: false,
desc: "Keep user logged in with refresh tokens. Defaults to false"

def verify_presence_of_devise_gem
return if gem_installed?("devise")

say "We couldn't find devise gem. Please configure devise gem and rerun the generator. Consider running `rails generate boring:devise:install` to set up Devise.",
:red

abort
end

def verify_presence_of_devise_model
return if File.exist?("app/models/#{options[:model_name].underscore}.rb")

say "We couldn't find the #{options[:model_name]} model. Maybe there is a typo? Please provide the correct model name and run the generator again.",
:red

abort
end

def add_doorkeeper_gem
say "Adding doorkeeper gem", :green
check_and_install_gem("doorkeeper")
bundle_install
end

def run_doorkeeper_generators
say "Running doorkeeper generators", :green

Bundler.with_unbundled_env do
run "bundle exec rails generate doorkeeper:install"
run "bundle exec rails generate doorkeeper:migration"
end
end

def add_doorkeeper_related_association_to_model
model_name = options[:model_name].underscore
say "Adding doorkeeper related associations to the model file app/models/#{model_name}.rb",
:green
model_content = <<~RUBY
has_many :access_grants,
class_name: 'Doorkeeper::AccessGrant',
foreign_key: :resource_owner_id,
dependent: :delete_all # or :destroy if you need callbacks

has_many :access_tokens,
class_name: 'Doorkeeper::AccessToken',
foreign_key: :resource_owner_id,
dependent: :delete_all # or :destroy if you need callbacks
RUBY

inject_into_file "app/models/#{model_name}.rb",
optimize_indentation(model_content, 2),
after: "ApplicationRecord\n"
end

def update_doorkeeper_initializer
say "Updating doorkeeper initializer", :green

configure_resource_owner_authenticator if options[:grant_flows].include?("authorization_code")
configure_admin_authenticator unless options[:api_only] || options[:skip_applications_routes]
configure_resource_owner_from_credentials if options[:grant_flows].include?("password")

gsub_file "config/initializers/doorkeeper.rb",
/# grant_flows %w\[authorization_code client_credentials\]/,
"grant_flows %w[#{options[:grant_flows].uniq.join(' ')}]"

if options[:api_only]
gsub_file "config/initializers/doorkeeper.rb",
/# api_only/,
"api_only"
end

if options[:skip_applications_routes]
doorkeeper_routes_content = <<~RUBY
use_doorkeeper do
skip_controllers :applications, :authorized_applications
end
RUBY

gsub_file "config/routes.rb",
/.*use_doorkeeper/,
optimize_indentation(doorkeeper_routes_content, 2)
end

if options[:use_refresh_token]
uncomment_lines "config/initializers/doorkeeper.rb",
/use_refresh_token/
end
end

def update_doorkeeper_migration
say "Updating doorkeeper migration", :green
model_name = options[:model_name].underscore

uncomment_lines Dir["db/migrate/*_create_doorkeeper_tables.rb"].first,
/add_foreign_key :oauth/

gsub_file Dir["db/migrate/*_create_doorkeeper_tables.rb"].first,
/<model>/,
":#{model_name.pluralize}"

return unless (%w[password client_credentials] & options[:grant_flows]).any?

gsub_file Dir["db/migrate/*_create_doorkeeper_tables.rb"].first,
/t.text :redirect_uri, null: false/,
"t.text :redirect_uri"
end

def show_message
return if options[:api_only] || options[:skip_applications_routes]

model_name = options[:model_name].underscore
admin_authenticator_content = "current_#{model_name} || warden.authenticate!(scope: :#{model_name})"

say "\nWe've implemented `#{admin_authenticator_content}` in the admin_authenticator block of config/initializers/doorkeeper.rb to manage access to application routes. Please adjust it as necessary to suit your requirements.",
:yellow
end

private

def configure_resource_owner_authenticator
model_name = options[:model_name].underscore
resource_owner_authenticator_content = <<~RUBY
resource_owner_authenticator do
current_#{model_name} || warden.authenticate!(scope: :#{model_name})
end
RUBY

gsub_file "config/initializers/doorkeeper.rb",
/.*resource_owner_authenticator do\n(?:\s|.)*?end/,
optimize_indentation(resource_owner_authenticator_content, 2)
end

def configure_admin_authenticator
model_name = options[:model_name].underscore
gsub_file "config/initializers/doorkeeper.rb",
/(?:# admin_authenticator do\n*)((?:\s|.)*?)(?:# end)/,
"admin_authenticator do\n" + "\\1" + "end"

admin_authenticator_content = "current_#{model_name} || warden.authenticate!(scope: :#{model_name})"
inject_into_file "config/initializers/doorkeeper.rb",
optimize_indentation(admin_authenticator_content, 4),
after: /admin_authenticator do\n/,
force: true

end

def configure_resource_owner_from_credentials
model_name = options[:model_name].underscore
resource_owner_for_credentials_content = <<~RUBY
resource_owner_from_credentials do |routes|
#{model_name} = #{options[:model_name]}.find_for_database_authentication(email: params[:email])
if #{model_name}&.valid_for_authentication? { #{model_name}.valid_password?(params[:password]) } && #{model_name}&.active_for_authentication?
request.env['warden'].set_user(#{model_name}, scope: :#{model_name}, store: false)
#{model_name}
end
end
RUBY

inject_into_file "config/initializers/doorkeeper.rb",
optimize_indentation(resource_owner_for_credentials_content, 2),
after: /resource_owner_authenticator do\n(?:\s|.)*?end\n/
end
end
end
end
end
31 changes: 31 additions & 0 deletions lib/generators/boring/dotenv/install/install_generator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# frozen_string_literal: true

module Boring
module Dotenv
class InstallGenerator < Rails::Generators::Base
desc 'Adds dotenv gem to the application'
source_root File.expand_path("templates", __dir__)

def add_dotenv_gem
say 'Adding dotenv gem', :green

Bundler.with_unbundled_env do
run 'bundle add dotenv-rails --group development'
end
end

def configure_dotenv_gem
say 'Configuring dotenv gem', :green

template '.env', '.env'

unless File.exist?('.gitignore')
create_file '.gitignore'
end

FileUtils.cp('.env', '.env.sample')
insert_into_file('.gitignore', "\n/.env\n")
end
end
end
end
3 changes: 3 additions & 0 deletions lib/generators/boring/dotenv/install/templates/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Add your environment variables here
# Example:
# SECRET_KEY_BASE=your_secret_key
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class InstallGenerator < Rails::Generators::Base
def add_factory_bot_gem
log :adding, "FactoryBot"
Bundler.with_unbundled_env do
run "bundle add factory_bot_rails --group='developement,test'"
run "bundle add factory_bot_rails --group='development,test'"
end
end

Expand Down
2 changes: 1 addition & 1 deletion lib/generators/boring/faker/install/install_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class InstallGenerator < Rails::Generators::Base
def add_faker_gem
log :adding, "faker"
Bundler.with_unbundled_env do
run "bundle add faker --group='developement,test'"
run "bundle add faker --group='development,test'"
end
end
end
Expand Down
Loading