require "thor" module UcbRailsCli class Cli < Thor MASTER_KEY_PATH = File.expand_path("~/.ucb_rails_master_key") ## error messages INSTALL_RAILS = "Unable to find rails - please make sure you've installed Rails 5.1 or greater" VERIFY_KEY = "Unable to find the master key for encrypted credentials\n" + "in #{MASTER_KEY_PATH} or the RAILS_MASTER_KEY environment variable.\n" + "Please set the master key in one of these two places before proceeding." GEMFILE_ERROR = "Unable to add new gems to Gemfile - check the console output for more info" LAYOUT_FILES = "Unable to copy view templates - check the console output for more info" HELPER_FILES = "Unable to copy helpers - check the console output for more info" ASSETS = "Unable to copy app assets - check the console output for more info" ROUTES = "Unable to copy routes file - check the console output for more info" MIGRATIONS = "Unable to copy migrations from ucb_rails_user gem - check the console output for more info" CONTROLLERS = "Unable to copy controllers - check the console output for more info" CONFIG_FILES = "Unable to copy config files - check the console output for more info" RSPEC = "Unable to install RSpec - check the console output for more info" desc 'version', 'Display version' map %w[-v --version] => :version def version say "ucb_rails_cli #{UcbRailsCli::VERSION}" end desc "new APP_NAME", "generate a new UCB Rails app called NAME" option :rails_options def new(app_name) puts "Generating #{app_name}..." verify_rails or exit_with_error(INSTALL_RAILS) verify_master_key or exit_with_error(VERIFY_KEY) create_rails_app(app_name) or exit_with_error add_to_gemfile(app_name) or exit_with_error(GEMFILE_ERROR) add_layout_files(app_name) or exit_with_error(LAYOUT_FILES) add_helpers(app_name) or exit_with_error(HELPER_FILES) add_assets(app_name) or exit_with_error(ASSETS) add_routes(app_name) or exit_with_error(ROUTES) add_controllers(app_name) or exit_with_error(CONTROLLERS) add_config_files(app_name) or exit_with_error(CONFIG_FILES) install_migrations(app_name) or exit_with_error(MIGRATIONS) setup_rspec(app_name) or exit_with_error(RSPEC) puts <<-END ******************************************************************** Finished! Your new app is in ./#{app_name} From here, you should set up the database: cd #{app_name} bin/rake db:create bin/rake db:migrate then start the server as usual: bin/rails server then access the homepage at http://localhost:3000. You should be able to login with your usual UCB credentials. Enjoy! END end private def exit_with_error(msg="") puts msg exit -1 end def verify_rails begin `rails --version` =~ /Rails 5\./ rescue Exception => e return false end end def verify_master_key ENV["RAILS_MASTER_KEY"].to_s.length > 0 || FileTest.file?(MASTER_KEY_PATH) end def create_rails_app(app_name) result = system("rails new #{app_name} #{options[:rails_options]}") return true if result puts "Unable to run \"rails new\" to create a new app - check the console output \n" + "for more details about what went wrong" false end def add_to_gemfile(app_name) if system("cat #{template_dir}/Gemfile_additions >> #{app_name}/Gemfile") puts "Installing new gems..." system "cd #{app_name} && bundle install" end end def add_layout_files(app_name) puts "Installing template files..." if system("cp #{template_dir}/views/* #{app_name}/app/views/layouts") system "rm -f #{app_name}/app/views/layouts/application.html.erb" else false end end def add_helpers(app_name) puts "Installing helpers..." file_contents = `cat #{template_dir}/helpers/application_helper.rb` .gsub("%APP_NAME", humanize(app_name)) system "echo '#{file_contents}' > #{app_name}/app/helpers/application_helper.rb" true end def add_assets(app_name) puts "Installing assets..." result = system("cp #{template_dir}/stylesheets/main.sass #{app_name}/app/assets/stylesheets") && system("cp -R #{template_dir}/stylesheets/themes #{app_name}/app/assets/stylesheets") && system("cp #{template_dir}/images/* #{app_name}/app/assets/images") if result # don't clobber the default file until we're sure everything else went through system "cp #{template_dir}/stylesheets/application.css #{app_name}/app/assets/stylesheets" system "cp #{template_dir}/javascripts/application.js #{app_name}/app/assets/javascripts" else false end end def add_routes(app_name) puts "Installing routes..." system "cp #{template_dir}/config/routes.rb #{app_name}/config/routes.rb" end def add_controllers(app_name) puts "Installing controllers..." system "cp #{template_dir}/controllers/* #{app_name}/app/controllers/" end def add_config_files(app_name) puts "Installing config files..." system("cp #{template_dir}/config/initializers/ucb_rails_user.rb #{app_name}/config/initializers") system("cp #{template_dir}/config/credentials.yml.enc #{app_name}/config/") # add exeception_notification config to production.rb config prod_config_addition = <<-END_CONFIG config.middleware.use ExceptionNotification::Rack, email: { email_prefix: "[#{app_name}] ", sender_address: %{"notifier" }, exception_recipients: %w{ucb-ist-developers@berkeley.edu} } end END_CONFIG prod_config_contents = `cat #{app_name}/config/environments/production.rb` .gsub(/end\s\Z/, prod_config_addition) system "echo '#{prod_config_contents}' > #{app_name}/config/environments/production.rb" # move master key, unless in ENV unless ENV["MASTER_KEY_PATH"].to_s.length > 0 system "cp ~/.ucb_rails_master_key #{app_name}/config/master.key" end end def install_migrations(app_name) puts "Installing migrations from ucb_rails_user..." system "cd #{app_name} && bundle install" system "cd #{app_name} && bundle exec rails railties:install:migrations" end def setup_rspec(app_name) puts "Setting up rspec..." system("cd #{app_name} && bin/spring stop && bin/rails generate rspec:install") && system("rm -rf #{app_name}/test") end def template_dir "#{File.dirname(__dir__)}/ucb_rails_cli/templates" end def humanize(str) str .gsub("_", " ") .split .map(&:capitalize) .join(" ") end end end