railties 7.1.5.1 → 7.2.2.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.
Files changed (131) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +197 -767
  3. data/lib/minitest/rails_plugin.rb +5 -2
  4. data/lib/rails/all.rb +1 -3
  5. data/lib/rails/api/task.rb +6 -4
  6. data/lib/rails/application/bootstrap.rb +5 -6
  7. data/lib/rails/application/configuration.rb +68 -33
  8. data/lib/rails/application/dummy_config.rb +2 -2
  9. data/lib/rails/application/finisher.rb +7 -0
  10. data/lib/rails/application.rb +22 -89
  11. data/lib/rails/backtrace_cleaner.rb +14 -1
  12. data/lib/rails/cli.rb +0 -1
  13. data/lib/rails/command.rb +1 -1
  14. data/lib/rails/commands/app/update_command.rb +102 -0
  15. data/lib/rails/commands/boot/boot_command.rb +14 -0
  16. data/lib/rails/commands/console/console_command.rb +2 -21
  17. data/lib/rails/commands/console/irb_console.rb +146 -0
  18. data/lib/rails/commands/credentials/credentials_command.rb +2 -2
  19. data/lib/rails/commands/dbconsole/dbconsole_command.rb +21 -30
  20. data/lib/rails/commands/devcontainer/devcontainer_command.rb +39 -0
  21. data/lib/rails/commands/rake/rake_command.rb +1 -1
  22. data/lib/rails/commands/runner/runner_command.rb +14 -3
  23. data/lib/rails/commands/server/server_command.rb +5 -3
  24. data/lib/rails/commands/test/test_command.rb +2 -0
  25. data/lib/rails/configuration.rb +10 -1
  26. data/lib/rails/console/app.rb +5 -32
  27. data/lib/rails/console/helpers.rb +5 -16
  28. data/lib/rails/console/methods.rb +23 -0
  29. data/lib/rails/engine.rb +7 -7
  30. data/lib/rails/gem_version.rb +2 -2
  31. data/lib/rails/generators/app_base.rb +70 -49
  32. data/lib/rails/generators/base.rb +5 -1
  33. data/lib/rails/generators/database.rb +227 -69
  34. data/lib/rails/generators/erb/scaffold/templates/edit.html.erb.tt +2 -0
  35. data/lib/rails/generators/erb/scaffold/templates/index.html.erb.tt +2 -0
  36. data/lib/rails/generators/erb/scaffold/templates/new.html.erb.tt +2 -0
  37. data/lib/rails/generators/generated_attribute.rb +26 -1
  38. data/lib/rails/generators/rails/app/app_generator.rb +56 -28
  39. data/lib/rails/generators/rails/app/templates/Dockerfile.tt +22 -15
  40. data/lib/rails/generators/rails/app/templates/Gemfile.tt +17 -17
  41. data/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb.tt +4 -0
  42. data/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt +8 -1
  43. data/lib/rails/generators/rails/app/templates/app/views/pwa/manifest.json.erb.tt +22 -0
  44. data/lib/rails/generators/rails/app/templates/app/views/pwa/service-worker.js +26 -0
  45. data/lib/rails/generators/rails/app/templates/bin/brakeman.tt +6 -0
  46. data/lib/rails/generators/rails/app/templates/bin/rubocop.tt +7 -0
  47. data/lib/rails/generators/rails/app/templates/bin/setup.tt +6 -2
  48. data/lib/rails/generators/rails/app/templates/config/application.rb.tt +1 -1
  49. data/lib/rails/generators/rails/app/templates/config/databases/mysql.yml.tt +3 -3
  50. data/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml.tt +7 -0
  51. data/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml.tt +8 -1
  52. data/lib/rails/generators/rails/app/templates/config/databases/trilogy.yml.tt +3 -3
  53. data/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt +14 -7
  54. data/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt +8 -0
  55. data/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt +8 -5
  56. data/lib/rails/generators/rails/app/templates/config/initializers/assets.rb.tt +1 -1
  57. data/lib/rails/generators/rails/app/templates/config/initializers/filter_parameter_logging.rb.tt +1 -1
  58. data/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_7_2.rb.tt +70 -0
  59. data/lib/rails/generators/rails/app/templates/config/puma.rb.tt +25 -35
  60. data/lib/rails/generators/rails/app/templates/config/routes.rb.tt +6 -0
  61. data/lib/rails/generators/rails/app/templates/docker-entrypoint.tt +5 -0
  62. data/lib/rails/generators/rails/app/templates/dockerignore.tt +13 -0
  63. data/lib/rails/generators/rails/app/templates/github/ci.yml.tt +138 -0
  64. data/lib/rails/generators/rails/app/templates/github/dependabot.yml +12 -0
  65. data/lib/rails/generators/rails/app/templates/gitignore.tt +3 -3
  66. data/lib/rails/generators/rails/app/templates/public/406-unsupported-browser.html +66 -0
  67. data/lib/rails/generators/rails/app/templates/public/icon.png +0 -0
  68. data/lib/rails/generators/rails/app/templates/public/icon.svg +3 -0
  69. data/lib/rails/generators/rails/app/templates/rubocop.yml.tt +8 -0
  70. data/lib/rails/generators/rails/app/templates/test/application_system_test_case.rb.tt +1 -1
  71. data/lib/rails/generators/rails/controller/controller_generator.rb +1 -1
  72. data/lib/rails/generators/rails/db/system/change/change_generator.rb +131 -20
  73. data/lib/rails/generators/rails/devcontainer/devcontainer_generator.rb +166 -0
  74. data/lib/rails/generators/rails/devcontainer/templates/devcontainer/Dockerfile.tt +3 -0
  75. data/lib/rails/generators/rails/devcontainer/templates/devcontainer/compose.yaml.tt +47 -0
  76. data/lib/rails/generators/rails/devcontainer/templates/devcontainer/devcontainer.json.tt +37 -0
  77. data/lib/rails/generators/rails/migration/migration_generator.rb +4 -0
  78. data/lib/rails/generators/rails/plugin/plugin_generator.rb +40 -7
  79. data/lib/rails/generators/rails/plugin/templates/%name%.gemspec.tt +2 -2
  80. data/lib/rails/generators/rails/plugin/templates/Gemfile.tt +5 -1
  81. data/lib/rails/generators/rails/plugin/templates/app/views/layouts/%namespaced_name%/application.html.erb.tt +2 -0
  82. data/lib/rails/generators/rails/plugin/templates/bin/rubocop.tt +7 -0
  83. data/lib/rails/generators/rails/plugin/templates/github/ci.yml.tt +103 -0
  84. data/lib/rails/generators/rails/plugin/templates/github/dependabot.yml +12 -0
  85. data/lib/rails/generators/rails/plugin/templates/rubocop.yml.tt +8 -0
  86. data/lib/rails/generators/rails/plugin/templates/test/application_system_test_case.rb.tt +1 -1
  87. data/lib/rails/generators/rails/plugin/templates/test/test_helper.rb.tt +2 -2
  88. data/lib/rails/generators/test_unit/mailer/templates/functional_test.rb.tt +6 -4
  89. data/lib/rails/generators/test_unit/mailer/templates/preview.rb.tt +3 -2
  90. data/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb +15 -1
  91. data/lib/rails/generators/test_unit/scaffold/templates/api_functional_test.rb.tt +2 -2
  92. data/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb.tt +2 -2
  93. data/lib/rails/generators/test_unit/scaffold/templates/system_test.rb.tt +2 -0
  94. data/lib/rails/generators/test_unit/system/templates/application_system_test_case.rb.tt +1 -1
  95. data/lib/rails/generators/testing/assertions.rb +20 -0
  96. data/lib/rails/generators/testing/behavior.rb +7 -6
  97. data/lib/rails/generators.rb +6 -2
  98. data/lib/rails/health_controller.rb +1 -1
  99. data/lib/rails/info.rb +2 -2
  100. data/lib/rails/mailers_controller.rb +14 -1
  101. data/lib/rails/paths.rb +2 -2
  102. data/lib/rails/pwa_controller.rb +15 -0
  103. data/lib/rails/rack/logger.rb +15 -7
  104. data/lib/rails/railtie/configurable.rb +2 -2
  105. data/lib/rails/railtie.rb +2 -3
  106. data/lib/rails/tasks/framework.rake +0 -26
  107. data/lib/rails/tasks/tmp.rake +1 -1
  108. data/lib/rails/templates/layouts/application.html.erb +1 -1
  109. data/lib/rails/templates/rails/mailers/email.html.erb +12 -8
  110. data/lib/rails/templates/rails/welcome/index.html.erb +4 -2
  111. data/lib/rails/test_help.rb +2 -4
  112. data/lib/rails/test_unit/reporter.rb +8 -2
  113. data/lib/rails/test_unit/runner.rb +26 -2
  114. data/lib/rails/test_unit/test_parser.rb +45 -0
  115. data/lib/rails.rb +6 -3
  116. metadata +40 -30
  117. data/lib/rails/app_updater.rb +0 -52
  118. data/lib/rails/commands/secrets/USAGE +0 -61
  119. data/lib/rails/commands/secrets/secrets_command.rb +0 -47
  120. data/lib/rails/generators/rails/app/templates/config/databases/jdbc.yml.tt +0 -68
  121. data/lib/rails/generators/rails/app/templates/config/databases/jdbcmysql.yml.tt +0 -54
  122. data/lib/rails/generators/rails/app/templates/config/databases/jdbcpostgresql.yml.tt +0 -70
  123. data/lib/rails/generators/rails/app/templates/config/databases/jdbcsqlite3.yml.tt +0 -24
  124. data/lib/rails/generators/rails/app/templates/config/databases/oracle.yml.tt +0 -62
  125. data/lib/rails/generators/rails/app/templates/config/databases/sqlserver.yml.tt +0 -53
  126. data/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_7_1.rb.tt +0 -280
  127. data/lib/rails/generators/rails/app/templates/public/apple-touch-icon-precomposed.png +0 -0
  128. data/lib/rails/generators/rails/app/templates/public/apple-touch-icon.png +0 -0
  129. data/lib/rails/generators/rails/app/templates/public/favicon.ico +0 -0
  130. data/lib/rails/ruby_version_check.rb +0 -17
  131. data/lib/rails/secrets.rb +0 -110
@@ -1,15 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "rails/generators/base"
4
+ require "yaml"
5
+ require "json"
4
6
 
5
7
  module Rails
6
8
  module Generators
7
9
  module Db
8
10
  module System
9
11
  class ChangeGenerator < Base # :nodoc:
10
- include Database
11
12
  include AppName
12
13
 
14
+ BASE_PACKAGES = %w( curl libvips )
15
+ BUILD_PACKAGES = %w( build-essential git )
16
+
13
17
  class_option :to, required: true,
14
18
  desc: "The database system to switch to."
15
19
 
@@ -21,8 +25,8 @@ module Rails
21
25
  def initialize(*)
22
26
  super
23
27
 
24
- unless DATABASES.include?(options[:to])
25
- raise Error, "Invalid value for --to option. Supported preconfigurations are: #{DATABASES.join(", ")}."
28
+ unless Database::DATABASES.include?(options[:to])
29
+ raise Error, "Invalid value for --to option. Supported preconfigurations are: #{Database::DATABASES.join(", ")}."
26
30
  end
27
31
 
28
32
  opt = options.dup
@@ -35,7 +39,7 @@ module Rails
35
39
  end
36
40
 
37
41
  def edit_gemfile
38
- name, version = gem_for_database
42
+ name, version = database.gem
39
43
  gsub_file("Gemfile", all_database_gems_regex, name)
40
44
  gsub_file("Gemfile", gem_entry_regex_for(name), gem_entry_for(name, *version))
41
45
  end
@@ -44,27 +48,44 @@ module Rails
44
48
  dockerfile_path = File.expand_path("Dockerfile", destination_root)
45
49
  return unless File.exist?(dockerfile_path)
46
50
 
47
- build_name = docker_for_database_build
48
- deploy_name = docker_for_database_deploy
49
- if build_name
50
- gsub_file("Dockerfile", all_docker_builds_regex, build_name)
51
- end
52
- if deploy_name
53
- gsub_file("Dockerfile", all_docker_deploys_regex, deploy_name)
54
- end
51
+ gsub_file("Dockerfile", all_docker_bases_regex, docker_base_packages(database.base_package))
52
+ gsub_file("Dockerfile", all_docker_builds_regex, docker_build_packages(database.build_package))
53
+ end
54
+
55
+ def edit_devcontainer_files
56
+ return unless devcontainer?
57
+
58
+ edit_devcontainer_json
59
+ edit_compose_yaml
55
60
  end
56
61
 
57
62
  private
58
63
  def all_database_gems
59
- DATABASES.map { |database| gem_for_database(database) }
64
+ Database.all.map { |database| database.gem }
65
+ end
66
+
67
+ def all_docker_bases
68
+ Database.all.map { |database| docker_base_packages(database.base_package) }.uniq
69
+ end
70
+
71
+ def docker_base_packages(database_package)
72
+ if database_package
73
+ [database_package].concat(BASE_PACKAGES).sort
74
+ else
75
+ BASE_PACKAGES
76
+ end.join("\s")
60
77
  end
61
78
 
62
79
  def all_docker_builds
63
- DATABASES.map { |database| docker_for_database_build(database).nil? ? nil : docker_for_database_build(database) }.compact!
80
+ Database.all.map { |database| docker_build_packages(database.build_package) }.uniq
64
81
  end
65
82
 
66
- def all_docker_deploys
67
- DATABASES.map { |database| docker_for_database_deploy(database).nil? ? nil : docker_for_database_deploy(database) }.compact!
83
+ def docker_build_packages(database_package)
84
+ if database_package
85
+ [database_package].concat(BUILD_PACKAGES).sort
86
+ else
87
+ BUILD_PACKAGES
88
+ end.join("\s")
68
89
  end
69
90
 
70
91
  def all_database_gems_regex
@@ -72,12 +93,12 @@ module Rails
72
93
  /(\b#{all_database_gem_names.join('\b|\b')}\b)/
73
94
  end
74
95
 
75
- def all_docker_builds_regex
76
- /(\b#{all_docker_builds.join('\b|\b')}\b)/
96
+ def all_docker_bases_regex
97
+ /(\b#{all_docker_bases.join('\b|\b')}\b)/
77
98
  end
78
99
 
79
- def all_docker_deploys_regex
80
- /(\b#{all_docker_deploys.join('\b|\b')}\b)/
100
+ def all_docker_builds_regex
101
+ /(\b#{all_docker_builds.join('\b|\b')}\b)/
81
102
  end
82
103
 
83
104
  def gem_entry_regex_for(gem_name)
@@ -88,6 +109,96 @@ module Rails
88
109
  gem_name_and_version.map! { |segment| "\"#{segment}\"" }
89
110
  "gem #{gem_name_and_version.join(", ")}"
90
111
  end
112
+
113
+ def edit_devcontainer_json
114
+ return unless devcontainer_json
115
+
116
+ update_devcontainer_db_host
117
+ update_devcontainer_db_feature
118
+ end
119
+
120
+ def edit_compose_yaml
121
+ compose_yaml_path = File.expand_path(".devcontainer/compose.yaml", destination_root)
122
+ return unless File.exist?(compose_yaml_path)
123
+
124
+ compose_config = YAML.load_file(compose_yaml_path)
125
+
126
+ Database.all.each do |database|
127
+ compose_config["services"].delete(database.name)
128
+ compose_config["volumes"]&.delete(database.volume)
129
+ compose_config["services"]["rails-app"]["depends_on"]&.delete(database.name)
130
+ end
131
+
132
+ if database.service
133
+ compose_config["services"][database.name] = database.service
134
+ compose_config["volumes"] = { database.volume => nil }.merge(compose_config["volumes"] || {})
135
+ compose_config["services"]["rails-app"]["depends_on"] = [
136
+ database.name,
137
+ compose_config["services"]["rails-app"]["depends_on"]
138
+ ].flatten.compact
139
+ end
140
+
141
+ compose_config.delete("volumes") unless compose_config["volumes"]&.any?
142
+ compose_config["services"]["rails-app"].delete("depends_on") unless compose_config["services"]["rails-app"]["depends_on"]&.any?
143
+
144
+ File.write(compose_yaml_path, compose_config.to_yaml)
145
+ end
146
+
147
+ def update_devcontainer_db_host
148
+ container_env = devcontainer_json["containerEnv"]
149
+ db_name = database.name
150
+
151
+ if container_env["DB_HOST"]
152
+ if database.service
153
+ container_env["DB_HOST"] = db_name
154
+ else
155
+ container_env.delete("DB_HOST")
156
+ end
157
+ else
158
+ if database.service
159
+ container_env["DB_HOST"] = db_name
160
+ end
161
+ end
162
+
163
+ new_json = JSON.pretty_generate(container_env, indent: " ", object_nl: "\n ")
164
+
165
+ gsub_file(".devcontainer/devcontainer.json", /("containerEnv"\s*:\s*)(.|\n)*?(^\s{2}})/, "\\1#{new_json}")
166
+ end
167
+
168
+ def update_devcontainer_db_feature
169
+ features = devcontainer_json["features"]
170
+ db_feature = database.feature
171
+
172
+ Database.all.each do |database|
173
+ features.delete(database.feature_name)
174
+ end
175
+
176
+ features.merge!(db_feature) if db_feature
177
+
178
+ new_json = JSON.pretty_generate(features, indent: " ", object_nl: "\n ")
179
+
180
+ gsub_file(".devcontainer/devcontainer.json", /("features"\s*:\s*)(.|\n)*?(^\s{2}})/, "\\1#{new_json}")
181
+ end
182
+
183
+ def devcontainer_json
184
+ return unless File.exist?(devcontainer_json_path)
185
+
186
+ @devcontainer_json ||= JSON.parse(File.read(devcontainer_json_path))
187
+ end
188
+
189
+ def devcontainer_json_path
190
+ File.expand_path(".devcontainer/devcontainer.json", destination_root)
191
+ end
192
+
193
+ def database
194
+ @database ||= Database.build(options[:database])
195
+ end
196
+
197
+ def devcontainer?
198
+ return @devcontainer if defined?(@devcontainer)
199
+
200
+ @devcontainer = File.exist?(File.expand_path(".devcontainer", destination_root))
201
+ end
91
202
  end
92
203
  end
93
204
  end
@@ -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", ".devcontainer/devcontainer.json"
35
+ template "devcontainer/Dockerfile", ".devcontainer/Dockerfile"
36
+ template "devcontainer/compose.yaml", ".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
+ optimize_indentation(<<-'RUBY', 2).chomp
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
@@ -0,0 +1,3 @@
1
+ # Make sure RUBY_VERSION matches the Ruby version in .ruby-version
2
+ ARG RUBY_VERSION=<%= gem_ruby_version %>
3
+ FROM ghcr.io/rails/devcontainer/images/ruby:$RUBY_VERSION
@@ -0,0 +1,47 @@
1
+ name: "<%= options[:app_name] %>"
2
+
3
+ services:
4
+ rails-app:
5
+ build:
6
+ context: ..
7
+ dockerfile: .devcontainer/Dockerfile
8
+
9
+ volumes:
10
+ - ../..:/workspaces:cached
11
+
12
+ # Overrides default command so things don't shut down after the process ends.
13
+ command: sleep infinity
14
+
15
+ # Uncomment the next line to use a non-root user for all processes.
16
+ # user: vscode
17
+
18
+ # Use "forwardPorts" in **devcontainer.json** to forward an app port locally.
19
+ # (Adding the "ports" property to this file will not forward from a Codespace.)
20
+ <%- if !dependencies.empty? -%>
21
+ depends_on:
22
+ <%- dependencies.each do |dependency| -%>
23
+ - <%= dependency %>
24
+ <%- end -%>
25
+ <%- end -%>
26
+ <%- if options[:system_test] -%>
27
+
28
+ selenium:
29
+ image: selenium/standalone-chromium
30
+ restart: unless-stopped
31
+ <%- end -%>
32
+
33
+ <%- if options[:redis] -%>
34
+ redis:
35
+ image: redis:7.2
36
+ restart: unless-stopped
37
+ volumes:
38
+ - redis-data:/data
39
+
40
+ <%- end -%>
41
+ <%= devcontainer_db_service_yaml(indentation: 4) %>
42
+ <%- if !volumes.empty? -%>
43
+ volumes:
44
+ <%- volumes.each do |volume| -%>
45
+ <%= volume %>:
46
+ <%- end -%>
47
+ <%- end -%>
@@ -0,0 +1,37 @@
1
+ // For format details, see https://aka.ms/devcontainer.json. For config options, see the
2
+ // README at: https://github.com/devcontainers/templates/tree/main/src/ruby
3
+ {
4
+ "name": "<%= options[:app_name] %>",
5
+ "dockerComposeFile": "compose.yaml",
6
+ "service": "rails-app",
7
+ "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
8
+
9
+ // Features to add to the dev container. More info: https://containers.dev/features.
10
+ "features": {
11
+ <%= features.map { |key, value| "\"#{key}\": #{value.as_json}" }.join(",\n ") %>
12
+ },
13
+
14
+ <%- if !container_env.empty? -%>
15
+ "containerEnv": {
16
+ <%= container_env.map { |key, value| "\"#{key}\": \"#{value}\"" }.join(",\n ") %>
17
+ },
18
+ <%- end -%>
19
+
20
+ // Use 'forwardPorts' to make a list of ports inside the container available locally.
21
+ "forwardPorts": <%= forward_ports.as_json %>,
22
+
23
+ // Configure tool-specific properties.
24
+ // "customizations": {},
25
+
26
+ // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
27
+ // "remoteUser": "root",
28
+
29
+ <%- if !mounts.empty? -%>
30
+ "mounts": [
31
+ <%= mounts.map { |mount| "{\n " + mount.map { |key, value| "\"#{key}\": \"#{value}\"" }.join(",\n ") + "\n }" }.join(",\n ") %>
32
+ ],
33
+ <%- end -%>
34
+
35
+ // Use 'postCreateCommand' to run commands after the container is created.
36
+ "postCreateCommand": "bin/setup"
37
+ }
@@ -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
- remove_file "db/seeds.rb"
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(force = false)
171
- bin_file = engine? ? "bin/rails.tt" : "bin/test.tt"
172
- template bin_file, force: force do |content|
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 = "\ngem '#{name}', path: '#{relative_path}'"
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, true)
367
+ build(:bin)
345
368
  end
346
369
  end
347
370
 
@@ -465,6 +488,16 @@ 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
+ "bin/rails db:test:prepare test"
495
+ elsif engine?
496
+ "bin/rails test"
497
+ else
498
+ "bin/test"
499
+ end
500
+ end
468
501
  end
469
502
  end
470
503
  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]
@@ -5,6 +5,8 @@
5
5
  <%%= csrf_meta_tags %>
6
6
  <%%= csp_meta_tag %>
7
7
 
8
+ <%%= yield :head %>
9
+
8
10
  <%%= stylesheet_link_tag "<%= namespaced_name %>/application", media: "all" %>
9
11
  </head>
10
12
  <body>
@@ -0,0 +1,7 @@
1
+ require "rubygems"
2
+ require "bundler/setup"
3
+
4
+ # explicit rubocop config increases performance slightly while avoiding config confusion.
5
+ ARGV.unshift("--config", File.expand_path("../.rubocop.yml", __dir__))
6
+
7
+ load Gem.bin_path("rubocop", "rubocop")