rsg 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/.circleci/config.yml +13 -0
  3. data/.gitignore +11 -0
  4. data/.rspec +3 -0
  5. data/.rubocop.yml +14 -0
  6. data/Gemfile +13 -0
  7. data/Gemfile.lock +190 -0
  8. data/LICENSE +201 -0
  9. data/README.md +192 -0
  10. data/Rakefile +10 -0
  11. data/bin/console +12 -0
  12. data/bin/setup +8 -0
  13. data/exe/rsg +22 -0
  14. data/lib/rsg/generators/actions.rb +108 -0
  15. data/lib/rsg/generators/app/USAGE +14 -0
  16. data/lib/rsg/generators/app/app_builder.rb +42 -0
  17. data/lib/rsg/generators/app/app_generator.rb +80 -0
  18. data/lib/rsg/generators/app/templates/README.md.erb +22 -0
  19. data/lib/rsg/generators/base.rb +27 -0
  20. data/lib/rsg/generators/dotenv/install_generator.rb +24 -0
  21. data/lib/rsg/generators/dotenv/templates/env.development +2 -0
  22. data/lib/rsg/generators/dotenv/templates/env.test +2 -0
  23. data/lib/rsg/generators/gemfile/cleanup_generator.rb +28 -0
  24. data/lib/rsg/generators/install/install_generator.rb +13 -0
  25. data/lib/rsg/generators/logging/common_generator.rb +40 -0
  26. data/lib/rsg/generators/logging/lograge_generator.rb +31 -0
  27. data/lib/rsg/generators/logging/templates/initializer_lograge.rb +9 -0
  28. data/lib/rsg/generators/misc/misc_generator.rb +61 -0
  29. data/lib/rsg/generators/misc/templates/puma.rb +44 -0
  30. data/lib/rsg/generators/options.rb +15 -0
  31. data/lib/rsg/generators/orm/active_record_generator.rb +44 -0
  32. data/lib/rsg/generators/orm/templates/active_record/mysql.yml +59 -0
  33. data/lib/rsg/generators/orm/templates/active_record/postgresql.yml +86 -0
  34. data/lib/rsg/generators/orm/templates/active_record/sqlite3.yml +25 -0
  35. data/lib/rsg/generators/orm/templates/db.rake +7 -0
  36. data/lib/rsg/generators/orm/templates/samples.rb +10 -0
  37. data/lib/rsg/generators/orm/templates/seeds.rb +9 -0
  38. data/lib/rsg/generators/testing/rspec_generator.rb +33 -0
  39. data/lib/rsg/generators/webpacker/install_generator.rb +51 -0
  40. data/lib/rsg/generators/webpacker/templates/application.js +18 -0
  41. data/lib/rsg/generators/webpacker/templates/application.sass +19 -0
  42. data/lib/rsg/generators/webpacker/templates/landing_controller.rb.erb +6 -0
  43. data/lib/rsg/generators/webpacker/templates/landing_show.html.erb +8 -0
  44. data/lib/rsg/version.rb +4 -0
  45. data/lib/rsg.rb +36 -0
  46. data/rsg.gemspec +28 -0
  47. data/templates/README.md +4 -0
  48. data/templates/rsg-default.rb +17 -0
  49. metadata +109 -0
data/exe/rsg ADDED
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "pathname"
5
+
6
+ source_path = Pathname.new(__FILE__).dirname.join("../lib").expand_path
7
+ $LOAD_PATH << source_path
8
+
9
+ require "rsg"
10
+
11
+ if ARGV.empty?
12
+ puts "Please provide a path for the new application"
13
+ puts
14
+ puts "See --help for more info"
15
+ exit 0
16
+ elsif ["-v", "--version"].include? ARGV[0]
17
+ puts "RSG: #{RSG::VERSION}"
18
+ puts "Rails: #{Rails::VERSION}"
19
+ exit 0
20
+ end
21
+
22
+ Rsg::AppGenerator.start
@@ -0,0 +1,108 @@
1
+ require "json"
2
+ require "shellwords"
3
+
4
+ module Rsg
5
+ module Generators
6
+ module Actions
7
+ def rsg_install
8
+ append_gem "rsg",
9
+ within_group: %i(development test),
10
+ install: false,
11
+ path: options[:path]
12
+ end
13
+
14
+ def rsg_generate(name, quiet: false)
15
+ cmd = "generate #{name}"
16
+ cmd << " -q" if quiet
17
+
18
+ rails_command cmd
19
+ git_add_commit "RSG Generator executed: #{name}"
20
+ end
21
+
22
+ def rsg_apply_default!
23
+ rsg_apply "rsg-default"
24
+ end
25
+
26
+ def rsg_apply(template)
27
+ apply Rsg.lookup_app_template(template)
28
+ end
29
+
30
+ def api_mode?
31
+ return @api_mode if defined?(@api_mode)
32
+ @api_mode = !!(File.read("config/application.rb") =~ /^[^#]*config\.api_only = true[^\n]*$/)
33
+ end
34
+
35
+ def confirm?(prompt)
36
+ opts = { limited_to: %w(y n) }
37
+ ask(prompt, opts).downcase == 'y'
38
+ end
39
+
40
+ def git_add_commit(commit_msg)
41
+ truncated_msg = commit_msg.strip.gsub("\n", ' ')[0..59].strip
42
+ truncated_msg.gsub!(/.{3}$/, '...') if commit_msg.length > 60
43
+ say_status :run, "git add . && git commit -m \"#{truncated_msg}\""
44
+
45
+ run "git add .", verbose: false, capture: true
46
+ run "git commit -m #{Shellwords.escape(commit_msg)}", verbose: false, capture: true
47
+ end
48
+
49
+ def enable_railtie(name)
50
+ uncomment_lines "config/application.rb", /require ['"]#{name}\/railtie['"]/
51
+ end
52
+
53
+ def append_gem(gem_name, install: true, within_group: [], after: ["bootsnap", "rails"], **gem_line_params)
54
+ within_group = Array(within_group)
55
+ if within_group.any?
56
+ group_part = within_group.map { |g| "[:'\"]#{g}['\"]?" }.join(", ")
57
+ regex = /^ *group #{group_part} do\n(\s*(gem|#)[^\n]+\n)+ *end\n/
58
+ else
59
+ regex = /.+/m
60
+ end
61
+
62
+ gsub_file "Gemfile", regex do |match|
63
+ gem_line = build_gem_line(gem_name, gem_line_params)
64
+ append_gem_line(match, gem_line, after)
65
+ end
66
+
67
+ run("bundle install", capture: true) if install
68
+ end
69
+
70
+ private
71
+
72
+ def append_gem_line(code, gem_line, after)
73
+ code_lines = code.split("\n")
74
+ index = code_lines.length
75
+ indentation = ""
76
+
77
+ # Goes to the line above the `end` line by default
78
+ if code_lines[0] =~ /^([^#]*)group/
79
+ index -= 1
80
+ indentation = "#{$1} "
81
+ end
82
+
83
+ Array(after).each do |candidate|
84
+ idx = code_lines.index { |l| l =~ /^([^#]*)gem ['"]#{candidate}['"].*$/ }
85
+ next unless idx
86
+
87
+ indentation = $1
88
+ index = idx + 1
89
+ break
90
+ end
91
+
92
+ code_lines.insert(index, "#{indentation}#{gem_line}").join("\n") << "\n"
93
+ end
94
+
95
+ def build_gem_line(gem_name, params = {})
96
+ line = "gem '#{gem_name}'"
97
+ if params.key?(:version)
98
+ version_args = Array(params[:version]).map { |v| "'#{v}'" }.join(", ")
99
+ line << ", #{version_args}"
100
+ end
101
+ line << ", require: '#{params[:require]}'" if params.key?(:require)
102
+ line << ", group: #{params[:group]}" if params.key?(:group)
103
+ line << ", path: '#{params[:path]}'" if params[:path].present?
104
+ line
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,14 @@
1
+ Description:
2
+ RSG is a Rails app generator with Doximity's basic defaults configured.
3
+
4
+ For full details on the changes we've made compared to a vanilla Rails app, check
5
+ our GitHub project:
6
+ https://github.com/doximity/rsg
7
+
8
+ Example:
9
+ rsg ~/Code/weblog [options]
10
+
11
+ Is the equivalent of running `rails new ~/Code/weblog [options]` with most Rails
12
+ components disabled by default. This will generate a minimal Rails app in
13
+ ~/Code/weblog configured with our preferred defaults. Some questions might be
14
+ asked along the way to fine tune the generated app.
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rsg
4
+ # The application builder allows you to override elements of the application
5
+ # generator without being forced to reverse the operations of the default
6
+ # generator.
7
+ #
8
+ # This allows you to override entire operations, like the creation of the
9
+ # Gemfile, README, or JavaScript files, without needing to know exactly
10
+ # what those operations do so you can create another template action.
11
+ #
12
+ # For Rails 6.1, you can check out https://github.com/rails/rails/blob/6-1-stable/railties/lib/rails/generators/rails/app/app_generator.rb#L44
13
+ class AppBuilder < ::Rails::AppBuilder
14
+ def master_key
15
+ gsub_file "config/application.rb",
16
+ /^(\s*)(config\.load_defaults[^\n]+)\n$/,
17
+ "\\1\\2\n\n\\1# We don't use Rails encrypted secrets\n"\
18
+ "\\1config.require_master_key = false\n" \
19
+ "\\1config.active_support.use_authenticated_message_encryption = false\n"
20
+ end
21
+
22
+ ###########################################################################
23
+ # Simple template overwrites
24
+ ###########################################################################
25
+
26
+ def readme
27
+ template "README.md.erb", "README.md"
28
+ end
29
+
30
+ ###########################################################################
31
+ # Things to skip since we don't care about them
32
+ ###########################################################################
33
+
34
+ def ruby_version
35
+ # NOOP since we have the ruby version in Gemfile
36
+ end
37
+
38
+ def credentials
39
+ # NOOP since we store env vars / secrets elsewhere
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,80 @@
1
+ # require "rails/generators"
2
+ require "rails/generators/rails/app/app_generator"
3
+
4
+ require_relative "app_builder"
5
+
6
+ module Rsg
7
+ # AppGenerator is the entrypoint for generation of new apps which builds on
8
+ # top of the core `rails new` command
9
+ class AppGenerator < Rails::Generators::AppGenerator
10
+ include Generators::Actions
11
+
12
+ hide!
13
+
14
+ class_option :version, type: :boolean, aliases: "-v", group: :rsg, desc: "Show RSG version number and quit"
15
+ class_option :help, type: :boolean, aliases: "-h", group: :rsg, desc: "Show this help message and quit"
16
+ class_option :path, type: :string, default: nil, desc: "Path to the RSG gem"
17
+ class_option :template, aliases: "-m", type: :string, default: "rsg-default", desc: "Path to some application template (can be a filesystem path or URL)"
18
+
19
+ # --minimal might take care of some of these, but not all, we change all defaults here regardless since
20
+ # --minimal is subject to change with new releases. We also hide them all, and re-add things as necessary
21
+ # based on user input as generators kick in
22
+ class_option :skip_action_cable, type: :boolean, default: true, desc: "Skip Action Cable files", hide: true
23
+ class_option :skip_action_mailbox, type: :boolean, default: true, desc: "Skip Action Mailbox files", hide: true
24
+ class_option :skip_action_mailer, type: :boolean, default: true, desc: "Skip Action Mailer files", hide: true
25
+ class_option :skip_action_text, type: :boolean, default: true, desc: "Skip Action Text files", hide: true
26
+ class_option :skip_active_job, type: :boolean, default: true, desc: "Skip Active Job files", hide: true
27
+ class_option :skip_active_record, type: :boolean, default: true, desc: "Skip Active Record files", hide: true
28
+ class_option :skip_active_storage, type: :boolean, default: true, desc: "Skip Active Storage files", hide: true
29
+ class_option :skip_bundle, type: :boolean, default: true, desc: "Don't run bundle install", hide: true
30
+ class_option :skip_javascript, type: :boolean, default: true, desc: "Skip JavaScript files", hide: true
31
+ class_option :skip_jbuilder, type: :boolean, default: true, desc: "Skip jbuilder gem", hide: true
32
+ class_option :skip_keeps, type: :boolean, default: true, desc: "Skip Puma", hide: true
33
+ class_option :skip_spring, type: :boolean, default: true, desc: "Don't install Spring application preloader", hide: true
34
+ class_option :skip_sprockets, type: :boolean, default: true, desc: "Skip Sprockets files", hide: true
35
+ class_option :skip_system_test, type: :boolean, default: true, desc: "Skip system test files", hide: true
36
+ class_option :skip_test, type: :boolean, default: true, desc: "Skip Test Unit", hide: true
37
+ class_option :skip_turbolinks, type: :boolean, default: true, desc: "Skip turbolinks gem", hide: true
38
+ class_option :skip_webpack_install, type: :boolean, default: true, desc: "Don't run webpack install", hide: true
39
+
40
+ # Hide other flags, but leave their defaults untouched
41
+ class_option :database, type: :string, default: "sqlite3", desc: "Configure for selected database (options: #{DATABASES.join("/")})", hide: true
42
+ class_option :dev, type: :boolean, default: false, desc: "Set up the application with Gemfile pointing to your Rails checkout", hide: true
43
+ class_option :edge, type: :boolean, default: false, desc: "Set up the application with Gemfile pointing to Rails repository", hide: true
44
+ class_option :master, type: :boolean, default: false, desc: "Preconfigure a minimal rails app", hide: true
45
+ class_option :minimal, type: :boolean, default: false, desc: "Preconfigure a minimal rails app", hide: true
46
+ class_option :skip_bootsnap, type: :boolean, default: false, desc: "Skip bootsnap gem", hide: true
47
+ class_option :skip_collision_check, type: :boolean, default: false, desc: "Skip collision check", hide: true
48
+ class_option :skip_gemfile, type: :boolean, default: false, desc: "Don't create a Gemfile", hide: true
49
+ class_option :skip_git, type: :boolean, default: false, desc: "Skip .gitignore file", hide: true
50
+ class_option :skip_listen, type: :boolean, default: false, desc: "Don't generate configuration that depends on the listen gem", hide: true
51
+ class_option :skip_namespace, type: :boolean, default: false, desc: "Skip namespace (affects only isolated engines)", hide: true
52
+ class_option :skip_puma, type: :boolean, default: false, desc: "Skip Puma related files", hide: true
53
+ class_option :webpack, type: :string, desc: "Preconfigure Webpack with a particular framework (options: react, vue, angular, elm, stimulus)", hide: true
54
+
55
+ def self.banner
56
+ "rsg #{arguments.map(&:usage).join(" ")} [options]"
57
+ end
58
+
59
+ def self.source_paths
60
+ @__source_paths ||= [
61
+ Rails::Generators::AppGenerator.source_root,
62
+ Pathname.new(__FILE__).dirname.join("templates").expand_path
63
+ ]
64
+ end
65
+
66
+ def set_default_accessors!
67
+ bundled_template = Rsg.lookup_app_template(options[:template])
68
+ super
69
+ self.rails_template = bundled_template if bundled_template
70
+ end
71
+
72
+ protected
73
+
74
+ # rubocop:disable Naming/AccessorMethodName
75
+ def get_builder_class
76
+ Rsg::AppBuilder
77
+ end
78
+ # rubocop:enable Naming/AccessorMethodName
79
+ end
80
+ end
@@ -0,0 +1,22 @@
1
+ # <%= app_name.humanize %>
2
+
3
+ ```
4
+ TODO: Write a few words about what the app does
5
+ ```
6
+
7
+ ## Generated with RSG v<%= Rsg::VERSION %>
8
+
9
+ This is an application generated with [rsg](https://github.com/doximity/rsg). If you've skipped any of its
10
+ generators (like ActiveRecord's) or if you'd like to know what else is available for you to configure you
11
+ can run `rails generate --help | grep rsg`.
12
+
13
+ ## Getting Started
14
+
15
+ After you have cloned this repo, run this setup script to set up your machine
16
+ with the necessary dependencies to run and test this app:
17
+
18
+ % ./bin/setup
19
+
20
+ Then start the web server with:
21
+
22
+ % ./bin/rails server
@@ -0,0 +1,27 @@
1
+ require "pathname"
2
+ require "rails/generators"
3
+
4
+ module Rsg
5
+ module Generators
6
+ class Base < Rails::Generators::Base
7
+ include Actions
8
+ include Options
9
+
10
+ def self.inherited(base)
11
+ super
12
+
13
+ parts = base.namespace.split(":")
14
+ return unless parts[0] == "rsg"
15
+
16
+ parts = parts[1..-2] + ["templates"]
17
+ templates_path = Pathname.new(__FILE__).dirname.join(*parts).expand_path
18
+
19
+ base.source_paths << templates_path if templates_path.exist?
20
+ end
21
+
22
+ def self.exit_on_failure?
23
+ true
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,24 @@
1
+ require_relative "../base"
2
+
3
+ module Rsg
4
+ module Dotenv
5
+ class InstallGenerator < Rsg::Generators::Base
6
+ def banner
7
+ say "Configuring dotent-rails in development and test environments"
8
+ end
9
+
10
+ def add_dotenv
11
+ append_gem "dotenv-rails",
12
+ version: "< 3",
13
+ after: "rails",
14
+ group: [:development, :test],
15
+ require: "dotenv/rails-now"
16
+ end
17
+
18
+ def configure_dotenv
19
+ copy_file "env.development", ".env.development"
20
+ copy_file "env.test", ".env.test"
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,2 @@
1
+ PORT="3000"
2
+ APP_URL="http://localhost:${PORT}"
@@ -0,0 +1,2 @@
1
+ PORT="3000"
2
+ APP_URL="http://test:${PORT}"
@@ -0,0 +1,28 @@
1
+ require_relative "../base"
2
+
3
+ module Rsg
4
+ module Gemfile
5
+ class CleanupGenerator < Rsg::Generators::Base
6
+ def banner
7
+ say "Cleaning up Gemfile"
8
+ end
9
+
10
+ def remove_comments
11
+ gsub_file "Gemfile", /^ *#\s*[^#\n]+\n/, ""
12
+ end
13
+
14
+ def remove_tzinfo
15
+ # Remove tzinfo-data since we don't have a need for it in dev / prod env
16
+ gsub_file "Gemfile", /\ngem 'tzinfo-data'[^\n]+\n/, ""
17
+ end
18
+
19
+ def remove_extra_whitespace
20
+ gsub_file "Gemfile", /^( *gem[^\n]+)\n\n\n/, "\\1\n\n"
21
+ end
22
+
23
+ def isolate_rails_gem
24
+ gsub_file "Gemfile", /^( *)(gem ["']rails["'][^\n]+)\n(?: *)(gem ['"]puma['"][^\n]+)\n$/, "\\1\\2\n\n\\3"
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,13 @@
1
+ require_relative "../base"
2
+
3
+ module Rsg
4
+ module Install
5
+ class InstallGenerator < Rsg::Generators::Base
6
+ class_option :path, type: :string, default: nil, desc: "Path to the RSG gem"
7
+
8
+ def add_rsg
9
+ install_rsg
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,40 @@
1
+ require_relative "../base"
2
+
3
+ module Rsg
4
+ module Logging
5
+ class CommonGenerator < Rsg::Generators::Base
6
+ def banner
7
+ say "Improving basic logging configs"
8
+ end
9
+
10
+ def log_level_env_var
11
+ inject_into_file "config/application.rb", <<-CODE, before: /^ end$/
12
+ \n # Sane default log levels per env, but able to tweak with env var
13
+ # NOTE: Settings on config/environments/*.rb take precedence over this
14
+ config.log_level = ENV.fetch('LOG_LEVEL') { Rails.env.development? ? 'debug' : 'info' }.to_sym
15
+
16
+ # Log to stdout most of the time and allow use of JSON logs in dev by using an env var
17
+ config.x.log_to_stdout = %w[1 true yes].include?(ENV.fetch('RAILS_LOG_TO_STDOUT', '1'))
18
+ CODE
19
+ end
20
+
21
+ def stdout_logging_in_dev
22
+ inject_into_file "config/environments/development.rb", <<-CODE, before: /^end$/
23
+ \n # Configure stdout logging in dev as well
24
+ if config.x.log_to_stdout
25
+ logger = ActiveSupport::Logger.new(STDOUT)
26
+ logger.formatter = config.log_formatter
27
+ config.logger = ActiveSupport::TaggedLogging.new(logger)
28
+ end
29
+ CODE
30
+ end
31
+
32
+ def adjust_prod
33
+ comment_lines "config/environments/production.rb", /^(\s*)(config\.log_level .+)$/
34
+ gsub_file "config/environments/production.rb",
35
+ 'ENV["RAILS_LOG_TO_STDOUT"].present?',
36
+ "config.x.log_to_stdout"
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,31 @@
1
+ require_relative "../base"
2
+
3
+ module Rsg
4
+ module Logging
5
+ class LogrageGenerator < Rsg::Generators::Base
6
+ def self.source_root
7
+ Pathname.new(__FILE__).dirname.join("templates").expand_path
8
+ end
9
+
10
+ def banner
11
+ say "Configuring lograge with JSON logging"
12
+ end
13
+
14
+ def add_lograge
15
+ append_gem "lograge", install: false
16
+ append_gem "logstash-event", after: "lograge"
17
+ end
18
+
19
+ def initializer
20
+ copy_file "initializer_lograge.rb", "config/initializers/logging.rb"
21
+ end
22
+
23
+ def json_logs_env_var
24
+ inject_into_file "config/application.rb", <<-CODE, before: /^ end$/
25
+ \n # Enable JSON logs with lograge
26
+ config.x.json_logs = Rails.env.production? || %w[1 true yes].include?(ENV.fetch('JSON_LOGS', '0'))
27
+ CODE
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,9 @@
1
+ Rails.application.configure do
2
+ return unless config.x.json_logs
3
+
4
+ # See https://github.com/roidrage/lograge for more information on how to configure the gem
5
+ # This only configures logs to be formatted as JSON when lograge is enabled but you can do much more with it,
6
+ # like annotating logs with user IDs
7
+ config.lograge.enabled = true
8
+ config.lograge.formatter = Lograge::Formatters::Logstash.new
9
+ end
@@ -0,0 +1,61 @@
1
+ require_relative "../base"
2
+
3
+ module Rsg
4
+ module Misc
5
+ class MiscGenerator < Generators::Base
6
+ def self.source_root
7
+ Pathname.new(__FILE__).dirname.join("templates").expand_path
8
+ end
9
+
10
+ def banner
11
+ say "Making some extra tweaks"
12
+ end
13
+
14
+ def disable_assets_generators
15
+ return if api_mode?
16
+
17
+ inject_into_file "config/application.rb", <<-CODE, before: /^\s*# Don't generate system test files./
18
+
19
+ # Don't generate CSS files when using scaffolding commands, since we compile assets through webpacker
20
+ config.generators.assets = false
21
+ config.generators.scaffold_stylesheet = false
22
+ config.generators.stylesheets = false
23
+
24
+ # Most of time we can get away with a handful of methods in the default application_helper. Other ones
25
+ # can be introduced as needed
26
+ config.generators.helper = false
27
+ CODE
28
+ end
29
+
30
+ def configure_pry
31
+ append_gem "pry-rails", within_group: :development
32
+ end
33
+
34
+ def remove_assets
35
+ run "rm -rf app/assets"
36
+ end
37
+
38
+ # TODO: Skip puma on app generator, introduce a new Puma::InstallGenerator
39
+ def puma_configs
40
+ copy_file "puma.rb", "config/puma.rb", force: true
41
+ end
42
+
43
+ # TODO: Move to an i18n generator that does this and more
44
+ def configure_environments
45
+ # If by any chance we make use of translations, let them fail and get
46
+ # caught early on the dev process
47
+ uncomment_lines "config/environments/development.rb", /raise_on_missing_translations/
48
+ uncomment_lines "config/environments/test.rb", /raise_on_missing_translations/
49
+ end
50
+
51
+ def healthcheck
52
+ inject_into_file "config/routes.rb", <<-CODE, before: "end"
53
+
54
+ # Defines a static healthcheck for probes. Please note that this won't
55
+ # output any logs in production
56
+ get :healthcheck, to: proc { [200, {}, ['OK']] }
57
+ CODE
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Puma can serve each request in a thread from an internal thread pool.
4
+ # The `threads` method setting takes two numbers: a minimum and maximum.
5
+ # Any libraries that use thread pools should be configured to match
6
+ # the maximum value specified for Puma. Default is set to 5 threads for minimum
7
+ # and maximum; this matches the default thread size of Active Record.
8
+ max_threads_count = ENV.fetch('RAILS_MAX_THREADS', 5)
9
+ min_threads_count = ENV.fetch('RAILS_MIN_THREADS') { max_threads_count }
10
+ threads min_threads_count, max_threads_count
11
+
12
+ # Specifies the `worker_timeout` threshold that Puma will use to wait before
13
+ # terminating a worker in development environments.
14
+ # worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development"
15
+
16
+ # Specifies the `port` that Puma will listen on to receive requests; default is 3000.
17
+ port ENV.fetch('PORT', 3000)
18
+
19
+ # Specifies the `environment` that Puma will run in.
20
+ # environment ENV.fetch("RAILS_ENV") { "development" }
21
+
22
+ # Specifies the `pidfile` that Puma will use.
23
+ # pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" }
24
+
25
+ # Specifies the number of `workers` to boot in clustered mode. Workers are
26
+ # forked web server processes. If using threads and workers together the
27
+ # concurrency of the application would be max `threads` * `workers`. Workers do
28
+ # not work on JRuby or Windows (both of which do not support processes).
29
+ #
30
+ # Here we disable workers by default since we tipically run our apps in
31
+ # containers, so we can scale the amount of processes by spinning up new
32
+ # containers to handle the load instead of having multiple processes running in
33
+ # the same container.
34
+ workers ENV.fetch('WEB_CONCURRENCY', 0)
35
+
36
+ # Use the `preload_app!` method when specifying a `workers` number.
37
+ # This directive tells Puma to first boot the application and load code
38
+ # before forking the application. This takes advantage of Copy On Write
39
+ # process behavior so workers use less memory.
40
+ #
41
+ # preload_app!
42
+
43
+ # Allow puma to be restarted by `rails restart` command.
44
+ plugin :tmp_restart
@@ -0,0 +1,15 @@
1
+ module Rsg
2
+ module Generators
3
+ module Options
4
+ def self.included(base)
5
+ configure_basic_options(base)
6
+ end
7
+
8
+ def self.configure_basic_options(base)
9
+ base.instance_eval do
10
+ class_option :quiet, type: :boolean, aliases: "-q", default: false, desc: "Suppress status output"
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,44 @@
1
+ require_relative "../base"
2
+
3
+ module Rsg
4
+ module Orm
5
+ class ActiveRecordGenerator < Generators::Base
6
+ include Rails::Generators::Database
7
+
8
+ SUPPORTED_DBS = %w(sqlite3 mysql postgres)
9
+ class_option :database, type: :string, default: nil, desc: "Configure for selected database (options: #{SUPPORTED_DBS.join("/")})"
10
+
11
+ def self.source_root
12
+ Pathname.new(__FILE__).dirname.join("templates").expand_path
13
+ end
14
+
15
+ def banner
16
+ say "Configuring active record"
17
+ end
18
+
19
+ def enable_active_record
20
+ enable_railtie "active_record"
21
+ end
22
+
23
+ def configure_driver
24
+ database = options.fetch(:database) { ask("Which database you'd like to use?", limited_to: SUPPORTED_DBS, default: "sqlite3") }
25
+ template "active_record/#{database}.yml", "config/database.yml"
26
+
27
+ name, version = gem_for_database(database)
28
+ append_gem name, version: version
29
+ end
30
+
31
+ def write_db_sample
32
+ copy_file "db.rake", "lib/tasks/db.rake"
33
+ copy_file "seeds.rb", "db/seeds.rb"
34
+ copy_file "samples.rb", "db/samples.rb"
35
+ end
36
+
37
+ def migrate
38
+ return if no?("Would you like to create the database schema?")
39
+
40
+ rake "db:create db:migrate"
41
+ end
42
+ end
43
+ end
44
+ end