migsupo 0.1.0
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 +7 -0
- data/README.md +246 -0
- data/lib/migsupo/configuration.rb +19 -0
- data/lib/migsupo/differ/diff.rb +22 -0
- data/lib/migsupo/differ/diff_calculator.rb +123 -0
- data/lib/migsupo/differ/operations/add_column.rb +27 -0
- data/lib/migsupo/differ/operations/add_index.rb +27 -0
- data/lib/migsupo/differ/operations/change_column.rb +33 -0
- data/lib/migsupo/differ/operations/create_table.rb +30 -0
- data/lib/migsupo/differ/operations/drop_table.rb +30 -0
- data/lib/migsupo/differ/operations/remove_column.rb +31 -0
- data/lib/migsupo/differ/operations/remove_index.rb +27 -0
- data/lib/migsupo/differ/operations/rename_column.rb +28 -0
- data/lib/migsupo/generator/migration_builder.rb +185 -0
- data/lib/migsupo/generator/migration_generator.rb +65 -0
- data/lib/migsupo/generator/naming.rb +45 -0
- data/lib/migsupo/loader/active_record_loader.rb +97 -0
- data/lib/migsupo/loader/schema_rb_loader.rb +24 -0
- data/lib/migsupo/parser/dsl_context.rb +49 -0
- data/lib/migsupo/parser/schemafile_parser.rb +18 -0
- data/lib/migsupo/parser/table_dsl_context.rb +92 -0
- data/lib/migsupo/railtie.rb +11 -0
- data/lib/migsupo/schema/column_definition.rb +42 -0
- data/lib/migsupo/schema/index_definition.rb +44 -0
- data/lib/migsupo/schema/schema_definition.rb +20 -0
- data/lib/migsupo/schema/table_definition.rb +31 -0
- data/lib/migsupo/tasks/migsupo.rake +56 -0
- data/lib/migsupo/version.rb +3 -0
- data/lib/migsupo.rb +75 -0
- data/migsupo.gemspec +23 -0
- metadata +156 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
module Migsupo
|
|
2
|
+
module Schema
|
|
3
|
+
class TableDefinition
|
|
4
|
+
attr_reader :name, :columns, :indexes, :options
|
|
5
|
+
|
|
6
|
+
def initialize(name:, columns: [], indexes: [], options: {})
|
|
7
|
+
@name = name.to_s
|
|
8
|
+
@columns = columns.freeze
|
|
9
|
+
@indexes = indexes.freeze
|
|
10
|
+
@options = options.transform_keys(&:to_sym).freeze
|
|
11
|
+
|
|
12
|
+
@columns_by_name = columns.each_with_object({}) { |c, h| h[c.name] = c }.freeze
|
|
13
|
+
@indexes_by_name = indexes.each_with_object({}) { |i, h| h[i.name] = i }.freeze
|
|
14
|
+
|
|
15
|
+
freeze
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def column(col_name)
|
|
19
|
+
@columns_by_name[col_name.to_s]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def index(idx_name)
|
|
23
|
+
@indexes_by_name[idx_name.to_s]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def to_h
|
|
27
|
+
{ name: name, columns: columns.map(&:to_h), indexes: indexes.map(&:to_h), options: options }
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
namespace :db do
|
|
2
|
+
namespace :generate_migration do
|
|
3
|
+
desc "Show diff between Schemafile and current DB schema without generating files"
|
|
4
|
+
task diff: :environment do
|
|
5
|
+
diff = Migsupo.calculate_diff(
|
|
6
|
+
schemafile_path: ENV.fetch("SCHEMAFILE", Migsupo.configuration.schemafile_path),
|
|
7
|
+
loader: ENV.fetch("LOADER", Migsupo.configuration.loader.to_s).to_sym
|
|
8
|
+
)
|
|
9
|
+
puts diff.to_s
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
desc "Exit with code 1 if Schemafile and current DB schema are not in sync"
|
|
13
|
+
task check: :environment do
|
|
14
|
+
diff = Migsupo.calculate_diff(
|
|
15
|
+
schemafile_path: ENV.fetch("SCHEMAFILE", Migsupo.configuration.schemafile_path),
|
|
16
|
+
loader: ENV.fetch("LOADER", Migsupo.configuration.loader.to_s).to_sym
|
|
17
|
+
)
|
|
18
|
+
if diff.empty?
|
|
19
|
+
puts "Schema is in sync."
|
|
20
|
+
else
|
|
21
|
+
puts "Schema is out of sync:"
|
|
22
|
+
puts diff.to_s
|
|
23
|
+
exit 1
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
desc "Generate Rails migration files from diff between Schemafile and current DB schema"
|
|
29
|
+
task generate_migration: :environment do
|
|
30
|
+
schemafile_path = ENV.fetch("SCHEMAFILE", Migsupo.configuration.schemafile_path)
|
|
31
|
+
output_dir = ENV.fetch("OUTPUT_DIR", Migsupo.configuration.migrations_dir)
|
|
32
|
+
loader = ENV.fetch("LOADER", Migsupo.configuration.loader.to_s).to_sym
|
|
33
|
+
dry_run = ENV["DRY_RUN"] == "true"
|
|
34
|
+
verbose = ENV["VERBOSE"] == "true"
|
|
35
|
+
|
|
36
|
+
diff = Migsupo.calculate_diff(schemafile_path: schemafile_path, loader: loader)
|
|
37
|
+
|
|
38
|
+
if diff.empty?
|
|
39
|
+
puts "No changes detected. No migration files generated."
|
|
40
|
+
next
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
if verbose
|
|
44
|
+
puts "Detected changes:"
|
|
45
|
+
puts diff.to_s
|
|
46
|
+
puts
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
files = Migsupo.generate_migrations(diff, output_dir: output_dir, dry_run: dry_run)
|
|
50
|
+
|
|
51
|
+
unless dry_run
|
|
52
|
+
puts "Generated #{files.size} migration file(s):"
|
|
53
|
+
files.each { |f| puts " #{f}" }
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
data/lib/migsupo.rb
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
require_relative "migsupo/version"
|
|
2
|
+
require_relative "migsupo/configuration"
|
|
3
|
+
require_relative "migsupo/schema/column_definition"
|
|
4
|
+
require_relative "migsupo/schema/index_definition"
|
|
5
|
+
require_relative "migsupo/schema/table_definition"
|
|
6
|
+
require_relative "migsupo/schema/schema_definition"
|
|
7
|
+
require_relative "migsupo/parser/schemafile_parser"
|
|
8
|
+
require_relative "migsupo/loader/active_record_loader"
|
|
9
|
+
require_relative "migsupo/loader/schema_rb_loader"
|
|
10
|
+
require_relative "migsupo/differ/diff_calculator"
|
|
11
|
+
require_relative "migsupo/generator/migration_generator"
|
|
12
|
+
|
|
13
|
+
module Migsupo
|
|
14
|
+
class << self
|
|
15
|
+
def configure
|
|
16
|
+
yield configuration
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def configuration
|
|
20
|
+
@configuration ||= Configuration.new
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def calculate_diff(schemafile_path: nil, loader: nil)
|
|
24
|
+
schemafile_path ||= configuration.schemafile_path
|
|
25
|
+
loader ||= configuration.loader
|
|
26
|
+
|
|
27
|
+
desired = Parser::SchemafileParser.parse(schemafile_path)
|
|
28
|
+
current = build_loader(loader).load_schema
|
|
29
|
+
|
|
30
|
+
Differ::DiffCalculator.new(rename_hints: configuration.rename_hints)
|
|
31
|
+
.calculate(desired: desired, current: current)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def generate_migrations(diff, output_dir: nil, dry_run: false)
|
|
35
|
+
output_dir ||= configuration.migrations_dir
|
|
36
|
+
|
|
37
|
+
Generator::MigrationGenerator.new(rails_version: detect_rails_version)
|
|
38
|
+
.generate(diff, output_dir: output_dir, dry_run: dry_run)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
def build_loader(loader)
|
|
44
|
+
case loader.to_sym
|
|
45
|
+
when :active_record
|
|
46
|
+
Loader::ActiveRecordLoader.new(ignored_tables: configuration.ignored_tables)
|
|
47
|
+
when :schema_rb
|
|
48
|
+
Loader::SchemaRbLoader.new(
|
|
49
|
+
schema_rb_path: resolve_schema_rb_path,
|
|
50
|
+
ignored_tables: configuration.ignored_tables
|
|
51
|
+
)
|
|
52
|
+
else
|
|
53
|
+
raise ArgumentError, "Unknown loader: #{loader}. Use :active_record or :schema_rb"
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def resolve_schema_rb_path
|
|
58
|
+
if defined?(Rails)
|
|
59
|
+
Rails.root.join("db", "schema.rb").to_s
|
|
60
|
+
else
|
|
61
|
+
"db/schema.rb"
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def detect_rails_version
|
|
66
|
+
return configuration.migration_version if configuration.migration_version
|
|
67
|
+
return nil unless defined?(Rails)
|
|
68
|
+
|
|
69
|
+
major_minor = Rails::VERSION::STRING.split(".").first(2).join(".")
|
|
70
|
+
major_minor
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
require_relative "migsupo/railtie" if defined?(Rails::Railtie)
|
data/migsupo.gemspec
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require_relative "lib/migsupo/version"
|
|
2
|
+
|
|
3
|
+
Gem::Specification.new do |spec|
|
|
4
|
+
spec.name = "migsupo"
|
|
5
|
+
spec.version = Migsupo::VERSION
|
|
6
|
+
spec.authors = ["masak1yu"]
|
|
7
|
+
spec.summary = "Generate Rails migrations from a Schemafile diff"
|
|
8
|
+
spec.description = "Like ridgepole but outputs Rails migration files instead of applying schema changes directly to the DB"
|
|
9
|
+
spec.license = "MIT"
|
|
10
|
+
|
|
11
|
+
spec.files = Dir["lib/**/*", "*.gemspec", "README.md"]
|
|
12
|
+
spec.require_paths = ["lib"]
|
|
13
|
+
|
|
14
|
+
spec.required_ruby_version = ">= 3.0"
|
|
15
|
+
|
|
16
|
+
spec.add_dependency "activerecord", ">= 6.1"
|
|
17
|
+
spec.add_dependency "activesupport", ">= 6.1"
|
|
18
|
+
|
|
19
|
+
spec.add_development_dependency "railties", ">= 6.1"
|
|
20
|
+
spec.add_development_dependency "rspec", "~> 3.12"
|
|
21
|
+
spec.add_development_dependency "rubocop", "~> 1.60"
|
|
22
|
+
spec.add_development_dependency "sqlite3", ">= 1.4"
|
|
23
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: migsupo
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- masak1yu
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2026-03-24 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: activerecord
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ">="
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '6.1'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - ">="
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '6.1'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: activesupport
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - ">="
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '6.1'
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - ">="
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '6.1'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: railties
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - ">="
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '6.1'
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - ">="
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '6.1'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: rspec
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - "~>"
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '3.12'
|
|
62
|
+
type: :development
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - "~>"
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '3.12'
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: rubocop
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - "~>"
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: '1.60'
|
|
76
|
+
type: :development
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - "~>"
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: '1.60'
|
|
83
|
+
- !ruby/object:Gem::Dependency
|
|
84
|
+
name: sqlite3
|
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - ">="
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: '1.4'
|
|
90
|
+
type: :development
|
|
91
|
+
prerelease: false
|
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - ">="
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: '1.4'
|
|
97
|
+
description: Like ridgepole but outputs Rails migration files instead of applying
|
|
98
|
+
schema changes directly to the DB
|
|
99
|
+
email:
|
|
100
|
+
executables: []
|
|
101
|
+
extensions: []
|
|
102
|
+
extra_rdoc_files: []
|
|
103
|
+
files:
|
|
104
|
+
- README.md
|
|
105
|
+
- lib/migsupo.rb
|
|
106
|
+
- lib/migsupo/configuration.rb
|
|
107
|
+
- lib/migsupo/differ/diff.rb
|
|
108
|
+
- lib/migsupo/differ/diff_calculator.rb
|
|
109
|
+
- lib/migsupo/differ/operations/add_column.rb
|
|
110
|
+
- lib/migsupo/differ/operations/add_index.rb
|
|
111
|
+
- lib/migsupo/differ/operations/change_column.rb
|
|
112
|
+
- lib/migsupo/differ/operations/create_table.rb
|
|
113
|
+
- lib/migsupo/differ/operations/drop_table.rb
|
|
114
|
+
- lib/migsupo/differ/operations/remove_column.rb
|
|
115
|
+
- lib/migsupo/differ/operations/remove_index.rb
|
|
116
|
+
- lib/migsupo/differ/operations/rename_column.rb
|
|
117
|
+
- lib/migsupo/generator/migration_builder.rb
|
|
118
|
+
- lib/migsupo/generator/migration_generator.rb
|
|
119
|
+
- lib/migsupo/generator/naming.rb
|
|
120
|
+
- lib/migsupo/loader/active_record_loader.rb
|
|
121
|
+
- lib/migsupo/loader/schema_rb_loader.rb
|
|
122
|
+
- lib/migsupo/parser/dsl_context.rb
|
|
123
|
+
- lib/migsupo/parser/schemafile_parser.rb
|
|
124
|
+
- lib/migsupo/parser/table_dsl_context.rb
|
|
125
|
+
- lib/migsupo/railtie.rb
|
|
126
|
+
- lib/migsupo/schema/column_definition.rb
|
|
127
|
+
- lib/migsupo/schema/index_definition.rb
|
|
128
|
+
- lib/migsupo/schema/schema_definition.rb
|
|
129
|
+
- lib/migsupo/schema/table_definition.rb
|
|
130
|
+
- lib/migsupo/tasks/migsupo.rake
|
|
131
|
+
- lib/migsupo/version.rb
|
|
132
|
+
- migsupo.gemspec
|
|
133
|
+
homepage:
|
|
134
|
+
licenses:
|
|
135
|
+
- MIT
|
|
136
|
+
metadata: {}
|
|
137
|
+
post_install_message:
|
|
138
|
+
rdoc_options: []
|
|
139
|
+
require_paths:
|
|
140
|
+
- lib
|
|
141
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
142
|
+
requirements:
|
|
143
|
+
- - ">="
|
|
144
|
+
- !ruby/object:Gem::Version
|
|
145
|
+
version: '3.0'
|
|
146
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
147
|
+
requirements:
|
|
148
|
+
- - ">="
|
|
149
|
+
- !ruby/object:Gem::Version
|
|
150
|
+
version: '0'
|
|
151
|
+
requirements: []
|
|
152
|
+
rubygems_version: 3.2.32
|
|
153
|
+
signing_key:
|
|
154
|
+
specification_version: 4
|
|
155
|
+
summary: Generate Rails migrations from a Schemafile diff
|
|
156
|
+
test_files: []
|