railties 7.1.3.2 → 7.2.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +175 -734
- 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
|