require 'rails/generators' require 'rails/generators/rails/app/app_generator' require 'json' require 'active_support/core_ext/hash/indifferent_access' module MobileWorkflowCli class AppGenerator < Rails::Generators::AppGenerator hide! class_option :skip_test, type: :boolean, default: true, desc: "Skip Test Unit" class_option :force, type: :boolean, default: true, desc: "Force overwrite" class_option :version, type: :boolean, aliases: "-v", desc: "Show version number and quit" class_option :help, type: :boolean, aliases: '-h', desc: "Show this help message and quit" class_option :heroku, type: :boolean, default: false, desc: "Create Heroku app" class_option :dokku, type: :boolean, default: false, desc: "Create Dokku app" class_option :dokku_host, type: :string, desc: "Specify the Dokku host machine e.g. 18.131.127.164" class_option :s3_storage, type: :boolean, default: false, desc: "Create an s3 backend for image upload and storage" class_option :aws_region, type: :string, default: 'us-east-1', desc: "Specify a region to create AWS resources in" def self.banner "mwf [options]" end def finish_template run "spring stop" super after_bundle do build :application_controller build :api_controller build :notifications_controller if options[:s3_storage] build :model_template build :procfiles build :rspec_generator build :controller_generator build :ability_generator build :active_storage if options[:s3_storage] open_api_spec = read_openapi_spec generate_models(open_api_spec) setup_db generate_administrate generate_controllers_and_routes(open_api_spec) admin_user = 'admin' admin_password = SecureRandom.base64(12) generate_dot_env(admin_user, admin_password) initial_git_commit build :heroku if options[:heroku] build :dokku, options[:dokku_host] if options[:dokku] build :s3_backend, options[:aws_region] if options[:s3_storage] end end protected def get_builder_class MobileWorkflowCli::AppBuilder end # Todo: MBS - move these methods to the builder class # Ideally override RailsBuilder methods private def read_openapi_spec openapi_spec_path = ARGV[1] say "Loading model from OpenAPI Spec: #{openapi_spec_path}" return JSON.parse(File.read(openapi_spec_path)).with_indifferent_access end def generate_administrate generate 'administrate:install' file 'app/assets/config/manifest.js', <<-CODE //= link administrate/application.css //= link administrate/application.js CODE file 'app/controllers/admin/application_controller.rb', <<-CODE module Admin class ApplicationController < Administrate::ApplicationController before_action :authenticate_admin def authenticate_admin self.class.http_basic_authenticate_with(name: ENV["ADMIN_USER"], password: ENV["ADMIN_PASSWORD"]) end end end CODE end def generate_models(openapi_spec) say "Generating models" openapi_spec[:components][:schemas].each_pair do |name, schema| next if ["answer", "attachment"].include? name # Don't generate schemas for MW schemas generated_properties_args = schema["properties"].keys.collect{|key| "#{key}:string" }.join(" ") if yes? "Use generated schema #{name}(#{generated_properties_args})[yn]?" generate(:model, "#{name.underscore} #{generated_properties_args}") else properties_args = ask "Specify schema for #{name}: (e.g. text:string image:attachment region:reference)" generate(:model, "#{name.underscore} #{properties_args}") end end end def generate_controllers_and_routes(openapi_spec) say "Generating controllers" controller_names = openapi_spec[:paths].keys.collect{|url_path| url_path.split('/').last.pluralize } controller_names.each {|n| generate "mobile_workflow:controller #{n.singularize}" } controller_names.each {|n| route "resources :#{n}, only: [:index, :show, :create]" } route "root to: 'admin/#{controller_names.first}#index'" end def setup_db rails_command "db:drop" rails_command "db:create" rails_command "db:migrate" end def initial_git_commit git add: "." git commit: %Q{ -m 'Initial commit' } end def generate_dot_env(admin_user, admin_password) file '.env', <<-CODE ADMIN_USER=#{admin_user} ADMIN_PASSWORD=#{admin_password} CODE end end end