railties 7.0.8.7 → 7.1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +723 -215
- data/MIT-LICENSE +1 -1
- data/RDOC_MAIN.md +99 -0
- data/README.rdoc +4 -4
- data/lib/minitest/rails_plugin.rb +63 -0
- data/lib/rails/api/task.rb +35 -4
- data/lib/rails/app_updater.rb +14 -2
- data/lib/rails/application/bootstrap.rb +23 -4
- data/lib/rails/application/configuration.rb +190 -69
- data/lib/rails/application/default_middleware_stack.rb +8 -2
- data/lib/rails/application/dummy_config.rb +19 -0
- data/lib/rails/application/finisher.rb +43 -33
- data/lib/rails/application.rb +141 -33
- data/lib/rails/backtrace_cleaner.rb +5 -3
- data/lib/rails/cli.rb +5 -2
- data/lib/rails/command/actions.rb +10 -12
- data/lib/rails/command/base.rb +55 -53
- data/lib/rails/command/environment_argument.rb +32 -16
- data/lib/rails/command/helpers/editor.rb +17 -12
- data/lib/rails/command.rb +84 -33
- data/lib/rails/commands/about/about_command.rb +14 -0
- data/lib/rails/commands/application/application_command.rb +2 -0
- data/lib/rails/commands/console/console_command.rb +14 -14
- data/lib/rails/commands/credentials/USAGE +53 -55
- data/lib/rails/commands/credentials/credentials_command/diffing.rb +5 -3
- data/lib/rails/commands/credentials/credentials_command.rb +64 -70
- data/lib/rails/commands/db/system/change/change_command.rb +2 -1
- data/lib/rails/commands/dbconsole/dbconsole_command.rb +25 -115
- data/lib/rails/commands/destroy/destroy_command.rb +3 -2
- data/lib/rails/commands/dev/dev_command.rb +1 -6
- data/lib/rails/commands/encrypted/USAGE +15 -20
- data/lib/rails/commands/encrypted/encrypted_command.rb +46 -35
- data/lib/rails/commands/gem_help/USAGE +16 -0
- data/lib/rails/commands/gem_help/gem_help_command.rb +13 -0
- data/lib/rails/commands/generate/generate_command.rb +2 -2
- data/lib/rails/commands/help/USAGE +13 -13
- data/lib/rails/commands/help/help_command.rb +21 -2
- data/lib/rails/commands/initializers/initializers_command.rb +1 -4
- data/lib/rails/commands/middleware/middleware_command.rb +17 -0
- data/lib/rails/commands/new/new_command.rb +2 -0
- data/lib/rails/commands/notes/notes_command.rb +2 -1
- data/lib/rails/commands/plugin/plugin_command.rb +2 -0
- data/lib/rails/commands/rake/rake_command.rb +25 -22
- data/lib/rails/commands/restart/restart_command.rb +14 -0
- data/lib/rails/commands/routes/routes_command.rb +13 -1
- data/lib/rails/commands/runner/USAGE +14 -12
- data/lib/rails/commands/runner/runner_command.rb +32 -20
- data/lib/rails/commands/secret/secret_command.rb +13 -0
- data/lib/rails/commands/secrets/USAGE +44 -49
- data/lib/rails/commands/secrets/secrets_command.rb +20 -38
- data/lib/rails/commands/server/server_command.rb +33 -32
- data/lib/rails/commands/test/USAGE +14 -0
- data/lib/rails/commands/test/test_command.rb +56 -14
- data/lib/rails/commands/unused_routes/unused_routes_command.rb +75 -0
- data/lib/rails/commands/version/version_command.rb +1 -0
- data/lib/rails/configuration.rb +5 -5
- data/lib/rails/console/app.rb +1 -4
- data/lib/rails/deprecator.rb +7 -0
- data/lib/rails/engine/configuration.rb +50 -6
- data/lib/rails/engine.rb +49 -21
- data/lib/rails/gem_version.rb +4 -4
- data/lib/rails/generators/actions.rb +6 -15
- data/lib/rails/generators/active_model.rb +28 -14
- data/lib/rails/generators/app_base.rb +355 -82
- data/lib/rails/generators/app_name.rb +3 -14
- data/lib/rails/generators/base.rb +17 -9
- data/lib/rails/generators/database.rb +40 -2
- data/lib/rails/generators/erb/mailer/templates/layout.html.erb.tt +1 -1
- data/lib/rails/generators/generated_attribute.rb +12 -0
- data/lib/rails/generators/migration.rb +4 -5
- data/lib/rails/generators/model_helpers.rb +2 -1
- data/lib/rails/generators/rails/app/USAGE +22 -6
- data/lib/rails/generators/rails/app/app_generator.rb +85 -64
- data/lib/rails/generators/rails/app/templates/Dockerfile.tt +103 -0
- data/lib/rails/generators/rails/app/templates/Gemfile.tt +9 -11
- data/lib/rails/generators/rails/app/templates/app/views/layouts/mailer.html.erb.tt +1 -1
- data/lib/rails/generators/rails/app/templates/bin/setup.tt +10 -1
- data/lib/rails/generators/rails/app/templates/config/application.rb.tt +6 -17
- data/lib/rails/generators/rails/app/templates/config/databases/jdbcpostgresql.yml.tt +4 -4
- data/lib/rails/generators/rails/app/templates/config/databases/jdbcsqlite3.yml.tt +3 -3
- data/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml.tt +4 -6
- data/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml.tt +3 -3
- data/lib/rails/generators/rails/app/templates/config/databases/trilogy.yml.tt +59 -0
- data/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt +12 -2
- data/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt +32 -28
- data/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt +13 -9
- data/lib/rails/generators/rails/app/templates/config/initializers/assets.rb.tt +2 -0
- data/lib/rails/generators/rails/app/templates/config/initializers/content_security_policy.rb.tt +2 -2
- data/lib/rails/generators/rails/app/templates/config/initializers/cors.rb.tt +1 -1
- data/lib/rails/generators/rails/app/templates/config/initializers/filter_parameter_logging.rb.tt +3 -3
- data/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_7_1.rb.tt +280 -0
- data/lib/rails/generators/rails/app/templates/config/initializers/permissions_policy.rb.tt +11 -9
- data/lib/rails/generators/rails/app/templates/config/locales/en.yml +11 -13
- data/lib/rails/generators/rails/app/templates/config/puma.rb.tt +21 -20
- data/lib/rails/generators/rails/app/templates/config/routes.rb.tt +5 -1
- data/lib/rails/generators/rails/app/templates/db/seeds.rb.tt +6 -4
- data/lib/rails/generators/rails/app/templates/docker-entrypoint.tt +10 -0
- data/lib/rails/generators/rails/app/templates/dockerignore.tt +43 -0
- data/lib/rails/generators/rails/app/templates/gitignore.tt +4 -8
- data/lib/rails/generators/rails/app/templates/node-version.tt +1 -0
- data/lib/rails/generators/rails/app/templates/test/channels/application_cable/connection_test.rb.tt +10 -8
- data/lib/rails/generators/rails/app/templates/test/test_helper.rb.tt +9 -7
- data/lib/rails/generators/rails/application_record/application_record_generator.rb +4 -0
- data/lib/rails/generators/rails/benchmark/benchmark_generator.rb +2 -1
- data/lib/rails/generators/rails/controller/USAGE +12 -4
- data/lib/rails/generators/rails/controller/controller_generator.rb +5 -0
- data/lib/rails/generators/rails/controller/templates/controller.rb.tt +1 -1
- data/lib/rails/generators/rails/credentials/credentials_generator.rb +29 -24
- data/lib/rails/generators/rails/credentials/templates/credentials.yml.tt +8 -0
- data/lib/rails/generators/rails/db/system/change/change_generator.rb +30 -0
- data/lib/rails/generators/rails/encryption_key_file/encryption_key_file_generator.rb +1 -2
- data/lib/rails/generators/rails/migration/USAGE +21 -11
- data/lib/rails/generators/rails/model/model_generator.rb +4 -0
- data/lib/rails/generators/rails/plugin/USAGE +17 -6
- data/lib/rails/generators/rails/plugin/plugin_generator.rb +5 -15
- data/lib/rails/generators/rails/plugin/templates/Gemfile.tt +2 -2
- data/lib/rails/generators/rails/plugin/templates/MIT-LICENSE.tt +1 -1
- data/lib/rails/generators/rails/plugin/templates/bin/rails.tt +1 -17
- data/lib/rails/generators/rails/plugin/templates/gitignore.tt +0 -2
- data/lib/rails/generators/rails/plugin/templates/test/test_helper.rb.tt +4 -4
- data/lib/rails/generators/rails/resource/resource_generator.rb +6 -0
- data/lib/rails/generators/rails/scaffold/scaffold_generator.rb +2 -1
- data/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb +1 -1
- data/lib/rails/generators/test_case.rb +2 -2
- data/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb +1 -1
- data/lib/rails/generators/testing/{behaviour.rb → behavior.rb} +4 -1
- data/lib/rails/generators.rb +6 -14
- data/lib/rails/health_controller.rb +55 -0
- data/lib/rails/info.rb +1 -1
- data/lib/rails/info_controller.rb +33 -11
- data/lib/rails/mailers_controller.rb +15 -5
- data/lib/rails/paths.rb +13 -10
- data/lib/rails/rack/logger.rb +15 -12
- data/lib/rails/rackup/server.rb +15 -0
- data/lib/rails/railtie/configuration.rb +14 -1
- data/lib/rails/railtie.rb +31 -31
- data/lib/rails/ruby_version_check.rb +2 -0
- data/lib/rails/source_annotation_extractor.rb +67 -18
- data/lib/rails/tasks/engine.rake +8 -8
- data/lib/rails/tasks/framework.rake +4 -10
- data/lib/rails/tasks/log.rake +1 -1
- data/lib/rails/tasks/misc.rake +3 -14
- data/lib/rails/tasks/statistics.rake +5 -4
- data/lib/rails/tasks/tmp.rake +5 -5
- data/lib/rails/tasks/zeitwerk.rake +15 -35
- data/lib/rails/tasks.rb +0 -2
- data/lib/rails/templates/rails/mailers/email.html.erb +32 -0
- data/lib/rails/templates/rails/mailers/index.html.erb +14 -7
- data/lib/rails/templates/rails/mailers/mailer.html.erb +11 -5
- data/lib/rails/templates/rails/welcome/index.html.erb +1 -0
- data/lib/rails/test_help.rb +9 -14
- data/lib/rails/test_unit/line_filtering.rb +1 -1
- data/lib/rails/test_unit/reporter.rb +6 -2
- data/lib/rails/test_unit/runner.rb +36 -18
- data/lib/rails/test_unit/test_parser.rb +88 -0
- data/lib/rails/test_unit/testing.rake +13 -33
- data/lib/rails/testing/maintain_test_schema.rb +16 -0
- data/lib/rails/version.rb +1 -1
- data/lib/rails/zeitwerk_checker.rb +15 -0
- data/lib/rails.rb +15 -15
- metadata +64 -27
- data/RDOC_MAIN.rdoc +0 -97
- data/lib/rails/application/dummy_erb_compiler.rb +0 -18
- data/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_7_0.rb.tt +0 -143
- data/lib/rails/generators/rails/model/USAGE +0 -113
- data/lib/rails/tasks/middleware.rake +0 -9
- data/lib/rails/tasks/restart.rake +0 -9
@@ -4,6 +4,7 @@ require "fileutils"
|
|
4
4
|
require "digest/md5"
|
5
5
|
require "rails/version" unless defined?(Rails::VERSION)
|
6
6
|
require "open-uri"
|
7
|
+
require "tsort"
|
7
8
|
require "uri"
|
8
9
|
require "rails/generators"
|
9
10
|
require "active_support/core_ext/array/extract_options"
|
@@ -14,6 +15,9 @@ module Rails
|
|
14
15
|
include Database
|
15
16
|
include AppName
|
16
17
|
|
18
|
+
NODE_LTS_VERSION = "18.15.0"
|
19
|
+
BUN_VERSION = "1.0.1"
|
20
|
+
|
17
21
|
attr_accessor :rails_template
|
18
22
|
add_shebang_option!
|
19
23
|
|
@@ -24,82 +28,95 @@ module Rails
|
|
24
28
|
end
|
25
29
|
|
26
30
|
def self.add_shared_options_for(name)
|
31
|
+
class_option :name, type: :string, aliases: "-n",
|
32
|
+
desc: "Name of the app"
|
33
|
+
|
27
34
|
class_option :template, type: :string, aliases: "-m",
|
28
35
|
desc: "Path to some #{name} template (can be a filesystem path or URL)"
|
29
36
|
|
30
37
|
class_option :database, type: :string, aliases: "-d", default: "sqlite3",
|
31
38
|
desc: "Preconfigure for selected database (options: #{DATABASES.join('/')})"
|
32
39
|
|
33
|
-
class_option :skip_git, type: :boolean, aliases: "-G", default:
|
34
|
-
desc: "Skip .gitignore
|
40
|
+
class_option :skip_git, type: :boolean, aliases: "-G", default: nil,
|
41
|
+
desc: "Skip git init, .gitignore and .gitattributes"
|
35
42
|
|
36
|
-
class_option :
|
43
|
+
class_option :skip_docker, type: :boolean, default: nil,
|
44
|
+
desc: "Skip Dockerfile, .dockerignore and bin/docker-entrypoint"
|
45
|
+
|
46
|
+
class_option :skip_keeps, type: :boolean, default: nil,
|
37
47
|
desc: "Skip source control .keep files"
|
38
48
|
|
39
49
|
class_option :skip_action_mailer, type: :boolean, aliases: "-M",
|
40
|
-
default:
|
50
|
+
default: nil,
|
41
51
|
desc: "Skip Action Mailer files"
|
42
52
|
|
43
|
-
class_option :skip_action_mailbox, type: :boolean, default:
|
53
|
+
class_option :skip_action_mailbox, type: :boolean, default: nil,
|
44
54
|
desc: "Skip Action Mailbox gem"
|
45
55
|
|
46
|
-
class_option :skip_action_text, type: :boolean, default:
|
56
|
+
class_option :skip_action_text, type: :boolean, default: nil,
|
47
57
|
desc: "Skip Action Text gem"
|
48
58
|
|
49
|
-
class_option :skip_active_record, type: :boolean, aliases: "-O", default:
|
59
|
+
class_option :skip_active_record, type: :boolean, aliases: "-O", default: nil,
|
50
60
|
desc: "Skip Active Record files"
|
51
61
|
|
52
|
-
class_option :skip_active_job, type: :boolean, default:
|
62
|
+
class_option :skip_active_job, type: :boolean, default: nil,
|
53
63
|
desc: "Skip Active Job"
|
54
64
|
|
55
|
-
class_option :skip_active_storage, type: :boolean, default:
|
65
|
+
class_option :skip_active_storage, type: :boolean, default: nil,
|
56
66
|
desc: "Skip Active Storage files"
|
57
67
|
|
58
|
-
class_option :skip_action_cable, type: :boolean, aliases: "-C", default:
|
68
|
+
class_option :skip_action_cable, type: :boolean, aliases: "-C", default: nil,
|
59
69
|
desc: "Skip Action Cable files"
|
60
70
|
|
61
|
-
class_option :skip_asset_pipeline, type: :boolean, aliases: "-A", default:
|
71
|
+
class_option :skip_asset_pipeline, type: :boolean, aliases: "-A", default: nil
|
62
72
|
|
63
73
|
class_option :asset_pipeline, type: :string, aliases: "-a", default: "sprockets",
|
64
74
|
desc: "Choose your asset pipeline [options: sprockets (default), propshaft]"
|
65
75
|
|
66
|
-
class_option :skip_javascript, type: :boolean, aliases: "-J", default: name == "plugin",
|
76
|
+
class_option :skip_javascript, type: :boolean, aliases: ["-J", "--skip-js"], default: (true if name == "plugin"),
|
67
77
|
desc: "Skip JavaScript files"
|
68
78
|
|
69
|
-
class_option :skip_hotwire, type: :boolean, default:
|
79
|
+
class_option :skip_hotwire, type: :boolean, default: nil,
|
70
80
|
desc: "Skip Hotwire integration"
|
71
81
|
|
72
|
-
class_option :skip_jbuilder, type: :boolean, default:
|
82
|
+
class_option :skip_jbuilder, type: :boolean, default: nil,
|
73
83
|
desc: "Skip jbuilder gem"
|
74
84
|
|
75
|
-
class_option :skip_test, type: :boolean, aliases: "-T", default:
|
85
|
+
class_option :skip_test, type: :boolean, aliases: "-T", default: nil,
|
76
86
|
desc: "Skip test files"
|
77
87
|
|
78
|
-
class_option :skip_system_test, type: :boolean, default:
|
88
|
+
class_option :skip_system_test, type: :boolean, default: nil,
|
79
89
|
desc: "Skip system test files"
|
80
90
|
|
81
|
-
class_option :skip_bootsnap, type: :boolean, default:
|
91
|
+
class_option :skip_bootsnap, type: :boolean, default: nil,
|
82
92
|
desc: "Skip bootsnap gem"
|
83
93
|
|
84
|
-
class_option :
|
94
|
+
class_option :skip_dev_gems, type: :boolean, default: nil,
|
95
|
+
desc: "Skip development gems (e.g., web-console)"
|
96
|
+
|
97
|
+
class_option :dev, type: :boolean, default: nil,
|
85
98
|
desc: "Set up the #{name} with Gemfile pointing to your Rails checkout"
|
86
99
|
|
87
|
-
class_option :edge, type: :boolean, default:
|
88
|
-
desc: "Set up the #{name} with Gemfile pointing to Rails repository"
|
100
|
+
class_option :edge, type: :boolean, default: nil,
|
101
|
+
desc: "Set up the #{name} with a Gemfile pointing to the #{edge_branch} branch on the Rails repository"
|
89
102
|
|
90
|
-
class_option :main, type: :boolean, default:
|
103
|
+
class_option :main, type: :boolean, default: nil, aliases: "--master",
|
91
104
|
desc: "Set up the #{name} with Gemfile pointing to Rails repository main branch"
|
92
105
|
|
93
106
|
class_option :rc, type: :string, default: nil,
|
94
107
|
desc: "Path to file containing extra configuration options for rails command"
|
95
108
|
|
96
|
-
class_option :no_rc, type: :boolean, default:
|
109
|
+
class_option :no_rc, type: :boolean, default: nil,
|
97
110
|
desc: "Skip loading of extra configuration options from .railsrc file"
|
98
111
|
|
99
112
|
class_option :help, type: :boolean, aliases: "-h", group: :rails,
|
100
113
|
desc: "Show this help message and quit"
|
101
114
|
end
|
102
115
|
|
116
|
+
def self.edge_branch # :nodoc:
|
117
|
+
Rails.gem_version.prerelease? ? "main" : [*Rails.gem_version.segments.first(2), "stable"].join("-")
|
118
|
+
end
|
119
|
+
|
103
120
|
def initialize(positional_argv, option_argv, *)
|
104
121
|
@argv = [*positional_argv, *option_argv]
|
105
122
|
@gem_filter = lambda { |gem| true }
|
@@ -117,7 +134,6 @@ module Rails
|
|
117
134
|
hotwire_gemfile_entry,
|
118
135
|
css_gemfile_entry,
|
119
136
|
jbuilder_gemfile_entry,
|
120
|
-
psych_gemfile_entry,
|
121
137
|
cable_gemfile_entry,
|
122
138
|
].flatten.compact.select(&@gem_filter)
|
123
139
|
end
|
@@ -134,6 +150,89 @@ module Rails
|
|
134
150
|
builder.public_send(meth, *args) if builder.respond_to?(meth)
|
135
151
|
end
|
136
152
|
|
153
|
+
def deduce_implied_options(options, option_reasons, meta_options)
|
154
|
+
active = options.transform_values { |value| [] if value }.compact
|
155
|
+
irrevocable = (active.keys - meta_options).to_set
|
156
|
+
|
157
|
+
deduction_order = TSort.tsort(
|
158
|
+
->(&block) { option_reasons.each_key(&block) },
|
159
|
+
->(key, &block) { option_reasons[key]&.each(&block) }
|
160
|
+
)
|
161
|
+
|
162
|
+
deduction_order.each do |name|
|
163
|
+
active_reasons = option_reasons[name].to_a.select(&active)
|
164
|
+
active[name] ||= active_reasons if active_reasons.any?
|
165
|
+
irrevocable << name if active_reasons.any?(irrevocable)
|
166
|
+
end
|
167
|
+
|
168
|
+
revoked = options.select { |name, value| value == false }.keys.to_set - irrevocable
|
169
|
+
deduction_order.reverse_each do |name|
|
170
|
+
revoked += option_reasons[name].to_a if revoked.include?(name)
|
171
|
+
end
|
172
|
+
revoked -= meta_options
|
173
|
+
|
174
|
+
active.filter_map do |name, reasons|
|
175
|
+
unless revoked.include?(name) || reasons.all?(revoked)
|
176
|
+
[name, reasons - revoked.to_a]
|
177
|
+
end
|
178
|
+
end.to_h
|
179
|
+
end
|
180
|
+
|
181
|
+
OPTION_IMPLICATIONS = { # :nodoc:
|
182
|
+
skip_active_job: [:skip_action_mailer, :skip_active_storage],
|
183
|
+
skip_active_record: [:skip_active_storage],
|
184
|
+
skip_active_storage: [:skip_action_mailbox, :skip_action_text],
|
185
|
+
skip_javascript: [:skip_hotwire],
|
186
|
+
}
|
187
|
+
|
188
|
+
# ==== Options
|
189
|
+
#
|
190
|
+
# [+:meta_options+]
|
191
|
+
# A list of generator options which only serve to trigger other options.
|
192
|
+
# These options should have no other effects, and will be treated
|
193
|
+
# transparently when revoking other options.
|
194
|
+
#
|
195
|
+
# For example: --minimal implies both --skip-active-job and
|
196
|
+
# --skip-active-storage. Also, --skip-active-job by itself implies
|
197
|
+
# --skip-active-storage. If --skip-active-job is explicitly
|
198
|
+
# specified, --no-skip-active-storage should raise an error. But, if
|
199
|
+
# only --minimal is specified, --no-skip-active-storage should "undo"
|
200
|
+
# the implied --skip-active-job. This can be accomplished by passing
|
201
|
+
# <tt>meta_options: [:minimal]</tt>.
|
202
|
+
#
|
203
|
+
# In contrast, --api is not a meta option because it does other things
|
204
|
+
# besides implying options such as --skip-asset-pipeline. (And so --api
|
205
|
+
# with --no-skip-asset-pipeline should raise an error.)
|
206
|
+
def imply_options(option_implications = OPTION_IMPLICATIONS, meta_options: [])
|
207
|
+
option_reasons = {}
|
208
|
+
option_implications.each do |reason, implications|
|
209
|
+
implications.each do |implication|
|
210
|
+
(option_reasons[implication.to_s] ||= []) << reason.to_s
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
@implied_options = deduce_implied_options(options, option_reasons, meta_options.map(&:to_s))
|
215
|
+
@implied_options_conflicts = @implied_options.keys.select { |name| options[name] == false }
|
216
|
+
self.options = options.merge(@implied_options.transform_values { true }).freeze
|
217
|
+
end
|
218
|
+
|
219
|
+
def report_implied_options
|
220
|
+
return if @implied_options.blank?
|
221
|
+
|
222
|
+
say "Based on the specified options, the following options will also be activated:"
|
223
|
+
say ""
|
224
|
+
@implied_options.each do |name, reasons|
|
225
|
+
due_to = reasons.map { |reason| "--#{reason.dasherize}" }.join(", ")
|
226
|
+
say " --#{name.dasherize} [due to #{due_to}]"
|
227
|
+
if @implied_options_conflicts.include?(name)
|
228
|
+
say " ERROR: Conflicts with --no-#{name.dasherize}", :red
|
229
|
+
end
|
230
|
+
end
|
231
|
+
say ""
|
232
|
+
|
233
|
+
raise "Cannot proceed due to conflicting options" if @implied_options_conflicts.any?
|
234
|
+
end
|
235
|
+
|
137
236
|
def create_root # :doc:
|
138
237
|
valid_const?
|
139
238
|
|
@@ -149,15 +248,13 @@ module Rails
|
|
149
248
|
|
150
249
|
def set_default_accessors! # :doc:
|
151
250
|
self.destination_root = File.expand_path(app_path, destination_root)
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
options[:template]
|
160
|
-
end
|
251
|
+
|
252
|
+
if options[:template].is_a?(String) && !options[:template].match?(/^https?:\/\//)
|
253
|
+
interpolated = options[:template].gsub(/\$(\w+)|\$\{\g<1>\}|%\g<1>%/) { |m| ENV[$1] || m }
|
254
|
+
self.rails_template = File.expand_path(interpolated)
|
255
|
+
else
|
256
|
+
self.rails_template = options[:template]
|
257
|
+
end
|
161
258
|
end
|
162
259
|
|
163
260
|
def database_gemfile_entry # :doc:
|
@@ -169,11 +266,11 @@ module Rails
|
|
169
266
|
end
|
170
267
|
|
171
268
|
def web_server_gemfile_entry # :doc:
|
172
|
-
GemfileEntry.new "puma", "
|
269
|
+
GemfileEntry.new "puma", ">= 5.0", "Use the Puma web server [https://github.com/puma/puma]"
|
173
270
|
end
|
174
271
|
|
175
272
|
def asset_pipeline_gemfile_entry
|
176
|
-
return if
|
273
|
+
return if skip_asset_pipeline?
|
177
274
|
|
178
275
|
if options[:asset_pipeline] == "sprockets"
|
179
276
|
GemfileEntry.floats "sprockets-rails",
|
@@ -183,19 +280,40 @@ module Rails
|
|
183
280
|
end
|
184
281
|
end
|
185
282
|
|
283
|
+
def required_railties
|
284
|
+
@required_railties ||= {
|
285
|
+
"active_model/railtie" => true,
|
286
|
+
"active_job/railtie" => !options[:skip_active_job],
|
287
|
+
"active_record/railtie" => !options[:skip_active_record],
|
288
|
+
"active_storage/engine" => !options[:skip_active_storage],
|
289
|
+
"action_controller/railtie" => true,
|
290
|
+
"action_mailer/railtie" => !options[:skip_action_mailer],
|
291
|
+
"action_mailbox/engine" => !options[:skip_action_mailbox],
|
292
|
+
"action_text/engine" => !options[:skip_action_text],
|
293
|
+
"action_view/railtie" => true,
|
294
|
+
"action_cable/engine" => !options[:skip_action_cable],
|
295
|
+
"rails/test_unit/railtie" => !options[:skip_test],
|
296
|
+
}
|
297
|
+
end
|
298
|
+
|
186
299
|
def include_all_railties? # :doc:
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
300
|
+
required_railties.values.all?
|
301
|
+
end
|
302
|
+
|
303
|
+
def rails_require_statement
|
304
|
+
if include_all_railties?
|
305
|
+
%(require "rails/all")
|
306
|
+
else
|
307
|
+
require_statements = required_railties.map do |railtie, required|
|
308
|
+
%(#{"# " if !required}require "#{railtie}")
|
309
|
+
end
|
310
|
+
|
311
|
+
<<~RUBY.strip
|
312
|
+
require "rails"
|
313
|
+
# Pick the frameworks you want:
|
314
|
+
#{require_statements.join("\n")}
|
315
|
+
RUBY
|
316
|
+
end
|
199
317
|
end
|
200
318
|
|
201
319
|
def comment_if(value) # :doc:
|
@@ -216,35 +334,43 @@ module Rails
|
|
216
334
|
end
|
217
335
|
|
218
336
|
def sqlite3? # :doc:
|
219
|
-
!
|
337
|
+
!skip_active_record? && options[:database] == "sqlite3"
|
338
|
+
end
|
339
|
+
|
340
|
+
def skip_active_record? # :doc:
|
341
|
+
options[:skip_active_record]
|
220
342
|
end
|
221
343
|
|
222
344
|
def skip_active_storage? # :doc:
|
223
|
-
options[:skip_active_storage]
|
345
|
+
options[:skip_active_storage]
|
346
|
+
end
|
347
|
+
|
348
|
+
def skip_action_cable? # :doc:
|
349
|
+
options[:skip_action_cable]
|
224
350
|
end
|
225
351
|
|
226
352
|
def skip_action_mailer? # :doc:
|
227
|
-
options[:skip_action_mailer]
|
353
|
+
options[:skip_action_mailer]
|
228
354
|
end
|
229
355
|
|
230
356
|
def skip_action_mailbox? # :doc:
|
231
|
-
options[:skip_action_mailbox]
|
357
|
+
options[:skip_action_mailbox]
|
232
358
|
end
|
233
359
|
|
234
360
|
def skip_action_text? # :doc:
|
235
|
-
options[:skip_action_text]
|
361
|
+
options[:skip_action_text]
|
236
362
|
end
|
237
363
|
|
238
|
-
def
|
239
|
-
options[:
|
364
|
+
def skip_asset_pipeline? # :doc:
|
365
|
+
options[:skip_asset_pipeline]
|
240
366
|
end
|
241
367
|
|
242
368
|
def skip_sprockets?
|
243
|
-
|
369
|
+
skip_asset_pipeline? || options[:asset_pipeline] != "sprockets"
|
244
370
|
end
|
245
371
|
|
246
372
|
def skip_propshaft?
|
247
|
-
|
373
|
+
skip_asset_pipeline? || options[:asset_pipeline] != "propshaft"
|
248
374
|
end
|
249
375
|
|
250
376
|
|
@@ -284,6 +410,10 @@ module Rails
|
|
284
410
|
end
|
285
411
|
end
|
286
412
|
|
413
|
+
def gem_ruby_version
|
414
|
+
Gem::Version.new(Gem::VERSION) >= Gem::Version.new("3.3.13") ? Gem.ruby_version : RUBY_VERSION
|
415
|
+
end
|
416
|
+
|
287
417
|
def rails_prerelease?
|
288
418
|
options.dev? || options.edge? || options.main?
|
289
419
|
end
|
@@ -292,7 +422,6 @@ module Rails
|
|
292
422
|
if options.dev?
|
293
423
|
GemfileEntry.path("rails", Rails::Generators::RAILS_DEV_PATH, "Use local checkout of Rails")
|
294
424
|
elsif options.edge?
|
295
|
-
edge_branch = Rails.gem_version.prerelease? ? "main" : [*Rails.gem_version.segments.first(2), "stable"].join("-")
|
296
425
|
GemfileEntry.github("rails", "rails/rails", edge_branch, "Use specific branch of Rails")
|
297
426
|
elsif options.main?
|
298
427
|
GemfileEntry.github("rails", "rails/rails", "main", "Use main development branch of Rails")
|
@@ -323,7 +452,7 @@ module Rails
|
|
323
452
|
def javascript_gemfile_entry
|
324
453
|
return if options[:skip_javascript]
|
325
454
|
|
326
|
-
if
|
455
|
+
if options[:javascript] == "importmap"
|
327
456
|
GemfileEntry.floats "importmap-rails", "Use JavaScript with ESM import maps [https://github.com/rails/importmap-rails]"
|
328
457
|
else
|
329
458
|
GemfileEntry.floats "jsbundling-rails", "Bundle and transpile JavaScript [https://github.com/rails/jsbundling-rails]"
|
@@ -331,7 +460,7 @@ module Rails
|
|
331
460
|
end
|
332
461
|
|
333
462
|
def hotwire_gemfile_entry
|
334
|
-
return if options[:
|
463
|
+
return if options[:skip_hotwire]
|
335
464
|
|
336
465
|
turbo_rails_entry =
|
337
466
|
GemfileEntry.floats "turbo-rails", "Hotwire's SPA-like page accelerator [https://turbo.hotwired.dev]"
|
@@ -342,43 +471,141 @@ module Rails
|
|
342
471
|
[ turbo_rails_entry, stimulus_rails_entry ]
|
343
472
|
end
|
344
473
|
|
474
|
+
def using_js_runtime?
|
475
|
+
(options[:javascript] && !%w[importmap].include?(options[:javascript])) ||
|
476
|
+
(options[:css] && !%w[tailwind sass].include?(options[:css]))
|
477
|
+
end
|
478
|
+
|
345
479
|
def using_node?
|
346
|
-
|
480
|
+
using_js_runtime? && !%w[bun].include?(options[:javascript])
|
347
481
|
end
|
348
482
|
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
483
|
+
def using_bun?
|
484
|
+
using_js_runtime? && %w[bun].include?(options[:javascript])
|
485
|
+
end
|
486
|
+
|
487
|
+
def node_version
|
488
|
+
if using_node?
|
489
|
+
ENV.fetch("NODE_VERSION") do
|
490
|
+
`node --version`[/\d+\.\d+\.\d+/]
|
491
|
+
rescue
|
492
|
+
NODE_LTS_VERSION
|
493
|
+
end
|
356
494
|
end
|
357
495
|
end
|
358
496
|
|
497
|
+
def dockerfile_yarn_version
|
498
|
+
using_node? and `yarn --version`[/\d+\.\d+\.\d+/]
|
499
|
+
rescue
|
500
|
+
"latest"
|
501
|
+
end
|
502
|
+
|
503
|
+
def dockerfile_bun_version
|
504
|
+
using_bun? and `bun --version`[/\d+\.\d+\.\d+/]
|
505
|
+
rescue
|
506
|
+
BUN_VERSION
|
507
|
+
end
|
508
|
+
|
509
|
+
def dockerfile_binfile_fixups
|
510
|
+
# binfiles may have OS specific paths to ruby. Normalize them.
|
511
|
+
shebangs = Dir["bin/*"].map { |file| IO.read(file).lines.first }.join
|
512
|
+
rubies = shebangs.scan(%r{#!/usr/bin/env (ruby.*)}).flatten.uniq
|
513
|
+
|
514
|
+
binfixups = (rubies - %w(ruby)).map do |ruby|
|
515
|
+
"sed -i 's/#{Regexp.quote(ruby)}$/ruby/' bin/*"
|
516
|
+
end
|
517
|
+
|
518
|
+
# Windows line endings will cause scripts to fail. If any
|
519
|
+
# or found OR this generation is run on a windows platform
|
520
|
+
# and there are other binfixups required, then convert
|
521
|
+
# line endings. This avoids adding unnecessary fixups if
|
522
|
+
# none are required, but prepares for the need to do the
|
523
|
+
# fix line endings if other fixups are required.
|
524
|
+
has_cr = Dir["bin/*"].any? { |file| IO.read(file).include? "\r" }
|
525
|
+
if has_cr || (Gem.win_platform? && !binfixups.empty?)
|
526
|
+
binfixups.unshift 'sed -i "s/\r$//g" bin/*'
|
527
|
+
end
|
528
|
+
|
529
|
+
# Windows file systems may not have the concept of executable.
|
530
|
+
# In such cases, fix up during the build.
|
531
|
+
unless Dir["bin/*"].all? { |file| File.executable? file }
|
532
|
+
binfixups.unshift "chmod +x bin/*"
|
533
|
+
end
|
534
|
+
|
535
|
+
binfixups
|
536
|
+
end
|
537
|
+
|
538
|
+
def dockerfile_build_packages
|
539
|
+
# start with the essentials
|
540
|
+
packages = %w(build-essential git pkg-config)
|
541
|
+
|
542
|
+
# add database support
|
543
|
+
packages << build_package_for_database unless skip_active_record?
|
544
|
+
|
545
|
+
# ActiveStorage preview support
|
546
|
+
packages << "libvips" unless skip_active_storage?
|
547
|
+
|
548
|
+
packages << "curl" if using_js_runtime?
|
549
|
+
|
550
|
+
packages << "unzip" if using_bun?
|
551
|
+
|
552
|
+
# node support, including support for building native modules
|
553
|
+
if using_node?
|
554
|
+
packages << "node-gyp" # pkg-config already listed above
|
555
|
+
|
556
|
+
# module build process depends on Python, and debian changed
|
557
|
+
# how python is installed with the bullseye release. Below
|
558
|
+
# is based on debian release included with the Ruby images on
|
559
|
+
# Dockerhub.
|
560
|
+
case Gem.ruby_version.to_s
|
561
|
+
when /^2\.7/
|
562
|
+
bullseye = Gem.ruby_version >= Gem::Version.new("2.7.4")
|
563
|
+
when /^3\.0/
|
564
|
+
bullseye = Gem.ruby_version >= Gem::Version.new("3.0.2")
|
565
|
+
else
|
566
|
+
bullseye = true
|
567
|
+
end
|
568
|
+
|
569
|
+
if bullseye
|
570
|
+
packages << "python-is-python3"
|
571
|
+
else
|
572
|
+
packages << "python"
|
573
|
+
end
|
574
|
+
end
|
575
|
+
|
576
|
+
packages.compact.sort
|
577
|
+
end
|
578
|
+
|
579
|
+
def dockerfile_deploy_packages
|
580
|
+
# Add curl to work with the default healthcheck strategy in Kamal
|
581
|
+
packages = ["curl"]
|
582
|
+
|
583
|
+
# ActiveRecord databases
|
584
|
+
packages << deploy_package_for_database unless skip_active_record?
|
585
|
+
|
586
|
+
# ActiveStorage preview support
|
587
|
+
packages << "libvips" unless skip_active_storage?
|
588
|
+
|
589
|
+
packages.compact.sort
|
590
|
+
end
|
591
|
+
|
359
592
|
def css_gemfile_entry
|
360
593
|
return unless options[:css]
|
361
594
|
|
362
|
-
if !
|
595
|
+
if !using_js_runtime? && options[:css] == "tailwind"
|
363
596
|
GemfileEntry.floats "tailwindcss-rails", "Use Tailwind CSS [https://github.com/rails/tailwindcss-rails]"
|
597
|
+
elsif !using_js_runtime? && options[:css] == "sass"
|
598
|
+
GemfileEntry.floats "dartsass-rails", "Use Dart SASS [https://github.com/rails/dartsass-rails]"
|
364
599
|
else
|
365
600
|
GemfileEntry.floats "cssbundling-rails", "Bundle and process CSS [https://github.com/rails/cssbundling-rails]"
|
366
601
|
end
|
367
602
|
end
|
368
603
|
|
369
|
-
def psych_gemfile_entry
|
370
|
-
return unless defined?(Rubinius)
|
371
|
-
|
372
|
-
comment = "Use Psych as the YAML engine, instead of Syck, so serialized " \
|
373
|
-
"data can be read safely from different rubies (see http://git.io/uuLVag)"
|
374
|
-
GemfileEntry.new("psych", "~> 2.0", comment, platforms: :rbx)
|
375
|
-
end
|
376
|
-
|
377
604
|
def cable_gemfile_entry
|
378
605
|
return if options[:skip_action_cable]
|
379
606
|
|
380
607
|
comment = "Use Redis adapter to run Action Cable in production"
|
381
|
-
GemfileEntry.new("redis", "
|
608
|
+
GemfileEntry.new("redis", ">= 4.0.1", comment, {}, true)
|
382
609
|
end
|
383
610
|
|
384
611
|
def bundle_command(command, env = {})
|
@@ -411,6 +638,10 @@ module Rails
|
|
411
638
|
!(options[:skip_bundle] || options[:pretend])
|
412
639
|
end
|
413
640
|
|
641
|
+
def bundler_windows_platforms
|
642
|
+
Gem.rubygems_version >= Gem::Version.new("3.3.22") ? "windows" : "mswin mswin64 mingw x64_mingw"
|
643
|
+
end
|
644
|
+
|
414
645
|
def depends_on_system_test?
|
415
646
|
!(options[:skip_system_test] || options[:skip_test] || options[:api])
|
416
647
|
end
|
@@ -431,7 +662,8 @@ module Rails
|
|
431
662
|
|
432
663
|
run_bundle
|
433
664
|
|
434
|
-
@argv
|
665
|
+
@argv.delete_at(@argv.index(app_path))
|
666
|
+
@argv.unshift(destination_root)
|
435
667
|
require "shellwords"
|
436
668
|
bundle_command("exec rails #{self_command} #{Shellwords.join(@argv)}")
|
437
669
|
exit
|
@@ -448,14 +680,14 @@ module Rails
|
|
448
680
|
def run_javascript
|
449
681
|
return if options[:skip_javascript] || !bundle_install?
|
450
682
|
|
451
|
-
case
|
452
|
-
when "importmap"
|
453
|
-
when "webpack", "esbuild", "rollup" then rails_command "javascript:install:#{
|
683
|
+
case options[:javascript]
|
684
|
+
when "importmap" then rails_command "importmap:install"
|
685
|
+
when "webpack", "bun", "esbuild", "rollup" then rails_command "javascript:install:#{options[:javascript]}"
|
454
686
|
end
|
455
687
|
end
|
456
688
|
|
457
689
|
def run_hotwire
|
458
|
-
return if options[:
|
690
|
+
return if options[:skip_hotwire] || !bundle_install?
|
459
691
|
|
460
692
|
rails_command "turbo:install stimulus:install"
|
461
693
|
end
|
@@ -463,13 +695,25 @@ module Rails
|
|
463
695
|
def run_css
|
464
696
|
return if !options[:css] || !bundle_install?
|
465
697
|
|
466
|
-
if !
|
698
|
+
if !using_js_runtime? && options[:css] == "tailwind"
|
467
699
|
rails_command "tailwindcss:install"
|
700
|
+
elsif !using_js_runtime? && options[:css] == "sass"
|
701
|
+
rails_command "dartsass:install"
|
468
702
|
else
|
469
703
|
rails_command "css:install:#{options[:css]}"
|
470
704
|
end
|
471
705
|
end
|
472
706
|
|
707
|
+
def add_bundler_platforms
|
708
|
+
if bundle_install?
|
709
|
+
# The vast majority of Rails apps will be deployed on `x86_64-linux`.
|
710
|
+
bundle_command("lock --add-platform=x86_64-linux")
|
711
|
+
|
712
|
+
# Users that develop on M1 mac may use docker and would need `aarch64-linux` as well.
|
713
|
+
bundle_command("lock --add-platform=aarch64-linux") if RUBY_PLATFORM.start_with?("arm64")
|
714
|
+
end
|
715
|
+
end
|
716
|
+
|
473
717
|
def generate_bundler_binstub
|
474
718
|
if bundle_install?
|
475
719
|
bundle_command("binstubs bundler")
|
@@ -484,6 +728,35 @@ module Rails
|
|
484
728
|
def keep_file(destination)
|
485
729
|
create_file("#{destination}/.keep") if keeps?
|
486
730
|
end
|
731
|
+
|
732
|
+
def user_default_branch
|
733
|
+
@user_default_branch ||= `git config init.defaultbranch`
|
734
|
+
end
|
735
|
+
|
736
|
+
def git_init_command
|
737
|
+
return "git init" if user_default_branch.strip.present?
|
738
|
+
|
739
|
+
git_version = `git --version`[/\d+\.\d+\.\d+/]
|
740
|
+
|
741
|
+
if Gem::Version.new(git_version) >= Gem::Version.new("2.28.0")
|
742
|
+
"git init -b main"
|
743
|
+
else
|
744
|
+
"git init && git symbolic-ref HEAD refs/heads/main"
|
745
|
+
end
|
746
|
+
end
|
747
|
+
|
748
|
+
def edge_branch
|
749
|
+
self.class.edge_branch
|
750
|
+
end
|
751
|
+
|
752
|
+
def dockerfile_chown_directories
|
753
|
+
directories = %w(log tmp)
|
754
|
+
|
755
|
+
directories << "storage" unless skip_active_storage? && !sqlite3?
|
756
|
+
directories << "db" unless skip_active_record?
|
757
|
+
|
758
|
+
directories.sort
|
759
|
+
end
|
487
760
|
end
|
488
761
|
end
|
489
762
|
end
|