exwiw 0.9.21 → 0.9.23

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.
@@ -9,7 +9,13 @@ module Exwiw
9
9
  # Reports how the committed schema config differs from what the application
10
10
  # would generate now, plus the columns still waiting for a masking decision.
11
11
  # Regenerating into a copy rather than over the config directory lets it run
12
- # on a working tree it must not modify (CI). ActiveRecord only.
12
+ # on a working tree it must not modify (CI).
13
+ #
14
+ # The diff/report side is source-agnostic (it reads JSON config files); what
15
+ # varies per schema source is only how to regenerate, injected as
16
+ # `regenerator` — a callable that receives a directory pre-seeded with a copy
17
+ # of the committed config and rewrites it the way `generate!` + `tidy!`
18
+ # would. `models:` remains as the ActiveRecord shorthand for it.
13
19
  class SchemaCheck
14
20
  CATEGORIES = %w[
15
21
  added_tables added_columns removed_tables removed_columns changed_tables needs_mask_decision
@@ -20,9 +26,39 @@ module Exwiw
20
26
  new(models: ActiveRecord::Base.descendants, schema_dir: schema_dir)
21
27
  end
22
28
 
23
- def initialize(models:, schema_dir:)
24
- @models = models
29
+ # The Mongoid counterpart. `Mongoid.models` registers only the base class of
30
+ # an inheritance hierarchy, which is exactly what MongoidSchemaGenerator
31
+ # expects (it expands descendants itself), so the same source the generate
32
+ # task introspects is used here.
33
+ def self.from_mongoid_application(schema_dir:)
34
+ Rails.application.eager_load!
35
+ new(schema_dir: schema_dir, regenerator: mongoid_regenerator(::Mongoid.models))
36
+ end
37
+
38
+ # The regeneration step `from_mongoid_application` injects, exposed so a
39
+ # caller (and the specs) can run the check against an explicit model list
40
+ # without a Rails application — and so what they exercise is the very lambda
41
+ # production uses.
42
+ #
43
+ # `skip_unsupported` is deliberately left off: this runs as a CI gate, and a
44
+ # newly added construct exwiw cannot represent has to fail the task with the
45
+ # generator's actionable message rather than quietly become an `ignore: true`
46
+ # config that reports clean while the collection stops being dumped.
47
+ def self.mongoid_regenerator(models)
48
+ lambda do |tmp_dir|
49
+ # Explicit: safe mode is not optional here, whatever the library default is.
50
+ MongoidSchemaGenerator.new(models: models, output_dir: tmp_dir, safe_new_columns: true).generate!
51
+ MongoidSchemaGenerator.new(models: models, output_dir: tmp_dir).tidy!
52
+ end
53
+ end
54
+
55
+ def initialize(schema_dir:, models: nil, regenerator: nil)
56
+ if models.nil? && regenerator.nil?
57
+ raise ArgumentError, "SchemaCheck requires either models: or regenerator:"
58
+ end
59
+
25
60
  @schema_dir = schema_dir
61
+ @regenerator = regenerator || active_record_regenerator(models)
26
62
  end
27
63
 
28
64
  # The report as a plain Hash. Every list is sorted, so a given state always
@@ -47,9 +83,15 @@ module Exwiw
47
83
 
48
84
  private def regenerate_into(tmp_dir)
49
85
  FileUtils.cp_r(File.join(@schema_dir, "."), tmp_dir) if Dir.exist?(@schema_dir)
50
- # Explicit: safe mode is not optional here, whatever the library default is.
51
- SchemaGenerator.new(models: @models, output_dir: tmp_dir, safe_new_columns: true).generate!
52
- SchemaGenerator.new(models: @models, output_dir: tmp_dir).tidy!
86
+ @regenerator.call(tmp_dir)
87
+ end
88
+
89
+ private def active_record_regenerator(models)
90
+ lambda do |tmp_dir|
91
+ # Explicit: safe mode is not optional here, whatever the library default is.
92
+ SchemaGenerator.new(models: models, output_dir: tmp_dir, safe_new_columns: true).generate!
93
+ SchemaGenerator.new(models: models, output_dir: tmp_dir).tidy!
94
+ end
53
95
  end
54
96
 
55
97
  # Every config file under `dir`, keyed by its path relative to `dir` so the
@@ -170,9 +170,9 @@ module Exwiw
170
170
  merged_table.type = passed_table.type
171
171
  merged_table.comment = comment
172
172
  merged_table.filter = filter
173
- merged_table.bulk_insert_chunk_size = passed_table.bulk_insert_chunk_size
174
173
  merged_table.ignore = ignore
175
174
  # User-owned, never regenerated: carry over from the existing config.
175
+ merged_table.bulk_insert_chunk_size = bulk_insert_chunk_size
176
176
  merged_table.scope_exempt = scope_exempt
177
177
  merged_table.scope_column = scope_column
178
178
  merged_table.reverse_scope = reverse_scope
data/lib/exwiw/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Exwiw
4
- VERSION = "0.9.21"
4
+ VERSION = "0.9.23"
5
5
  end
data/lib/exwiw.rb CHANGED
@@ -40,6 +40,10 @@ require_relative "exwiw/after_insert_hook"
40
40
  require_relative "exwiw/runner"
41
41
  require_relative "exwiw/explain_runner"
42
42
  require_relative "exwiw/schema_generator"
43
+ require_relative "exwiw/db_introspector"
44
+ require_relative "exwiw/db_introspector/mysql_introspector"
45
+ require_relative "exwiw/db_introspector/postgresql_introspector"
46
+ require_relative "exwiw/db_schema_generator"
43
47
  require_relative "exwiw/schema_check"
44
48
  require_relative "exwiw/mongoid_schema_generator"
45
49
 
data/lib/tasks/exwiw.rake CHANGED
@@ -100,7 +100,44 @@ namespace :exwiw do
100
100
  Exwiw::MongoidSchemaGenerator.from_rails_application(
101
101
  output_dir: resolve_schema_dir.call,
102
102
  skip_unsupported: ENV["EXWIW_SKIP_UNSUPPORTED"] == "1",
103
+ # Same convention as `generate`: safe unless EXWIW_NEW_COLUMNS=plain.
104
+ safe_new_columns: safe_new_columns.call,
103
105
  ).generate!
104
106
  end
107
+
108
+ desc "Remove collections from the schema config that no longer exist in the Mongoid application"
109
+ task tidy_mongoid: :environment do
110
+ require "exwiw"
111
+
112
+ result = Exwiw::MongoidSchemaGenerator.from_rails_application(
113
+ output_dir: resolve_schema_dir.call,
114
+ ).tidy!
115
+
116
+ if result.empty?
117
+ puts "exwiw: schema config is already tidy; nothing to remove."
118
+ else
119
+ result.removed_tables.each do |name|
120
+ puts "exwiw: removed config for collection '#{name}' (no longer exists in the application)."
121
+ end
122
+ end
123
+ end
124
+
125
+ desc "Report how the committed schema config differs from the Mongoid application, without changing it"
126
+ task check_mongoid: :environment do
127
+ require "exwiw"
128
+
129
+ report = Exwiw::SchemaCheck.from_mongoid_application(schema_dir: resolve_schema_dir.call).run
130
+ json = JSON.pretty_generate(report)
131
+ puts json
132
+ # A file too, so a caller need not assume stdout carries only the JSON.
133
+ File.write(ENV["EXWIW_SCHEMA_CHECK_OUTPUT"], json + "\n") if ENV["EXWIW_SCHEMA_CHECK_OUTPUT"]
134
+
135
+ unless Exwiw::SchemaCheck.clean?(report)
136
+ $stderr.puts "exwiw: the schema config is out of date or has undecided masking; " \
137
+ "run `rake exwiw:schema:generate_mongoid exwiw:schema:tidy_mongoid` " \
138
+ "and resolve every `needs_mask_decision` field."
139
+ exit 1
140
+ end
141
+ end
105
142
  end
106
143
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: exwiw
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.21
4
+ version: 0.9.23
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shia
@@ -69,6 +69,10 @@ files:
69
69
  - lib/exwiw/belongs_to.rb
70
70
  - lib/exwiw/cli.rb
71
71
  - lib/exwiw/config_file.rb
72
+ - lib/exwiw/db_introspector.rb
73
+ - lib/exwiw/db_introspector/mysql_introspector.rb
74
+ - lib/exwiw/db_introspector/postgresql_introspector.rb
75
+ - lib/exwiw/db_schema_generator.rb
72
76
  - lib/exwiw/ddl_postprocessor.rb
73
77
  - lib/exwiw/default_mask.rb
74
78
  - lib/exwiw/determine_table_processing_order.rb