# typed: false # frozen_string_literal: true require "rails/generators" require "rails/generators/rails/app/app_generator" require "tempfile" module Hephaestus class AppGenerator < Rails::Generators::AppGenerator include ExitOnFailure hide! class_option :version, type: :boolean, aliases: "-v", group: :hephaestus, desc: "Show Hephaestus version number and quit" class_option :help, type: :boolean, aliases: "-h", group: :hephaestus, desc: "Show this help message and quit" def finish_template invoke(:hephaestus_customization) super end # NOTE: this function name is important as it overrides # a Rails function of the same name (that function performs work # that we don't want to do) def leftovers build(:replace_generic_variables) say(set_color("Generating `hephaestus:license`...", :cyan)) capture_stdout do generate("hephaestus:license") end say(set_color("Generating `hephaestus:rubocop`...", :cyan)) capture_stdout do generate("hephaestus:rubocop") end say(set_color("Generating `hephaestus:sorbet`...", :cyan)) capture_stdout do generate("hephaestus:sorbet") end say(set_color("Creating first commit...", :cyan)) capture_stdout do invoke(:commit) end build(:restore_gemfile) invoke(:outro) end def hephaestus_customization say(set_color("Invoking Hephaestus customizations...", :cyan)) run("rails app:update:bin", capture: true) invoke(:customize_gemfile) invoke(:copy_github_actions) invoke(:copy_vscode_settings) invoke(:setup_development_environment) invoke(:setup_production_environment) invoke(:setup_staging_environment) invoke(:setup_test_environment) invoke(:setup_shared_environment_logic) invoke(:configure_app) invoke(:create_github_repo) end def customize_gemfile say(set_color("Customizing Gemfile...", :cyan)) build(:replace_gemfile) capture_stdout do bundle_command("install") bundle_command("lock --add-platform x86_64-linux") end end def copy_github_actions say(set_color("Copying GitHub Actions...", :cyan)) capture_stdout do directory(Hephaestus.source_path(".github"), ".github") end end def copy_vscode_settings say(set_color("Copying .vscode/...", :cyan)) capture_stdout do directory(Hephaestus.source_path(".vscode"), ".vscode") end end def setup_development_environment say(set_color("Setting up the development environment...", :cyan)) capture_stdout do build(:raise_on_delivery_errors) build(:configure_dev_hosting) build(:copy_setup_scripts) end end def setup_production_environment say(set_color("Setting up the production environment...", :cyan)) capture_stdout do build(:setup_asset_host) build(:setup_ssl) end end def setup_staging_environment say(set_color("Setting up the staging environment...", :cyan)) capture_stdout do build(:setup_staging_environment) end end def setup_test_environment say(set_color("Setting up the test environment...", :cyan)) capture_stdout do build(:setup_test_environment) end end def setup_shared_environment_logic capture_stdout do build(:setup_background_worker) build(:setup_slack_logger) end end def configure_app say(set_color("Configuring app...", :cyan)) remove_dir("app/assets") remove_dir("app/helpers") remove_dir("app/models") remove_dir("app/views/layouts") remove_dir("lib/assets") remove_dir("lib/tasks/.keep") remove_dir("test/helpers") remove_dir("test/channels") remove_dir("test/models") build(:configure_time_formats) bundle_command("binstubs bundler") capture_stdout do generate("hephaestus:core") generate("hephaestus:deployment") generate("hephaestus:lib") # keep this at the end generate("hephaestus:config") end end def create_github_repo if !options[:skip_git] && options[:github] say(set_color("Creating repository via `gh repo`...", :cyan)) build(:create_github_repo, options[:github]) end end def commit run("git add .") run("git commit -m 'Initial commit'", capture: true) end def outro say(<<~OUTPUT) #{set_color("Congratulations!", :green)} You just made a Yetto plug. You'll need to `cd #{ARGV.first}` and run the following commands--I can't do it for you! * `bin/rails credentials:edit --environment development` #{set_color("WAIT!", :red)} After running this command, note that Rails credited a file called development.key in the config/credentials directory. Store this in 1Password, then change the .env file to use this value. Generate keys for staging/production, too: * `bin/rails credentials:edit --environment staging` `bin/rails credentials:edit --environment production` Store this in 1Password too; you don't need the .env file for staging/production. For `SIGNING_SECRET` and `YETTO_PLUG_ID`, you'll need to generate those values yourself. Then, try running `bin/rails c` to ensure that everything was set up correctly. Running `rake test` is also a good idea. #{set_color("Also, after pushing to GitHub:", :yellow)} * Set `settings/branches` to protect `production` * ✅ Require status checks to pass before merging * 🖊️ Status checks that are required: `test`, `ruby / brakeman`, `ruby / bundle-audit`. You can only set those 👆 after you've opened the first PR on GitHub. Crazy, I know!! But, doing so is *essential* for automerge to function properly. * Speaking of which, in `/settings` * ✅ Allow auto-merge * ✅ Automatically delete head branches OUTPUT end class << self def banner "hephaestus #{arguments.map(&:usage).join(" ")} [options]" end end protected def get_builder_class # rubocop:disable Naming/AccessorMethodName Hephaestus::AppBuilder end def using_active_record? !options[:skip_active_record] end private def capture_stdout stream = "stdout" captured_stream = Tempfile.new(stream) stream_io = eval("$#{stream}", binding, __FILE__, __LINE__) origin_stream = stream_io.dup stream_io.reopen(captured_stream) yield stream_io.rewind captured_stream.read ensure unless captured_stream.nil? captured_stream.close captured_stream.unlink end stream_io.reopen(origin_stream) unless stream_io.nil? end end end