mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Add rails db:system:change command
Add `rails db:system:change` command for changing databases. ``` bin/rails db:system:change --to=postgresql force config/database.yml gsub Gemfile ``` The change command copies a template `config/database.yml` with the target database adapter into your app, and replaces your database gem with the target database gem.
This commit is contained in:
parent
e3204b9c33
commit
4b1ae57f0f
8 changed files with 265 additions and 1 deletions
|
@ -1,3 +1,15 @@
|
|||
* Add `rails db:system:change` command for changing databases.
|
||||
|
||||
```
|
||||
bin/rails db:system:change --to=postgresql
|
||||
force config/database.yml
|
||||
gsub Gemfile
|
||||
```
|
||||
|
||||
The change command copies a template `config/database.yml` with the target database adapter into your app, and replaces your database gem with the target database gem.
|
||||
|
||||
*Gannon McGibbon*
|
||||
|
||||
* Use original `bundler` environment variables during the process of generating a new rails project.
|
||||
|
||||
*Marco Costa*
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require "rails/generators"
|
||||
require "rails/generators/rails/db/system/change/change_generator"
|
||||
|
||||
module Rails
|
||||
module Command
|
||||
module Db
|
||||
module System
|
||||
class ChangeCommand < Base # :nodoc:
|
||||
class_option :to, desc: "The database system to switch to."
|
||||
|
||||
def perform
|
||||
Rails::Generators::Db::System::ChangeGenerator.start
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -220,6 +220,7 @@ module Rails
|
|||
rails.delete("encryption_key_file")
|
||||
rails.delete("master_key")
|
||||
rails.delete("credentials")
|
||||
rails.delete("db:system:change")
|
||||
|
||||
hidden_namespaces.each { |n| groups.delete(n.to_s) }
|
||||
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require "rails/generators/base"
|
||||
|
||||
module Rails
|
||||
module Generators
|
||||
module Db
|
||||
module System
|
||||
class ChangeGenerator < Base # :nodoc:
|
||||
include Database
|
||||
include AppName
|
||||
|
||||
class_option :to, required: true,
|
||||
desc: "The database system to switch to."
|
||||
|
||||
def self.default_generator_root
|
||||
path = File.expand_path(File.join(base_name, "app"), base_root)
|
||||
path if File.exist?(path)
|
||||
end
|
||||
|
||||
def initialize(*)
|
||||
super
|
||||
|
||||
unless DATABASES.include?(options[:to])
|
||||
raise Error, "Invalid value for --to option. Supported for preconfiguration are: #{DATABASES.join(", ")}."
|
||||
end
|
||||
|
||||
opt = options.dup
|
||||
opt[:database] ||= opt[:to]
|
||||
self.options = opt.freeze
|
||||
end
|
||||
|
||||
def edit_database_config
|
||||
template("config/databases/#{options[:database]}.yml", "config/database.yml")
|
||||
end
|
||||
|
||||
def edit_gemfile
|
||||
database_gem_name, _ = gem_for_database
|
||||
gsub_file("Gemfile", all_database_gems_regex, database_gem_name)
|
||||
end
|
||||
|
||||
private
|
||||
def all_database_gems
|
||||
DATABASES.map { |database| gem_for_database(database) }
|
||||
end
|
||||
|
||||
def all_database_gems_regex
|
||||
all_database_gem_names = all_database_gems.map(&:first)
|
||||
/(\b#{all_database_gem_names.join('\b|\b')}\b)/
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
62
railties/test/commands/db_system_change_test.rb
Normal file
62
railties/test/commands/db_system_change_test.rb
Normal file
|
@ -0,0 +1,62 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require "isolation/abstract_unit"
|
||||
require "rails/command"
|
||||
require "rails/commands/db/system/change/change_command"
|
||||
|
||||
class Rails::Command::Db::System::ChangeCommandTest < ActiveSupport::TestCase
|
||||
include ActiveSupport::Testing::Isolation
|
||||
|
||||
setup { build_app }
|
||||
|
||||
teardown { teardown_app }
|
||||
|
||||
test "change to existing database" do
|
||||
change_database(to: "sqlite3")
|
||||
|
||||
output = change_database(to: "sqlite3")
|
||||
|
||||
assert_match "identical config/database.yml", output
|
||||
assert_match "gsub Gemfile", output
|
||||
end
|
||||
|
||||
test "change to invalid database" do
|
||||
output = change_database(to: "invalid-db")
|
||||
|
||||
assert_match <<~MSG.squish, output
|
||||
Invalid value for --to option.
|
||||
Supported for preconfiguration are:
|
||||
mysql, postgresql, sqlite3, oracle, frontbase,
|
||||
ibm_db, sqlserver, jdbcmysql, jdbcsqlite3,
|
||||
jdbcpostgresql, jdbc.
|
||||
MSG
|
||||
end
|
||||
|
||||
test "change to postgresql" do
|
||||
output = change_database(to: "postgresql")
|
||||
|
||||
assert_match "force config/database.yml", output
|
||||
assert_match "gsub Gemfile", output
|
||||
end
|
||||
|
||||
test "change to mysql" do
|
||||
output = change_database(to: "mysql")
|
||||
|
||||
assert_match "force config/database.yml", output
|
||||
assert_match "gsub Gemfile", output
|
||||
end
|
||||
|
||||
test "change to sqlite3" do
|
||||
change_database(to: "postgresql")
|
||||
output = change_database(to: "sqlite3")
|
||||
|
||||
assert_match "force config/database.yml", output
|
||||
assert_match "gsub Gemfile", output
|
||||
end
|
||||
|
||||
private
|
||||
def change_database(to:, **options)
|
||||
args = ["--to", to]
|
||||
rails "db:system:change", args, **options
|
||||
end
|
||||
end
|
78
railties/test/generators/db_system_change_generator_test.rb
Normal file
78
railties/test/generators/db_system_change_generator_test.rb
Normal file
|
@ -0,0 +1,78 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require "generators/generators_test_helper"
|
||||
require "rails/generators/rails/db/system/change/change_generator"
|
||||
|
||||
module Rails
|
||||
module Generators
|
||||
module Db
|
||||
module System
|
||||
class ChangeGeneratorTest < Rails::Generators::TestCase
|
||||
include GeneratorsTestHelper
|
||||
|
||||
setup do
|
||||
copy_gemfile(
|
||||
GemfileEntry.new("sqlite3", nil, "Use sqlite3 as the database for Active Record")
|
||||
)
|
||||
end
|
||||
|
||||
test "change to invalid database" do
|
||||
output = capture(:stderr) do
|
||||
run_generator ["--to", "invalid-db"]
|
||||
end
|
||||
|
||||
assert_match <<~MSG.squish, output
|
||||
Invalid value for --to option.
|
||||
Supported for preconfiguration are:
|
||||
mysql, postgresql, sqlite3, oracle, frontbase,
|
||||
ibm_db, sqlserver, jdbcmysql, jdbcsqlite3,
|
||||
jdbcpostgresql, jdbc.
|
||||
MSG
|
||||
end
|
||||
|
||||
test "change to postgresql" do
|
||||
run_generator ["--to", "postgresql"]
|
||||
|
||||
assert_file("config/database.yml") do |content|
|
||||
assert_match "adapter: postgresql", content
|
||||
assert_match "database: test_app", content
|
||||
end
|
||||
|
||||
assert_file("Gemfile") do |content|
|
||||
assert_match "# Use pg as the database for Active Record", content
|
||||
assert_match "gem 'pg'", content
|
||||
end
|
||||
end
|
||||
|
||||
test "change to mysql" do
|
||||
run_generator ["--to", "mysql"]
|
||||
|
||||
assert_file("config/database.yml") do |content|
|
||||
assert_match "adapter: mysql2", content
|
||||
assert_match "database: test_app", content
|
||||
end
|
||||
|
||||
assert_file("Gemfile") do |content|
|
||||
assert_match "# Use mysql2 as the database for Active Record", content
|
||||
assert_match "gem 'mysql2'", content
|
||||
end
|
||||
end
|
||||
|
||||
test "change to sqlite3" do
|
||||
run_generator ["--to", "sqlite3"]
|
||||
|
||||
assert_file("config/database.yml") do |content|
|
||||
assert_match "adapter: sqlite3", content
|
||||
assert_match "db/development.sqlite3", content
|
||||
end
|
||||
|
||||
assert_file("Gemfile") do |content|
|
||||
assert_match "# Use sqlite3 as the database for Active Record", content
|
||||
assert_match "gem 'sqlite3'", content
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -30,6 +30,12 @@ module GeneratorsTestHelper
|
|||
include ActiveSupport::Testing::Stream
|
||||
include ActiveSupport::Testing::MethodCallAssertions
|
||||
|
||||
GemfileEntry = Struct.new(:name, :version, :comment, :options, :commented_out) do
|
||||
def initialize(name, version, comment, options = {}, commented_out = false)
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
def self.included(base)
|
||||
base.class_eval do
|
||||
destination File.join(Rails.root, "tmp")
|
||||
|
@ -63,4 +69,34 @@ module GeneratorsTestHelper
|
|||
FileUtils.mkdir_p(destination)
|
||||
FileUtils.cp routes, File.join(destination, "routes.rb")
|
||||
end
|
||||
|
||||
def copy_gemfile(*gemfile_entries)
|
||||
locals = gemfile_locals.merge(gemfile_entries: gemfile_entries)
|
||||
gemfile = File.expand_path("../../lib/rails/generators/rails/app/templates/Gemfile.tt", __dir__)
|
||||
gemfile = evaluate_template(gemfile, locals)
|
||||
destination = File.join(destination_root)
|
||||
File.write File.join(destination, "Gemfile"), gemfile
|
||||
end
|
||||
|
||||
def evaluate_template(file, locals = {})
|
||||
erb = ERB.new(File.read(file), nil, "-", "@output_buffer")
|
||||
context = Class.new do
|
||||
locals.each do |local, value|
|
||||
class_attribute local, default: value
|
||||
end
|
||||
end
|
||||
erb.result(context.new.instance_eval("binding"))
|
||||
end
|
||||
|
||||
private
|
||||
def gemfile_locals
|
||||
{
|
||||
skip_active_storage: true,
|
||||
depend_on_bootsnap: false,
|
||||
depend_on_listen: false,
|
||||
spring_install: false,
|
||||
depends_on_system_test: false,
|
||||
options: ActiveSupport::OrderedOptions.new,
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -476,7 +476,7 @@ Module.new do
|
|||
`yarn build`
|
||||
end
|
||||
|
||||
`#{Gem.ruby} #{RAILS_FRAMEWORK_ROOT}/railties/exe/rails new #{app_template_path} --skip-gemfile --skip-listen --no-rc`
|
||||
`#{Gem.ruby} #{RAILS_FRAMEWORK_ROOT}/railties/exe/rails new #{app_template_path} --skip-bundle --skip-listen --no-rc`
|
||||
File.open("#{app_template_path}/config/boot.rb", "w") do |f|
|
||||
f.puts "require 'rails/all'"
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue