omg-railties 8.0.0.alpha3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (351) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +171 -0
  3. data/MIT-LICENSE +20 -0
  4. data/RDOC_MAIN.md +99 -0
  5. data/README.rdoc +39 -0
  6. data/exe/rails +10 -0
  7. data/lib/minitest/rails_plugin.rb +140 -0
  8. data/lib/rails/all.rb +21 -0
  9. data/lib/rails/api/generator.rb +38 -0
  10. data/lib/rails/api/task.rb +235 -0
  11. data/lib/rails/app_loader.rb +77 -0
  12. data/lib/rails/application/bootstrap.rb +118 -0
  13. data/lib/rails/application/configuration.rb +659 -0
  14. data/lib/rails/application/default_middleware_stack.rb +140 -0
  15. data/lib/rails/application/dummy_config.rb +19 -0
  16. data/lib/rails/application/finisher.rb +238 -0
  17. data/lib/rails/application/routes_reloader.rb +79 -0
  18. data/lib/rails/application.rb +658 -0
  19. data/lib/rails/application_controller.rb +28 -0
  20. data/lib/rails/autoloaders/inflector.rb +21 -0
  21. data/lib/rails/autoloaders.rb +48 -0
  22. data/lib/rails/backtrace_cleaner.rb +42 -0
  23. data/lib/rails/cli.rb +21 -0
  24. data/lib/rails/code_statistics.rb +159 -0
  25. data/lib/rails/code_statistics_calculator.rb +99 -0
  26. data/lib/rails/command/actions.rb +52 -0
  27. data/lib/rails/command/base.rb +185 -0
  28. data/lib/rails/command/behavior.rb +84 -0
  29. data/lib/rails/command/environment_argument.rb +56 -0
  30. data/lib/rails/command/helpers/editor.rb +40 -0
  31. data/lib/rails/command.rb +172 -0
  32. data/lib/rails/commands/about/about_command.rb +14 -0
  33. data/lib/rails/commands/app/update_command.rb +94 -0
  34. data/lib/rails/commands/application/application_command.rb +33 -0
  35. data/lib/rails/commands/boot/boot_command.rb +14 -0
  36. data/lib/rails/commands/console/console_command.rb +91 -0
  37. data/lib/rails/commands/console/irb_console.rb +136 -0
  38. data/lib/rails/commands/credentials/USAGE +73 -0
  39. data/lib/rails/commands/credentials/credentials_command/diffing.rb +53 -0
  40. data/lib/rails/commands/credentials/credentials_command.rb +139 -0
  41. data/lib/rails/commands/db/system/change/change_command.rb +26 -0
  42. data/lib/rails/commands/dbconsole/dbconsole_command.rb +88 -0
  43. data/lib/rails/commands/destroy/destroy_command.rb +29 -0
  44. data/lib/rails/commands/dev/dev_command.rb +14 -0
  45. data/lib/rails/commands/devcontainer/devcontainer_command.rb +39 -0
  46. data/lib/rails/commands/encrypted/USAGE +23 -0
  47. data/lib/rails/commands/encrypted/encrypted_command.rb +98 -0
  48. data/lib/rails/commands/gem_help/USAGE +16 -0
  49. data/lib/rails/commands/gem_help/gem_help_command.rb +13 -0
  50. data/lib/rails/commands/generate/generate_command.rb +30 -0
  51. data/lib/rails/commands/help/USAGE +17 -0
  52. data/lib/rails/commands/help/help_command.rb +34 -0
  53. data/lib/rails/commands/initializers/initializers_command.rb +20 -0
  54. data/lib/rails/commands/middleware/middleware_command.rb +17 -0
  55. data/lib/rails/commands/new/new_command.rb +21 -0
  56. data/lib/rails/commands/notes/notes_command.rb +30 -0
  57. data/lib/rails/commands/plugin/plugin_command.rb +47 -0
  58. data/lib/rails/commands/rake/rake_command.rb +55 -0
  59. data/lib/rails/commands/restart/restart_command.rb +14 -0
  60. data/lib/rails/commands/routes/routes_command.rb +49 -0
  61. data/lib/rails/commands/runner/USAGE +22 -0
  62. data/lib/rails/commands/runner/runner_command.rb +81 -0
  63. data/lib/rails/commands/secret/secret_command.rb +13 -0
  64. data/lib/rails/commands/server/server_command.rb +290 -0
  65. data/lib/rails/commands/stats/stats_command.rb +19 -0
  66. data/lib/rails/commands/test/USAGE +14 -0
  67. data/lib/rails/commands/test/test_command.rb +81 -0
  68. data/lib/rails/commands/unused_routes/unused_routes_command.rb +75 -0
  69. data/lib/rails/commands/version/version_command.rb +12 -0
  70. data/lib/rails/commands.rb +18 -0
  71. data/lib/rails/configuration.rb +170 -0
  72. data/lib/rails/console/app.rb +8 -0
  73. data/lib/rails/console/helpers.rb +8 -0
  74. data/lib/rails/console/methods.rb +23 -0
  75. data/lib/rails/deprecator.rb +7 -0
  76. data/lib/rails/dev_caching.rb +44 -0
  77. data/lib/rails/engine/commands.rb +9 -0
  78. data/lib/rails/engine/configuration.rb +138 -0
  79. data/lib/rails/engine/lazy_route_set.rb +109 -0
  80. data/lib/rails/engine/railties.rb +23 -0
  81. data/lib/rails/engine/updater.rb +21 -0
  82. data/lib/rails/engine.rb +760 -0
  83. data/lib/rails/gem_version.rb +17 -0
  84. data/lib/rails/generators/actions/create_migration.rb +75 -0
  85. data/lib/rails/generators/actions.rb +528 -0
  86. data/lib/rails/generators/active_model.rb +94 -0
  87. data/lib/rails/generators/app_base.rb +806 -0
  88. data/lib/rails/generators/app_name.rb +39 -0
  89. data/lib/rails/generators/base.rb +432 -0
  90. data/lib/rails/generators/database.rb +287 -0
  91. data/lib/rails/generators/erb/authentication/authentication_generator.rb +15 -0
  92. data/lib/rails/generators/erb/authentication/templates/views/passwords/edit.html.erb +9 -0
  93. data/lib/rails/generators/erb/authentication/templates/views/passwords/new.html.erb +8 -0
  94. data/lib/rails/generators/erb/authentication/templates/views/sessions/new.html.erb +11 -0
  95. data/lib/rails/generators/erb/controller/controller_generator.rb +24 -0
  96. data/lib/rails/generators/erb/controller/templates/view.html.erb.tt +2 -0
  97. data/lib/rails/generators/erb/mailer/mailer_generator.rb +41 -0
  98. data/lib/rails/generators/erb/mailer/templates/layout.html.erb.tt +13 -0
  99. data/lib/rails/generators/erb/mailer/templates/layout.text.erb.tt +1 -0
  100. data/lib/rails/generators/erb/mailer/templates/view.html.erb.tt +5 -0
  101. data/lib/rails/generators/erb/mailer/templates/view.text.erb.tt +3 -0
  102. data/lib/rails/generators/erb/scaffold/scaffold_generator.rb +34 -0
  103. data/lib/rails/generators/erb/scaffold/templates/_form.html.erb.tt +37 -0
  104. data/lib/rails/generators/erb/scaffold/templates/edit.html.erb.tt +12 -0
  105. data/lib/rails/generators/erb/scaffold/templates/index.html.erb.tt +16 -0
  106. data/lib/rails/generators/erb/scaffold/templates/new.html.erb.tt +11 -0
  107. data/lib/rails/generators/erb/scaffold/templates/partial.html.erb.tt +17 -0
  108. data/lib/rails/generators/erb/scaffold/templates/show.html.erb.tt +10 -0
  109. data/lib/rails/generators/erb.rb +26 -0
  110. data/lib/rails/generators/generated_attribute.rb +274 -0
  111. data/lib/rails/generators/migration.rb +71 -0
  112. data/lib/rails/generators/model_helpers.rb +62 -0
  113. data/lib/rails/generators/named_base.rb +227 -0
  114. data/lib/rails/generators/rails/app/USAGE +31 -0
  115. data/lib/rails/generators/rails/app/app_generator.rb +678 -0
  116. data/lib/rails/generators/rails/app/templates/Dockerfile.tt +119 -0
  117. data/lib/rails/generators/rails/app/templates/Gemfile.tt +83 -0
  118. data/lib/rails/generators/rails/app/templates/README.md.tt +24 -0
  119. data/lib/rails/generators/rails/app/templates/Rakefile.tt +6 -0
  120. data/lib/rails/generators/rails/app/templates/app/assets/stylesheets/application.css.tt +15 -0
  121. data/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb.tt +6 -0
  122. data/lib/rails/generators/rails/app/templates/app/helpers/application_helper.rb.tt +2 -0
  123. data/lib/rails/generators/rails/app/templates/app/jobs/application_job.rb.tt +7 -0
  124. data/lib/rails/generators/rails/app/templates/app/mailers/application_mailer.rb.tt +4 -0
  125. data/lib/rails/generators/rails/app/templates/app/models/application_record.rb.tt +3 -0
  126. data/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt +33 -0
  127. data/lib/rails/generators/rails/app/templates/app/views/layouts/mailer.html.erb.tt +13 -0
  128. data/lib/rails/generators/rails/app/templates/app/views/layouts/mailer.text.erb.tt +1 -0
  129. data/lib/rails/generators/rails/app/templates/app/views/pwa/manifest.json.erb.tt +22 -0
  130. data/lib/rails/generators/rails/app/templates/app/views/pwa/service-worker.js +26 -0
  131. data/lib/rails/generators/rails/app/templates/bin/brakeman.tt +6 -0
  132. data/lib/rails/generators/rails/app/templates/bin/dev.tt +1 -0
  133. data/lib/rails/generators/rails/app/templates/bin/rails.tt +3 -0
  134. data/lib/rails/generators/rails/app/templates/bin/rake.tt +3 -0
  135. data/lib/rails/generators/rails/app/templates/bin/rubocop.tt +7 -0
  136. data/lib/rails/generators/rails/app/templates/bin/setup.tt +45 -0
  137. data/lib/rails/generators/rails/app/templates/bin/thrust.tt +4 -0
  138. data/lib/rails/generators/rails/app/templates/config/application.rb.tt +42 -0
  139. data/lib/rails/generators/rails/app/templates/config/boot.rb.tt +6 -0
  140. data/lib/rails/generators/rails/app/templates/config/cable.yml.tt +10 -0
  141. data/lib/rails/generators/rails/app/templates/config/databases/mysql.yml.tt +82 -0
  142. data/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml.tt +114 -0
  143. data/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml.tt +72 -0
  144. data/lib/rails/generators/rails/app/templates/config/databases/trilogy.yml.tt +82 -0
  145. data/lib/rails/generators/rails/app/templates/config/deploy.yml.tt +107 -0
  146. data/lib/rails/generators/rails/app/templates/config/environment.rb.tt +5 -0
  147. data/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt +89 -0
  148. data/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt +125 -0
  149. data/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt +62 -0
  150. data/lib/rails/generators/rails/app/templates/config/initializers/assets.rb.tt +7 -0
  151. data/lib/rails/generators/rails/app/templates/config/initializers/content_security_policy.rb.tt +25 -0
  152. data/lib/rails/generators/rails/app/templates/config/initializers/cors.rb.tt +16 -0
  153. data/lib/rails/generators/rails/app/templates/config/initializers/filter_parameter_logging.rb.tt +8 -0
  154. data/lib/rails/generators/rails/app/templates/config/initializers/inflections.rb.tt +16 -0
  155. data/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_8_0.rb.tt +25 -0
  156. data/lib/rails/generators/rails/app/templates/config/locales/en.yml +31 -0
  157. data/lib/rails/generators/rails/app/templates/config/puma.rb.tt +43 -0
  158. data/lib/rails/generators/rails/app/templates/config/routes.rb.tt +16 -0
  159. data/lib/rails/generators/rails/app/templates/config/storage.yml.tt +34 -0
  160. data/lib/rails/generators/rails/app/templates/config.ru.tt +6 -0
  161. data/lib/rails/generators/rails/app/templates/db/seeds.rb.tt +9 -0
  162. data/lib/rails/generators/rails/app/templates/docker-entrypoint.tt +16 -0
  163. data/lib/rails/generators/rails/app/templates/dockerignore.tt +56 -0
  164. data/lib/rails/generators/rails/app/templates/env.erb.tt +5 -0
  165. data/lib/rails/generators/rails/app/templates/gitattributes.tt +9 -0
  166. data/lib/rails/generators/rails/app/templates/github/ci.yml.tt +138 -0
  167. data/lib/rails/generators/rails/app/templates/github/dependabot.yml +12 -0
  168. data/lib/rails/generators/rails/app/templates/gitignore.tt +38 -0
  169. data/lib/rails/generators/rails/app/templates/node-version.tt +1 -0
  170. data/lib/rails/generators/rails/app/templates/public/400.html +67 -0
  171. data/lib/rails/generators/rails/app/templates/public/404.html +67 -0
  172. data/lib/rails/generators/rails/app/templates/public/406-unsupported-browser.html +66 -0
  173. data/lib/rails/generators/rails/app/templates/public/422.html +67 -0
  174. data/lib/rails/generators/rails/app/templates/public/500.html +66 -0
  175. data/lib/rails/generators/rails/app/templates/public/icon.png +0 -0
  176. data/lib/rails/generators/rails/app/templates/public/icon.svg +3 -0
  177. data/lib/rails/generators/rails/app/templates/public/robots.txt +1 -0
  178. data/lib/rails/generators/rails/app/templates/rubocop.yml.tt +8 -0
  179. data/lib/rails/generators/rails/app/templates/ruby-version.tt +1 -0
  180. data/lib/rails/generators/rails/app/templates/test/application_system_test_case.rb.tt +5 -0
  181. data/lib/rails/generators/rails/app/templates/test/test_helper.rb.tt +21 -0
  182. data/lib/rails/generators/rails/application_record/application_record_generator.rb +13 -0
  183. data/lib/rails/generators/rails/authentication/USAGE +6 -0
  184. data/lib/rails/generators/rails/authentication/authentication_generator.rb +54 -0
  185. data/lib/rails/generators/rails/authentication/templates/controllers/concerns/authentication.rb +55 -0
  186. data/lib/rails/generators/rails/authentication/templates/controllers/passwords_controller.rb +33 -0
  187. data/lib/rails/generators/rails/authentication/templates/controllers/sessions_controller.rb +21 -0
  188. data/lib/rails/generators/rails/authentication/templates/mailers/passwords_mailer.rb +6 -0
  189. data/lib/rails/generators/rails/authentication/templates/models/current.rb +4 -0
  190. data/lib/rails/generators/rails/authentication/templates/models/session.rb +3 -0
  191. data/lib/rails/generators/rails/authentication/templates/models/user.rb +6 -0
  192. data/lib/rails/generators/rails/authentication/templates/test/mailers/previews/passwords_mailer_preview.rb +7 -0
  193. data/lib/rails/generators/rails/authentication/templates/views/passwords_mailer/reset.html.erb +4 -0
  194. data/lib/rails/generators/rails/authentication/templates/views/passwords_mailer/reset.text.erb +2 -0
  195. data/lib/rails/generators/rails/benchmark/USAGE +19 -0
  196. data/lib/rails/generators/rails/benchmark/benchmark_generator.rb +30 -0
  197. data/lib/rails/generators/rails/benchmark/templates/benchmark.rb.tt +15 -0
  198. data/lib/rails/generators/rails/controller/USAGE +26 -0
  199. data/lib/rails/generators/rails/controller/controller_generator.rb +42 -0
  200. data/lib/rails/generators/rails/controller/templates/controller.rb.tt +9 -0
  201. data/lib/rails/generators/rails/credentials/credentials_generator.rb +61 -0
  202. data/lib/rails/generators/rails/credentials/templates/credentials.yml.tt +12 -0
  203. data/lib/rails/generators/rails/db/system/change/change_generator.rb +206 -0
  204. data/lib/rails/generators/rails/devcontainer/devcontainer_generator.rb +168 -0
  205. data/lib/rails/generators/rails/devcontainer/templates/devcontainer/Dockerfile.tt +3 -0
  206. data/lib/rails/generators/rails/devcontainer/templates/devcontainer/compose.yaml.tt +47 -0
  207. data/lib/rails/generators/rails/devcontainer/templates/devcontainer/devcontainer.json.tt +37 -0
  208. data/lib/rails/generators/rails/encrypted_file/encrypted_file_generator.rb +31 -0
  209. data/lib/rails/generators/rails/encryption_key_file/encryption_key_file_generator.rb +57 -0
  210. data/lib/rails/generators/rails/generator/USAGE +13 -0
  211. data/lib/rails/generators/rails/generator/generator_generator.rb +27 -0
  212. data/lib/rails/generators/rails/generator/templates/%file_name%_generator.rb.tt +3 -0
  213. data/lib/rails/generators/rails/generator/templates/USAGE.tt +8 -0
  214. data/lib/rails/generators/rails/generator/templates/templates/.empty_directory +0 -0
  215. data/lib/rails/generators/rails/helper/USAGE +12 -0
  216. data/lib/rails/generators/rails/helper/helper_generator.rb +20 -0
  217. data/lib/rails/generators/rails/helper/templates/helper.rb.tt +4 -0
  218. data/lib/rails/generators/rails/integration_test/USAGE +10 -0
  219. data/lib/rails/generators/rails/integration_test/integration_test_generator.rb +9 -0
  220. data/lib/rails/generators/rails/master_key/master_key_generator.rb +53 -0
  221. data/lib/rails/generators/rails/migration/USAGE +45 -0
  222. data/lib/rails/generators/rails/migration/migration_generator.rb +14 -0
  223. data/lib/rails/generators/rails/model/model_generator.rb +18 -0
  224. data/lib/rails/generators/rails/plugin/USAGE +21 -0
  225. data/lib/rails/generators/rails/plugin/plugin_generator.rb +499 -0
  226. data/lib/rails/generators/rails/plugin/templates/%name%.gemspec.tt +28 -0
  227. data/lib/rails/generators/rails/plugin/templates/Gemfile.tt +23 -0
  228. data/lib/rails/generators/rails/plugin/templates/MIT-LICENSE.tt +20 -0
  229. data/lib/rails/generators/rails/plugin/templates/README.md.tt +28 -0
  230. data/lib/rails/generators/rails/plugin/templates/Rakefile.tt +14 -0
  231. data/lib/rails/generators/rails/plugin/templates/app/controllers/%namespaced_name%/application_controller.rb.tt +5 -0
  232. data/lib/rails/generators/rails/plugin/templates/app/helpers/%namespaced_name%/application_helper.rb.tt +5 -0
  233. data/lib/rails/generators/rails/plugin/templates/app/jobs/%namespaced_name%/application_job.rb.tt +5 -0
  234. data/lib/rails/generators/rails/plugin/templates/app/mailers/%namespaced_name%/application_mailer.rb.tt +7 -0
  235. data/lib/rails/generators/rails/plugin/templates/app/models/%namespaced_name%/application_record.rb.tt +6 -0
  236. data/lib/rails/generators/rails/plugin/templates/app/views/layouts/%namespaced_name%/application.html.erb.tt +17 -0
  237. data/lib/rails/generators/rails/plugin/templates/bin/rails.tt +15 -0
  238. data/lib/rails/generators/rails/plugin/templates/bin/rubocop.tt +7 -0
  239. data/lib/rails/generators/rails/plugin/templates/bin/test.tt +4 -0
  240. data/lib/rails/generators/rails/plugin/templates/config/routes.rb.tt +6 -0
  241. data/lib/rails/generators/rails/plugin/templates/github/ci.yml.tt +103 -0
  242. data/lib/rails/generators/rails/plugin/templates/github/dependabot.yml +12 -0
  243. data/lib/rails/generators/rails/plugin/templates/gitignore.tt +14 -0
  244. data/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%/engine.rb.tt +7 -0
  245. data/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%/railtie.rb.tt +5 -0
  246. data/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%/version.rb.tt +1 -0
  247. data/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%.rb.tt +8 -0
  248. data/lib/rails/generators/rails/plugin/templates/lib/tasks/%namespaced_name%_tasks.rake.tt +4 -0
  249. data/lib/rails/generators/rails/plugin/templates/rails/boot.rb.tt +5 -0
  250. data/lib/rails/generators/rails/plugin/templates/rails/routes.rb.tt +3 -0
  251. data/lib/rails/generators/rails/plugin/templates/rails/stylesheets.css +15 -0
  252. data/lib/rails/generators/rails/plugin/templates/rubocop.yml.tt +8 -0
  253. data/lib/rails/generators/rails/plugin/templates/test/%namespaced_name%_test.rb.tt +7 -0
  254. data/lib/rails/generators/rails/plugin/templates/test/application_system_test_case.rb.tt +5 -0
  255. data/lib/rails/generators/rails/plugin/templates/test/integration/navigation_test.rb.tt +7 -0
  256. data/lib/rails/generators/rails/plugin/templates/test/test_helper.rb.tt +21 -0
  257. data/lib/rails/generators/rails/resource/USAGE +23 -0
  258. data/lib/rails/generators/rails/resource/resource_generator.rb +27 -0
  259. data/lib/rails/generators/rails/resource_route/resource_route_generator.rb +23 -0
  260. data/lib/rails/generators/rails/scaffold/USAGE +41 -0
  261. data/lib/rails/generators/rails/scaffold/scaffold_generator.rb +18 -0
  262. data/lib/rails/generators/rails/scaffold_controller/USAGE +19 -0
  263. data/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb +56 -0
  264. data/lib/rails/generators/rails/scaffold_controller/templates/api_controller.rb.tt +57 -0
  265. data/lib/rails/generators/rails/scaffold_controller/templates/controller.rb.tt +64 -0
  266. data/lib/rails/generators/rails/script/USAGE +18 -0
  267. data/lib/rails/generators/rails/script/script_generator.rb +18 -0
  268. data/lib/rails/generators/rails/script/templates/script.rb.tt +3 -0
  269. data/lib/rails/generators/rails/system_test/USAGE +10 -0
  270. data/lib/rails/generators/rails/system_test/system_test_generator.rb +9 -0
  271. data/lib/rails/generators/rails/task/USAGE +9 -0
  272. data/lib/rails/generators/rails/task/task_generator.rb +13 -0
  273. data/lib/rails/generators/rails/task/templates/task.rb.tt +8 -0
  274. data/lib/rails/generators/resource_helpers.rb +82 -0
  275. data/lib/rails/generators/test_case.rb +37 -0
  276. data/lib/rails/generators/test_unit/controller/controller_generator.rb +19 -0
  277. data/lib/rails/generators/test_unit/controller/templates/functional_test.rb.tt +23 -0
  278. data/lib/rails/generators/test_unit/generator/generator_generator.rb +27 -0
  279. data/lib/rails/generators/test_unit/generator/templates/generator_test.rb.tt +16 -0
  280. data/lib/rails/generators/test_unit/helper/helper_generator.rb +11 -0
  281. data/lib/rails/generators/test_unit/integration/integration_generator.rb +20 -0
  282. data/lib/rails/generators/test_unit/integration/templates/integration_test.rb.tt +9 -0
  283. data/lib/rails/generators/test_unit/job/job_generator.rb +20 -0
  284. data/lib/rails/generators/test_unit/job/templates/unit_test.rb.tt +9 -0
  285. data/lib/rails/generators/test_unit/mailer/mailer_generator.rb +28 -0
  286. data/lib/rails/generators/test_unit/mailer/templates/functional_test.rb.tt +23 -0
  287. data/lib/rails/generators/test_unit/mailer/templates/preview.rb.tt +14 -0
  288. data/lib/rails/generators/test_unit/model/model_generator.rb +37 -0
  289. data/lib/rails/generators/test_unit/model/templates/fixtures.yml.tt +29 -0
  290. data/lib/rails/generators/test_unit/model/templates/unit_test.rb.tt +9 -0
  291. data/lib/rails/generators/test_unit/plugin/plugin_generator.rb +15 -0
  292. data/lib/rails/generators/test_unit/plugin/templates/%file_name%_test.rb.tt +7 -0
  293. data/lib/rails/generators/test_unit/plugin/templates/test_helper.rb +2 -0
  294. data/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb +82 -0
  295. data/lib/rails/generators/test_unit/scaffold/templates/api_functional_test.rb.tt +44 -0
  296. data/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb.tt +54 -0
  297. data/lib/rails/generators/test_unit/scaffold/templates/system_test.rb.tt +57 -0
  298. data/lib/rails/generators/test_unit/system/system_generator.rb +24 -0
  299. data/lib/rails/generators/test_unit/system/templates/application_system_test_case.rb.tt +5 -0
  300. data/lib/rails/generators/test_unit/system/templates/system_test.rb.tt +9 -0
  301. data/lib/rails/generators/test_unit.rb +10 -0
  302. data/lib/rails/generators/testing/assertions.rb +147 -0
  303. data/lib/rails/generators/testing/behavior.rb +116 -0
  304. data/lib/rails/generators/testing/setup_and_teardown.rb +20 -0
  305. data/lib/rails/generators.rb +327 -0
  306. data/lib/rails/health_controller.rb +55 -0
  307. data/lib/rails/info.rb +105 -0
  308. data/lib/rails/info_controller.rb +71 -0
  309. data/lib/rails/initializable.rb +95 -0
  310. data/lib/rails/mailers_controller.rb +122 -0
  311. data/lib/rails/paths.rb +246 -0
  312. data/lib/rails/plugin/test.rb +9 -0
  313. data/lib/rails/pwa_controller.rb +15 -0
  314. data/lib/rails/rack/logger.rb +88 -0
  315. data/lib/rails/rack/silence_request.rb +33 -0
  316. data/lib/rails/rack.rb +8 -0
  317. data/lib/rails/rackup/server.rb +15 -0
  318. data/lib/rails/railtie/configurable.rb +36 -0
  319. data/lib/rails/railtie/configuration.rb +114 -0
  320. data/lib/rails/railtie.rb +302 -0
  321. data/lib/rails/source_annotation_extractor.rb +214 -0
  322. data/lib/rails/tasks/engine.rake +85 -0
  323. data/lib/rails/tasks/framework.rake +34 -0
  324. data/lib/rails/tasks/log.rake +41 -0
  325. data/lib/rails/tasks/misc.rake +68 -0
  326. data/lib/rails/tasks/statistics.rake +23 -0
  327. data/lib/rails/tasks/tmp.rake +51 -0
  328. data/lib/rails/tasks/yarn.rake +29 -0
  329. data/lib/rails/tasks/zeitwerk.rake +41 -0
  330. data/lib/rails/tasks.rb +17 -0
  331. data/lib/rails/templates/layouts/application.html.erb +51 -0
  332. data/lib/rails/templates/rails/info/notes.html.erb +65 -0
  333. data/lib/rails/templates/rails/info/properties.html.erb +1 -0
  334. data/lib/rails/templates/rails/info/routes.html.erb +9 -0
  335. data/lib/rails/templates/rails/mailers/email.html.erb +201 -0
  336. data/lib/rails/templates/rails/mailers/index.html.erb +15 -0
  337. data/lib/rails/templates/rails/mailers/mailer.html.erb +12 -0
  338. data/lib/rails/templates/rails/welcome/index.html.erb +93 -0
  339. data/lib/rails/test_help.rb +47 -0
  340. data/lib/rails/test_unit/line_filtering.rb +13 -0
  341. data/lib/rails/test_unit/railtie.rb +25 -0
  342. data/lib/rails/test_unit/reporter.rb +121 -0
  343. data/lib/rails/test_unit/runner.rb +209 -0
  344. data/lib/rails/test_unit/test_parser.rb +133 -0
  345. data/lib/rails/test_unit/testing.rake +39 -0
  346. data/lib/rails/testing/maintain_test_schema.rb +16 -0
  347. data/lib/rails/version.rb +10 -0
  348. data/lib/rails/welcome_controller.rb +11 -0
  349. data/lib/rails/zeitwerk_checker.rb +15 -0
  350. data/lib/rails.rb +130 -0
  351. metadata +518 -0
@@ -0,0 +1,806 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fileutils"
4
+ require "digest/md5"
5
+ require "rails/version" unless defined?(Rails::VERSION)
6
+ require "open-uri"
7
+ require "tsort"
8
+ require "uri"
9
+ require "rails/generators"
10
+ require "active_support/core_ext/array/extract_options"
11
+
12
+ module Rails
13
+ module Generators
14
+ class AppBase < Base # :nodoc:
15
+ include AppName
16
+
17
+ NODE_LTS_VERSION = "20.11.1"
18
+ BUN_VERSION = "1.0.1"
19
+
20
+ JAVASCRIPT_OPTIONS = %w( importmap bun webpack esbuild rollup )
21
+ CSS_OPTIONS = %w( tailwind bootstrap bulma postcss sass )
22
+
23
+ attr_accessor :rails_template
24
+ add_shebang_option!
25
+
26
+ argument :app_path, type: :string
27
+
28
+ def self.strict_args_position
29
+ false
30
+ end
31
+
32
+ def self.add_shared_options_for(name)
33
+ class_option :name, type: :string, aliases: "-n",
34
+ desc: "Name of the app"
35
+
36
+ class_option :template, type: :string, aliases: "-m",
37
+ desc: "Path to some #{name} template (can be a filesystem path or URL)"
38
+
39
+ class_option :database, type: :string, aliases: "-d", default: "sqlite3",
40
+ enum: Database::DATABASES,
41
+ desc: "Preconfigure for selected database"
42
+
43
+ class_option :skip_git, type: :boolean, aliases: "-G", default: nil,
44
+ desc: "Skip git init, .gitignore and .gitattributes"
45
+
46
+ class_option :skip_docker, type: :boolean, default: nil,
47
+ desc: "Skip Dockerfile, .dockerignore and bin/docker-entrypoint"
48
+
49
+ class_option :skip_keeps, type: :boolean, default: nil,
50
+ desc: "Skip source control .keep files"
51
+
52
+ class_option :skip_action_mailer, type: :boolean, aliases: "-M",
53
+ default: nil,
54
+ desc: "Skip Action Mailer files"
55
+
56
+ class_option :skip_action_mailbox, type: :boolean, default: nil,
57
+ desc: "Skip Action Mailbox gem"
58
+
59
+ class_option :skip_action_text, type: :boolean, default: nil,
60
+ desc: "Skip Action Text gem"
61
+
62
+ class_option :skip_active_record, type: :boolean, aliases: "-O", default: nil,
63
+ desc: "Skip Active Record files"
64
+
65
+ class_option :skip_active_job, type: :boolean, default: nil,
66
+ desc: "Skip Active Job"
67
+
68
+ class_option :skip_active_storage, type: :boolean, default: nil,
69
+ desc: "Skip Active Storage files"
70
+
71
+ class_option :skip_action_cable, type: :boolean, aliases: "-C", default: nil,
72
+ desc: "Skip Action Cable files"
73
+
74
+ class_option :skip_asset_pipeline, type: :boolean, aliases: "-A", default: nil
75
+
76
+ class_option :skip_javascript, type: :boolean, aliases: ["-J", "--skip-js"], default: (true if name == "plugin"),
77
+ desc: "Skip JavaScript files"
78
+
79
+ class_option :skip_hotwire, type: :boolean, default: nil,
80
+ desc: "Skip Hotwire integration"
81
+
82
+ class_option :skip_jbuilder, type: :boolean, default: nil,
83
+ desc: "Skip jbuilder gem"
84
+
85
+ class_option :skip_test, type: :boolean, aliases: "-T", default: nil,
86
+ desc: "Skip test files"
87
+
88
+ class_option :skip_system_test, type: :boolean, default: nil,
89
+ desc: "Skip system test files"
90
+
91
+ class_option :skip_bootsnap, type: :boolean, default: nil,
92
+ desc: "Skip bootsnap gem"
93
+
94
+ class_option :skip_dev_gems, type: :boolean, default: nil,
95
+ desc: "Skip development gems (e.g., web-console)"
96
+
97
+ class_option :skip_thruster, type: :boolean, default: nil,
98
+ desc: "Skip Thruster setup"
99
+
100
+ class_option :skip_rubocop, type: :boolean, default: nil,
101
+ desc: "Skip RuboCop setup"
102
+
103
+ class_option :skip_brakeman, type: :boolean, default: nil,
104
+ desc: "Skip brakeman setup"
105
+
106
+ class_option :skip_ci, type: :boolean, default: nil,
107
+ desc: "Skip GitHub CI files"
108
+
109
+ class_option :skip_kamal, type: :boolean, default: nil,
110
+ desc: "Skip Kamal setup"
111
+
112
+ class_option :skip_solid, type: :boolean, default: nil,
113
+ desc: "Skip Solid Cache & Queue setup"
114
+
115
+ class_option :dev, type: :boolean, default: nil,
116
+ desc: "Set up the #{name} with Gemfile pointing to your Rails checkout"
117
+
118
+ class_option :devcontainer, type: :boolean, default: nil,
119
+ desc: "Generate devcontainer files"
120
+
121
+ class_option :edge, type: :boolean, default: nil,
122
+ desc: "Set up the #{name} with a Gemfile pointing to the #{edge_branch} branch on the Rails repository"
123
+
124
+ class_option :main, type: :boolean, default: nil, aliases: "--master",
125
+ desc: "Set up the #{name} with Gemfile pointing to Rails repository main branch"
126
+
127
+ class_option :rc, type: :string, default: nil,
128
+ desc: "Path to file containing extra configuration options for rails command"
129
+
130
+ class_option :no_rc, type: :boolean, default: nil,
131
+ desc: "Skip loading of extra configuration options from .railsrc file"
132
+
133
+ class_option :help, type: :boolean, aliases: "-h", group: :rails,
134
+ desc: "Show this help message and quit"
135
+ end
136
+
137
+ def self.edge_branch # :nodoc:
138
+ Rails.gem_version.prerelease? ? "main" : [*Rails.gem_version.segments.first(2), "stable"].join("-")
139
+ end
140
+
141
+ def initialize(positional_argv, option_argv, *)
142
+ @argv = [*positional_argv, *option_argv]
143
+ @gem_filter = lambda { |gem| true }
144
+ super
145
+ end
146
+
147
+ private
148
+ def gemfile_entries # :doc:
149
+ [
150
+ rails_gemfile_entry,
151
+ asset_pipeline_gemfile_entry,
152
+ database_gemfile_entry,
153
+ web_server_gemfile_entry,
154
+ javascript_gemfile_entry,
155
+ hotwire_gemfile_entry,
156
+ css_gemfile_entry,
157
+ jbuilder_gemfile_entry,
158
+ cable_gemfile_entry,
159
+ ].flatten.compact.select(&@gem_filter)
160
+ end
161
+
162
+ def builder # :doc:
163
+ @builder ||= begin
164
+ builder_class = get_builder_class
165
+ builder_class.include(ActionMethods)
166
+ builder_class.new(self)
167
+ end
168
+ end
169
+
170
+ def build(meth, *args) # :doc:
171
+ builder.public_send(meth, *args) if builder.respond_to?(meth)
172
+ end
173
+
174
+ def deduce_implied_options(options, option_reasons, meta_options)
175
+ active = options.transform_values { |value| [] if value }.compact
176
+ irrevocable = (active.keys - meta_options).to_set
177
+
178
+ deduction_order = TSort.tsort(
179
+ ->(&block) { option_reasons.each_key(&block) },
180
+ ->(key, &block) { option_reasons[key]&.each(&block) }
181
+ )
182
+
183
+ deduction_order.each do |name|
184
+ active_reasons = option_reasons[name].to_a.select(&active)
185
+ active[name] ||= active_reasons if active_reasons.any?
186
+ irrevocable << name if active_reasons.any?(irrevocable)
187
+ end
188
+
189
+ revoked = options.select { |name, value| value == false }.keys.to_set - irrevocable
190
+ deduction_order.reverse_each do |name|
191
+ revoked += option_reasons[name].to_a if revoked.include?(name)
192
+ end
193
+ revoked -= meta_options
194
+
195
+ active.filter_map do |name, reasons|
196
+ unless revoked.include?(name) || reasons.all?(revoked)
197
+ [name, reasons - revoked.to_a]
198
+ end
199
+ end.to_h
200
+ end
201
+
202
+ OPTION_IMPLICATIONS = { # :nodoc:
203
+ skip_active_job: [:skip_action_mailer, :skip_active_storage],
204
+ skip_active_record: [:skip_active_storage, :skip_solid],
205
+ skip_active_storage: [:skip_action_mailbox, :skip_action_text],
206
+ skip_javascript: [:skip_hotwire],
207
+ }
208
+
209
+ # ==== Options
210
+ #
211
+ # [+:meta_options+]
212
+ # A list of generator options which only serve to trigger other options.
213
+ # These options should have no other effects, and will be treated
214
+ # transparently when revoking other options.
215
+ #
216
+ # For example: --minimal implies both --skip-active-job and
217
+ # --skip-active-storage. Also, --skip-active-job by itself implies
218
+ # --skip-active-storage. If --skip-active-job is explicitly
219
+ # specified, --no-skip-active-storage should raise an error. But, if
220
+ # only --minimal is specified, --no-skip-active-storage should "undo"
221
+ # the implied --skip-active-job. This can be accomplished by passing
222
+ # <tt>meta_options: [:minimal]</tt>.
223
+ #
224
+ # In contrast, --api is not a meta option because it does other things
225
+ # besides implying options such as --skip-asset-pipeline. (And so --api
226
+ # with --no-skip-asset-pipeline should raise an error.)
227
+ def imply_options(option_implications = OPTION_IMPLICATIONS, meta_options: [])
228
+ option_reasons = {}
229
+ option_implications.each do |reason, implications|
230
+ implications.each do |implication|
231
+ (option_reasons[implication.to_s] ||= []) << reason.to_s
232
+ end
233
+ end
234
+
235
+ @implied_options = deduce_implied_options(options, option_reasons, meta_options.map(&:to_s))
236
+ @implied_options_conflicts = @implied_options.keys.select { |name| options[name] == false }
237
+ self.options = options.merge(@implied_options.transform_values { true }).freeze
238
+ end
239
+
240
+ def report_implied_options
241
+ return if @implied_options.blank?
242
+
243
+ say "Based on the specified options, the following options will also be activated:"
244
+ say ""
245
+ @implied_options.each do |name, reasons|
246
+ due_to = reasons.map { |reason| "--#{reason.dasherize}" }.join(", ")
247
+ say " --#{name.dasherize} [due to #{due_to}]"
248
+ if @implied_options_conflicts.include?(name)
249
+ say " ERROR: Conflicts with --no-#{name.dasherize}", :red
250
+ end
251
+ end
252
+ say ""
253
+
254
+ raise "Cannot proceed due to conflicting options" if @implied_options_conflicts.any?
255
+ end
256
+
257
+ def create_root # :doc:
258
+ valid_const?
259
+
260
+ empty_directory "."
261
+ FileUtils.cd(destination_root) unless options[:pretend]
262
+ end
263
+
264
+ def apply_rails_template # :doc:
265
+ apply rails_template if rails_template
266
+ rescue Thor::Error, LoadError, Errno::ENOENT => e
267
+ raise Error, "The template [#{rails_template}] could not be loaded. Error: #{e}"
268
+ end
269
+
270
+ def set_default_accessors! # :doc:
271
+ self.destination_root = File.expand_path(app_path, destination_root)
272
+
273
+ if options[:template].is_a?(String) && !options[:template].match?(/^https?:\/\//)
274
+ interpolated = options[:template].gsub(/\$(\w+)|\$\{\g<1>\}|%\g<1>%/) { |m| ENV[$1] || m }
275
+ self.rails_template = File.expand_path(interpolated)
276
+ else
277
+ self.rails_template = options[:template]
278
+ end
279
+ end
280
+
281
+ def database_gemfile_entry # :doc:
282
+ return if options[:skip_active_record]
283
+
284
+ gem_name, gem_version = database.gem
285
+ GemfileEntry.version gem_name, gem_version,
286
+ "Use #{options[:database]} as the database for Active Record"
287
+ end
288
+
289
+ def web_server_gemfile_entry # :doc:
290
+ GemfileEntry.new "puma", ">= 5.0", "Use the Puma web server [https://github.com/puma/puma]"
291
+ end
292
+
293
+ def asset_pipeline_gemfile_entry
294
+ unless skip_asset_pipeline?
295
+ GemfileEntry.floats "propshaft", "The modern asset pipeline for Rails [https://github.com/rails/propshaft]"
296
+ end
297
+ end
298
+
299
+ def required_railties
300
+ @required_railties ||= {
301
+ "active_model/railtie" => true,
302
+ "active_job/railtie" => !options[:skip_active_job],
303
+ "active_record/railtie" => !options[:skip_active_record],
304
+ "active_storage/engine" => !options[:skip_active_storage],
305
+ "action_controller/railtie" => true,
306
+ "action_mailer/railtie" => !options[:skip_action_mailer],
307
+ "action_mailbox/engine" => !options[:skip_action_mailbox],
308
+ "action_text/engine" => !options[:skip_action_text],
309
+ "action_view/railtie" => true,
310
+ "action_cable/engine" => !options[:skip_action_cable],
311
+ "rails/test_unit/railtie" => !options[:skip_test],
312
+ }
313
+ end
314
+
315
+ def include_all_railties? # :doc:
316
+ required_railties.values.all?
317
+ end
318
+
319
+ def rails_require_statement
320
+ if include_all_railties?
321
+ %(require "rails/all")
322
+ else
323
+ require_statements = required_railties.map do |railtie, required|
324
+ %(#{"# " if !required}require "#{railtie}")
325
+ end
326
+
327
+ <<~RUBY.strip
328
+ require "rails"
329
+ # Pick the frameworks you want:
330
+ #{require_statements.join("\n")}
331
+ RUBY
332
+ end
333
+ end
334
+
335
+ def comment_if(value) # :doc:
336
+ question = "#{value}?"
337
+
338
+ comment =
339
+ if respond_to?(question, true)
340
+ send(question)
341
+ else
342
+ options[value]
343
+ end
344
+
345
+ comment ? "# " : ""
346
+ end
347
+
348
+ def keeps? # :doc:
349
+ !options[:skip_keeps]
350
+ end
351
+
352
+ def sqlite3? # :doc:
353
+ !skip_active_record? && options[:database] == "sqlite3"
354
+ end
355
+
356
+ def skip_active_record? # :doc:
357
+ options[:skip_active_record]
358
+ end
359
+
360
+ def skip_active_storage? # :doc:
361
+ options[:skip_active_storage]
362
+ end
363
+
364
+ def skip_storage? # :doc:
365
+ skip_active_storage? && !sqlite3?
366
+ end
367
+
368
+ def skip_action_cable? # :doc:
369
+ options[:skip_action_cable]
370
+ end
371
+
372
+ def skip_action_mailer? # :doc:
373
+ options[:skip_action_mailer]
374
+ end
375
+
376
+ def skip_action_mailbox? # :doc:
377
+ options[:skip_action_mailbox]
378
+ end
379
+
380
+ def skip_action_text? # :doc:
381
+ options[:skip_action_text]
382
+ end
383
+
384
+ def skip_asset_pipeline? # :doc:
385
+ options[:skip_asset_pipeline]
386
+ end
387
+
388
+ def skip_thruster?
389
+ options[:skip_thruster]
390
+ end
391
+
392
+ def skip_rubocop?
393
+ options[:skip_rubocop]
394
+ end
395
+
396
+ def skip_brakeman?
397
+ options[:skip_brakeman]
398
+ end
399
+
400
+ def skip_ci?
401
+ options[:skip_ci]
402
+ end
403
+
404
+ def skip_devcontainer?
405
+ !options[:devcontainer]
406
+ end
407
+
408
+ def devcontainer?
409
+ options[:devcontainer]
410
+ end
411
+
412
+ def skip_kamal?
413
+ options[:skip_kamal]
414
+ end
415
+
416
+ def skip_solid?
417
+ options[:skip_solid]
418
+ end
419
+
420
+ class GemfileEntry < Struct.new(:name, :version, :comment, :options, :commented_out)
421
+ def initialize(name, version, comment, options = {}, commented_out = false)
422
+ super
423
+ end
424
+
425
+ def self.github(name, github, branch = nil, comment = nil)
426
+ if branch
427
+ new(name, nil, comment, github: github, branch: branch)
428
+ else
429
+ new(name, nil, comment, github: github)
430
+ end
431
+ end
432
+
433
+ def self.version(name, version, comment = nil)
434
+ new(name, version, comment)
435
+ end
436
+
437
+ def self.floats(name, comment = nil)
438
+ new(name, nil, comment)
439
+ end
440
+
441
+ def self.path(name, path, comment = nil)
442
+ new(name, nil, comment, path: path)
443
+ end
444
+
445
+ def to_s
446
+ [
447
+ (comment.gsub(/^/, "# ").chomp + "\n" if comment),
448
+ ("# " if commented_out),
449
+ "gem \"#{name}\"",
450
+ *Array(version).map { |constraint| ", \"#{constraint}\"" },
451
+ *options.map { |key, value| ", #{key}: #{value.inspect}" },
452
+ ].compact.join
453
+ end
454
+ end
455
+
456
+ def rails_prerelease?
457
+ options.dev? || options.edge? || options.main?
458
+ end
459
+
460
+ def rails_gemfile_entry
461
+ if options.dev?
462
+ GemfileEntry.path("rails", Rails::Generators::RAILS_DEV_PATH, "Use local checkout of Rails")
463
+ elsif options.edge?
464
+ GemfileEntry.github("rails", "rails/rails", edge_branch, "Use specific branch of Rails")
465
+ elsif options.main?
466
+ GemfileEntry.github("rails", "rails/rails", "main", "Use main development branch of Rails")
467
+ else
468
+ GemfileEntry.version("rails", rails_version_specifier,
469
+ %(Bundle edge Rails instead: gem "rails", github: "rails/rails", branch: "main"))
470
+ end
471
+ end
472
+
473
+ def rails_version_specifier(gem_version = Rails.gem_version)
474
+ if gem_version.segments.size == 3 || gem_version.release.segments.size == 3
475
+ # ~> 1.2.3
476
+ # ~> 1.2.3.pre4
477
+ "~> #{gem_version}"
478
+ else
479
+ # ~> 1.2.3, >= 1.2.3.4
480
+ # ~> 1.2.3, >= 1.2.3.4.pre5
481
+ patch = gem_version.segments[0, 3].join(".")
482
+ ["~> #{patch}", ">= #{gem_version}"]
483
+ end
484
+ end
485
+
486
+ def jbuilder_gemfile_entry
487
+ return if options[:skip_jbuilder]
488
+ GemfileEntry.new "jbuilder", nil, "Build JSON APIs with ease [https://github.com/rails/jbuilder]", {}, options[:api]
489
+ end
490
+
491
+ def javascript_gemfile_entry
492
+ return if options[:skip_javascript]
493
+
494
+ if options[:javascript] == "importmap"
495
+ GemfileEntry.floats "importmap-rails", "Use JavaScript with ESM import maps [https://github.com/rails/importmap-rails]"
496
+ else
497
+ GemfileEntry.floats "jsbundling-rails", "Bundle and transpile JavaScript [https://github.com/rails/jsbundling-rails]"
498
+ end
499
+ end
500
+
501
+ def hotwire_gemfile_entry
502
+ return if options[:skip_hotwire]
503
+
504
+ turbo_rails_entry =
505
+ GemfileEntry.floats "turbo-rails", "Hotwire's SPA-like page accelerator [https://turbo.hotwired.dev]"
506
+
507
+ stimulus_rails_entry =
508
+ GemfileEntry.floats "stimulus-rails", "Hotwire's modest JavaScript framework [https://stimulus.hotwired.dev]"
509
+
510
+ [ turbo_rails_entry, stimulus_rails_entry ]
511
+ end
512
+
513
+ def using_js_runtime?
514
+ (options[:javascript] && !%w[importmap].include?(options[:javascript])) ||
515
+ (options[:css] && !%w[tailwind sass].include?(options[:css]))
516
+ end
517
+
518
+ def using_node?
519
+ using_js_runtime? && !%w[bun].include?(options[:javascript])
520
+ end
521
+
522
+ def using_bun?
523
+ using_js_runtime? && %w[bun].include?(options[:javascript])
524
+ end
525
+
526
+ def node_version
527
+ if using_node?
528
+ ENV.fetch("NODE_VERSION") do
529
+ `node --version`[/\d+\.\d+\.\d+/]
530
+ rescue
531
+ NODE_LTS_VERSION
532
+ end
533
+ end
534
+ end
535
+
536
+ def dockerfile_yarn_version
537
+ using_node? and `yarn --version`[/\d+\.\d+\.\d+/]
538
+ rescue
539
+ "latest"
540
+ end
541
+
542
+ def dockerfile_bun_version
543
+ using_bun? and `bun --version`[/\d+\.\d+\.\d+/]
544
+ rescue
545
+ BUN_VERSION
546
+ end
547
+
548
+ def dockerfile_binfile_fixups
549
+ # binfiles may have OS specific paths to ruby. Normalize them.
550
+ shebangs = Dir["bin/*"].map { |file| IO.read(file).lines.first }.join
551
+ rubies = shebangs.scan(%r{#!/usr/bin/env (ruby.*)}).flatten.uniq
552
+
553
+ binfixups = (rubies - %w(ruby)).map do |ruby|
554
+ "sed -i 's/#{Regexp.quote(ruby)}$/ruby/' bin/*"
555
+ end
556
+
557
+ # Windows line endings will cause scripts to fail. If any
558
+ # or found OR this generation is run on a windows platform
559
+ # and there are other binfixups required, then convert
560
+ # line endings. This avoids adding unnecessary fixups if
561
+ # none are required, but prepares for the need to do the
562
+ # fix line endings if other fixups are required.
563
+ has_cr = Dir["bin/*"].any? { |file| IO.read(file).include? "\r" }
564
+ if has_cr || (Gem.win_platform? && !binfixups.empty?)
565
+ binfixups.unshift 'sed -i "s/\r$//g" bin/*'
566
+ end
567
+
568
+ # Windows file systems may not have the concept of executable.
569
+ # In such cases, fix up during the build.
570
+ unless Dir["bin/*"].all? { |file| File.executable? file }
571
+ binfixups.unshift "chmod +x bin/*"
572
+ end
573
+
574
+ binfixups
575
+ end
576
+
577
+ def dockerfile_base_packages
578
+ # Add curl to work with the default health check strategy in Kamal
579
+ packages = ["curl"]
580
+
581
+ # ActiveRecord databases
582
+ packages << database.base_package unless skip_active_record?
583
+
584
+ # ActiveStorage preview support
585
+ packages << "libvips" unless skip_active_storage?
586
+
587
+ # jemalloc for memory optimization
588
+ packages << "libjemalloc2"
589
+
590
+ packages.compact.sort
591
+ end
592
+
593
+ def dockerfile_build_packages
594
+ # start with the essentials
595
+ packages = %w(build-essential git pkg-config)
596
+
597
+ # add database support
598
+ packages << database.build_package unless skip_active_record?
599
+
600
+ packages << "unzip" if using_bun?
601
+
602
+ # node support, including support for building native modules
603
+ if using_node?
604
+ packages << "node-gyp" # pkg-config already listed above
605
+
606
+ packages << "python-is-python3"
607
+ end
608
+
609
+ packages.compact.sort
610
+ end
611
+
612
+ def css_gemfile_entry
613
+ return if options[:api]
614
+ return unless options[:css]
615
+
616
+ if !using_js_runtime? && options[:css] == "tailwind"
617
+ GemfileEntry.floats "tailwindcss-rails", "Use Tailwind CSS [https://github.com/rails/tailwindcss-rails]"
618
+ elsif !using_js_runtime? && options[:css] == "sass"
619
+ GemfileEntry.floats "dartsass-rails", "Use Dart SASS [https://github.com/rails/dartsass-rails]"
620
+ else
621
+ GemfileEntry.floats "cssbundling-rails", "Bundle and process CSS [https://github.com/rails/cssbundling-rails]"
622
+ end
623
+ end
624
+
625
+ def cable_gemfile_entry
626
+ return if options[:skip_action_cable]
627
+
628
+ comment = "Use Redis adapter to run Action Cable in production"
629
+ GemfileEntry.new("redis", ">= 4.0.1", comment, {}, true)
630
+ end
631
+
632
+ def bundle_command(command, env = {})
633
+ say_status :run, "bundle #{command}"
634
+
635
+ # We are going to shell out rather than invoking Bundler::CLI.new(command)
636
+ # because `rails new` loads the Thor gem and on the other hand bundler uses
637
+ # its own vendored Thor, which could be a different version. Running both
638
+ # things in the same process is a recipe for a night with paracetamol.
639
+ #
640
+ # Thanks to James Tucker for the Gem tricks involved in this call.
641
+ _bundle_command = Gem.bin_path("bundler", "bundle")
642
+
643
+ require "bundler"
644
+ Bundler.with_original_env do
645
+ exec_bundle_command(_bundle_command, command, env)
646
+ end
647
+ end
648
+
649
+ def exec_bundle_command(bundle_command, command, env)
650
+ full_command = %Q["#{Gem.ruby}" "#{bundle_command}" #{command}]
651
+ if options[:quiet]
652
+ system(env, full_command, out: File::NULL)
653
+ else
654
+ system(env, full_command)
655
+ end
656
+ end
657
+
658
+ def bundle_install?
659
+ !(options[:skip_bundle] || options[:pretend])
660
+ end
661
+
662
+ def bundler_windows_platforms
663
+ Gem.rubygems_version >= Gem::Version.new("3.3.22") ? "windows" : "mswin mswin64 mingw x64_mingw"
664
+ end
665
+
666
+ def depends_on_system_test?
667
+ !(options[:skip_system_test] || options[:skip_test] || options[:api])
668
+ end
669
+
670
+ def depend_on_bootsnap?
671
+ !options[:skip_bootsnap] && !options[:dev] && !defined?(JRUBY_VERSION)
672
+ end
673
+
674
+ def target_rails_prerelease(self_command = "new")
675
+ return unless rails_prerelease? && bundle_install?
676
+
677
+ if !File.exist?(File.expand_path("Gemfile", destination_root))
678
+ create_file("Gemfile", <<~GEMFILE)
679
+ source "https://rubygems.org"
680
+ #{rails_gemfile_entry}
681
+ GEMFILE
682
+
683
+ run_bundle
684
+
685
+ @argv.delete_at(@argv.index(app_path))
686
+ @argv.unshift(destination_root)
687
+ require "shellwords"
688
+ bundle_command("exec rails #{self_command} #{Shellwords.join(@argv)}")
689
+ exit
690
+ else
691
+ remove_file("Gemfile")
692
+ remove_file("Gemfile.lock")
693
+ end
694
+ end
695
+
696
+ def run_bundle
697
+ bundle_command("install --quiet", "BUNDLE_IGNORE_MESSAGES" => "1") if bundle_install?
698
+ end
699
+
700
+ def run_javascript
701
+ return if options[:skip_javascript] || !bundle_install?
702
+
703
+ case options[:javascript]
704
+ when "importmap" then rails_command "importmap:install"
705
+ when "webpack", "bun", "esbuild", "rollup" then rails_command "javascript:install:#{options[:javascript]}"
706
+ end
707
+ end
708
+
709
+ def run_hotwire
710
+ return if options[:skip_hotwire] || !bundle_install?
711
+
712
+ rails_command "turbo:install stimulus:install"
713
+ end
714
+
715
+ def run_css
716
+ return if !options[:css] || !bundle_install?
717
+
718
+ if !using_js_runtime? && options[:css] == "tailwind"
719
+ rails_command "tailwindcss:install"
720
+ elsif !using_js_runtime? && options[:css] == "sass"
721
+ rails_command "dartsass:install"
722
+ else
723
+ rails_command "css:install:#{options[:css]}"
724
+ end
725
+ end
726
+
727
+ def run_kamal
728
+ return if options[:skip_kamal] || !bundle_install?
729
+
730
+ bundle_command "binstubs kamal"
731
+ bundle_command "exec kamal init"
732
+
733
+ remove_file ".env"
734
+ template "env.erb", ".env.erb"
735
+ template "config/deploy.yml", force: true
736
+ end
737
+
738
+ def run_solid
739
+ return if skip_solid? || !bundle_install?
740
+
741
+ commands = "solid_cache:install solid_queue:install"
742
+ commands += " solid_cable:install" unless skip_action_cable?
743
+
744
+ rails_command commands
745
+ end
746
+
747
+ def add_bundler_platforms
748
+ if bundle_install?
749
+ # The vast majority of Rails apps will be deployed on `x86_64-linux`.
750
+ bundle_command("lock --add-platform=x86_64-linux")
751
+
752
+ # Users that develop on M1 mac may use docker and would need `aarch64-linux` as well.
753
+ bundle_command("lock --add-platform=aarch64-linux") if RUBY_PLATFORM.start_with?("arm64")
754
+ end
755
+ end
756
+
757
+ def generate_bundler_binstub
758
+ if bundle_install?
759
+ bundle_command("binstubs bundler")
760
+ end
761
+ end
762
+
763
+ def empty_directory_with_keep_file(destination, config = {})
764
+ empty_directory(destination, config)
765
+ keep_file(destination)
766
+ end
767
+
768
+ def keep_file(destination)
769
+ create_file("#{destination}/.keep") if keeps?
770
+ end
771
+
772
+ def user_default_branch
773
+ @user_default_branch ||= `git config init.defaultbranch`
774
+ end
775
+
776
+ def git_init_command
777
+ return "git init" if user_default_branch.strip.present?
778
+
779
+ git_version = `git --version`[/\d+\.\d+\.\d+/]
780
+
781
+ if Gem::Version.new(git_version) >= Gem::Version.new("2.28.0")
782
+ "git init -b main"
783
+ else
784
+ "git init && git symbolic-ref HEAD refs/heads/main"
785
+ end
786
+ end
787
+
788
+ def edge_branch
789
+ self.class.edge_branch
790
+ end
791
+
792
+ def dockerfile_chown_directories
793
+ directories = %w(log tmp)
794
+
795
+ directories << "storage" unless skip_storage?
796
+ directories << "db" unless skip_active_record?
797
+
798
+ directories.sort
799
+ end
800
+
801
+ def database
802
+ @database ||= Database.build(options[:database])
803
+ end
804
+ end
805
+ end
806
+ end