code0-zero_track 0.0.0 → 0.0.2
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 +4 -4
- data/LICENSE +0 -0
- data/README.md +48 -0
- data/Rakefile +0 -0
- data/lib/code0/zero_track/context.rb +133 -0
- data/lib/code0/zero_track/database/column_methods.rb +35 -0
- data/lib/code0/zero_track/database/migration.rb +26 -0
- data/lib/code0/zero_track/database/migration_helpers/add_column_enhancements.rb +41 -0
- data/lib/code0/zero_track/database/migration_helpers/constraint_helpers.rb +22 -0
- data/lib/code0/zero_track/database/migration_helpers/index_helpers.rb +18 -0
- data/lib/code0/zero_track/database/migration_helpers/table_enhancements.rb +78 -0
- data/lib/code0/zero_track/database/postgresql_adapter/dump_schema_versions_mixin.rb +27 -0
- data/lib/code0/zero_track/database/postgresql_database_tasks/load_schema_versions_mixin.rb +26 -0
- data/lib/code0/zero_track/database/schema_cleaner.rb +51 -0
- data/lib/code0/zero_track/database/schema_migrations/context.rb +48 -0
- data/lib/code0/zero_track/database/schema_migrations/migrations.rb +62 -0
- data/lib/code0/zero_track/database/schema_migrations.rb +32 -0
- data/lib/code0/zero_track/injectors/active_record_schema_migrations.rb +20 -0
- data/lib/code0/zero_track/injectors/active_record_timestamps.rb +21 -0
- data/lib/code0/zero_track/loggable.rb +48 -0
- data/lib/code0/zero_track/logs/json_formatter.rb +42 -0
- data/lib/code0/zero_track/memoize.rb +50 -0
- data/lib/code0/zero_track/railtie.rb +15 -0
- data/lib/code0/zero_track/version.rb +1 -1
- data/lib/code0/zero_track.rb +10 -2
- data/lib/rubocop/code0/zero_track/file_helpers.rb +25 -0
- data/lib/rubocop/cop/code0/zero_track/logs/rails_logger.rb +31 -0
- data/lib/rubocop/cop/code0/zero_track/migration/create_table_with_timestamps.rb +72 -0
- data/lib/rubocop/cop/code0/zero_track/migration/datetime.rb +53 -0
- data/lib/rubocop/cop/code0/zero_track/migration/timestamps.rb +38 -0
- data/lib/rubocop/cop/code0/zero_track/migration/versioned_class.rb +93 -0
- data/lib/rubocop/zero_track.rb +5 -0
- data/lib/tasks/code0/zero_track_tasks.rake +33 -4
- metadata +60 -7
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Code0
|
4
|
+
module ZeroTrack
|
5
|
+
module Injectors
|
6
|
+
class ActiveRecordSchemaMigrations
|
7
|
+
def self.inject!
|
8
|
+
# Patch to write version information as empty files under the db/schema_migrations directory
|
9
|
+
# This is intended to reduce potential for merge conflicts in db/structure.sql
|
10
|
+
ActiveSupport.on_load(:active_record_postgresqladapter) do
|
11
|
+
prepend Database::PostgresqlAdapter::DumpSchemaVersionsMixin
|
12
|
+
end
|
13
|
+
# Patch to load version information from empty files under the db/schema_migrations directory
|
14
|
+
ActiveRecord::Tasks::PostgreSQLDatabaseTasks
|
15
|
+
.prepend Database::PostgresqlDatabaseTasks::LoadSchemaVersionsMixin
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Code0
|
4
|
+
module ZeroTrack
|
5
|
+
module Injectors
|
6
|
+
class ActiveRecordTimestamps
|
7
|
+
def self.inject!
|
8
|
+
ActiveSupport.on_load(:active_record_postgresqladapter) do
|
9
|
+
self::NATIVE_DATABASE_TYPES[:datetime_with_timezone] = { name: 'timestamptz' }
|
10
|
+
end
|
11
|
+
|
12
|
+
ActiveSupport.on_load(:active_record) do
|
13
|
+
ActiveRecord::Base.time_zone_aware_types += [:datetime_with_timezone]
|
14
|
+
end
|
15
|
+
|
16
|
+
ActiveRecord::ConnectionAdapters::ColumnMethods.include ZeroTrack::Database::ColumnMethods::Timestamps
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Code0
|
4
|
+
module ZeroTrack
|
5
|
+
module Loggable
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
class_methods do
|
9
|
+
def logger
|
10
|
+
Logger.new(Rails.logger, name || '<Anonymous>')
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def logger
|
15
|
+
Logger.new(Rails.logger, self.class.name || '<Anonymous>')
|
16
|
+
end
|
17
|
+
|
18
|
+
class Logger
|
19
|
+
def initialize(log, clazz)
|
20
|
+
@log = log
|
21
|
+
@clazz = clazz
|
22
|
+
end
|
23
|
+
|
24
|
+
delegate :debug?, :info?, :warn?, :error?, :fatal?, :formatter, :level, to: :@log
|
25
|
+
|
26
|
+
def with_context(&block)
|
27
|
+
Code0::ZeroTrack::Context.with_context(class: @clazz, &block)
|
28
|
+
end
|
29
|
+
|
30
|
+
def debug(message)
|
31
|
+
with_context { @log.debug(message) }
|
32
|
+
end
|
33
|
+
|
34
|
+
def error(message)
|
35
|
+
with_context { @log.error(message) }
|
36
|
+
end
|
37
|
+
|
38
|
+
def warn(message)
|
39
|
+
with_context { @log.warn(message) }
|
40
|
+
end
|
41
|
+
|
42
|
+
def info(message)
|
43
|
+
with_context { @log.info(message) }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Code0
|
4
|
+
module ZeroTrack
|
5
|
+
module Logs
|
6
|
+
class JsonFormatter < ::Logger::Formatter
|
7
|
+
def call(severity, datetime, _progname, message)
|
8
|
+
JSON.generate(data(severity, datetime, message)) << "\n"
|
9
|
+
end
|
10
|
+
|
11
|
+
def data(severity, datetime, message)
|
12
|
+
data = {}
|
13
|
+
data[:severity] = severity
|
14
|
+
data[:time] = datetime.utc.iso8601(3)
|
15
|
+
|
16
|
+
case message
|
17
|
+
when String
|
18
|
+
data[:message] = chomp message
|
19
|
+
when Hash
|
20
|
+
data.merge!(message)
|
21
|
+
end
|
22
|
+
|
23
|
+
data.merge!(Code0::ZeroTrack::Context.current.to_h)
|
24
|
+
end
|
25
|
+
|
26
|
+
def chomp(message)
|
27
|
+
message.chomp! until message.chomp == message
|
28
|
+
|
29
|
+
message.strip
|
30
|
+
end
|
31
|
+
|
32
|
+
class Tagged < JsonFormatter
|
33
|
+
include ActiveSupport::TaggedLogging::Formatter
|
34
|
+
|
35
|
+
def tagged(*_args)
|
36
|
+
yield self # Ignore tags, they break the json layout as they are prepended to the log line
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Code0
|
4
|
+
module ZeroTrack
|
5
|
+
module Memoize
|
6
|
+
def memoize(name, reset_on_change: nil)
|
7
|
+
unless reset_on_change.nil?
|
8
|
+
reset_trigger = reset_on_change.call
|
9
|
+
reset_memoize = memoize("#{name}_reset_on_change") { reset_trigger }
|
10
|
+
|
11
|
+
if reset_trigger != reset_memoize
|
12
|
+
clear_memoize(name)
|
13
|
+
clear_memoize("#{name}_reset_on_change")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
if memoized?(name)
|
18
|
+
instance_variable_get(ivar(name))
|
19
|
+
else
|
20
|
+
instance_variable_set(ivar(name), yield)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def memoized?(name)
|
25
|
+
instance_variable_defined?(ivar(name))
|
26
|
+
end
|
27
|
+
|
28
|
+
def clear_memoize(name)
|
29
|
+
clear_memoize!(name) if memoized?(name)
|
30
|
+
end
|
31
|
+
|
32
|
+
def clear_memoize!(name)
|
33
|
+
remove_instance_variable(ivar(name))
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def ivar(name)
|
39
|
+
case name
|
40
|
+
when Symbol
|
41
|
+
name.to_s.prepend('@').to_sym
|
42
|
+
when String
|
43
|
+
:"@#{name}"
|
44
|
+
else
|
45
|
+
raise ArgumentError, "Invalid type of '#{name}'"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -3,6 +3,21 @@
|
|
3
3
|
module Code0
|
4
4
|
module ZeroTrack
|
5
5
|
class Railtie < ::Rails::Railtie
|
6
|
+
config.zero_track = ActiveSupport::OrderedOptions.new
|
7
|
+
config.zero_track.active_record = ActiveSupport::OrderedOptions.new
|
8
|
+
config.zero_track.active_record.timestamps = false
|
9
|
+
config.zero_track.active_record.schema_migrations = false
|
10
|
+
config.zero_track.active_record.schema_cleaner = false
|
11
|
+
|
12
|
+
rake_tasks do
|
13
|
+
path = File.expand_path(__dir__)
|
14
|
+
Dir.glob("#{path}/../../tasks/**/*.rake").each { |f| load f }
|
15
|
+
end
|
16
|
+
|
17
|
+
config.after_initialize do
|
18
|
+
Injectors::ActiveRecordTimestamps.inject! if config.zero_track.active_record.timestamps
|
19
|
+
Injectors::ActiveRecordSchemaMigrations.inject! if config.zero_track.active_record.schema_migrations
|
20
|
+
end
|
6
21
|
end
|
7
22
|
end
|
8
23
|
end
|
data/lib/code0/zero_track.rb
CHANGED
@@ -1,10 +1,18 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require '
|
4
|
-
|
3
|
+
require 'rails/railtie'
|
4
|
+
|
5
|
+
require 'zeitwerk'
|
6
|
+
loader = Zeitwerk::Loader.new
|
7
|
+
loader.tag = File.basename(__FILE__, '.rb')
|
8
|
+
loader.inflector = Zeitwerk::GemInflector.new(__FILE__)
|
9
|
+
loader.push_dir(File.expand_path(File.join(__dir__, '..')))
|
10
|
+
loader.setup
|
5
11
|
|
6
12
|
module Code0
|
7
13
|
module ZeroTrack
|
8
14
|
# Your code goes here...
|
9
15
|
end
|
10
16
|
end
|
17
|
+
|
18
|
+
Code0::ZeroTrack::Railtie # eager load the railtie
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Code0
|
5
|
+
module ZeroTrack
|
6
|
+
module FileHelpers
|
7
|
+
def dirname(node)
|
8
|
+
File.dirname(filepath(node))
|
9
|
+
end
|
10
|
+
|
11
|
+
def basename(node)
|
12
|
+
File.basename(filepath(node))
|
13
|
+
end
|
14
|
+
|
15
|
+
def filepath(node)
|
16
|
+
node.location.expression.source_buffer.name
|
17
|
+
end
|
18
|
+
|
19
|
+
def in_migration?(node)
|
20
|
+
dirname(node).end_with?('db/migrate')
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Code0
|
6
|
+
module ZeroTrack
|
7
|
+
module Logs
|
8
|
+
# Cop that checks if 'timestamps' method is called with timezone information.
|
9
|
+
class RailsLogger < RuboCop::Cop::Base
|
10
|
+
MSG = 'Do not use `Rails.logger` directly, include `Code0::ZeroTrack::Loggable` instead'
|
11
|
+
LOG_METHODS = %i[debug error fatal info warn].freeze
|
12
|
+
LOG_METHODS_PATTERN = LOG_METHODS.map(&:inspect).join(' ').freeze
|
13
|
+
|
14
|
+
def_node_matcher :rails_logger_log?, <<~PATTERN
|
15
|
+
(send
|
16
|
+
(send (const nil? :Rails) :logger)
|
17
|
+
{#{LOG_METHODS_PATTERN}} ...
|
18
|
+
)
|
19
|
+
PATTERN
|
20
|
+
|
21
|
+
def on_send(node)
|
22
|
+
return unless rails_logger_log?(node)
|
23
|
+
|
24
|
+
add_offense(node)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../../../code0/zero_track/file_helpers'
|
4
|
+
|
5
|
+
module RuboCop
|
6
|
+
module Cop
|
7
|
+
module Code0
|
8
|
+
module ZeroTrack
|
9
|
+
module Migration
|
10
|
+
class CreateTableWithTimestamps < RuboCop::Cop::Base
|
11
|
+
include RuboCop::Code0::ZeroTrack::FileHelpers
|
12
|
+
|
13
|
+
MSG = 'Add timestamps when creating a new table.'
|
14
|
+
RESTRICT_ON_SEND = %i[create_table].freeze
|
15
|
+
|
16
|
+
def_node_matcher :create_table_with_timestamps_proc?, <<~PATTERN
|
17
|
+
(send nil? :create_table (sym _) ... (block-pass (sym :timestamps_with_timezone)))
|
18
|
+
PATTERN
|
19
|
+
|
20
|
+
def_node_search :timestamps_included?, <<~PATTERN
|
21
|
+
(send _var :timestamps_with_timezone ...)
|
22
|
+
PATTERN
|
23
|
+
|
24
|
+
def_node_search :created_at_included?, <<~PATTERN
|
25
|
+
(send _var :datetime_with_timezone
|
26
|
+
{(sym :created_at)(str "created_at")}
|
27
|
+
...)
|
28
|
+
PATTERN
|
29
|
+
|
30
|
+
def_node_search :updated_at_included?, <<~PATTERN
|
31
|
+
(send _var :datetime_with_timezone
|
32
|
+
{(sym :updated_at)(str "updated_at")}
|
33
|
+
...)
|
34
|
+
PATTERN
|
35
|
+
|
36
|
+
def_node_matcher :create_table_with_block?, <<~PATTERN
|
37
|
+
(block
|
38
|
+
(send nil? :create_table ...)
|
39
|
+
(args (arg _var)+)
|
40
|
+
_)
|
41
|
+
PATTERN
|
42
|
+
|
43
|
+
def on_send(node)
|
44
|
+
return unless in_migration?(node)
|
45
|
+
return unless node.command?(:create_table)
|
46
|
+
|
47
|
+
parent = node.parent
|
48
|
+
|
49
|
+
if create_table_with_block?(parent)
|
50
|
+
add_offense(parent) if parent.body.nil? || !time_columns_included?(parent.body)
|
51
|
+
elsif create_table_with_timestamps_proc?(node)
|
52
|
+
# nothing to do
|
53
|
+
else
|
54
|
+
add_offense(node)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def time_columns_included?(node)
|
61
|
+
timestamps_included?(node) || created_at_and_updated_at_included?(node)
|
62
|
+
end
|
63
|
+
|
64
|
+
def created_at_and_updated_at_included?(node)
|
65
|
+
created_at_included?(node) && updated_at_included?(node)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../../../code0/zero_track/file_helpers'
|
4
|
+
|
5
|
+
module RuboCop
|
6
|
+
module Cop
|
7
|
+
module Code0
|
8
|
+
module ZeroTrack
|
9
|
+
module Migration
|
10
|
+
# Cop that checks if datetime data type is added with timezone information.
|
11
|
+
class Datetime < RuboCop::Cop::Base
|
12
|
+
include RuboCop::Code0::ZeroTrack::FileHelpers
|
13
|
+
extend AutoCorrector
|
14
|
+
|
15
|
+
MSG = 'Do not use the `%s` data type, use `datetime_with_timezone` instead'
|
16
|
+
|
17
|
+
# Check methods in table creation.
|
18
|
+
def on_def(node)
|
19
|
+
return unless in_migration?(node)
|
20
|
+
|
21
|
+
node.each_descendant(:send) do |send_node|
|
22
|
+
method_name = send_node.children[1]
|
23
|
+
|
24
|
+
next unless %i[datetime timestamp].include?(method_name)
|
25
|
+
|
26
|
+
add_offense(send_node.loc.selector, message: format(MSG, method_name)) do |corrector|
|
27
|
+
corrector.replace(send_node.loc.selector, 'datetime_with_timezone')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Check methods.
|
33
|
+
def on_send(node)
|
34
|
+
return unless in_migration?(node)
|
35
|
+
|
36
|
+
node.each_descendant do |descendant|
|
37
|
+
next unless descendant.type == :sym
|
38
|
+
|
39
|
+
last_argument = descendant.children.last
|
40
|
+
|
41
|
+
next unless %i[datetime timestamp].include?(last_argument)
|
42
|
+
|
43
|
+
add_offense(descendant, message: format(MSG, last_argument)) do |corrector|
|
44
|
+
corrector.replace(descendant, ':datetime_with_timezone')
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../../../code0/zero_track/file_helpers'
|
4
|
+
|
5
|
+
module RuboCop
|
6
|
+
module Cop
|
7
|
+
module Code0
|
8
|
+
module ZeroTrack
|
9
|
+
module Migration
|
10
|
+
# Cop that checks if 'timestamps' method is called with timezone information.
|
11
|
+
class Timestamps < RuboCop::Cop::Base
|
12
|
+
include RuboCop::Code0::ZeroTrack::FileHelpers
|
13
|
+
extend AutoCorrector
|
14
|
+
|
15
|
+
MSG = 'Do not use `timestamps`, use `timestamps_with_timezone` instead'
|
16
|
+
|
17
|
+
# Check methods in table creation.
|
18
|
+
def on_def(node)
|
19
|
+
return unless in_migration?(node)
|
20
|
+
|
21
|
+
node.each_descendant(:send) do |send_node|
|
22
|
+
next unless method_name(send_node) == :timestamps
|
23
|
+
|
24
|
+
add_offense(send_node.loc.selector) do |corrector|
|
25
|
+
corrector.replace(send_node.loc.selector, 'timestamps_with_timezone')
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def method_name(node)
|
31
|
+
node.children[1]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../../../code0/zero_track/file_helpers'
|
4
|
+
|
5
|
+
module RuboCop
|
6
|
+
module Cop
|
7
|
+
module Code0
|
8
|
+
module ZeroTrack
|
9
|
+
module Migration
|
10
|
+
class VersionedClass < RuboCop::Cop::Base
|
11
|
+
include RuboCop::Code0::ZeroTrack::FileHelpers
|
12
|
+
extend AutoCorrector
|
13
|
+
|
14
|
+
MIGRATION_CLASS = 'Code0::ZeroTrack::Database::Migration'
|
15
|
+
|
16
|
+
# rubocop:disable Layout/LineLength
|
17
|
+
MSG_WRONG_BASE_CLASS = "Don't use `%<base_class>s`. Use `#{MIGRATION_CLASS}` instead.".freeze
|
18
|
+
MSG_WRONG_VERSION = "Don't use version `%<current_version>s` of `#{MIGRATION_CLASS}`. Use version `%<allowed_version>s` instead.".freeze
|
19
|
+
# rubocop:enable Layout/LineLength
|
20
|
+
|
21
|
+
def on_class(node)
|
22
|
+
return unless in_migration?(node)
|
23
|
+
|
24
|
+
return on_zerotrack_migration(node) if zerotrack_migration?(node)
|
25
|
+
|
26
|
+
add_offense(
|
27
|
+
node.parent_class,
|
28
|
+
message: format(MSG_WRONG_BASE_CLASS, base_class: superclass(node))
|
29
|
+
) do |corrector|
|
30
|
+
corrector.replace(node.parent_class, "#{MIGRATION_CLASS}[#{find_allowed_versions(node).last}]")
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def on_zerotrack_migration(node)
|
37
|
+
return if cop_config['AllowedVersions'].nil? # allow all versions if nothing configured
|
38
|
+
return if correct_migration_version?(node)
|
39
|
+
|
40
|
+
current_version = get_migration_version(node)
|
41
|
+
allowed_version = find_allowed_versions(node).last
|
42
|
+
|
43
|
+
version_node = get_migration_version_node(node)
|
44
|
+
|
45
|
+
add_offense(
|
46
|
+
version_node,
|
47
|
+
message: format(MSG_WRONG_VERSION, current_version: current_version, allowed_version: allowed_version)
|
48
|
+
) do |corrector|
|
49
|
+
corrector.replace(version_node, find_allowed_versions(node).last.to_s)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def zerotrack_migration?(node)
|
54
|
+
superclass(node) == MIGRATION_CLASS
|
55
|
+
end
|
56
|
+
|
57
|
+
def superclass(class_node)
|
58
|
+
_, *others = class_node.descendants
|
59
|
+
|
60
|
+
others.find { |node| node.const_type? && node.const_name != 'Types' }&.const_name
|
61
|
+
end
|
62
|
+
|
63
|
+
def correct_migration_version?(node)
|
64
|
+
find_allowed_versions(node).include?(get_migration_version(node))
|
65
|
+
end
|
66
|
+
|
67
|
+
def get_migration_version_node(node)
|
68
|
+
node.parent_class.arguments[0]
|
69
|
+
end
|
70
|
+
|
71
|
+
def get_migration_version(node)
|
72
|
+
get_migration_version_node(node).value
|
73
|
+
end
|
74
|
+
|
75
|
+
def find_allowed_versions(node)
|
76
|
+
migration_version = basename(node).split('_').first.to_i
|
77
|
+
allowed_versions.select do |range, _|
|
78
|
+
range.include?(migration_version)
|
79
|
+
end.values
|
80
|
+
end
|
81
|
+
|
82
|
+
def allowed_versions
|
83
|
+
cop_config['AllowedVersions'].transform_keys do |range|
|
84
|
+
range_ints = range.split('..').map(&:to_i)
|
85
|
+
range_ints[0]..range_ints[1]
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -1,6 +1,35 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
3
|
+
namespace :code0 do
|
4
|
+
namespace :zero_track do
|
5
|
+
namespace :db do
|
6
|
+
desc 'This adjusts and cleans db/structure.sql - it runs after db:schema:dump'
|
7
|
+
task clean_structure_sql: :environment do |task_name|
|
8
|
+
# Allow this task to be called multiple times, as happens when running db:migrate:redo
|
9
|
+
Rake::Task[task_name].reenable
|
10
|
+
|
11
|
+
next unless Rails.application.config.zero_track.active_record.schema_cleaner
|
12
|
+
|
13
|
+
ActiveRecord::Base.configurations
|
14
|
+
.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env)
|
15
|
+
.each do |db_config|
|
16
|
+
structure_file = ActiveRecord::Tasks::DatabaseTasks.schema_dump_path(db_config)
|
17
|
+
|
18
|
+
schema = File.read(structure_file)
|
19
|
+
|
20
|
+
File.open(structure_file, 'wb+') do |io|
|
21
|
+
Code0::ZeroTrack::Database::SchemaCleaner.new(schema).clean(io)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Inform Rake that custom tasks should be run every time rake db:schema:dump is run
|
27
|
+
Rake::Task['db:schema:dump'].enhance do
|
28
|
+
Rake::Task['code0:zero_track:db:clean_structure_sql'].invoke
|
29
|
+
end
|
30
|
+
Rake::Task['db:prepare'].enhance do
|
31
|
+
Rake::Task['code0:zero_track:db:clean_structure_sql'].invoke
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|