railties 7.1.3.4 → 7.2.0.beta1
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 +175 -744
- data/lib/minitest/rails_plugin.rb +5 -2
- data/lib/rails/all.rb +1 -3
- data/lib/rails/api/task.rb +3 -2
- data/lib/rails/application/bootstrap.rb +5 -6
- data/lib/rails/application/configuration.rb +34 -39
- data/lib/rails/application/dummy_config.rb +2 -2
- data/lib/rails/application/finisher.rb +7 -0
- data/lib/rails/application.rb +7 -48
- data/lib/rails/backtrace_cleaner.rb +18 -3
- data/lib/rails/cli.rb +0 -1
- data/lib/rails/command.rb +1 -1
- data/lib/rails/commands/app/update_command.rb +86 -0
- data/lib/rails/commands/console/console_command.rb +2 -21
- data/lib/rails/commands/console/irb_console.rb +137 -0
- data/lib/rails/commands/credentials/credentials_command.rb +2 -2
- data/lib/rails/commands/dbconsole/dbconsole_command.rb +21 -30
- data/lib/rails/commands/devcontainer/devcontainer_command.rb +34 -0
- data/lib/rails/commands/rake/rake_command.rb +1 -1
- data/lib/rails/commands/runner/runner_command.rb +14 -3
- data/lib/rails/commands/server/server_command.rb +5 -3
- data/lib/rails/commands/test/test_command.rb +2 -0
- data/lib/rails/configuration.rb +10 -1
- data/lib/rails/console/app.rb +5 -32
- data/lib/rails/console/helpers.rb +5 -16
- data/lib/rails/console/methods.rb +23 -0
- data/lib/rails/engine.rb +5 -5
- data/lib/rails/gem_version.rb +3 -3
- data/lib/rails/generators/app_base.rb +70 -49
- data/lib/rails/generators/base.rb +5 -1
- data/lib/rails/generators/database.rb +227 -69
- data/lib/rails/generators/erb/scaffold/templates/edit.html.erb.tt +2 -0
- data/lib/rails/generators/erb/scaffold/templates/index.html.erb.tt +2 -0
- data/lib/rails/generators/erb/scaffold/templates/new.html.erb.tt +2 -0
- data/lib/rails/generators/generated_attribute.rb +26 -1
- data/lib/rails/generators/migration.rb +3 -3
- data/lib/rails/generators/rails/app/app_generator.rb +52 -23
- data/lib/rails/generators/rails/app/templates/Dockerfile.tt +23 -14
- data/lib/rails/generators/rails/app/templates/Gemfile.tt +16 -16
- data/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb.tt +4 -0
- data/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt +8 -1
- data/lib/rails/generators/rails/app/templates/app/views/pwa/manifest.json.erb.tt +22 -0
- data/lib/rails/generators/rails/app/templates/app/views/pwa/service-worker.js +26 -0
- data/lib/rails/generators/rails/app/templates/bin/brakeman.tt +6 -0
- data/lib/rails/generators/rails/app/templates/bin/rubocop.tt +7 -0
- data/lib/rails/generators/rails/app/templates/bin/setup.tt +6 -2
- data/lib/rails/generators/rails/app/templates/config/application.rb.tt +1 -1
- data/lib/rails/generators/rails/app/templates/config/databases/mysql.yml.tt +3 -3
- data/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml.tt +7 -0
- data/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml.tt +8 -1
- data/lib/rails/generators/rails/app/templates/config/databases/trilogy.yml.tt +3 -3
- data/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt +11 -6
- data/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt +2 -0
- data/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt +6 -5
- data/lib/rails/generators/rails/app/templates/config/initializers/filter_parameter_logging.rb.tt +1 -1
- data/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_7_2.rb.tt +70 -0
- data/lib/rails/generators/rails/app/templates/config/puma.rb.tt +42 -23
- data/lib/rails/generators/rails/app/templates/config/routes.rb.tt +4 -0
- data/lib/rails/generators/rails/app/templates/docker-entrypoint.tt +5 -0
- data/lib/rails/generators/rails/app/templates/dockerignore.tt +13 -0
- data/lib/rails/generators/rails/app/templates/github/ci.yml.tt +138 -0
- data/lib/rails/generators/rails/app/templates/github/dependabot.yml +12 -0
- data/lib/rails/generators/rails/app/templates/gitignore.tt +3 -3
- data/lib/rails/generators/rails/app/templates/public/406-unsupported-browser.html +66 -0
- data/lib/rails/generators/rails/app/templates/public/icon.png +0 -0
- data/lib/rails/generators/rails/app/templates/public/icon.svg +3 -0
- data/lib/rails/generators/rails/app/templates/rubocop.yml.tt +8 -0
- data/lib/rails/generators/rails/app/templates/test/application_system_test_case.rb.tt +1 -1
- data/lib/rails/generators/rails/controller/controller_generator.rb +1 -1
- data/lib/rails/generators/rails/db/system/change/change_generator.rb +131 -20
- data/lib/rails/generators/rails/devcontainer/devcontainer_generator.rb +166 -0
- data/lib/rails/generators/rails/migration/migration_generator.rb +4 -0
- data/lib/rails/generators/rails/plugin/plugin_generator.rb +38 -7
- data/lib/rails/generators/rails/plugin/templates/%name%.gemspec.tt +2 -2
- data/lib/rails/generators/rails/plugin/templates/Gemfile.tt +5 -1
- data/lib/rails/generators/rails/plugin/templates/bin/rubocop.tt +7 -0
- data/lib/rails/generators/rails/plugin/templates/github/ci.yml.tt +103 -0
- data/lib/rails/generators/rails/plugin/templates/github/dependabot.yml +12 -0
- data/lib/rails/generators/rails/plugin/templates/rubocop.yml.tt +8 -0
- data/lib/rails/generators/rails/plugin/templates/test/application_system_test_case.rb.tt +1 -1
- data/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb +10 -0
- data/lib/rails/generators/test_unit/scaffold/templates/system_test.rb.tt +2 -0
- data/lib/rails/generators/test_unit/system/templates/application_system_test_case.rb.tt +1 -1
- data/lib/rails/generators/testing/assertions.rb +20 -0
- data/lib/rails/generators/testing/behavior.rb +7 -6
- data/lib/rails/generators.rb +1 -1
- data/lib/rails/health_controller.rb +1 -1
- data/lib/rails/info.rb +2 -2
- data/lib/rails/mailers_controller.rb +14 -1
- data/lib/rails/paths.rb +2 -2
- data/lib/rails/pwa_controller.rb +15 -0
- data/lib/rails/rack/logger.rb +15 -7
- data/lib/rails/railtie/configurable.rb +2 -2
- data/lib/rails/railtie.rb +2 -3
- data/lib/rails/tasks/framework.rake +0 -26
- data/lib/rails/tasks/tmp.rake +1 -1
- data/lib/rails/templates/layouts/application.html.erb +1 -1
- data/lib/rails/templates/rails/mailers/email.html.erb +12 -8
- data/lib/rails/templates/rails/welcome/index.html.erb +3 -2
- data/lib/rails/test_help.rb +2 -4
- data/lib/rails/test_unit/reporter.rb +8 -2
- data/lib/rails/test_unit/runner.rb +21 -2
- data/lib/rails/test_unit/test_parser.rb +45 -0
- data/lib/rails.rb +7 -4
- metadata +38 -32
- data/lib/rails/app_updater.rb +0 -40
- data/lib/rails/commands/secrets/USAGE +0 -61
- data/lib/rails/commands/secrets/secrets_command.rb +0 -47
- data/lib/rails/generators/rails/app/templates/config/databases/jdbc.yml.tt +0 -68
- data/lib/rails/generators/rails/app/templates/config/databases/jdbcmysql.yml.tt +0 -54
- data/lib/rails/generators/rails/app/templates/config/databases/jdbcpostgresql.yml.tt +0 -70
- data/lib/rails/generators/rails/app/templates/config/databases/jdbcsqlite3.yml.tt +0 -24
- data/lib/rails/generators/rails/app/templates/config/databases/oracle.yml.tt +0 -62
- data/lib/rails/generators/rails/app/templates/config/databases/sqlserver.yml.tt +0 -53
- data/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_7_1.rb.tt +0 -284
- data/lib/rails/generators/rails/app/templates/public/apple-touch-icon-precomposed.png +0 -0
- data/lib/rails/generators/rails/app/templates/public/apple-touch-icon.png +0 -0
- data/lib/rails/generators/rails/app/templates/public/favicon.ico +0 -0
- data/lib/rails/ruby_version_check.rb +0 -17
- data/lib/rails/secrets.rb +0 -110
@@ -0,0 +1,166 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rails/generators"
|
4
|
+
|
5
|
+
module Rails
|
6
|
+
module Generators
|
7
|
+
class DevcontainerGenerator < Base # :nodoc:
|
8
|
+
class_option :app_name, type: :string, default: "rails_app",
|
9
|
+
desc: "Name of the app"
|
10
|
+
|
11
|
+
class_option :database, enum: Database::DATABASES, type: :string, default: "sqlite3",
|
12
|
+
desc: "Include configuration for selected database"
|
13
|
+
|
14
|
+
class_option :redis, type: :boolean, default: true,
|
15
|
+
desc: "Include configuration for Redis"
|
16
|
+
|
17
|
+
class_option :system_test, type: :boolean, default: true,
|
18
|
+
desc: "Include configuration for System Tests"
|
19
|
+
|
20
|
+
class_option :active_storage, type: :boolean, default: true,
|
21
|
+
desc: "Include configuration for Active Storage"
|
22
|
+
|
23
|
+
class_option :node, type: :boolean, default: false,
|
24
|
+
desc: "Include configuration for Node"
|
25
|
+
|
26
|
+
class_option :dev, type: :boolean, default: false,
|
27
|
+
desc: "For applications pointing to a local Rails checkout"
|
28
|
+
|
29
|
+
source_paths << File.expand_path(File.join(base_name, "app", "templates"), base_root)
|
30
|
+
|
31
|
+
def create_devcontainer
|
32
|
+
empty_directory ".devcontainer"
|
33
|
+
|
34
|
+
template ".devcontainer/devcontainer.json"
|
35
|
+
template ".devcontainer/Dockerfile"
|
36
|
+
template ".devcontainer/compose.yaml"
|
37
|
+
end
|
38
|
+
|
39
|
+
def update_application_system_test_case
|
40
|
+
return unless options[:system_test]
|
41
|
+
return unless File.exist?("test/application_system_test_case.rb")
|
42
|
+
|
43
|
+
gsub_file("test/application_system_test_case.rb", /^(\s*driven_by\b.*)/, system_test_configuration)
|
44
|
+
end
|
45
|
+
|
46
|
+
def update_database_yml
|
47
|
+
# Only postgresql has devcontainer specific configuration, so only update database.yml if we are using postgres
|
48
|
+
return unless options[:database] == "postgresql"
|
49
|
+
|
50
|
+
template("config/databases/#{options[:database]}.yml", "config/database.yml")
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
def devcontainer?
|
55
|
+
true
|
56
|
+
end
|
57
|
+
|
58
|
+
def app_name
|
59
|
+
options[:app_name]
|
60
|
+
end
|
61
|
+
|
62
|
+
def dependencies
|
63
|
+
return @dependencies if @dependencies
|
64
|
+
|
65
|
+
@dependencies = []
|
66
|
+
|
67
|
+
@dependencies << "selenium" if options[:system_test]
|
68
|
+
@dependencies << "redis" if options[:redis]
|
69
|
+
@dependencies << database.name if database.service
|
70
|
+
@dependencies
|
71
|
+
end
|
72
|
+
|
73
|
+
def container_env
|
74
|
+
return @container_env if @container_env
|
75
|
+
|
76
|
+
@container_env = {}
|
77
|
+
|
78
|
+
@container_env["CAPYBARA_SERVER_PORT"] = "45678" if options[:system_test]
|
79
|
+
@container_env["SELENIUM_HOST"] = "selenium" if options[:system_test]
|
80
|
+
@container_env["REDIS_URL"] = "redis://redis:6379/1" if options[:redis]
|
81
|
+
@container_env["DB_HOST"] = database.name if database.service
|
82
|
+
|
83
|
+
@container_env
|
84
|
+
end
|
85
|
+
|
86
|
+
def volumes
|
87
|
+
return @volumes if @volumes
|
88
|
+
|
89
|
+
@volumes = []
|
90
|
+
|
91
|
+
@volumes << "redis-data" if options[:redis]
|
92
|
+
@volumes << database.volume if database.volume
|
93
|
+
|
94
|
+
@volumes
|
95
|
+
end
|
96
|
+
|
97
|
+
def features
|
98
|
+
return @features if @features
|
99
|
+
|
100
|
+
@features = {
|
101
|
+
"ghcr.io/devcontainers/features/github-cli:1" => {}
|
102
|
+
}
|
103
|
+
|
104
|
+
@features["ghcr.io/rails/devcontainer/features/activestorage"] = {} if options[:active_storage]
|
105
|
+
@features["ghcr.io/devcontainers/features/node:1"] = {} if options[:node]
|
106
|
+
|
107
|
+
@features.merge!(database.feature) if database.feature
|
108
|
+
|
109
|
+
@features
|
110
|
+
end
|
111
|
+
|
112
|
+
def mounts
|
113
|
+
return @mounts if @mounts
|
114
|
+
|
115
|
+
@mounts = []
|
116
|
+
|
117
|
+
@mounts << local_rails_mount if options[:dev]
|
118
|
+
|
119
|
+
@mounts
|
120
|
+
end
|
121
|
+
|
122
|
+
def forward_ports
|
123
|
+
return @forward_ports if @forward_ports
|
124
|
+
|
125
|
+
@forward_ports = [3000]
|
126
|
+
@forward_ports << database.port if database.port
|
127
|
+
@forward_ports << 6379 if options[:redis]
|
128
|
+
|
129
|
+
@forward_ports
|
130
|
+
end
|
131
|
+
|
132
|
+
def database
|
133
|
+
@database ||= Database.build(options[:database])
|
134
|
+
end
|
135
|
+
|
136
|
+
def devcontainer_db_service_yaml(**options)
|
137
|
+
return unless service = database.service
|
138
|
+
|
139
|
+
{ database.name => service }.to_yaml(**options)[4..-1]
|
140
|
+
end
|
141
|
+
|
142
|
+
def local_rails_mount
|
143
|
+
{
|
144
|
+
type: "bind",
|
145
|
+
source: Rails::Generators::RAILS_DEV_PATH,
|
146
|
+
target: Rails::Generators::RAILS_DEV_PATH
|
147
|
+
}
|
148
|
+
end
|
149
|
+
|
150
|
+
def system_test_configuration
|
151
|
+
<<~RUBY
|
152
|
+
if ENV["CAPYBARA_SERVER_PORT"]
|
153
|
+
served_by host: "rails-app", port: ENV["CAPYBARA_SERVER_PORT"]
|
154
|
+
|
155
|
+
driven_by :selenium, using: :headless_chrome, screen_size: [ 1400, 1400 ], options: {
|
156
|
+
browser: :remote,
|
157
|
+
url: "http://#{ENV["SELENIUM_HOST"]}:4444"
|
158
|
+
}
|
159
|
+
else
|
160
|
+
driven_by :selenium, using: :headless_chrome, screen_size: [ 1400, 1400 ]
|
161
|
+
end
|
162
|
+
RUBY
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
@@ -5,6 +5,10 @@ module Rails
|
|
5
5
|
class MigrationGenerator < NamedBase # :nodoc:
|
6
6
|
argument :attributes, type: :array, default: [], banner: "field[:type][:index] field[:type][:index]"
|
7
7
|
hook_for :orm, required: true, desc: "ORM to be invoked"
|
8
|
+
|
9
|
+
def self.exit_on_failure? # :nodoc:
|
10
|
+
true
|
11
|
+
end
|
8
12
|
end
|
9
13
|
end
|
10
14
|
end
|
@@ -66,6 +66,16 @@ module Rails
|
|
66
66
|
template "gitignore", ".gitignore"
|
67
67
|
end
|
68
68
|
|
69
|
+
def cifiles
|
70
|
+
empty_directory ".github/workflows"
|
71
|
+
template "github/ci.yml", ".github/workflows/ci.yml"
|
72
|
+
template "github/dependabot.yml", ".github/dependabot.yml"
|
73
|
+
end
|
74
|
+
|
75
|
+
def rubocop
|
76
|
+
template "rubocop.yml", ".rubocop.yml"
|
77
|
+
end
|
78
|
+
|
69
79
|
def version_control
|
70
80
|
if !options[:skip_git] && !options[:pretend]
|
71
81
|
run git_init_command, capture: options[:quiet], abort_on_failure: false
|
@@ -112,9 +122,12 @@ module Rails
|
|
112
122
|
def generate_test_dummy(force = false)
|
113
123
|
opts = options.transform_keys(&:to_sym).except(*DUMMY_IGNORE_OPTIONS)
|
114
124
|
opts[:force] = force
|
125
|
+
opts[:skip_brakeman] = true
|
115
126
|
opts[:skip_bundle] = true
|
127
|
+
opts[:skip_ci] = true
|
116
128
|
opts[:skip_git] = true
|
117
129
|
opts[:skip_hotwire] = true
|
130
|
+
opts[:skip_rubocop] = true
|
118
131
|
opts[:dummy_app] = true
|
119
132
|
|
120
133
|
invoke Rails::Generators::AppGenerator,
|
@@ -144,7 +157,7 @@ module Rails
|
|
144
157
|
def test_dummy_clean
|
145
158
|
inside dummy_path do
|
146
159
|
remove_file ".ruby-version"
|
147
|
-
|
160
|
+
remove_dir "db"
|
148
161
|
remove_file "Gemfile"
|
149
162
|
remove_file "lib/tasks"
|
150
163
|
remove_file "public/robots.txt"
|
@@ -167,12 +180,12 @@ module Rails
|
|
167
180
|
end
|
168
181
|
end
|
169
182
|
|
170
|
-
def bin
|
171
|
-
|
172
|
-
|
183
|
+
def bin
|
184
|
+
exclude_pattern = Regexp.union([(engine? ? /test\.tt/ : /rails\.tt/), (/rubocop/ if skip_rubocop?)].compact)
|
185
|
+
directory "bin", { exclude_pattern: exclude_pattern } do |content|
|
173
186
|
"#{shebang}\n" + content
|
174
187
|
end
|
175
|
-
chmod "bin", 0755, verbose: false
|
188
|
+
chmod "bin", 0755 & ~File.umask, verbose: false
|
176
189
|
end
|
177
190
|
|
178
191
|
def gemfile_entry
|
@@ -180,7 +193,7 @@ module Rails
|
|
180
193
|
|
181
194
|
gemfile_in_app_path = File.join(rails_app_path, "Gemfile")
|
182
195
|
if File.exist? gemfile_in_app_path
|
183
|
-
entry =
|
196
|
+
entry = %{\ngem "#{name}", path: "#{relative_path}"}
|
184
197
|
append_file gemfile_in_app_path, entry
|
185
198
|
end
|
186
199
|
end
|
@@ -243,6 +256,16 @@ module Rails
|
|
243
256
|
build(:app)
|
244
257
|
end
|
245
258
|
|
259
|
+
def create_rubocop_file
|
260
|
+
return if skip_rubocop?
|
261
|
+
build(:rubocop)
|
262
|
+
end
|
263
|
+
|
264
|
+
def create_cifiles
|
265
|
+
return if skip_ci?
|
266
|
+
build(:cifiles)
|
267
|
+
end
|
268
|
+
|
246
269
|
def create_config_files
|
247
270
|
build(:config)
|
248
271
|
end
|
@@ -341,7 +364,7 @@ module Rails
|
|
341
364
|
build(:test_dummy_sprocket_assets) unless skip_sprockets?
|
342
365
|
build(:test_dummy_clean)
|
343
366
|
# ensure that bin/rails has proper dummy_path
|
344
|
-
build(:bin
|
367
|
+
build(:bin)
|
345
368
|
end
|
346
369
|
end
|
347
370
|
|
@@ -465,6 +488,14 @@ module Rails
|
|
465
488
|
return unless inside_application?
|
466
489
|
app_path.delete_prefix("#{rails_app_path}/")
|
467
490
|
end
|
491
|
+
|
492
|
+
def test_command
|
493
|
+
if engine? && !options[:skip_active_record] && with_dummy_app?
|
494
|
+
"db:test:prepare test"
|
495
|
+
else
|
496
|
+
"test"
|
497
|
+
end
|
498
|
+
end
|
468
499
|
end
|
469
500
|
end
|
470
501
|
end
|
@@ -3,8 +3,8 @@ require_relative "lib/<%= namespaced_name %>/version"
|
|
3
3
|
Gem::Specification.new do |spec|
|
4
4
|
spec.name = <%= name.inspect %>
|
5
5
|
spec.version = <%= camelized_modules %>::VERSION
|
6
|
-
spec.authors = [<%= author.inspect %>]
|
7
|
-
spec.email = [<%= email.inspect %>]
|
6
|
+
spec.authors = [ <%= author.inspect %> ]
|
7
|
+
spec.email = [ <%= email.inspect %> ]
|
8
8
|
spec.homepage = "TODO"
|
9
9
|
spec.summary = "TODO: Summary of <%= camelized_modules %>."
|
10
10
|
spec.description = "TODO: Description of <%= camelized_modules %>."
|
@@ -1,5 +1,4 @@
|
|
1
1
|
source "https://rubygems.org"
|
2
|
-
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
|
3
2
|
<% unless options[:skip_gemspec] -%>
|
4
3
|
|
5
4
|
# Specify your gem's dependencies in <%= name %>.gemspec.
|
@@ -8,6 +7,11 @@ gemspec
|
|
8
7
|
<% gemfile_entries.each do |gemfile_entry| %>
|
9
8
|
<%= gemfile_entry %>
|
10
9
|
<% end -%>
|
10
|
+
<%- unless options.skip_rubocop? -%>
|
11
|
+
|
12
|
+
# Omakase Ruby styling [https://github.com/rails/rubocop-rails-omakase/]
|
13
|
+
gem "rubocop-rails-omakase", require: false
|
14
|
+
<%- end -%>
|
11
15
|
<% if RUBY_ENGINE == "ruby" -%>
|
12
16
|
|
13
17
|
# Start debugger with binding.b [https://github.com/ruby/debug]
|
@@ -0,0 +1,103 @@
|
|
1
|
+
name: CI
|
2
|
+
|
3
|
+
on:
|
4
|
+
pull_request:
|
5
|
+
push:
|
6
|
+
branches: [ main ]
|
7
|
+
|
8
|
+
jobs:
|
9
|
+
<%- unless skip_rubocop? -%>
|
10
|
+
lint:
|
11
|
+
runs-on: ubuntu-latest
|
12
|
+
steps:
|
13
|
+
- name: Checkout code
|
14
|
+
uses: actions/checkout@v4
|
15
|
+
|
16
|
+
- name: Set up Ruby
|
17
|
+
uses: ruby/setup-ruby@v1
|
18
|
+
with:
|
19
|
+
ruby-version: <%= ENV["RBENV_VERSION"] || ENV["rvm_ruby_string"] || "#{RUBY_ENGINE}-#{RUBY_ENGINE_VERSION}" %>
|
20
|
+
bundler-cache: true
|
21
|
+
|
22
|
+
- name: Lint code for consistent style
|
23
|
+
run: bin/rubocop -f github
|
24
|
+
|
25
|
+
<% end -%>
|
26
|
+
<% unless options[:skip_test] -%>
|
27
|
+
test:
|
28
|
+
runs-on: ubuntu-latest
|
29
|
+
|
30
|
+
<%- if options[:database] == "sqlite3" -%>
|
31
|
+
# services:
|
32
|
+
# redis:
|
33
|
+
# image: redis
|
34
|
+
# ports:
|
35
|
+
# - 6379:6379
|
36
|
+
# options: --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5
|
37
|
+
<%- else -%>
|
38
|
+
services:
|
39
|
+
<%- if options[:database] == "mysql" || options[:database] == "trilogy" -%>
|
40
|
+
mysql:
|
41
|
+
image: mysql
|
42
|
+
env:
|
43
|
+
MYSQL_ALLOW_EMPTY_PASSWORD: true
|
44
|
+
ports:
|
45
|
+
- 3306:3306
|
46
|
+
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
|
47
|
+
<%- elsif options[:database] == "postgresql" -%>
|
48
|
+
postgres:
|
49
|
+
image: postgres
|
50
|
+
env:
|
51
|
+
POSTGRES_USER: postgres
|
52
|
+
POSTGRES_PASSWORD: postgres
|
53
|
+
ports:
|
54
|
+
- 5432:5432
|
55
|
+
options: --health-cmd="pg_isready" --health-interval=10s --health-timeout=5s --health-retries=3
|
56
|
+
<%- end -%>
|
57
|
+
|
58
|
+
# redis:
|
59
|
+
# image: redis
|
60
|
+
# ports:
|
61
|
+
# - 6379:6379
|
62
|
+
# options: --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5
|
63
|
+
|
64
|
+
<%- end -%>
|
65
|
+
steps:
|
66
|
+
- name: Install packages
|
67
|
+
run: sudo apt-get update && sudo apt-get install --no-install-recommends -y google-chrome-stable <%= (dockerfile_base_packages + [database.base_package]).join(" ") %>
|
68
|
+
|
69
|
+
- name: Checkout code
|
70
|
+
uses: actions/checkout@v4
|
71
|
+
|
72
|
+
- name: Set up Ruby
|
73
|
+
uses: ruby/setup-ruby@v1
|
74
|
+
with:
|
75
|
+
ruby-version: <%= ENV["RBENV_VERSION"] || ENV["rvm_ruby_string"] || "#{RUBY_ENGINE}-#{RUBY_ENGINE_VERSION}" %>
|
76
|
+
bundler-cache: true
|
77
|
+
<%- if using_bun? -%>
|
78
|
+
|
79
|
+
- uses: oven-sh/setup-bun@v1
|
80
|
+
with:
|
81
|
+
bun-version: <%= dockerfile_bun_version %>
|
82
|
+
<%- end -%>
|
83
|
+
|
84
|
+
- name: Run tests
|
85
|
+
env:
|
86
|
+
RAILS_ENV: test
|
87
|
+
<%- if options[:database] == "mysql" || options[:database] == "trilogy" -%>
|
88
|
+
DATABASE_URL: mysql2://127.0.0.1:3306
|
89
|
+
<%- elsif options[:database] == "postgresql" -%>
|
90
|
+
DATABASE_URL: postgres://postgres:postgres@localhost:5432
|
91
|
+
<%- end -%>
|
92
|
+
# REDIS_URL: redis://localhost:6379/0
|
93
|
+
run: bin/rails <%= test_command %>
|
94
|
+
|
95
|
+
- name: Keep screenshots from failed system tests
|
96
|
+
uses: actions/upload-artifact@v4
|
97
|
+
if: failure()
|
98
|
+
with:
|
99
|
+
name: screenshots
|
100
|
+
path: ${{ github.workspace }}/tmp/screenshots
|
101
|
+
if-no-files-found: ignore
|
102
|
+
<% end -%>
|
103
|
+
|
@@ -63,6 +63,16 @@ module TestUnit # :nodoc:
|
|
63
63
|
attribute = attributes.find { |attr| attr.name == name }
|
64
64
|
attribute&.virtual?
|
65
65
|
end
|
66
|
+
|
67
|
+
def datetime?(name)
|
68
|
+
attribute = attributes.find { |attr| attr.name == name }
|
69
|
+
attribute&.type == :datetime
|
70
|
+
end
|
71
|
+
|
72
|
+
def time?(name)
|
73
|
+
attribute = attributes.find { |attr| attr.name == name }
|
74
|
+
attribute&.type == :time
|
75
|
+
end
|
66
76
|
end
|
67
77
|
end
|
68
78
|
end
|
@@ -35,6 +35,8 @@ class <%= class_name.pluralize %>Test < ApplicationSystemTestCase
|
|
35
35
|
<%- attributes_hash.each do |attr, value| -%>
|
36
36
|
<%- if boolean?(attr) -%>
|
37
37
|
check "<%= attr.humanize %>" if <%= value %>
|
38
|
+
<%- elsif datetime?(attr) || time?(attr) -%>
|
39
|
+
fill_in "<%= attr.humanize %>", with: <%= value %>.to_s
|
38
40
|
<%- else -%>
|
39
41
|
fill_in "<%= attr.humanize %>", with: <%= value %>
|
40
42
|
<%- end -%>
|
@@ -121,6 +121,26 @@ module Rails
|
|
121
121
|
assert_equal(value, create_generated_attribute(attribute_type).default)
|
122
122
|
end
|
123
123
|
end
|
124
|
+
|
125
|
+
# Asserts a given initializer exists. You need to supply a path relative
|
126
|
+
# to the `config/initializers/` directory.
|
127
|
+
#
|
128
|
+
# assert_initializer "mail_interceptors.rb"
|
129
|
+
#
|
130
|
+
# You can also give extra arguments. If the argument is a regexp, it will check if the
|
131
|
+
# regular expression matches the given file content. If it's a string, it compares the
|
132
|
+
# file with the given string:
|
133
|
+
#
|
134
|
+
# assert_initializer "mail_interceptors.rb", /SandboxEmailInterceptor/
|
135
|
+
#
|
136
|
+
# Finally, when a block is given, it yields the file content:
|
137
|
+
#
|
138
|
+
# assert_initializer "mail_interceptors.rb" do |initializer|
|
139
|
+
# assert_match(/SandboxEmailInterceptor/, initializer)
|
140
|
+
# end
|
141
|
+
def assert_initializer(name, *contents, &block)
|
142
|
+
assert_file("config/initializers/#{name}", *contents, &block)
|
143
|
+
end
|
124
144
|
end
|
125
145
|
end
|
126
146
|
end
|
@@ -65,11 +65,15 @@ module Rails
|
|
65
65
|
# You can provide a configuration hash as second argument. This method returns the output
|
66
66
|
# printed by the generator.
|
67
67
|
def run_generator(args = default_arguments, config = {})
|
68
|
-
|
69
|
-
|
70
|
-
args += ["--skip-bootsnap"] unless args.include?("--no-skip-bootsnap") || args.include?("--skip-bootsnap")
|
68
|
+
args += ["--skip-bundle"] unless args.include?("--no-skip-bundle") || args.include?("--dev")
|
69
|
+
args += ["--skip-bootsnap"] unless args.include?("--no-skip-bootsnap") || args.include?("--skip-bootsnap")
|
71
70
|
|
71
|
+
if ENV["RAILS_LOG_TO_STDOUT"] == "true"
|
72
72
|
generator_class.start(args, config.reverse_merge(destination_root: destination_root))
|
73
|
+
else
|
74
|
+
capture(:stdout) do
|
75
|
+
generator_class.start(args, config.reverse_merge(destination_root: destination_root))
|
76
|
+
end
|
73
77
|
end
|
74
78
|
end
|
75
79
|
|
@@ -107,9 +111,6 @@ module Rails
|
|
107
111
|
Dir.glob("#{dirname}/[0-9]*_*.rb").grep(/\d+_#{file_name}.rb$/).first
|
108
112
|
end
|
109
113
|
end
|
110
|
-
|
111
|
-
include ActiveSupport::Deprecation::DeprecatedConstantAccessor
|
112
|
-
deprecate_constant "Behaviour", "Rails::Generators::Testing::Behavior", deprecator: Rails.deprecator
|
113
114
|
end
|
114
115
|
end
|
115
116
|
end
|
data/lib/rails/generators.rb
CHANGED
@@ -23,6 +23,7 @@ module Rails
|
|
23
23
|
autoload :NamedBase, "rails/generators/named_base"
|
24
24
|
autoload :ResourceHelpers, "rails/generators/resource_helpers"
|
25
25
|
autoload :TestCase, "rails/generators/test_case"
|
26
|
+
autoload :Devcontainer, "rails/generators/devcontainer"
|
26
27
|
|
27
28
|
mattr_accessor :namespace
|
28
29
|
|
@@ -202,7 +203,6 @@ module Rails
|
|
202
203
|
rails.map! { |n| n.delete_prefix("rails:") }
|
203
204
|
rails.delete("app")
|
204
205
|
rails.delete("plugin")
|
205
|
-
rails.delete("encrypted_secrets")
|
206
206
|
rails.delete("encrypted_file")
|
207
207
|
rails.delete("encryption_key_file")
|
208
208
|
rails.delete("master_key")
|
@@ -24,7 +24,7 @@ module Rails
|
|
24
24
|
# The health check will now be accessible via the +/healthz+ path.
|
25
25
|
#
|
26
26
|
# NOTE: This endpoint does not reflect the status of all of your application's
|
27
|
-
# dependencies, such as the database or
|
27
|
+
# dependencies, such as the database or Redis cluster. Replace
|
28
28
|
# <tt>"rails/health#show"</tt> with your own controller action if you have
|
29
29
|
# application specific needs.
|
30
30
|
#
|
data/lib/rails/info.rb
CHANGED
@@ -95,11 +95,11 @@ module Rails
|
|
95
95
|
|
96
96
|
# The name of the database adapter for the current environment.
|
97
97
|
property "Database adapter" do
|
98
|
-
ActiveRecord::Base.
|
98
|
+
ActiveRecord::Base.connection_pool.db_config.adapter
|
99
99
|
end
|
100
100
|
|
101
101
|
property "Database schema version" do
|
102
|
-
ActiveRecord::Base.
|
102
|
+
ActiveRecord::Base.connection_pool.migration_context.current_version rescue nil
|
103
103
|
end
|
104
104
|
end
|
105
105
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "rails/application_controller"
|
4
|
+
require "active_support/core_ext/enumerable"
|
4
5
|
|
5
6
|
class Rails::MailersController < Rails::ApplicationController # :nodoc:
|
6
7
|
prepend_view_path ActionDispatch::DebugView::RESCUES_TEMPLATE_PATHS
|
@@ -9,7 +10,7 @@ class Rails::MailersController < Rails::ApplicationController # :nodoc:
|
|
9
10
|
before_action :find_preview, only: [:preview, :download]
|
10
11
|
before_action :require_local!, unless: :show_previews?
|
11
12
|
|
12
|
-
helper_method :part_query, :locale_query
|
13
|
+
helper_method :attachment_url, :part_query, :locale_query
|
13
14
|
|
14
15
|
content_security_policy(false)
|
15
16
|
|
@@ -38,6 +39,8 @@ class Rails::MailersController < Rails::ApplicationController # :nodoc:
|
|
38
39
|
if @preview.email_exists?(@email_action)
|
39
40
|
@page_title = "Mailer Preview for #{@preview.preview_name}##{@email_action}"
|
40
41
|
@email = @preview.call(@email_action, params)
|
42
|
+
@attachments = attachments_for(@email).reject { |filename, attachment| attachment.inline? }
|
43
|
+
@inline_attachments = attachments_for(@email).select { |filename, attachment| attachment.inline? }
|
41
44
|
|
42
45
|
if params[:part]
|
43
46
|
part_type = Mime::Type.lookup(params[:part])
|
@@ -95,6 +98,16 @@ class Rails::MailersController < Rails::ApplicationController # :nodoc:
|
|
95
98
|
end
|
96
99
|
end
|
97
100
|
|
101
|
+
def attachments_for(email)
|
102
|
+
email.all_parts.to_a.select(&:attachment?).index_by do |attachment|
|
103
|
+
attachment.respond_to?(:original_filename) ? attachment.original_filename : attachment.filename
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def attachment_url(attachment)
|
108
|
+
"data:application/octet-stream;charset=utf-8;base64,#{Base64.encode64(attachment.body.to_s)}"
|
109
|
+
end
|
110
|
+
|
98
111
|
def part_query(mime_type)
|
99
112
|
request.query_parameters.merge(part: mime_type).to_query
|
100
113
|
end
|
data/lib/rails/paths.rb
CHANGED
@@ -105,8 +105,8 @@ module Rails
|
|
105
105
|
private
|
106
106
|
def filter_by(&block)
|
107
107
|
all_paths.find_all(&block).flat_map { |path|
|
108
|
-
paths = path.
|
109
|
-
paths - path.children.flat_map { |p| yield(p) ? [] : p.
|
108
|
+
paths = path.existent_directories
|
109
|
+
paths - path.children.flat_map { |p| yield(p) ? [] : p.existent_directories }
|
110
110
|
}.uniq
|
111
111
|
end
|
112
112
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rails/application_controller"
|
4
|
+
|
5
|
+
class Rails::PwaController < Rails::ApplicationController # :nodoc:
|
6
|
+
skip_forgery_protection
|
7
|
+
|
8
|
+
def service_worker
|
9
|
+
render template: "pwa/service-worker", layout: false
|
10
|
+
end
|
11
|
+
|
12
|
+
def manifest
|
13
|
+
render template: "pwa/manifest", layout: false
|
14
|
+
end
|
15
|
+
end
|