songbird 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/.rspec +3 -0
- data/LICENSE.txt +21 -0
- data/README.md +116 -0
- data/Rakefile +8 -0
- data/lib/songbird/migration_discoverer.rb +94 -0
- data/lib/songbird/railtie.rb +11 -0
- data/lib/songbird/sql_generator.rb +197 -0
- data/lib/songbird/version.rb +5 -0
- data/lib/songbird.rb +26 -0
- data/lib/tasks/songbird.rake +41 -0
- metadata +99 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: f4b3d882caf1f2537fe3904c8e24a56fb58b0ac3edb46907f7c183e5afdaf3a9
|
4
|
+
data.tar.gz: dec81593f25440661a062486f6e33b4063642a52d702477b6fadd7547c1b5c15
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ea0a7bcf2c5ac38d28f2f42d0150532cd5eff59aa045e8f8320830158df7d4013c28727659dd89d5a0c2f22e0565be18dd8441c8d077612aba641af8fe3d8dc3
|
7
|
+
data.tar.gz: 9468d3b43d4c1111bbbae0040787769d9fef9d86dc9d06a7a9fed2045d09bf4919b2625b2051230e8ad1fa297bf14f9df343a197ac585f67266aaccacccd7e9a
|
data/.rspec
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2025 Elcio Nakashima
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
# 🐦 Songbird
|
2
|
+
|
3
|
+
Extract SQL statements from Rails migrations for manual review and execution. Perfect for debugging, review, or manual execution of schema changes.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'songbird'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
```bash
|
16
|
+
$ bundle install
|
17
|
+
```
|
18
|
+
|
19
|
+
Or install it directly:
|
20
|
+
|
21
|
+
```bash
|
22
|
+
$ gem install songbird
|
23
|
+
```
|
24
|
+
|
25
|
+
## Usage
|
26
|
+
|
27
|
+
Songbird provides Rake tasks that integrate seamlessly with your Rails application to generate SQL for migrations.
|
28
|
+
|
29
|
+
### Basic Usage
|
30
|
+
|
31
|
+
Generate SQL for a specific migration:
|
32
|
+
```bash
|
33
|
+
rake db:migrate:sql[20241201000000]
|
34
|
+
```
|
35
|
+
|
36
|
+
Running the command without a version will show usage instructions and list your three most recent migrations for easy reference.
|
37
|
+
|
38
|
+
### Shortcut Commands
|
39
|
+
|
40
|
+
Songbird also provides a convenient shortcut command:
|
41
|
+
|
42
|
+
```bash
|
43
|
+
rake songbird:sql[20241201000000] # Generate SQL for specific migration
|
44
|
+
```
|
45
|
+
|
46
|
+
### Output Format
|
47
|
+
|
48
|
+
The generated SQL includes helpful comments and proper formatting:
|
49
|
+
|
50
|
+
```sql
|
51
|
+
-- Generated SQL for pending Rails migrations
|
52
|
+
-- Generated at: 2024-12-01 10:30:00 UTC
|
53
|
+
|
54
|
+
-- Migration: 20241201000001 - Create users
|
55
|
+
-- File: 20241201000001_create_users.rb
|
56
|
+
CREATE TABLE "users" (id SERIAL PRIMARY KEY);
|
57
|
+
ALTER TABLE "users" ADD COLUMN "name" VARCHAR NOT NULL;
|
58
|
+
|
59
|
+
-- Update schema_migrations table:
|
60
|
+
INSERT INTO schema_migrations (version) VALUES ('20241201000001');
|
61
|
+
|
62
|
+
-- Migration: 20241201000002 - Add email to users
|
63
|
+
-- File: 20241201000002_add_email_to_users.rb
|
64
|
+
ALTER TABLE "users" ADD COLUMN "email" VARCHAR;
|
65
|
+
|
66
|
+
-- Update schema_migrations table:
|
67
|
+
INSERT INTO schema_migrations (version) VALUES ('20241201000002');
|
68
|
+
```
|
69
|
+
|
70
|
+
## Features
|
71
|
+
|
72
|
+
- ✅ **Database-Agnostic** - Works with any ActiveRecord-supported database
|
73
|
+
- ✅ **Rails Integration** - Works seamlessly with Rails migration system
|
74
|
+
- ✅ **Schema Metadata** - Automatically generates `schema_migrations` INSERT statements
|
75
|
+
- ✅ **Clean Output Format** - Properly commented SQL ready for database execution
|
76
|
+
- ✅ **Specific Migration Support** - Generate SQL for individual migrations by version
|
77
|
+
- ✅ **Complete Migration Support** - Supports all Rails migration operations by intercepting at the SQL level
|
78
|
+
|
79
|
+
## Use Cases
|
80
|
+
|
81
|
+
### Migration Timeouts
|
82
|
+
When Rails migrations timeout in production due to long-running operations, they can leave migrations in an incomplete state that requires manual intervention. With Songbird:
|
83
|
+
|
84
|
+
1. Run `rake db:migrate:sql[specific_migration_version]` for the failed migration
|
85
|
+
2. Execute the generated SQL manually in your database
|
86
|
+
3. Resume normal Rails migrations
|
87
|
+
|
88
|
+
### Database Review Process
|
89
|
+
For organizations requiring DBA approval of schema changes:
|
90
|
+
|
91
|
+
1. Generate SQL using Songbird
|
92
|
+
2. Submit SQL for review
|
93
|
+
3. Execute approved SQL manually
|
94
|
+
4. Update `schema_migrations` table
|
95
|
+
|
96
|
+
### Complex Migration Debugging
|
97
|
+
Debug migration issues by reviewing the generated SQL before execution:
|
98
|
+
|
99
|
+
1. Generate SQL to understand what operations will be performed
|
100
|
+
2. Identify potential issues (missing indexes, constraint violations, etc.)
|
101
|
+
3. Modify migrations as needed
|
102
|
+
|
103
|
+
|
104
|
+
## Development
|
105
|
+
|
106
|
+
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.
|
107
|
+
|
108
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
109
|
+
|
110
|
+
## License
|
111
|
+
|
112
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
113
|
+
|
114
|
+
## Contributing
|
115
|
+
|
116
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/elciok/songbird.
|
data/Rakefile
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_record'
|
4
|
+
|
5
|
+
module Songbird
|
6
|
+
class MigrationDiscoverer
|
7
|
+
attr_reader :migrations_path
|
8
|
+
|
9
|
+
def initialize(migrations_path = nil)
|
10
|
+
@migrations_path = migrations_path || default_migrations_path
|
11
|
+
end
|
12
|
+
|
13
|
+
# Get all available migrations
|
14
|
+
def load_all_migrations
|
15
|
+
load_migration_files
|
16
|
+
end
|
17
|
+
|
18
|
+
# Load a specific migration class by version
|
19
|
+
def load_migration_class(version)
|
20
|
+
migration_info = find_migration_by_version_private(version)
|
21
|
+
return nil unless migration_info
|
22
|
+
|
23
|
+
# Load the migration file
|
24
|
+
load migration_info[:filepath]
|
25
|
+
|
26
|
+
# Get the migration class
|
27
|
+
migration_info[:class_name].constantize
|
28
|
+
end
|
29
|
+
|
30
|
+
# Find migration info by version
|
31
|
+
def find_migration_by_version(version)
|
32
|
+
find_migration_by_version_private(version)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Check if migrations directory exists
|
36
|
+
def migrations_exist?
|
37
|
+
Dir.exist?(@migrations_path)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Get the path to migrations directory
|
41
|
+
def migrations_path
|
42
|
+
@migrations_path
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def default_migrations_path
|
48
|
+
if defined?(Rails)
|
49
|
+
# Use Rails' configured migrations paths - this is more accurate than hardcoding
|
50
|
+
# Rails can have multiple migration paths and this gets the primary one
|
51
|
+
ActiveRecord::Migrator.migrations_paths.first || Rails.root.join('db', 'migrate').to_s
|
52
|
+
else
|
53
|
+
File.join(Dir.pwd, 'db', 'migrate')
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def load_migration_files
|
58
|
+
return [] unless migrations_exist?
|
59
|
+
|
60
|
+
migration_files = Dir.glob(File.join(@migrations_path, '*.rb')).sort
|
61
|
+
|
62
|
+
migration_files.map do |filepath|
|
63
|
+
filename = File.basename(filepath, '.rb')
|
64
|
+
version, name = extract_version_and_name(filename)
|
65
|
+
|
66
|
+
next unless version
|
67
|
+
|
68
|
+
{
|
69
|
+
version: version,
|
70
|
+
name: name,
|
71
|
+
filename: filename,
|
72
|
+
filepath: filepath,
|
73
|
+
class_name: name.camelize
|
74
|
+
}
|
75
|
+
end.compact
|
76
|
+
end
|
77
|
+
|
78
|
+
def extract_version_and_name(filename)
|
79
|
+
# Migration files follow pattern: YYYYMMDDHHMMSS_migration_name.rb
|
80
|
+
if match = filename.match(/\A(\d{14})_(.+)\z/)
|
81
|
+
version = match[1]
|
82
|
+
name = match[2]
|
83
|
+
[version, name]
|
84
|
+
else
|
85
|
+
[nil, nil]
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def find_migration_by_version_private(version)
|
90
|
+
all_migrations = load_migration_files
|
91
|
+
all_migrations.find { |m| m[:version] == version.to_s }
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,197 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'delegate'
|
4
|
+
require 'ostruct'
|
5
|
+
require 'logger'
|
6
|
+
require_relative 'migration_discoverer'
|
7
|
+
|
8
|
+
module Songbird
|
9
|
+
class SQLGenerator
|
10
|
+
attr_reader :discoverer
|
11
|
+
|
12
|
+
def initialize(migrations_path: nil)
|
13
|
+
@discoverer = MigrationDiscoverer.new(migrations_path)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Process migration request - generate SQL for a specific migration or show usage
|
17
|
+
def process(version: nil, output_format: :raw)
|
18
|
+
unless @discoverer.migrations_exist?
|
19
|
+
raise "Migrations directory not found: #{@discoverer.migrations_path}"
|
20
|
+
end
|
21
|
+
|
22
|
+
if version
|
23
|
+
# Generate SQL for specific migration
|
24
|
+
migration_info = @discoverer.find_migration_by_version(version)
|
25
|
+
if migration_info.nil?
|
26
|
+
return "-- Migration #{version} not found"
|
27
|
+
end
|
28
|
+
|
29
|
+
migration_sql = generate_migration_sql(migration_info)
|
30
|
+
schema_sql = generate_schema_migration_sql(migration_info[:version])
|
31
|
+
sql_statement = format_migration_block(migration_info, migration_sql, schema_sql, output_format)
|
32
|
+
|
33
|
+
case output_format
|
34
|
+
when :commented
|
35
|
+
format_with_comments([sql_statement])
|
36
|
+
else
|
37
|
+
sql_statement
|
38
|
+
end
|
39
|
+
else
|
40
|
+
# Show usage with recent migrations when no version specified
|
41
|
+
recent_migrations = @discoverer.load_all_migrations.last(3)
|
42
|
+
|
43
|
+
usage_text = <<~USAGE
|
44
|
+
-- Songbird: Generate SQL for Rails migrations
|
45
|
+
--
|
46
|
+
-- Usage: rake db:migrate:sql[VERSION]
|
47
|
+
-- Example: rake db:migrate:sql[20241201000001]
|
48
|
+
--
|
49
|
+
-- This will generate the SQL commands for the specified migration
|
50
|
+
-- that you can execute manually in your database.
|
51
|
+
USAGE
|
52
|
+
|
53
|
+
if recent_migrations.any?
|
54
|
+
usage_text += "\n-- Recent migrations:\n"
|
55
|
+
recent_migrations.reverse.each do |migration|
|
56
|
+
name = humanize_migration_name(migration[:name])
|
57
|
+
usage_text += "-- #{migration[:version]} - #{name}\n"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
return usage_text
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Generate SQL for a single migration
|
66
|
+
def generate_migration_sql(migration_info)
|
67
|
+
begin
|
68
|
+
migration_class = @discoverer.load_migration_class(migration_info[:version])
|
69
|
+
|
70
|
+
if migration_class.nil?
|
71
|
+
return "-- ERROR: Could not load migration class for #{migration_info[:version]}"
|
72
|
+
end
|
73
|
+
|
74
|
+
# Intercept SQL at the connection execute level
|
75
|
+
captured_sql = []
|
76
|
+
connection = ActiveRecord::Base.connection
|
77
|
+
|
78
|
+
# Store original execute method
|
79
|
+
original_execute = connection.method(:execute)
|
80
|
+
|
81
|
+
# Override execute to capture SQL
|
82
|
+
connection.define_singleton_method(:execute) do |sql, name = nil|
|
83
|
+
captured_sql << sql.to_s
|
84
|
+
# Return empty result to prevent actual execution
|
85
|
+
ActiveRecord::Result.new([], [])
|
86
|
+
end
|
87
|
+
|
88
|
+
# Suppress Rails migration logging
|
89
|
+
original_verbose = ActiveRecord::Migration.verbose
|
90
|
+
original_logger = ActiveRecord::Base.logger
|
91
|
+
|
92
|
+
ActiveRecord::Migration.verbose = false
|
93
|
+
ActiveRecord::Base.logger = Logger.new(IO::NULL)
|
94
|
+
|
95
|
+
# Run the migration to generate SQL
|
96
|
+
migration_instance = migration_class.new
|
97
|
+
migration_instance.migrate(:up)
|
98
|
+
|
99
|
+
# Format captured SQL
|
100
|
+
if captured_sql.empty?
|
101
|
+
"-- No SQL statements captured for migration #{migration_info[:version]}"
|
102
|
+
else
|
103
|
+
captured_sql.map { |sql| format_sql_statement(sql) }.join("\n")
|
104
|
+
end
|
105
|
+
|
106
|
+
rescue => e
|
107
|
+
"-- ERROR in migration #{migration_info[:version]}: #{e.message}"
|
108
|
+
ensure
|
109
|
+
# Restore original execute method and logging
|
110
|
+
if connection && original_execute
|
111
|
+
connection.define_singleton_method(:execute, original_execute)
|
112
|
+
end
|
113
|
+
|
114
|
+
if defined?(original_verbose)
|
115
|
+
ActiveRecord::Migration.verbose = original_verbose
|
116
|
+
end
|
117
|
+
|
118
|
+
if defined?(original_logger)
|
119
|
+
ActiveRecord::Base.logger = original_logger
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
# Generate the schema_migrations INSERT statement
|
125
|
+
def generate_schema_migration_sql(version)
|
126
|
+
result_sql = nil
|
127
|
+
if defined?(ActiveRecord::SchemaMigration)
|
128
|
+
begin
|
129
|
+
# Create SchemaMigration instance with connection pool
|
130
|
+
pool = ActiveRecord::Tasks::DatabaseTasks.migration_connection_pool
|
131
|
+
schema_migration = ActiveRecord::SchemaMigration.new(pool)
|
132
|
+
|
133
|
+
# Use the instance's arel_table and replicate Rails' create_version logic
|
134
|
+
arel_table = schema_migration.arel_table
|
135
|
+
insert_manager = Arel::InsertManager.new(arel_table)
|
136
|
+
insert_manager.insert(arel_table[schema_migration.primary_key] => version)
|
137
|
+
result_sql = insert_manager.to_sql
|
138
|
+
rescue => e
|
139
|
+
puts "-- Using default INSERT command after error generating schema migration SQL: #{e.message}."
|
140
|
+
result_sql = nil
|
141
|
+
end
|
142
|
+
else
|
143
|
+
result_sql = nil
|
144
|
+
end
|
145
|
+
if result_sql.nil?
|
146
|
+
# Fallback
|
147
|
+
result_sql = "INSERT INTO schema_migrations (version) VALUES ('#{version}')"
|
148
|
+
end
|
149
|
+
result_sql
|
150
|
+
end
|
151
|
+
|
152
|
+
|
153
|
+
private
|
154
|
+
|
155
|
+
def format_sql_statement(sql)
|
156
|
+
# Clean up and format SQL statement
|
157
|
+
formatted = sql.to_s.strip
|
158
|
+
formatted = formatted.gsub(/\s+/, ' ') # Normalize whitespace
|
159
|
+
formatted += ';' unless formatted.end_with?(';')
|
160
|
+
formatted
|
161
|
+
end
|
162
|
+
|
163
|
+
def format_migration_block(migration_info, migration_sql, schema_sql, format)
|
164
|
+
case format
|
165
|
+
when :commented
|
166
|
+
[
|
167
|
+
"-- Migration: #{migration_info[:version]} - #{migration_info[:name].humanize}",
|
168
|
+
"-- File: #{migration_info[:filename]}.rb",
|
169
|
+
migration_sql,
|
170
|
+
"",
|
171
|
+
"-- Update schema_migrations table:",
|
172
|
+
"#{schema_sql};"
|
173
|
+
].join("\n")
|
174
|
+
else
|
175
|
+
[
|
176
|
+
migration_sql,
|
177
|
+
"#{schema_sql};"
|
178
|
+
].join("\n")
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def format_with_comments(sql_statements)
|
183
|
+
[
|
184
|
+
"-- Generated SQL for pending Rails migrations",
|
185
|
+
"-- Generated at: #{Time.current}",
|
186
|
+
"",
|
187
|
+
sql_statements.join("\n\n")
|
188
|
+
].join("\n")
|
189
|
+
end
|
190
|
+
|
191
|
+
def humanize_migration_name(name)
|
192
|
+
# Convert migration name from snake_case to human readable
|
193
|
+
name.tr('_', ' ').split.map(&:capitalize).join(' ')
|
194
|
+
end
|
195
|
+
|
196
|
+
end
|
197
|
+
end
|
data/lib/songbird.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "songbird/version"
|
4
|
+
require_relative "songbird/migration_discoverer"
|
5
|
+
require_relative "songbird/sql_generator"
|
6
|
+
|
7
|
+
if defined?(Rails)
|
8
|
+
require_relative "songbird/railtie"
|
9
|
+
end
|
10
|
+
|
11
|
+
module Songbird
|
12
|
+
class Error < StandardError; end
|
13
|
+
|
14
|
+
# Main entry point for the gem
|
15
|
+
def self.generate_sql(version: nil, migrations_path: nil, output_format: :raw)
|
16
|
+
generator = SQLGenerator.new(
|
17
|
+
migrations_path: migrations_path
|
18
|
+
)
|
19
|
+
|
20
|
+
generator.process(
|
21
|
+
version: version,
|
22
|
+
output_format: output_format
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'songbird'
|
4
|
+
|
5
|
+
namespace :db do
|
6
|
+
namespace :migrate do
|
7
|
+
desc 'Generate SQL for migrations'
|
8
|
+
task :sql, [:version, :migrations_path] => :environment do |task, args|
|
9
|
+
begin
|
10
|
+
# Create SQL generator
|
11
|
+
generator = Songbird::SQLGenerator.new(
|
12
|
+
migrations_path: args[:migrations_path]
|
13
|
+
)
|
14
|
+
|
15
|
+
version = args[:version]
|
16
|
+
|
17
|
+
sql_output = generator.process(
|
18
|
+
version: version,
|
19
|
+
output_format: :commented
|
20
|
+
)
|
21
|
+
|
22
|
+
puts sql_output
|
23
|
+
|
24
|
+
rescue => e
|
25
|
+
puts "Error generating migration SQL: #{e.message}"
|
26
|
+
puts e.backtrace.first(5).join("\n") if ENV['DEBUG']
|
27
|
+
exit 1
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Add helpful shortcuts
|
36
|
+
namespace :songbird do
|
37
|
+
desc 'Show SQL commands for migrations (shortcut)'
|
38
|
+
task :sql, [:version, :migrations_path] => 'db:migrate:sql'
|
39
|
+
|
40
|
+
|
41
|
+
end
|
metadata
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: songbird
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Elcio Nakashima
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2025-09-05 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: '7.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '7.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: railties
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '7.0'
|
34
|
+
type: :runtime
|
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: sqlite3
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.7'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.7'
|
55
|
+
description: Extract SQL statements from Rails migrations for manual review and execution.
|
56
|
+
Perfect for debugging, review, or manual execution of schema changes.
|
57
|
+
email:
|
58
|
+
- elciok@gmail.com
|
59
|
+
executables: []
|
60
|
+
extensions: []
|
61
|
+
extra_rdoc_files: []
|
62
|
+
files:
|
63
|
+
- ".rspec"
|
64
|
+
- LICENSE.txt
|
65
|
+
- README.md
|
66
|
+
- Rakefile
|
67
|
+
- lib/songbird.rb
|
68
|
+
- lib/songbird/migration_discoverer.rb
|
69
|
+
- lib/songbird/railtie.rb
|
70
|
+
- lib/songbird/sql_generator.rb
|
71
|
+
- lib/songbird/version.rb
|
72
|
+
- lib/tasks/songbird.rake
|
73
|
+
homepage: https://github.com/elciok/songbird
|
74
|
+
licenses:
|
75
|
+
- MIT
|
76
|
+
metadata:
|
77
|
+
homepage_uri: https://github.com/elciok/songbird
|
78
|
+
source_code_uri: https://github.com/elciok/songbird
|
79
|
+
changelog_uri: https://github.com/elciok/songbird/blob/main/CHANGELOG.md
|
80
|
+
post_install_message:
|
81
|
+
rdoc_options: []
|
82
|
+
require_paths:
|
83
|
+
- lib
|
84
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: 3.1.0
|
89
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
90
|
+
requirements:
|
91
|
+
- - ">="
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
requirements: []
|
95
|
+
rubygems_version: 3.5.11
|
96
|
+
signing_key:
|
97
|
+
specification_version: 4
|
98
|
+
summary: Extract SQL statements from Rails migrations for manual review and execution.
|
99
|
+
test_files: []
|