lib/generators/katapult/basics/basics_generator.rb in katapult-0.2.0 vs lib/generators/katapult/basics/basics_generator.rb in katapult-0.3.0

- old
+ new

@@ -1,125 +1,224 @@ # Generates model-independent application basics (see method names). +require 'katapult/generator_goodies' +require 'katapult/version' # For writing .ruby-version + module Katapult module Generators class BasicsGenerator < Rails::Generators::Base + include Katapult::GeneratorGoodies - SKIP_GEMS = %w(sass-rails coffee-rails turbolinks sdoc uglifier) + WEBPACK_DIR = 'app/webpack' + YARN_PACKAGES = %w[ + autoprefixer + autosize + bootstrap-sass + jquery + jquery-ujs + unpoly + ] desc 'Generate basics like test directories and gems' source_root File.expand_path('../templates', __FILE__) - class_option :db_user, type: :string, default: 'root', + class_option :db_user, type: :string, default: '', description: 'The user to set in config/database.yml' class_option :db_password, type: :string, default: '', description: 'The password to set in config/database.yml' + def write_ruby_version + template '.ruby-version' + end def add_gitignore template '.gitignore', force: true end - def write_ruby_version - template '.ruby-version' + def add_robots_txt + template 'public/robots.txt', force: true end - def write_database_ymls - @db_user = options.db_user - @db_password = options.db_password + # Gems ################################################################### - template 'config/database.yml', force: true - template 'config/database.sample.yml' - end - - # Overwrite Gemfile with the template, but transfer all gems that are not - # skipped (see SKIP_GEMS). def enhance_gemfile - gem_lines = File.readlines('Gemfile').select{ |line| line =~ /^gem/ } - @original_gems = gem_lines.reject do |line| - line =~ /'(#{ SKIP_GEMS.join '|' })'/ - end - + # Need to transfer the katapult line, because in tests, katapult is + # installed with a custom :path option + @katapult = File.readlines('Gemfile').find{ |line| line =~ /^gem 'katapult'/ } template 'Gemfile', force: true end def bundle_install run 'bundle install' + # Fix Bundler for parallel_tests + run 'bundle config --local disable_exec_load true' + # This is relevant for the server, so it may happen after bundling here. # By having Nokogiri use system libraries, it will get automatic updates # of the frequently broken libxml (i.e. when the system libxml updates). run 'bundle config --local build.nokogiri --use-system-libraries' end - def remove_turbolinks_js - gsub_file 'app/assets/javascripts/application.js', "//= require turbolinks\n", '' - gsub_file 'app/views/layouts/application.html.erb', ", 'data-turbolinks-track' => true", '' + + # Database ############################################################### + + def write_database_ymls + @db_user = options.db_user + @db_password = options.db_password + + template 'config/database.yml', force: true + template 'config/database.sample.yml' end - def setup_spring - # run 'spring binstub --all' - # # remove_file 'bin/bundle' # Won't play together with parallel_tests - # template 'config/spring.rb' - # template 'bin/rake' - run 'spring stop' # Reload (just in case) + def create_databases + # Need to unset RAILS_ENV variable for this sub command because + # parallel_tests defaults to "test" only if the variable is not set (<-> + # empty string value). However, because this is run from a Rails + # generator, the variable is already set to "development". Cannot set to + # "test" either because parallel_tests is only loaded in development. + run 'unset RAILS_ENV; bundle exec rake db:drop db:create parallel:drop parallel:create' end - def setup_guard - template 'Guardfile' - environment 'config.middleware.use Rack::LiveReload', env: :development + + # Configure Rails ######################################################## + + def install_application_layout + remove_file 'app/views/layouts/application.html.erb' + directory 'app/views/layouts' end + # We're using Webpacker + def remove_asset_pipeline_traces + remove_dir 'app/assets' + end + + def disable_migration_errors + development = 'config/environments/development.rb' + gsub_file development, /(migration_error =) :page_load/, '\1 false' + end + def setup_staging - FileUtils.copy 'config/environments/production.rb', 'config/environments/staging.rb' - secret = `rake secret`.chomp + template 'config/environments/staging.rb' + # Cheating in the "staging" secret between "test" and "production" + secret = run('bundle exec rake secret', capture: true).chomp insert_into_file 'config/secrets.yml', <<~SECRET, after: "test:\n" secret_key_base: #{ secret } staging: SECRET end - def create_databases - run 'rake db:drop:all db:create:all parallel:create' + def configure_test_environment + test_env = 'config/environments/test.rb' + + gsub_file test_env, + /# Do not eager load code on boot.*config\.eager_load = false/m, + 'config.eager_load = true' + gsub_file test_env, + / # Show full error.*\n config\.consider_all_requests_local\s.*$/, + ' config.consider_all_requests_local = false' + gsub_file test_env, + / # Disable request forgery protection.*\n config\.action_controller\.allow_forgery_protection\s.*$\n/, + '' + gsub_file test_env, /config\.action_controller\.perform_caching\s.*$/, + 'config.action_controller.perform_caching = true' end def configure_action_mailer app_con = 'app/controllers/application_controller.rb' inject_into_file app_con, <<-CONFIG, before: /end\n\z/ - before_filter :make_action_mailer_use_request_host_and_protocol + before_action :make_action_mailer_use_request_host_and_protocol private def make_action_mailer_use_request_host_and_protocol ActionMailer::Base.default_url_options[:protocol] = request.protocol ActionMailer::Base.default_url_options[:host] = request.host_with_port end CONFIG + + gsub_file 'app/mailers/application_mailer.rb', + /(^\s+default from:).*$/, '\1 Rails.configuration.system_email' end def set_timezone + # This results in correct indentation :) + application <<-'LOAD_PATHS' +config.time_zone = 'Berlin' + config.active_record.default_timezone = :local + config.active_record.time_zone_aware_attributes = false + LOAD_PATHS gsub_file 'config/application.rb', /# config\.time_zone =.*$/, "config.time_zone = 'Berlin'" end + def configure_system_email + application "config.system_email = 'system@#{app_name}.com'\n" + end + def disable_asset_debugging # Faster gsub_file 'config/environments/development.rb', /config\.assets\.debug =.*$/, 'config.assets.debug = false' end + def install_helpers + directory 'app/helpers' + end + + def install_errors_controller + template 'app/controllers/errors_controller.rb' + route 'resources :errors, only: :new' + end + def install_initializers directory 'config/initializers' end def install_ext directory 'lib/ext' end + + # Configure 3rd party #################################################### + + def setup_spring + run 'spring binstub --all' + + # Enhance Spring config + config = 'config/spring.rb' + inject_into_file config, <<-DIR, after: /\A%w\(\n/ + lib/templates + DIR + prepend_to_file config, <<-MKDIR +# Custom generator templates are put into lib/templates +FileUtils.mkdir_p 'lib/templates' + + MKDIR + + # Parallel-fix binstubs + Dir['bin/*'].each do |binstub| + if File.read(binstub) =~ /load.*spring/ + inject_into_file binstub, <<-PARALLEL, after: /\A.*\n/ +running_in_parallel = ENV.has_key?('TEST_ENV_NUMBER') || ARGV.any? { |arg| arg =~ /^parallel:/ } + + PARALLEL + + gsub_file binstub, /^(\s*load .*spring.*)$/, '\1 unless running_in_parallel' + end + end + end + + def setup_guard + template 'Guardfile' + environment "config.middleware.use Rack::LiveReload\n", env: :development + environment "config.assets.digest = false # For Guard::Livereload\n", env: :development + end + def add_modularity_load_paths # This results in correct indentation :) application <<-'LOAD_PATHS' config.autoload_paths << "#{Rails.root}/app/controllers/shared" config.autoload_paths << "#{Rails.root}/app/models/shared" @@ -127,57 +226,93 @@ config.autoload_paths << "#{Rails.root}/app/util/shared" LOAD_PATHS end def install_cucumber + run 'spring stop' # Spring constantly causes trouble here + generate 'cucumber:install' directory 'features/support' template 'config/cucumber.yml', force: true # Remove cucumber section from database.yml. Don't need this. gsub_file 'config/database.yml', /^cucumber.*\z/m, '' + + environment <<~ACTIVE_JOB, env: 'test' + config.active_job.queue_adapter = :inline + ACTIVE_JOB end def install_rspec generate 'rspec:install' + directory 'spec' + gsub_file '.rspec', "--warnings\n", '' # Don't show Ruby warnings - uncomment_lines 'spec/rails_helper.rb', /Dir.Rails.root.join.+spec.support/ - template 'spec/support/shoulda_matchers.rb' - template 'spec/support/factory_girl.rb' - directory 'spec/factories' + template '.rspec_parallel' + + merge_rails_helper_into_spec_helper + + uncomment_lines 'spec/spec_helper.rb', /Dir.Rails.root.join.+spec.support/ + gsub_file 'spec/spec_helper.rb', + /^ config\.use_transactional_fixtures = true/, <<-CONTENT + # RSpec's transaction logic needs to be disabled for DatabaseCleaner to work + config.use_transactional_fixtures = false + CONTENT end def install_capistrano # Create Capfile *before* installing Capistrano to prevent annoying # Harrow.io ad template 'Capfile', force: true run 'cap install' + deploy_rb = File.read('config/deploy.rb') + @version = deploy_rb[/^lock.*?([\d\.]+)/, 1] template 'config/deploy.rb', force: true template 'config/deploy/staging.rb', force: true template 'config/deploy/production.rb', force: true directory 'lib/capistrano/tasks' template 'lib/tasks/pending_migrations.rake' end - def install_styles - remove_file 'app/assets/stylesheets/application.css' - directory 'app/assets/stylesheets', force: true - end + def setup_webpacker + remove_dir 'app/javascript' + directory WEBPACK_DIR + directory 'config/webpack' + gsub_file 'config/webpacker.yml', /^( source_path:).*$/, '\1 ' + WEBPACK_DIR + inject_into_file 'config/webpack/environment.js', <<~JQUERY, after: /\A.*\n/ # 1st line + const webpack = require('webpack') - private + environment.plugins.set('Provide', new webpack.ProvidePlugin({ + $: 'jquery', + jQuery: 'jquery' + }) + ) + JQUERY - def app_name - File.basename(Dir.pwd) + yarn :add, *YARN_PACKAGES end - def run(*) - Bundler.with_clean_env do - super - end + def configure_autoprefixer + template '.browserslistrc' + end + + # Bundler prefers installed gems, but we want the newest versions possible + def update_gems + run 'bundle install' + end + + private + + def merge_rails_helper_into_spec_helper + spec_helper = File.read 'spec/spec_helper.rb' + spec_helper.gsub! /.*^RSpec\.configure.+?$/m, '' # Remove introduction + gsub_file 'spec/rails_helper.rb', /end\n\z/, spec_helper + + FileUtils.mv 'spec/rails_helper.rb', 'spec/spec_helper.rb', force: true end end end end