edgestitch 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/.rubocop.yml +2 -0
- data/Gemfile +9 -0
- data/Rakefile +17 -0
- data/doc/dependency_decisions.yml +3 -0
- data/docs/CHANGELOG.md +4 -0
- data/docs/README.md +99 -0
- data/edgestitch.gemspec +46 -0
- data/lib/edgestitch/exporter.rb +74 -0
- data/lib/edgestitch/mysql/dump.rb +93 -0
- data/lib/edgestitch/mysql/structure_constraint_order_munger.rb +59 -0
- data/lib/edgestitch/railtie.rb +12 -0
- data/lib/edgestitch/stitch.sql.erb +10 -0
- data/lib/edgestitch/stitcher.rb +28 -0
- data/lib/edgestitch/tasks.rb +91 -0
- data/lib/edgestitch/version.rb +5 -0
- data/lib/edgestitch.rb +26 -0
- data/mkdocs.yml +6 -0
- metadata +220 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 5dc175dee8364f977b9ba83df8cc9945b1931c08020620d390d38d3aaeae8fad
|
4
|
+
data.tar.gz: 3bba36bddf299d60b90195027d3b8454ade141f29b852f9300324761f7d18e66
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ff5f823716dc7ec8ffb0fa9be01ade5386fcf6ac123e539a16a7706d5b4557172eccdd344e71075ca2721a48a7b4c30f955e3cd6f1d9257c80d73ef94781cbd6
|
7
|
+
data.tar.gz: '050108e3c5dd92310aaf907df4b9cb7360422fcef56dfd1bcfb3b706d93b86501a3c415fb0cf669cb1601deb7c5e6d4c281438a11cc236b05f459658245b9f67'
|
data/.rubocop.yml
ADDED
data/Gemfile
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
|
3
|
+
# frozen_string_literal: true
|
4
|
+
|
5
|
+
require "bundler/setup"
|
6
|
+
Bundler::GemHelper.install_tasks
|
7
|
+
|
8
|
+
require "rspec/core/rake_task"
|
9
|
+
RSpec::Core::RakeTask.new(:spec)
|
10
|
+
|
11
|
+
require "rubocop/rake_task"
|
12
|
+
RuboCop::RakeTask.new(:rubocop)
|
13
|
+
|
14
|
+
APP_RAKEFILE = File.expand_path("spec/dummy/Rakefile", __dir__)
|
15
|
+
load "rails/tasks/engine.rake"
|
16
|
+
|
17
|
+
task default: %i[rubocop app:db:prepare spec]
|
data/docs/CHANGELOG.md
ADDED
data/docs/README.md
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
# Edgestitch
|
2
|
+
|
3
|
+
Edgestitch allows engines to define partial structure-self.sql files to be stitched into a single structure.sql file by the umbrella application. This allows big teams to develop large [Cobra](https://cbra.info) [Applications](https://github.com/powerhome/cobra_commander) without much conflict happening in a single structure.sql file. Instead, each team will more likely update one component or two structure-self.sql files while other teams concerned with other areas of the application will be changing different files.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
### Umbrella App
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
# Gemfile
|
13
|
+
|
14
|
+
gem "edgestitch", require: false
|
15
|
+
```
|
16
|
+
|
17
|
+
And then execute:
|
18
|
+
|
19
|
+
$ bundle install
|
20
|
+
|
21
|
+
Then require the railtie in the umbrella's `config/application.rb`:
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
# config/application.rb
|
25
|
+
|
26
|
+
require "edgestitch/railtie"
|
27
|
+
```
|
28
|
+
|
29
|
+
If your umbrella app also has migrations or even models, you'll have to also install the engine task to your `Rakefile`:
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
# Rakefile
|
33
|
+
|
34
|
+
Edgestitch.define_engine(::My::Application)
|
35
|
+
```
|
36
|
+
|
37
|
+
### Engines
|
38
|
+
|
39
|
+
Each internal engine will also have a development dependency on `edgestitch`, and can install it the same way:
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
# crazy.gemspec
|
43
|
+
|
44
|
+
spec.add_development_dependency "edgestitch"
|
45
|
+
```
|
46
|
+
|
47
|
+
And then execute:
|
48
|
+
|
49
|
+
$ bundle install
|
50
|
+
|
51
|
+
And install the helper tasks:
|
52
|
+
|
53
|
+
```ruby
|
54
|
+
Edgestitch.define_engine(::Crazy::Engine)
|
55
|
+
```
|
56
|
+
|
57
|
+
You'll also have to add the `railtie` to the dummy app (as they're dummy umbrella apps), in case the engine has external database dependencies.
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
# spec/dummy/config/application.rb
|
61
|
+
|
62
|
+
require "edgestitch/railtie"
|
63
|
+
```
|
64
|
+
|
65
|
+
## Usage
|
66
|
+
|
67
|
+
Edgestitch will enhance the default rails tasks, so nothing special has to be done in order to use it. Once edgestitch is correctly installed things should Just Work™️ as explained in the rails manual, but it will be generating `structure-self.sql` along with `structure.sql` files. **Important**: It's recommended that `structure.sql` files are added to `.gitignore`.
|
68
|
+
|
69
|
+
# How does it work
|
70
|
+
|
71
|
+
Edgestitch works based on table and migrations ownership. Based on these ownerships, Edgestitch can export a `structure-self.sql` file defining the DDL owned by a specific engine.
|
72
|
+
|
73
|
+
The stitching process then takes all loaded engines (assuming the dependency between engines is defined correctly) and assembles a structure.sql file.
|
74
|
+
|
75
|
+
## Table and Migration Ownerships
|
76
|
+
|
77
|
+
A model is owned by an engine when it inherits from the Engine's ApplicationModel, and thus the table is owned by that engine. A migration is owned by the engine if it is defined within its `db/migrate` directory.
|
78
|
+
|
79
|
+
## Extra tables
|
80
|
+
|
81
|
+
When an external dependency brings in extra tables (i.e. acts_as_taggable) that are not defined in any `structure-self.sql`. To be part of the ecosystem, the new tables should be owned by the engine adding them. That can be done by adding these tables to `<engine>/db/extra_tables`. It's a simple text file with a list of table names that do not inherit from `<Engine>::AplicationModel`, but are owned by that engine and should be included in its structure-self.sql.
|
82
|
+
|
83
|
+
## External Gems
|
84
|
+
|
85
|
+
An external gem can also define a `structure-self.sql` file to be adapted in this ecosystem. That can be done using the same approach specified in Installation / Engines.
|
86
|
+
|
87
|
+
## Development
|
88
|
+
|
89
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
90
|
+
|
91
|
+
To install this gem onto your local machine, run `bundle exec rake install`.
|
92
|
+
|
93
|
+
## Contributing
|
94
|
+
|
95
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/powerhome/power-tools.
|
96
|
+
|
97
|
+
## License
|
98
|
+
|
99
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/edgestitch.gemspec
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
$LOAD_PATH.push File.expand_path("lib", __dir__)
|
4
|
+
|
5
|
+
require "edgestitch/version"
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = "edgestitch"
|
9
|
+
spec.version = Edgestitch::VERSION
|
10
|
+
spec.authors = ["Carlos Palhares"]
|
11
|
+
spec.email = ["chjunior@gmail.com"]
|
12
|
+
|
13
|
+
spec.description = spec.summary = "Edgestitch allows engines to define partial structure-self.sql files to be " \
|
14
|
+
"stitched into a single structure.sql file by the umbrella application."
|
15
|
+
spec.homepage = "https://github.com/powerhome/power-tools"
|
16
|
+
spec.license = "MIT"
|
17
|
+
spec.required_ruby_version = ">= 2.7"
|
18
|
+
|
19
|
+
spec.metadata["rubygems_mfa_required"] = "true"
|
20
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
21
|
+
spec.metadata["source_code_uri"] = spec.homepage
|
22
|
+
spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/main/packages/edgestitch/docs/CHANGELOG.md"
|
23
|
+
|
24
|
+
# Specify which files should be added to the gem when it is released.
|
25
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
26
|
+
spec.files = Dir.chdir(__dir__) do
|
27
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
28
|
+
(f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
|
29
|
+
end
|
30
|
+
end
|
31
|
+
spec.bindir = "exe"
|
32
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
33
|
+
spec.require_paths = ["lib"]
|
34
|
+
|
35
|
+
spec.add_development_dependency "bundler", "~> 2.1"
|
36
|
+
spec.add_development_dependency "license_finder", ">= 7.0"
|
37
|
+
spec.add_development_dependency "mysql2", "0.5.3"
|
38
|
+
spec.add_development_dependency "pry-byebug", "3.9.0"
|
39
|
+
spec.add_development_dependency "rails", ">= 5.2.8.1"
|
40
|
+
spec.add_development_dependency "rake", "~> 13.0"
|
41
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
42
|
+
spec.add_development_dependency "rspec-rails", "~> 5.1.2"
|
43
|
+
spec.add_development_dependency "rubocop-powerhome", "0.5.0"
|
44
|
+
spec.add_development_dependency "simplecov", "0.15.1"
|
45
|
+
spec.add_development_dependency "yard", "0.9.21"
|
46
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Edgestitch
|
4
|
+
# @private
|
5
|
+
#
|
6
|
+
# This class is responsible for exporting an engine's owned tables and
|
7
|
+
# migrations to a SQL file.
|
8
|
+
#
|
9
|
+
class Exporter
|
10
|
+
# Exports an engine using a dump helper (@see Edgestitch::Mysql::Dump)
|
11
|
+
#
|
12
|
+
# @param engine [Class<Rails::Engine>] the engine to export
|
13
|
+
# @param dump [<#export_tables,#export_migrations>] the dump helper
|
14
|
+
#
|
15
|
+
def self.export(engine, dump)
|
16
|
+
new(engine).export(dump)
|
17
|
+
end
|
18
|
+
|
19
|
+
attr_reader :engine
|
20
|
+
|
21
|
+
def initialize(engine)
|
22
|
+
@engine = engine
|
23
|
+
@database_directory_path = engine.root.join("db")
|
24
|
+
@extra_tables_path = database_directory_path.join("extra_tables")
|
25
|
+
@structure_file_path = database_directory_path.join("structure-self.sql")
|
26
|
+
end
|
27
|
+
|
28
|
+
def export(dump, to: structure_file_path)
|
29
|
+
StringIO.open do |buffer|
|
30
|
+
buffer.puts dump.export_tables(tables)
|
31
|
+
buffer.puts
|
32
|
+
buffer.puts dump.export_migrations(migrations)
|
33
|
+
File.write to, "#{buffer.string.strip}\n"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def migrations
|
38
|
+
@migrations ||= begin
|
39
|
+
migrations_glob = database_directory_path.join("{migrate,migrate.archive}/*.rb")
|
40
|
+
Dir[migrations_glob]
|
41
|
+
.map { |filename| File.basename(filename).to_i }
|
42
|
+
.sort
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def tables
|
47
|
+
component_tables + extra_tables
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
attr_reader :database_directory_path, :extra_tables_path, :structure_file_path
|
53
|
+
|
54
|
+
def extra_tables
|
55
|
+
@extra_tables ||= extra_tables_path.exist? ? extra_tables_path.readlines.map(&:strip) : []
|
56
|
+
end
|
57
|
+
|
58
|
+
def component_tables
|
59
|
+
@component_tables ||= models.each_with_object(Set.new) do |model, tables|
|
60
|
+
tables << model.table_name if model.table_exists?
|
61
|
+
end.sort
|
62
|
+
end
|
63
|
+
|
64
|
+
def models
|
65
|
+
@models ||= application_record&.descendants || []
|
66
|
+
end
|
67
|
+
|
68
|
+
def application_record
|
69
|
+
@application_record ||= engine.railtie_namespace&.const_get(:ApplicationRecord, false)
|
70
|
+
rescue LoadError, NameError
|
71
|
+
nil
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "open3"
|
4
|
+
|
5
|
+
require_relative "./structure_constraint_order_munger"
|
6
|
+
|
7
|
+
module Edgestitch
|
8
|
+
module Mysql
|
9
|
+
# @private
|
10
|
+
#
|
11
|
+
# Wrapper for the mysqldump tool to dump specific tables and migration data
|
12
|
+
#
|
13
|
+
class Dump
|
14
|
+
# Sanitizes a DDL code with some opinionated preferences:
|
15
|
+
# * Constraints starting with `_fk` will start with `fk`
|
16
|
+
# * Clear empty lines (with empty spaces even)
|
17
|
+
# * Reorder constraints (@see Edgestitch::Mysql::StructureConstraintOrderMunger)
|
18
|
+
#
|
19
|
+
# @param sql [String] the DDL code to sanitize
|
20
|
+
# @return String the same DDL sanitized
|
21
|
+
def self.sanitize_sql(sql)
|
22
|
+
comment_instructions_regex = %r{^/\*![0-9]{5}\s+[^;]+;\s*$}
|
23
|
+
|
24
|
+
cleanups = sql.gsub(/\s+AUTO_INCREMENT=\d+/, "")
|
25
|
+
.gsub(/CONSTRAINT `_+fk_/, "CONSTRAINT `fk_")
|
26
|
+
.gsub(comment_instructions_regex, "")
|
27
|
+
.gsub(/\n\s*\n\s*\n/, "\n\n")
|
28
|
+
.strip
|
29
|
+
::Edgestitch::Mysql::StructureConstraintOrderMunger.munge(cleanups)
|
30
|
+
end
|
31
|
+
|
32
|
+
#
|
33
|
+
# @param config [ActiveRecord::DatabaseConfigurations::DatabaseConfig] rails database configuration
|
34
|
+
def initialize(config)
|
35
|
+
hash = config.respond_to?(:configuration_hash) ? config.configuration_hash : config.config
|
36
|
+
@database = hash["database"] || hash[:database]
|
37
|
+
@config = {
|
38
|
+
"-h" => hash["host"] || hash[:host],
|
39
|
+
"-u" => hash["username"] || hash[:username],
|
40
|
+
"-p" => hash["password"] || hash[:password],
|
41
|
+
"--port=" => hash["port"] || hash[:port],
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
45
|
+
# Exports DDL for the given tables in a mysql compatible way
|
46
|
+
#
|
47
|
+
# @param tables [Array<String>] table names
|
48
|
+
# @return String the DDL for the given tables
|
49
|
+
def export_tables(tables)
|
50
|
+
return if tables.empty?
|
51
|
+
|
52
|
+
self.class.sanitize_sql(
|
53
|
+
execute("--compact", "--skip-lock-tables", "--single-transaction", "--no-data",
|
54
|
+
"--column-statistics=0", *tables)
|
55
|
+
)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Exports INSERT statements for the given migration names.
|
59
|
+
#
|
60
|
+
# The INSERT statements are in groups of 50 migrations per multi-insert statement.
|
61
|
+
#
|
62
|
+
# Notice: this does not export the creation of the schema_migrations table.
|
63
|
+
#
|
64
|
+
# @param migrations [Array<Integer,String>] migration ids/timestamps
|
65
|
+
# @return String the INSERT statements.
|
66
|
+
def export_migrations(migrations)
|
67
|
+
migrations.in_groups_of(50, false).map do |versions|
|
68
|
+
execute(
|
69
|
+
"--compact", "--skip-lock-tables", "--single-transaction",
|
70
|
+
"--no-create-info", "--column-statistics=0",
|
71
|
+
"schema_migrations",
|
72
|
+
"-w", "version IN (#{versions.join(',')})"
|
73
|
+
)
|
74
|
+
end.join.gsub(/VALUES /, "VALUES\n").gsub(/,/, ",\n")
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def execute(*args)
|
80
|
+
stdout, stderr, status = Open3.capture3("mysqldump", *connection_args, @database, *args)
|
81
|
+
raise stderr unless status.success?
|
82
|
+
|
83
|
+
stdout
|
84
|
+
end
|
85
|
+
|
86
|
+
def connection_args
|
87
|
+
@config.compact.map do |arg, value|
|
88
|
+
"#{arg}#{value}"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# rubocop:disable all
|
2
|
+
|
3
|
+
module Edgestitch
|
4
|
+
module Mysql
|
5
|
+
# @private
|
6
|
+
class StructureConstraintOrderMunger
|
7
|
+
class << self
|
8
|
+
def munge(sql)
|
9
|
+
start_idx = end_idx = nil
|
10
|
+
lines = sql.split("\n")
|
11
|
+
lines.each_with_index do |line, idx|
|
12
|
+
if line =~ /^\s*CONSTRAINT\b/
|
13
|
+
start_idx = idx if start_idx.nil?
|
14
|
+
elsif start_idx
|
15
|
+
end_idx = idx - 1
|
16
|
+
unless end_idx == start_idx
|
17
|
+
lines[start_idx..end_idx] = order_and_commafy(lines[start_idx..end_idx])
|
18
|
+
end
|
19
|
+
start_idx = end_idx = nil
|
20
|
+
end
|
21
|
+
end
|
22
|
+
lines.join("\n")
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def ends_with_comma(s)
|
28
|
+
s.rstrip.end_with?(",")
|
29
|
+
end
|
30
|
+
|
31
|
+
def decommafy(s)
|
32
|
+
return s unless ends_with_comma(s.rstrip)
|
33
|
+
"#{s.rstrip[0..-2]}\n"
|
34
|
+
end
|
35
|
+
|
36
|
+
def commafy(s)
|
37
|
+
return s if ends_with_comma(s.rstrip)
|
38
|
+
"#{s.rstrip},\n"
|
39
|
+
end
|
40
|
+
|
41
|
+
def order_and_commafy(lines)
|
42
|
+
last_line_should_have_comma = ends_with_comma(lines[-1])
|
43
|
+
lines.sort!
|
44
|
+
# First lines.length-1 lines always need commas
|
45
|
+
lines[0..-2].each_with_index do |line, idx|
|
46
|
+
lines[idx] = commafy(line)
|
47
|
+
end
|
48
|
+
# Last line may or may not need comma
|
49
|
+
if last_line_should_have_comma
|
50
|
+
lines[-1] = commafy(lines[-1])
|
51
|
+
else
|
52
|
+
lines[-1] = decommafy(lines[-1])
|
53
|
+
end
|
54
|
+
lines
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "edgestitch"
|
4
|
+
|
5
|
+
module Edgestitch
|
6
|
+
# Railtie to install the stitch task (db:stitch).
|
7
|
+
# require this railtie to automatically install the stitch task for the app,
|
8
|
+
# or define it manually adding `::Edgestitch.define_stitch` to your Rakefile.
|
9
|
+
class Railtie < ::Rails::Railtie
|
10
|
+
rake_tasks { ::Edgestitch::Tasks.define_stitch }
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
CREATE TABLE IF NOT EXISTS `schema_migrations` (
|
2
|
+
`version` varchar(255) NOT NULL,
|
3
|
+
PRIMARY KEY (`version`),
|
4
|
+
UNIQUE KEY `unique_schema_migrations` (`version`)
|
5
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
6
|
+
|
7
|
+
<% each_file do |file| %>
|
8
|
+
-- <%= file.realpath %>
|
9
|
+
<%= file.read %>
|
10
|
+
<% end %>
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "erb"
|
4
|
+
|
5
|
+
module Edgestitch
|
6
|
+
# @private
|
7
|
+
#
|
8
|
+
# Renders a structure.sql file based on all given engine's structure-self.sql
|
9
|
+
#
|
10
|
+
class Stitcher
|
11
|
+
def initialize(engines)
|
12
|
+
@engines = Set.new(engines)
|
13
|
+
end
|
14
|
+
|
15
|
+
def each_file(&block)
|
16
|
+
@engines.map { |engine| engine.root.join("db", "structure-self.sql") }
|
17
|
+
.filter(&:exist?)
|
18
|
+
.uniq.each(&block)
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.to_file(file, *engines)
|
22
|
+
File.write(file, new(engines).render)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
erb = ERB.new(File.read(File.join(__dir__, "stitch.sql.erb")))
|
28
|
+
erb.def_method(Edgestitch::Stitcher, "render()")
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rake/tasklib"
|
4
|
+
|
5
|
+
module Edgestitch
|
6
|
+
# @private
|
7
|
+
#
|
8
|
+
# Define rake tasks to deal with edgestitch structurefiles:
|
9
|
+
#
|
10
|
+
# db:stitch: creates a structure.sql out of loaded engines and application
|
11
|
+
# structure-self.sql
|
12
|
+
# db:stitch:<engine_name>: creates a structure-self.sql containing only the
|
13
|
+
# engine's models and migrations
|
14
|
+
#
|
15
|
+
# In order to integrate well with rails, it also enhances tasks like db:structure:load,
|
16
|
+
# db:prepare and others.
|
17
|
+
#
|
18
|
+
module Tasks
|
19
|
+
class << self
|
20
|
+
include Rake::DSL
|
21
|
+
|
22
|
+
# Defines a task to stitch a structure.sql from loaded Engines.
|
23
|
+
# This task is responsible for gathering all loaded engines and the current
|
24
|
+
# application's structrure-self.sql and stitching them together into a
|
25
|
+
# structure.sql.
|
26
|
+
#
|
27
|
+
# Rails enhancements will happen before each of these tasks:
|
28
|
+
#
|
29
|
+
# - db:prepare
|
30
|
+
# - db:structure:load
|
31
|
+
# - db:schema:load
|
32
|
+
#
|
33
|
+
# @param namespace [String] namespace where the task will run [default: db:stitch]
|
34
|
+
# @return [Rake::Task]
|
35
|
+
def define_stitch(namespace = "db:stitch")
|
36
|
+
enhance(namespace, "db:prepare", "db:structure:load", "db:schema:load")
|
37
|
+
desc "Create structure.sql for an app based on all loaded engines' structure-self.sql"
|
38
|
+
task namespace => [:environment] do |_task, _args|
|
39
|
+
ActiveRecord::Base.configurations.configs_for(env_name: Rails.env).each do |db_config|
|
40
|
+
::Edgestitch::Stitcher.to_file(filename(db_config), *::Rails::Engine.subclasses, Rails.application)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Defines a task to generate the structure-self.sql file from an engine.
|
46
|
+
# This task is responsible for gathering all models owned by the engine and all
|
47
|
+
# migrations defined within the engine and generate a structure-self.sql.
|
48
|
+
#
|
49
|
+
# Rails enhancements will happen before each of these tasks:
|
50
|
+
#
|
51
|
+
# - db:structure:dump
|
52
|
+
# - db:schema:dump
|
53
|
+
# - app:db:structure:dump
|
54
|
+
# - app:db:schema:dump
|
55
|
+
#
|
56
|
+
# @param engine [Class<Rails::Engine>] target class of the task
|
57
|
+
# @param namespace [String] the namespace where the target will be generated [default: db:stitch]
|
58
|
+
# @param name [String] the name of the task within the given namespace [default: engine.engine_name]
|
59
|
+
# @return [Rake::Task]
|
60
|
+
def define_engine(engine, namespace: "db:stitch", name: engine.engine_name)
|
61
|
+
enhance("#{namespace}:#{name}", "db:structure:dump", "app:db:structure:dump", "db:schema:dump",
|
62
|
+
"app:db:schema:dump")
|
63
|
+
|
64
|
+
desc "Create structure-self.sql for an engine"
|
65
|
+
task "#{namespace}:#{name}" => [:environment] do |_, _args|
|
66
|
+
Rails.application.eager_load!
|
67
|
+
engine&.eager_load!
|
68
|
+
ActiveRecord::Base.configurations.configs_for(env_name: Rails.env).each do |db_config|
|
69
|
+
::Edgestitch::Exporter.export(engine, ::Edgestitch::Mysql::Dump.new(db_config))
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def enhance(with, *tasks)
|
77
|
+
tasks.filter { |task| Rake::Task.task_defined?(task) }
|
78
|
+
.each { |task| Rake::Task[task].enhance([with]) }
|
79
|
+
end
|
80
|
+
|
81
|
+
def filename(db_config)
|
82
|
+
if ::ActiveRecord::Tasks::DatabaseTasks.respond_to?(:schema_dump_path)
|
83
|
+
::ActiveRecord::Tasks::DatabaseTasks.schema_dump_path(db_config, :sql)
|
84
|
+
else
|
85
|
+
name = db_config.respond_to?(:name) ? db_config.name : db_config.spec_name
|
86
|
+
::ActiveRecord::Tasks::DatabaseTasks.dump_filename(name, :sql)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
data/lib/edgestitch.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "edgestitch/exporter"
|
4
|
+
require "edgestitch/stitcher"
|
5
|
+
require "edgestitch/tasks"
|
6
|
+
require "edgestitch/version"
|
7
|
+
|
8
|
+
require "edgestitch/mysql/dump"
|
9
|
+
|
10
|
+
# Facade module to access public Edgestitch functions
|
11
|
+
#
|
12
|
+
module Edgestitch
|
13
|
+
module_function
|
14
|
+
|
15
|
+
# Define a db:stitch task
|
16
|
+
# @see Edgestitch::Tasks
|
17
|
+
def define_stitch(...)
|
18
|
+
::Edgestitch::Tasks.define_stitch(...)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Define a db:stitch:<engine_name> task
|
22
|
+
# @see Edgestitch::Tasks
|
23
|
+
def define_engine(...)
|
24
|
+
::Edgestitch::Tasks.define_engine(...)
|
25
|
+
end
|
26
|
+
end
|
data/mkdocs.yml
ADDED
metadata
ADDED
@@ -0,0 +1,220 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: edgestitch
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Carlos Palhares
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2022-12-27 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.1'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.1'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: license_finder
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '7.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '7.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: mysql2
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.5.3
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.5.3
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: pry-byebug
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 3.9.0
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 3.9.0
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rails
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 5.2.8.1
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 5.2.8.1
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rake
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '13.0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '13.0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rspec
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '3.0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '3.0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: rspec-rails
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 5.1.2
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: 5.1.2
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: rubocop-powerhome
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - '='
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: 0.5.0
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - '='
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: 0.5.0
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: simplecov
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - '='
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: 0.15.1
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - '='
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: 0.15.1
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: yard
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - '='
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: 0.9.21
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - '='
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: 0.9.21
|
167
|
+
description: Edgestitch allows engines to define partial structure-self.sql files
|
168
|
+
to be stitched into a single structure.sql file by the umbrella application.
|
169
|
+
email:
|
170
|
+
- chjunior@gmail.com
|
171
|
+
executables: []
|
172
|
+
extensions: []
|
173
|
+
extra_rdoc_files: []
|
174
|
+
files:
|
175
|
+
- ".rubocop.yml"
|
176
|
+
- Gemfile
|
177
|
+
- Rakefile
|
178
|
+
- doc/dependency_decisions.yml
|
179
|
+
- docs/CHANGELOG.md
|
180
|
+
- docs/README.md
|
181
|
+
- edgestitch.gemspec
|
182
|
+
- lib/edgestitch.rb
|
183
|
+
- lib/edgestitch/exporter.rb
|
184
|
+
- lib/edgestitch/mysql/dump.rb
|
185
|
+
- lib/edgestitch/mysql/structure_constraint_order_munger.rb
|
186
|
+
- lib/edgestitch/railtie.rb
|
187
|
+
- lib/edgestitch/stitch.sql.erb
|
188
|
+
- lib/edgestitch/stitcher.rb
|
189
|
+
- lib/edgestitch/tasks.rb
|
190
|
+
- lib/edgestitch/version.rb
|
191
|
+
- mkdocs.yml
|
192
|
+
homepage: https://github.com/powerhome/power-tools
|
193
|
+
licenses:
|
194
|
+
- MIT
|
195
|
+
metadata:
|
196
|
+
rubygems_mfa_required: 'true'
|
197
|
+
homepage_uri: https://github.com/powerhome/power-tools
|
198
|
+
source_code_uri: https://github.com/powerhome/power-tools
|
199
|
+
changelog_uri: https://github.com/powerhome/power-tools/blob/main/packages/edgestitch/docs/CHANGELOG.md
|
200
|
+
post_install_message:
|
201
|
+
rdoc_options: []
|
202
|
+
require_paths:
|
203
|
+
- lib
|
204
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
205
|
+
requirements:
|
206
|
+
- - ">="
|
207
|
+
- !ruby/object:Gem::Version
|
208
|
+
version: '2.7'
|
209
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
210
|
+
requirements:
|
211
|
+
- - ">="
|
212
|
+
- !ruby/object:Gem::Version
|
213
|
+
version: '0'
|
214
|
+
requirements: []
|
215
|
+
rubygems_version: 3.3.26
|
216
|
+
signing_key:
|
217
|
+
specification_version: 4
|
218
|
+
summary: Edgestitch allows engines to define partial structure-self.sql files to be
|
219
|
+
stitched into a single structure.sql file by the umbrella application.
|
220
|
+
test_files: []
|